From fc009f966c98317401b51127f59de4ad37bb7d19 Mon Sep 17 00:00:00 2001 From: Geoff Keating Date: Thu, 9 Sep 1999 04:00:37 +0000 Subject: Makefile.in (cppexp.o): Depend on cpphash.h. * Makefile.in (cppexp.o): Depend on cpphash.h. * cppexp.c (cpp_lex): Handle `defined (xxx)' for poisoned xxx. Include cpphash.h. * cpphash.c (special_symbol): Handle plain `xxx' for poisoned xxx. * cpplib.c (do_define): Generalise to handle poisoned definitions, redefining poisoned identifiers, etc. (do_undef): Don't allow poisoned identifiers to be undefined. (do_pragma): Add #pragma poison. (do_xifdef): Handle `#ifdef xxx' for poisoned xxx. * cccp.c: Add T_POISON node type. (special_symbol): Handle `defined(xxx)' and plain `xxx' for poisoned xxx. (do_define): Generalise to handle poisoned definitions, redefining poisoned identifiers, etc. (do_undef): Don't allow poisoned identifiers to be undefined. (do_pragma): Add #pragma poison. (do_xifdef): Handle `#ifdef xxx' for poisoned xxx. * c-pragma.c (handle_pragma_token): Ignore #pragma poison. * c-pragma.h: Add ps_poison state. We now always have generic pragmas. From-SVN: r29224 --- gcc/ChangeLog | 25 +++++ gcc/Makefile.in | 2 +- gcc/c-pragma.c | 17 +++- gcc/c-pragma.h | 6 +- gcc/cccp.c | 108 +++++++++++++++----- gcc/cpp.texi | 26 ++++- gcc/cppexp.c | 13 ++- gcc/cpphash.c | 7 ++ gcc/cpplib.c | 112 ++++++++++++++++++--- gcc/cpplib.h | 1 + gcc/testsuite/gcc.c-torture/ChangeLog | 5 + .../gcc.c-torture/noncompile/noncompile.exp | 10 ++ gcc/testsuite/gcc.c-torture/noncompile/poison-1.c | 22 ++++ 13 files changed, 304 insertions(+), 50 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/noncompile/poison-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bdd4753..ffd9ae5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +Thu Sep 9 13:46:06 1999 Geoffrey Keating + + * Makefile.in (cppexp.o): Depend on cpphash.h. + * cppexp.c (cpp_lex): Handle `defined (xxx)' for poisoned xxx. + Include cpphash.h. + * cpphash.c (special_symbol): Handle plain `xxx' for poisoned xxx. + * cpplib.c (do_define): Generalise to handle poisoned definitions, + redefining poisoned identifiers, etc. + (do_undef): Don't allow poisoned identifiers to be undefined. + (do_pragma): Add #pragma poison. + (do_xifdef): Handle `#ifdef xxx' for poisoned xxx. + + * cccp.c: Add T_POISON node type. + (special_symbol): Handle `defined(xxx)' and plain `xxx' for + poisoned xxx. + (do_define): Generalise to handle poisoned definitions, + redefining poisoned identifiers, etc. + (do_undef): Don't allow poisoned identifiers to be undefined. + (do_pragma): Add #pragma poison. + (do_xifdef): Handle `#ifdef xxx' for poisoned xxx. + + * c-pragma.c (handle_pragma_token): Ignore #pragma poison. + * c-pragma.h: Add ps_poison state. We now always have generic + pragmas. + Wed Sep 8 20:30:42 1999 Mark Mitchell * ggc.h (ggc_alloc): New function. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 3f44714..a5a87ee 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2019,7 +2019,7 @@ cpplib.o: cpplib.c $(CONFIG_H) cpplib.h intl.h system.h cpphash.h cpphash.o: cpphash.c $(CONFIG_H) cpplib.h intl.h system.h cpphash.h cppalloc.o: cppalloc.c $(CONFIG_H) cpplib.h intl.h system.h cpperror.o: cpperror.c $(CONFIG_H) cpplib.h intl.h system.h -cppexp.o: cppexp.c $(CONFIG_H) cpplib.h intl.h system.h +cppexp.o: cppexp.c $(CONFIG_H) cpplib.h intl.h system.h cpphash.h cppfiles.o: cppfiles.c $(CONFIG_H) cpplib.h intl.h system.h cppinit.o: cppinit.c $(CONFIG_H) cpplib.h intl.h system.h \ diff --git a/gcc/c-pragma.c b/gcc/c-pragma.c index 017bdef..bfb6bdc 100644 --- a/gcc/c-pragma.c +++ b/gcc/c-pragma.c @@ -300,6 +300,10 @@ handle_pragma_token (string, token) ret_val = 1; /* Ignore the pragma. */ break; #endif /* HANDLE_PRAGMA_WEAK */ + + case ps_poison: + ret_val = 1; + break; } type = state = ps_start; @@ -338,9 +342,11 @@ handle_pragma_token (string, token) #ifdef HANDLE_PRAGMA_WEAK if (strcmp (string, "weak") == 0) type = state = ps_weak; -#endif +#endif + if (strcmp (string, "poison") == 0) + type = state = ps_poison; break; - + #ifdef HANDLE_PRAGMA_WEAK case ps_weak: name = permalloc (strlen (string) + 1); @@ -485,7 +491,12 @@ handle_pragma_token (string, token) state = ps_bad; break; #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */ - + + case ps_poison: + if (token && TREE_CODE (token) != IDENTIFIER_NODE) + state = ps_bad; + break; + case ps_bad: case ps_done: break; diff --git a/gcc/c-pragma.h b/gcc/c-pragma.h index f94ee9f..bfe7c1fe 100644 --- a/gcc/c-pragma.h +++ b/gcc/c-pragma.h @@ -61,13 +61,12 @@ extern int add_weak PROTO((char *, char *)); #endif /* HANDLE_PRAGMA_WEAK */ -#if defined HANDLE_PRAGMA_PACK || defined HANDLE_PRAGMA_WEAK /* Define HANDLE_GENERIC_PRAGMAS if any kind of front-end pragma parsing is to be done. The code in GCC's generic C source files will only look for the definition of this constant. They will - ignore definitions of HANDLE_PRAGMA_PACK and so on. */ + ignore definitions of HANDLE_PRAGMA_PACK and so on. + With #pragma poison, this is always set. */ #define HANDLE_GENERIC_PRAGMAS 1 -#endif #ifdef HANDLE_GENERIC_PRAGMAS @@ -91,6 +90,7 @@ enum pragma_state ps_push, ps_pushcomma, ps_pushid, ps_pushcomma2, ps_pop, ps_popcomma, #endif + ps_poison, ps_bad }; diff --git a/gcc/cccp.c b/gcc/cccp.c index 5c90cfa..16def7a 100644 --- a/gcc/cccp.c +++ b/gcc/cccp.c @@ -640,6 +640,7 @@ enum node_type { T_DISABLED, /* macro temporarily turned off for rescan */ T_SPEC_DEFINED, /* special `defined' macro for use in #if statements */ T_PCSTRING, /* precompiled string (hashval is KEYDEF *) */ + T_POISON, /* defined with `#pragma poison' */ T_UNUSED /* Used for something not defined. */ }; @@ -4281,7 +4282,12 @@ special_symbol (hp, op) || (hp->type == T_MACRO && hp->value.defn->predefined))) /* Output a precondition for this macro use. */ fprintf (pcp_outfile, "#define %s\n", hp->name); - buf = " 1 "; + if (hp->type == T_POISON) { + error("attempt to use poisoned `%s'.", hp->name); + buf = " 0 "; + } else { + buf = " 1 "; + } } else if (pcp_outfile && pcp_inside_if) { @@ -4302,6 +4308,11 @@ special_symbol (hp, op) } break; + case T_POISON: + error("attempt to use poisoned `%s'.", hp->name); + buf = " 0 "; /* Consider poisoned symbol to not be defined */ + break; + oops: error ("`defined' without an identifier"); @@ -5926,6 +5937,7 @@ do_define (buf, limit, op, keyword) { int hashcode; MACRODEF mdef; + enum node_type newtype = keyword->type == T_DEFINE ? T_MACRO : T_POISON; /* If this is a precompiler run (with -pcp) pass thru #define directives. */ if (pcp_outfile && op) @@ -5944,35 +5956,50 @@ do_define (buf, limit, op, keyword) /* Redefining a precompiled key is ok. */ if (hp->type == T_PCSTRING) ok = 1; + /* Redefining a poisoned identifier is even worse than `not ok'. */ + else if (hp->type == T_POISON) + ok = -1; + /* Poisoning anything else is not ok. + The poison should always come first. */ + else if (newtype == T_POISON) + ok = 0; /* Redefining a macro is ok if the definitions are the same. */ else if (hp->type == T_MACRO) ok = ! compare_defs (mdef.defn, hp->value.defn); /* Redefining a constant is ok with -D. */ else if (hp->type == T_CONST) ok = ! done_initializing; - /* Print the warning if it's not ok. */ - if (!ok) { - /* If we are passing through #define and #undef directives, do - that for this re-definition now. */ - if (debug_output && op) - pass_thru_directive (buf, limit, op, keyword); - - pedwarn ("`%.*s' redefined", mdef.symlen, mdef.symnam); - if (hp->type == T_MACRO) - pedwarn_with_file_and_line (hp->value.defn->file, - hp->value.defn->file_len, - hp->value.defn->line, - "this is the location of the previous definition"); - } - /* Replace the old definition. */ - hp->type = T_MACRO; - hp->value.defn = mdef.defn; + + /* Print the warning or error if it's not ok. */ + if (ok <= 0) + { + /* If we are passing through #define and #undef directives, do + that for this re-definition now. */ + if (debug_output && op) + pass_thru_directive (buf, limit, op, keyword); + + if (hp->type == T_POISON) + error ("redefining poisoned `%.*s'", mdef.symlen, mdef.symnam); + else + pedwarn ("`%.*s' redefined", mdef.symlen, mdef.symnam); + if (hp->type == T_MACRO) + pedwarn_with_file_and_line (hp->value.defn->file, + hp->value.defn->file_len, + hp->value.defn->line, + "this is the location of the previous definition"); + } + if (hp->type != T_POISON) + { + /* Replace the old definition. */ + hp->type = newtype; + hp->value.defn = mdef.defn; + } } else { /* If we are passing through #define and #undef directives, do that for this new definition now. */ if (debug_output && op) pass_thru_directive (buf, limit, op, keyword); - install (mdef.symnam, mdef.symlen, T_MACRO, + install (mdef.symnam, mdef.symlen, newtype, (char *) mdef.defn, hashcode); } } @@ -6990,9 +7017,13 @@ do_undef (buf, limit, op, keyword) need to pass through all effective #undef directives. */ if (debug_output && op) pass_thru_directive (orig_buf, limit, op, keyword); - if (hp->type != T_MACRO) - warning ("undefining `%s'", hp->name); - delete_macro (hp); + if (hp->type == T_POISON) + error ("cannot undefine poisoned `%s'", hp->name); + else { + if (hp->type != T_MACRO) + warning ("undefining `%s'", hp->name); + delete_macro (hp); + } } if (pedantic) { @@ -7087,9 +7118,9 @@ do_ident (buf, limit, op, keyword) static int do_pragma (buf, limit, op, keyword) - U_CHAR *buf, *limit ATTRIBUTE_UNUSED; - FILE_BUF *op ATTRIBUTE_UNUSED; - struct directive *keyword ATTRIBUTE_UNUSED; + U_CHAR *buf, *limit; + FILE_BUF *op; + struct directive *keyword; { SKIP_WHITE_SPACE (buf); if (!strncmp ((char *) buf, "once", 4)) { @@ -7100,6 +7131,29 @@ do_pragma (buf, limit, op, keyword) do_once (); } + if (!strncmp (buf, "poison", 6)) { + /* Poison these symbols so that all subsequent usage produces an + error message. */ + U_CHAR *p = buf + 6; + + SKIP_WHITE_SPACE (p); + while (p < limit) + { + U_CHAR *end = p; + + while (end < limit && is_idchar[*end]) + end++; + if (end < limit && !is_space[*end]) + { + error ("invalid #pragma poison"); + return 0; + } + do_define(p, end, op, keyword); + p = end; + SKIP_WHITE_SPACE (p); + } + } + if (!strncmp ((char *) buf, "implementation", 14)) { /* Be quiet about `#pragma implementation' for a file only if it hasn't been included yet. */ @@ -7351,6 +7405,10 @@ do_xifdef (buf, limit, op, keyword) } } + if ((hp != NULL) && (hp->type == T_POISON)) { + error("attempt to use poisoned `%s'.", hp->name); + hp = NULL; + } skip = (hp == NULL) ^ (keyword->type == T_IFNDEF); if (start_of_file && !skip) { control_macro = (U_CHAR *) xmalloc (end - buf + 1); diff --git a/gcc/cpp.texi b/gcc/cpp.texi index e9a9095..5751722 100644 --- a/gcc/cpp.texi +++ b/gcc/cpp.texi @@ -551,6 +551,7 @@ in the C preprocessor. * Concatenation:: Building tokens from parts taken from macro arguments. * Undefining:: Cancelling a macro's definition. * Redefining:: Changing a macro's definition. +* Poisoning:: Ensuring a macro is never defined or used. * Macro Pitfalls:: Macros can confuse the unwary. Here we explain several common problems and strange features. @end menu @@ -1370,7 +1371,7 @@ The same form of @samp{#undef} directive will cancel definitions with arguments or definitions that don't expect arguments. The @samp{#undef} directive has no effect when used on a name not currently defined as a macro. -@node Redefining, Macro Pitfalls, Undefining, Macros +@node Redefining, Poisoning, Undefining, Macros @subsection Redefining Macros @cindex redefining macros @@ -1404,7 +1405,28 @@ where there was no whitespace at all. Recall that a comment counts as whitespace. -@node Macro Pitfalls,, Redefining, Macros +@node Poisoning, Macro Pitfalls, Redefining, Macros +@subsection Poisoning Macros +@cindex poisoning macros + +Sometimes, there is an identifier that you want to remove completely +from your program, and make sure that it never creeps back in. To +enforce this, the @samp{#pragma poison} directive can be used. +@samp{#pragma poison} is followed by a list of identifiers to poison, +and takes effect for the rest of the source. You cannot @samp{#undef} a +poisoned identifier or test to see if it's defined with @samp{#ifdef}. + +For example, + +@example +#pragma poison printf sprintf fprintf +sprintf(some_string, "hello"); +@end example + +@noindent +will produce an error. + +@node Macro Pitfalls,, Poisoning, Macros @subsection Pitfalls and Subtleties of Macros @cindex problems with macros @cindex pitfalls of macros diff --git a/gcc/cppexp.c b/gcc/cppexp.c index 330236e..f037924 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -27,6 +27,7 @@ Written by Per Bothner 1994. */ #include "config.h" #include "system.h" #include "cpplib.h" +#include "cpphash.h" #ifdef MULTIBYTE_CHARS #include @@ -445,6 +446,7 @@ cpp_lex (pfile, skip_evaluation) int paren = 0, len; cpp_buffer *ip = CPP_BUFFER (pfile); U_CHAR *tok; + HASHNODE *hp; cpp_skip_hspace (pfile); if (*ip->cur == '(') @@ -469,9 +471,14 @@ cpp_lex (pfile, skip_evaluation) goto oops; ++ip->cur; } - if (cpp_lookup (pfile, tok, len, -1)) - op.value = 1; - + hp = cpp_lookup (pfile, tok, len, -1); + if (hp != NULL) + { + if (hp->type == T_POISON) + cpp_error (pfile, "attempt to use poisoned `%s'", hp->name); + else + op.value = 1; + } } return op; diff --git a/gcc/cpphash.c b/gcc/cpphash.c index c75cad1..c7da2b3 100644 --- a/gcc/cpphash.c +++ b/gcc/cpphash.c @@ -1020,6 +1020,13 @@ special_symbol (hp, pfile) return; } + case T_POISON: + cpp_error (pfile, "attempt to use poisoned `%s'.", hp->name); + CPP_RESERVE (pfile, 1); + CPP_PUTC_Q (pfile, '0'); + CPP_NUL_TERMINATE_Q (pfile); + break; + default: cpp_fatal (pfile, "cpplib internal error: invalid special hash type"); return; diff --git a/gcc/cpplib.c b/gcc/cpplib.c index 4ac7f51..e274df9 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -625,8 +625,9 @@ check_macro_name (pfile, symname, assertion) } /* Process a #define command. -KEYWORD is the keyword-table entry for #define, -or NULL for a "predefined" macro. */ + KEYWORD is the keyword-table entry for #define, + or NULL for a "predefined" macro, + or the keyword-table entry for #pragma in the case of a #pragma poison. */ static int do_define (pfile, keyword) @@ -638,10 +639,16 @@ do_define (pfile, keyword) HASHNODE *hp; long here; U_CHAR *macro, *buf, *end; + enum node_type new_type; here = CPP_WRITTEN (pfile); copy_rest_of_line (pfile); + if (keyword == NULL || keyword->type == T_DEFINE) + new_type = T_MACRO; + else + new_type = T_POISON; + /* Copy out the line so we can pop the token buffer. */ buf = pfile->token_buffer + here; end = CPP_PWRITTEN (pfile); @@ -663,30 +670,40 @@ do_define (pfile, keyword) /* Redefining a precompiled key is ok. */ if (hp->type == T_PCSTRING) ok = 1; + /* Redefining a poisoned identifier is even worse than `not ok'. */ + else if (hp->type == T_POISON) + ok = -1; /* Redefining a macro is ok if the definitions are the same. */ else if (hp->type == T_MACRO) ok = ! compare_defs (pfile, mdef.defn, hp->value.defn); /* Redefining a constant is ok with -D. */ else if (hp->type == T_CONST || hp->type == T_STDC) ok = ! CPP_OPTIONS (pfile)->done_initializing; - /* Print the warning if it's not ok. */ - if (!ok) + /* Print the warning or error if it's not ok. */ + if (ok <= 0) { - cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam); + if (hp->type == T_POISON) + cpp_error (pfile, "redefining poisoned `%.*s'", + mdef.symlen, mdef.symnam); + else + cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam); if (hp->type == T_MACRO) cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file, hp->value.defn->line, "this is the location of the previous definition"); } - /* Replace the old definition. */ - hp->type = T_MACRO; - hp->value.defn = mdef.defn; + if (hp->type != T_POISON) + { + /* Replace the old definition. */ + hp->type = new_type; + hp->value.defn = mdef.defn; + } } else - cpp_install (pfile, mdef.symnam, mdef.symlen, T_MACRO, + cpp_install (pfile, mdef.symnam, mdef.symlen, new_type, (char *) mdef.defn, hashcode); - if (keyword) + if (keyword != NULL && keyword->type == T_DEFINE) { if (CPP_OPTIONS (pfile)->debug_output || CPP_OPTIONS (pfile)->dump_macros == dump_definitions) @@ -1425,9 +1442,14 @@ do_undef (pfile, keyword) need to pass through all effective #undef commands. */ if (CPP_OPTIONS (pfile)->debug_output && keyword) pass_thru_directive (name, sym_length, pfile, keyword); - if (hp->type != T_MACRO) - cpp_warning (pfile, "undefining `%s'", hp->name); - delete_macro (hp); + if (hp->type == T_POISON) + cpp_error (pfile, "cannot undefine poisoned `%s'", hp->name); + else + { + if (hp->type != T_MACRO) + cpp_warning (pfile, "undefining `%s'", hp->name); + delete_macro (hp); + } } return 0; @@ -1579,6 +1601,65 @@ do_pragma (pfile, keyword) "`#pragma implementation' for `%s' appears after file is included", fcopy); } + else if (!strncmp (buf, "poison", 6)) + { + /* Poison these symbols so that all subsequent usage produces an + error message. */ + U_CHAR *p = buf + 6; + size_t plen; + U_CHAR *syms; + int writeit; + + SKIP_WHITE_SPACE (p); + plen = strlen(p) + 1; + + syms = (U_CHAR *) alloca (plen); + memcpy (syms, p, plen); + + /* As a rule, don't include #pragma poison commands in output, + unless the user asks for them. */ + writeit = (CPP_OPTIONS (pfile)->debug_output + || CPP_OPTIONS (pfile)->dump_macros == dump_definitions + || CPP_OPTIONS (pfile)->dump_macros == dump_names); + + if (writeit) + CPP_SET_WRITTEN (pfile, here); + else + CPP_SET_WRITTEN (pfile, here-8); + + if (writeit) + { + CPP_RESERVE (pfile, plen + 7); + CPP_PUTS_Q (pfile, "poison", 7); + } + + while (*syms != '\0') + { + U_CHAR *end = syms; + + while (is_idchar[*end]) + end++; + + if (!is_hor_space[*end] && *end != '\0') + { + cpp_error (pfile, "invalid #pragma poison directive"); + return 1; + } + + if (cpp_push_buffer (pfile, syms, end - syms) != NULL) + { + do_define (pfile, keyword); + cpp_pop_buffer (pfile); + } + if (writeit) + { + CPP_PUTC_Q (pfile, ' '); + CPP_PUTS_Q (pfile, syms, end - syms); + } + syms = end; + SKIP_WHITE_SPACE (syms); + } + } return 0; } @@ -1807,6 +1888,11 @@ do_xifdef (pfile, keyword) control_macro = (U_CHAR *) xmalloc (ident_length + 1); bcopy (ident, control_macro, ident_length + 1); } + if (hp != NULL && hp->type == T_POISON) + { + cpp_error (pfile, "attempt to use poisoned `%s'", hp->name); + skip = !skip; + } } else { diff --git a/gcc/cpplib.h b/gcc/cpplib.h index 619645f..daff0c63 100644 --- a/gcc/cpplib.h +++ b/gcc/cpplib.h @@ -600,6 +600,7 @@ enum node_type { T_MACRO, /* macro defined by `#define' */ T_DISABLED, /* macro temporarily turned off for rescan */ T_PCSTRING, /* precompiled string (hashval is KEYDEF *) */ + T_POISON, /* defined with `#pragma poison' */ T_UNUSED /* Used for something not defined. */ }; diff --git a/gcc/testsuite/gcc.c-torture/ChangeLog b/gcc/testsuite/gcc.c-torture/ChangeLog index a805615..9252ab3 100644 --- a/gcc/testsuite/gcc.c-torture/ChangeLog +++ b/gcc/testsuite/gcc.c-torture/ChangeLog @@ -1,3 +1,8 @@ +1999-09-08 Geoffrey Keating + + * noncompile/noncompile.exp: Add poison-1.c. + * noncompile/poison-1.c: New file. + 1999-09-06 Franz Sirl * execute/va-arg-9.c: New test. diff --git a/gcc/testsuite/gcc.c-torture/noncompile/noncompile.exp b/gcc/testsuite/gcc.c-torture/noncompile/noncompile.exp index 901aca9..80a5487 100644 --- a/gcc/testsuite/gcc.c-torture/noncompile/noncompile.exp +++ b/gcc/testsuite/gcc.c-torture/noncompile/noncompile.exp @@ -323,3 +323,13 @@ set compiler_output ".*:6:" set groups {passed gcc-noncompile} postbase_with_opts $src_code $run $groups + +# Test poison-1.c +prebase + +set src_code poison-1.c +set compiler_output ".*c:2:.*c:4:.*c:5:.*c:7:.*c:8:.*c:9:.*c:11:.*c:12:.*c:13:.*c:14:.*c:17:.*c:20:" + +set groups {passed gcc-noncompile} + +postbase $src_code $run $groups diff --git a/gcc/testsuite/gcc.c-torture/noncompile/poison-1.c b/gcc/testsuite/gcc.c-torture/noncompile/poison-1.c new file mode 100644 index 0000000..1cb275e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/noncompile/poison-1.c @@ -0,0 +1,22 @@ +#pragma poison foo +foo +#pragma poison foo2 foo3 +foo2 +foo3 +#pragma poison foo4 foo5 +foo4 +foo5 +#pragma poison +++ +#define foo6 123 +#pragma poison foo6 +#define foo6 345 +#define foo6 456 +#ifdef foo6 +#error hey! foo6 poisoned! +#endif +#if defined(foo6) +#error no, foo6 still poisoned! +#else +foo6 +#endif +#pragma poison -- cgit v1.1