From fc009f966c98317401b51127f59de4ad37bb7d19 Mon Sep 17 00:00:00 2001
From: Geoff Keating <geoffk@cygnus.com>
Date: Thu, 9 Sep 1999 04:00:37 +0000
Subject: [PATCH] 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/testsuite/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  <geoffk@cygnus.com>
+
+	* 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  <mark@codesourcery.com>
 
 	* 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..bfe7c1f 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 <locale.h>
@@ -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..daff0c6 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  <geoffk@cygnus.com>
+
+	* noncompile/noncompile.exp: Add poison-1.c.
+	* noncompile/poison-1.c: New file.
+
 1999-09-06  Franz Sirl  <Franz.Sirl-kernel@lauterbach.com>
 
 	* 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
--
libgit2 0.26.0