Fix parsing of type-specifier-seq's. Types are syntactically allowed to be
defined here, but not semantically, so

  new struct S {};

is always ill-formed, even if there is a struct S in scope.

We also had a couple of bugs in ParseOptionalTypeSpecifier caused by it being
under-loved (due to it only being used in a few places) so merge it into
ParseDeclarationSpecifiers with a new DeclSpecContext. To avoid regressing, this
required improving ParseDeclarationSpecifiers' diagnostics in some cases. This
also required teaching ParseSpecifierQualifierList about constexpr... which
incidentally fixes an issue where we'd allow the constexpr specifier in other
bad places.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152549 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index c5cab86..9552218 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -280,9 +280,11 @@
   "type name does not allow storage class to be specified">;
 def err_typename_invalid_functionspec : Error<
   "type name does not allow function specifier to be specified">;
+def err_typename_invalid_constexpr : Error<
+  "type name does not allow constexpr specifier to be specified">;
 def err_typename_identifiers_only : Error<
   "typename is allowed for identifiers only">;
-  
+
 def err_invalid_decl_spec_combination : Error<
   "cannot combine with previous '%0' declaration specifier">;
 def err_invalid_vector_decl_spec_combination : Error<
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 2124f1e..0496057 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1621,6 +1621,7 @@
   enum DeclSpecContext {
     DSC_normal, // normal context
     DSC_class,  // class context, enables 'friend'
+    DSC_type_specifier, // C++ type-specifier-seq
     DSC_top_level // top-level/namespace declaration context
   };
 
@@ -1663,27 +1664,23 @@
 
   bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
                         const ParsedTemplateInfo &TemplateInfo,
-                        AccessSpecifier AS);
+                        AccessSpecifier AS, DeclSpecContext DSC);
   DeclSpecContext getDeclSpecContextFromDeclaratorContext(unsigned Context);
   void ParseDeclarationSpecifiers(DeclSpec &DS,
                 const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
                                   AccessSpecifier AS = AS_none,
                                   DeclSpecContext DSC = DSC_normal,
                                   LateParsedAttrList *LateAttrs = 0);
-  bool ParseOptionalTypeSpecifier(DeclSpec &DS, bool &isInvalid,
-                                  const char *&PrevSpec,
-                                  unsigned &DiagID,
-               const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
-                                  bool SuppressDeclarations = false);
 
-  void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none);
+  void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none,
+                                   DeclSpecContext DSC = DSC_normal);
 
   void ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
                                   Declarator::TheContext Context);
 
   void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS,
-                const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
-                AccessSpecifier AS = AS_none);
+                          const ParsedTemplateInfo &TemplateInfo,
+                          AccessSpecifier AS, DeclSpecContext DSC);
   void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl);
   void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
                             Decl *TagDecl);
@@ -2060,11 +2057,9 @@
   //===--------------------------------------------------------------------===//
   // C++ 9: classes [class] and C structs/unions.
   void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
-                           DeclSpec &DS,
-                const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
-                           AccessSpecifier AS = AS_none,
-                           bool EnteringContext = false,
-                           bool SuppressDeclarations = false);
+                           DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo,
+                           AccessSpecifier AS, bool EnteringContext,
+                           DeclSpecContext DSC);
   void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
                                    Decl *TagDecl);
   ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index e86b485..425335e 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -614,6 +614,11 @@
   bool isConstexprSpecified() const { return Constexpr_specified; }
   SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }
 
+  void ClearConstexprSpec() {
+    Constexpr_specified = false;
+    ConstexprLoc = SourceLocation();
+  }
+
   AttributePool &getAttributePool() const {
     return Attrs.getPool();
   }
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 12866b9..c1f6eb5 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1424,17 +1424,24 @@
 ///          type-qualifier specifier-qualifier-list[opt]
 /// [GNU]    attributes     specifier-qualifier-list[opt]
 ///
-void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) {
+void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
+                                         DeclSpecContext DSC) {
   /// specifier-qualifier-list is a subset of declaration-specifiers.  Just
   /// parse declaration-specifiers and complain about extra stuff.
   /// TODO: diagnose attribute-specifiers and alignment-specifiers.
-  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
+  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC);
 
   // Validate declspec for type-name.
   unsigned Specs = DS.getParsedSpecifiers();
