cpphash.c (trad_stringify, add_pat): New functions.
authorZack Weinberg <zack@wolery.cumb.org>
Sat, 22 Apr 2000 23:02:08 +0000 (23:02 +0000)
committerZack Weinberg <zack@gcc.gnu.org>
Sat, 22 Apr 2000 23:02:08 +0000 (23:02 +0000)
* cpphash.c (trad_stringify, add_pat): New functions.
(collect_expansion): Restore support for -traditional syntax.
Use trad_stringify and add_pat.
(_cpp_macroexpand): Restore support for -traditional semantics.
* cpplex.c (_cpp_scan_line): Don't change space_before if we
get a COMMENT token.
(_cpp_lex_token): Provide COMMENT tokens to caller if
traditional and parsing_define_directive.
(skip_comment): Warn about // comments if -Wtraditional.
* cpplib.c (do_define): Fix typo.  Create EMPTY nodes with
proper node type.
(do_undef): Don't warn about undefining EMPTY nodes.

From-SVN: r33350

gcc/ChangeLog
gcc/cpphash.c
gcc/cpplex.c
gcc/cpplib.c

index ec86bbd02e04e4f83af361233af4373f89ccbaae..28db7bafdb5e6cdb3889a18cc499e1bf042caa06 100644 (file)
@@ -1,3 +1,18 @@
+2000-04-22  Zack Weinberg  <zack@wolery.cumb.org>
+
+       * cpphash.c (trad_stringify, add_pat): New functions.
+       (collect_expansion): Restore support for -traditional syntax.
+       Use trad_stringify and add_pat.
+       (_cpp_macroexpand): Restore support for -traditional semantics.
+       * cpplex.c (_cpp_scan_line): Don't change space_before if we
+       get a COMMENT token.
+       (_cpp_lex_token): Provide COMMENT tokens to caller if
+       traditional and parsing_define_directive.
+       (skip_comment): Warn about // comments if -Wtraditional.
+       * cpplib.c (do_define): Fix typo.  Create EMPTY nodes with
+       proper node type.
+       (do_undef): Don't warn about undefining EMPTY nodes.
+
 Sat Apr 22 22:35:38 MET DST 2000  Jan Hubicka  <jh@suse.cz>
 
        * loop.c (strength_reduce): Fix biv removal code.
