cpplex.c (_cpp_lex_token): Handle directives in macro arguments.
* 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. testsuite: * 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. From-SVN: r50091
This commit is contained in:
parent
f585a35687
commit
e808ec9c71
10 changed files with 143 additions and 49 deletions
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
16
gcc/cpplib.c
16
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
34
gcc/testsuite/gcc.dg/cpp/mac-dir-1.c
Normal file
34
gcc/testsuite/gcc.dg/cpp/mac-dir-1.c
Normal file
|
@ -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;
|
||||
}
|
16
gcc/testsuite/gcc.dg/cpp/mac-dir-2.c
Normal file
16
gcc/testsuite/gcc.dg/cpp/mac-dir-2.c
Normal file
|
@ -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
|
|
@ -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 )
|
Loading…
Add table
Reference in a new issue