public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch]: Add push_macro/pop_macro feature for all targets by moving   it from C frontent into libcpp
@ 2009-11-03 15:13 Kai Tietz
  2009-11-03 17:00 ` Joseph S. Myers
  2009-11-03 17:36 ` Tom Tromey
  0 siblings, 2 replies; 19+ messages in thread
From: Kai Tietz @ 2009-11-03 15:13 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 1792 bytes --]

Hello,

the current implementation of the push_macro/pop_macro feature for
windows targets was broken for C++ frontend and preprocessor. Just for
C it was working proper. So I would like to move this feature from C
frontend into libcpp as internal support pragma for all targets.

As example code see:

#include <stdio.h>
#undef _
#define _ 2
#pragma push_macro ("_")
#undef _
#define _ 1
#pragma pop_macro("_")
int crappy = _ ;

int main()
{
  printf ("Crap is %d\n", crappy);
  return 0;
}

It should show 'Crap is 2", but without this patch it shows for c++
(cygwin/mingw targets) 'Crap is 1".

ChangeLog for libcpp

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* directives.c (do_pragma_push_macro): New pragma handler.
	(do_pragma_pop_macro): Likewise.
	(def_pragma_macro): New structure.
	(pushed_macro_table): New static variable.
	(_cpp_init_internal_pragmas): Add push_macro and
	pop_macro handler to internal pragmas.
	(lex_macro_node_from_str): Removed.
	(cpp_push_definition): Replace lex_macro_node_from_str
	by _cpp_lex_identifier.
	(cpp_pop_definition): Likewise.
	* internal.h (_cpp_lex_identifier): New prototype.
	* lex.c (_cpp_lex_identifier): New function.
	(lex_identifier_intern): New function.


ChangeLog for gcc

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* config/i386/cygming.h (HANDLE_PRAGMA_PUSH_POP_MACRO):
	Removed.
	* c-pragma.c (def_pragma_macro_value): Likewise.
	(def_pragma_macro): Likewise.
	(pushed_macro_table): Likewise.
	(HANDLE_PRAGMA_PUSH_POP_MACRO): Remove guarded
	code.

I tested this patch for i686-pc-linux, i686-pc-cygwin,
i686-pc-mingw32, and x86_64-pc-mingw32. Is this patch ok for apply?

Cheers,
Kai


-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: mvpushpop.diff --]
[-- Type: application/octet-stream, Size: 13039 bytes --]

Index: gcc/libcpp/directives.c
===================================================================
--- gcc.orig/libcpp/directives.c	2009-11-03 08:01:08.000000000 +0100
+++ gcc/libcpp/directives.c	2009-11-03 14:52:24.303000000 +0100
@@ -126,6 +126,8 @@
 static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
 static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
 static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -185,6 +187,14 @@
 #undef D
 #undef DIRECTIVE_TABLE
 
+struct def_pragma_macro {
+  struct def_pragma_macro *next;
+  char *name;
+  cpp_macro *value;
+};
+
+static struct def_pragma_macro *pushed_macro_table;
+
 /* Wrapper struct directive for linemarkers.
    The origin is more or less true - the original K+R cpp
    did use this notation in its preprocessed output.  */
@@ -1244,6 +1254,8 @@
 {
   /* Pragmas in the global namespace.  */
   register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+  register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
   register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
@@ -1423,6 +1435,92 @@
   _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *c;
+
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma push_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+  c = XNEW (struct def_pragma_macro);
+  c->name = XNEWVAR (char, strlen (macroname) + 1);
+  strcpy (c->name, macroname);
+  c->next = pushed_macro_table;
+  c->value = cpp_push_definition (pfile, c->name);
+  pushed_macro_table = c;
+}
+
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *l = NULL, *c = pushed_macro_table;
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma pop_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+
+  while (c != NULL)
+    {
+      if (!strcmp (c->name, macroname))
+	{
+	  if (!l)
+	    pushed_macro_table = c->next;
+	  else
+	    l->next = c->next;
+	  cpp_pop_definition (pfile, c->name, c->value);
+	  free (c->name);
+	  free (c);
+	  break;
+	}
+      l = c;
+      c = c->next;
+    }
+}
+
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
@@ -2225,28 +2323,11 @@
   run_directive (pfile, T_UNDEF, buf, len);
 }
 
-/* Like lex_macro_node, but read the input from STR.  */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
-  size_t len = strlen (str);
-  uchar *buf = (uchar *) alloca (len + 1);
-  cpp_hashnode *node;
-
-  memcpy (buf, str, len);
-  buf[len] = '\n';
-  cpp_push_buffer (pfile, buf, len, true);
-  node = lex_macro_node (pfile, true);
-  _cpp_pop_buffer (pfile);
-
-  return node;
-}
-
 /* If STR is a defined macro, return its definition node, else return NULL.  */
 cpp_macro *
 cpp_push_definition (cpp_reader *pfile, const char *str)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node && node->type == NT_MACRO)
     return node->value.macro;
   else
@@ -2258,7 +2339,7 @@
 void
 cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node == NULL)
     return;
 
Index: gcc/libcpp/internal.h
===================================================================
--- gcc.orig/libcpp/internal.h	2009-10-20 20:26:19.000000000 +0200
+++ gcc/libcpp/internal.h	2009-11-03 14:51:38.151000000 +0100
@@ -575,6 +575,7 @@
 extern cpp_token *_cpp_lex_direct (cpp_reader *);
 extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
+extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
Index: gcc/libcpp/lex.c
===================================================================
--- gcc.orig/libcpp/lex.c	2009-11-03 10:42:38.000000000 +0100
+++ gcc/libcpp/lex.c	2009-11-03 14:17:32.687000000 +0100
@@ -504,6 +504,62 @@
   return false;
 }
 
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base,
+		       struct normalize_state *nst)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+					      base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+			&& !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+	cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
+		   NODE_NAME (result));
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+	 replacement list of a variadic macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+	  && !pfile->state.va_args_ok)
+	cpp_error (pfile, CPP_DL_PEDWARN,
+		   "__VA_ARGS__ can only appear in the expansion"
+		   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+	cpp_error (pfile, CPP_DL_WARNING,
+		   "identifier \"%s\" is a special operator name in C++",
+		   NODE_NAME (result));
+    }
+
+  return result;
+}
+
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  struct normalize_state nst = INITIAL_NORMALIZE_STATE;
+  result = lex_identifier_intern (pfile, (uchar *) name, &nst);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
Index: gcc/gcc/c-pragma.c
===================================================================
--- gcc.orig/gcc/c-pragma.c	2009-11-03 14:54:12.000000000 +0100
+++ gcc/gcc/c-pragma.c	2009-11-03 14:59:03.856000000 +0100
@@ -243,144 +243,6 @@
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
-struct GTY(()) def_pragma_macro_value {
-  struct def_pragma_macro_value *prev;
-  cpp_macro *value;
-};
-
-struct GTY(()) def_pragma_macro {
-  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 *const a = (const struct def_pragma_macro *) pa,
-    *const b = (const struct def_pragma_macro *) 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 = (struct def_pragma_macro *) *slot;
-  if (c == NULL)
-    {
-      *slot = c = GGC_NEW (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_NEW (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 = NULL;
-
-  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;
-  if (pushed_macro_table)
-    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
-				     dummy.hash, NO_INSERT);
-  if (slot == NULL)
-    return;
-  c = (struct def_pragma_macro *) *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
@@ -1421,10 +1283,6 @@
   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
Index: gcc/gcc/config/i386/cygming.h
===================================================================
--- gcc.orig/gcc/config/i386/cygming.h	2009-10-20 21:45:24.000000000 +0200
+++ gcc/gcc/config/i386/cygming.h	2009-11-03 15:00:17.032000000 +0100
@@ -127,8 +127,6 @@
 \f
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
-/* Enable push_macro & pop_macro */
-#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by  moving   it from C frontent into libcpp
  2009-11-03 15:13 [patch]: Add push_macro/pop_macro feature for all targets by moving it from C frontent into libcpp Kai Tietz
@ 2009-11-03 17:00 ` Joseph S. Myers
  2009-11-03 17:09   ` Kai Tietz
  2009-11-03 17:36 ` Tom Tromey
  1 sibling, 1 reply; 19+ messages in thread
From: Joseph S. Myers @ 2009-11-03 17:00 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches

On Tue, 3 Nov 2009, Kai Tietz wrote:

> Hello,
> 
> the current implementation of the push_macro/pop_macro feature for
> windows targets was broken for C++ frontend and preprocessor. Just for
> C it was working proper. So I would like to move this feature from C
> frontend into libcpp as internal support pragma for all targets.

I don't see a testcase added to the testsuite by the patch.  You need to 
add at least one that fails before and passes after the patch, unless 
there is already one there.

(This is not a review of the rest of the patch.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-03 17:00 ` Joseph S. Myers
@ 2009-11-03 17:09   ` Kai Tietz
  2009-11-03 17:25     ` Joseph S. Myers
  0 siblings, 1 reply; 19+ messages in thread
From: Kai Tietz @ 2009-11-03 17:09 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 1001 bytes --]

2009/11/3 Joseph S. Myers <joseph@codesourcery.com>:
> On Tue, 3 Nov 2009, Kai Tietz wrote:
>
>> Hello,
>>
>> the current implementation of the push_macro/pop_macro feature for
>> windows targets was broken for C++ frontend and preprocessor. Just for
>> C it was working proper. So I would like to move this feature from C
>> frontend into libcpp as internal support pragma for all targets.
>
> I don't see a testcase added to the testsuite by the patch.  You need to
> add at least one that fails before and passes after the patch, unless
> there is already one there.
>
> (This is not a review of the rest of the patch.)
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

Ok. Revised version with additional testcase.

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

        * gcc.c-torture/execute/pushpop_macro.c: New testcase.


Kai

-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: mvpushpop.diff --]
[-- Type: application/octet-stream, Size: 13509 bytes --]

Index: gcc/libcpp/directives.c
===================================================================
--- gcc.orig/libcpp/directives.c	2009-11-03 08:01:08.000000000 +0100
+++ gcc/libcpp/directives.c	2009-11-03 14:52:24.303000000 +0100
@@ -126,6 +126,8 @@
 static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
 static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
 static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -185,6 +187,14 @@
 #undef D
 #undef DIRECTIVE_TABLE
 
+struct def_pragma_macro {
+  struct def_pragma_macro *next;
+  char *name;
+  cpp_macro *value;
+};
+
+static struct def_pragma_macro *pushed_macro_table;
+
 /* Wrapper struct directive for linemarkers.
    The origin is more or less true - the original K+R cpp
    did use this notation in its preprocessed output.  */
@@ -1244,6 +1254,8 @@
 {
   /* Pragmas in the global namespace.  */
   register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+  register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
   register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
@@ -1423,6 +1435,92 @@
   _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *c;
+
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma push_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+  c = XNEW (struct def_pragma_macro);
+  c->name = XNEWVAR (char, strlen (macroname) + 1);
+  strcpy (c->name, macroname);
+  c->next = pushed_macro_table;
+  c->value = cpp_push_definition (pfile, c->name);
+  pushed_macro_table = c;
+}
+
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *l = NULL, *c = pushed_macro_table;
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma pop_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+
+  while (c != NULL)
+    {
+      if (!strcmp (c->name, macroname))
+	{
+	  if (!l)
+	    pushed_macro_table = c->next;
+	  else
+	    l->next = c->next;
+	  cpp_pop_definition (pfile, c->name, c->value);
+	  free (c->name);
+	  free (c);
+	  break;
+	}
+      l = c;
+      c = c->next;
+    }
+}
+
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
@@ -2225,28 +2323,11 @@
   run_directive (pfile, T_UNDEF, buf, len);
 }
 
-/* Like lex_macro_node, but read the input from STR.  */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
-  size_t len = strlen (str);
-  uchar *buf = (uchar *) alloca (len + 1);
-  cpp_hashnode *node;
-
-  memcpy (buf, str, len);
-  buf[len] = '\n';
-  cpp_push_buffer (pfile, buf, len, true);
-  node = lex_macro_node (pfile, true);
-  _cpp_pop_buffer (pfile);
-
-  return node;
-}
-
 /* If STR is a defined macro, return its definition node, else return NULL.  */
 cpp_macro *
 cpp_push_definition (cpp_reader *pfile, const char *str)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node && node->type == NT_MACRO)
     return node->value.macro;
   else
@@ -2258,7 +2339,7 @@
 void
 cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node == NULL)
     return;
 
Index: gcc/libcpp/internal.h
===================================================================
--- gcc.orig/libcpp/internal.h	2009-10-20 20:26:19.000000000 +0200
+++ gcc/libcpp/internal.h	2009-11-03 14:51:38.151000000 +0100
@@ -575,6 +575,7 @@
 extern cpp_token *_cpp_lex_direct (cpp_reader *);
 extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
+extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
Index: gcc/libcpp/lex.c
===================================================================
--- gcc.orig/libcpp/lex.c	2009-11-03 10:42:38.000000000 +0100
+++ gcc/libcpp/lex.c	2009-11-03 14:17:32.687000000 +0100
@@ -504,6 +504,62 @@
   return false;
 }
 
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base,
+		       struct normalize_state *nst)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+					      base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+			&& !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+	cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
+		   NODE_NAME (result));
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+	 replacement list of a variadic macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+	  && !pfile->state.va_args_ok)
+	cpp_error (pfile, CPP_DL_PEDWARN,
+		   "__VA_ARGS__ can only appear in the expansion"
+		   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+	cpp_error (pfile, CPP_DL_WARNING,
+		   "identifier \"%s\" is a special operator name in C++",
+		   NODE_NAME (result));
+    }
+
+  return result;
+}
+
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  struct normalize_state nst = INITIAL_NORMALIZE_STATE;
+  result = lex_identifier_intern (pfile, (uchar *) name, &nst);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
Index: gcc/gcc/c-pragma.c
===================================================================
--- gcc.orig/gcc/c-pragma.c	2009-11-03 14:54:12.000000000 +0100
+++ gcc/gcc/c-pragma.c	2009-11-03 14:59:03.856000000 +0100
@@ -243,144 +243,6 @@
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
-struct GTY(()) def_pragma_macro_value {
-  struct def_pragma_macro_value *prev;
-  cpp_macro *value;
-};
-
-struct GTY(()) def_pragma_macro {
-  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 *const a = (const struct def_pragma_macro *) pa,
-    *const b = (const struct def_pragma_macro *) 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 = (struct def_pragma_macro *) *slot;
-  if (c == NULL)
-    {
-      *slot = c = GGC_NEW (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_NEW (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 = NULL;
-
-  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;
-  if (pushed_macro_table)
-    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
-				     dummy.hash, NO_INSERT);
-  if (slot == NULL)
-    return;
-  c = (struct def_pragma_macro *) *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
@@ -1421,10 +1283,6 @@
   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
Index: gcc/gcc/config/i386/cygming.h
===================================================================
--- gcc.orig/gcc/config/i386/cygming.h	2009-10-20 21:45:24.000000000 +0200
+++ gcc/gcc/config/i386/cygming.h	2009-11-03 15:00:17.032000000 +0100
@@ -127,8 +127,6 @@
 \f
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
-/* Enable push_macro & pop_macro */
-#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c	2009-11-03 18:05:39.796000000 +0100
@@ -0,0 +1,15 @@
+extern void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by    moving it from C frontent into libcpp
  2009-11-03 17:09   ` Kai Tietz
@ 2009-11-03 17:25     ` Joseph S. Myers
  2009-11-03 17:32       ` Kai Tietz
  0 siblings, 1 reply; 19+ messages in thread
From: Joseph S. Myers @ 2009-11-03 17:25 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches

On Tue, 3 Nov 2009, Kai Tietz wrote:

> 2009-11-03  Kai Tietz  <kai.tietz@onevision.com>
> 
>         * gcc.c-torture/execute/pushpop_macro.c: New testcase.

You said things worked for C but were broken for C++.  Now you propose 
adding a C testcase.  Is this another case that was broken before but 
works after the patch?  Are there cases failing for C++ but not for C (if 
so, such a case should be added to the C++ testsuite)?

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-03 17:25     ` Joseph S. Myers
@ 2009-11-03 17:32       ` Kai Tietz
  0 siblings, 0 replies; 19+ messages in thread
From: Kai Tietz @ 2009-11-03 17:32 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 967 bytes --]

2009/11/3 Joseph S. Myers <joseph@codesourcery.com>:
> On Tue, 3 Nov 2009, Kai Tietz wrote:
>
>> 2009-11-03  Kai Tietz  <kai.tietz@onevision.com>
>>
>>         * gcc.c-torture/execute/pushpop_macro.c: New testcase.
>
> You said things worked for C but were broken for C++.  Now you propose
> adding a C testcase.  Is this another case that was broken before but
> works after the patch?  Are there cases failing for C++ but not for C (if
> so, such a case should be added to the C++ testsuite)?
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
>

Yes, you are right. The C++ case is necessary to show the issue for
the cygwin/mingw targets.

New patch contains test for C++, too.

ChangeLog

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

        * g++.dg/torture/pushpop_macro.C: New testcase.



Kai

-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: mvpushpop.diff --]
[-- Type: application/octet-stream, Size: 14097 bytes --]

Index: gcc/libcpp/directives.c
===================================================================
--- gcc.orig/libcpp/directives.c	2009-11-03 08:01:08.000000000 +0100
+++ gcc/libcpp/directives.c	2009-11-03 14:52:24.303000000 +0100
@@ -126,6 +126,8 @@
 static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
 static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
 static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -185,6 +187,14 @@
 #undef D
 #undef DIRECTIVE_TABLE
 
+struct def_pragma_macro {
+  struct def_pragma_macro *next;
+  char *name;
+  cpp_macro *value;
+};
+
+static struct def_pragma_macro *pushed_macro_table;
+
 /* Wrapper struct directive for linemarkers.
    The origin is more or less true - the original K+R cpp
    did use this notation in its preprocessed output.  */
@@ -1244,6 +1254,8 @@
 {
   /* Pragmas in the global namespace.  */
   register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+  register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
   register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
@@ -1423,6 +1435,92 @@
   _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *c;
+
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma push_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+  c = XNEW (struct def_pragma_macro);
+  c->name = XNEWVAR (char, strlen (macroname) + 1);
+  strcpy (c->name, macroname);
+  c->next = pushed_macro_table;
+  c->value = cpp_push_definition (pfile, c->name);
+  pushed_macro_table = c;
+}
+
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *l = NULL, *c = pushed_macro_table;
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma pop_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+
+  while (c != NULL)
+    {
+      if (!strcmp (c->name, macroname))
+	{
+	  if (!l)
+	    pushed_macro_table = c->next;
+	  else
+	    l->next = c->next;
+	  cpp_pop_definition (pfile, c->name, c->value);
+	  free (c->name);
+	  free (c);
+	  break;
+	}
+      l = c;
+      c = c->next;
+    }
+}
+
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
@@ -2225,28 +2323,11 @@
   run_directive (pfile, T_UNDEF, buf, len);
 }
 
-/* Like lex_macro_node, but read the input from STR.  */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
-  size_t len = strlen (str);
-  uchar *buf = (uchar *) alloca (len + 1);
-  cpp_hashnode *node;
-
-  memcpy (buf, str, len);
-  buf[len] = '\n';
-  cpp_push_buffer (pfile, buf, len, true);
-  node = lex_macro_node (pfile, true);
-  _cpp_pop_buffer (pfile);
-
-  return node;
-}
-
 /* If STR is a defined macro, return its definition node, else return NULL.  */
 cpp_macro *
 cpp_push_definition (cpp_reader *pfile, const char *str)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node && node->type == NT_MACRO)
     return node->value.macro;
   else
@@ -2258,7 +2339,7 @@
 void
 cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node == NULL)
     return;
 
Index: gcc/libcpp/internal.h
===================================================================
--- gcc.orig/libcpp/internal.h	2009-10-20 20:26:19.000000000 +0200
+++ gcc/libcpp/internal.h	2009-11-03 14:51:38.151000000 +0100
@@ -575,6 +575,7 @@
 extern cpp_token *_cpp_lex_direct (cpp_reader *);
 extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
+extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
Index: gcc/libcpp/lex.c
===================================================================
--- gcc.orig/libcpp/lex.c	2009-11-03 10:42:38.000000000 +0100
+++ gcc/libcpp/lex.c	2009-11-03 14:17:32.687000000 +0100
@@ -504,6 +504,62 @@
   return false;
 }
 
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base,
+		       struct normalize_state *nst)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+					      base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+			&& !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+	cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
+		   NODE_NAME (result));
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+	 replacement list of a variadic macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+	  && !pfile->state.va_args_ok)
+	cpp_error (pfile, CPP_DL_PEDWARN,
+		   "__VA_ARGS__ can only appear in the expansion"
+		   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+	cpp_error (pfile, CPP_DL_WARNING,
+		   "identifier \"%s\" is a special operator name in C++",
+		   NODE_NAME (result));
+    }
+
+  return result;
+}
+
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  struct normalize_state nst = INITIAL_NORMALIZE_STATE;
+  result = lex_identifier_intern (pfile, (uchar *) name, &nst);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
Index: gcc/gcc/c-pragma.c
===================================================================
--- gcc.orig/gcc/c-pragma.c	2009-11-03 14:54:12.000000000 +0100
+++ gcc/gcc/c-pragma.c	2009-11-03 14:59:03.856000000 +0100
@@ -243,144 +243,6 @@
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
-struct GTY(()) def_pragma_macro_value {
-  struct def_pragma_macro_value *prev;
-  cpp_macro *value;
-};
-
-struct GTY(()) def_pragma_macro {
-  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 *const a = (const struct def_pragma_macro *) pa,
-    *const b = (const struct def_pragma_macro *) 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 = (struct def_pragma_macro *) *slot;
-  if (c == NULL)
-    {
-      *slot = c = GGC_NEW (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_NEW (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 = NULL;
-
-  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;
-  if (pushed_macro_table)
-    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
-				     dummy.hash, NO_INSERT);
-  if (slot == NULL)
-    return;
-  c = (struct def_pragma_macro *) *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
@@ -1421,10 +1283,6 @@
   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
Index: gcc/gcc/config/i386/cygming.h
===================================================================
--- gcc.orig/gcc/config/i386/cygming.h	2009-10-20 21:45:24.000000000 +0200
+++ gcc/gcc/config/i386/cygming.h	2009-11-03 15:00:17.032000000 +0100
@@ -127,8 +127,6 @@
 \f
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
-/* Enable push_macro & pop_macro */
-#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c	2009-11-03 18:05:39.796000000 +0100
@@ -0,0 +1,15 @@
+extern void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C	2009-11-03 18:28:47.401000000 +0100
@@ -0,0 +1,20 @@
+/* Do the type-generic tests.  Unlike pr28796-2.c, we test these
+   without any fast-math flags.  */
+
+/* { dg-do run } */
+
+extern "C" void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by moving   it from C frontent into libcpp
  2009-11-03 15:13 [patch]: Add push_macro/pop_macro feature for all targets by moving it from C frontent into libcpp Kai Tietz
  2009-11-03 17:00 ` Joseph S. Myers
@ 2009-11-03 17:36 ` Tom Tromey
  2009-11-03 18:30   ` Kai Tietz
  1 sibling, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2009-11-03 17:36 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches

>>>>> "Kai" == Kai Tietz <ktietz70@googlemail.com> writes:

Kai> the current implementation of the push_macro/pop_macro feature for
Kai> windows targets was broken for C++ frontend and preprocessor. Just for
Kai> C it was working proper. So I would like to move this feature from C
Kai> frontend into libcpp as internal support pragma for all targets.

This plan sounds reasonable to me.

Kai> +static struct def_pragma_macro *pushed_macro_table;

This should be a field of struct cpp_reader, so that multiple readers
can be active at once.  Also, it should be freed when the reader is
destroyed.

Kai> +static void
Kai> +do_pragma_push_macro (cpp_reader *pfile)

This needs an introductory comment, as do the other new functions.

Kai> +      cpp_error (pfile, CPP_DL_ERROR,
Kai> +		 "invalid #pragma push_macro directive");

I would prefer that all new errors pass an explicit location.
This occurs a couple of times.

Tom

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-03 17:36 ` Tom Tromey
@ 2009-11-03 18:30   ` Kai Tietz
  2009-11-03 20:20     ` Kai Tietz
  0 siblings, 1 reply; 19+ messages in thread
From: Kai Tietz @ 2009-11-03 18:30 UTC (permalink / raw)
  To: tromey; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 1782 bytes --]

Hello Tom,

I reworked the patch as you suggested.

2009/11/3 Tom Tromey <tromey@redhat.com>:
> Kai> +      cpp_error (pfile, CPP_DL_ERROR,
> Kai> +           "invalid #pragma push_macro directive");
>
> I would prefer that all new errors pass an explicit location.
> This occurs a couple of times.
This is didn't got. What you mean here about explicit location? You
mean special messages for syntactical errors here?

ChangeLog for libcpp

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* directives.c (do_pragma_push_macro): New pragma handler.
	(do_pragma_pop_macro): Likewise.
	(_cpp_init_internal_pragmas): Add push_macro and
	pop_macro handler to internal pragmas.
	(lex_macro_node_from_str): Removed.
	(cpp_push_definition): Replace lex_macro_node_from_str
	by _cpp_lex_identifier.
	(cpp_pop_definition): Likewise.
	* internal.h (_cpp_lex_identifier): New prototype.
	(def_pragma_macro): New structure.
	(cpp_reader): New member pushed_macros.
	* lex.c (_cpp_lex_identifier): New function.
	(lex_identifier_intern): New function.
	* init.c (cpp_create_reader): Initialize pushed_macros
	member.
	(cpp_destroy): Free elements in pushed_macros member.

ChangeLog for gcc

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* config/i386/cygming.h (HANDLE_PRAGMA_PUSH_POP_MACRO):
	Removed.
	* c-pragma.c (def_pragma_macro_value): Likewise.
	(def_pragma_macro): Likewise.
	(pushed_macro_table): Likewise.
	(HANDLE_PRAGMA_PUSH_POP_MACRO): Remove guarded
	code.

ChangeLog for gcc/testsuite

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* g++.dg/torture/pushpop_macro.C: New testcase.
	* gcc.c-torture/execute/pushpop_macro.c: New testcase.


Kai

-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: mvpushpop.diff --]
[-- Type: application/octet-stream, Size: 15818 bytes --]

Index: gcc/libcpp/directives.c
===================================================================
--- gcc.orig/libcpp/directives.c	2009-11-03 08:01:08.000000000 +0100
+++ gcc/libcpp/directives.c	2009-11-03 19:12:17.696000000 +0100
@@ -126,6 +126,8 @@
 static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
 static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
 static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -1244,6 +1246,8 @@
 {
   /* Pragmas in the global namespace.  */
   register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+  register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
   register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
@@ -1423,6 +1427,94 @@
   _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
+/* Handle #pragma push_macro(STRING).  */
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *c;
+
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma push_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+  c = XNEW (struct def_pragma_macro);
+  c->name = XNEWVAR (char, strlen (macroname) + 1);
+  strcpy (c->name, macroname);
+  c->next = pfile->pushed_macros;
+  c->value = cpp_push_definition (pfile, c->name);
+  pfile->pushed_macros = c;
+}
+
+/* Handle #pragma pop_macro(STRING).  */
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *l = NULL, *c = pfile->pushed_macros;
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma pop_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+
+  while (c != NULL)
+    {
+      if (!strcmp (c->name, macroname))
+	{
+	  if (!l)
+	    pfile->pushed_macros = c->next;
+	  else
+	    l->next = c->next;
+	  cpp_pop_definition (pfile, c->name, c->value);
+	  free (c->name);
+	  free (c);
+	  break;
+	}
+      l = c;
+      c = c->next;
+    }
+}
+
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
@@ -2225,28 +2317,11 @@
   run_directive (pfile, T_UNDEF, buf, len);
 }
 
-/* Like lex_macro_node, but read the input from STR.  */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
-  size_t len = strlen (str);
-  uchar *buf = (uchar *) alloca (len + 1);
-  cpp_hashnode *node;
-
-  memcpy (buf, str, len);
-  buf[len] = '\n';
-  cpp_push_buffer (pfile, buf, len, true);
-  node = lex_macro_node (pfile, true);
-  _cpp_pop_buffer (pfile);
-
-  return node;
-}
-
 /* If STR is a defined macro, return its definition node, else return NULL.  */
 cpp_macro *
 cpp_push_definition (cpp_reader *pfile, const char *str)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node && node->type == NT_MACRO)
     return node->value.macro;
   else
@@ -2258,7 +2333,7 @@
 void
 cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node == NULL)
     return;
 
Index: gcc/libcpp/internal.h
===================================================================
--- gcc.orig/libcpp/internal.h	2009-10-20 20:26:19.000000000 +0200
+++ gcc/libcpp/internal.h	2009-11-03 18:46:54.053000000 +0100
@@ -305,6 +305,16 @@
   struct cset_converter input_cset_desc;
 };
 
+/* The list of saved macros by push_macro pragma.  */
+struct def_pragma_macro {
+  /* Chain element to previous saved macro.  */
+  struct def_pragma_macro *next;
+  /* Name of the macro.  */
+  char *name;
+  /* The stored macro content.  */
+  cpp_macro *value;
+};
+
 /* A cpp_reader encapsulates the "state" of a pre-processor run.
    Applying cpp_get_token repeatedly yields a stream of pre-processor
    tokens.  Usually, there is only one cpp_reader object active.  */
@@ -475,6 +485,9 @@
 
   /* Table of comments, when state.save_comments is true.  */
   cpp_comment_table comments;
+
+  /* List of saved macros by push_macro.  */
+  struct def_pragma_macro *pushed_macros;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
@@ -575,6 +588,7 @@
 extern cpp_token *_cpp_lex_direct (cpp_reader *);
 extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
+extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
Index: gcc/libcpp/lex.c
===================================================================
--- gcc.orig/libcpp/lex.c	2009-11-03 10:42:38.000000000 +0100
+++ gcc/libcpp/lex.c	2009-11-03 19:16:43.334000000 +0100
@@ -504,6 +504,65 @@
   return false;
 }
 
+/* Helper function to get the cpp_hashnode of the identifier BASE.  */
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base,
+		       struct normalize_state *nst)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+					      base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+			&& !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+	cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
+		   NODE_NAME (result));
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+	 replacement list of a variadic macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+	  && !pfile->state.va_args_ok)
+	cpp_error (pfile, CPP_DL_PEDWARN,
+		   "__VA_ARGS__ can only appear in the expansion"
+		   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+	cpp_error (pfile, CPP_DL_WARNING,
+		   "identifier \"%s\" is a special operator name in C++",
+		   NODE_NAME (result));
+    }
+
+  return result;
+}
+
+/* Get the cpp_hashnode of an identifier specified by NAME in
+   the current cpp_reader object.  If none is found, NULL is returned.  */
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  struct normalize_state nst = INITIAL_NORMALIZE_STATE;
+  result = lex_identifier_intern (pfile, (uchar *) name, &nst);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
Index: gcc/gcc/c-pragma.c
===================================================================
--- gcc.orig/gcc/c-pragma.c	2009-11-03 14:54:12.000000000 +0100
+++ gcc/gcc/c-pragma.c	2009-11-03 14:59:03.856000000 +0100
@@ -243,144 +243,6 @@
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
-struct GTY(()) def_pragma_macro_value {
-  struct def_pragma_macro_value *prev;
-  cpp_macro *value;
-};
-
-struct GTY(()) def_pragma_macro {
-  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 *const a = (const struct def_pragma_macro *) pa,
-    *const b = (const struct def_pragma_macro *) 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 = (struct def_pragma_macro *) *slot;
-  if (c == NULL)
-    {
-      *slot = c = GGC_NEW (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_NEW (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 = NULL;
-
-  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;
-  if (pushed_macro_table)
-    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
-				     dummy.hash, NO_INSERT);
-  if (slot == NULL)
-    return;
-  c = (struct def_pragma_macro *) *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
@@ -1421,10 +1283,6 @@
   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
Index: gcc/gcc/config/i386/cygming.h
===================================================================
--- gcc.orig/gcc/config/i386/cygming.h	2009-10-20 21:45:24.000000000 +0200
+++ gcc/gcc/config/i386/cygming.h	2009-11-03 15:00:17.032000000 +0100
@@ -127,8 +127,6 @@
 \f
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
-/* Enable push_macro & pop_macro */
-#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c	2009-11-03 18:05:39.796000000 +0100
@@ -0,0 +1,15 @@
+extern void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C	2009-11-03 18:28:47.401000000 +0100
@@ -0,0 +1,20 @@
+/* Do the type-generic tests.  Unlike pr28796-2.c, we test these
+   without any fast-math flags.  */
+
+/* { dg-do run } */
+
+extern "C" void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/libcpp/init.c
===================================================================
--- gcc.orig/libcpp/init.c	2009-06-14 15:38:51.000000000 +0200
+++ gcc/libcpp/init.c	2009-11-03 19:04:00.585000000 +0100
@@ -216,6 +216,9 @@
   pfile->a_buff = _cpp_get_buff (pfile, 0);
   pfile->u_buff = _cpp_get_buff (pfile, 0);
 
+  /* Initialize table for push_macro/pop_macro.  */
+  pfile->pushed_macros = 0;
+
   /* The expression parser stack.  */
   _cpp_expand_op_stack (pfile);
 
@@ -245,6 +248,7 @@
 cpp_destroy (cpp_reader *pfile)
 {
   cpp_context *context, *contextn;
+  struct def_pragma_macro *pmacro;
   tokenrun *run, *runn;
   int i;
 
@@ -296,6 +300,17 @@
 
       free (pfile->comments.entries);
     }
+  if (pfile->pushed_macros)
+    {
+      do
+	{
+	  pmacro = pfile->pushed_macros;
+	  pfile->pushed_macros = pmacro->next;
+	  free (pmacro->name);
+	  free (pmacro);
+	}
+      while (pfile->pushed_macros);
+    }
 
   free (pfile);
 }

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-03 18:30   ` Kai Tietz
@ 2009-11-03 20:20     ` Kai Tietz
  2009-11-04 16:25       ` Tom Tromey
  0 siblings, 1 reply; 19+ messages in thread
From: Kai Tietz @ 2009-11-03 20:20 UTC (permalink / raw)
  To: tromey; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 2663 bytes --]

2009/11/3 Kai Tietz <ktietz70@googlemail.com>:
> Hello Tom,
>
> I reworked the patch as you suggested.
>
> 2009/11/3 Tom Tromey <tromey@redhat.com>:
>> Kai> +      cpp_error (pfile, CPP_DL_ERROR,
>> Kai> +           "invalid #pragma push_macro directive");
>>
>> I would prefer that all new errors pass an explicit location.
>> This occurs a couple of times.
> This is didn't got. What you mean here about explicit location? You
> mean special messages for syntactical errors here?
>
> ChangeLog for libcpp
>
> 2009-11-03  Kai Tietz  <kai.tietz@onevision.com>
>
>        * directives.c (do_pragma_push_macro): New pragma handler.
>        (do_pragma_pop_macro): Likewise.
>        (_cpp_init_internal_pragmas): Add push_macro and
>        pop_macro handler to internal pragmas.
>        (lex_macro_node_from_str): Removed.
>        (cpp_push_definition): Replace lex_macro_node_from_str
>        by _cpp_lex_identifier.
>        (cpp_pop_definition): Likewise.
>        * internal.h (_cpp_lex_identifier): New prototype.
>        (def_pragma_macro): New structure.
>        (cpp_reader): New member pushed_macros.
>        * lex.c (_cpp_lex_identifier): New function.
>        (lex_identifier_intern): New function.
>        * init.c (cpp_create_reader): Initialize pushed_macros
>        member.
>        (cpp_destroy): Free elements in pushed_macros member.
>
> ChangeLog for gcc
>
> 2009-11-03  Kai Tietz  <kai.tietz@onevision.com>
>
>        * config/i386/cygming.h (HANDLE_PRAGMA_PUSH_POP_MACRO):
>        Removed.
>        * c-pragma.c (def_pragma_macro_value): Likewise.
>        (def_pragma_macro): Likewise.
>        (pushed_macro_table): Likewise.
>        (HANDLE_PRAGMA_PUSH_POP_MACRO): Remove guarded
>        code.
>
> ChangeLog for gcc/testsuite
>
> 2009-11-03  Kai Tietz  <kai.tietz@onevision.com>
>
>        * g++.dg/torture/pushpop_macro.C: New testcase.
>        * gcc.c-torture/execute/pushpop_macro.c: New testcase.
>
>
> Kai
>
> --
> |  (\_/) This is Bunny. Copy and paste
> | (='.'=) Bunny into your signature to help
> | (")_(") him gain world domination
>

By testing patch for i686-pc-linux, i686-pc-cygwin, i686-pc-mingw32,
and x86_64-pc-mingw32 I found two issues I corrected in this patch. In
function lex_identifier_intern I passed an unused argument, which I
removed in the attached patch. Also I corrected the starting comment
of the new C++ testcase, which was copy/pasted by accident.

Is this patch ok for apply?

Cheers,
Kai

-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: mvpushpop.diff --]
[-- Type: application/octet-stream, Size: 15668 bytes --]

Index: gcc/libcpp/directives.c
===================================================================
--- gcc.orig/libcpp/directives.c	2009-11-03 08:01:08.000000000 +0100
+++ gcc/libcpp/directives.c	2009-11-03 19:12:17.696000000 +0100
@@ -126,6 +126,8 @@
 static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
 static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
 static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -1244,6 +1246,8 @@
 {
   /* Pragmas in the global namespace.  */
   register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+  register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
   register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
@@ -1423,6 +1427,94 @@
   _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
+/* Handle #pragma push_macro(STRING).  */
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *c;
+
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma push_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+  c = XNEW (struct def_pragma_macro);
+  c->name = XNEWVAR (char, strlen (macroname) + 1);
+  strcpy (c->name, macroname);
+  c->next = pfile->pushed_macros;
+  c->value = cpp_push_definition (pfile, c->name);
+  pfile->pushed_macros = c;
+}
+
+/* Handle #pragma pop_macro(STRING).  */
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *l = NULL, *c = pfile->pushed_macros;
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma pop_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+
+  while (c != NULL)
+    {
+      if (!strcmp (c->name, macroname))
+	{
+	  if (!l)
+	    pfile->pushed_macros = c->next;
+	  else
+	    l->next = c->next;
+	  cpp_pop_definition (pfile, c->name, c->value);
+	  free (c->name);
+	  free (c);
+	  break;
+	}
+      l = c;
+      c = c->next;
+    }
+}
+
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
@@ -2225,28 +2317,11 @@
   run_directive (pfile, T_UNDEF, buf, len);
 }
 
