OSDN Git Service

* cpphash.c (is__va_args__): New function.
authorneil <neil@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 8 Jul 2000 02:18:25 +0000 (02:18 +0000)
committerneil <neil@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 8 Jul 2000 02:18:25 +0000 (02:18 +0000)
(count_params): Fix line reported in error messages.  Use
is__va_args__.  Don't return ')' on error.  Flag GNU style
rest args macro definitions.
(parse_define): Check macro name is not __VA_ARGS__.
(save_expansion): Check identifier in non-varargs-macro is
not __VA_ARGS__.  Don't flag GNU_VARARGS.
* cpplex.c (parse_args): Accept no argument iff GNU_REST_ARGS.
(maybe_paste_with_next): Use per-macro GNU_REST_ARGS rather
 than per-token GNU_VARARGS.
* cpplib.h (GNU_VARARGS): Remove.
(GNU_REST_ARGS): New.

* gcc.dg/cpp/macsyntx.c: New tests.

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

gcc/ChangeLog
gcc/cpphash.c
gcc/cpplex.c
gcc/cpplib.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cpp/macsyntx.c [new file with mode: 0644]

index decd31f..eaee6c8 100644 (file)
@@ -1,3 +1,18 @@
+2000-07-08  Neil Booth  <NeilB@earthling.net>
+
+       * cpphash.c (is__va_args__): New function.
+       (count_params): Fix line reported in error messages.  Use
+       is__va_args__.  Don't return ')' on error.  Flag GNU style
+       rest args macro definitions.
+       (parse_define): Check macro name is not __VA_ARGS__.
+       (save_expansion): Check identifier in non-varargs-macro is
+       not __VA_ARGS__.  Don't flag GNU_VARARGS.
+       * cpplex.c (parse_args): Accept no argument iff GNU_REST_ARGS.
+       (maybe_paste_with_next): Use per-macro GNU_REST_ARGS rather
+        than per-token GNU_VARARGS.
+       * cpplib.h (GNU_VARARGS): Remove.
+       (GNU_REST_ARGS): New.
+
 Sat Jul  8 01:38:25 MET DST 2000  Jan Hubicka  <jh@suse.cz>
 
        * i386.md (call_pop, call, call_value_pop): Do not set
index 2007c52..ee0521b 100644 (file)
@@ -52,6 +52,7 @@ static void dump_funlike_macro        PARAMS ((cpp_reader *, cpp_hashnode *));
 static const cpp_token *count_params PARAMS ((cpp_reader *,
                                              const cpp_token *,
                                              cpp_toklist *));
+static int is__va_args__ PARAMS ((cpp_reader *, const cpp_token *));
 static cpp_toklist *parse_define PARAMS((cpp_reader *));
 static int check_macro_redefinition PARAMS((cpp_reader *, cpp_hashnode *hp,
                                             const cpp_toklist *));
@@ -197,6 +198,26 @@ find_param (first, token)
   return 0;
 }
 
+/* Constraint 6.10.3.5: __VA_ARGS__ should only appear in the
+   replacement list of a variable-arguments macro.  TOKEN is assumed
+   to be of type CPP_NAME.  */
+static int
+is__va_args__ (pfile, token)
+     cpp_reader *pfile;
+     const cpp_token *token;
+{
+  if (!CPP_OPTION (pfile, pedantic)
+      || token->val.name.len != sizeof (var_args_str) - 1
+      || ustrncmp (token->val.name.text, var_args_str,
+                  sizeof (var_args_str) - 1))
+    return 0;
+
+  cpp_pedwarn_with_line (pfile, token->line, token->col,
+       "\"%s\" is only valid in the replacement list of a function-like macro",
+                      var_args_str);
+  return 1;
+}
+
 /* Counts the parameters to a function like macro, and saves their
    spellings if necessary.  Returns the token that we stopped scanning
    at; if it's type isn't CPP_CLOSE_PAREN there was an error, which
@@ -208,7 +229,6 @@ count_params (pfile, first, list)
      cpp_toklist *list;
 {
   unsigned int params_len = 0, prev_ident = 0;
-  unsigned int line = pfile->token_list.line;
   const cpp_token *token, *temp;
 
   list->paramc = 0;
@@ -217,7 +237,8 @@ count_params (pfile, first, list)
       switch (token->type)
        {
        case CPP_EOF:
-         cpp_error_with_line (pfile, line, token->col,
+       missing_paren:
+         cpp_error_with_line (pfile, token->line, token->col,
                               "missing ')' in macro parameter list");
          goto out;
 
@@ -227,21 +248,14 @@ count_params (pfile, first, list)
        case CPP_NAME:
          if (prev_ident)
            {
-             cpp_error_with_line (pfile, line, token->col,
+             cpp_error_with_line (pfile, token->line, token->col,
                           "macro parameters must be comma-separated");
              goto out;
            }
 
          /* Constraint 6.10.3.5  */
