aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Booth <neil@daikokuya.demon.co.uk>2002-02-27 07:24:53 +0000
committerNeil Booth <neil@gcc.gnu.org>2002-02-27 07:24:53 +0000
commite808ec9c71e52aa64bdb4579ad2ef75802b7bcb5 (patch)
tree7ffd19f1f5d3104b1545c9af4c64c746cda65cbc
parentf585a35687df424814b57fd201253c11a19795f5 (diff)
downloadgcc-e808ec9c71e52aa64bdb4579ad2ef75802b7bcb5.zip
gcc-e808ec9c71e52aa64bdb4579ad2ef75802b7bcb5.tar.gz
gcc-e808ec9c71e52aa64bdb4579ad2ef75802b7bcb5.tar.bz2
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
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/cpplex.c5
-rw-r--r--gcc/cpplib.c16
-rw-r--r--gcc/cppmacro.c37
-rw-r--r--gcc/doc/cpp.texi44
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.dg/cpp/directiv.c7
-rw-r--r--gcc/testsuite/gcc.dg/cpp/mac-dir-1.c34
-rw-r--r--gcc/testsuite/gcc.dg/cpp/mac-dir-2.c16
-rw-r--r--gcc/testsuite/gcc.dg/cpp/undef1.c14
10 files changed, 143 insertions, 49 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8765f32..ee24ef7 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 eea6a9e..a5a20db 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 1a38f01..d9f95bd 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 538c689..d44ac49 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 d672e57..9e28e92 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 b45bd6d..ae4efb8 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 cbf4ac6..aafe2ec 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 0000000..002c47f
--- /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 0000000..b574cfd
--- /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 446fc93..0000000
--- 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 )