-/* Like lex_macro_node, but read the input from STR.  */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
-  size_t len = strlen (str);
-  uchar *buf = (uchar *) alloca (len + 1);
-  cpp_hashnode *node;
-
-  memcpy (buf, str, len);
-  buf[len] = '\n';
-  cpp_push_buffer (pfile, buf, len, true);
-  node = lex_macro_node (pfile, true);
-  _cpp_pop_buffer (pfile);
-
-  return node;
-}
-
 /* If STR is a defined macro, return its definition node, else return NULL.  */
 cpp_macro *
 cpp_push_definition (cpp_reader *pfile, const char *str)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node && node->type == NT_MACRO)
     return node->value.macro;
   else
@@ -2258,7 +2333,7 @@
 void
 cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node == NULL)
     return;
 
Index: gcc/libcpp/internal.h
===================================================================
--- gcc.orig/libcpp/internal.h	2009-10-20 20:26:19.000000000 +0200
+++ gcc/libcpp/internal.h	2009-11-03 18:46:54.053000000 +0100
@@ -305,6 +305,16 @@
   struct cset_converter input_cset_desc;
 };
 
+/* The list of saved macros by push_macro pragma.  */
+struct def_pragma_macro {
+  /* Chain element to previous saved macro.  */
+  struct def_pragma_macro *next;
+  /* Name of the macro.  */
+  char *name;
+  /* The stored macro content.  */
+  cpp_macro *value;
+};
+
 /* A cpp_reader encapsulates the "state" of a pre-processor run.
    Applying cpp_get_token repeatedly yields a stream of pre-processor
    tokens.  Usually, there is only one cpp_reader object active.  */
@@ -475,6 +485,9 @@
 
   /* Table of comments, when state.save_comments is true.  */
   cpp_comment_table comments;
+
+  /* List of saved macros by push_macro.  */
+  struct def_pragma_macro *pushed_macros;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
@@ -575,6 +588,7 @@
 extern cpp_token *_cpp_lex_direct (cpp_reader *);
 extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
+extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
Index: gcc/libcpp/lex.c
===================================================================
--- gcc.orig/libcpp/lex.c	2009-11-03 10:42:38.000000000 +0100
+++ gcc/libcpp/lex.c	2009-11-03 21:11:46.305000000 +0100
@@ -504,6 +504,63 @@
   return false;
 }
 
+/* Helper function to get the cpp_hashnode of the identifier BASE.  */
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+					      base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+			&& !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+	cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
+		   NODE_NAME (result));
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+	 replacement list of a variadic macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+	  && !pfile->state.va_args_ok)
+	cpp_error (pfile, CPP_DL_PEDWARN,
+		   "__VA_ARGS__ can only appear in the expansion"
+		   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+	cpp_error (pfile, CPP_DL_WARNING,
+		   "identifier \"%s\" is a special operator name in C++",
+		   NODE_NAME (result));
+    }
+
+  return result;
+}
+
+/* Get the cpp_hashnode of an identifier specified by NAME in
+   the current cpp_reader object.  If none is found, NULL is returned.  */
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  result = lex_identifier_intern (pfile, (uchar *) name);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
Index: gcc/gcc/c-pragma.c
===================================================================
--- gcc.orig/gcc/c-pragma.c	2009-11-03 14:54:12.000000000 +0100
+++ gcc/gcc/c-pragma.c	2009-11-03 14:59:03.856000000 +0100
@@ -243,144 +243,6 @@
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
-struct GTY(()) def_pragma_macro_value {
-  struct def_pragma_macro_value *prev;
-  cpp_macro *value;
-};
-
-struct GTY(()) def_pragma_macro {
-  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 *const a = (const struct def_pragma_macro *) pa,
-    *const b = (const struct def_pragma_macro *) 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 = (struct def_pragma_macro *) *slot;
-  if (c == NULL)
-    {
-      *slot = c = GGC_NEW (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_NEW (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 = NULL;
-
-  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;
-  if (pushed_macro_table)
-    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
-				     dummy.hash, NO_INSERT);
-  if (slot == NULL)
-    return;
-  c = (struct def_pragma_macro *) *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
@@ -1421,10 +1283,6 @@
   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
Index: gcc/gcc/config/i386/cygming.h
===================================================================
--- gcc.orig/gcc/config/i386/cygming.h	2009-10-20 21:45:24.000000000 +0200
+++ gcc/gcc/config/i386/cygming.h	2009-11-03 15:00:17.032000000 +0100
@@ -127,8 +127,6 @@
 \f
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
-/* Enable push_macro & pop_macro */
-#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c	2009-11-03 18:05:39.796000000 +0100
@@ -0,0 +1,15 @@
+extern void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C	2009-11-03 21:13:24.154000000 +0100
@@ -0,0 +1,19 @@
+/* Do the preprocessor push_macro/pop_macro test.  */
+
+/* { dg-do run } */
+
+extern "C" void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/libcpp/init.c
===================================================================
--- gcc.orig/libcpp/init.c	2009-06-14 15:38:51.000000000 +0200
+++ gcc/libcpp/init.c	2009-11-03 19:04:00.585000000 +0100
@@ -216,6 +216,9 @@
   pfile->a_buff = _cpp_get_buff (pfile, 0);
   pfile->u_buff = _cpp_get_buff (pfile, 0);
 
+  /* Initialize table for push_macro/pop_macro.  */
+  pfile->pushed_macros = 0;
+
   /* The expression parser stack.  */
   _cpp_expand_op_stack (pfile);
 
@@ -245,6 +248,7 @@
 cpp_destroy (cpp_reader *pfile)
 {
   cpp_context *context, *contextn;
+  struct def_pragma_macro *pmacro;
   tokenrun *run, *runn;
   int i;
 
@@ -296,6 +300,17 @@
 
       free (pfile->comments.entries);
     }
+  if (pfile->pushed_macros)
+    {
+      do
+	{
+	  pmacro = pfile->pushed_macros;
+	  pfile->pushed_macros = pmacro->next;
+	  free (pmacro->name);
+	  free (pmacro);
+	}
+      while (pfile->pushed_macros);
+    }
 
   free (pfile);
 }

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by  moving it from C frontent into libcpp
  2009-11-03 20:20     ` Kai Tietz
@ 2009-11-04 16:25       ` Tom Tromey
  2009-11-04 17:05         ` Kai Tietz
                           ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Tom Tromey @ 2009-11-04 16:25 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches

>>>>> "Kai" == Kai Tietz <ktietz70@googlemail.com> writes:

Tom> I would prefer that all new errors pass an explicit location.
Tom> This occurs a couple of times.

Kai> This is didn't got. What you mean here about explicit location? You
Kai> mean special messages for syntactical errors here?

What I meant is, for a new error, use the cpp_error_with_line function
and pass in the proper location explicitly.  Sometimes (I didn't check
this code) this is not easy, in which case it is ok to skip it.

Kai> -/* Like lex_macro_node, but read the input from STR.  */
Kai> -static cpp_hashnode *
Kai> -lex_macro_node_from_str (cpp_reader *pfile, const char *str)

What is the rationale for this part of the change?

Kai> -static GTY((param_is (struct def_pragma_macro))) htab_t pushed_macro_table;

Do pushed macros work properly with PCH after this patch?

This is looking pretty good.

Tom

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-04 16:25       ` Tom Tromey
@ 2009-11-04 17:05         ` Kai Tietz
  2009-11-04 18:13           ` Dave Korn
  2009-11-05 10:46         ` Kai Tietz
  2009-11-05 16:23         ` Paolo Bonzini
  2 siblings, 1 reply; 19+ messages in thread
From: Kai Tietz @ 2009-11-04 17:05 UTC (permalink / raw)
  To: Tom Tromey; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 2906 bytes --]

2009/11/4 Tom Tromey <tromey@redhat.com>:
>>>>>> "Kai" == Kai Tietz <ktietz70@googlemail.com> writes:
>
> Tom> I would prefer that all new errors pass an explicit location.
> Tom> This occurs a couple of times.
>
> Kai> This is didn't got. What you mean here about explicit location? You
> Kai> mean special messages for syntactical errors here?
>
> What I meant is, for a new error, use the cpp_error_with_line function
> and pass in the proper location explicitly.  Sometimes (I didn't check
> this code) this is not easy, in which case it is ok to skip it.
>
> Kai> -/* Like lex_macro_node, but read the input from STR.  */
> Kai> -static cpp_hashnode *
> Kai> -lex_macro_node_from_str (cpp_reader *pfile, const char *str)
>
> What is the rationale for this part of the change?

The issue I had here was, that the old code wasn't usable within the
pragma parsing. As I use the internal identifier lex function for
getting the cpp_hashnode for an name, this static function was simply
not used anymore.

> Kai> -static GTY((param_is (struct def_pragma_macro))) htab_t pushed_macro_table;
>
> Do pushed macros work properly with PCH after this patch?

As far as my test have shown for i686-pc-linux, it works now pretty well.

> This is looking pretty good.
>
> Tom
>

I added to the patch the cleanup of the tm.texi part about target
macro HANDLE_PRAGMA_PUSH_POP_MACRO,

ChangeLog for libcpp

2009-11-04  Kai Tietz  <kai.tietz@onevision.com>

	* directives.c (do_pragma_push_macro): New pragma handler.
	(do_pragma_pop_macro): Likewise.
	(_cpp_init_internal_pragmas): Add push_macro and
	pop_macro handler to internal pragmas.
	(lex_macro_node_from_str): Removed.
	(cpp_push_definition): Replace lex_macro_node_from_str
	by _cpp_lex_identifier.
	(cpp_pop_definition): Likewise.
	* internal.h (_cpp_lex_identifier): New prototype.
	(def_pragma_macro): New structure.
	(cpp_reader): New member pushed_macros.
	* lex.c (_cpp_lex_identifier): New function.
	(lex_identifier_intern): New function.
	* init.c (cpp_create_reader): Initialize pushed_macros
	member.
	(cpp_destroy): Free elements in pushed_macros member.

ChangeLog for gcc

2009-11-04  Kai Tietz  <kai.tietz@onevision.com>

	* config/i386/cygming.h (HANDLE_PRAGMA_PUSH_POP_MACRO):
	Removed.
	* c-pragma.c (def_pragma_macro_value): Likewise.
	(def_pragma_macro): Likewise.
	(pushed_macro_table): Likewise.
	(HANDLE_PRAGMA_PUSH_POP_MACRO): Remove guarded
	code.
	* doc/tm.texi (HANDLE_PRAGMA_PUSH_POP_MACRO):
	Removed.

ChangeLog for gcc/testsuite

2009-11-04  Kai Tietz  <kai.tietz@onevision.com>

	* g++.dg/torture/pushpop_macro.C: New testcase.
	* gcc.c-torture/execute/pushpop_macro.c: New testcase.


Ok for apply?

Cheers,
Kai

-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: mvpushpop.diff --]
[-- Type: application/octet-stream, Size: 16584 bytes --]

Index: gcc/libcpp/directives.c
===================================================================
--- gcc.orig/libcpp/directives.c	2009-11-04 07:57:26.395597000 +0100
+++ gcc/libcpp/directives.c	2009-11-04 08:42:54.018597000 +0100
@@ -126,6 +126,8 @@
 static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
 static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
 static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -1244,6 +1246,8 @@
 {
   /* Pragmas in the global namespace.  */
   register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+  register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
   register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
@@ -1423,6 +1427,94 @@
   _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
+/* Handle #pragma push_macro(STRING).  */
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *c;
+
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma push_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+  c = XNEW (struct def_pragma_macro);
+  c->name = XNEWVAR (char, strlen (macroname) + 1);
+  strcpy (c->name, macroname);
+  c->next = pfile->pushed_macros;
+  c->value = cpp_push_definition (pfile, c->name);
+  pfile->pushed_macros = c;
+}
+
+/* Handle #pragma pop_macro(STRING).  */
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *l = NULL, *c = pfile->pushed_macros;
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      cpp_error (pfile, CPP_DL_ERROR,
+		 "invalid #pragma pop_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+
+  while (c != NULL)
+    {
+      if (!strcmp (c->name, macroname))
+	{
+	  if (!l)
+	    pfile->pushed_macros = c->next;
+	  else
+	    l->next = c->next;
+	  cpp_pop_definition (pfile, c->name, c->value);
+	  free (c->name);
+	  free (c);
+	  break;
+	}
+      l = c;
+      c = c->next;
+    }
+}
+
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
@@ -2225,28 +2317,11 @@
   run_directive (pfile, T_UNDEF, buf, len);
 }
 
