@@ -592,6 +592,64 @@ c_token_starts_declaration (c_token *token)
static c_token *c_parser_peek_2nd_token (c_parser *parser);
+/* Return true if the next token from PARSER cannot follow a
+ declaration, false otherwise. */
+static inline bool
+c_parser_next_token_cannot_follow_declaration (c_parser *parser,
+ struct c_declarator *declarator)
+{
+ c_token *token = c_parser_peek_token (parser);
+
+ switch (token->type)
+ {
+ case CPP_KEYWORD:
+ switch (token->keyword)
+ {
+ case RID_EXTERN:
+ case RID_STATIC:
+ case RID_TYPEDEF:
+ case RID_INLINE:
+ case RID_AUTO:
+ case RID_THREAD:
+ /* Can never follow. */
+ return true;
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_INT128:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_COMPLEX:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ case RID_ENUM:
+ /* We need to be careful, since K&R argument lists can begin
+ with these tokens. Consult the types of the argument info;
+ if we actually have a type, then these tokens are invalid.
+ Don't bother grovelling through the whole list. */
+ if (declarator->kind == cdk_pointer)
+ declarator = declarator->declarator;
+ if (declarator->kind == cdk_function)
+ return TYPE_P (TREE_VALUE (declarator->u.arg_info->types));
+ else
+ return true;
+ default:
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+}
+
/* Return true if the next token from PARSER can start declaration
specifiers, false otherwise. */
static inline bool
@@ -1601,6 +1659,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
return;
}
}
+ else if (c_parser_next_token_cannot_follow_declaration (parser,
+ declarator))
+ {
+ start_decl (declarator, specs, false, all_prefix_attrs);
+ c_parser_error (parser, "expected %<;%>");
+ return;
+ }
else if (!fndef_ok)
{
c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, "
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } // suppress default -pedantic-errors */
+
+extern void f1 (int)
+extern void f2 (int); /* { dg-error "expected" } */
+
+extern int x
+extern int z; /* { dg-error "expected" } */
+
+extern void g1 (int)
+struct s { int a; }; /* { dg-error "expected" } */
+
+typedef unsigned int uint32
+extern int i; /* { dg-error "expected" } */