#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "tree.h"
#include "function.h"
#include "cpplib.h"
#include "c-pragma.h"
#include "flags.h"
#include "toplev.h"
#include "ggc.h"
#include "c-common.h"
#include "output.h"
#include "tm_p.h"
#include "target.h"
#define GCC_BAD(gmsgid) do { warning (gmsgid); return; } while (0)
#define GCC_BAD2(gmsgid, arg) \
do { warning (gmsgid, arg); return; } while (0)
typedef struct align_stack GTY(())
{
int alignment;
tree id;
struct align_stack * prev;
} align_stack;
static GTY(()) struct align_stack * alignment_stack;
static GTY(()) tree pending_weaks;
#ifdef HANDLE_PRAGMA_WEAK
static void apply_pragma_weak (tree, tree);
static void handle_pragma_weak (cpp_reader *);
static void
apply_pragma_weak (tree decl, tree value)
{
if (value)
{
value = build_string (IDENTIFIER_LENGTH (value),
IDENTIFIER_POINTER (value));
decl_attributes (&decl, build_tree_list (get_identifier ("alias"),
build_tree_list (NULL, value)),
0);
}
if (SUPPORTS_WEAK && DECL_EXTERNAL (decl) && TREE_USED (decl)
&& !DECL_WEAK (decl)
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
warning ("%Japplying #pragma weak %qD after first use results "
"in unspecified behavior", decl, decl);
declare_weak (decl);
}
void
maybe_apply_pragma_weak (tree decl)
{
tree *p, t, id;
if (!pending_weaks)
return;
if (!DECL_EXTERNAL (decl) && !TREE_PUBLIC (decl))
return;
if (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL)
return;
id = DECL_ASSEMBLER_NAME (decl);
for (p = &pending_weaks; (t = *p) ; p = &TREE_CHAIN (t))
if (id == TREE_PURPOSE (t))
{
apply_pragma_weak (decl, TREE_VALUE (t));
*p = TREE_CHAIN (t);
break;
}
}
void
maybe_apply_pending_pragma_weaks (void)
{
tree *p, t, alias_id, id, decl, *next;
for (p = &pending_weaks; (t = *p) ; p = next)
{
next = &TREE_CHAIN (t);
alias_id = TREE_PURPOSE (t);
id = TREE_VALUE (t);
if (TREE_VALUE (t) == NULL)
continue;
decl = build_decl (FUNCTION_DECL, alias_id, default_function_type);
DECL_ARTIFICIAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
DECL_EXTERNAL (decl) = 1;
DECL_WEAK (decl) = 1;
assemble_alias (decl, id);
}
}
static void
handle_pragma_weak (cpp_reader * ARG_UNUSED (dummy))
{
tree name, value, x, decl;
enum cpp_ttype t;
value = 0;
if (c_lex (&name) != CPP_NAME)
GCC_BAD ("malformed #pragma weak, ignored");
t = c_lex (&x);
if (t == CPP_EQ)
{
if (c_lex (&value) != CPP_NAME)
GCC_BAD ("malformed #pragma weak, ignored");
t = c_lex (&x);
}
if (t != CPP_EOF)
warning ("junk at end of #pragma weak");
decl = identifier_global_value (name);
if (decl && DECL_P (decl))
{
apply_pragma_weak (decl, value);
if (value)
assemble_alias (decl, value);
}
else
pending_weaks = tree_cons (name, value, pending_weaks);
}
#else
void
maybe_apply_pragma_weak (tree ARG_UNUSED (decl))
{
}
void
maybe_apply_pending_pragma_weaks (void)
{
}
#endif
static GTY(()) tree pending_redefine_extname;
static void handle_pragma_redefine_extname (cpp_reader *);
static void
handle_pragma_redefine_extname (cpp_reader * ARG_UNUSED (dummy))
{
tree oldname, newname, decl, x;
enum cpp_ttype t;
if (c_lex (&oldname) != CPP_NAME)
GCC_BAD ("malformed #pragma redefine_extname, ignored");
if (c_lex (&newname) != CPP_NAME)
GCC_BAD ("malformed #pragma redefine_extname, ignored");
t = c_lex (&x);
if (t != CPP_EOF)
warning ("junk at end of #pragma redefine_extname");
if (!flag_mudflap && !targetm.handle_pragma_redefine_extname)
{
if (warn_unknown_pragmas > in_system_header)
warning ("#pragma redefine_extname not supported on this target");
return;
}
decl = identifier_global_value (oldname);
if (decl
&& (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
&& (TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == VAR_DECL)
&& has_c_linkage (decl))
{
if (DECL_ASSEMBLER_NAME_SET_P (decl))
{
const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
name = targetm.strip_name_encoding (name);
if (strcmp (name, IDENTIFIER_POINTER (newname)))
warning ("#pragma redefine_extname ignored due to conflict with "
"previous rename");
}
else
change_decl_assembler_name (decl, newname);
}
else
add_to_renaming_pragma_list (oldname, newname);
}
void
add_to_renaming_pragma_list (tree oldname, tree newname)
{
tree previous = purpose_member (oldname, pending_redefine_extname);
if (previous)
{
if (TREE_VALUE (previous) != newname)
warning ("#pragma redefine_extname ignored due to conflict with "
"previous #pragma redefine_extname");
return;
}
pending_redefine_extname
= tree_cons (oldname, newname, pending_redefine_extname);
}
static GTY(()) tree pragma_extern_prefix;
static void
handle_pragma_extern_prefix (cpp_reader * ARG_UNUSED (dummy))
{
tree prefix, x;
enum cpp_ttype t;
if (c_lex (&prefix) != CPP_STRING)
GCC_BAD ("malformed #pragma extern_prefix, ignored");
t = c_lex (&x);
if (t != CPP_EOF)
warning ("junk at end of #pragma extern_prefix");
if (targetm.handle_pragma_extern_prefix)
pragma_extern_prefix = (TREE_STRING_LENGTH (prefix) > 1 ? prefix : NULL);
else if (warn_unknown_pragmas > in_system_header)
warning ("#pragma extern_prefix not supported on this target");
}
tree
maybe_apply_renaming_pragma (tree decl, tree asmname)
{
tree *p, t;
if ((TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL)
|| (!TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
|| !has_c_linkage (decl))
return asmname;
if (DECL_ASSEMBLER_NAME_SET_P (decl))
{
const char *oldname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
oldname = targetm.strip_name_encoding (oldname);
if (asmname && strcmp (TREE_STRING_POINTER (asmname), oldname))
warning ("asm declaration ignored due to "
"conflict with previous rename");
for (p = &pending_redefine_extname; (t = *p); p = &TREE_CHAIN (t))
if (DECL_NAME (decl) == TREE_PURPOSE (t))
{
if (strcmp (IDENTIFIER_POINTER (TREE_VALUE (t)), oldname))
warning ("#pragma redefine_extname ignored due to "
"conflict with previous rename");
*p = TREE_CHAIN (t);
break;
}
return 0;
}
for (p = &pending_redefine_extname; (t = *p); p = &TREE_CHAIN (t))
if (DECL_NAME (decl) == TREE_PURPOSE (t))
{
tree newname = TREE_VALUE (t);
*p = TREE_CHAIN (t);
if (asmname)
{
if (strcmp (TREE_STRING_POINTER (asmname),
IDENTIFIER_POINTER (newname)) != 0)
warning ("#pragma redefine_extname ignored due to "
"conflict with __asm__ declaration");
return asmname;
}
return build_string (IDENTIFIER_LENGTH (newname),
IDENTIFIER_POINTER (newname));
}
if (asmname)
return asmname;
if (pragma_extern_prefix)
{
const char *prefix = TREE_STRING_POINTER (pragma_extern_prefix);
size_t plen = TREE_STRING_LENGTH (pragma_extern_prefix) - 1;
const char *id = IDENTIFIER_POINTER (DECL_NAME (decl));
size_t ilen = IDENTIFIER_LENGTH (DECL_NAME (decl));
char *newname = (char *) alloca (plen + ilen + 1);
memcpy (newname, prefix, plen);
memcpy (newname + plen, id, ilen + 1);
return build_string (plen + ilen, newname);
}
return 0;
}
#ifdef HANDLE_PRAGMA_VISIBILITY
static void handle_pragma_visibility (cpp_reader *);
static void
handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED)
{
static int visstack [16], visidx;
tree x;
enum cpp_ttype token;
enum { bad, push, pop } action = bad;
token = c_lex (&x);
if (token == CPP_NAME)
{
const char *op = IDENTIFIER_POINTER (x);
if (!strcmp (op, "push"))
action = push;
else if (!strcmp (op, "pop"))
action = pop;
}
if (bad == action)
GCC_BAD ("#pragma GCC visibility must be followed by push or pop");
else
{
if (pop == action)
{
if (!visidx)
{
GCC_BAD ("No matching push for %<#pragma GCC visibility pop%>");
}
else
{
default_visibility = visstack[--visidx];
visibility_options.inpragma = (visidx>0);
}
}
else
{
if (c_lex (&x) != CPP_OPEN_PAREN)
GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored");
token = c_lex (&x);
if (token != CPP_NAME)
{
GCC_BAD ("malformed #pragma GCC visibility push");
}
else if (visidx >= 16)
{
GCC_BAD ("No more than sixteen #pragma GCC visibility pushes allowed at once");
}
else
{
const char *str = IDENTIFIER_POINTER (x);
visstack[visidx++] = default_visibility;
if (!strcmp (str, "default"))
default_visibility = VISIBILITY_DEFAULT;
else if (!strcmp (str, "internal"))
default_visibility = VISIBILITY_INTERNAL;
else if (!strcmp (str, "hidden"))
default_visibility = VISIBILITY_HIDDEN;
else if (!strcmp (str, "protected"))
default_visibility = VISIBILITY_PROTECTED;
else
{
GCC_BAD ("#pragma GCC visibility push() must specify default, internal, hidden or protected");
}
visibility_options.inpragma = 1;
}
if (c_lex (&x) != CPP_CLOSE_PAREN)
GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored");
}
}
if (c_lex (&x) != CPP_EOF)
warning ("junk at end of %<#pragma GCC visibility%>");
}
#endif
void
c_register_pragma (const char *space, const char *name,
void (*handler) (struct cpp_reader *))
{
cpp_register_pragma (parse_in, space, name, handler, 0);
}
void
c_register_pragma_with_expansion (const char *space, const char *name,
void (*handler) (struct cpp_reader *))
{
cpp_register_pragma (parse_in, space, name, handler, 1);
}
void
init_pragma (void)
{
#ifdef HANDLE_PRAGMA_WEAK
c_register_pragma (0, "weak", handle_pragma_weak);
#endif
#ifdef HANDLE_PRAGMA_VISIBILITY
c_register_pragma ("GCC", "visibility", handle_pragma_visibility);
#endif
c_register_pragma (0, "redefine_extname", handle_pragma_redefine_extname);
c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix);
#ifdef REGISTER_OS_PRAGMAS
REGISTER_OS_PRAGMAS ();
#endif
c_register_pragma ("GCC", "pch_preprocess", c_common_pch_pragma);
#ifdef REGISTER_TARGET_PRAGMAS
REGISTER_TARGET_PRAGMAS ();
#endif
}
#include "gt-c-pragma.h"