-/* Like lex_macro_node, but read the input from STR.  */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
-  size_t len = strlen (str);
-  uchar *buf = (uchar *) alloca (len + 1);
-  cpp_hashnode *node;
-
-  memcpy (buf, str, len);
-  buf[len] = '\n';
-  cpp_push_buffer (pfile, buf, len, true);
-  node = lex_macro_node (pfile, true);
-  _cpp_pop_buffer (pfile);
-
-  return node;
-}
-
 /* If STR is a defined macro, return its definition node, else return NULL.  */
 cpp_macro *
 cpp_push_definition (cpp_reader *pfile, const char *str)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node && node->type == NT_MACRO)
     return node->value.macro;
   else
@@ -2258,7 +2333,7 @@
 void
 cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node == NULL)
     return;
 
Index: gcc/libcpp/internal.h
===================================================================
--- gcc.orig/libcpp/internal.h	2009-11-04 07:57:26.400597000 +0100
+++ gcc/libcpp/internal.h	2009-11-04 08:42:54.027597000 +0100
@@ -305,6 +305,16 @@
   struct cset_converter input_cset_desc;
 };
 
+/* The list of saved macros by push_macro pragma.  */
+struct def_pragma_macro {
+  /* Chain element to previous saved macro.  */
+  struct def_pragma_macro *next;
+  /* Name of the macro.  */
+  char *name;
+  /* The stored macro content.  */
+  cpp_macro *value;
+};
+
 /* A cpp_reader encapsulates the "state" of a pre-processor run.
    Applying cpp_get_token repeatedly yields a stream of pre-processor
    tokens.  Usually, there is only one cpp_reader object active.  */
@@ -475,6 +485,9 @@
 
   /* Table of comments, when state.save_comments is true.  */
   cpp_comment_table comments;
+
+  /* List of saved macros by push_macro.  */
+  struct def_pragma_macro *pushed_macros;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
@@ -575,6 +588,7 @@
 extern cpp_token *_cpp_lex_direct (cpp_reader *);
 extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
+extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
Index: gcc/libcpp/lex.c
===================================================================
--- gcc.orig/libcpp/lex.c	2009-11-04 07:57:26.402597000 +0100
+++ gcc/libcpp/lex.c	2009-11-04 08:42:54.034597000 +0100
@@ -504,6 +504,63 @@
   return false;
 }
 
