* cpplex.c (_cpp_lex_token): Handle directives in macro
authorneil <neil@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 27 Feb 2002 07:24:53 +0000 (07:24 +0000)
committerneil <neil@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 27 Feb 2002 07:24:53 +0000 (07:24 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@50091 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cpplex.c
gcc/cpplib.c
gcc/cppmacro.c
gcc/doc/cpp.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cpp/directiv.c
gcc/testsuite/gcc.dg/cpp/mac-dir-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/mac-dir-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/undef1.c [deleted file]

index 8765f32..ee24ef7 100644 (file)
@@ -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.
index eea6a9e..a5a20db 100644 (file)
@@ -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)
index 1a38f01..d9f95bd 100644 (file)
@@ -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;
 }
 
index 538c689..d44ac49 100644 (file)
@@ -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;
 
index d672e57..9e28e92 100644 (file)
@@ -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
index b45bd6d..ae4efb8 100644 (file)
@@ -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.
index cbf4ac6..aafe2ec 100644 (file)
@@ -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 (file)
index 0000000..002c47f
--- /dev/null
@@ -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 (file)
index 0000000..b574cfd
--- /dev/null
@@ -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 (file)
index 446fc93..0000000
+++ /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 )