-  if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
-      !DS.hasAttributes())
+  if (DSC == DSC_type_specifier && !DS.hasTypeSpecifier()) {
+    Diag(Tok, diag::err_expected_type);
+    DS.SetTypeSpecError();
+  } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
+             !DS.hasAttributes()) {
     Diag(Tok, diag::err_typename_requires_specqual);
+    if (!DS.hasTypeSpecifier())
+      DS.SetTypeSpecError();
+  }
 
   // Issue diagnostic and remove storage class if present.
   if (Specs & DeclSpec::PQ_StorageClassSpecifier) {
@@ -1455,6 +1462,12 @@
       Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
     DS.ClearFunctionSpecs();
   }
+
+  // Issue diagnostic and remove constexpr specfier if present.
+  if (DS.isConstexprSpecified()) {
+    Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
+    DS.ClearConstexprSpec();
+  }
 }
 
 /// isValidAfterIdentifierInDeclaratorAfterDeclSpec - Return true if the
@@ -1493,7 +1506,7 @@
 ///
 bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
                               const ParsedTemplateInfo &TemplateInfo,
-                              AccessSpecifier AS) {
+                              AccessSpecifier AS, DeclSpecContext DSC) {
   assert(Tok.is(tok::identifier) && "should have identifier");
 
   SourceLocation Loc = Tok.getLocation();
@@ -1512,8 +1525,13 @@
   assert(!DS.hasTypeSpecifier() && "Type specifier checked above");
 
   // Since we know that this either implicit int (which is rare) or an
-  // error, we'd do lookahead to try to do better recovery.
-  if (isValidAfterIdentifierInDeclarator(NextToken())) {
+  // error, do lookahead to try to do better recovery. This never applies within
+  // a type specifier.
+  // FIXME: Don't bail out here in languages with no implicit int (like
+  // C++ with no -fms-extensions). This is much more likely to be an undeclared
+  // type or typo than a use of implicit int.
+  if (DSC != DSC_type_specifier &&
+      isValidAfterIdentifierInDeclarator(NextToken())) {
     // If this token is valid for implicit int, e.g. "static x = 4", then
     // we just avoid eating the identifier, so it will be parsed as the
     // identifier in the declarator.
@@ -1549,9 +1567,10 @@
 
       // Parse this as a tag as if the missing tag were present.
       if (TagKind == tok::kw_enum)
-        ParseEnumSpecifier(Loc, DS, TemplateInfo, AS);
+        ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSC_normal);
       else
-        ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS);
+        ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS,
+                            /*EnteringContext*/ false, DSC_normal);
       return true;
     }
   }
@@ -1585,9 +1604,7 @@
   }
 
   // Mark this as an error.
-  const char *PrevSpec;
-  unsigned DiagID;
-  DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec, DiagID);
+  DS.SetTypeSpecError();
   DS.SetRangeEnd(Tok.getLocation());
   ConsumeToken();
 
@@ -1895,7 +1912,7 @@
       // typename.
       if (TypeRep == 0) {
         ConsumeToken();   // Eat the scope spec so the identifier is current.
-        if (ParseImplicitInt(DS, &SS, TemplateInfo, AS)) continue;
+        if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext)) continue;
         goto DoneWithDeclSpec;
       }
 
@@ -1979,7 +1996,6 @@
       if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
         break;
 
-      // It has to be available as a typedef too!
       ParsedType TypeRep =
         Actions.getTypeName(*Tok.getIdentifierInfo(),
                             Tok.getLocation(), getCurScope());
@@ -1987,7 +2003,7 @@
       // If this is not a typedef name, don't parse it as part of the declspec,
       // it must be an implicit int or an error.
       if (!TypeRep) {
-        if (ParseImplicitInt(DS, 0, TemplateInfo, AS)) continue;
+        if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext)) continue;
         goto DoneWithDeclSpec;
       }
 
@@ -2276,14 +2292,15 @@
     case tok::kw_union: {
       tok::TokenKind Kind = Tok.getKind();
       ConsumeToken();
-      ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS, EnteringContext);
+      ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS,
+                          EnteringContext, DSContext);
       continue;
     }
 
     // enum-specifier:
     case tok::kw_enum:
       ConsumeToken();
-      ParseEnumSpecifier(Loc, DS, TemplateInfo, AS);
+      ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext);
       continue;
 
     // cv-qualifier:
@@ -2375,301 +2392,6 @@
   }
 }
 
