Patchwork Better error reporting for missing semicolons after a struct definition

login
register
mail settings
Submitter Paolo Bonzini
Date Nov. 9, 2010, 4:43 p.m.
Message ID <4CD97A23.90209@gnu.org>
Download mbox | patch
Permalink /patch/70560/
State New
Headers show

Comments

Paolo Bonzini - Nov. 9, 2010, 4:43 p.m.
On 11/05/2010 07:04 PM, Joseph S. Myers wrote:
> Consider the following testcase.
> 
> struct s { struct { int a; } };
> int *f(struct s *p) { return &p->a; }

The attached patch (mostly untested) fixes this testcase.  This will also pedwarn:

  struct t { int };

like this:

  f.c:3:16: warning: declaration does not declare anything [enabled by default]
  f.c:3:16: warning: no semicolon at end of struct or union [enabled by default]

while GCC 4.5 gives

  f.c:3:16: error: expected identifier or ‘(’ before ‘}’ token
  f.c:3:16: error: expected specifier-qualifier-list at end of input

Paolo
fix corner case of unnamed struct and missing final semicolon

* c-parser.c (enum c_dtr_syn): Change to a 3-bit mask.
(c_parser_declarator, c_parser_direct_declarator): Adjust tests, change
c_dtr_syn argument to int.
(c_parser_struct_declaration): Remove wrong code from previous patch.
Accept an abstract declarator, usually an unnamed struct, and do not
crash when other kinds of abstract declarator are found in a struct.

Patch

Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(branch diag-2)
+++ gcc/c-parser.c	(working copy)
@@ -1030,9 +1030,9 @@  restore_extension_diagnostics (int flags
 /* Possibly kinds of declarator to parse.  */
 typedef enum c_dtr_syn {
   /* A normal declarator with an identifier.  */
-  C_DTR_NORMAL,
+  C_DTR_NORMAL = 1,
   /* An abstract declarator (maybe empty).  */
-  C_DTR_ABSTRACT,
+  C_DTR_ABSTRACT = 2,
   /* A parameter declarator: may be either, but after a type name does
      not redeclare a typedef name as an identifier if it can
      alternatively be interpreted as a typedef name; see DR#009,
@@ -1043,7 +1043,7 @@  typedef enum c_dtr_syn {
      abstract declarators rather than involving redundant parentheses;
      the same applies with attributes inside the parentheses before
      "T".  */
-  C_DTR_PARM
+  C_DTR_PARM = 4
 } c_dtr_syn;
 
 static void c_parser_external_declaration (c_parser *);
@@ -1058,10 +1058,10 @@  static struct c_typespec c_parser_enum_s
 static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
 static tree c_parser_struct_declaration (c_parser *);
 static struct c_typespec c_parser_typeof_specifier (c_parser *);
-static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn,
+static struct c_declarator *c_parser_declarator (c_parser *, bool, int,
 						 bool *);
 static struct c_declarator *c_parser_direct_declarator (c_parser *, bool,
-							c_dtr_syn, bool *);
+							int, bool *);
 static struct c_declarator *c_parser_direct_declarator_inner (c_parser *,
 							      bool,
 							      struct c_declarator *);
@@ -2516,8 +2516,6 @@  c_parser_struct_declaration (c_parser *p
       parser->error = false;
       return NULL_TREE;
     }
-  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
-    return NULL_TREE;
 
   pending_xref_error ();
   prefix_attrs = specs->attrs;
