public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] PR c/20385: more detection of unknown type names
@ 2010-11-21  2:19 Paolo Bonzini
  2010-11-25  7:19 ` Joseph S. Myers
  0 siblings, 1 reply; 3+ messages in thread
From: Paolo Bonzini @ 2010-11-21  2:19 UTC (permalink / raw)
  To: gcc-patches

This fixes the remaining part of PR 20385 by detecting unknown type
names within declspecs, typeof/sizeof/alignof, casts, etc.  Since these
are implemented with (conservative) heuristics, in some cases the new
error is disabled: for example in typeof(X) it is better to diagnose an
undeclared identifier than an unknown type name.

There is in some cases suboptimal error recovery, that leads the parser
to emit a bogus error message about a missing closing parenthesis.
This however happens only in complex cases such as casts to function
pointer types with an unknown typename in the arguments.

Another suboptimal case is that sizeof(X*) is not handled correctly
because the current parser code would require a three-token lookahead.
I believe this can be fixed, anyway it is minor compared to the overall
improvement.

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

Paolo

2010-11-20  Paolo Bonzini  <bonzini@gnu.org>

        PR c/20385
        * function.c (used_types_insert): Handle ERROR_MARK.
        * c-decl.c (grokdeclarator): Handle ERROR_MARK.
        (declspecs_add_type): Leave error_mark_node in specs->type.
        (finish_declspecs): Change it to integer_type_node here.
        * c-parser.c (c_parser_peek_2nd_token): Move earlier.
        (enum c_lookahead_kind): New.
        (c_parser_next_token_starts_typename): New name of
        c_parser_next_tokens_start_typename.  Accept lookahead enum
        and handle it here instead of...
        (c_parser_next_tokens_start_declaration): ... here.  Call it.
        (c_parser_declspecs): Accept bool argument.  Do not exit
        on C_ID_ID if it is guessed to be an unknown typename.
        (c_parser_parms_declarator): Use 2nd token to distinguish a K&R
        declaration from an ANSI declaration starting with an unknown
        typename.
        (c_parser_struct_declaration, c_parser_objc_type_name,
        c_parser_typeof_specifier, c_parser_declarator,
        c_parser_direct_declarator_inner): Adjust calls.
        (c_parser_parameter_declaration): Likewise.
        (c_parser_type_name): Pass back an error_mark_node to the caller.
        (c_parser_postfix_expression): Do error recovery when 
        c_parser_type_name returns NULL for the first offsetof argument.

2010-11-20  Paolo Bonzini  <bonzini@gnu.org>

        PR c/20385
        * objc.dg/tls/init-2.m: Adjust.
        * gcc.dg/noncompile/920923-1.c: Adjust.
        * gcc.dg/noncompile/pr44517.c: Adjust.
        * gcc.dg/declspec.c: New test.

Index: gcc/function.c
===================================================================
--- gcc/function.c	(branch diag-2)
+++ gcc/function.c	(working copy)
@@ -5704,6 +5704,8 @@ used_types_insert (tree t)
       break;
     else
       t = TREE_TYPE (t);
+  if (TREE_CODE (t) == ERROR_MARK)
+    return;
   if (TYPE_NAME (t) == NULL_TREE
       || TYPE_NAME (t) == TYPE_NAME (TYPE_MAIN_VARIANT (t)))
     t = TYPE_MAIN_VARIANT (t);
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c	(branch diag-2)
+++ gcc/c-decl.c	(working copy)
@@ -4864,6 +4864,8 @@ grokdeclarator (const struct c_declarato
   tree expr_dummy;
   bool expr_const_operands_dummy;
 
+  if (TREE_CODE (type) == ERROR_MARK)
+    return error_mark_node;
   if (expr == NULL)
     expr = &expr_dummy;
   if (expr_const_operands == NULL)
@@ -9307,9 +9309,9 @@ declspecs_add_type (location_t loc, stru
       else
 	specs->type = TREE_TYPE (t);
     }
-  else if (TREE_CODE (type) != ERROR_MARK)
+  else
     {
-      if (spec.kind == ctsk_typeof)
+      if (TREE_CODE (type) != ERROR_MARK && spec.kind == ctsk_typeof)
 	{
 	  specs->typedef_p = true;
 	  if (spec.expr)
@@ -9324,11 +9326,6 @@ declspecs_add_type (location_t loc, stru
 	}
       specs->type = type;
     }
-  else
-    {
-      /* Set a dummy type here to avoid warning about implicit 'int'.  */
-      specs->type = integer_type_node;
-    }
 
   return specs;
 }
@@ -9444,6 +9441,10 @@ finish_declspecs (struct c_declspecs *sp
       gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p
 		  && !specs->signed_p && !specs->unsigned_p
 		  && !specs->complex_p);
+
+      /* Set a dummy type.  */
+      if (TREE_CODE (specs->type) == ERROR_MARK)
+        specs->type = integer_type_node;
       return specs;
     }
 
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(branch diag-2)
+++ gcc/c-parser.c	(working copy)
@@ -433,6 +433,22 @@ c_parser_next_token_is_keyword (c_parser
   return c_parser_peek_token (parser)->keyword == keyword;
 }
 
+/* Return a pointer to the next-but-one token from PARSER, reading it
+   in if necessary.  The next token is already read in.  */
+
+static c_token *
+c_parser_peek_2nd_token (c_parser *parser)
+{
+  if (parser->tokens_avail >= 2)
+    return &parser->tokens[1];
+  gcc_assert (parser->tokens_avail == 1);
+  gcc_assert (parser->tokens[0].type != CPP_EOF);
+  gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
+  c_lex_one_token (parser, &parser->tokens[1]);
+  parser->tokens_avail = 2;
+  return &parser->tokens[1];
+}
+
 /* Return true if TOKEN can start a type name,
    false otherwise.  */
 static bool
@@ -497,13 +513,46 @@ c_token_starts_typename (c_token *token)
     }
 }
 
+enum c_lookahead_kind {
+  /* Always treat unknown identifiers as typenames.  */
+  cla_prefer_type,
+
+  /* Could be parsing a nonabstract declarator.  Only treat an identifier
+     as a typename if followed by another identifier or a star.  */
+  cla_nonabstract_decl,
+
+  /* Never treat identifiers as typenames.  */
+  cla_prefer_id
+};
+
 /* Return true if the next token from PARSER can start a type name,
-   false otherwise.  */
+   false otherwise.  LA specifies how to do lookahead in order to
+   detect unknown type names.  If unsure, pick CLA_PREFER_ID.  */
+
 static inline bool
-c_parser_next_token_starts_typename (c_parser *parser)
+c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la)
 {
   c_token *token = c_parser_peek_token (parser);
-  return c_token_starts_typename (token);
+  if (c_token_starts_typename (token))
+    return true;
+
+  /* Try a bit harder to detect an unknown typename.  */
+  if (la != cla_prefer_id
+      && token->type == CPP_NAME
+      && token->id_kind == C_ID_ID
+
+      /* Do not try too hard when we could have "object in array".  */
+      && !parser->objc_could_be_foreach_context
+
+      && (la == cla_prefer_type
+          || c_parser_peek_2nd_token (parser)->type == CPP_NAME
+          || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+
+      /* Only unknown identifiers.  */
+      && !lookup_name (token->value))
+    return true;
+
+  return false;
 }
 
 /* Return true if TOKEN is a type qualifier, false otherwise.  */
@@ -631,8 +680,6 @@ c_token_starts_declaration (c_token *tok
     return false;
 }
 
-static c_token *c_parser_peek_2nd_token (c_parser *parser);
-
 /* Return true if the next token from PARSER can start declaration
    specifiers, false otherwise.  */
 static inline bool
@@ -677,36 +724,12 @@ c_parser_next_tokens_start_declaration (
   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)
-
-      /* Do not try too hard when we could have "object in array".  */
-      && !parser->objc_could_be_foreach_context)
+  if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl))
     return true;
 
   return false;
 }
 
-/* Return a pointer to the next-but-one token from PARSER, reading it
-   in if necessary.  The next token is already read in.  */
-
-static c_token *
-c_parser_peek_2nd_token (c_parser *parser)
-{
-  if (parser->tokens_avail >= 2)
-    return &parser->tokens[1];
-  gcc_assert (parser->tokens_avail == 1);
-  gcc_assert (parser->tokens[0].type != CPP_EOF);
-  gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
-  c_lex_one_token (parser, &parser->tokens[1]);
-  parser->tokens_avail = 2;
-  return &parser->tokens[1];
-}
-
 /* Consume the next token from PARSER.  */
 
 static void
@@ -1076,7 +1099,7 @@ static void c_parser_declaration_or_fnde
 static void c_parser_static_assert_declaration_no_semi (c_parser *);
 static void c_parser_static_assert_declaration (c_parser *);
 static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
-				bool);
+				bool, bool);
 static struct c_typespec c_parser_enum_specifier (c_parser *);
 static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
 static tree c_parser_struct_declaration (c_parser *);
@@ -1425,7 +1448,7 @@ c_parser_declaration_or_fndef (c_parser 
       fndef_ok = !nested;
     }
 
-  c_parser_declspecs (parser, specs, true, true, start_attr_ok);
+  c_parser_declspecs (parser, specs, true, true, start_attr_ok, true);
   if (parser->error)
     {
       c_parser_skip_to_end_of_block_or_statement (parser);
@@ -1922,12 +1945,12 @@ c_parser_static_assert_declaration_no_se
 
 static void
 c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
-		    bool scspec_ok, bool typespec_ok, bool start_attr_ok)
+		    bool scspec_ok, bool typespec_ok, bool start_attr_ok,
+		    bool nonabstract_decl)
 {
   bool attrs_ok = start_attr_ok;
   bool seen_type = specs->typespec_kind != ctsk_none;
-  while ((c_parser_next_token_is (parser, CPP_NAME)
-	  && c_parser_peek_token (parser)->id_kind != C_ID_ID)
+  while (c_parser_next_token_is (parser, CPP_NAME)
 	 || c_parser_next_token_is (parser, CPP_KEYWORD)
 	 || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
     {
@@ -1937,18 +1960,30 @@ c_parser_declspecs (c_parser *parser, st
 
       if (!c_parser_next_token_is_qualifier (parser))
         {
-	  /* Exit for TYPENAMEs after any type because they can appear as a
+          enum c_lookahead_kind la;
+
+	  /* After any type, exit even for TYPENAMEs, because they can appear as a
 	     field name.  */
           if (seen_type && c_parser_next_token_is (parser, CPP_NAME))
             break;
 
-          /* If we cannot accept a type, and the next token must start one,
-	     exit.  Do the same if we already have seen a tagged definition,
-	     since it would be an error anyway and likely the user has simply
-	     forgotten a semicolon.  */
-          if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef)
-	      && c_parser_next_token_starts_typename (parser))
-            break;
+          la = nonabstract_decl ? cla_nonabstract_decl : cla_prefer_type;
+          if (c_parser_next_tokens_start_typename (parser, la))
+            {
+              /* We cannot accept a type, and the next token must start one;
+                 exit.  Do the same if we already have seen a tagged definition,
+                 since it would be an error anyway and likely the user has simply
+                 forgotten a semicolon.  */
+              if (!typespec_ok || specs->typespec_kind == ctsk_tagdef)
+                break;
+            }
+          else
+            {
+              /* If the next token is an identifier, and it is not guessed
+                 to be an unknown typename, exit.  */
+              if (c_parser_next_token_is (parser, CPP_NAME))
+                break;
+            }
         }
 
       if (c_parser_next_token_is (parser, CPP_NAME))
@@ -1966,20 +2001,25 @@ c_parser_declspecs (c_parser *parser, st
 	      continue;
 	    }
 
-	  /* Now at a C_ID_TYPENAME or C_ID_CLASSNAME.  */
+	  /* Now at an unknown typename (C_ID_ID), a C_ID_TYPENAME or
+	     a C_ID_CLASSNAME.  */
 	  c_parser_consume_token (parser);
 	  seen_type = true;
 	  attrs_ok = true;
-	  if (kind == C_ID_TYPENAME
-	      && (!c_dialect_objc ()
-		  || c_parser_next_token_is_not (parser, CPP_LESS)))
+          if (kind == C_ID_ID)
+            {
+              error ("unknown type name %qE", value);
+              t.kind = ctsk_typedef;
+              t.spec = error_mark_node;
+            }
+          else if (kind == C_ID_TYPENAME
+                   && (!c_dialect_objc ()
+                       || c_parser_next_token_is_not (parser, CPP_LESS)))
 	    {
 	      t.kind = ctsk_typedef;
 	      /* For a typedef name, record the meaning, not the name.
 		 In case of 'foo foo, bar;'.  */
 	      t.spec = lookup_name (value);
-	      t.expr = NULL_TREE;
-	      t.expr_const_operands = true;
 	    }
 	  else
 	    {
@@ -1989,9 +2029,9 @@ c_parser_declspecs (c_parser *parser, st
 	      if (c_parser_next_token_is (parser, CPP_LESS))
 		proto = c_parser_objc_protocol_refs (parser);
 	      t.spec = objc_get_protocol_qualified_type (value, proto);
-	      t.expr = NULL_TREE;
-	      t.expr_const_operands = true;
 	    }
+          t.expr = NULL_TREE;
+          t.expr_const_operands = true;
 	  declspecs_add_type (loc, specs, t);
 	  continue;
 	}
@@ -2498,7 +2538,7 @@ c_parser_struct_declaration (c_parser *p
     }
   specs = build_null_declspecs ();
   decl_loc = c_parser_peek_token (parser)->location;
-  c_parser_declspecs (parser, specs, false, true, true);
+  c_parser_declspecs (parser, specs, false, true, true, true);
   if (parser->error)
     return NULL_TREE;
   if (!specs->declspecs_seen_p)
@@ -2644,7 +2684,7 @@ c_parser_typeof_specifier (c_parser *par
       in_typeof--;
       return ret;
     }
-  if (c_parser_next_token_starts_typename (parser))
+  if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
     {
       struct c_type_name *type = c_parser_type_name (parser);
       c_inhibit_evaluation_warnings--;
@@ -2770,7 +2810,8 @@ c_parser_declarator (c_parser *parser, b
       struct c_declspecs *quals_attrs = build_null_declspecs ();
       struct c_declarator *inner;
       c_parser_consume_token (parser);
-      c_parser_declspecs (parser, quals_attrs, false, false, true);
+      c_parser_declspecs (parser, quals_attrs, false, false, true,
+			  kind != C_DTR_ABSTRACT);
       inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
       if (inner == NULL)
 	return NULL;
@@ -2922,12 +2963,12 @@ c_parser_direct_declarator_inner (c_pars
       bool star_seen;
       tree dimen;
       c_parser_consume_token (parser);
-      c_parser_declspecs (parser, quals_attrs, false, false, true);
+      c_parser_declspecs (parser, quals_attrs, false, false, true, true);
       static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
       if (static_seen)
 	c_parser_consume_token (parser);
       if (static_seen && !quals_attrs->declspecs_seen_p)
-	c_parser_declspecs (parser, quals_attrs, false, false, true);
+	c_parser_declspecs (parser, quals_attrs, false, false, true, true);
       if (!quals_attrs->declspecs_seen_p)
 	quals_attrs = NULL;
       /* If "static" is present, there must be an array dimension.
@@ -3015,7 +3056,13 @@ c_parser_parms_declarator (c_parser *par
   if (id_list_ok
       && !attrs
       && c_parser_next_token_is (parser, CPP_NAME)
-      && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+      && c_parser_peek_token (parser)->id_kind == C_ID_ID
+      
+      /* Look ahead to detect typos in type names.  */
+      && c_parser_peek_2nd_token (parser)->type != CPP_NAME
+      && c_parser_peek_2nd_token (parser)->type != CPP_MULT
+      && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN
+      && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE)
     {
       tree list = NULL_TREE, *nextp = &list;
       while (c_parser_next_token_is (parser, CPP_NAME)
@@ -3178,9 +3225,7 @@ c_parser_parameter_declaration (c_parser
       if (parser->error)
 	return NULL;
       c_parser_set_source_position_from_token (token);
-      if (token->type == CPP_NAME
-	  && c_parser_peek_2nd_token (parser)->type != CPP_COMMA
-	  && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN)
+      if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
 	{
 	  error ("unknown type name %qE", token->value);
 	  parser->error = true;
@@ -3199,7 +3244,7 @@ c_parser_parameter_declaration (c_parser
       declspecs_add_attrs (specs, attrs);
       attrs = NULL_TREE;
     }
-  c_parser_declspecs (parser, specs, true, true, true);
+  c_parser_declspecs (parser, specs, true, true, true, true);
   finish_declspecs (specs);
   pending_xref_error ();
   prefix_attrs = specs->attrs;
@@ -3489,14 +3534,17 @@ c_parser_type_name (c_parser *parser)
   struct c_declarator *declarator;
   struct c_type_name *ret;
   bool dummy = false;
-  c_parser_declspecs (parser, specs, false, true, true);
+  c_parser_declspecs (parser, specs, false, true, true, false);
   if (!specs->declspecs_seen_p)
     {
       c_parser_error (parser, "expected specifier-qualifier-list");
       return NULL;
     }
-  pending_xref_error ();
-  finish_declspecs (specs);
+  if (specs->type != error_mark_node)
+    {
+      pending_xref_error ();
+      finish_declspecs (specs);
+    }
   declarator = c_parser_declarator (parser,
 				    specs->typespec_kind != ctsk_none,
 				    C_DTR_ABSTRACT, &dummy);
@@ -5624,7 +5672,8 @@ c_parser_cast_expression (c_parser *pars
   /* If the expression begins with a parenthesized type name, it may
      be either a cast or a compound literal; we need to see whether
      the next character is '{' to tell the difference.  If not, it is
-     an unary expression.  */
+     an unary expression.  Full detection of unknown typenames here
+     would require a 3-token lookahead.  */
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
     {
@@ -6186,16 +6235,16 @@ c_parser_postfix_expression (c_parser *p
 	    }
 	  t1 = c_parser_type_name (parser);
 	  if (t1 == NULL)
-	    {
-	      expr.value = error_mark_node;
-	      break;
-	    }
+	    parser->error = true;
 	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+            gcc_assert (parser->error);
+	  if (parser->error)
 	    {
 	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
 	      expr.value = error_mark_node;
 	      break;
 	    }
+
 	  {
 	    tree type = groktypename (t1, NULL, NULL);
 	    tree offsetof_ref;
@@ -7427,7 +7476,7 @@ c_parser_objc_type_name (c_parser *parse
       else
 	break;
     }
-  if (c_parser_next_token_starts_typename (parser))
+  if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
     type_name = c_parser_type_name (parser);
   if (type_name)
     type = groktypename (type_name, NULL, NULL);
Index: gcc/testsuite/objc.dg/tls/init-2.m
===================================================================
--- gcc/testsuite/objc.dg/tls/init-2.m	(branch diag-2)
+++ gcc/testsuite/objc.dg/tls/init-2.m	(working copy)
@@ -11,4 +11,4 @@ struct S
 {
   S(); 			/* { dg-error "expected specifier-qualifier-list before 'S'" } */
 };
-__thread S s;		/* { dg-error "expected" } two errors here */
+__thread S s;		/* { dg-error "unknown type name" } */
Index: gcc/testsuite/gcc.dg/noncompile/920923-1.c
===================================================================
--- gcc/testsuite/gcc.dg/noncompile/920923-1.c	(branch diag-2)
+++ gcc/testsuite/gcc.dg/noncompile/920923-1.c	(working copy)
@@ -2,13 +2,13 @@
 typedef BYTE unsigned char;	/* { dg-error "expected" } */
 typedef int item_n;
 typedef int perm_set;
-struct PENT { caddr_t v_addr; };/* { dg-error "expected" } */
+struct PENT { caddr_t v_addr; };/* { dg-error "unknown type name" } */
 typedef struct PENT prec;
 typedef struct PENT *prec_t;
 prec_t mem_hash;
 BYTE *mem_base;			/* { dg-error "unknown type name" } */
 struct PTE {
-     BYTE *p_page;		/* { dg-error "expected" } */
+     BYTE *p_page;		/* { dg-error "unknown type name" } */
      perm_set p_perms;
 };
 typedef struct PTE pte;
@@ -56,7 +56,7 @@ int va_op;
 caddr_t v_addr;			/* { dg-error "unknown type name" } */
 {
      register prec_t bucket;
-     register caddr_t p_addr;	/* { dg-error "expected|undeclared" } */
+     register caddr_t p_addr;	/* { dg-error "unknown type name" } */
      bucket = mem_hash+((((v_addr)>>ITEMBITS))&hash_mask);  /* { dg-error "undeclared" } */
      do {
 	  if (bucket->v_addr == ((v_addr)>>ITEMBITS) {	/* { dg-error "expected|undeclared|no member" } */
Index: gcc/testsuite/gcc.dg/noncompile/pr44517.c
===================================================================
--- gcc/testsuite/gcc.dg/noncompile/pr44517.c	(branch diag-2)
+++ gcc/testsuite/gcc.dg/noncompile/pr44517.c	(working copy)
@@ -12,7 +12,7 @@ int f2(int x, lon y, long z, ...){ /* { 
 void f3(int n, int a[n], pid_t x); /* { dg-error "unknown type name 'pid_t'" } */
 void f4() {}
 void f5(int a, *b); /* { dg-error "expected declaration specifiers or" } */
-void f6(int a, b);  /* { dg-error "expected declaration specifiers or" } */
+void f6(int a, b);  /* { dg-error "unknown type name 'b'" } */
 void f7(int a, goto b); /* { dg-error "expected declaration specifiers or" } */
 void f8(int a, in goto); /* { dg-error "unknown type name 'in'" } */
 void f9(int a, in 1); /* { dg-error "unknown type name 'in'" } */



/* { dg-do compile } */
/* { dg-options "-std=gnu89" } */

static t1 *a;           /* { dg-error "unknown type name 't1'" } */

int z;                  /* { dg-message "previous declaration of 'z'" } */
typedef t2 *z;          /* { dg-error "unknown type name 't2'" } */
/* { dg-error "'z' redeclared " "" { target *-*-* } 7 } */

extern t3 p1(void);     /* { dg-error "unknown type name 't3'" } */
int p2(const t4 x);     /* { dg-error "unknown type name 't4'" } */
int p3(const t1 x);     /* { dg-error "unknown type name 't1'" } */ /* dup??? */
int p4(t5 (*x)(void));  /* { dg-error "unknown type name 't5'" } */
int p5(t6 *);           /* { dg-error "unknown type name 't6'" } */
int p6(t7 x);           /* { dg-error "unknown type name 't7'" } */
int p7(t8[]);           /* { dg-error "unknown type name 't8'" } */
int p8(int, t9);        /* { dg-error "unknown type name 't9'" } */

struct s {
  const t1 a;           /* { dg-error "unknown type name 't1'" } */ /* dup??? */
  const t10 b;          /* { dg-error "unknown type name 't10'" } */
  int b;                /* { dg-error "duplicate member" } */
};

typeof (z) c1;
typeof (x1) c2;         /* { dg-error "undeclared" } */
typeof (const t11) c3;  /* { dg-error "unknown type name 't11'" } */
typeof (t11 *) c3;      /* { dg-error "unknown type name 't12'" "" { xfail *-*-* } } */
/* { dg-bogus "unknown type name 'x1'" "" { target *-*-* } 26 } */
/* { dg-bogus "undeclared" "" { xfail *-*-* } 28 } */
/* { dg-bogus "expected expression before" "" { xfail *-*-* } 28 } */

int recover1;

int s0 = sizeof (z);
int s1 = sizeof (x2);          /* { dg-error "undeclared" } */
int s2 = sizeof (const t12);   /* { dg-error "unknown type name 't12'" } */
int s3 = sizeof (t13 *);       /* { dg-error "unknown type name 't13'" "" { xfail *-*-* } } */

int recover2;

/* { dg-bogus "unknown type name 'x2'" "" { target *-*-* } 36 } */
/* { dg-bogus "undeclared" "" { xfail *-*-* } 38 } */
/* { dg-bogus "expected expression before" "" { xfail *-*-* } 38 } */

int a0 = __alignof__ (z);
int a1 = __alignof__ (x3);          /* { dg-error "undeclared" } */
int a2 = __alignof__ (const t14);   /* { dg-error "unknown type name 't14'" } */
int a3 = __alignof__ (t15 *);       /* { dg-error "unknown type name 't15'" "" { xfail *-*-* } } */

int recover3;

/* { dg-bogus "unknown type name 'x3'" "" { target *-*-* } 47 } */
/* { dg-bogus "undeclared" "" { xfail *-*-* } 49 } */
/* { dg-bogus "expected expression before" "" { xfail *-*-* } 49 } */


/* Cannot detect (undefd_type *) or (undefd_type (*) because it would
   require 3 tokens of lookahead (same as above).  */

const char *f1()
{
  return (const t16) "abc";       /* { dg-error "unknown type name 't16'" } */
/* { dg-bogus "expected" "" { target *-*-* } 63 } */
}

const char *f2()
{
  return (const t17 *) "abc";     /* { dg-error "unknown type name 't17'" } */
/* { dg-bogus "expected" "" { target *-*-* } 69 } */
}


/* The parser has problems distinguishing semantic and syntactic errors,
   so it emits a wrong "expected ')'" error here.  */

void *f3(int x)
{
  return (void *) ((void *(*)(t18)) f3);       /* { dg-error "unknown type name 't18'" } */
/* { dg-bogus "expected" "" { xfail *-*-* } 79 } */
}

const void *f4()
{
  return &((const t19){1});       /* { dg-error "unknown type name 't19'" } */
/* { dg-bogus "return discards 'const'" "" { target *-*-* } 85 } */
/* { dg-bogus "expected" "" { target *-*-* } 85 } */
}

int f5(__builtin_va_list ap)
{
  int x = __builtin_va_arg (ap, t20);       /* { dg-error "unknown type name 't20'" } */
  int y = __builtin_va_arg (ap, const t21); /* { dg-error "unknown type name 't21'" } */
}

int f6(void)
{
  return __builtin_offsetof (t22, field); /* { dg-error "unknown type name 't22'" } */
/* { dg-bogus "request for member" "" { target *-*-* } 98 } */
}






^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] PR c/20385: more detection of unknown type names
  2010-11-21  2:19 [PATCH] PR c/20385: more detection of unknown type names Paolo Bonzini
@ 2010-11-25  7:19 ` Joseph S. Myers
  2010-11-25 17:03   ` Paolo Bonzini
  0 siblings, 1 reply; 3+ messages in thread
From: Joseph S. Myers @ 2010-11-25  7:19 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: gcc-patches

On Sun, 21 Nov 2010, Paolo Bonzini wrote:

> @@ -1922,12 +1945,12 @@ c_parser_static_assert_declaration_no_se
>  
>  static void
>  c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
> -		    bool scspec_ok, bool typespec_ok, bool start_attr_ok)
> +		    bool scspec_ok, bool typespec_ok, bool start_attr_ok,
> +		    bool nonabstract_decl)

I don't see an update of the comment above this function (starting quite a 
long way above) to explain the new parameter.

> -          /* If we cannot accept a type, and the next token must start one,
> -	     exit.  Do the same if we already have seen a tagged definition,
> -	     since it would be an error anyway and likely the user has simply
> -	     forgotten a semicolon.  */
> -          if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef)
> -	      && c_parser_next_token_starts_typename (parser))
> -            break;
> +          la = nonabstract_decl ? cla_nonabstract_decl : cla_prefer_type;
> +          if (c_parser_next_tokens_start_typename (parser, la))
> +            {
> +              /* We cannot accept a type, and the next token must start one;
> +                 exit.  Do the same if we already have seen a tagged definition,
> +                 since it would be an error anyway and likely the user has simply
> +                 forgotten a semicolon.  */
> +              if (!typespec_ok || specs->typespec_kind == ctsk_tagdef)
> +                break;

As far as I can see, this rewording of the comment is incorrect; inside 
the outer if, we don't yet know that "We cannot accept a type", that's the 
first condition of the inner if.  I think the original wording would still 
have been correct here.

Also, I'm concerned about the interaction of the new parameter with the 
!typespec_ok case.  Logically, I don't think the new parameter should 
matter at all in that case; if type names aren't valid (as in qualifiers 
in pointer and array declarators), this function shouldn't attempt to 
guess what undeclared identifiers might be, it should just return for 
them.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] PR c/20385: more detection of unknown type names
  2010-11-25  7:19 ` Joseph S. Myers