index c39ca9f5fa69c5bdfcbed2127aa9259d5e5e3eaf..26d03fec05514df1c818a6846d0a09116c7d5e26 100644 (file)
@@ -79,7 +79,13 @@ static unsigned int collect_params PARAMS ((cpp_reader *, cpp_toklist *,
 
 static void warn_trad_stringify        PARAMS ((cpp_reader *, U_CHAR *, size_t,
                                         unsigned int, const struct arg *));
+static unsigned int trad_stringify PARAMS ((cpp_reader *, U_CHAR *, size_t,
+                                           unsigned int, const struct arg *,
+                                           struct reflist **,
+                                           struct reflist **, unsigned int));
 static int duplicate_arg_p PARAMS ((U_CHAR *, U_CHAR *));
+static void add_pat PARAMS ((struct reflist **, struct reflist **,
+                            unsigned int, unsigned int, int, int, int, int));
 
 /* This structure represents one parsed argument in a macro call.
    `raw' points to the argument text as written (`raw_length' is its length).
@@ -279,6 +285,32 @@ macro_cleanup (pbuf, pfile)
   return 0;
 }
 
+/* Create pat nodes.  */
+
+static void
+add_pat (pat, endpat, nchars, argno, raw_before, raw_after, strize, rest)
+     struct reflist **pat, **endpat;
+     unsigned int nchars;
+     unsigned int argno;
+     int raw_before, raw_after, strize, rest;
+{
+  struct reflist *tpat;
+  tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
+  tpat->next = NULL;
+  tpat->raw_before = raw_before;
+  tpat->raw_after = raw_after;
+  tpat->stringify = strize;
+  tpat->rest_args = rest;
+  tpat->argno = argno;
+  tpat->nchars = nchars;
+
+  if (*endpat == NULL)
+    *pat = tpat;
+  else
+    (*endpat)->next = tpat;
+  *endpat = tpat;
+}  
+
 /* Issue warnings for macro argument names seen inside strings.  */
 static void
 warn_trad_stringify (pfile, p, len, argc, argv)
@@ -287,7 +319,6 @@ warn_trad_stringify (pfile, p, len, argc, argv)
      size_t len;
      unsigned int argc;
      const struct arg *argv;
-     
 {
   U_CHAR *limit;
   unsigned int i;
@@ -315,6 +346,59 @@ warn_trad_stringify (pfile, p, len, argc, argv)
     }
 }
 
+/* Generate pat nodes for macro arguments seen inside strings.  */
+static unsigned int
+trad_stringify (pfile, base, len, argc, argv, pat, endpat, last)
+     cpp_reader *pfile;
+     U_CHAR *base;
+     size_t len;
+     unsigned int argc;
+     const struct arg *argv;
+     struct reflist **pat, **endpat;
+     unsigned int last;
+{
+  U_CHAR *p, *limit;
+  unsigned int i;
+
+  p = base;
+  limit = base + len;
+  for (;;)
+    {
+    proceed:
+      while (p < limit && !is_idstart (*p)) p++;
+      if (p >= limit)
+       break;
+
+      for (i = 0; i < argc; i++)
+       if (!strncmp (p, argv[i].name, argv[i].len)
+           && ! is_idchar (p[argv[i].len]))
+         {
+           if (CPP_WTRADITIONAL (pfile))
+             cpp_warning (pfile, "macro argument \"%s\" is stringified",
+                          argv[i].name);
+           /* Write out the string up to this point, and add a pat
+              node for the argument.  Note that the argument is NOT
+              stringified.  */
+           CPP_PUTS (pfile, base, p - base);
+           add_pat (pat, endpat, CPP_WRITTEN (pfile) - last, i /* argno */,
+                    !is_hspace (p[-1]) /* raw_before */,
+                    !is_hspace (p[argv[i].len]) /* raw_after */,
+                    0 /* strize */,
+                    argv[i].rest_arg);
+           last = CPP_WRITTEN (pfile);
+           base = p + argv[i].len;
+           goto proceed;
+         }
+      p++;
+      while (p < limit && is_idchar (*p)) p++;
+      if (p >= limit)
+       break;
+    }
+  CPP_PUTS (pfile, base, p - base);
+  return last;
+}
+
+
 /* Read a replacement list for a macro, and build the DEFINITION
    structure.  LIST contains the replacement list, beginning at
    REPLACEMENT.  ARGLIST specifies the formal parameters to look for
@@ -332,7 +416,7 @@ collect_expansion (pfile, list, arglist, replacement)
   DEFINITION *defn;
   struct reflist *pat = 0, *endpat = 0;
   enum cpp_ttype token;
-  long start, last;
+  unsigned int start, last;
   unsigned int i;
   int j, argc;
   size_t len;
@@ -374,19 +458,21 @@ collect_expansion (pfile, list, arglist, replacement)
          /* # is not special in object-like macros.  It is special in
             function-like macros with no args.  (6.10.3.2 para 1.)
             However, it is not special after PASTE. (Implied by
-            6.10.3.3 para 4.)  */
-         if (arglist == NULL || last_token == PASTE)
-           goto norm;
+            6.10.3.3 para 4.)  Nor is it special if -traditional.  */
+         if (arglist == NULL || last_token == PASTE
+             || CPP_TRADITIONAL (pfile))
+           break;
          last_token = STRIZE;
-         break;
+         continue;
 
        case CPP_PASTE:
-         if (last_token == PASTE)
-           /* ## ## - the second ## is ordinary.  */
-           goto norm;
-         else if (last_token == START)
+         /* ## is not special if it appears right after another ##;
+            nor is it special if -traditional.  */
+         if (last_token == PASTE || CPP_TRADITIONAL (pfile))
+           break;
+
+         if (last_token == START)
            cpp_error (pfile, "`##' at start of macro definition");
-           
          else if (last_token == ARG)
            /* If the last token was an argument, mark it raw_after.  */
            endpat->raw_after = 1;