-         if (token->val.name.len == sizeof (var_args_str) - 1
-             && !ustrncmp (token->val.name.text, var_args_str,
-                           sizeof (var_args_str) - 1))
-           {
-             cpp_error_with_line (pfile, line, token->col,
-                                  "\"%s\" is not a valid parameter name",
-                                  var_args_str);
-             goto out;
-           }
+         if (is__va_args__ (pfile, token))
+           goto out;
 
          params_len += token->val.name.len + 1;
          prev_ident = 1;
@@ -250,7 +264,7 @@ count_params (pfile, first, list)
          /* Constraint 6.10.3.6 - duplicate parameter names.  */
          if (find_param (first, token))
            {
-             cpp_error_with_line (pfile, line, token->col,
+             cpp_error_with_line (pfile, token->line, token->col,
                                   "duplicate macro parameter \"%.*s\"",
                                   (int) token->val.name.len,
                                   token->val.name.text);
@@ -259,7 +273,7 @@ count_params (pfile, first, list)
          break;
 
        default:
-         cpp_error_with_line (pfile, line, token->col,
+         cpp_error_with_line (pfile, token->line, token->col,
                               "illegal token in macro parameter list");
          goto out;
 
@@ -271,8 +285,10 @@ count_params (pfile, first, list)
        case CPP_COMMA:
          if (!prev_ident)
            {
-             cpp_error_with_line (pfile, line, token->col,
-                                  "missing parameter name");
+             cpp_error_with_line (pfile, token->line, token->col,
+                                  "parameter name expected");
+             if (token->type == CPP_CLOSE_PAREN)
+               token--;                /* Return the ',' not ')'.  */
              goto out;
            }
          prev_ident = 0;
@@ -293,22 +309,24 @@ count_params (pfile, first, list)
              tok->val.name.len = sizeof (var_args_str) - 1;
              tok->val.name.text = var_args_str; /* Safe.  */
              list->paramc++;
-
+         
              if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99))
                cpp_pedwarn (pfile,
                             "C89 does not permit anon varargs macros");
            }
-         else if (CPP_PEDANTIC (pfile))
-           cpp_pedwarn (pfile,
-                        "ISO C does not permit named varargs parameters");
+         else
+           {
+             list->flags |= GNU_REST_ARGS;
+             if (CPP_PEDANTIC (pfile))
+               cpp_pedwarn (pfile,
+                            "ISO C does not permit named varargs parameters");
+           }
 
          list->flags |= VAR_ARGS;
          token++;
          if (token->type == CPP_CLOSE_PAREN)
            goto scanned;
-         cpp_error_with_line (pfile, line, token->col,
-                              "')' expected after \"...\"");
-         goto out;
+         goto missing_paren;
        }
     }
 
@@ -345,8 +363,15 @@ parse_define (pfile)
   cpp_toklist *list;
   int prev_white = 0;
 