+/* Helper function to get the cpp_hashnode of the identifier BASE.  */
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+					      base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+			&& !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+	cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
+		   NODE_NAME (result));
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+	 replacement list of a variadic macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+	  && !pfile->state.va_args_ok)
+	cpp_error (pfile, CPP_DL_PEDWARN,
+		   "__VA_ARGS__ can only appear in the expansion"
+		   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+	cpp_error (pfile, CPP_DL_WARNING,
+		   "identifier \"%s\" is a special operator name in C++",
+		   NODE_NAME (result));
+    }
+
+  return result;
+}
+
+/* Get the cpp_hashnode of an identifier specified by NAME in
+   the current cpp_reader object.  If none is found, NULL is returned.  */
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  result = lex_identifier_intern (pfile, (uchar *) name);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
Index: gcc/gcc/c-pragma.c
===================================================================
--- gcc.orig/gcc/c-pragma.c	2009-11-04 07:57:26.319597000 +0100
+++ gcc/gcc/c-pragma.c	2009-11-04 08:42:54.058597000 +0100
@@ -243,144 +243,6 @@
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
-struct GTY(()) def_pragma_macro_value {
-  struct def_pragma_macro_value *prev;
-  cpp_macro *value;
-};
-
-struct GTY(()) def_pragma_macro {
-  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 *const a = (const struct def_pragma_macro *) pa,
-    *const b = (const struct def_pragma_macro *) 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 = (struct def_pragma_macro *) *slot;
-  if (c == NULL)
-    {
-      *slot = c = GGC_NEW (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_NEW (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 = NULL;
-
-  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;
-  if (pushed_macro_table)
-    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
-				     dummy.hash, NO_INSERT);
-  if (slot == NULL)
-    return;
-  c = (struct def_pragma_macro *) *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
@@ -1421,10 +1283,6 @@
   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
Index: gcc/gcc/config/i386/cygming.h
===================================================================
--- gcc.orig/gcc/config/i386/cygming.h	2009-11-04 07:57:26.324597000 +0100
+++ gcc/gcc/config/i386/cygming.h	2009-11-04 08:42:54.081597000 +0100
@@ -127,8 +127,6 @@
 \f
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
-/* Enable push_macro & pop_macro */
-#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c	2009-11-04 08:42:54.092597000 +0100
@@ -0,0 +1,15 @@
+extern void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C	2009-11-04 08:42:54.101597000 +0100
@@ -0,0 +1,19 @@
+/* Do the preprocessor push_macro/pop_macro test.  */
+
+/* { dg-do run } */
+
+extern "C" void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/libcpp/init.c
===================================================================
--- gcc.orig/libcpp/init.c	2009-11-04 07:57:26.398597000 +0100
+++ gcc/libcpp/init.c	2009-11-04 08:42:54.116597000 +0100
@@ -216,6 +216,9 @@
   pfile->a_buff = _cpp_get_buff (pfile, 0);
   pfile->u_buff = _cpp_get_buff (pfile, 0);
 
+  /* Initialize table for push_macro/pop_macro.  */
+  pfile->pushed_macros = 0;
+
   /* The expression parser stack.  */
   _cpp_expand_op_stack (pfile);
 
@@ -245,6 +248,7 @@
 cpp_destroy (cpp_reader *pfile)
 {
   cpp_context *context, *contextn;
+  struct def_pragma_macro *pmacro;
   tokenrun *run, *runn;
   int i;
 
@@ -296,6 +300,17 @@
 
       free (pfile->comments.entries);
     }
+  if (pfile->pushed_macros)
+    {
+      do
+	{
+	  pmacro = pfile->pushed_macros;
+	  pfile->pushed_macros = pmacro->next;
+	  free (pmacro->name);
+	  free (pmacro);
+	}
+      while (pfile->pushed_macros);
+    }
 
   free (pfile);
 }
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi	2009-11-04 08:01:02.000000000 +0100
+++ gcc/gcc/doc/tm.texi	2009-11-04 08:44:55.617597000 +0100
@@ -10476,18 +10476,6 @@
 @samp{#pragma pack()} (that is, a small power of two).
 @end defmac
 
-@findex #pragma
-@findex pragma
-@defmac HANDLE_PRAGMA_PUSH_POP_MACRO
-Define this macro if you want to support the Win32 style pragmas
-@samp{#pragma push_macro(macro-name-as-string)} and @samp{#pragma
-pop_macro(macro-name-as-string)}.  The @samp{#pragma push_macro(
-macro-name-as-string)} pragma saves the named macro and via
-@samp{#pragma pop_macro(macro-name-as-string)} it will return to the
-previous value.
-@end defmac
-
-
 @defmac DOLLARS_IN_IDENTIFIERS
 Define this macro to control use of the character @samp{$} in
 identifier names for the C family of languages.  0 means @samp{$} is

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by    moving it from C frontent into libcpp
  2009-11-04 17:05         ` Kai Tietz
@ 2009-11-04 18:13           ` Dave Korn
  2009-11-04 18:18             ` Kai Tietz
  0 siblings, 1 reply; 19+ messages in thread
From: Dave Korn @ 2009-11-04 18:13 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Tom Tromey, GCC Patches

Kai Tietz wrote:

> ChangeLog for gcc/testsuite
> 
> 2009-11-04  Kai Tietz  <kai.tietz@onevision.com>
> 
> 	* g++.dg/torture/pushpop_macro.C: New testcase.
> 	* gcc.c-torture/execute/pushpop_macro.c: New testcase.

  We have a C and C++ common dir in the testsuite now, I think you could
probably just put one copy of the testcase in there?  Not sure if it does
execute tests or just compile tests, but in that case you could just tweak the
testcase so that instead of defining the underscore to 2 or 1, you could
define it to 2 or something that creates a syntax or link error.

     cheers,
      DaveK



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-04 18:13           ` Dave Korn
@ 2009-11-04 18:18             ` Kai Tietz
  0 siblings, 0 replies; 19+ messages in thread
From: Kai Tietz @ 2009-11-04 18:18 UTC (permalink / raw)
  To: Dave Korn; +Cc: Tom Tromey, GCC Patches

2009/11/4 Dave Korn <dave.korn.cygwin@googlemail.com>:
> Kai Tietz wrote:
>
>> ChangeLog for gcc/testsuite
>>
>> 2009-11-04  Kai Tietz  <kai.tietz@onevision.com>
>>
>>       * g++.dg/torture/pushpop_macro.C: New testcase.
>>       * gcc.c-torture/execute/pushpop_macro.c: New testcase.
>
>  We have a C and C++ common dir in the testsuite now, I think you could
> probably just put one copy of the testcase in there?  Not sure if it does
> execute tests or just compile tests, but in that case you could just tweak the
> testcase so that instead of defining the underscore to 2 or 1, you could
> define it to 2 or something that creates a syntax or link error.
>
>     cheers,
>      DaveK

Well, as this feature is more or less IMHO a torture testcase and the
C and C++ cases are different, as exactly at the moment we have a
working C version, but C++ fails badly, I think they are well placed
where they are. If it would be better to make out of those testcase
compile-only tests is IMHO more an esthetically question.
But good to know that there is now a common C/C++ directory. Thanks
for this head up.

Cheers,
Kai


-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-04 16:25       ` Tom Tromey
  2009-11-04 17:05         ` Kai Tietz
@ 2009-11-05 10:46         ` Kai Tietz
  2009-11-05 16:23         ` Paolo Bonzini
  2 siblings, 0 replies; 19+ messages in thread
From: Kai Tietz @ 2009-11-05 10:46 UTC (permalink / raw)
  To: Tom Tromey; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 2729 bytes --]

2009/11/4 Tom Tromey <tromey@redhat.com>:
>>>>>> "Kai" == Kai Tietz <ktietz70@googlemail.com> writes:
>
> Tom> I would prefer that all new errors pass an explicit location.
> Tom> This occurs a couple of times.
>
> Kai> This is didn't got. What you mean here about explicit location? You
> Kai> mean special messages for syntactical errors here?
>
> What I meant is, for a new error, use the cpp_error_with_line function
> and pass in the proper location explicitly.  Sometimes (I didn't check
> this code) this is not easy, in which case it is ok to skip it.
>
> Kai> -/* Like lex_macro_node, but read the input from STR.  */
> Kai> -static cpp_hashnode *
> Kai> -lex_macro_node_from_str (cpp_reader *pfile, const char *str)
>
> What is the rationale for this part of the change?
>
> Kai> -static GTY((param_is (struct def_pragma_macro))) htab_t pushed_macro_table;
>
> Do pushed macros work properly with PCH after this patch?
>
> This is looking pretty good.
>
> Tom
>

I changed the error output from cpp_error to cpp_error_with_line as
you suggested. And it works pretty well.

ChangeLog for libcpp

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* directives.c (do_pragma_push_macro): New pragma handler.
	(do_pragma_pop_macro): Likewise.
	(_cpp_init_internal_pragmas): Add push_macro and
	pop_macro handler to internal pragmas.
	(lex_macro_node_from_str): Removed.
	(cpp_push_definition): Replace lex_macro_node_from_str
	by _cpp_lex_identifier.
	(cpp_pop_definition): Likewise.
	* internal.h (_cpp_lex_identifier): New prototype.
	(def_pragma_macro): New structure.
	(cpp_reader): New member pushed_macros.
	* lex.c (_cpp_lex_identifier): New function.
	(lex_identifier_intern): New function.
	* init.c (cpp_create_reader): Initialize pushed_macros
	member.
	(cpp_destroy): Free elements in pushed_macros member.

ChangeLog for gcc

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* config/i386/cygming.h (HANDLE_PRAGMA_PUSH_POP_MACRO):
	Removed.
	* c-pragma.c (def_pragma_macro_value): Likewise.
	(def_pragma_macro): Likewise.
	(pushed_macro_table): Likewise.
	(HANDLE_PRAGMA_PUSH_POP_MACRO): Remove guarded
	code.
	* doc/tm.texi (HANDLE_PRAGMA_PUSH_POP_MACRO):
	Removed.

ChangeLog for gcc/testsuite

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* g++.dg/torture/pushpop_macro.C: New testcase.
	* gcc.c-torture/execute/pushpop_macro.c: New testcase.

Tested for i686-pc-linux, i686-pc-mingw32, and x86_64-pc-mingw32. Ok
for apply to trunk? And possibly a back-merge to 4.4 branch, too?

Cheers,
Kai

-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: mvpushpop.diff --]
[-- Type: application/octet-stream, Size: 16754 bytes --]

Index: gcc/libcpp/directives.c
===================================================================
--- gcc.orig/libcpp/directives.c	2009-11-04 19:28:54.497097000 +0100
+++ gcc/libcpp/directives.c	2009-11-05 11:10:00.872800600 +0100
@@ -126,6 +126,8 @@
 static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
 static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
 static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -1244,6 +1246,8 @@
 {
   /* Pragmas in the global namespace.  */
   register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+  register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
   register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
@@ -1423,6 +1427,96 @@
   _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
+/* Handle #pragma push_macro(STRING).  */
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *c;
+
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      source_location src_loc = pfile->cur_token[-1].src_loc;
+      cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+		 "invalid #pragma push_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+  c = XNEW (struct def_pragma_macro);
+  c->name = XNEWVAR (char, strlen (macroname) + 1);
+  strcpy (c->name, macroname);
+  c->next = pfile->pushed_macros;
+  c->value = cpp_push_definition (pfile, c->name);
+  pfile->pushed_macros = c;
+}
+
+/* Handle #pragma pop_macro(STRING).  */
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *l = NULL, *c = pfile->pushed_macros;
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      source_location src_loc = pfile->cur_token[-1].src_loc;
+      cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+		 "invalid #pragma pop_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+
+  while (c != NULL)
+    {
+      if (!strcmp (c->name, macroname))
+	{
+	  if (!l)
+	    pfile->pushed_macros = c->next;
+	  else
+	    l->next = c->next;
+	  cpp_pop_definition (pfile, c->name, c->value);
+	  free (c->name);
+	  free (c);
+	  break;
+	}
+      l = c;
+      c = c->next;
+    }
+}
+
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
@@ -2225,28 +2319,11 @@
   run_directive (pfile, T_UNDEF, buf, len);
 }
 
-/* Like lex_macro_node, but read the input from STR.  */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
-  size_t len = strlen (str);
-  uchar *buf = (uchar *) alloca (len + 1);
-  cpp_hashnode *node;
-
-  memcpy (buf, str, len);
-  buf[len] = '\n';
-  cpp_push_buffer (pfile, buf, len, true);
-  node = lex_macro_node (pfile, true);
-  _cpp_pop_buffer (pfile);
-
-  return node;
-}
-
 /* If STR is a defined macro, return its definition node, else return NULL.  */
 cpp_macro *
 cpp_push_definition (cpp_reader *pfile, const char *str)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node && node->type == NT_MACRO)
     return node->value.macro;
   else
@@ -2258,7 +2335,7 @@
 void
 cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node == NULL)
     return;
 
Index: gcc/libcpp/internal.h
===================================================================
--- gcc.orig/libcpp/internal.h	2009-11-04 19:28:54.502097000 +0100
+++ gcc/libcpp/internal.h	2009-11-04 20:46:54.779097100 +0100
@@ -305,6 +305,16 @@
   struct cset_converter input_cset_desc;
 };
 
+/* The list of saved macros by push_macro pragma.  */
+struct def_pragma_macro {
+  /* Chain element to previous saved macro.  */
+  struct def_pragma_macro *next;
+  /* Name of the macro.  */
+  char *name;
+  /* The stored macro content.  */
+  cpp_macro *value;
+};
+
 /* A cpp_reader encapsulates the "state" of a pre-processor run.
    Applying cpp_get_token repeatedly yields a stream of pre-processor
    tokens.  Usually, there is only one cpp_reader object active.  */
@@ -475,6 +485,9 @@
 
   /* Table of comments, when state.save_comments is true.  */
   cpp_comment_table comments;
+
+  /* List of saved macros by push_macro.  */
+  struct def_pragma_macro *pushed_macros;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
@@ -575,6 +588,7 @@
 extern cpp_token *_cpp_lex_direct (cpp_reader *);
 extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
+extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
Index: gcc/libcpp/lex.c
===================================================================
--- gcc.orig/libcpp/lex.c	2009-11-04 19:28:54.507097000 +0100
+++ gcc/libcpp/lex.c	2009-11-04 20:46:54.785097100 +0100
@@ -504,6 +504,63 @@
   return false;
 }
 
+/* Helper function to get the cpp_hashnode of the identifier BASE.  */
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+					      base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+			&& !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+	cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
+		   NODE_NAME (result));
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+	 replacement list of a variadic macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+	  && !pfile->state.va_args_ok)
+	cpp_error (pfile, CPP_DL_PEDWARN,
+		   "__VA_ARGS__ can only appear in the expansion"
+		   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+	cpp_error (pfile, CPP_DL_WARNING,
+		   "identifier \"%s\" is a special operator name in C++",
+		   NODE_NAME (result));
+    }
+
+  return result;
+}
+
+/* Get the cpp_hashnode of an identifier specified by NAME in
+   the current cpp_reader object.  If none is found, NULL is returned.  */
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  result = lex_identifier_intern (pfile, (uchar *) name);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
Index: gcc/gcc/c-pragma.c
===================================================================
--- gcc.orig/gcc/c-pragma.c	2009-11-04 19:28:54.471097000 +0100
+++ gcc/gcc/c-pragma.c	2009-11-04 20:46:54.790097100 +0100
@@ -243,144 +243,6 @@
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
-struct GTY(()) def_pragma_macro_value {
-  struct def_pragma_macro_value *prev;
-  cpp_macro *value;
-};
-
-struct GTY(()) def_pragma_macro {
-  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 *const a = (const struct def_pragma_macro *) pa,
-    *const b = (const struct def_pragma_macro *) 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 = (struct def_pragma_macro *) *slot;
-  if (c == NULL)
-    {
-      *slot = c = GGC_NEW (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_NEW (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 = NULL;
-
-  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;
-  if (pushed_macro_table)
-    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
-				     dummy.hash, NO_INSERT);
-  if (slot == NULL)
-    return;
-  c = (struct def_pragma_macro *) *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
@@ -1421,10 +1283,6 @@
   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
Index: gcc/gcc/config/i386/cygming.h
===================================================================
--- gcc.orig/gcc/config/i386/cygming.h	2009-11-04 19:28:54.476097000 +0100
+++ gcc/gcc/config/i386/cygming.h	2009-11-04 20:46:54.795097100 +0100
@@ -127,8 +127,6 @@
 \f
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
-/* Enable push_macro & pop_macro */
-#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c	2009-11-04 20:46:54.805097100 +0100
@@ -0,0 +1,15 @@
+extern void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C	2009-11-04 20:46:54.814097100 +0100
@@ -0,0 +1,19 @@
+/* Do the preprocessor push_macro/pop_macro test.  */
+
+/* { dg-do run } */
+
+extern "C" void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/libcpp/init.c
===================================================================
--- gcc.orig/libcpp/init.c	2009-11-04 19:28:54.499097000 +0100
+++ gcc/libcpp/init.c	2009-11-04 20:46:54.820097100 +0100
@@ -216,6 +216,9 @@
   pfile->a_buff = _cpp_get_buff (pfile, 0);
   pfile->u_buff = _cpp_get_buff (pfile, 0);
 
+  /* Initialize table for push_macro/pop_macro.  */
+  pfile->pushed_macros = 0;
+
   /* The expression parser stack.  */
   _cpp_expand_op_stack (pfile);
 
@@ -245,6 +248,7 @@
 cpp_destroy (cpp_reader *pfile)
 {
   cpp_context *context, *contextn;
+  struct def_pragma_macro *pmacro;
   tokenrun *run, *runn;
   int i;
 
@@ -296,6 +300,17 @@
 
       free (pfile->comments.entries);
     }
+  if (pfile->pushed_macros)
+    {
+      do
+	{
+	  pmacro = pfile->pushed_macros;
+	  pfile->pushed_macros = pmacro->next;
+	  free (pmacro->name);
+	  free (pmacro);
+	}
+      while (pfile->pushed_macros);
+    }
 
   free (pfile);
 }
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi	2009-11-04 19:28:54.480097000 +0100
+++ gcc/gcc/doc/tm.texi	2009-11-04 20:46:54.833097100 +0100
@@ -10476,18 +10476,6 @@
 @samp{#pragma pack()} (that is, a small power of two).
 @end defmac
 
-@findex #pragma
-@findex pragma
-@defmac HANDLE_PRAGMA_PUSH_POP_MACRO
-Define this macro if you want to support the Win32 style pragmas
-@samp{#pragma push_macro(macro-name-as-string)} and @samp{#pragma
-pop_macro(macro-name-as-string)}.  The @samp{#pragma push_macro(
-macro-name-as-string)} pragma saves the named macro and via
-@samp{#pragma pop_macro(macro-name-as-string)} it will return to the
-previous value.
-@end defmac
-
-
 @defmac DOLLARS_IN_IDENTIFIERS
 Define this macro to control use of the character @samp{$} in
 identifier names for the C family of languages.  0 means @samp{$} is

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-04 16:25       ` Tom Tromey
  2009-11-04 17:05         ` Kai Tietz
  2009-11-05 10:46         ` Kai Tietz
@ 2009-11-05 16:23         ` Paolo Bonzini
  2009-11-05 22:11           ` Kai Tietz
  2 siblings, 1 reply; 19+ messages in thread
From: Paolo Bonzini @ 2009-11-05 16:23 UTC (permalink / raw)
  To: gcc-patches

On 11/04/2009 05:25 PM, Tom Tromey wrote:
> Kai>  -static GTY((param_is (struct def_pragma_macro))) htab_t pushed_macro_table;
>
> Do pushed macros work properly with PCH after this patch?

I don't think so.  There is nothing that saves the state, so placing

--- test.h ---
#define FOO bar
#pragma push_macro("FOO")
#define FOO baz

--- test.c ---
#include "test.h"
#pragma pop_macro("FOO")


would fail because pop_macro would not find FOO on the stack.  It is 
extremely unlikely to happen in practice, but it is still a bug.  You 
need to modify libcpp/pch.c to fix this.

Paolo

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-05 16:23         ` Paolo Bonzini
@ 2009-11-05 22:11           ` Kai Tietz
  2009-11-06  9:39             ` Kai Tietz
  0 siblings, 1 reply; 19+ messages in thread
From: Kai Tietz @ 2009-11-05 22:11 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2684 bytes --]

2009/11/5 Paolo Bonzini <bonzini@gnu.org>:
> On 11/04/2009 05:25 PM, Tom Tromey wrote:
>>
>> Kai>  -static GTY((param_is (struct def_pragma_macro))) htab_t
>> pushed_macro_table;
>>
>> Do pushed macros work properly with PCH after this patch?
>
> I don't think so.  There is nothing that saves the state, so placing
>
> --- test.h ---
> #define FOO bar
> #pragma push_macro("FOO")
> #define FOO baz
>
> --- test.c ---
> #include "test.h"
> #pragma pop_macro("FOO")
>
>
> would fail because pop_macro would not find FOO on the stack.  It is
> extremely unlikely to happen in practice, but it is still a bug.  You need
> to modify libcpp/pch.c to fix this.
>
> Paolo
>
>

Thanks Paolo for pointing this out. It is right that this case should
be extremely unlikely, but it would be a bug too. So here the patch
treating the pch case, too.

ChangeLog for libcpp

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* directives.c (do_pragma_push_macro): New pragma handler.
	(do_pragma_pop_macro): Likewise.
	(_cpp_init_internal_pragmas): Add push_macro and
	pop_macro handler to internal pragmas.
	(lex_macro_node_from_str): Removed.
	(cpp_push_definition): Replace lex_macro_node_from_str
	by _cpp_lex_identifier.
	(cpp_pop_definition): Likewise.
	* internal.h (_cpp_lex_identifier): New prototype.
	(def_pragma_macro): New structure.
	(cpp_reader): New member pushed_macros.
	* lex.c (_cpp_lex_identifier): New function.
	(lex_identifier_intern): New function.
	* init.c (cpp_create_reader): Initialize pushed_macros
	member.
	(cpp_destroy): Free elements in pushed_macros member.
	* pch.c (_cpp_save_pushed_macros): New function.
	(_cpp_restore_pushed_macros): Likewise.
	(_cpp_restore_pushed_macros): Use _cpp_restore_pushed_macros.
	(cpp_read_state): Use _cpp_save_pushed_macros.

ChangeLog for gcc

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* config/i386/cygming.h (HANDLE_PRAGMA_PUSH_POP_MACRO):
	Removed.
	* c-pragma.c (def_pragma_macro_value): Likewise.
	(def_pragma_macro): Likewise.
	(pushed_macro_table): Likewise.
	(HANDLE_PRAGMA_PUSH_POP_MACRO): Remove guarded
	code.
	* doc/tm.texi (HANDLE_PRAGMA_PUSH_POP_MACRO):
	Removed.

ChangeLog for gcc/testsuite

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* g++.dg/torture/pushpop_macro.C: New testcase.
	* gcc.c-torture/execute/pushpop_macro.c: New testcase.


Tested for i686-pc-mingw32, i686-pc-linux, x86_64-pc-mingw32, and for
i686-pc-cygwin. Ok for applying to trunk and 4.4 branch?

Cheers,
Kai

-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: mvpushpop.diff --]
[-- Type: application/octet-stream, Size: 21089 bytes --]

Index: gcc/libcpp/directives.c
===================================================================
--- gcc.orig/libcpp/directives.c	2009-11-04 19:28:54.497097000 +0100
+++ gcc/libcpp/directives.c	2009-11-05 11:10:00.872800600 +0100
@@ -126,6 +126,8 @@
 static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
 static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
 static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -1244,6 +1246,8 @@
 {
   /* Pragmas in the global namespace.  */
   register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+  register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
   register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
@@ -1423,6 +1427,96 @@
   _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
+/* Handle #pragma push_macro(STRING).  */
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *c;
+
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      source_location src_loc = pfile->cur_token[-1].src_loc;
+      cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+		 "invalid #pragma push_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+  c = XNEW (struct def_pragma_macro);
+  c->name = XNEWVAR (char, strlen (macroname) + 1);
+  strcpy (c->name, macroname);
+  c->next = pfile->pushed_macros;
+  c->value = cpp_push_definition (pfile, c->name);
+  pfile->pushed_macros = c;
+}
+
+/* Handle #pragma pop_macro(STRING).  */
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *l = NULL, *c = pfile->pushed_macros;
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      source_location src_loc = pfile->cur_token[-1].src_loc;
+      cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+		 "invalid #pragma pop_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+
+  while (c != NULL)
+    {
+      if (!strcmp (c->name, macroname))
+	{
+	  if (!l)
+	    pfile->pushed_macros = c->next;
+	  else
+	    l->next = c->next;
+	  cpp_pop_definition (pfile, c->name, c->value);
+	  free (c->name);
+	  free (c);
+	  break;
+	}
+      l = c;
+      c = c->next;
+    }
+}
+
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
@@ -2225,28 +2319,11 @@
   run_directive (pfile, T_UNDEF, buf, len);
 }
 
-/* Like lex_macro_node, but read the input from STR.  */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
-  size_t len = strlen (str);
-  uchar *buf = (uchar *) alloca (len + 1);
-  cpp_hashnode *node;
-
-  memcpy (buf, str, len);
-  buf[len] = '\n';
-  cpp_push_buffer (pfile, buf, len, true);
-  node = lex_macro_node (pfile, true);
-  _cpp_pop_buffer (pfile);
-
-  return node;
-}
-
 /* If STR is a defined macro, return its definition node, else return NULL.  */
 cpp_macro *
 cpp_push_definition (cpp_reader *pfile, const char *str)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node && node->type == NT_MACRO)
     return node->value.macro;
   else
@@ -2258,7 +2335,7 @@
 void
 cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node == NULL)
     return;
 
Index: gcc/libcpp/internal.h
===================================================================
--- gcc.orig/libcpp/internal.h	2009-11-04 19:28:54.502097000 +0100
+++ gcc/libcpp/internal.h	2009-11-04 20:46:54.779097100 +0100
@@ -305,6 +305,16 @@
   struct cset_converter input_cset_desc;
 };
 
+/* The list of saved macros by push_macro pragma.  */
+struct def_pragma_macro {
+  /* Chain element to previous saved macro.  */
+  struct def_pragma_macro *next;
+  /* Name of the macro.  */
+  char *name;
+  /* The stored macro content.  */
+  cpp_macro *value;
+};
+
 /* A cpp_reader encapsulates the "state" of a pre-processor run.
    Applying cpp_get_token repeatedly yields a stream of pre-processor
    tokens.  Usually, there is only one cpp_reader object active.  */
@@ -475,6 +485,9 @@
 
   /* Table of comments, when state.save_comments is true.  */
   cpp_comment_table comments;
+
+  /* List of saved macros by push_macro.  */
+  struct def_pragma_macro *pushed_macros;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
@@ -575,6 +588,7 @@
 extern cpp_token *_cpp_lex_direct (cpp_reader *);
 extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
+extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
Index: gcc/libcpp/lex.c
===================================================================
--- gcc.orig/libcpp/lex.c	2009-11-04 19:28:54.507097000 +0100
+++ gcc/libcpp/lex.c	2009-11-04 20:46:54.785097100 +0100
@@ -504,6 +504,63 @@
   return false;
 }
 
+/* Helper function to get the cpp_hashnode of the identifier BASE.  */
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+					      base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+			&& !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+	cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
+		   NODE_NAME (result));
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+	 replacement list of a variadic macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+	  && !pfile->state.va_args_ok)
+	cpp_error (pfile, CPP_DL_PEDWARN,
+		   "__VA_ARGS__ can only appear in the expansion"
+		   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+	cpp_error (pfile, CPP_DL_WARNING,
+		   "identifier \"%s\" is a special operator name in C++",
+		   NODE_NAME (result));
+    }
+
+  return result;
+}
+
+/* Get the cpp_hashnode of an identifier specified by NAME in
+   the current cpp_reader object.  If none is found, NULL is returned.  */
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  result = lex_identifier_intern (pfile, (uchar *) name);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
Index: gcc/gcc/c-pragma.c
===================================================================
--- gcc.orig/gcc/c-pragma.c	2009-11-04 19:28:54.471097000 +0100
+++ gcc/gcc/c-pragma.c	2009-11-04 20:46:54.790097100 +0100
@@ -243,144 +243,6 @@
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
-struct GTY(()) def_pragma_macro_value {
-  struct def_pragma_macro_value *prev;
-  cpp_macro *value;
-};
-
-struct GTY(()) def_pragma_macro {
-  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 *const a = (const struct def_pragma_macro *) pa,
-    *const b = (const struct def_pragma_macro *) 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 = (struct def_pragma_macro *) *slot;
-  if (c == NULL)
-    {
-      *slot = c = GGC_NEW (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_NEW (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 = NULL;
-
-  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;
-  if (pushed_macro_table)
-    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
-				     dummy.hash, NO_INSERT);
-  if (slot == NULL)
-    return;
-  c = (struct def_pragma_macro *) *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
@@ -1421,10 +1283,6 @@
   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
Index: gcc/gcc/config/i386/cygming.h
===================================================================
--- gcc.orig/gcc/config/i386/cygming.h	2009-11-04 19:28:54.476097000 +0100
+++ gcc/gcc/config/i386/cygming.h	2009-11-04 20:46:54.795097100 +0100
@@ -127,8 +127,6 @@
 \f
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
-/* Enable push_macro & pop_macro */
-#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c	2009-11-04 20:46:54.805097100 +0100
@@ -0,0 +1,15 @@
+extern void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C	2009-11-04 20:46:54.814097100 +0100
@@ -0,0 +1,19 @@
+/* Do the preprocessor push_macro/pop_macro test.  */
+
+/* { dg-do run } */
+
+extern "C" void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/libcpp/init.c
===================================================================
--- gcc.orig/libcpp/init.c	2009-11-04 19:28:54.499097000 +0100
+++ gcc/libcpp/init.c	2009-11-04 20:46:54.820097100 +0100
@@ -216,6 +216,9 @@
   pfile->a_buff = _cpp_get_buff (pfile, 0);
   pfile->u_buff = _cpp_get_buff (pfile, 0);
 
+  /* Initialize table for push_macro/pop_macro.  */
+  pfile->pushed_macros = 0;
+
   /* The expression parser stack.  */
   _cpp_expand_op_stack (pfile);
 
@@ -245,6 +248,7 @@
 cpp_destroy (cpp_reader *pfile)
 {
   cpp_context *context, *contextn;
+  struct def_pragma_macro *pmacro;
   tokenrun *run, *runn;
   int i;
 
@@ -296,6 +300,17 @@
 
       free (pfile->comments.entries);
     }
+  if (pfile->pushed_macros)
+    {
+      do
+	{
+	  pmacro = pfile->pushed_macros;
+	  pfile->pushed_macros = pmacro->next;
+	  free (pmacro->name);
+	  free (pmacro);
+	}
+      while (pfile->pushed_macros);
+    }
 
   free (pfile);
 }
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi	2009-11-04 19:28:54.480097000 +0100
+++ gcc/gcc/doc/tm.texi	2009-11-04 20:46:54.833097100 +0100
@@ -10476,18 +10476,6 @@
 @samp{#pragma pack()} (that is, a small power of two).
 @end defmac
 
-@findex #pragma
-@findex pragma
-@defmac HANDLE_PRAGMA_PUSH_POP_MACRO
-Define this macro if you want to support the Win32 style pragmas
-@samp{#pragma push_macro(macro-name-as-string)} and @samp{#pragma
-pop_macro(macro-name-as-string)}.  The @samp{#pragma push_macro(
-macro-name-as-string)} pragma saves the named macro and via
-@samp{#pragma pop_macro(macro-name-as-string)} it will return to the
-previous value.
-@end defmac
-
-
 @defmac DOLLARS_IN_IDENTIFIERS
 Define this macro to control use of the character @samp{$} in
 identifier names for the C family of languages.  0 means @samp{$} is
Index: gcc/libcpp/pch.c
===================================================================
--- gcc.orig/libcpp/pch.c	2009-04-12 20:43:38.000000000 +0200
+++ gcc/libcpp/pch.c	2009-11-05 23:08:50.032000000 +0100
@@ -33,6 +33,8 @@
 static int collect_ht_nodes (cpp_reader *, cpp_hashnode *, void *);
 static int write_defs (cpp_reader *, cpp_hashnode *, void *);
 static int save_macros (cpp_reader *, cpp_hashnode *, void *);
+static int _cpp_save_pushed_macros (cpp_reader *, FILE *);
+static int _cpp_restore_pushed_macros (cpp_reader *, FILE *);
 
 /* This structure represents a macro definition on disk.  */
 struct macrodef_struct
@@ -378,9 +380,145 @@
       return -1;
     }
 
+  /* Write saved macros.  */
+  if (! _cpp_save_pushed_macros (r, f))
+    {
+      cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");
+      return -1;
+    }
+
   return 0;
 }
 
+static int
+_cpp_restore_pushed_macros (cpp_reader *r, FILE *f)
+{
+  size_t count_saved = 0;
+  size_t i;
+  struct def_pragma_macro *p;
+  size_t nlen;
+  cpp_hashnode *h;
+  cpp_macro *m;
+  uchar *defn;
+  size_t defnlen;
+
+  if (fread (&count_saved, sizeof (count_saved), 1, f) != 1)
+    return 0;
+  if (! count_saved)
+    return 1;
+  for (i = 0; i < count_saved; i++)
+    {
+      if (fread (&nlen, sizeof (nlen), 1, f) != 1)
+	return 0;
+      p = XNEW (struct def_pragma_macro);
+      p->name = XNEWVAR (char, nlen + 1);
+      p->name[nlen] = 0;
+      if (fread (p->name, nlen, 1, f) != 1)
+	return 0;
+      /* Save old state.  */
+      m = cpp_push_definition (r, p->name);
+      if (fread (&defnlen, sizeof (defnlen), 1, f) != 1)
+	return 0;
+      defn = XNEWVAR (uchar, defnlen + 2);
+      defn[defnlen] = '\n';
+      defn[defnlen + 1] = 0;
+
+      if (fread (defn, defnlen, 1, f) != 1)
+	return 0;
+
+      {
+	size_t namelen;
+	uchar *dn;
+	int saved_type = h->type;
+	int saved_flags = h->flags;
+
+	namelen = ustrcspn (defn, "( \n");
+	h = cpp_lookup (r, defn, namelen);
+	dn = defn + namelen;
+
+	if (h->type != NT_VOID)
+	{
+	  h->type = NT_VOID;
+	  h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED|NODE_USED);
+	}
+	if (cpp_push_buffer (r, dn, ustrchr (dn, '\n') - dn, true)
+	    != NULL)
+	  {
+	    _cpp_clean_line (r);
+	    if (!_cpp_create_definition (r, h))
+	      abort ();
+	    _cpp_pop_buffer (r);
+	  }
+	else
+	  abort ();
+	h->type = saved_type;
+	h->flags = saved_flags;
+      }
+
+      free (defn);
+      p->next = r->pushed_macros;
+      r->pushed_macros = p;
+      /* Restore current state.  */
+      cpp_pop_definition (r, p->name, m);
+    }
+}
+
+static int
+_cpp_save_pushed_macros (cpp_reader *r, FILE *f)
+{
+  size_t count_saved = 0;
+  size_t i;
+  struct def_pragma_macro *p,**pp;
+  cpp_hashnode *node;
+  cpp_macro *m;
+  size_t defnlen;
+  const uchar *defn;
+
+  /* Get count. */
+  p = r->pushed_macros;
+  while (p != NULL)
+    {
+      count_saved++;
+      p = p->next;
+    }
+  if (fwrite (&count_saved, sizeof (count_saved), 1, f) != 1)
+    return 0;
+  if (!count_saved)
+    return 1;
+
+  pp = (struct def_pragma_macro **) alloca (sizeof (struct def_pragma_macro *)
+					    * count_saved);
+  /* Store them in reverse order.  */
+  p = r->pushed_macros;
+  i = count_saved;
+  while (p != NULL)
+    {
+      --i;
+      pp[i] = p;
+      p = p->next;
+    }
+  for (i = 0; i < count_saved; i++)
+    {
+      /* Save old state.  */
+      m = cpp_push_definition (r, pp[i]->name);
+      /* Set temporary macro name to saved state.  */
+      cpp_pop_definition (r, pp[i]->name, pp[i]->value);
+      node = _cpp_lex_identifier (r, pp[i]->name);
+      defnlen = strlen (pp[i]->name);
+      if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1
+	  || fwrite (pp[i]->name, defnlen, 1, f) != 1)
+	return 0;
+      defn = cpp_macro_definition (r, node);
+      defnlen = ustrlen (defn);
+      if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1
+	  || fwrite (defn, defnlen, 1, f) != 1)
+	return 0;
+      /* Restore current state.  */
+      cpp_pop_definition (r, pp[i]->name, m);
+    }
+  return 1;
+}
+
 
 /* Data structure to transform hash table nodes into a sorted list */
 
@@ -752,6 +890,9 @@
   if (!r->counter)
     r->counter = counter;
 
+  /* Read pushed macros. */
+  if (! _cpp_restore_pushed_macros (r, f))
+    goto error;
   return 0;
 
  error:

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-05 22:11           ` Kai Tietz
@ 2009-11-06  9:39             ` Kai Tietz
  2009-11-06  9:41               ` Kai Tietz
  0 siblings, 1 reply; 19+ messages in thread
From: Kai Tietz @ 2009-11-06  9:39 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3165 bytes --]

2009/11/5 Kai Tietz <ktietz70@googlemail.com>:
> 2009/11/5 Paolo Bonzini <bonzini@gnu.org>:
>> On 11/04/2009 05:25 PM, Tom Tromey wrote:
>>>
>>> Kai>  -static GTY((param_is (struct def_pragma_macro))) htab_t
>>> pushed_macro_table;
>>>
>>> Do pushed macros work properly with PCH after this patch?
>>
>> I don't think so.  There is nothing that saves the state, so placing
>>
>> --- test.h ---
>> #define FOO bar
>> #pragma push_macro("FOO")
>> #define FOO baz
>>
>> --- test.c ---
>> #include "test.h"
>> #pragma pop_macro("FOO")
>>
>>
>> would fail because pop_macro would not find FOO on the stack.  It is
>> extremely unlikely to happen in practice, but it is still a bug.  You need
>> to modify libcpp/pch.c to fix this.
>>
>> Paolo
>>
>>
>
> Thanks Paolo for pointing this out. It is right that this case should
> be extremely unlikely, but it would be a bug too. So here the patch
> treating the pch case, too.
>
> ChangeLog for libcpp
>
> 2009-11-03  Kai Tietz  <kai.tietz@onevision.com>
>
>        * directives.c (do_pragma_push_macro): New pragma handler.
>        (do_pragma_pop_macro): Likewise.
>        (_cpp_init_internal_pragmas): Add push_macro and
>        pop_macro handler to internal pragmas.
>        (lex_macro_node_from_str): Removed.
>        (cpp_push_definition): Replace lex_macro_node_from_str
>        by _cpp_lex_identifier.
>        (cpp_pop_definition): Likewise.
>        * internal.h (_cpp_lex_identifier): New prototype.
>        (def_pragma_macro): New structure.
>        (cpp_reader): New member pushed_macros.
>        * lex.c (_cpp_lex_identifier): New function.
>        (lex_identifier_intern): New function.
>        * init.c (cpp_create_reader): Initialize pushed_macros
>        member.
>        (cpp_destroy): Free elements in pushed_macros member.
>        * pch.c (_cpp_save_pushed_macros): New function.
>        (_cpp_restore_pushed_macros): Likewise.
>        (_cpp_restore_pushed_macros): Use _cpp_restore_pushed_macros.
>        (cpp_read_state): Use _cpp_save_pushed_macros.
>
> ChangeLog for gcc
>
> 2009-11-03  Kai Tietz  <kai.tietz@onevision.com>
>
>        * config/i386/cygming.h (HANDLE_PRAGMA_PUSH_POP_MACRO):
>        Removed.
>        * c-pragma.c (def_pragma_macro_value): Likewise.
>        (def_pragma_macro): Likewise.
>        (pushed_macro_table): Likewise.
>        (HANDLE_PRAGMA_PUSH_POP_MACRO): Remove guarded
>        code.
>        * doc/tm.texi (HANDLE_PRAGMA_PUSH_POP_MACRO):
>        Removed.
>
> ChangeLog for gcc/testsuite
>
> 2009-11-03  Kai Tietz  <kai.tietz@onevision.com>
>
>        * g++.dg/torture/pushpop_macro.C: New testcase.
>        * gcc.c-torture/execute/pushpop_macro.c: New testcase.
>
>
> Tested for i686-pc-mingw32, i686-pc-linux, x86_64-pc-mingw32, and for
> i686-pc-cygwin. Ok for applying to trunk and 4.4 branch?
>
> Cheers,
> Kai

Sorry, just noticed that I attached an old patch (which wasn't
tested). Here is the version I've tested.

Kai


-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: mvpushpop.diff --]
[-- Type: application/octet-stream, Size: 21059 bytes --]

Index: gcc/libcpp/directives.c
===================================================================
--- gcc.orig/libcpp/directives.c	2009-11-04 19:28:54.497097000 +0100
+++ gcc/libcpp/directives.c	2009-11-05 11:10:00.872800600 +0100
@@ -126,6 +126,8 @@
 static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
 static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
 static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -1244,6 +1246,8 @@
 {
   /* Pragmas in the global namespace.  */
   register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+  register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
   register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
@@ -1423,6 +1427,96 @@
   _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
+/* Handle #pragma push_macro(STRING).  */
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *c;
+
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      source_location src_loc = pfile->cur_token[-1].src_loc;
+      cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+		 "invalid #pragma push_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+  c = XNEW (struct def_pragma_macro);
+  c->name = XNEWVAR (char, strlen (macroname) + 1);
+  strcpy (c->name, macroname);
+  c->next = pfile->pushed_macros;
+  c->value = cpp_push_definition (pfile, c->name);
+  pfile->pushed_macros = c;
+}
+
+/* Handle #pragma pop_macro(STRING).  */
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *l = NULL, *c = pfile->pushed_macros;
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      source_location src_loc = pfile->cur_token[-1].src_loc;
+      cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+		 "invalid #pragma pop_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+
+  while (c != NULL)
+    {
+      if (!strcmp (c->name, macroname))
+	{
+	  if (!l)
+	    pfile->pushed_macros = c->next;
+	  else
+	    l->next = c->next;
+	  cpp_pop_definition (pfile, c->name, c->value);
+	  free (c->name);
+	  free (c);
+	  break;
+	}
+      l = c;
+      c = c->next;
+    }
+}
+
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
@@ -2225,28 +2319,11 @@
   run_directive (pfile, T_UNDEF, buf, len);
 }
 