@ 2010-11-25 17:03   ` Paolo Bonzini
  0 siblings, 0 replies; 3+ messages in thread
From: Paolo Bonzini @ 2010-11-25 17:03 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches

>> -          /* If we cannot accept a type, and the next token must start one,
>> -          exit.  Do the same if we already have seen a tagged definition,
>> -          since it would be an error anyway and likely the user has simply
>> -          forgotten a semicolon.  */
>> -          if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef)
>> -           && c_parser_next_token_starts_typename (parser))
>> -            break;
>> +          la = nonabstract_decl ? cla_nonabstract_decl : cla_prefer_type;
>> +          if (c_parser_next_tokens_start_typename (parser, la))
>> +            {
>> +              /* We cannot accept a type, and the next token must start one;
>> +                 exit.  Do the same if we already have seen a tagged definition,
>> +                 since it would be an error anyway and likely the user has simply
>> +                 forgotten a semicolon.  */
>> +              if (!typespec_ok || specs->typespec_kind == ctsk_tagdef)
>> +                break;
>
> As far as I can see, this rewording of the comment is incorrect; inside
> the outer if, we don't yet know that "We cannot accept a type", that's the
> first condition of the inner if.  I think the original wording would still
> have been correct here.

Right.

> Also, I'm concerned about the interaction of the new parameter with the
> !typespec_ok case.  Logically, I don't think the new parameter should
> matter at all in that case; if type names aren't valid (as in qualifiers
> in pointer and array declarators), this function shouldn't attempt to
> guess what undeclared identifiers might be, it should just return for
> them.

I agree it is better to use cla_prefer_id if !typespec_ok.

Thanks for the review!

Paolo

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-11-25 13:20 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-11-21  2:19 [PATCH] PR c/20385: more detection of unknown type names Paolo Bonzini
2010-11-25  7:19 ` Joseph S. Myers
2010-11-25 17:03   ` Paolo Bonzini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).