/* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack.
- Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
- Free Software Foundation, Inc.
+ Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006 Free Software Foundation, Inc.
This file is part of GCC.
#include "tm_p.h"
#include "vec.h"
#include "target.h"
-
+#include "diagnostic.h"
+#include "opts.h"
#define GCC_BAD(gmsgid) \
do { warning (OPT_Wpragmas, gmsgid); return; } while (0)
typedef struct align_stack GTY(())
{
- int alignment;
- tree id;
+ int alignment;
+ tree id;
struct align_stack * prev;
} align_stack;
#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
/* If we have a "global" #pragma pack(<n>) in effect when the first
- #pragma pack(push,<n>) is encountered, this stores the value of
- maximum_field_alignment in effect. When the final pop_alignment()
+ #pragma pack(push,<n>) is encountered, this stores the value of
+ maximum_field_alignment in effect. When the final pop_alignment()
happens, we restore the value to this, not to a value of 0 for
maximum_field_alignment. Value is in bits. */
static int default_alignment;
entry = GGC_NEW (align_stack);
entry->alignment = alignment;
- entry->id = id;
- entry->prev = alignment_stack;
-
- /* The current value of maximum_field_alignment is not necessarily
- 0 since there may be a #pragma pack(<n>) in effect; remember it
+ entry->id = id;
+ entry->prev = alignment_stack;
+
+ /* The current value of maximum_field_alignment is not necessarily
+ 0 since there may be a #pragma pack(<n>) in effect; remember it
so that we can restore it after the final #pragma pop(). */
if (alignment_stack == NULL)
default_alignment = maximum_field_alignment;
-
+
alignment_stack = entry;
maximum_field_alignment = alignment;
pop_alignment (tree id)
{
align_stack * entry;
-
+
if (alignment_stack == NULL)
GCC_BAD ("#pragma pack (pop) encountered without matching #pragma pack (push)");
/* #pragma pack ()
#pragma pack (N)
-
+
#pragma pack (push)
#pragma pack (push, N)
#pragma pack (push, ID)
}
else if (token == CPP_NUMBER)
{
+ if (TREE_CODE (x) != INTEGER_CST)
+ GCC_BAD ("invalid constant in %<#pragma pack%> - ignored");
align = TREE_INT_CST_LOW (x);
action = set;
if (pragma_lex (&x) != CPP_CLOSE_PAREN)
}
else if (token == CPP_NUMBER && action == push && align == -1)
{
+ if (TREE_CODE (x) != INTEGER_CST)
+ GCC_BAD ("invalid constant in %<#pragma pack%> - ignored");
align = TREE_INT_CST_LOW (x);
if (align == -1)
action = set;
{
case set: SET_GLOBAL_ALIGNMENT (align); break;
case push: push_alignment (align, id); break;
- case pop: pop_alignment (id); break;
+ case pop: pop_alignment (id); break;
}
}
#endif /* HANDLE_PRAGMA_PACK */
+struct def_pragma_macro_value GTY(())
+{
+ struct def_pragma_macro_value *prev;
+ cpp_macro *value;
+};
+
+struct def_pragma_macro GTY(())
+{
+ hashval_t hash;
+ const char *name;
+ struct def_pragma_macro_value value;
+};
+
+static GTY((param_is (struct def_pragma_macro))) htab_t pushed_macro_table;
+
+#ifdef HANDLE_PRAGMA_PUSH_POP_MACRO
+/* Hash table control functions for pushed_macro_table. */
+static hashval_t
+dpm_hash (const void *p)
+{
+ return ((const struct def_pragma_macro *)p)->hash;
+}
+
+static int
+dpm_eq (const void *pa, const void *pb)
+{
+ const struct def_pragma_macro *a = pa, *b = pb;
+ return a->hash == b->hash && strcmp (a->name, b->name) == 0;
+}
+
+/* #pragma push_macro("MACRO_NAME")
+ #pragma pop_macro("MACRO_NAME") */
+
+static void
+handle_pragma_push_macro (cpp_reader *reader)
+{
+ tree x, id = 0;
+ enum cpp_ttype token;
+ struct def_pragma_macro dummy, *c;
+ const char *macroname;
+ void **slot;
+
+ if (pragma_lex (&x) != CPP_OPEN_PAREN)
+ GCC_BAD ("missing %<(%> after %<#pragma push_macro%> - ignored");
+
+ token = pragma_lex (&id);
+
+ /* Silently ignore */
+ if (token == CPP_CLOSE_PAREN)
+ return;
+ if (token != CPP_STRING)
+ GCC_BAD ("invalid constant in %<#pragma push_macro%> - ignored");
+
+ if (pragma_lex (&x) != CPP_CLOSE_PAREN)
+ GCC_BAD ("missing %<)%> after %<#pragma push_macro%> - ignored");
+
+ if (pragma_lex (&x) != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of %<#pragma push_macro%>");
+
+ /* Check for empty string, and silently ignore. */
+ if (TREE_STRING_LENGTH (id) < 1)
+ return;
+ macroname = TREE_STRING_POINTER (id);
+
+ if (pushed_macro_table == NULL)
+ pushed_macro_table = htab_create_ggc (15, dpm_hash, dpm_eq, 0);
+
+ dummy.hash = htab_hash_string (macroname);
+ dummy.name = macroname;
+ slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
+ dummy.hash, INSERT);
+ c = *slot;
+ if (c == NULL)
+ {
+ *slot = c = ggc_alloc (sizeof (struct def_pragma_macro));
+ c->hash = dummy.hash;
+ c->name = ggc_alloc_string (macroname, TREE_STRING_LENGTH (id) - 1);
+ c->value.prev = NULL;
+ }
+ else
+ {
+ struct def_pragma_macro_value *v;
+ v = ggc_alloc (sizeof (struct def_pragma_macro_value));
+ *v = c->value;
+ c->value.prev = v;
+ }
+
+ c->value.value = cpp_push_definition (reader, macroname);
+}
+
+static void
+handle_pragma_pop_macro (cpp_reader *reader)
+{
+ tree x, id = 0;
+ enum cpp_ttype token;
+ struct def_pragma_macro dummy, *c;
+ const char *macroname;
+ void **slot;
+
+ if (pragma_lex (&x) != CPP_OPEN_PAREN)
+ GCC_BAD ("missing %<(%> after %<#pragma pop_macro%> - ignored");
+
+ token = pragma_lex (&id);
+
+ /* Silently ignore */
+ if (token == CPP_CLOSE_PAREN)
+ return;
+ if (token != CPP_STRING)
+ GCC_BAD ("invalid constant in %<#pragma pop_macro%> - ignored");
+
+ if (pragma_lex (&x) != CPP_CLOSE_PAREN)
+ GCC_BAD ("missing %<)%> after %<#pragma pop_macro%> - ignored");
+
+ if (pragma_lex (&x) != CPP_EOF)
+ warning (OPT_Wpragmas, "junk at end of %<#pragma pop_macro%>");
+
+ /* Check for empty string, and silently ignore. */
+ if (TREE_STRING_LENGTH (id) < 1)
+ return;
+ macroname = TREE_STRING_POINTER (id);
+
+ dummy.hash = htab_hash_string (macroname);
+ dummy.name = macroname;
+ slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
+ dummy.hash, NO_INSERT);
+ if (slot == NULL)
+ return;
+ c = *slot;
+
+ cpp_pop_definition (reader, c->name, c->value.value);
+
+ if (c->value.prev)
+ c->value = *c->value.prev;
+ else
+ htab_clear_slot (pushed_macro_table, slot);
+}
+#endif /* HANDLE_PRAGMA_PUSH_POP_MACRO */
+
static GTY(()) tree pending_weaks;
#ifdef HANDLE_PRAGMA_WEAK
&& !DECL_WEAK (decl) /* Don't complain about a redundant #pragma. */
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
warning (OPT_Wpragmas, "applying #pragma weak %q+D after first use "
- "results in unspecified behavior", decl);
+ "results in unspecified behavior", decl);
declare_weak (decl);
}
"conflict with previous #pragma redefine_extname");
return;
}
-
+
pending_redefine_extname
= tree_cons (oldname, newname, pending_redefine_extname);
}
*p = TREE_CHAIN (t);
/* If we already have an asmname, #pragma redefine_extname is
- ignored (with a warning if it conflicts). */
+ ignored (with a warning if it conflicts). */
if (asmname)
{
if (strcmp (TREE_STRING_POINTER (asmname),
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);
typedef enum symbol_visibility visibility;
DEF_VEC_I (visibility);
DEF_VEC_ALLOC_I (visibility, heap);
+static VEC (visibility, heap) *visstack;
+
+/* Push the visibility indicated by STR onto the top of the #pragma
+ visibility stack. */
+
+void
+push_visibility (const char *str)
+{
+ VEC_safe_push (visibility, heap, visstack,
+ 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;
+}
+
+/* Pop a level of the #pragma visibility stack. */
+
+void
+pop_visibility (void)
+{
+ default_visibility = VEC_pop (visibility, visstack);
+ visibility_options.inpragma
+ = VEC_length (visibility, visstack) != 0;
+}
/* Sets the default visibility for symbols to something other than that
specified on the command line. */
+
static void
handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED)
{
tree x;
enum cpp_ttype token;
enum { bad, push, pop } action = bad;
- static VEC (visibility, heap) *visstack;
-
+
token = pragma_lex (&x);
if (token == CPP_NAME)
{
const char *op = IDENTIFIER_POINTER (x);
if (!strcmp (op, "push"))
- action = push;
+ action = push;
else if (!strcmp (op, "pop"))
- action = pop;
+ action = pop;
}
if (bad == action)
GCC_BAD ("#pragma GCC visibility must be followed by push or pop");
else
{
if (pop == action)
- {
- if (!VEC_length (visibility, visstack))
- {
- GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>");
- }
- else
- {
- default_visibility = VEC_pop (visibility, visstack);
- visibility_options.inpragma
- = VEC_length (visibility, visstack) != 0;
- }
- }
+ {
+ if (!VEC_length (visibility, visstack))
+ GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>");
+ else
+ pop_visibility ();
+ }
else
- {
- if (pragma_lex (&x) != CPP_OPEN_PAREN)
- GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored");
- token = pragma_lex (&x);
- if (token != CPP_NAME)
- {
- GCC_BAD ("malformed #pragma GCC visibility push");
- }
- else
- {
- const char *str = IDENTIFIER_POINTER (x);
- VEC_safe_push (visibility, heap, visstack,
- 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 (pragma_lex (&x) != CPP_CLOSE_PAREN)
- GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored");
- }
+ {
+ if (pragma_lex (&x) != CPP_OPEN_PAREN)
+ GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored");
+ token = pragma_lex (&x);
+ if (token != CPP_NAME)
+ GCC_BAD ("malformed #pragma GCC visibility push");
+ else
+ push_visibility (IDENTIFIER_POINTER (x));
+ if (pragma_lex (&x) != CPP_CLOSE_PAREN)
+ GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored");
+ }
}
if (pragma_lex (&x) != CPP_EOF)
warning (OPT_Wpragmas, "junk at end of %<#pragma GCC visibility%>");
#endif
+static void
+handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
+{
+ const char *kind_string, *option_string;
+ unsigned int option_index;
+ enum cpp_ttype token;
+ diagnostic_t kind;
+ tree x;
+
+ if (cfun)
+ {
+ error ("#pragma GCC diagnostic not allowed inside functions");
+ return;
+ }
+
+ token = pragma_lex (&x);
+ if (token != CPP_NAME)
+ GCC_BAD ("missing [error|warning|ignored] after %<#pragma GCC diagnostic%>");
+ kind_string = IDENTIFIER_POINTER (x);
+ if (strcmp (kind_string, "error") == 0)
+ kind = DK_ERROR;
+ else if (strcmp (kind_string, "warning") == 0)
+ kind = DK_WARNING;
+ else if (strcmp (kind_string, "ignored") == 0)
+ kind = DK_IGNORED;
+ else
+ GCC_BAD ("expected [error|warning|ignored] after %<#pragma GCC diagnostic%>");
+
+ token = pragma_lex (&x);
+ if (token != CPP_STRING)
+ GCC_BAD ("missing option after %<#pragma GCC diagnostic%> kind");
+ option_string = TREE_STRING_POINTER (x);
+ for (option_index = 0; option_index < cl_options_count; option_index++)
+ if (strcmp (cl_options[option_index].opt_text, option_string) == 0)
+ {
+ /* This overrides -Werror, for example. */
+ diagnostic_classify_diagnostic (global_dc, option_index, kind);
+ /* This makes sure the option is enabled, like -Wfoo would do. */
+ if (cl_options[option_index].var_type == CLVC_BOOLEAN
+ && cl_options[option_index].flag_var
+ && kind != DK_IGNORED)
+ *(int *) cl_options[option_index].flag_var = 1;
+ return;
+ }
+ GCC_BAD ("unknown option after %<#pragma GCC diagnostic%> kind");
+}
+
/* A vector of registered pragma callbacks. */
DEF_VEC_O (pragma_handler);
c_register_pragma (0, "pack", handle_pragma_pack);
#endif
#endif
+#ifdef HANDLE_PRAGMA_PUSH_POP_MACRO
+ c_register_pragma (0 ,"push_macro", handle_pragma_push_macro);
+ c_register_pragma (0 ,"pop_macro", handle_pragma_pop_macro);
+#endif
#ifdef HANDLE_PRAGMA_WEAK
c_register_pragma (0, "weak", handle_pragma_weak);
#endif
c_register_pragma ("GCC", "visibility", handle_pragma_visibility);
#endif
- c_register_pragma (0, "redefine_extname", handle_pragma_redefine_extname);
+ c_register_pragma ("GCC", "diagnostic", handle_pragma_diagnostic);
+
+ c_register_pragma_with_expansion (0, "redefine_extname", handle_pragma_redefine_extname);
c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix);
#ifdef REGISTER_TARGET_PRAGMAS