-/* Like lex_macro_node, but read the input from STR.  */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
-  size_t len = strlen (str);
-  uchar *buf = (uchar *) alloca (len + 1);
-  cpp_hashnode *node;
-
-  memcpy (buf, str, len);
-  buf[len] = '\n';
-  cpp_push_buffer (pfile, buf, len, true);
-  node = lex_macro_node (pfile, true);
-  _cpp_pop_buffer (pfile);
-
-  return node;
-}
-
 /* If STR is a defined macro, return its definition node, else return NULL.  */
 cpp_macro *
 cpp_push_definition (cpp_reader *pfile, const char *str)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node && node->type == NT_MACRO)
     return node->value.macro;
   else
@@ -2258,7 +2335,7 @@
 void
 cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node == NULL)
     return;
 
Index: gcc/libcpp/internal.h
===================================================================
--- gcc.orig/libcpp/internal.h	2009-11-04 19:28:54.502097000 +0100
+++ gcc/libcpp/internal.h	2009-11-04 20:46:54.779097100 +0100
@@ -305,6 +305,16 @@
   struct cset_converter input_cset_desc;
 };
 
+/* The list of saved macros by push_macro pragma.  */
+struct def_pragma_macro {
+  /* Chain element to previous saved macro.  */
+  struct def_pragma_macro *next;
+  /* Name of the macro.  */
+  char *name;
+  /* The stored macro content.  */
+  cpp_macro *value;
+};
+
 /* A cpp_reader encapsulates the "state" of a pre-processor run.
    Applying cpp_get_token repeatedly yields a stream of pre-processor
    tokens.  Usually, there is only one cpp_reader object active.  */
@@ -475,6 +485,9 @@
 
   /* Table of comments, when state.save_comments is true.  */
   cpp_comment_table comments;
+
+  /* List of saved macros by push_macro.  */
+  struct def_pragma_macro *pushed_macros;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
@@ -575,6 +588,7 @@
 extern cpp_token *_cpp_lex_direct (cpp_reader *);
 extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
+extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
Index: gcc/libcpp/lex.c
===================================================================
--- gcc.orig/libcpp/lex.c	2009-11-04 19:28:54.507097000 +0100
+++ gcc/libcpp/lex.c	2009-11-04 20:46:54.785097100 +0100
@@ -504,6 +504,63 @@
   return false;
 }
 