-/// ParseOptionalTypeSpecifier - Try to parse a single type-specifier. We
-/// primarily follow the C++ grammar with additions for C99 and GNU,
-/// which together subsume the C grammar. Note that the C++
-/// type-specifier also includes the C type-qualifier (for const,
-/// volatile, and C99 restrict). Returns true if a type-specifier was
-/// found (and parsed), false otherwise.
-///
-///       type-specifier: [C++ 7.1.5]
-///         simple-type-specifier
-///         class-specifier
-///         enum-specifier
-///         elaborated-type-specifier  [TODO]
-///         cv-qualifier
-///
-///       cv-qualifier: [C++ 7.1.5.1]
-///         'const'
-///         'volatile'
-/// [C99]   'restrict'
-///
-///       simple-type-specifier: [ C++ 7.1.5.2]
-///         '::'[opt] nested-name-specifier[opt] type-name [TODO]
-///         '::'[opt] nested-name-specifier 'template' template-id [TODO]
-///         'char'
-///         'wchar_t'
-///         'bool'
-///         'short'
-///         'int'
-///         'long'
-///         'signed'
-///         'unsigned'
-///         'float'
-///         'double'
-///         'void'
-/// [C99]   '_Bool'
-/// [C99]   '_Complex'
-/// [C99]   '_Imaginary'  // Removed in TC2?
-/// [GNU]   '_Decimal32'
-/// [GNU]   '_Decimal64'
-/// [GNU]   '_Decimal128'
-/// [GNU]   typeof-specifier
-/// [OBJC]  class-name objc-protocol-refs[opt]    [TODO]
-/// [OBJC]  typedef-name objc-protocol-refs[opt]  [TODO]
-/// [C++0x] 'decltype' ( expression )
-/// [AltiVec] '__vector'
-bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
-                                        const char *&PrevSpec,
-                                        unsigned &DiagID,
-                                        const ParsedTemplateInfo &TemplateInfo,
-                                        bool SuppressDeclarations) {
-  SourceLocation Loc = Tok.getLocation();
-
-  switch (Tok.getKind()) {
-  case tok::identifier:   // foo::bar
-    // If we already have a type specifier, this identifier is not a type.
-    if (DS.getTypeSpecType() != DeclSpec::TST_unspecified ||
-        DS.getTypeSpecWidth() != DeclSpec::TSW_unspecified ||
-        DS.getTypeSpecSign() != DeclSpec::TSS_unspecified)
-      return false;
-    // Check for need to substitute AltiVec keyword tokens.
-    if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
-      break;
-    // Fall through.
-  case tok::kw_decltype:
-  case tok::kw_typename:  // typename foo::bar
-    // Annotate typenames and C++ scope specifiers.  If we get one, just
-    // recurse to handle whatever we get.
-    if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false,
-                                    /*NeedType=*/true))
-      return true;
-    if (Tok.is(tok::identifier))
-      return false;
-    return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
-                                      TemplateInfo, SuppressDeclarations);
-  case tok::coloncolon:   // ::foo::bar
-    if (NextToken().is(tok::kw_new) ||    // ::new
-        NextToken().is(tok::kw_delete))   // ::delete
-      return false;
-
-    // Annotate typenames and C++ scope specifiers.  If we get one, just
-    // recurse to handle whatever we get.
-    if (TryAnnotateTypeOrScopeToken(/*EnteringContext=*/false,
-                                    /*NeedType=*/true))
-      return true;
-    return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
-                                      TemplateInfo, SuppressDeclarations);
-
-  // simple-type-specifier:
-  case tok::annot_typename: {
-    if (ParsedType T = getTypeAnnotation(Tok)) {
-      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
-                                     Tok.getAnnotationEndLoc(), PrevSpec,
-                                     DiagID, T);
-    } else
-      DS.SetTypeSpecError();
-    DS.SetRangeEnd(Tok.getAnnotationEndLoc());
-    ConsumeToken(); // The typename
-
-    // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
-    // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
-    // Objective-C interface.  If we don't have Objective-C or a '<', this is
-    // just a normal reference to a typedef name.
-    if (Tok.is(tok::less) && getLangOpts().ObjC1)
-      ParseObjCProtocolQualifiers(DS);
-    
-    return true;
-  }
-
-  case tok::kw_short:
-    isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_long:
-    if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
-      isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec,
-                                      DiagID);
-    else
-      isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
-                                      DiagID);
-    break;
-  case tok::kw___int64:
-      isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
-                                      DiagID);
-    break;
-  case tok::kw_signed:
-    isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_unsigned:
-    isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec,
-                                   DiagID);
-    break;
-  case tok::kw__Complex:
-    isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
-                                      DiagID);
-    break;
-  case tok::kw__Imaginary:
-    isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
-                                      DiagID);
-    break;
-  case tok::kw_void:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_char:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_int:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_half:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_float:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_double:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_wchar_t:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_char16_t:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_char32_t:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw_bool:
-  case tok::kw__Bool:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw__Decimal32:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec,
-                                   DiagID);
-    break;
-  case tok::kw__Decimal64:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec,
-                                   DiagID);
-    break;
-  case tok::kw__Decimal128:
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
-                                   DiagID);
-    break;
-  case tok::kw___vector:
-    isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
-    break;
-  case tok::kw___pixel:
-    isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
-    break;
-  
-  // class-specifier:
-  case tok::kw_class:
-  case tok::kw_struct:
-  case tok::kw_union: {
-    tok::TokenKind Kind = Tok.getKind();
-    ConsumeToken();
-    ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS_none,
-                        /*EnteringContext=*/false,
-                        SuppressDeclarations);
-    return true;
-  }
-
-  // enum-specifier:
-  case tok::kw_enum:
-    ConsumeToken();
-    ParseEnumSpecifier(Loc, DS, TemplateInfo, AS_none);
-    return true;
-
-  // cv-qualifier:
-  case tok::kw_const:
-    isInvalid = DS.SetTypeQual(DeclSpec::TQ_const   , Loc, PrevSpec,
-                               DiagID, getLangOpts());
-    break;
-  case tok::kw_volatile:
-    isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec,
-                               DiagID, getLangOpts());
-    break;
-  case tok::kw_restrict:
-    isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec,
-                               DiagID, getLangOpts());
-    break;
-
-  // GNU typeof support.
-  case tok::kw_typeof:
-    ParseTypeofSpecifier(DS);
-    return true;
-
-  // C++0x decltype support.
-  case tok::annot_decltype:
-    ParseDecltypeSpecifier(DS);
-    return true;
-
-  // C++0x type traits support.
-  case tok::kw___underlying_type:
-    ParseUnderlyingTypeSpecifier(DS);
-    return true;
-
-  case tok::kw__Atomic:
-    ParseAtomicSpecifier(DS);
-    return true;
-
-  // OpenCL qualifiers:
-  case tok::kw_private: 
-    if (!getLangOpts().OpenCL)
-      return false;
-  case tok::kw___private:
-  case tok::kw___global:
-  case tok::kw___local:
-  case tok::kw___constant:
-  case tok::kw___read_only:
-  case tok::kw___write_only:
-  case tok::kw___read_write:
-    ParseOpenCLQualifiers(DS);
-    break;
-
-  // C++0x auto support.
-  case tok::kw_auto:
-    // This is only called in situations where a storage-class specifier is
-    // illegal, so we can assume an auto type specifier was intended even in
-    // C++98. In C++98 mode, DeclSpec::Finish will produce an appropriate
-    // extension diagnostic.
-    if (!getLangOpts().CPlusPlus)
-      return false;
-
-    isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID);
-    break;
-
-  case tok::kw___ptr64:
-  case tok::kw___ptr32:
-  case tok::kw___w64:
-  case tok::kw___cdecl:
-  case tok::kw___stdcall:
-  case tok::kw___fastcall:
-  case tok::kw___thiscall:
-  case tok::kw___unaligned:
-    ParseMicrosoftTypeAttributes(DS.getAttributes());
-    return true;
-
-  case tok::kw___pascal:
-    ParseBorlandTypeAttributes(DS.getAttributes());
-    return true;
-
-  default:
-    // Not a type-specifier; do nothing.
-    return false;
-  }
-
-  // If the specifier combination wasn't legal, issue a diagnostic.
-  if (isInvalid) {
-    assert(PrevSpec && "Method did not return previous specifier!");
-    // Pick between error or extwarn.
-    Diag(Tok, DiagID) << PrevSpec;
-  }
-  DS.SetRangeEnd(Tok.getLocation());
-  ConsumeToken(); // whatever we parsed above.
-  return true;
-}
-
 /// ParseStructDeclaration - Parse a struct declaration without the terminating
 /// semicolon.
 ///
