diff options
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/cpplex.c | 5 | ||||
-rw-r--r-- | gcc/cpplib.c | 16 | ||||
-rw-r--r-- | gcc/cppmacro.c | 37 | ||||
-rw-r--r-- | gcc/doc/cpp.texi | 44 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/directiv.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/mac-dir-1.c | 34 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/mac-dir-2.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cpp/undef1.c | 14 |
10 files changed, 143 insertions, 49 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8765f325205..ee24ef77f20 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2002-02-27 Neil Booth <neil@daikokuya.demon.co.uk> + + * cpplex.c (_cpp_lex_token): Handle directives in macro + arguments. + * cpplib.c (_cpp_handle_directive): Save and restore state + if parsing macro args when entering a directive. + * cppmacro.c (collect_args): No need to handle directives + in macro arguments. + (enter_macro_context, replace_args): Use the original macro + definition in case it was redefined whilst collecting arguments. +doc: + * cpp.texi: Update. + 2002-02-26 David Edelsohn <edelsohn@gnu.org> * config/rs6000/aix43.h (THREAD_MODEL_SPEC): Delete. diff --git a/gcc/cpplex.c b/gcc/cpplex.c index eea6a9e1c53..a5a20db73d1 100644 --- a/gcc/cpplex.c +++ b/gcc/cpplex.c @@ -828,7 +828,10 @@ _cpp_lex_token (pfile) /* Is this a directive. If _cpp_handle_directive returns false, it is an assembler #. */ if (result->type == CPP_HASH - && !pfile->state.parsing_args + /* 6.10.3 p 11: Directives in a list of macro arguments + gives undefined behavior. This implementation + handles the directive as normal. */ + && pfile->state.parsing_args != 1 && _cpp_handle_directive (pfile, result->flags & PREV_WHITE)) continue; if (pfile->cb.line_change && !pfile->state.skipping) diff --git a/gcc/cpplib.c b/gcc/cpplib.c index 1a38f01c2fb..d9f95bd216d 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -316,8 +316,17 @@ _cpp_handle_directive (pfile, indented) { const directive *dir = 0; const cpp_token *dname; + bool was_parsing_args = pfile->state.parsing_args; int skip = 1; + if (was_parsing_args) + { + if (CPP_OPTION (pfile, pedantic)) + cpp_pedwarn (pfile, + "embedding a directive within macro arguments is not portable"); + pfile->state.parsing_args = 0; + pfile->state.prevent_expansion = 0; + } start_directive (pfile); dname = _cpp_lex_token (pfile); @@ -393,6 +402,13 @@ _cpp_handle_directive (pfile, indented) _cpp_backup_tokens (pfile, 1); end_directive (pfile, skip); + if (was_parsing_args) + { + /* Restore state when within macro args. */ + pfile->state.parsing_args = 2; + pfile->state.prevent_expansion = 1; + pfile->buffer->saved_flags |= PREV_WHITE; + } return skip; } diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c index 538c689b1e5..d44ac498658 100644 --- a/gcc/cppmacro.c +++ b/gcc/cppmacro.c @@ -74,7 +74,8 @@ static const cpp_token *stringify_arg PARAMS ((cpp_reader *, macro_arg *)); static void paste_all_tokens PARAMS ((cpp_reader *, const cpp_token *)); static bool paste_tokens PARAMS ((cpp_reader *, const cpp_token **, const cpp_token *)); -static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_arg *)); +static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, cpp_macro *, + macro_arg *)); static _cpp_buff *funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *)); /* #define directive parsing and handling. */ @@ -546,34 +547,15 @@ collect_args (pfile, node) arg++; } } - while (token->type != CPP_CLOSE_PAREN - && token->type != CPP_EOF - && token->type != CPP_HASH); + while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF); - if (token->type == CPP_EOF || token->type == CPP_HASH) + if (token->type == CPP_EOF) { - bool step_back = false; - - /* 6.10.3 paragraph 11: If there are sequences of preprocessing - tokens within the list of arguments that would otherwise act - as preprocessing directives, the behavior is undefined. - - This implementation will report a hard error, terminate the - macro invocation, and proceed to process the directive. */ - if (token->type == CPP_HASH) - { - cpp_error (pfile, - "directives may not be used inside a macro argument"); - step_back = true; - } - else - step_back = (pfile->context->prev || pfile->state.in_directive); - /* We still need the CPP_EOF to end directives, and to end pre-expansion of a macro argument. Step back is not unconditional, since we don't want to return a CPP_EOF to our callers at the end of an -include-d file. */ - if (step_back) + if (pfile->context->prev || pfile->state.in_directive) _cpp_backup_tokens (pfile, 1); cpp_error (pfile, "unterminated argument list invoking macro \"%s\"", NODE_NAME (node)); @@ -697,8 +679,8 @@ enter_macro_context (pfile, node) return 0; } - if (node->value.macro->paramc > 0) - replace_args (pfile, node, (macro_arg *) buff->base); + if (macro->paramc > 0) + replace_args (pfile, node, macro, (macro_arg *) buff->base); _cpp_release_buff (pfile, buff); } @@ -720,9 +702,10 @@ enter_macro_context (pfile, node) Expand each argument before replacing, unless it is operated upon by the # or ## operators. */ static void -replace_args (pfile, node, args) +replace_args (pfile, node, macro, args) cpp_reader *pfile; cpp_hashnode *node; + cpp_macro *macro; macro_arg *args; { unsigned int i, total; @@ -730,13 +713,11 @@ replace_args (pfile, node, args) const cpp_token **dest, **first; macro_arg *arg; _cpp_buff *buff; - cpp_macro *macro; /* First, fully macro-expand arguments, calculating the number of tokens in the final expansion as we go. The ordering of the if statements below is subtle; we must handle stringification before pasting. */ - macro = node->value.macro; total = macro->count; limit = macro->expansion + macro->count; diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi index d672e575cf5..9e28e92e800 100644 --- a/gcc/doc/cpp.texi +++ b/gcc/doc/cpp.texi @@ -121,6 +121,7 @@ Macros * Variadic Macros:: * Predefined Macros:: * Undefining and Redefining Macros:: +* Directives Within Macro Arguments:: * Macro Pitfalls:: Predefined Macros @@ -1115,6 +1116,7 @@ macros when you are compiling C++. * Variadic Macros:: * Predefined Macros:: * Undefining and Redefining Macros:: +* Directives Within Macro Arguments:: * Macro Pitfalls:: @end menu @@ -2116,6 +2118,48 @@ the same, the redefinition is silently ignored. This allows, for instance, two different headers to define a common macro. The preprocessor will only complain if the definitions do not match. +@node Directives Within Macro Arguments +@section Directives Within Macro Arguments +@cindex macro arguments and directives + +Occasionally it is convenient to use preprocessor directives within +the arguments of a macro. The C and C++ standards declare that +behavior in these cases is undefined. + +Versions of GNU CPP prior to 3.2 would reject such constructs with an +error message. This was the only syntactic difference between normal +functions and function-like macros, so it seemed attractive to remove +this limitation, and people would often be surprised that they could +not use macros in this way. Moreover, sometimes people would use +conditional compilation in the argument list to a normal library +function like @samp{printf}, only to find that after a library upgrade +@samp{printf} had changed to be a function-like macro, and their code +would no longer compile. So from version 3.2 we changed CPP to +successfully process arbitrary directives within macro arguments in +exactly the same way as it would have processed the directive were the +function-like macro invocation not present. + +If, within a macro invocation, that macro is redefined, then the new +definition takes effect in time for argument pre-expansion, but the +original definition is still used for argument replacement. Here is a +pathological example: + +@smallexample +#define f(x) x x +f (1 +#undef f +#define f 2 +f) +@end smallexample + +@noindent which expands to + +@smallexample +1 2 1 2 +@end smallexample + +@noindent with the semantics described above. + @node Macro Pitfalls @section Macro Pitfalls @cindex problems with macros diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b45bd6d7f49..ae4efb8fa76 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2002-02-27 Neil Booth <neil@daikokuya.demon.co.uk> + + * gcc.dg/cpp/undef1.c: Remove. + * gcc.dg/cpp/directiv.c: Update. + * gcc.dg/cpp/mac-dir-1.c, mac-dir-2.c: New tests. + 2002-02-27 Michael Meissner <meissner@redhat.com> * gcc.c-torture/execute/20020226-1.c: New test. diff --git a/gcc/testsuite/gcc.dg/cpp/directiv.c b/gcc/testsuite/gcc.dg/cpp/directiv.c index cbf4ac6501c..aafe2ec109d 100644 --- a/gcc/testsuite/gcc.dg/cpp/directiv.c +++ b/gcc/testsuite/gcc.dg/cpp/directiv.c @@ -25,16 +25,11 @@ EMPTY #define bar /* Our friend the null directive OK? */ # -/* Check that directives always start a line, even if in middle of - macro expansion. */ -#define func(x) x -func (2 /* { dg-error "unterminated" "" } */ -#define foobar /* { dg-error "directives may not" } */ - /* Check newlines end directives, even in function-like macro invocations. 6.10 paragraph 1. Note that the #if is still treated as a conditional, so there should be no errors about #endif without #if. */ +#define func(x) x #if func ( /* { dg-error "unterminated argument" } */ #endif diff --git a/gcc/testsuite/gcc.dg/cpp/mac-dir-1.c b/gcc/testsuite/gcc.dg/cpp/mac-dir-1.c new file mode 100644 index 00000000000..002c47f5f2b --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/mac-dir-1.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. */ + +/* { dg-do preprocess } */ + +/* Source: Neil Booth, 26 Feb 2002. + + Test that we allow directives in macro arguments. */ + +/* { dg-do run } */ +/* { dg-options "" } */ + +#define f(x) x +extern void abort (void); + +int main () +{ + if (f ( +#if f(1) /* True. */ + 0)) /* False. */ +#else + 1)) +#endif + abort (); + + /* Outer f expands to original definition, f in argument expands + to new definition, so result is: if (1 != 2 - 1). */ + if (1 != f(2 +#undef f +#define f - 1 + f)) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/cpp/mac-dir-2.c b/gcc/testsuite/gcc.dg/cpp/mac-dir-2.c new file mode 100644 index 00000000000..b574cfd71cf --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/mac-dir-2.c @@ -0,0 +1,16 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. */ + +/* { dg-do preprocess } */ + +/* Source: Neil Booth, 26 Feb 2002. + + Test that we allow directives in macro arguments. */ + +/* { dg-do preprocess } */ + +#define f(x) x + +f ( +#if 1 /* { dg-warning "not portable" } */ +1) +#endif diff --git a/gcc/testsuite/gcc.dg/cpp/undef1.c b/gcc/testsuite/gcc.dg/cpp/undef1.c deleted file mode 100644 index 446fc93117d..00000000000 --- a/gcc/testsuite/gcc.dg/cpp/undef1.c +++ /dev/null @@ -1,14 +0,0 @@ -/* { dg-do preprocess } */ - -/* 6.9.3.11: ...If there are sequences of preprocessing tokens within - the list of arguments that would otherwise act as preprocessing - directives, the behavior is undefined. - - I choose to make this a hard error. It definitely should not cause - a core dump. */ - -#define foo(bar) bar - -foo( blah /* { dg-error "unterminated" "" } */ -#undef foo /* { dg-error "may not be used inside" "foo(#undef foo)" } */ - blah ) |