+/* Helper function to get the cpp_hashnode of the identifier BASE.  */
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+					      base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+			&& !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+	cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
+		   NODE_NAME (result));
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+	 replacement list of a variadic macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+	  && !pfile->state.va_args_ok)
+	cpp_error (pfile, CPP_DL_PEDWARN,
+		   "__VA_ARGS__ can only appear in the expansion"
+		   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+	cpp_error (pfile, CPP_DL_WARNING,
+		   "identifier \"%s\" is a special operator name in C++",
+		   NODE_NAME (result));
+    }
+
+  return result;
+}
+
+/* Get the cpp_hashnode of an identifier specified by NAME in
+   the current cpp_reader object.  If none is found, NULL is returned.  */
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  result = lex_identifier_intern (pfile, (uchar *) name);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
Index: gcc/gcc/c-pragma.c
===================================================================
--- gcc.orig/gcc/c-pragma.c	2009-11-04 19:28:54.471097000 +0100
+++ gcc/gcc/c-pragma.c	2009-11-04 20:46:54.790097100 +0100
@@ -243,144 +243,6 @@
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
-struct GTY(()) def_pragma_macro_value {
-  struct def_pragma_macro_value *prev;
-  cpp_macro *value;
-};
-
-struct GTY(()) def_pragma_macro {
-  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 *const a = (const struct def_pragma_macro *) pa,
-    *const b = (const struct def_pragma_macro *) 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 = (struct def_pragma_macro *) *slot;
-  if (c == NULL)
-    {
-      *slot = c = GGC_NEW (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_NEW (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 = NULL;
-
-  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;
-  if (pushed_macro_table)
-    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
-				     dummy.hash, NO_INSERT);
-  if (slot == NULL)
-    return;
-  c = (struct def_pragma_macro *) *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
@@ -1421,10 +1283,6 @@
   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
Index: gcc/gcc/config/i386/cygming.h
===================================================================
--- gcc.orig/gcc/config/i386/cygming.h	2009-11-04 19:28:54.476097000 +0100
+++ gcc/gcc/config/i386/cygming.h	2009-11-04 20:46:54.795097100 +0100
@@ -127,8 +127,6 @@
 \f
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
-/* Enable push_macro & pop_macro */
-#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c	2009-11-04 20:46:54.805097100 +0100
@@ -0,0 +1,15 @@
+extern void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C	2009-11-04 20:46:54.814097100 +0100
@@ -0,0 +1,19 @@
+/* Do the preprocessor push_macro/pop_macro test.  */
+
+/* { dg-do run } */
+
+extern "C" void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/libcpp/init.c
===================================================================
--- gcc.orig/libcpp/init.c	2009-11-04 19:28:54.499097000 +0100
+++ gcc/libcpp/init.c	2009-11-04 20:46:54.820097100 +0100
@@ -216,6 +216,9 @@
   pfile->a_buff = _cpp_get_buff (pfile, 0);
   pfile->u_buff = _cpp_get_buff (pfile, 0);
 
+  /* Initialize table for push_macro/pop_macro.  */
+  pfile->pushed_macros = 0;
+
   /* The expression parser stack.  */
   _cpp_expand_op_stack (pfile);
 
@@ -245,6 +248,7 @@
 cpp_destroy (cpp_reader *pfile)
 {
   cpp_context *context, *contextn;
+  struct def_pragma_macro *pmacro;
   tokenrun *run, *runn;
   int i;
 
@@ -296,6 +300,17 @@
 
       free (pfile->comments.entries);
     }
+  if (pfile->pushed_macros)
+    {
+      do
+	{
+	  pmacro = pfile->pushed_macros;
+	  pfile->pushed_macros = pmacro->next;
+	  free (pmacro->name);
+	  free (pmacro);
+	}
+      while (pfile->pushed_macros);
+    }
 
   free (pfile);
 }
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi	2009-11-04 19:28:54.480097000 +0100
+++ gcc/gcc/doc/tm.texi	2009-11-04 20:46:54.833097100 +0100
@@ -10476,18 +10476,6 @@
 @samp{#pragma pack()} (that is, a small power of two).
 @end defmac
 
-@findex #pragma
-@findex pragma
-@defmac HANDLE_PRAGMA_PUSH_POP_MACRO
-Define this macro if you want to support the Win32 style pragmas
-@samp{#pragma push_macro(macro-name-as-string)} and @samp{#pragma
-pop_macro(macro-name-as-string)}.  The @samp{#pragma push_macro(
-macro-name-as-string)} pragma saves the named macro and via
-@samp{#pragma pop_macro(macro-name-as-string)} it will return to the
-previous value.
-@end defmac
-
-
 @defmac DOLLARS_IN_IDENTIFIERS
 Define this macro to control use of the character @samp{$} in
 identifier names for the C family of languages.  0 means @samp{$} is
Index: gcc/libcpp/pch.c
===================================================================
--- gcc.orig/libcpp/pch.c	2009-04-12 20:43:38.000000000 +0200
+++ gcc/libcpp/pch.c	2009-11-06 09:45:54.942691200 +0100
@@ -33,6 +33,8 @@
 static int collect_ht_nodes (cpp_reader *, cpp_hashnode *, void *);
 static int write_defs (cpp_reader *, cpp_hashnode *, void *);
 static int save_macros (cpp_reader *, cpp_hashnode *, void *);
+static int _cpp_save_pushed_macros (cpp_reader *, FILE *);
+static int _cpp_restore_pushed_macros (cpp_reader *, FILE *);
 
 /* This structure represents a macro definition on disk.  */
 struct macrodef_struct
@@ -378,9 +380,140 @@
       return -1;
     }
 
+  /* Write saved macros.  */
+  if (! _cpp_save_pushed_macros (r, f))
+    {
+      cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");
+      return -1;
+    }
+
   return 0;
 }
 
+static int
+_cpp_restore_pushed_macros (cpp_reader *r, FILE *f)
+{
+  size_t count_saved = 0;
+  size_t i;
+  struct def_pragma_macro *p;
+  size_t nlen;
+  cpp_hashnode *h = NULL;
+  cpp_macro *m;
+  uchar *defn;
+  size_t defnlen;
+
+  if (fread (&count_saved, sizeof (count_saved), 1, f) != 1)
+    return 0;
+  if (! count_saved)
+    return 1;
+  for (i = 0; i < count_saved; i++)
+    {
+      if (fread (&nlen, sizeof (nlen), 1, f) != 1)
+	return 0;
+      p = XNEW (struct def_pragma_macro);
+      p->name = XNEWVAR (char, nlen + 1);
+      p->name[nlen] = 0;
+      if (fread (p->name, nlen, 1, f) != 1)
+	return 0;
+      /* Save old state.  */
+      m = cpp_push_definition (r, p->name);
+      if (fread (&defnlen, sizeof (defnlen), 1, f) != 1)
+	return 0;
+      defn = XNEWVAR (uchar, defnlen + 2);
+      defn[defnlen] = '\n';
+      defn[defnlen + 1] = 0;
+
+      if (fread (defn, defnlen, 1, f) != 1)
+	return 0;
+      cpp_pop_definition (r, p->name, NULL);
+      {
+	size_t namelen;
+	uchar *dn;
+
+	namelen = ustrcspn (defn, "( \n");
+	h = cpp_lookup (r, defn, namelen);
+	dn = defn + namelen;
+
+	h->type = NT_VOID;
+	h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED|NODE_USED);
+	if (cpp_push_buffer (r, dn, ustrchr (dn, '\n') - dn, true)
+	    != NULL)
+	  {
+	    _cpp_clean_line (r);
+	    if (!_cpp_create_definition (r, h))
+	      abort ();
+	    _cpp_pop_buffer (r);
+	  }
+	else
+	  abort ();
+      }
+      p->value = cpp_push_definition (r, p->name);
+
+      free (defn);
+      p->next = r->pushed_macros;
+      r->pushed_macros = p;
+      /* Restore current state.  */
+      cpp_pop_definition (r, p->name, m);
+    }
+  return 1;
+}
+
+static int
+_cpp_save_pushed_macros (cpp_reader *r, FILE *f)
+{
+  size_t count_saved = 0;
+  size_t i;
+  struct def_pragma_macro *p,**pp;
+  cpp_hashnode *node;
+  cpp_macro *m;
+  size_t defnlen;
+  const uchar *defn;
+
+  /* Get count. */
+  p = r->pushed_macros;
+  while (p != NULL)
+    {
+      count_saved++;
+      p = p->next;
+    }
+  if (fwrite (&count_saved, sizeof (count_saved), 1, f) != 1)
+    return 0;
+  if (!count_saved)
+    return 1;
+
+  pp = (struct def_pragma_macro **) alloca (sizeof (struct def_pragma_macro *)
+					    * count_saved);
+  /* Store them in reverse order.  */
+  p = r->pushed_macros;
+  i = count_saved;
+  while (p != NULL)
+    {
+      --i;
+      pp[i] = p;
+      p = p->next;
+    }
+  for (i = 0; i < count_saved; i++)
+    {
+      /* Save old state.  */
+      m = cpp_push_definition (r, pp[i]->name);
+      /* Set temporary macro name to saved state.  */
+      cpp_pop_definition (r, pp[i]->name, pp[i]->value);
+      node = _cpp_lex_identifier (r, pp[i]->name);
+      defnlen = strlen (pp[i]->name);
+      if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1
+	  || fwrite (pp[i]->name, defnlen, 1, f) != 1)
+	return 0;
+      defn = cpp_macro_definition (r, node);
+      defnlen = ustrlen (defn);
+      if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1
+	  || fwrite (defn, defnlen, 1, f) != 1)
+	return 0;
+      /* Restore current state.  */
+      cpp_pop_definition (r, pp[i]->name, m);
+    }
+  return 1;
+}
+
 
 /* Data structure to transform hash table nodes into a sorted list */
 
@@ -752,6 +885,9 @@
   if (!r->counter)
     r->counter = counter;
 