-  while ((token = cpp_get_token (pfile))->type == CPP_COMMENT)
-    prev_white = 1;
+  /* The first token after the macro's name.  */
+  token = cpp_get_token (pfile);
+
+  /* Constraint 6.10.3.5  */
+  if (is__va_args__ (pfile, token - 1))
+    return 0;
+
+  while (token->type == CPP_COMMENT)
+    token++, prev_white = 1;
 
   /* Allocate the expansion's list.  It will go in the hash table.  */
   list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist));
@@ -461,6 +486,12 @@ save_expansion (pfile, list, first, first_param)
                }
            }
        }
+      else if (token->type == CPP_NAME)
+       {
+         /* Constraint 6.10.3.5  */
+         if (!(list->flags & VAR_ARGS) && is__va_args__ (pfile, token))
+           return 1;
+       }
       ntokens++;
       if (token_spellings[token->type].type > SPELL_NONE)
        len += token->val.name.len;
@@ -497,10 +528,6 @@ save_expansion (pfile, list, first, first_param)
            dest->flags = token[-1].flags | STRINGIFY_ARG;
          else
            dest->flags = token->flags;  /* Particularly PREV_WHITE.  */
-
-         if ((int) param_no == list->paramc && list->flags & VAR_ARGS
-             && dest != list->tokens && dest[-1].flags & PASTE_LEFT)
-           dest[-1].flags |= GNU_VARARGS;
          dest++;
          continue;
 
index 24e4712..03439fa 100644 (file)
@@ -2222,9 +2222,9 @@ parse_args (pfile, hp, args)
         e.g. #define debug(format, args...) ...
         debug("string");
         This is exactly the same as if the rest argument had received no
-        tokens - debug("string",);  */
+        tokens - debug("string",);  This extension is deprecated.  */
        