@@ -2905,7 +2627,7 @@
 ///
 void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
                                 const ParsedTemplateInfo &TemplateInfo,
-                                AccessSpecifier AS) {
+                                AccessSpecifier AS, DeclSpecContext DSC) {
   // Parse the tag portion of this.
   if (Tok.is(tok::code_completion)) {
     // Code completion for an enum name.
@@ -3065,7 +2787,7 @@
     TUK = Sema::TUK_Friend;
   else if (Tok.is(tok::l_brace))
     TUK = Sema::TUK_Definition;
-  else if (Tok.is(tok::semi))
+  else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)
     TUK = Sema::TUK_Declaration;
   else
     TUK = Sema::TUK_Reference;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 5b68c7a..391db19 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -903,7 +903,7 @@
 /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or
 /// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which
 /// until we reach the start of a definition or see a token that
-/// cannot start a definition. If SuppressDeclarations is true, we do know.
+/// cannot start a definition.
 ///
 ///       class-specifier: [C++ class]
 ///         class-head '{' member-specification[opt] '}'
@@ -944,8 +944,7 @@
                                  SourceLocation StartLoc, DeclSpec &DS,
                                  const ParsedTemplateInfo &TemplateInfo,
                                  AccessSpecifier AS, 
-                                 bool EnteringContext,
-                                 bool SuppressDeclarations){
+                                 bool EnteringContext, DeclSpecContext DSC) {
   DeclSpec::TST TagType;
   if (TagTokKind == tok::kw_struct)
     TagType = DeclSpec::TST_struct;
@@ -1120,18 +1119,17 @@
   // have to be treated differently.  If we have 'struct foo {...',
   // 'struct foo :...' or 'struct foo final[opt]' then this is a
   // definition. Otherwise we have something like 'struct foo xyz', a reference.
-  // However, in some contexts, things look like declarations but are just
-  // references, e.g.
-  // new struct s;
+  // However, in type-specifier-seq's, things look like declarations but are
+  // just references, e.g.
+  //   new struct s;
   // or
-  // &T::operator struct s;
-  // For these, SuppressDeclarations is true.
+  //   &T::operator struct s;
+  // For these, DSC is DSC_type_specifier.
   Sema::TagUseKind TUK;
-  if (SuppressDeclarations)
-    TUK = Sema::TUK_Reference;
-  else if (Tok.is(tok::l_brace) || 
-           (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
-           isCXX0XFinalKeyword()) {
+  if (Tok.is(tok::l_brace) ||
+      (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
+      // FIXME: 'final' must be followed by ':' or '{' to mark a definition.
+      isCXX0XFinalKeyword()) {
     if (DS.isFriendSpecified()) {
       // C++ [class.friend]p2:
       //   A class shall not be defined in a friend declaration.
@@ -1146,7 +1144,7 @@
       // Okay, this is a class definition.
       TUK = Sema::TUK_Definition;
     }
-  } else if (Tok.is(tok::semi))
+  } else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)
     TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration;
   else
     TUK = Sema::TUK_Reference;
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 325c398..9d1038e 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -1551,22 +1551,7 @@
 ///     type-specifier type-specifier-seq[opt]
 ///
 bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
-  DS.SetRangeStart(Tok.getLocation());
-  const char *PrevSpec = 0;
-  unsigned DiagID;
-  bool isInvalid = 0;
-
-  // Parse one or more of the type specifiers.
-  if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
-      ParsedTemplateInfo(), /*SuppressDeclarations*/true)) {
-    Diag(Tok, diag::err_expected_type);
-    return true;
-  }
-
-  while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID,
-         ParsedTemplateInfo(), /*SuppressDeclarations*/true))
-  {}
-
+  ParseSpecifierQualifierList(DS, AS_none, DSC_type_specifier);
   DS.Finish(Diags, PP);
   return false;
 }
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
index 979da29..0b518bb 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -fcxx-exceptions
 
 using X = struct { // ok
 };
