Patchwork detect unknown type names in declaration

login
register
mail settings
Submitter Paolo Bonzini
Date Oct. 30, 2010, 1:24 p.m.
Message ID <1288445090-8881-1-git-send-email-bonzini@gnu.org>
Download mbox | patch
Permalink /patch/69653/
State New
Headers show

Comments

Paolo Bonzini - Oct. 30, 2010, 1:24 p.m.
This patch improves GCC error detection so that some cases of
declarations with unknown type names are detected.  This also
allows GCC to do better on cascading errors, because the variables
that are declared enter the symbol table.

Bootstrapped/regtested x86_64-pc-linux-gnu, ok?

2010-10-30  Paolo Bonzini  <bonzini@gnu.org>

        * 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.

testsuite:
2010-10-30  Paolo Bonzini  <bonzini@gnu.org>

        * gcc.dg/decl-9.c: New.




/* { 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" } */
}
Joseph S. Myers - Nov. 6, 2010, midnight
On Sat, 30 Oct 2010, Paolo Bonzini wrote:

> This patch improves GCC error detection so that some cases of
> declarations with unknown type names are detected.  This also
> allows GCC to do better on cascading errors, because the variables
> that are declared enter the symbol table.
> 
> Bootstrapped/regtested x86_64-pc-linux-gnu, ok?

This is OK.  Note that it's PR c/20385, although the patch may not fix all 
cases that should be fixed before closing that bug (in particular, it 
looks like unknown types in parameter declarations in function prototypes 
- whether or not part of a function definition - will need separate 
handling, taking care to distinguish them from old-style function 
declarations with identifier lists).
H.J. Lu - Nov. 13, 2010, 2:15 p.m.
On Sat, Oct 30, 2010 at 6:24 AM, Paolo Bonzini <bonzini@gnu.org> wrote:
> This patch improves GCC error detection so that some cases of
> declarations with unknown type names are detected.  This also
> allows GCC to do better on cascading errors, because the variables
> that are declared enter the symbol table.
>
> Bootstrapped/regtested x86_64-pc-linux-gnu, ok?
>
> 2010-10-30  Paolo Bonzini  <bonzini@gnu.org>
>
>        * 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.
>

This caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46462


H.J.

Patch

Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(branch diag-2)
+++ gcc/c-parser.c	(working copy)
@@ -642,13 +642,30 @@  c_parser_next_token_starts_declspecs (c_
   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);
-  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
@@ -1365,6 +1382,24 @@  c_parser_declaration_or_fndef (c_parser 
       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)
     {
@@ -3927,7 +3962,7 @@  c_parser_compound_statement_nostart (c_p
 	  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);
@@ -4089,9 +4124,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 "
@@ -4685,7 +4718,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, 
@@ -9056,7 +9089,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));