@@ -395,12 +481,33 @@ collect_expansion (pfile, list, arglist, replacement)
            CPP_PUTC (pfile, '#');
 
          last_token = PASTE;
-         break;
+         continue;
 
+       default:;
+       }
+
+      if (last_token != PASTE && last_token != START
+         && (list->tokens[i].flags & HSPACE_BEFORE))
+       CPP_PUTC (pfile, ' ');
+      if (last_token == ARG && CPP_TRADITIONAL (pfile)
+         && !(list->tokens[i].flags & HSPACE_BEFORE))
+       endpat->raw_after = 1;
+
+      switch (token)
+       {
        case CPP_STRING:
        case CPP_CHAR:
-         if (argc && CPP_WTRADITIONAL (pfile))
-           warn_trad_stringify (pfile, tok, len, argc, argv);
+         if (argc)
+           {
+             if (CPP_TRADITIONAL (pfile))
+               {
+                 last = trad_stringify (pfile, tok, len, argc, argv,
+                                        &pat, &endpat, last);
+                 break;
+               }
+             if (CPP_WTRADITIONAL (pfile))
+               warn_trad_stringify (pfile, tok, len, argc, argv);
+           }
          goto norm;
          
        case CPP_NAME:
@@ -419,31 +526,20 @@ collect_expansion (pfile, list, arglist, replacement)
            CPP_PUTC (pfile, ' ');
          CPP_PUTS (pfile, tok, len);
          last_token = NORM;
-         break;
        }
       continue;
 
     addref:
       {
-       struct reflist *tpat;
-       if (last_token != PASTE && (list->tokens[i].flags & HSPACE_BEFORE))
-         CPP_PUTC (pfile, ' ');
-
-       /* Make a pat node for this arg and add it to the pat list */
-       tpat = (struct reflist *) xmalloc (sizeof (struct reflist));
-       tpat->next = NULL;
-       tpat->raw_before = (last_token == PASTE);
-       tpat->raw_after = 0;
-       tpat->stringify = (last_token == STRIZE);
-       tpat->rest_args = argv[j].rest_arg;
-       tpat->argno = j;
-       tpat->nchars = CPP_WRITTEN (pfile) - last;
-
-       if (endpat == NULL)
-         pat = tpat;
-       else
-         endpat->next = tpat;
-       endpat = tpat;
+       int raw_before = (last_token == PASTE
+                         || (CPP_TRADITIONAL (pfile)
+                             && !(list->tokens[i].flags & HSPACE_BEFORE)));
+      
+       add_pat (&pat, &endpat,
+                CPP_WRITTEN (pfile) - last /* nchars */, j /* argno */,
+                raw_before, 0 /* raw_after */,
+                (last_token == STRIZE), argv[j].rest_arg);
+      
        last = CPP_WRITTEN (pfile);
       }
       last_token = ARG;
@@ -1028,8 +1124,11 @@ _cpp_macroexpand (pfile, hp)
        }
       else if (i < nargs)
        {
+         /* traditional C allows foo() if foo wants one argument.  */
+         if (nargs == 1 && i == 0 && CPP_TRADITIONAL (pfile))
+           ;
          /* the rest args token is allowed to absorb 0 tokens */
-         if (i == nargs - 1 && defn->rest_args)
+         else if (i == nargs - 1 && defn->rest_args)
            rest_zero = 1;
          else if (i == 0)
            cpp_error (pfile, "macro `%s' used without args", hp->name);
@@ -1317,8 +1416,19 @@ _cpp_macroexpand (pfile, hp)
   /* Pop the space we've used in the token_buffer for argument expansion.  */
   CPP_SET_WRITTEN (pfile, old_written);
 
-  /* Per C89, a macro cannot be expanded recursively.  */
-  hp->type = T_DISABLED;
+  /* In C89, a macro cannot be expanded recursively.  Traditional C
+     permits it, but any use in an object-like macro must lead to
+     infinite recursion, so always follow C89 in object-like macros.
+
+     The only example known where this doesn't cause infinite recursion
+     in function-like macros is:
+       #define foo(x,y) bar(x(y, 0))
+       foo(foo, baz)
+     which expands to bar(foo(baz, 0)) in C89 and
+     bar(bar(baz(0, 0)) in K+R.  This looks pathological to me.
+     If someone has a real-world example I would love to see it.  */
+  if (nargs <= 0 || !CPP_TRADITIONAL (pfile))
+    hp->type = T_DISABLED;
 }
 
 /* Return 1 iff a token ending in C1 followed directly by a token C2
index effb6ca05103c4065e0765fe77b4cd036ac46c86..3e6a89feac590e23c8bc0ec5cf0f37720f88eebe 100644 (file)
@@ -513,6 +513,11 @@ _cpp_scan_line (pfile, list)
          space_before = 1;
          continue;
        }
+      else if (type == CPP_COMMENT)
+       /* Only happens when processing -traditional macro definitions.
+          Do not give this a token entry, but do not change space_before
+          either.  */
+       continue;
 
       if (list->tokens_used >= list->tokens_cap)
        expand_token_space (list);