@@ -7,21 +7,21 @@
 
 class K {
   virtual ~K();
-  // FIXME: Diagnostic could use some work
-  operator struct S {} (); // expected-error{{'operator S' cannot be the name of a variable or data member}} \
-  // expected-error{{expected ';' at end of declaration list}}
+  operator struct S {} (); // expected-error{{'K::S' can not be defined in a type specifier}}
 };
 
+struct A {};
+
 void f() {
   int arr[3] = {1,2,3};
 
   for (struct S { S(int) {} } s : arr) { // expected-error {{types may not be defined in a for range declaration}}
   }
 
-  new struct T {}; // expected-error {{allocation of incomplete type}} expected-note {{forward declaration}}
+  new struct T {}; // expected-error {{'T' can not be defined in a type specifier}}
+  new struct A {}; // expected-error {{'A' can not be defined in a type specifier}}
 
-  // FIXME: the diagnostic here isn't very good
-  try {} catch (struct U {}); // expected-error 3{{}} expected-note 2{{}}
+  try {} catch (struct U {}) {} // expected-error {{'U' can not be defined in a type specifier}}
 
   (void)(struct V { V(int); })0; // expected-error {{'V' can not be defined in a type specifier}}
 
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
index 7993489..b06eb01 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
@@ -17,9 +17,10 @@
   using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
   using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}}
   using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
