diff options
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 17 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 3 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 3 | ||||
-rw-r--r-- | clang/test/SemaCXX/conversion-function.cpp | 11 |
8 files changed, 63 insertions, 17 deletions
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 42a0ad67e4a..e1609c39997 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1646,9 +1646,26 @@ private: DSC_class, // class context, enables 'friend' DSC_type_specifier, // C++ type-specifier-seq or C specifier-qualifier-list DSC_trailing, // C++11 trailing-type-specifier in a trailing return type + DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration DSC_top_level // top-level/namespace declaration context }; + /// Is this a context in which we are parsing just a type-specifier (or + /// trailing-type-specifier)? + static bool isTypeSpecifier(DeclSpecContext DSC) { + switch (DSC) { + case DSC_normal: + case DSC_class: + case DSC_top_level: + return false; + + case DSC_type_specifier: + case DSC_trailing: + case DSC_alias_declaration: + return true; + } + } + /// Information on a C++0x for-range-initializer found while parsing a /// declaration which turns out to be a for-range-declaration. struct ForRangeInit { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ed5fb47b051..2a900f36e3e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1668,7 +1668,8 @@ public: MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, - bool ScopedEnumUsesClassTag, TypeResult UnderlyingType); + bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, + bool IsTypeSpecifier); Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 277355cd40d..27df0c0795d 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2056,8 +2056,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, // Validate declspec for type-name. unsigned Specs = DS.getParsedSpecifiers(); - if ((DSC == DSC_type_specifier || DSC == DSC_trailing) && - !DS.hasTypeSpecifier()) { + if (isTypeSpecifier(DSC) && !DS.hasTypeSpecifier()) { Diag(Tok, diag::err_expected_type); DS.SetTypeSpecError(); } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() && @@ -2155,8 +2154,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // within a type specifier. Outside of C++, we allow this even if the // language doesn't "officially" support implicit int -- we support // implicit int as an extension in C99 and C11. - if (DSC != DSC_type_specifier && DSC != DSC_trailing && - !getLangOpts().CPlusPlus && + if (!isTypeSpecifier(DSC) && !getLangOpts().CPlusPlus && 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 @@ -2226,7 +2224,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // Determine whether this identifier could plausibly be the name of something // being declared (with a missing type). - if (DSC != DSC_type_specifier && DSC != DSC_trailing && + if (!isTypeSpecifier(DSC) && (!SS || DSC == DSC_top_level || DSC == DSC_class)) { // Look ahead to the next token to try to figure out what this declaration // was supposed to be. @@ -2339,6 +2337,9 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { return DSC_top_level; if (Context == Declarator::TrailingReturnContext) return DSC_trailing; + if (Context == Declarator::AliasDeclContext || + Context == Declarator::AliasTemplateContext) + return DSC_alias_declaration; return DSC_normal; } @@ -3751,7 +3752,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } else { TUK = Sema::TUK_Definition; } - } else if (DSC != DSC_type_specifier && + } else if (!isTypeSpecifier(DSC) && (Tok.is(tok::semi) || (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(CanBeBitfield)))) { @@ -3813,7 +3814,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, StartLoc, SS, Name, NameLoc, attrs.getList(), AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, ScopedEnumKWLoc, - IsScopedUsingClassTag, BaseType); + IsScopedUsingClassTag, BaseType, + DSC == DSC_type_specifier); if (IsDependent) { // This enum has a dependent nested-name-specifier. Handle it as a diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 295ade33572..1fbc0adeb93 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1308,7 +1308,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // new struct s; // or // &T::operator struct s; - // For these, DSC is DSC_type_specifier. + // For these, DSC is DSC_type_specifier or DSC_alias_declaration. // If there are attributes after class name, parse them. MaybeParseCXX11Attributes(Attributes); @@ -1365,7 +1365,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TUK = Sema::TUK_Reference; PA.Revert(); - } else if (DSC != DSC_type_specifier && + } else if (!isTypeSpecifier(DSC) && (Tok.is(tok::semi) || (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) { TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; @@ -1581,7 +1581,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, SourceLocation(), false, - clang::TypeResult()); + clang::TypeResult(), + DSC == DSC_type_specifier); // If ActOnTag said the type was dependent, try again with the // less common call. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 07a551da2f1..7cdf81a87e4 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10396,6 +10396,9 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. +/// +/// IsTypeSpecifier is true if this is a type-specifier (or +/// trailing-type-specifier) other than one in an alias-declaration. Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, @@ -10405,7 +10408,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, - TypeResult UnderlyingType) { + TypeResult UnderlyingType, + bool IsTypeSpecifier) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; assert((Name != 0 || TUK == TUK_Definition) && @@ -11016,6 +11020,14 @@ CreateNewDecl: cast_or_null<RecordDecl>(PrevDecl)); } + // C++11 [dcl.type]p3: + // A type-specifier-seq shall not define a class or enumeration [...]. + if (getLangOpts().CPlusPlus && IsTypeSpecifier && TUK == TUK_Definition) { + Diag(New->getLocation(), diag::err_type_defined_in_type_specifier) + << Context.getTagDeclType(New); + Invalid = true; + } + // Maybe add qualifier info. if (SS.isNotEmpty()) { if (SS.isSet()) { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 91b9c6a5880..28f038a69e3 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11460,14 +11460,15 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, bool Owned = false; bool IsDependent = false; return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, - Attr, AS_public, + Attr, AS_public, /*ModulePrivateLoc=*/SourceLocation(), - MultiTemplateParamsArg(), Owned, IsDependent, + MultiTemplateParamsArg(), Owned, IsDependent, /*ScopedEnumKWLoc=*/SourceLocation(), /*ScopedEnumUsesClassTag=*/false, - /*UnderlyingType=*/TypeResult()); + /*UnderlyingType=*/TypeResult(), + /*IsTypeSpecifier=*/false); } - + NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); ElaboratedTypeKeyword Keyword = TypeWithKeyword::getKeywordForTagTypeKind(Kind); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 4f050345bc8..b468e31f097 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -7101,7 +7101,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, KWLoc, SS, Name, NameLoc, Attr, AS_none, /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(), Owned, IsDependent, - SourceLocation(), false, TypeResult()); + SourceLocation(), false, TypeResult(), + /*IsTypeSpecifier*/false); assert(!IsDependent && "explicit instantiation of dependent name not yet handled"); if (!TagD) diff --git a/clang/test/SemaCXX/conversion-function.cpp b/clang/test/SemaCXX/conversion-function.cpp index 7eaed54934b..0a35ea4ff59 100644 --- a/clang/test/SemaCXX/conversion-function.cpp +++ b/clang/test/SemaCXX/conversion-function.cpp @@ -405,3 +405,14 @@ namespace PR12712 { A f(const C c) { return c; } } + +namespace PR18234 { + struct A { + operator enum E { e } (); // expected-error {{'PR18234::A::E' can not be defined in a type specifier}} + operator struct S { int n; } (); // expected-error {{'PR18234::A::S' can not be defined in a type specifier}} + } a; + A::S s = a; + A::E e = a; // expected-note {{here}} + bool k1 = e == A::e; // expected-error {{no member named 'e'}} + bool k2 = e.n == 0; +} |