-      if (argc + 1 == macro->paramc && (macro->flags & VAR_ARGS))
+      if (argc + 1 == macro->paramc && (macro->flags & GNU_REST_ARGS))
        {
          /* Duplicate the placemarker.  Then we can set its flags and
              position and safely be using more than one.  */
@@ -2525,15 +2525,19 @@ maybe_paste_with_next (pfile, token)
   second = cpp_get_token (pfile);
   pfile->paste_level = 0;
 
-  /* Ignore placemarker argument tokens.  */
+  /* Ignore placemarker argument tokens (cannot be from an empty macro
+     since macros are not expanded).  */
   if (token->type == CPP_PLACEMARKER)
      pasted = duplicate_token (pfile, second);
   else if (second->type == CPP_PLACEMARKER)
     {
+      cpp_context *mac_context = CURRENT_CONTEXT (pfile) - 1;
       /* GCC has special extended semantics for a ## b where b is a
         varargs parameter: a disappears if b consists of no tokens.
         This extension is deprecated.  */
-      if (token->flags & GNU_VARARGS)
+      if ((mac_context->u.list->flags & GNU_REST_ARGS)
+         && (mac_context->u.list->tokens[mac_context->posn - 1].val.aux + 1
+             == (unsigned) mac_context->u.list->paramc))
        {
          cpp_warning (pfile, "deprecated GNU ## extension used");
          pasted = duplicate_token (pfile, second);
index 1c516a6..e9bb24f 100644 (file)
@@ -158,7 +158,6 @@ struct cpp_name
 #define STRINGIFY_ARG  (1 << 3) /* If macro argument to be stringified.  */
 #define PASTE_LEFT     (1 << 4) /* If on LHS of a ## operator.  */
 #define PASTED         (1 << 5) /* The result of a ## operator.  */
-#define GNU_VARARGS    (1 << 6) /* GNU ## kludge.   */
 
 /* A preprocessing token.  This has been carefully packed and should
    occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts.  */
@@ -181,7 +180,8 @@ struct cpp_token
 /* cpp_toklist flags.  */
 #define LIST_OFFSET     (1 << 0)
 #define VAR_ARGS       (1 << 1)
-#define BEG_OF_FILE    (1 << 2)
+#define GNU_REST_ARGS  (1 << 2) /* Set in addition to VAR_ARGS.  */
+#define BEG_OF_FILE    (1 << 3)
 
 struct directive;              /* These are deliberately incomplete.  */
 struct answer;
index 096cea1..4410e2e 100644 (file)
@@ -1,3 +1,7 @@
+2000-07-08  Neil Booth  <NeilB@earthling.net>
+
+       * gcc.dg/cpp/macsyntx.c: New tests.
+
 2000-07-07  Jakub Jelinek  <jakub@redhat.com>
 
        * gcc.dg/20000707-1.c: New test.
diff --git a/gcc/testsuite/gcc.dg/cpp/macsyntx.c b/gcc/testsuite/gcc.dg/cpp/macsyntx.c
new file mode 100644 (file)
index 0000000..baa69d1
--- /dev/null
@@ -0,0 +1,72 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.  */
+
+/* { dg-do preprocess } */
+/* { dg-options -pedantic } */
+
+/* Tests macro syntax, for both definition and invocation, including:-
+
+   o Full range of macro definition semantics.
+   o No. of arguments supplied to function-like macros.
+   o Odd GNU rest args behaviour.
+   o Macro arguments do not flow into the rest of the file.  */
+
+
+/* Test basic macro definition syntax.  The macros are all called
+   "foo" deliberately to provoke an (excess) redefinition warning in
+   case the macros succeed in being entered in the macro hash table
+   despite being an error.
+
+   Split a couple of the lines to check that the errors appear on the
+   right line (i.e. are associated with the correct token).  */
+
+#define ;                      /* { dg-error "identifier" } */
+#define SEMI;                  /* { dg-warning "space" } */
+#define foo(X                  /* { dg-error "missing" } */
+#define foo\
+(X,)                           /* { dg-error "parameter name" } */
+#define foo(, X)               /* { dg-error "parameter name" } */
+#define foo(X, X)              /* { dg-error "duplicate" } */
+#define foo(X Y)               /* { dg-error "comma" } */
+#define foo(()                 /* { dg-error "illegal token" } */
+#define foo(..., X)            /* { dg-error "missing" } */
+#define foo \
+__VA_ARGS__                    /* { dg-warning "__VA_ARGS__" } */
+#define foo(__VA_ARGS__)       /* { dg-warning "__VA_ARGS__" } */
+#define foo(...) __VA_ARGS__   /* OK.  */
+#define __VA_ARGS__            /* { dg-warning "__VA_ARGS__" } */
+
+/* test # of supplied arguments.  */
+#define none()
+#define one(x)
+#define two(x, y)
+#define var0(...)
+#define var1(x, ...)
+none()                         /* OK.  */
+none(ichi)                     /* { dg-error "too many" } */
+one()                          /* OK.  */
+one(ichi)                      /* OK.  */
+one(ichi\
+, ni)                          /* { dg-error "too many" } */
+two(ichi)                      /* { dg-error "insufficient" } */
+var0()                         /* OK.  */
+var0(ichi)                     /* OK.  */
+var1()                         /* { dg-error "insufficient" } */
+var1(ichi)                     /* { dg-error "insufficient" } */
+var1(ichi, ni)                 /* OK.  */
+
+/* This tests two deprecated oddities of GNU rest args - omitting a
+   comma is OK, and backtracking a token on pasting an empty rest
+   args.  */
+#define rest(x, y...) x ## y   /* { dg-warning "ISO C" } */
+rest(ichi,)                    /* { dg-warning "deprecated" } */
+rest(ichi)                     /* { dg-warning "deprecated" } */
+#if 23 != rest(2, 3)           /* OK, no warning.  */
+#error 23 != 23 !!
+#endif
+
+/* Test that we don't allow arguments to flow into the rest of the
+   file.  */
+#define half_invocation do_nowt(2
+#define do_nowt(x) x
+half_invocation )              /* OK.  */
+do_nowt (half_invocation))     /* { dg-error "unterminated invocation" } */