+  using H = constexpr int; // expected-error {{type name does not allow constexpr specifier}}
 
-  using H = void(int n); // ok
-  using I = void(int n) &&; // ok
+  using Y = void(int n); // ok
+  using Z = void(int n) &&; // ok
 }
 
 namespace IllegalSyntax {
@@ -123,9 +124,8 @@
 }
 
 namespace CWG1044 {
-  // FIXME: this is terrible. one error is plenty.
+  // FIXME: this diagnostic isn't ideal. one diagnostic is enough.
   using T = T; // expected-error {{type name requires a specifier}} \
-                  expected-error {{C++ requires a type specifier}} \
                   expected-error {{expected ';' after alias declaration}}
 }
 
diff --git a/test/CXX/dcl.decl/dcl.name/p1.cpp b/test/CXX/dcl.decl/dcl.name/p1.cpp
index 7586007..9838b4f 100644
--- a/test/CXX/dcl.decl/dcl.name/p1.cpp
+++ b/test/CXX/dcl.decl/dcl.name/p1.cpp
@@ -2,15 +2,19 @@
 
 namespace pr6200 {
   struct v {};
+  enum E { e };
   struct s {
     int i;
     operator struct v() { return v(); };
+    operator enum E() { return e; }
   };
 
   void f()
   {
-    // Neither of these is a declaration.
+    // None of these is a declaration.
     (void)new struct s;
+    (void)new enum E;
     (void)&s::operator struct v;
+    (void)&s::operator enum E;
   }
 }
diff --git a/test/Parser/cxx11-type-specifier.cpp b/test/Parser/cxx11-type-specifier.cpp
new file mode 100644
index 0000000..2e629f3
--- /dev/null
+++ b/test/Parser/cxx11-type-specifier.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -verify %s -std=c++11 -fcxx-exceptions
+
+// Tests for parsing of type-specifier-seq
+
+struct S {
+  operator constexpr int(); // expected-error{{type name does not allow constexpr}}
+};
+enum E { e };
+
+void f() {
+  try {
+    (void) new constexpr int; // expected-error{{type name does not allow constexpr}}
+  } catch (constexpr int) { // expected-error{{type name does not allow constexpr}}
+  }
+
+  // These parse as type definitions, not as type references with braced
+  // initializers. Sad but true...
+  (void) new struct S {}; // expected-error{{'S' can not be defined in a type specifier}}
+  (void) new enum E { e }; // expected-error{{'E' can not be defined in a type specifier}}
+}
diff --git a/test/Sema/invalid-struct-init.c b/test/Sema/invalid-struct-init.c
index a598d57..000d3ab 100644
--- a/test/Sema/invalid-struct-init.c
+++ b/test/Sema/invalid-struct-init.c
@@ -3,8 +3,6 @@
 typedef struct _zend_module_entry zend_module_entry;
 struct _zend_module_entry {
   _efree((p)); // expected-error{{type name requires a specifier or qualifier}} \
-                  expected-error{{field '_efree' declared as a function}} \
-                  expected-warning {{type specifier missing, defaults to 'int'}} \
                   expected-warning {{type specifier missing, defaults to 'int'}}
   
 };
diff --git a/test/SemaCXX/alias-template.cpp b/test/SemaCXX/alias-template.cpp
index 8911328..484dd33 100644
--- a/test/SemaCXX/alias-template.cpp
+++ b/test/SemaCXX/alias-template.cpp
@@ -14,9 +14,10 @@
   template<typename U> using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
   template<typename U> using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}}
   template<typename U> using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
+  template<typename U> using H = constexpr int; // expected-error {{type name does not allow constexpr specifier}}
 
