This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

cpp macro expansion for #pragmas


This is revived from several months back.  It adds cpp macro expansion
capability for #pragma directives, under control of a gcc command line
option (-expand-pragmas).  It's against version 117267 of the svn
tree, which is now a day or so old, except the testsuite/ChangeLog
diff is against a newer revision (but changelogs always get patch
conflicts anyway).  I'd like to submit it for GCC 4.3.  I've run the
full gcc test suite and while there are a number of unexpected
failures and successes, they're in non-cpp-related areas and I get the
same failures when running the tests using the unpatched cpp (2
unexpected failures in C, one unexpected success in C++, and 16
unexpected failures in Fortran, IIRC.  I think Fortran does not use
the cpp at all).  Please let me know of any probs.

Thanks / regards,

--Paul

(svn diff follows)

Index: gcc/doc/cpp.texi
===================================================================
--- gcc/doc/cpp.texi	(revision 117267)
+++ gcc/doc/cpp.texi	(working copy)
@@ -3859,9 +3859,16 @@
 @item Treatment of a @samp{#pragma} directive that after macro-expansion
 results in a standard pragma.
 
-No macro expansion occurs on any @samp{#pragma} directive line, so the
-question does not arise.
+Macro expansion in #pragma directives is controlled by the
+@option{-expand-pragmas} command line option.  If this option is not
+enabled, then no macro expansion occurs on any @samp{#pragma}
+directive line other than certain special GOMP-related pragmas which
+can't expand to standard pragmas, so the question does not arise.
 
+If the option is enabled, then macros are expanded in #pragma
+directives, @emph{except} for the STDC pragmas.  C99 requires that
+STDC pragmas @emph{not} be expanded.
+
 Note that GCC does not yet implement any of the standard
 pragmas.
 
Index: gcc/doc/cppopts.texi
===================================================================
--- gcc/doc/cppopts.texi	(revision 117267)
+++ gcc/doc/cppopts.texi	(working copy)
@@ -344,6 +344,20 @@
 location.  The filename may be absolute or it may be relative to GCC's
 current directory.
 
+@item -expand-pragmas
+@opindex expand-pragmas
+This option instructs the preprocessor to expand preprocessor macros
+inside @code{pragma} directives.  GCC's default is to never expand
+macros in @code{#pragma} directives, except for certain GOMP-related
+pragmas for which expansion is required.
+
+With @option{-expand-pragmas} set, GCC expands macros in pragmas,
+except for pragmas in the @code{STDC} namespace.  The C99 standard
+prohibits expansion of some specific pragmas, all of which are in
+@code{STDC}.  The standard leaves expansion of the other pragmas up to
+implementations.
+
+
 @end ifclear
 @item -x c
 @itemx -x c++
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c	(revision 117267)
+++ gcc/gcc.c	(working copy)
@@ -789,6 +789,7 @@
 static const char *cpp_options =
 "%(cpp_unique_options) %1 %{m*} %{std*&ansi&trigraphs} %{W*&pedantic*} %{w}\
  %{f*} %{g*:%{!g0:%{!fno-working-directory:-fworking-directory}}} %{O*}\
+ %{expand-pragmas}\
  %{undef} %{save-temps:-fpch-preprocess}";
 
 /* This contains cpp options which are not passed when the preprocessor
@@ -1078,6 +1079,7 @@
    {"--dumpbase", "-dumpbase", "a"},
    {"--encoding", "-fencoding=", "aj"},
    {"--entry", "-e", 0},
+   {"--expand-pragmas", "-expand-pragmas", 0},
    {"--extra-warnings", "-W", 0},
    {"--extdirs", "-fextdirs=", "aj"},
    {"--for-assembler", "-Wa", "a"},
Index: gcc/ChangeLog
===================================================================
--- gcc/ChangeLog	(revision 117267)
+++ gcc/ChangeLog	(working copy)
@@ -1,3 +1,18 @@
+2006-09-27  Paul Rubin  <phr-gcc@nightsong.com>
+
+	* c-ppoutput.c (cb_def_pragma): use scan_translation_unit
+	instead of cpp_output_line to copy pragmas, allowing re-use
+	of scan_translation_unit's complex paste avoidance logic.
+        (preprocess_file): pass new arg to scan_translation_unit.
+	(scan_translation_unit): add 'ipad' arg for use with pragma expansion.
+
+	*  c.opt (expand-pragmas): new flag.
+
+	* c-opts.c (c_common_handle_option) add OPT_expand_pragmas
+
+	* gcc.c (option_map): add -expand-pragmas
+	(cpp_options): add (--expand-pragmas)
+
 2006-09-27  Steven G. Kargl  <kargl@gcc.gnu.org>
 
 	* doc/install.texi: Document required versions of GMP and MPFR.
Index: gcc/testsuite/gcc.dg/cpp/pragma-exp0.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/pragma-exp0.c	(revision 0)
+++ gcc/testsuite/gcc.dg/cpp/pragma-exp0.c	(revision 0)
@@ -0,0 +1,21 @@
+/* { dg-do preprocess } */
+
+/* Test that without -expand-pragmas, preprocessor symbols in pragmas
+   don't get expanded.
+ */
+
+
+#pragma frobozz
+int x = 3;
+
+#define frobozz muffin
+#pragma frobozz
+
+/* make sure there's not unwanted token pasting */
+#define FOO abc
+#define BAR def
+#pragma FOO BAR ghi
+
+/* { dg-final { scan-file pragma-exp0.i "#pragma frobozz" } } */
+/* { dg-final { scan-file-not pragma-exp0.i "#pragma muffin" } } */
+/* { dg-final { scan-file pragma-exp0.i "#pragma FOO BAR ghi" } } */
Index: gcc/testsuite/gcc.dg/cpp/pragma-exp1.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/pragma-exp1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/cpp/pragma-exp1.c	(revision 0)
@@ -0,0 +1,44 @@
+/* { dg-do preprocess } */
+/* { dg-options -expand-pragmas } */
+
+/* test that expand-pragmas causes pragma <preprocessor symbol>
+   to get expanded */
+
+#pragma frobozz
+int x = 3;
+
+#define frobozz muffin
+#pragma frobozz
+
+/* make sure there's not unwanted token pasting */
+#define FOO abc
+#define BAR def
+#pragma FOO BAR ghi
+
+/* check that STDC pragmas aren't expanded, per C99 */
+#pragma STDC abc FOO xyz
+
+/* even if STDC is redefined */
+#define STDC blah
+#pragma STDC abc2 FOO xyz
+
+/* expand a macro with arguments */
+#define ADD(x,y,z) x+y+z
+
+/* check that macro with args gets expanded correctly at beginning of
+   pragma */
+#pragma ADD(a,b,c) xyz
+
+/* and also when not at the beginning */
+#pragma xyz ADD(a,b,c)
+
+
+/* { dg-final { scan-file pragma-exp1.i "#pragma frobozz" } } */
+/* { dg-final { scan-file pragma-exp1.i "#pragma muffin" } } */
+/* { dg-final { scan-file pragma-exp1.i "#pragma abc def ghi" } } */
+/* { dg-final { scan-file pragma-exp1.i "#pragma STDC abc FOO xyz" } } */
+/* { dg-final { scan-file pragma-exp1.i "#pragma STDC abc2 FOO xyz" } } */
+/* { dg-final { scan-file-not pragma-exp1.i "#pragma STDC abc abc xyz" } } */
+/* { dg-final { scan-file-not pragma-exp1.i "#pragma blah" } } */
+/* { dg-final { scan-file pragma-exp1.i "#pragma a\\+b\\+c xyz" } } */
+/* { dg-final { scan-file pragma-exp1.i "#pragma xyz a\\+b\\+c" } } */
Index: gcc/testsuite/ChangeLog
===================================================================
--- gcc/testsuite/ChangeLog	(revision 117274)
+++ gcc/testsuite/ChangeLog	(working copy)
@@ -1,3 +1,8 @@
+2006-09-27  Paul Rubin <phr-gcc@nightsong.com>
+ 
+ 	* gcc.dg/cpp/pragma-exp0.c, gcc.dg/cpp/pragma-exp1.c:
+ 	new tests.
+
 2006-09-27  Steven G. Kargl  <kargls@gcc.gnu.org>
 
 	PR fortran/28276
Index: gcc/c.opt
===================================================================
--- gcc/c.opt	(revision 117267)
+++ gcc/c.opt	(working copy)
@@ -435,6 +435,10 @@
 C ObjC C++ ObjC++ Joined
 ; Documented in common.opt.  FIXME - what about -dI, -dD, -dN and -dD?
 
+expand-pragmas
+C ObjC C++ ObjC++
+Expand preprocessor macros in #pragma statements
+
 faccess-control
 C++ ObjC++
 Enforce class member access control semantics
Index: gcc/c-opts.c
===================================================================
--- gcc/c-opts.c	(revision 117267)
+++ gcc/c-opts.c	(working copy)
@@ -555,6 +555,10 @@
       handle_OPT_d (arg);
       break;
 
+    case OPT_expand_pragmas:
+      cpp_opts->expand_pragmas = true;
+      break;
+
     case OPT_fcond_mismatch:
       if (!c_dialect_cxx ())
 	{
Index: gcc/c-ppoutput.c
===================================================================
--- gcc/c-ppoutput.c	(revision 117267)
+++ gcc/c-ppoutput.c	(working copy)
@@ -40,7 +40,7 @@
 } print;
 
 /* General output routines.  */
-static void scan_translation_unit (cpp_reader *);
+static void scan_translation_unit (cpp_reader *, bool);
 static void scan_translation_unit_trad (cpp_reader *);
 static void account_for_newlines (const unsigned char *, size_t);
 static int dump_macro (cpp_reader *, cpp_hashnode *, void *);
@@ -76,7 +76,7 @@
   else if (cpp_get_options (pfile)->traditional)
     scan_translation_unit_trad (pfile);
   else
-    scan_translation_unit (pfile);
+    scan_translation_unit (pfile, false);
 
   /* -dM command line option.  Should this be elsewhere?  */
   if (flag_dump_macros == 'M')
@@ -131,9 +131,12 @@
 }
 
 /* Writes out the preprocessed file, handling spacing and paste
-   avoidance issues.  */
+   avoidance issues.  IPAD means make sure not to paste to previous
+   token (which might not be flagged with PREV_WHITE depending on
+   where it came from). */
+
 static void
-scan_translation_unit (cpp_reader *pfile)
+scan_translation_unit (cpp_reader *pfile, bool ipad)
 {
   bool avoid_paste = false;
 
@@ -142,6 +145,9 @@
     {
       const cpp_token *token = cpp_get_token (pfile);
 
+      if (ipad)
+	avoid_paste = true;
+
       if (token->type == CPP_PADDING)
 	{
 	  avoid_paste = true;
@@ -160,11 +166,15 @@
 	{
 	  if (print.source == NULL)
 	    print.source = token;
-	  if (print.source->flags & PREV_WHITE
+	  if (ipad
+	      || print.source->flags & PREV_WHITE
 	      || (print.prev
 		  && cpp_avoid_paste (pfile, print.prev, token))
 	      || (print.prev == NULL && token->type == CPP_HASH))
-	    putc (' ', print.outf);
+	    {
+	      putc (' ', print.outf);
+	      ipad = false;
+	    }
 	}
       else if (token->flags & PREV_WHITE)
 	putc (' ', print.outf);
@@ -422,8 +432,9 @@
 cb_def_pragma (cpp_reader *pfile, source_location line)
 {
   maybe_print_line (line);
-  fputs ("#pragma ", print.outf);
-  cpp_output_line (pfile, print.outf);
+  fputs ("#pragma", print.outf);
+  scan_translation_unit (pfile, true);
+  putc ('\n', print.outf);
   print.src_line++;
 }
 
Index: libcpp/macro.c
===================================================================
--- libcpp/macro.c	(revision 117267)
+++ libcpp/macro.c	(working copy)
@@ -1061,6 +1061,15 @@
   pfile->context = context->prev;
 }
 
+/* utility function for cpp_get_token, to check whether a padding
+   token is needed at this place in the input. */
+static inline bool
+dont_pad(cpp_reader *pfile)
+{
+  return pfile->state.in_directive &&
+    !pfile->state.directive_wants_padding;
+}
+
 /* External routine to get a token.  Also used nearly everywhere
    internally, except for places where we know we can safely call
    _cpp_lex_token directly, such as lexing a directive name.
@@ -1095,7 +1104,7 @@
 	  if (result->flags & PASTE_LEFT)
 	    {
 	      paste_all_tokens (pfile, result);
-	      if (pfile->state.in_directive)
+	      if (dont_pad (pfile))
 		continue;
 	      return padding_token (pfile, result);
 	    }
@@ -1103,7 +1112,7 @@
       else
 	{
 	  _cpp_pop_context (pfile);
-	  if (pfile->state.in_directive)
+	  if (dont_pad (pfile))
 	    continue;
 	  return &pfile->avoid_paste;
 	}
@@ -1124,7 +1133,7 @@
 	  if (!pfile->state.prevent_expansion
 	      && enter_macro_context (pfile, node))
 	    {
-	      if (pfile->state.in_directive)
+	      if (dont_pad (pfile))
 		continue;
 	      return padding_token (pfile, result);
 	    }
Index: libcpp/directives.c
===================================================================
--- libcpp/directives.c	(revision 117267)
+++ libcpp/directives.c	(working copy)
@@ -1259,7 +1259,9 @@
    expansion happens for other pragmas is implementation defined.
    This implementation allows for a mix of both, since GCC did not
    traditionally macro expand its (few) pragmas, whereas OpenMP
-   specifies that macro expansion should happen.  */
+   specifies that macro expansion should happen.  It also supports
+   a command-line option (-expand-pragmas) that causes all pragmas
+   to be expanded by default. */
 static void
 do_pragma (cpp_reader *pfile)
 {
@@ -1268,10 +1270,43 @@
   cpp_token ns_token;
   unsigned int count = 1;
 
+  char save_directive_wants_padding;
+  bool reenable_expansion;
+
+  /* Decide whether to expand macros as follows:
+     1. Turn off macro expansion
+     2. Read token to find out what namespace
+     3. If it's STDC, don't re-enable expansion
+     4. Otherwise, enable expansion if expand_pragmas is turned on,
+        and push back the token. */
+
   pfile->state.prevent_expansion++;
+  reenable_expansion = true;
 
   token = cpp_get_token (pfile);
   ns_token = *token;
+
+  /* for testing effect of the pragma expansion feature on code that
+     doesn't expect it, set this to 1 and it will always expand regardless
+     of the -expand-pragmas option. */
+#define ALWAYS_EXPAND 0
+
+#if !ALWAYS_EXPAND
+  if (CPP_OPTION(pfile, expand_pragmas) &&
+      token->type == CPP_NAME &&
+      (NODE_LEN(token->val.node) != 4 ||
+       ustrncmp(NODE_NAME(token->val.node), (unsigned char *) "STDC", 4)))
+#endif
+    {
+      _cpp_backup_tokens(pfile, 1);
+      pfile->state.prevent_expansion--;      
+      reenable_expansion = false;
+      token = cpp_get_token (pfile);
+    }
+
+  save_directive_wants_padding = pfile->state.directive_wants_padding;
+  pfile->state.directive_wants_padding = 1;
+
   if (token->type == CPP_NAME)
     {
       p = lookup_pragma_entry (pfile->pragmas, token->val.node);
@@ -1280,7 +1315,9 @@
 	  bool allow_name_expansion = p->allow_expansion;
 	  if (allow_name_expansion)
 	    pfile->state.prevent_expansion--;
-	  token = cpp_get_token (pfile);
+	  do {
+	    token = cpp_get_token (pfile);
+	  } while (token->type == CPP_PADDING);
 	  if (token->type == CPP_NAME)
 	    p = lookup_pragma_entry (p->u.space, token->val.node);
 	  else
@@ -1339,7 +1376,10 @@
       pfile->cb.def_pragma (pfile, pfile->directive_line);
     }
 
-  pfile->state.prevent_expansion--;
+  if (reenable_expansion)
+    pfile->state.prevent_expansion--;
+
+  pfile->state.directive_wants_padding = save_directive_wants_padding;
 }
 
 /* Handle #pragma once.  */
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h	(revision 117267)
+++ libcpp/include/cpplib.h	(working copy)
@@ -405,6 +405,9 @@
   /* True if dependencies should be restored from a precompiled header.  */
   bool restore_pch_deps;
 
+  /* True if #pragma statements should be macro-expanded. */
+  bool expand_pragmas;
+
   /* Dependency generation.  */
   struct
   {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]