aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/c-parser.c50
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/decl-9.c32
4 files changed, 89 insertions, 9 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index af43e31..4a036dc 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2010-10-30 Paolo Bonzini <bonzini@gnu.org>
+
+ PR c/20385
+ * c-parser.c (c_parser_next_token_starts_declaration): Rename to...
+ (c_parser_next_tokens_start_declaration): ... this. Handle 2nd
+ token lookahead.
+ (c_parser_compound_statement_nostart, c_parser_label,
+ c_parser_for_statement, c_parser_omp_for_loop): Adjust calls.
+ (c_parser_declaration_or_fndef): Detect the case now matched by
+ c_parser_next_tokens_start_declaration, give error and correct it.
+
2010-11-13 Paolo Bonzini <bonzini@gnu.org>
* c-tree.h (enum c_typespec_kind): Add ctsk_none.
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index 9761e4e..e5ec2d9 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -614,10 +614,10 @@ c_parser_next_token_starts_declspecs (c_parser *parser)
return c_token_starts_declspecs (token);
}
-/* Return true if the next token from PARSER can start declaration
+/* Return true if the next tokens from PARSER can start declaration
specifiers or a static assertion, false otherwise. */
static inline bool
-c_parser_next_token_starts_declaration (c_parser *parser)
+c_parser_next_tokens_start_declaration (c_parser *parser)
{
c_token *token = c_parser_peek_token (parser);
@@ -628,7 +628,23 @@ c_parser_next_token_starts_declaration (c_parser *parser)
&& c_parser_peek_2nd_token (parser)->type == CPP_DOT)
return false;
- return c_token_starts_declaration (token);
+ /* Labels do not start declarations. */
+ if (token->type == CPP_NAME
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ return false;
+
+ if (c_token_starts_declaration (token))
+ return true;
+
+ /* Try a bit harder to detect an unknown typename. */
+ if (token->type == CPP_NAME
+ && token->id_kind == C_ID_ID
+ && (c_parser_peek_2nd_token (parser)->type == CPP_NAME
+ || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+ && !lookup_name (token->value))
+ return true;
+
+ return false;
}
/* Return a pointer to the next-but-one token from PARSER, reading it
@@ -1345,6 +1361,24 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
return;
}
specs = build_null_declspecs ();
+
+ /* Try to detect an unknown type name when we have "A B" or "A *B". */
+ if (c_parser_peek_token (parser)->type == CPP_NAME
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID
+ && (c_parser_peek_2nd_token (parser)->type == CPP_NAME
+ || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+ && (!nested || !lookup_name (c_parser_peek_token (parser)->value)))
+ {
+ error_at (here, "unknown type name %qE",
+ c_parser_peek_token (parser)->value);
+
+ /* Parse declspecs normally to get a correct pointer type, but avoid
+ a further "fails to be a type name" error. */
+ c_parser_peek_token (parser)->type = CPP_KEYWORD;
+ c_parser_peek_token (parser)->keyword = RID_VOID;
+ c_parser_peek_token (parser)->value = error_mark_node;
+ }
+
c_parser_declspecs (parser, specs, true, true, start_attr_ok);
if (parser->error)
{
@@ -3868,7 +3902,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
c_parser_label (parser);
}
else if (!last_label
- && c_parser_next_token_starts_declaration (parser))
+ && c_parser_next_tokens_start_declaration (parser))
{
last_label = false;
mark_valid_location_for_stdc_pragma (false);
@@ -4030,9 +4064,7 @@ c_parser_label (c_parser *parser)
}
if (label)
{
- if (c_parser_next_token_starts_declaration (parser)
- && !(c_parser_next_token_is (parser, CPP_NAME)
- && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+ if (c_parser_next_tokens_start_declaration (parser))
{
error_at (c_parser_peek_token (parser)->location,
"a label can only be part of a statement and "
@@ -4626,7 +4658,7 @@ c_parser_for_statement (c_parser *parser)
c_parser_consume_token (parser);
c_finish_expr_stmt (loc, NULL_TREE);
}
- else if (c_parser_next_token_starts_declaration (parser))
+ else if (c_parser_next_tokens_start_declaration (parser))
{
parser->objc_could_be_foreach_context = true;
c_parser_declaration_or_fndef (parser, true, true, true, true, true,
@@ -9010,7 +9042,7 @@ c_parser_omp_for_loop (location_t loc,
goto pop_scopes;
/* Parse the initialization declaration or expression. */
- if (c_parser_next_token_starts_declaration (parser))
+ if (c_parser_next_tokens_start_declaration (parser))
{
if (i > 0)
VEC_safe_push (tree, gc, for_block, c_begin_compound_stmt (true));
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f878023..a2d1a56 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,10 @@
2010-11-13 Paolo Bonzini <bonzini@gnu.org>
+ PR c/20385
+ * gcc.dg/decl-9.c: New.
+
+2010-11-13 Paolo Bonzini <bonzini@gnu.org>
+
* gcc.dg/Wcxx-compat-8.c: Add testcases involving incomplete types.
2010-11-13 Paolo Bonzini <bonzini@gnu.org>
diff --git a/gcc/testsuite/gcc.dg/decl-9.c b/gcc/testsuite/gcc.dg/decl-9.c
new file mode 100644
index 0000000..cc23b07
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/decl-9.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+
+w *x; /* { dg-error "unknown type name 'w'" } */
+
+int z; /* { dg-message "previous declaration of 'z'" } */
+y /* { dg-error "unknown type name 'y'" } */
+ * z; /* { dg-error "conflicting " } */
+
+int f1()
+{
+ int d, e;
+ d * e; /* { dg-bogus "unknown type name 'd'" } */
+ g * h; /* { dg-error "unknown type name 'g'" } */
+ g i; /* { dg-error "unknown type name 'g'" } */
+}
+
+typedef int a;
+
+int f2()
+{
+b: a: ; /* { dg-bogus "a label can only be part of a statement" } */
+c: d e; /* { dg-error "a label can only be part of a statement" } */
+/* { dg-error "unknown type name 'd'" "" { target *-*-* } 23 } */
+ ;
+}
+
+void *f3()
+{
+ return x; /* { dg-bogus "'x' undeclared" } */
+}
+