-  template<typename U> using H = void(int n); // ok
-  template<typename U> using I = void(int n) &&; // ok
+  template<typename U> using Y = void(int n); // ok
+  template<typename U> using Z = void(int n) &&; // ok
 }
 
 namespace IllegalSyntax {
diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp
index 37025d9..287d9af 100644
--- a/test/SemaCXX/invalid-member-expr.cpp
+++ b/test/SemaCXX/invalid-member-expr.cpp
@@ -8,7 +8,7 @@
   x.int; // expected-error{{expected unqualified-id}}
   x.~int(); // expected-error{{expected a class name}}
   x.operator; // expected-error{{expected a type}}
-  x.operator typedef; // expected-error{{expected a type}}
+  x.operator typedef; // expected-error{{expected a type}} expected-error{{type name does not allow storage class}}
 }
 
 void test2() {
@@ -17,7 +17,7 @@
   x->int; // expected-error{{expected unqualified-id}}
   x->~int(); // expected-error{{expected a class name}}
   x->operator; // expected-error{{expected a type}}
-  x->operator typedef; // expected-error{{expected a type}}
+  x->operator typedef; // expected-error{{expected a type}} expected-error{{type name does not allow storage class}}
 }
 
 // PR6327
diff --git a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
index 0351db1..83f8395 100644
--- a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
+++ b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
@@ -4,7 +4,7 @@
                                       // expected-note {{'Foobar' declared here}}
 Foobar *my_bar  // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}}
     = new Foobar; // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}}
-fizbin::Foobar *my_foo = new fizbin::FooBar; // expected-error{{unknown type name 'FooBar'; did you mean 'Foobar'?}}
+fizbin::Foobar *my_foo = new fizbin::FooBar; // expected-error{{no type named 'FooBar' in namespace 'fizbin'; did you mean 'Foobar'?}}
 
 namespace barstool { int toFoobar() { return 1; } } // expected-note 3 {{'barstool::toFoobar' declared here}}
 int Double(int x) { return x + x; }
@@ -64,14 +64,13 @@
 
 // Test case from http://llvm.org/bugs/show_bug.cgi?id=10318
 namespace llvm {
- template <typename T> class GraphWriter {}; // expected-note {{'llvm::GraphWriter' declared here}} \
-                                             // expected-note {{'GraphWriter' declared here}}
+ template <typename T> class GraphWriter {}; // expected-note 3{{declared here}}
 }
 
 struct S {};
 void bar() {
  GraphWriter<S> x; //expected-error{{no template named 'GraphWriter'; did you mean 'llvm::GraphWriter'?}}
- (void)new llvm::GraphWriter; // expected-error {{expected a type}}
+ (void)new llvm::GraphWriter; // expected-error {{use of class template llvm::GraphWriter requires template arguments}}
  (void)new llvm::Graphwriter<S>; // expected-error {{no template named 'Graphwriter' in namespace 'llvm'; did you mean 'GraphWriter'?}}
 }
 
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index 579ec33..88d85ca 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -387,7 +387,7 @@
 
 namespace PR7702 {
   void test1() {
-    new DoesNotExist; // expected-error {{expected a type}}
+    new DoesNotExist; // expected-error {{unknown type name 'DoesNotExist'}}
   }
 }
 
diff --git a/test/SemaObjC/property-9.m b/test/SemaObjC/property-9.m
index 60c8fd1..a7668da 100644
--- a/test/SemaObjC/property-9.m
+++ b/test/SemaObjC/property-9.m
@@ -44,8 +44,7 @@
 }
 
 @property (readonly) int; // expected-warning {{declaration does not declare anything}}
-@property (readonly) ; // expected-error {{type name requires a specifier or qualifier}} \
-                          expected-warning {{declaration does not declare anything}}
+@property (readonly) ; // expected-error {{type name requires a specifier or qualifier}}
 @property (readonly) int : 4; // expected-error {{property requires fields to be named}}
 
 
diff --git a/test/SemaTemplate/deduction-crash.cpp b/test/SemaTemplate/deduction-crash.cpp
index fb23eda..cf3899f 100644
--- a/test/SemaTemplate/deduction-crash.cpp
+++ b/test/SemaTemplate/deduction-crash.cpp
@@ -2,7 +2,7 @@
 
 // Note that the error count below doesn't matter. We just want to
 // make sure that the parser doesn't crash.
-// CHECK: 14 errors
+// CHECK: 13 errors
 
 // PR7511
 template<a>