This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
cpp macro expansion for #pragmas
- From: Paul Rubin <phr-2006 at nightsong dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: 29 Sep 2006 14:09:51 -0000
- Subject: cpp macro expansion for #pragmas
- Reply-to: Paul Rubin <phr-2006 at nightsong dot com>
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
{