As reported in bug 91193, if an old-style function definition
redeclares a typedef name as a function, then uses that function name
at the start of the first old-style parameter definition, then the
parser interprets that token as a typedef name (because lookahead
occurred before processing of the function declarator completed), but
when it is looked up in processing that parameter definition, what is
found is the redefinition, resulting in an ICE.

The function name's scope starts at the end of its declarator, so this
is similar to other cases where we call
c_parser_maybe_reclassify_token because lookahead might have
classified a token as being a typedef or not based on information from
the wrong scope; do so in this case as well, so resulting in the
expected parse errors from using something that's no longer a typedef
name as if it were a typedef name, and eliminating the ICE.

Bootstrapped with no regressions for x86_64-pc-linux-gnu.

        PR c/91193

gcc/c/
        * c-parser.cc (c_parser_maybe_reclassify_token): Define earlier.
        (c_parser_declaration_or_fndef): Call
        c_parser_maybe_reclassify_token before parsing old-style parameter
        definitions.

gcc/testsuite/
        * gcc.dg/pr91193-1.c, gcc.dg/pr91193-2.c: New tests.

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 730f70bfdc66..9f16493aa143 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -2129,6 +2129,43 @@ handle_assume_attribute (location_t here, tree attrs, 
bool nested)
   return remove_attribute ("gnu", "assume", attrs);
 }
 
+/* We might need to reclassify any previously-lexed identifier, e.g.
+   when we've left a for loop with an if-statement without else in the
+   body - we might have used a wrong scope for the token.  See PR67784.  */
+
+static void
+c_parser_maybe_reclassify_token (c_parser *parser)
+{
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      c_token *token = c_parser_peek_token (parser);
+
+      if (token->id_kind != C_ID_CLASSNAME)
+       {
+         tree decl = lookup_name (token->value);
+
+         token->id_kind = C_ID_ID;
+         if (decl)
+           {
+             if (TREE_CODE (decl) == TYPE_DECL)
+               token->id_kind = C_ID_TYPENAME;
+           }
+         else if (c_dialect_objc ())
+           {
+             tree objc_interface_decl = objc_is_class_name (token->value);
+             /* Objective-C class names are in the same namespace as
+                variables and typedefs, and hence are shadowed by local
+                declarations.  */
+             if (objc_interface_decl)
+               {
+                 token->value = objc_interface_decl;
+                 token->id_kind = C_ID_CLASSNAME;
+               }
+           }
+       }
+    }
+}
+
 /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
    6.7, 6.9.1, C11 6.7, 6.9.1).  If FNDEF_OK is true, a function definition
    is accepted; otherwise (old-style parameter declarations) only other
@@ -3021,6 +3058,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool 
fndef_ok,
         function definitions either.  */
       int save_debug_nonbind_markers_p = debug_nonbind_markers_p;
       debug_nonbind_markers_p = 0;
+      c_parser_maybe_reclassify_token (parser);
       while (c_parser_next_token_is_not (parser, CPP_EOF)
             && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
        c_parser_declaration_or_fndef (parser, false, false, false,
@@ -8359,43 +8397,6 @@ c_parser_else_body (c_parser *parser, const 
token_indent_info &else_tinfo,
   return c_end_compound_stmt (body_loc, block, flag_isoc99);
 }
 
-/* We might need to reclassify any previously-lexed identifier, e.g.
-   when we've left a for loop with an if-statement without else in the
-   body - we might have used a wrong scope for the token.  See PR67784.  */
-
-static void
-c_parser_maybe_reclassify_token (c_parser *parser)
-{
-  if (c_parser_next_token_is (parser, CPP_NAME))
-    {
-      c_token *token = c_parser_peek_token (parser);
-
-      if (token->id_kind != C_ID_CLASSNAME)
-       {
-         tree decl = lookup_name (token->value);
-
-         token->id_kind = C_ID_ID;
-         if (decl)
-           {
-             if (TREE_CODE (decl) == TYPE_DECL)
-               token->id_kind = C_ID_TYPENAME;
-           }
-         else if (c_dialect_objc ())
-           {
-             tree objc_interface_decl = objc_is_class_name (token->value);
-             /* Objective-C class names are in the same namespace as
-                variables and typedefs, and hence are shadowed by local
-                declarations.  */
-             if (objc_interface_decl)
-               {
-                 token->value = objc_interface_decl;
-                 token->id_kind = C_ID_CLASSNAME;
-               }
-           }
-       }
-    }
-}
-
 /* Parse an if statement (C90 6.6.4, C99 6.8.4, C11 6.8.4).
 
    if-statement:
diff --git a/gcc/testsuite/gcc.dg/pr91193-1.c b/gcc/testsuite/gcc.dg/pr91193-1.c
new file mode 100644
index 000000000000..52999a7edd3b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr91193-1.c
@@ -0,0 +1,12 @@
+/* Test ICE using function name in parameter type in old-style function
+   definition (bug 91193).  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu17" } */
+
+typedef int T;
+
+void
+T (x) /* { dg-error "redeclared as different kind of symbol|defaults to 'int'" 
} */
+     T x; /* { dg-error "expected declaration specifiers" } */
+{
+}
diff --git a/gcc/testsuite/gcc.dg/pr91193-2.c b/gcc/testsuite/gcc.dg/pr91193-2.c
new file mode 100644
index 000000000000..7ca0e728eba6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr91193-2.c
@@ -0,0 +1,12 @@
+/* Test ICE using function name in parameter type in old-style function
+   definition (bug 91193).  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu17" } */
+
+typedef int T;
+
+void
+f (void)
+{
+  void T (x) T x; { } /* { dg-error "expected declaration specifiers|defaults 
to 'int'" } */
+}

-- 
Joseph S. Myers
josmy...@redhat.com

Reply via email to