diff options
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 4 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 23 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 5 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 350 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 26 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 17 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp | 14 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp | 8 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.name/p1.cpp | 6 | ||||
-rw-r--r-- | test/Parser/cxx11-type-specifier.cpp | 20 | ||||
-rw-r--r-- | test/Sema/invalid-struct-init.c | 2 | ||||
-rw-r--r-- | test/SemaCXX/alias-template.cpp | 5 | ||||
-rw-r--r-- | test/SemaCXX/invalid-member-expr.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp | 7 | ||||
-rw-r--r-- | test/SemaCXX/new-delete.cpp | 2 | ||||
-rw-r--r-- | test/SemaObjC/property-9.m | 3 | ||||
-rw-r--r-- | test/SemaTemplate/deduction-crash.cpp | 2 |
17 files changed, 113 insertions, 385 deletions
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index c5cab868c7..95522189e1 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -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< diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 2124f1ebe2..0496057886 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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, diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index e86b4852d6..425335e95e 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -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(); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 12866b9127..c1f6eb5d42 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 5b68c7a784..391db1987a 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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; diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 325c398f34..9d1038e241 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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; } 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 979da29e1b..0b518bb085 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 @@ 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}} 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 7993489faf..b06eb01a7f 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 @@ 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}} } diff --git a/test/CXX/dcl.decl/dcl.name/p1.cpp b/test/CXX/dcl.decl/dcl.name/p1.cpp index 7586007cc7..9838b4f473 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 0000000000..2e629f3ab5 --- /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 a598d577f0..000d3ab59d 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 8911328b4c..484dd3379e 100644 --- a/test/SemaCXX/alias-template.cpp +++ b/test/SemaCXX/alias-template.cpp @@ -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 { diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp index 37025d9334..287d9af130 100644 --- a/test/SemaCXX/invalid-member-expr.cpp +++ b/test/SemaCXX/invalid-member-expr.cpp @@ -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 diff --git a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp index 0351db1855..83f8395139 100644 --- a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp +++ b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp @@ -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'?}} } diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index 579ec33a43..88d85ca792 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -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'}} } } diff --git a/test/SemaObjC/property-9.m b/test/SemaObjC/property-9.m index 60c8fd19dd..a7668da040 100644 --- a/test/SemaObjC/property-9.m +++ b/test/SemaObjC/property-9.m @@ -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}} diff --git a/test/SemaTemplate/deduction-crash.cpp b/test/SemaTemplate/deduction-crash.cpp index fb23eda5bb..cf3899f5ed 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> |