@@ -2526,7 +2524,9 @@  c_parser_struct_declaration (c_parser *p
   decls = NULL_TREE;
   while (true)
     {
-      /* Declaring one or more declarators or un-named bit-fields.  */
+      /* Declaring one or more declarators or un-named bit-fields.  The
+         identifier in a declarator is optional, since we could have an
+	  unnamed struct.  */
       struct c_declarator *declarator;
       bool dummy = false;
       if (c_parser_next_token_is (parser, CPP_COLON))
@@ -2534,7 +2534,7 @@  c_parser_struct_declaration (c_parser *p
       else
 	declarator = c_parser_declarator (parser,
 					  specs->typespec_kind != ctsk_none,
-					  C_DTR_NORMAL, &dummy);
+					  C_DTR_NORMAL|C_DTR_ABSTRACT, &dummy);
       if (declarator == NULL)
 	{
 	  c_parser_skip_to_end_of_block_or_statement (parser);
@@ -2558,10 +2558,13 @@  c_parser_struct_declaration (c_parser *p
 	    postfix_attrs = c_parser_attributes (parser);
 	  d = grokfield (c_parser_peek_token (parser)->location,
 			 declarator, specs, width, &all_prefix_attrs);
-	  decl_attributes (&d, chainon (postfix_attrs,
-					all_prefix_attrs), 0);
-	  DECL_CHAIN (d) = decls;
-	  decls = d;
+	  if (d)
+            {
+              decl_attributes (&d, chainon (postfix_attrs,
+                                            all_prefix_attrs), 0);
+              DECL_CHAIN (d) = decls;
+              decls = d;
+            }
 	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
 	    all_prefix_attrs = chainon (c_parser_attributes (parser),
 					prefix_attrs);
@@ -2734,7 +2737,7 @@  c_parser_typeof_specifier (c_parser *par
    an abstract declarator, although not part of the formal syntax.  */
 
 static struct c_declarator *
-c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
+c_parser_declarator (c_parser *parser, bool type_seen_p, int kind,
 		     bool *seen_id)
 {
   /* Parse any initial pointer part.  */
@@ -2759,7 +2762,7 @@  c_parser_declarator (c_parser *parser, b
    as c_parser_declarator.  */
 
 static struct c_declarator *
-c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
+c_parser_direct_declarator (c_parser *parser, bool type_seen_p, int kind,
 			    bool *seen_id)
 {
   /* The direct declarator must start with an identifier (possibly
@@ -2796,7 +2799,7 @@  c_parser_direct_declarator (c_parser *pa
      ??? Also following the old parser, typedef names may be
      redeclared in declarators, but not Objective-C class names.  */
 
-  if (kind != C_DTR_ABSTRACT
+  if ((kind & ~C_DTR_ABSTRACT)
       && c_parser_next_token_is (parser, CPP_NAME)
       && ((type_seen_p
 	   && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
@@ -2811,7 +2814,7 @@  c_parser_direct_declarator (c_parser *pa
       return c_parser_direct_declarator_inner (parser, *seen_id, inner);
     }
 
-  if (kind != C_DTR_NORMAL
+  if ((kind & ~C_DTR_NORMAL)
       && c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
     {
       struct c_declarator *inner = build_id_declarator (NULL_TREE);
@@ -2827,13 +2830,12 @@  c_parser_direct_declarator (c_parser *pa
       struct c_declarator *inner;
       c_parser_consume_token (parser);
       attrs = c_parser_attributes (parser);
-      if (kind != C_DTR_NORMAL
+      if ((kind & ~C_DTR_NORMAL)
 	  && (c_parser_next_token_starts_declspecs (parser)
 	      || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
 	{
 	  struct c_arg_info *args
-	    = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL,
-					 attrs);
+	    = c_parser_parms_declarator (parser, false, attrs);
 	  if (args == NULL)
 	    return NULL;
 	  else
@@ -2866,13 +2868,13 @@  c_parser_direct_declarator (c_parser *pa
     }
   else
     {
-      if (kind == C_DTR_NORMAL)
+      if (kind & ~C_DTR_NORMAL)
+	return build_id_declarator (NULL_TREE);
+      else
 	{
 	  c_parser_error (parser, "expected identifier or %<(%>");
 	  return NULL;
 	}
-      else
-	return build_id_declarator (NULL_TREE);
     }
 }