Patchwork [v2] PR c/20385: more detection of unknown type names

login
register
mail settings
Submitter Paolo Bonzini
Date Nov. 30, 2010, 3:33 p.m.
Message ID <1291131182-9976-1-git-send-email-bonzini@gnu.org>
Download mbox | patch
Permalink /patch/73618/
State New
Headers show

Comments

Paolo Bonzini - Nov. 30, 2010, 3:33 p.m.
This patch fixes the problems in c_parser_declspecs pointed out by
review of v1.  The new argument is changed to specify the desired
lookahead directly.

Bootstrapped/regtested x86_64-pc-linux-gnu.

Paolo

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

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

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

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





/* { 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 } */
}
Joseph S. Myers - Dec. 6, 2010, 5:36 p.m.
On Tue, 30 Nov 2010, Paolo Bonzini wrote:

> typeof (t11 *) c3;      /* { dg-error "unknown type name 't12'" "" { xfail *-*-* } } */

The expected (and XFAILed) message here should refer to t11 not t12 as the 
unknown type.

The C parts of the patch are OK with that change.
Paolo Bonzini - Dec. 17, 2010, 9:22 p.m.
On 12/06/2010 06:36 PM, Joseph S. Myers wrote:
> On Tue, 30 Nov 2010, Paolo Bonzini wrote:
>
>> typeof (t11 *) c3;      /* { dg-error "unknown type name 't12'" "" { xfail *-*-* } } */
>
> The expected (and XFAILed) message here should refer to t11 not t12 as the
> unknown type.
>
> The C parts of the patch are OK with that change.

Since the non C parts are 2 lines of code and 10 days have passed since 
your review, I'm committing the patch.

Paolo
H.J. Lu - Dec. 17, 2010, 11:50 p.m.
On Fri, Dec 17, 2010 at 1:22 PM, Paolo Bonzini <bonzini@gnu.org> wrote:
> On 12/06/2010 06:36 PM, Joseph S. Myers wrote:
>>
>> On Tue, 30 Nov 2010, Paolo Bonzini wrote:
>>
>>> typeof (t11 *) c3;      /* { dg-error "unknown type name 't12'" "" {
>>> xfail *-*-* } } */
>>
>> The expected (and XFAILed) message here should refer to t11 not t12 as the
>> unknown type.
>>
>> The C parts of the patch are OK with that change.
>
> Since the non C parts are 2 lines of code and 10 days have passed since your
> review, I'm committing the patch.
>

It caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46998
Paolo Bonzini - Dec. 18, 2010, 2:33 a.m.
On 12/18/2010 12:50 AM, H.J. Lu wrote:
> On Fri, Dec 17, 2010 at 1:22 PM, Paolo Bonzini<bonzini@gnu.org>  wrote:
>> On 12/06/2010 06:36 PM, Joseph S. Myers wrote:
>>>
>>> On Tue, 30 Nov 2010, Paolo Bonzini wrote:
>>>
>>>> typeof (t11 *) c3;      /* { dg-error "unknown type name 't12'" "" {
>>>> xfail *-*-* } } */
>>>
>>> The expected (and XFAILed) message here should refer to t11 not t12 as the
>>> unknown type.
>>>
>>> The C parts of the patch are OK with that change.
>>
>> Since the non C parts are 2 lines of code and 10 days have passed since your
>> review, I'm committing the patch.
>>
>
> It caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46998

Already fixed by Nicola (I rebootstrapped the patch without running the 
full testsuite).

Paolo

Patch

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'" } */
Index: gcc/function.c
===================================================================
--- gcc/function.c	(branch diag-2)
+++ gcc/function.c	(working copy)
@@ -5712,6 +5712,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, enum c_lookahead_kind);
 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,8 @@  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,
+		      cla_nonabstract_decl);
   if (parser->error)
     {
       c_parser_skip_to_end_of_block_or_statement (parser);
@@ -1922,12 +1945,16 @@  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,
+		    enum c_lookahead_kind la)
 {
   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)
+
+  if (!typespec_ok)
+    gcc_assert (la == cla_prefer_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)))
     {
@@ -1935,21 +1962,14 @@  c_parser_declspecs (c_parser *parser, st
       tree attrs;
       location_t loc = c_parser_peek_token (parser)->location;
 
-      if (!c_parser_next_token_is_qualifier (parser))
-        {
-	  /* Exit for TYPENAMEs after any type 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;
-        }
+      /* If we cannot accept a type, exit if the next token must start
+	 one.  Also, if we already have seen a tagged definition,
+	 a typename would be an error anyway and likely the user
+	 has simply forgotten a semicolon, so we exit.  */
+      if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef)
+	  && c_parser_next_tokens_start_typename (parser, la)
+	  && !c_parser_next_token_is_qualifier (parser))
+	break;
 
       if (c_parser_next_token_is (parser, CPP_NAME))
 	{
@@ -1966,20 +1986,34 @@  c_parser_declspecs (c_parser *parser, st
 	      continue;
 	    }
 
-	  /* Now at a C_ID_TYPENAME or C_ID_CLASSNAME.  */
+	  gcc_assert (!c_parser_next_token_is_qualifier (parser));
+
+	  /* 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 (seen_type || !c_parser_next_tokens_start_typename (parser, la))
+	    break;
+
+	  /* 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 +2023,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 +2532,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, cla_nonabstract_decl);
   if (parser->error)
     return NULL_TREE;
   if (!specs->declspecs_seen_p)
@@ -2644,7 +2678,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 +2804,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,
+			  cla_prefer_id);
       inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
       if (inner == NULL)
 	return NULL;
@@ -2922,12 +2956,14 @@  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,
+			  cla_prefer_id);
       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,
+			    cla_prefer_id);
       if (!quals_attrs->declspecs_seen_p)
 	quals_attrs = NULL;
       /* If "static" is present, there must be an array dimension.
@@ -3015,7 +3049,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 +3218,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 +3237,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, cla_nonabstract_decl);
   finish_declspecs (specs);
   pending_xref_error ();
   prefix_attrs = specs->attrs;
@@ -3489,14 +3527,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, cla_prefer_type);
   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 +5665,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, or parsing parentheses here.  */
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
     {
@@ -6186,16 +6228,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 +7469,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);