+  /* Read pushed macros. */
+  if (! _cpp_restore_pushed_macros (r, f))
+    goto error;
   return 0;
 
  error:

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-06  9:39             ` Kai Tietz
@ 2009-11-06  9:41               ` Kai Tietz
  2009-11-10 16:19                 ` Tom Tromey
  0 siblings, 1 reply; 19+ messages in thread
From: Kai Tietz @ 2009-11-06  9:41 UTC (permalink / raw)
  To: Tom Tromey, Paolo Bonzini; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1887 bytes --]

I have added to this patch a tests for pch.

ChangeLog for libcpp

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* directives.c (do_pragma_push_macro): New pragma handler.
	(do_pragma_pop_macro): Likewise.
	(_cpp_init_internal_pragmas): Add push_macro and
	pop_macro handler to internal pragmas.
	(lex_macro_node_from_str): Removed.
	(cpp_push_definition): Replace lex_macro_node_from_str
	by _cpp_lex_identifier.
	(cpp_pop_definition): Likewise.
	* internal.h (_cpp_lex_identifier): New prototype.
	(def_pragma_macro): New structure.
	(cpp_reader): New member pushed_macros.
	* lex.c (_cpp_lex_identifier): New function.
	(lex_identifier_intern): New function.
	* init.c (cpp_create_reader): Initialize pushed_macros
	member.
	(cpp_destroy): Free elements in pushed_macros member.
	* pch.c (_cpp_save_pushed_macros): New function.
	(_cpp_restore_pushed_macros): Likewise.
	(_cpp_restore_pushed_macros): Use _cpp_save_pushed_macros.
	(cpp_read_state): Use _cpp_restore_pushed_macros.

ChangeLog for gcc

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* config/i386/cygming.h (HANDLE_PRAGMA_PUSH_POP_MACRO):
	Removed.
	* c-pragma.c (def_pragma_macro_value): Likewise.
	(def_pragma_macro): Likewise.
	(pushed_macro_table): Likewise.
	(HANDLE_PRAGMA_PUSH_POP_MACRO): Remove guarded
	code.
	* doc/tm.texi (HANDLE_PRAGMA_PUSH_POP_MACRO):
	Removed.

ChangeLog for gcc/testsuite

2009-11-03  Kai Tietz  <kai.tietz@onevision.com>

	* g++.dg/torture/pushpop_macro.C: New testcase.
	* gcc.c-torture/execute/pushpop_macro.c: New testcase.
	* gcc.dg/cpp/pragma-pop_macro-1.c: Allow test for all
	targets.
	* gcc.dg/pch/pushpop-1.c: New.
	* gcc.dg/pch/pushpop-1.hs: New.

Tested for i686-pc-mingw32, x86_64-pc-mingw32, i686-pc-linux, and
i686-pc-cygwin.
Ok for apply?
-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

[-- Attachment #2: mvpushpop.diff --]
[-- Type: application/octet-stream, Size: 22356 bytes --]

Index: gcc/libcpp/directives.c
===================================================================
--- gcc.orig/libcpp/directives.c	2009-11-04 19:28:54.497097000 +0100
+++ gcc/libcpp/directives.c	2009-11-05 11:10:00.872800600 +0100
@@ -126,6 +126,8 @@
 static cpp_hashnode *parse_assertion (cpp_reader *, struct answer **, int);
 static struct answer ** find_answer (cpp_hashnode *, const struct answer *);
 static void handle_assertion (cpp_reader *, const char *, int);
+static void do_pragma_push_macro (cpp_reader *);
+static void do_pragma_pop_macro (cpp_reader *);
 
 /* This is the table of directive handlers.  It is ordered by
    frequency of occurrence; the numbers at the end are directive
@@ -1244,6 +1246,8 @@
 {
   /* Pragmas in the global namespace.  */
   register_pragma_internal (pfile, 0, "once", do_pragma_once);
+  register_pragma_internal (pfile, 0, "push_macro", do_pragma_push_macro);
+  register_pragma_internal (pfile, 0, "pop_macro", do_pragma_pop_macro);
 
   /* New GCC-specific pragmas should be put in the GCC namespace.  */
   register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
@@ -1423,6 +1427,96 @@
   _cpp_mark_file_once_only (pfile, pfile->buffer->file);
 }
 
+/* Handle #pragma push_macro(STRING).  */
+static void
+do_pragma_push_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *c;
+
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      source_location src_loc = pfile->cur_token[-1].src_loc;
+      cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+		 "invalid #pragma push_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+  c = XNEW (struct def_pragma_macro);
+  c->name = XNEWVAR (char, strlen (macroname) + 1);
+  strcpy (c->name, macroname);
+  c->next = pfile->pushed_macros;
+  c->value = cpp_push_definition (pfile, c->name);
+  pfile->pushed_macros = c;
+}
+
+/* Handle #pragma pop_macro(STRING).  */
+static void
+do_pragma_pop_macro (cpp_reader *pfile)
+{
+  char *macroname, *dest;
+  const char *limit, *src;
+  const cpp_token *txt;
+  struct def_pragma_macro *l = NULL, *c = pfile->pushed_macros;
+  txt = get__Pragma_string (pfile);
+  if (!txt)
+    {
+      source_location src_loc = pfile->cur_token[-1].src_loc;
+      cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
+		 "invalid #pragma pop_macro directive");
+      check_eol (pfile, false);
+      skip_rest_of_line (pfile);
+      return;
+    }
+  dest = macroname = (char *) alloca (txt->val.str.len + 2);
+  src = (const char *) (txt->val.str.text + 1 + (txt->val.str.text[0] == 'L'));
+  limit = (const char *) (txt->val.str.text + txt->val.str.len - 1);
+  while (src < limit)
+    {
+      /* We know there is a character following the backslash.  */
+      if (*src == '\\' && (src[1] == '\\' || src[1] == '"'))
+	src++;
+      *dest++ = *src++;
+    }
+  *dest = 0;
+  check_eol (pfile, false);
+  skip_rest_of_line (pfile);
+
+  while (c != NULL)
+    {
+      if (!strcmp (c->name, macroname))
+	{
+	  if (!l)
+	    pfile->pushed_macros = c->next;
+	  else
+	    l->next = c->next;
+	  cpp_pop_definition (pfile, c->name, c->value);
+	  free (c->name);
+	  free (c);
+	  break;
+	}
+      l = c;
+      c = c->next;
+    }
+}
+
 /* Handle #pragma GCC poison, to poison one or more identifiers so
    that the lexer produces a hard error for each subsequent usage.  */
 static void
@@ -2225,28 +2319,11 @@
   run_directive (pfile, T_UNDEF, buf, len);
 }
 
-/* Like lex_macro_node, but read the input from STR.  */
-static cpp_hashnode *
-lex_macro_node_from_str (cpp_reader *pfile, const char *str)
-{
-  size_t len = strlen (str);
-  uchar *buf = (uchar *) alloca (len + 1);
-  cpp_hashnode *node;
-
-  memcpy (buf, str, len);
-  buf[len] = '\n';
-  cpp_push_buffer (pfile, buf, len, true);
-  node = lex_macro_node (pfile, true);
-  _cpp_pop_buffer (pfile);
-
-  return node;
-}
-
 /* If STR is a defined macro, return its definition node, else return NULL.  */
 cpp_macro *
 cpp_push_definition (cpp_reader *pfile, const char *str)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node && node->type == NT_MACRO)
     return node->value.macro;
   else
@@ -2258,7 +2335,7 @@
 void
 cpp_pop_definition (cpp_reader *pfile, const char *str, cpp_macro *dfn)
 {
-  cpp_hashnode *node = lex_macro_node_from_str (pfile, str);
+  cpp_hashnode *node = _cpp_lex_identifier (pfile, str);
   if (node == NULL)
     return;
 
Index: gcc/libcpp/internal.h
===================================================================
--- gcc.orig/libcpp/internal.h	2009-11-04 19:28:54.502097000 +0100
+++ gcc/libcpp/internal.h	2009-11-04 20:46:54.779097100 +0100
@@ -305,6 +305,16 @@
   struct cset_converter input_cset_desc;
 };
 
+/* The list of saved macros by push_macro pragma.  */
+struct def_pragma_macro {
+  /* Chain element to previous saved macro.  */
+  struct def_pragma_macro *next;
+  /* Name of the macro.  */
+  char *name;
+  /* The stored macro content.  */
+  cpp_macro *value;
+};
+
 /* A cpp_reader encapsulates the "state" of a pre-processor run.
    Applying cpp_get_token repeatedly yields a stream of pre-processor
    tokens.  Usually, there is only one cpp_reader object active.  */
@@ -475,6 +485,9 @@
 
   /* Table of comments, when state.save_comments is true.  */
   cpp_comment_table comments;
+
+  /* List of saved macros by push_macro.  */
+  struct def_pragma_macro *pushed_macros;
 };
 
 /* Character classes.  Based on the more primitive macros in safe-ctype.h.
@@ -575,6 +588,7 @@
 extern cpp_token *_cpp_lex_direct (cpp_reader *);
 extern int _cpp_equiv_tokens (const cpp_token *, const cpp_token *);
 extern void _cpp_init_tokenrun (tokenrun *, unsigned int);
+extern cpp_hashnode *_cpp_lex_identifier (cpp_reader *, const char *);
 
 /* In init.c.  */
 extern void _cpp_maybe_push_include_file (cpp_reader *);
Index: gcc/libcpp/lex.c
===================================================================
--- gcc.orig/libcpp/lex.c	2009-11-04 19:28:54.507097000 +0100
+++ gcc/libcpp/lex.c	2009-11-04 20:46:54.785097100 +0100
@@ -504,6 +504,63 @@
   return false;
 }
 
+/* Helper function to get the cpp_hashnode of the identifier BASE.  */
+static cpp_hashnode *
+lex_identifier_intern (cpp_reader *pfile, const uchar *base)
+{
+  cpp_hashnode *result;
+  const uchar *cur;
+  unsigned int len;
+  unsigned int hash = HT_HASHSTEP (0, *base);
+
+  cur = base + 1;
+  while (ISIDNUM (*cur))
+    {
+      hash = HT_HASHSTEP (hash, *cur);
+      cur++;
+    }
+  len = cur - base;
+  hash = HT_HASHFINISH (hash, len);
+  result = CPP_HASHNODE (ht_lookup_with_hash (pfile->hash_table,
+					      base, len, hash, HT_ALLOC));
+
+  /* Rarely, identifiers require diagnostics when lexed.  */
+  if (__builtin_expect ((result->flags & NODE_DIAGNOSTIC)
+			&& !pfile->state.skipping, 0))
+    {
+      /* It is allowed to poison the same identifier twice.  */
+      if ((result->flags & NODE_POISONED) && !pfile->state.poisoned_ok)
+	cpp_error (pfile, CPP_DL_ERROR, "attempt to use poisoned \"%s\"",
+		   NODE_NAME (result));
+
+      /* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+	 replacement list of a variadic macro.  */
+      if (result == pfile->spec_nodes.n__VA_ARGS__
+	  && !pfile->state.va_args_ok)
+	cpp_error (pfile, CPP_DL_PEDWARN,
+		   "__VA_ARGS__ can only appear in the expansion"
+		   " of a C99 variadic macro");
+
+      /* For -Wc++-compat, warn about use of C++ named operators.  */
+      if (result->flags & NODE_WARN_OPERATOR)
+	cpp_error (pfile, CPP_DL_WARNING,
+		   "identifier \"%s\" is a special operator name in C++",
+		   NODE_NAME (result));
+    }
+
+  return result;
+}
+
+/* Get the cpp_hashnode of an identifier specified by NAME in
+   the current cpp_reader object.  If none is found, NULL is returned.  */
+cpp_hashnode *
+_cpp_lex_identifier (cpp_reader *pfile, const char *name)
+{
+  cpp_hashnode *result;
+  result = lex_identifier_intern (pfile, (uchar *) name);
+  return result;
+}
+
 /* Lex an identifier starting at BUFFER->CUR - 1.  */
 static cpp_hashnode *
 lex_identifier (cpp_reader *pfile, const uchar *base, bool starts_ucn,
Index: gcc/gcc/c-pragma.c
===================================================================
--- gcc.orig/gcc/c-pragma.c	2009-11-04 19:28:54.471097000 +0100
+++ gcc/gcc/c-pragma.c	2009-11-04 20:46:54.790097100 +0100
@@ -243,144 +243,6 @@
 }
 #endif  /* HANDLE_PRAGMA_PACK */
 
-struct GTY(()) def_pragma_macro_value {
-  struct def_pragma_macro_value *prev;
-  cpp_macro *value;
-};
-
-struct GTY(()) def_pragma_macro {
-  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 *const a = (const struct def_pragma_macro *) pa,
-    *const b = (const struct def_pragma_macro *) 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 = (struct def_pragma_macro *) *slot;
-  if (c == NULL)
-    {
-      *slot = c = GGC_NEW (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_NEW (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 = NULL;
-
-  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;
-  if (pushed_macro_table)
-    slot = htab_find_slot_with_hash (pushed_macro_table, &dummy,
-				     dummy.hash, NO_INSERT);
-  if (slot == NULL)
-    return;
-  c = (struct def_pragma_macro *) *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
@@ -1421,10 +1283,6 @@
   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
Index: gcc/gcc/config/i386/cygming.h
===================================================================
--- gcc.orig/gcc/config/i386/cygming.h	2009-11-04 19:28:54.476097000 +0100
+++ gcc/gcc/config/i386/cygming.h	2009-11-04 20:46:54.795097100 +0100
@@ -127,8 +127,6 @@
 \f
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
-/* Enable push_macro & pop_macro */
-#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *
Index: gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.c-torture/execute/pushpop_macro.c	2009-11-04 20:46:54.805097100 +0100
@@ -0,0 +1,15 @@
+extern void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/g++.dg/torture/pushpop_macro.C	2009-11-04 20:46:54.814097100 +0100
@@ -0,0 +1,19 @@
+/* Do the preprocessor push_macro/pop_macro test.  */
+
+/* { dg-do run } */
+
+extern "C" void abort ();
+
+#define _ 2
+#pragma push_macro("_")
+#undef _
+#define _ 1
+#pragma pop_macro("_")
+
+int main ()
+{
+  if (_ != 2)
+    abort ();
+  return 0;
+}
+
Index: gcc/libcpp/init.c
===================================================================
--- gcc.orig/libcpp/init.c	2009-11-04 19:28:54.499097000 +0100
+++ gcc/libcpp/init.c	2009-11-04 20:46:54.820097100 +0100
@@ -216,6 +216,9 @@
   pfile->a_buff = _cpp_get_buff (pfile, 0);
   pfile->u_buff = _cpp_get_buff (pfile, 0);
 
+  /* Initialize table for push_macro/pop_macro.  */
+  pfile->pushed_macros = 0;
+
   /* The expression parser stack.  */
   _cpp_expand_op_stack (pfile);
 
@@ -245,6 +248,7 @@
 cpp_destroy (cpp_reader *pfile)
 {
   cpp_context *context, *contextn;
+  struct def_pragma_macro *pmacro;
   tokenrun *run, *runn;
   int i;
 
@@ -296,6 +300,17 @@
 
       free (pfile->comments.entries);
     }
+  if (pfile->pushed_macros)
+    {
+      do
+	{
+	  pmacro = pfile->pushed_macros;
+	  pfile->pushed_macros = pmacro->next;
+	  free (pmacro->name);
+	  free (pmacro);
+	}
+      while (pfile->pushed_macros);
+    }
 
   free (pfile);
 }
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi	2009-11-04 19:28:54.480097000 +0100
+++ gcc/gcc/doc/tm.texi	2009-11-04 20:46:54.833097100 +0100
@@ -10476,18 +10476,6 @@
 @samp{#pragma pack()} (that is, a small power of two).
 @end defmac
 
-@findex #pragma
-@findex pragma
-@defmac HANDLE_PRAGMA_PUSH_POP_MACRO
-Define this macro if you want to support the Win32 style pragmas
-@samp{#pragma push_macro(macro-name-as-string)} and @samp{#pragma
-pop_macro(macro-name-as-string)}.  The @samp{#pragma push_macro(
-macro-name-as-string)} pragma saves the named macro and via
-@samp{#pragma pop_macro(macro-name-as-string)} it will return to the
-previous value.
-@end defmac
-
-
 @defmac DOLLARS_IN_IDENTIFIERS
 Define this macro to control use of the character @samp{$} in
 identifier names for the C family of languages.  0 means @samp{$} is
Index: gcc/libcpp/pch.c
===================================================================
--- gcc.orig/libcpp/pch.c	2009-04-12 20:43:38.000000000 +0200
+++ gcc/libcpp/pch.c	2009-11-06 09:45:54.942691200 +0100
@@ -33,6 +33,8 @@
 static int collect_ht_nodes (cpp_reader *, cpp_hashnode *, void *);
 static int write_defs (cpp_reader *, cpp_hashnode *, void *);
 static int save_macros (cpp_reader *, cpp_hashnode *, void *);
+static int _cpp_save_pushed_macros (cpp_reader *, FILE *);
+static int _cpp_restore_pushed_macros (cpp_reader *, FILE *);
 
 /* This structure represents a macro definition on disk.  */
 struct macrodef_struct
@@ -378,9 +380,140 @@
       return -1;
     }
 
+  /* Write saved macros.  */
+  if (! _cpp_save_pushed_macros (r, f))
+    {
+      cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");
+      return -1;
+    }
+
   return 0;
 }
 
+static int
+_cpp_restore_pushed_macros (cpp_reader *r, FILE *f)
+{
+  size_t count_saved = 0;
+  size_t i;
+  struct def_pragma_macro *p;
+  size_t nlen;
+  cpp_hashnode *h = NULL;
+  cpp_macro *m;
+  uchar *defn;
+  size_t defnlen;
+
+  if (fread (&count_saved, sizeof (count_saved), 1, f) != 1)
+    return 0;
+  if (! count_saved)
+    return 1;
+  for (i = 0; i < count_saved; i++)
+    {
+      if (fread (&nlen, sizeof (nlen), 1, f) != 1)
+	return 0;
+      p = XNEW (struct def_pragma_macro);
+      p->name = XNEWVAR (char, nlen + 1);
+      p->name[nlen] = 0;
+      if (fread (p->name, nlen, 1, f) != 1)
+	return 0;
+      /* Save old state.  */
+      m = cpp_push_definition (r, p->name);
+      if (fread (&defnlen, sizeof (defnlen), 1, f) != 1)
+	return 0;
+      defn = XNEWVAR (uchar, defnlen + 2);
+      defn[defnlen] = '\n';
+      defn[defnlen + 1] = 0;
+
+      if (fread (defn, defnlen, 1, f) != 1)
+	return 0;
+      cpp_pop_definition (r, p->name, NULL);
+      {
+	size_t namelen;
+	uchar *dn;
+
+	namelen = ustrcspn (defn, "( \n");
+	h = cpp_lookup (r, defn, namelen);
+	dn = defn + namelen;
+
+	h->type = NT_VOID;
+	h->flags &= ~(NODE_POISONED|NODE_BUILTIN|NODE_DISABLED|NODE_USED);
+	if (cpp_push_buffer (r, dn, ustrchr (dn, '\n') - dn, true)
+	    != NULL)
+	  {
+	    _cpp_clean_line (r);
+	    if (!_cpp_create_definition (r, h))
+	      abort ();
+	    _cpp_pop_buffer (r);
+	  }
+	else
+	  abort ();
+      }
+      p->value = cpp_push_definition (r, p->name);
+
+      free (defn);
+      p->next = r->pushed_macros;
+      r->pushed_macros = p;
+      /* Restore current state.  */
+      cpp_pop_definition (r, p->name, m);
+    }
+  return 1;
+}
+
+static int
+_cpp_save_pushed_macros (cpp_reader *r, FILE *f)
+{
+  size_t count_saved = 0;
+  size_t i;
+  struct def_pragma_macro *p,**pp;
+  cpp_hashnode *node;
+  cpp_macro *m;
+  size_t defnlen;
+  const uchar *defn;
+
+  /* Get count. */
+  p = r->pushed_macros;
+  while (p != NULL)
+    {
+      count_saved++;
+      p = p->next;
+    }
+  if (fwrite (&count_saved, sizeof (count_saved), 1, f) != 1)
+    return 0;
+  if (!count_saved)
+    return 1;
+
+  pp = (struct def_pragma_macro **) alloca (sizeof (struct def_pragma_macro *)
+					    * count_saved);
+  /* Store them in reverse order.  */
+  p = r->pushed_macros;
+  i = count_saved;
+  while (p != NULL)
+    {
+      --i;
+      pp[i] = p;
+      p = p->next;
+    }
+  for (i = 0; i < count_saved; i++)
+    {
+      /* Save old state.  */
+      m = cpp_push_definition (r, pp[i]->name);
+      /* Set temporary macro name to saved state.  */
+      cpp_pop_definition (r, pp[i]->name, pp[i]->value);
+      node = _cpp_lex_identifier (r, pp[i]->name);
+      defnlen = strlen (pp[i]->name);
+      if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1
+	  || fwrite (pp[i]->name, defnlen, 1, f) != 1)
+	return 0;
+      defn = cpp_macro_definition (r, node);
+      defnlen = ustrlen (defn);
+      if (fwrite (&defnlen, sizeof (size_t), 1, f) != 1
+	  || fwrite (defn, defnlen, 1, f) != 1)
+	return 0;
+      /* Restore current state.  */
+      cpp_pop_definition (r, pp[i]->name, m);
+    }
+  return 1;
+}
+
 
 /* Data structure to transform hash table nodes into a sorted list */
 
@@ -752,6 +885,9 @@
   if (!r->counter)
     r->counter = counter;
 
+  /* Read pushed macros. */
+  if (! _cpp_restore_pushed_macros (r, f))
+    goto error;
   return 0;
 
  error:
Index: gcc/gcc/testsuite/gcc.dg/cpp/pragma-pop_macro-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/cpp/pragma-pop_macro-1.c	2008-11-03 20:40:24.000000000 +0100
+++ gcc/gcc/testsuite/gcc.dg/cpp/pragma-pop_macro-1.c	2009-11-06 10:19:39.837691200 +0100
@@ -1,7 +1,7 @@
 /* PR preprocessor/35061 */
 /* Do nothing if there is nothing on the macro stack to pop.  */
 
-/* { dg-do preprocess { target *-*-mingw* *-*-cygwin* } } */
+/* { dg-do preprocess } */
 
 #define X  1
 /* # pragma push_macro("X") */
Index: gcc/gcc/testsuite/gcc.dg/pch/pushpop-1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/pch/pushpop-1.c	2009-11-06 10:30:06.779691200 +0100
@@ -0,0 +1,11 @@
+#include "pushpop-1.hs"
+
+#if FOO != 2
+#error FOO != 2
+#endif
+#pragma pop_macro("FOO")
+
+#if FOO != 1
+#error FOR != 1
+#endif
+
Index: gcc/gcc/testsuite/gcc.dg/pch/pushpop-1.hs
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.dg/pch/pushpop-1.hs	2009-11-06 10:29:24.146691200 +0100
@@ -0,0 +1,5 @@
+#define FOO 1
+#pragma push_macro ("FOO")
+#undef FOO
+#define FOO 2
+

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by  moving it from C frontent into libcpp
  2009-11-06  9:41               ` Kai Tietz
@ 2009-11-10 16:19                 ` Tom Tromey
  2009-11-10 17:34                   ` Kai Tietz
  0 siblings, 1 reply; 19+ messages in thread
From: Tom Tromey @ 2009-11-10 16:19 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Paolo Bonzini, gcc-patches

>>>>> "Kai" == Kai Tietz <ktietz70@googlemail.com> writes:

Kai> ChangeLog for libcpp
Kai> 2009-11-03  Kai Tietz  <kai.tietz@onevision.com>
Kai> 	* directives.c (do_pragma_push_macro): New pragma handler.
Kai> 	(do_pragma_pop_macro): Likewise.
Kai> 	(_cpp_init_internal_pragmas): Add push_macro and
Kai> 	pop_macro handler to internal pragmas.
Kai> 	(lex_macro_node_from_str): Removed.
Kai> 	(cpp_push_definition): Replace lex_macro_node_from_str
Kai> 	by _cpp_lex_identifier.
Kai> 	(cpp_pop_definition): Likewise.
Kai> 	* internal.h (_cpp_lex_identifier): New prototype.
Kai> 	(def_pragma_macro): New structure.
Kai> 	(cpp_reader): New member pushed_macros.
Kai> 	* lex.c (_cpp_lex_identifier): New function.
Kai> 	(lex_identifier_intern): New function.
Kai> 	* init.c (cpp_create_reader): Initialize pushed_macros
Kai> 	member.
Kai> 	(cpp_destroy): Free elements in pushed_macros member.
Kai> 	* pch.c (_cpp_save_pushed_macros): New function.
Kai> 	(_cpp_restore_pushed_macros): Likewise.
Kai> 	(_cpp_restore_pushed_macros): Use _cpp_save_pushed_macros.
Kai> 	(cpp_read_state): Use _cpp_restore_pushed_macros.

The libcpp parts are ok.

I can't approve the other bits.

Tom

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch]: Add push_macro/pop_macro feature for all targets by   moving it from C frontent into libcpp
  2009-11-10 16:19                 ` Tom Tromey
@ 2009-11-10 17:34                   ` Kai Tietz
  0 siblings, 0 replies; 19+ messages in thread
From: Kai Tietz @ 2009-11-10 17:34 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Paolo Bonzini, gcc-patches, Joseph S. Myers

2009/11/10 Tom Tromey <tromey@redhat.com>:
>>>>>> "Kai" == Kai Tietz <ktietz70@googlemail.com> writes:
>
> Kai> ChangeLog for libcpp
> Kai> 2009-11-03  Kai Tietz  <kai.tietz@onevision.com>
> Kai>    * directives.c (do_pragma_push_macro): New pragma handler.
> Kai>    (do_pragma_pop_macro): Likewise.
> Kai>    (_cpp_init_internal_pragmas): Add push_macro and
> Kai>    pop_macro handler to internal pragmas.
> Kai>    (lex_macro_node_from_str): Removed.
> Kai>    (cpp_push_definition): Replace lex_macro_node_from_str
> Kai>    by _cpp_lex_identifier.
> Kai>    (cpp_pop_definition): Likewise.
> Kai>    * internal.h (_cpp_lex_identifier): New prototype.
> Kai>    (def_pragma_macro): New structure.
> Kai>    (cpp_reader): New member pushed_macros.
> Kai>    * lex.c (_cpp_lex_identifier): New function.
> Kai>    (lex_identifier_intern): New function.
> Kai>    * init.c (cpp_create_reader): Initialize pushed_macros
> Kai>    member.
> Kai>    (cpp_destroy): Free elements in pushed_macros member.
> Kai>    * pch.c (_cpp_save_pushed_macros): New function.
> Kai>    (_cpp_restore_pushed_macros): Likewise.
> Kai>    (_cpp_restore_pushed_macros): Use _cpp_save_pushed_macros.
> Kai>    (cpp_read_state): Use _cpp_restore_pushed_macros.
>
> The libcpp parts are ok.
>
> I can't approve the other bits.
>
> Tom
>

Thanks for reviewing. As the parts changed by this patch in c-pragma.c
where just active for cygwin/mingw targets, and this patch just
removes implementation and TARGET macro there, I think that I can
approve it by  myself. I will commit it later, if there aren't an
objections.

Cheers,
Kai

-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2009-11-10 17:32 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-03 15:13 [patch]: Add push_macro/pop_macro feature for all targets by moving it from C frontent into libcpp Kai Tietz
2009-11-03 17:00 ` Joseph S. Myers
2009-11-03 17:09   ` Kai Tietz
2009-11-03 17:25     ` Joseph S. Myers
2009-11-03 17:32       ` Kai Tietz
2009-11-03 17:36 ` Tom Tromey
2009-11-03 18:30   ` Kai Tietz
2009-11-03 20:20     ` Kai Tietz
2009-11-04 16:25       ` Tom Tromey
2009-11-04 17:05         ` Kai Tietz
2009-11-04 18:13           ` Dave Korn
2009-11-04 18:18             ` Kai Tietz
2009-11-05 10:46         ` Kai Tietz
2009-11-05 16:23         ` Paolo Bonzini
2009-11-05 22:11           ` Kai Tietz
2009-11-06  9:39             ` Kai Tietz
2009-11-06  9:41               ` Kai Tietz
2009-11-10 16:19                 ` Tom Tromey
2009-11-10 17:34                   ` Kai Tietz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).