]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c: Fix ICE using function name in parameter type in old-style function definition...
authorJoseph Myers <josmyers@redhat.com>
Wed, 27 Nov 2024 22:27:08 +0000 (22:27 +0000)
committerJoseph Myers <josmyers@redhat.com>
Wed, 27 Nov 2024 22:27:08 +0000 (22:27 +0000)
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.

gcc/c/c-parser.cc
gcc/testsuite/gcc.dg/pr91193-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr91193-2.c [new file with mode: 0644]

index 0e6f87ed5a29694730162c0cb8c599086072ca8a..6eaea2cf1ca7d5a44ffc0a6f60304977b6243f57 100644 (file)
@@ -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 (file)
index 0000000..52999a7
--- /dev/null
@@ -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 (file)
index 0000000..7ca0e72
--- /dev/null
@@ -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'" } */
+}