]> granicus.if.org Git - clang/commitdiff
Fix parsing of type-specifier-seq's. Types are syntactically allowed to be
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 12 Mar 2012 07:56:15 +0000 (07:56 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 12 Mar 2012 07:56:15 +0000 (07:56 +0000)
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

17 files changed:
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Parse/Parser.h
include/clang/Sema/DeclSpec.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseExprCXX.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
test/CXX/dcl.decl/dcl.name/p1.cpp
test/Parser/cxx11-type-specifier.cpp [new file with mode: 0644]
test/Sema/invalid-struct-init.c
test/SemaCXX/alias-template.cpp
test/SemaCXX/invalid-member-expr.cpp
test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
test/SemaCXX/new-delete.cpp
test/SemaObjC/property-9.m
test/SemaTemplate/deduction-crash.cpp

index c5cab868c79acd843559764973124257d77b931c..95522189e190a6121c0dfdf125150a14127dc4c6 100644 (file)
@@ -280,9 +280,11 @@ def err_typename_invalid_storageclass : Error<
   "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<
index 2124f1ebe28e0682b570156abc5e2b793ba2c9df..0496057886adc58bcc3fe44569331c39f2bd5be4 100644 (file)
@@ -1621,6 +1621,7 @@ private:
   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 @@ private:
 
   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 @@ private:
   //===--------------------------------------------------------------------===//
   // 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,
index e86b4852d667d8946d7ea4dd2fecc5099dce4a5c..425335e95ebe5194ff121f25b72e8b75a1512e2e 100644 (file)
@@ -614,6 +614,11 @@ public:
   bool isConstexprSpecified() const { return Constexpr_specified; }
   SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }
 
+  void ClearConstexprSpec() {
+    Constexpr_specified = false;
+    ConstexprLoc = SourceLocation();
+  }
+
   AttributePool &getAttributePool() const {
     return Attrs.getPool();
   }
index 12866b91272bb86739f168553fd53174736dc6ce..c1f6eb5d42393a6f6c9301baec4077909dfcc74c 100644 (file)
@@ -1424,17 +1424,24 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
 ///          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 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS) {
       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 @@ static bool isValidAfterIdentifierInDeclarator(const Token &T) {
 ///
 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 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
   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 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
 
       // 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 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
   }
 
   // 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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
       // 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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
       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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
       // 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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
     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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
   }
 }
 
-/// 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::ParseStructUnionBody(SourceLocation RecordLoc,
 ///
 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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
     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;
index 5b68c7a78453792b4389556fbdeaaa3a549dd585..391db1987a14676cc756c4d32448658da8f22f56 100644 (file)
@@ -903,7 +903,7 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
 /// 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
                                  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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
   // 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
       // 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;
index 325c398f343b5d77e6ce490e3eff8b16332bf7ac..9d1038e241278e1b618199c40c6f056013897805 100644 (file)
@@ -1551,22 +1551,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
 ///     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;
 }
index 979da29e1b5728ee5542d7efa12baa479e603eb3..0b518bb08573e4eac7732b5048f486023078abc6 100644 (file)
@@ -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 @@ template<typename T> using Y = struct { // expected-error {{can not be defined i
 
 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}}
 
index 7993489fafd90fe41d9824e4b6fa721e30dc769d..b06eb01a7fb5cbf44bd69a148350be6cd6fd5f28 100644 (file)
@@ -17,9 +17,10 @@ namespace IllegalTypeIds {
   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 TagName {
 }
 
 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}}
 }
 
index 7586007cc7b3892706f50bc8f15d3001fb82088d..9838b4f4737dbd1da203f771734fbf9d176b9327 100644 (file)
@@ -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 (file)
index 0000000..2e629f3
--- /dev/null
@@ -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}}
+}
index a598d577f006da1742b0e4f73429121a63e69ae7..000d3ab59dc55bc11b4d014f2c17784ce1ee068d 100644 (file)
@@ -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'}}
   
 };
index 8911328b4cd496feb756855510f77675b13d3458..484dd3379ed706d744919dc729bdec5a6d6ff96e 100644 (file)
@@ -14,9 +14,10 @@ namespace IllegalTypeIds {
   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 {
index 37025d93344a7f61d55286657aabb97383488cbe..287d9af13094118ed993d32787078b2e77bf02fa 100644 (file)
@@ -8,7 +8,7 @@ void test() {
   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 @@ void test2() {
   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
index 0351db18553a34edf9fbc31b82042b02f7b1bba7..83f83951395cb95111e107eb94aa9d46d1f8b308 100644 (file)
@@ -4,7 +4,7 @@ namespace fizbin { class Foobar {}; } // expected-note 2 {{'fizbin::Foobar' decl
                                       // 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 @@ void f() {
 
 // 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'?}}
 }
 
index 579ec33a43e8898454fb2d29e3a3b81d76b40209..88d85ca792edc959c5e501ad73e89c23338b7272 100644 (file)
@@ -387,7 +387,7 @@ namespace PairedDelete {
 
 namespace PR7702 {
   void test1() {
-    new DoesNotExist; // expected-error {{expected a type}}
+    new DoesNotExist; // expected-error {{unknown type name 'DoesNotExist'}}
   }
 }
 
index 60c8fd19ddd92cbcd8f90ab0900837e143258505..a7668da04095892c52ec015afd460bd76864b742 100644 (file)
@@ -44,8 +44,7 @@ typedef signed char BOOL;
 }
 
 @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}}
 
 
index fb23eda5bb9dad62d13b43b5c0a8466d1e486db8..cf3899f5eda78d1bd00052c58424e095b07a537d 100644 (file)
@@ -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>