@@ -644,13 +649,17 @@ skip_comment (pfile, m)
        }
       else if (CPP_OPTION (pfile, cplusplus_comments))
        {
-         if (CPP_OPTION (pfile, c89)
-             && CPP_PEDANTIC (pfile)
-             && ! CPP_BUFFER (pfile)->warned_cplusplus_comments)
+         if (! CPP_BUFFER (pfile)->warned_cplusplus_comments)
            {
-             cpp_pedwarn (pfile,
-                          "C++ style comments are not allowed in ISO C89");
-             cpp_pedwarn (pfile,
+             if (CPP_WTRADITIONAL (pfile))
+               cpp_pedwarn (pfile,
+                       "C++ style comments are not allowed in traditional C");
+             else if (CPP_OPTION (pfile, c89) && CPP_PEDANTIC (pfile))
+               cpp_pedwarn (pfile,
+                       "C++ style comments are not allowed in ISO C89");
+             if (CPP_WTRADITIONAL (pfile)
+                 || (CPP_OPTION (pfile, c89) && CPP_PEDANTIC (pfile)))
+               cpp_pedwarn (pfile,
                           "(this will be reported only once per input file)");
              CPP_BUFFER (pfile)->warned_cplusplus_comments = 1;
            }
@@ -1053,7 +1062,11 @@ _cpp_lex_token (pfile)
       if (!CPP_OPTION (pfile, discard_comments))
        return CPP_COMMENT;
       else if (CPP_TRADITIONAL (pfile))
-       goto get_next;
+       {
+         if (pfile->parsing_define_directive)
+           return CPP_COMMENT;
+         goto get_next;
+       }
       else
        {
          CPP_PUTC (pfile, c);
index f8815842f58ccaaa0d4fb1366156272a1992b459..7f2554bfc06ec3a8f71ec971f16d98de9674dc36 100644 (file)
@@ -352,7 +352,7 @@ do_define (pfile)
 
 
   if (list->tokens_used == 2 && list->tokens[1].type == CPP_VSPACE)
-    empty = 0;  /* Empty definition of object-like macro.  */
+    empty = 1;  /* Empty definition of object-like macro.  */
 
   /* If the next character, with no intervening whitespace, is '(',
      then this is a function-like macro.  Otherwise it is an object-
@@ -425,7 +425,8 @@ do_define (pfile)
     }
   else
     {
-      HASHNODE *hp = _cpp_make_hashnode (sym, len, T_MACRO, hash);
+      HASHNODE *hp = _cpp_make_hashnode (sym, len, empty ? T_EMPTY : T_MACRO,
+                                        hash);
       hp->value.defn = def;
       *slot = hp;
     }
@@ -768,7 +769,7 @@ do_undef (pfile)
          if (CPP_OPTION (pfile, debug_output))
            pass_thru_directive (hp->name, len, pfile, T_UNDEF);
 
-         if (hp->type != T_MACRO)
+         if (hp->type != T_MACRO && hp->type != T_EMPTY)
            cpp_warning (pfile, "undefining `%s'", hp->name);
 
          htab_clear_slot (pfile->hashtab, (void **)slot);