From 1af83c444e5a2f6f50a6e1c15e6ebc618ae18a5f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 23 Mar 2012 03:33:32 +0000 Subject: [PATCH] Support for definitions of member enumerations of class templates outside the class template's definition, and for explicit specializations of such enum members. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153304 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 10 ++ include/clang/Basic/DiagnosticParseKinds.td | 2 + include/clang/Basic/DiagnosticSemaKinds.td | 31 ++-- include/clang/Sema/Sema.h | 20 +++ lib/AST/Decl.cpp | 18 +++ lib/Parse/ParseDecl.cpp | 71 +++++--- lib/Parse/ParseDeclCXX.cpp | 15 +- lib/Sema/SemaCXXScopeSpec.cpp | 12 +- lib/Sema/SemaDecl.cpp | 17 +- lib/Sema/SemaLookup.cpp | 3 +- lib/Sema/SemaTemplate.cpp | 34 +++- lib/Sema/SemaTemplateInstantiate.cpp | 15 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 +- .../temp.class/temp.mem.enum/p1.cpp | 152 ++++++++++++++++++ .../temp/temp.spec/temp.explicit/p1-0x.cpp | 9 ++ 15 files changed, 344 insertions(+), 70 deletions(-) create mode 100644 test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 81973a29c3..11696db279 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2862,6 +2862,16 @@ public: /// this enumeration was not instantiated from any template. EnumDecl *getInstantiatedFromMemberEnum() const; + /// \brief If this enumeration is a member of a specialization of a + /// templated class, determine what kind of template specialization + /// or instantiation this is. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// \brief For an enumeration member that was instantiated from a member + /// enumeration of a templated class, set the template specialiation kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + /// \brief If this enumeration is an instantiation of a member enumeration of /// a class template specialization, retrieves the member specialization /// information. diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 1f03a0777c..c585f87c73 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -500,6 +500,8 @@ def err_explicit_instantiation_with_definition : Error< "definition is meant to be an explicit specialization, add '<>' after the " "'template' keyword">; def err_enum_template : Error<"enumeration cannot be a template">; +def err_explicit_instantiation_enum : Error< + "enumerations cannot be explicitly instantiated">; def err_missing_dependent_template_keyword : Error< "use 'template' keyword to treat '%0' as a dependent template name">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2ce1e895dc..36232b1e98 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2376,7 +2376,8 @@ def err_pointer_to_member_oper_value_classify: Error< // C++ template specialization def err_template_spec_unknown_kind : Error< "can only provide an explicit specialization for a class template, function " - "template, or a member function, static data member, or member class of a " + "template, or a member function, static data member, " + "%select{or member class|member class, or member enumeration}0 of a " "class template">; def note_specialized_entity : Note< "explicitly specialized declaration is here">; @@ -2388,30 +2389,30 @@ def err_template_spec_decl_friend : Error< "cannot declare an explicit specialization in a friend">; def err_template_spec_decl_out_of_scope_global : Error< "%select{class template|class template partial|function template|member " - "function|static data member|member class}0 specialization of %1 must " - "originally be declared in the global scope">; + "function|static data member|member class|member enumeration}0 " + "specialization of %1 must originally be declared in the global scope">; def err_template_spec_decl_out_of_scope : Error< "%select{class template|class template partial|function template|member " - "function|static data member|member class}0 specialization of %1 must " - "originally be declared in namespace %2">; + "function|static data member|member class|member enumeration}0 " + "specialization of %1 must originally be declared in namespace %2">; def ext_template_spec_decl_out_of_scope : ExtWarn< "first declaration of %select{class template|class template partial|" - "function template|member function|static data member|member class}0 " - "specialization of %1 outside namespace %2 is a C++11 extension">, - InGroup; + "function template|member function|static data member|member class|" + "member enumeration}0 specialization of %1 outside namespace %2 is a " + "C++11 extension">, InGroup; def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning< "%select{class template|class template partial|function template|member " - "function|static data member|member class}0 specialization of %1 outside " - "namespace %2 is incompatible with C++98">, + "function|static data member|member class|member enumeration}0 " + "specialization of %1 outside namespace %2 is incompatible with C++98">, InGroup, DefaultIgnore; def err_template_spec_redecl_out_of_scope : Error< "%select{class template|class template partial|function template|member " - "function|static data member|member class}0 specialization of %1 not in a " - "namespace enclosing %2">; + "function|static data member|member class|member enumeration}0 " + "specialization of %1 not in a namespace enclosing %2">; def err_template_spec_redecl_global_scope : Error< "%select{class template|class template partial|function template|member " - "function|static data member|member class}0 specialization of %1 must occur " - "at global scope">; + "function|static data member|member class|member enumeration}0 " + "specialization of %1 must occur at global scope">; def err_spec_member_not_instantiated : Error< "specialization of member %q0 does not specialize an instantiated member">; def note_specialized_decl : Note<"attempt to specialize declaration here">; @@ -2579,8 +2580,6 @@ def warn_cxx98_compat_explicit_instantiation_after_specialization : Warning< InGroup, DefaultIgnore; def note_previous_template_specialization : Note< "previous template specialization is here">; -def err_explicit_instantiation_enum : Error< - "explicit instantiation of enumeration type %0">; def err_explicit_instantiation_nontemplate_type : Error< "explicit instantiation of non-templated type %0">; def note_nontemplate_decl_here : Note< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 70c40e150d..85ded4f06c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4132,6 +4132,26 @@ public: /// failures rather than hard errors. bool AccessCheckingSFINAE; + /// \brief RAII object used to temporarily suppress access checking. + class SuppressAccessChecksRAII { + Sema &S; + bool SuppressingAccess; + + public: + SuppressAccessChecksRAII(Sema &S, bool Suppress) + : S(S), SuppressingAccess(Suppress) { + if (Suppress) S.ActOnStartSuppressingAccessChecks(); + } + ~SuppressAccessChecksRAII() { + done(); + } + void done() { + if (!SuppressingAccess) return; + S.ActOnStopSuppressingAccessChecks(); + SuppressingAccess = false; + } + }; + void ActOnStartSuppressingAccessChecks(); void ActOnStopSuppressingAccessChecks(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 34ec7a879b..3b7113d354 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2674,6 +2674,24 @@ void EnumDecl::completeDefinition(QualType NewType, TagDecl::completeDefinition(); } +TemplateSpecializationKind EnumDecl::getTemplateSpecializationKind() const { + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) + return MSI->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +void EnumDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation) { + MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); + assert(MSI && "Not an instantiated member enumeration?"); + MSI->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + MSI->getPointOfInstantiation().isInvalid()) + MSI->setPointOfInstantiation(PointOfInstantiation); +} + EnumDecl *EnumDecl::getInstantiatedFromMemberEnum() const { if (SpecializationInfo) return cast(SpecializationInfo->getInstantiatedFrom()); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 6f344f6691..24386d08ba 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2611,19 +2611,20 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, /// 'enum' identifier /// [GNU] 'enum' attributes[opt] identifier /// -/// [C++0x] enum-head '{' enumerator-list[opt] '}' -/// [C++0x] enum-head '{' enumerator-list ',' '}' +/// [C++11] enum-head '{' enumerator-list[opt] '}' +/// [C++11] enum-head '{' enumerator-list ',' '}' /// -/// enum-head: [C++0x] -/// enum-key attributes[opt] identifier[opt] enum-base[opt] -/// enum-key attributes[opt] nested-name-specifier identifier enum-base[opt] +/// enum-head: [C++11] +/// enum-key attribute-specifier-seq[opt] identifier[opt] enum-base[opt] +/// enum-key attribute-specifier-seq[opt] nested-name-specifier +/// identifier enum-base[opt] /// -/// enum-key: [C++0x] +/// enum-key: [C++11] /// 'enum' /// 'enum' 'class' /// 'enum' 'struct' /// -/// enum-base: [C++0x] +/// enum-base: [C++11] /// ':' type-specifier-seq /// /// [C++] elaborated-type-specifier: @@ -2648,7 +2649,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, IsScopedUsingClassTag = Tok.is(tok::kw_class); ScopedEnumKWLoc = ConsumeToken(); } - + + // C++11 [temp.explicit]p12: The usual access controls do not apply to names + // used to specify explicit instantiations. We extend this to also cover + // explicit specializations. + Sema::SuppressAccessChecksRAII SuppressAccess(Actions, + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + // If attributes exist after tag, parse them. ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); @@ -2711,6 +2719,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, IsScopedUsingClassTag = false; } + // Stop suppressing access control now we've parsed the enum name. + SuppressAccess.done(); + TypeResult BaseType; // Parse the fixed underlying type. @@ -2801,34 +2812,44 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, TUK = Sema::TUK_Declaration; else TUK = Sema::TUK_Reference; - - // enums cannot be templates, although they can be referenced from a - // template. + + MultiTemplateParamsArg TParams; if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && TUK != Sema::TUK_Reference) { - Diag(Tok, diag::err_enum_template); - - // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); - return; + if (!getLangOpts().CPlusPlus0x || !SS.isSet()) { + // Skip the rest of this declarator, up until the comma or semicolon. + Diag(Tok, diag::err_enum_template); + SkipUntil(tok::comma, true); + return; + } + + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { + // Enumerations can't be explicitly instantiated. + DS.SetTypeSpecError(); + Diag(StartLoc, diag::err_explicit_instantiation_enum); + return; + } + + assert(TemplateInfo.TemplateParams && "no template parameters"); + TParams = MultiTemplateParamsArg(TemplateInfo.TemplateParams->data(), + TemplateInfo.TemplateParams->size()); } - + if (!Name && TUK != Sema::TUK_Definition) { Diag(Tok, diag::err_enumerator_unnamed_no_def); - + // Skip the rest of this declarator, up until the comma or semicolon. SkipUntil(tok::comma, true); return; } - + bool Owned = false; bool IsDependent = false; const char *PrevSpec = 0; unsigned DiagID; Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, attrs.getList(), - AS, DS.getModulePrivateSpecLoc(), - MultiTemplateParamsArg(Actions), + AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, ScopedEnumKWLoc, IsScopedUsingClassTag, BaseType); @@ -2870,10 +2891,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { - if (TUK == Sema::TUK_Friend) + if (TUK == Sema::TUK_Friend) { Diag(Tok, diag::err_friend_decl_defines_type) << SourceRange(DS.getFriendSpecLoc()); - ParseEnumBody(StartLoc, TagDecl); + ConsumeBrace(); + SkipUntil(tok::r_brace); + } else { + ParseEnumBody(StartLoc, TagDecl); + } } if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index cf18a5b629..9321c137fb 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -968,12 +968,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // As an extension we do not perform access checking on the names used to // specify explicit specializations either. This is important to allow // specializing traits classes for private types. - bool SuppressingAccessChecks = false; - if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) { - Actions.ActOnStartSuppressingAccessChecks(); - SuppressingAccessChecks = true; - } + Sema::SuppressAccessChecksRAII SuppressAccess(Actions, + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); ParsedAttributes attrs(AttrFactory); // If attributes exist after tag, parse them. @@ -1102,17 +1099,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, DS.SetTypeSpecError(); SkipUntil(tok::semi, false, true); - if (SuppressingAccessChecks) - Actions.ActOnStopSuppressingAccessChecks(); - return; } } // As soon as we're finished parsing the class's template-id, turn access // checking back on. - if (SuppressingAccessChecks) - Actions.ActOnStopSuppressingAccessChecks(); + SuppressAccess.done(); // There are four options here. // - If we are in a trailing return type, this is always just a reference, diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 5e6c27b15d..5a0fceca20 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -246,10 +246,14 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, EnumDecl *ED = enumType->getDecl(); if (EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) { MemberSpecializationInfo *MSI = ED->getMemberSpecializationInfo(); - if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) - return InstantiateEnum(loc, ED, Pattern, - getTemplateInstantiationArgs(ED), - TSK_ImplicitInstantiation); + if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) { + if (InstantiateEnum(loc, ED, Pattern, getTemplateInstantiationArgs(ED), + TSK_ImplicitInstantiation)) { + SS.SetInvalid(SS.getRange()); + return true; + } + return false; + } } Diag(loc, diag::err_incomplete_nested_name_spec) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 15cd745d07..71f567f47a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -8283,10 +8283,19 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // If we're defining a specialization and the previous definition // is from an implicit instantiation, don't emit an error // here; we'll catch this in the general case below. - if (!isExplicitSpecialization || - !isa(Def) || - cast(Def)->getTemplateSpecializationKind() - == TSK_ExplicitSpecialization) { + bool IsExplicitSpecializationAfterInstantiation = false; + if (isExplicitSpecialization) { + if (CXXRecordDecl *RD = dyn_cast(Def)) + IsExplicitSpecializationAfterInstantiation = + RD->getTemplateSpecializationKind() != + TSK_ExplicitSpecialization; + else if (EnumDecl *ED = dyn_cast(Def)) + IsExplicitSpecializationAfterInstantiation = + ED->getTemplateSpecializationKind() != + TSK_ExplicitSpecialization; + } + + if (!IsExplicitSpecializationAfterInstantiation) { // A redeclaration in function prototype scope in C isn't // visible elsewhere, so merely issue a warning. if (!getLangOpts().CPlusPlus && S->containedInPrototypeScope()) diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 0382a83548..e47bc1c8b1 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1413,8 +1413,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, assert((!isa(LookupCtx) || LookupCtx->isDependentContext() || cast(LookupCtx)->isCompleteDefinition() || - Context.getTypeDeclType(cast(LookupCtx))->getAs() - ->isBeingDefined()) && + cast(LookupCtx)->isBeingDefined()) && "Declaration context must already be complete!"); // Perform qualified name lookup into the LookupCtx. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 680e6eaf2e..3a4a6f5312 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4699,8 +4699,11 @@ static bool CheckTemplateSpecializationScope(Sema &S, EntityKind = 4; else if (isa(Specialized)) EntityKind = 5; + else if (isa(Specialized) && S.getLangOpts().CPlusPlus0x) + EntityKind = 6; else { - S.Diag(Loc, diag::err_template_spec_unknown_kind); + S.Diag(Loc, diag::err_template_spec_unknown_kind) + << S.getLangOpts().CPlusPlus0x; S.Diag(Specialized->getLocation(), diag::note_specialized_entity); return true; } @@ -5816,6 +5819,14 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass(); MSInfo = PrevRecord->getMemberSpecializationInfo(); } + } else if (isa(Member)) { + EnumDecl *PrevEnum; + if (Previous.isSingleResult() && + (PrevEnum = dyn_cast(Previous.getFoundDecl()))) { + Instantiation = PrevEnum; + InstantiatedFrom = PrevEnum->getInstantiatedFromMemberEnum(); + MSInfo = PrevEnum->getMemberSpecializationInfo(); + } } if (!Instantiation) { @@ -5906,8 +5917,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { cast(InstantiatedFrom), TSK_ExplicitSpecialization); MarkUnusedFileScopedDecl(InstantiationVar); - } else { - assert(isa(Member) && "Only member classes remain"); + } else if (isa(Member)) { CXXRecordDecl *InstantiationClass = cast(Instantiation); if (InstantiationClass->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) { @@ -5919,6 +5929,18 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { cast(Member)->setInstantiationOfMemberClass( cast(InstantiatedFrom), TSK_ExplicitSpecialization); + } else { + assert(isa(Member) && "Only member enums remain"); + EnumDecl *InstantiationEnum = cast(Instantiation); + if (InstantiationEnum->getTemplateSpecializationKind() == + TSK_ImplicitInstantiation) { + InstantiationEnum->setTemplateSpecializationKind( + TSK_ExplicitSpecialization); + InstantiationEnum->setLocation(Member->getLocation()); + } + + cast(Member)->setInstantiationOfMemberEnum( + cast(InstantiatedFrom), TSK_ExplicitSpecialization); } // Save the caller the trouble of having to figure out which declaration @@ -6219,11 +6241,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, return true; TagDecl *Tag = cast(TagD); - if (Tag->isEnum()) { - Diag(TemplateLoc, diag::err_explicit_instantiation_enum) - << Context.getTypeDeclType(Tag); - return true; - } + assert(!Tag->isEnum() && "shouldn't see enumerations here"); if (Tag->isInvalidDecl()) return true; diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index c2ebbf4b55..afa65ea9ee 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1843,7 +1843,20 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (OldField->getInClassInitializer()) FieldsWithMemberInitializers.push_back(std::make_pair(OldField, Field)); - } else if (NewMember->isInvalidDecl()) + } else if (EnumDecl *Enum = dyn_cast(NewMember)) { + // C++11 [temp.inst]p1: The implicit instantiation of a class template + // specialization causes the implicit instantiation of the definitions + // of unscoped member enumerations. + // Record a point of instantiation for this implicit instantiation. + if (TSK == TSK_ImplicitInstantiation && !Enum->isScoped()) { + MemberSpecializationInfo *MSInfo =Enum->getMemberSpecializationInfo(); + assert(MSInfo && "no spec info for member enum specialization"); + MSInfo->setTemplateSpecializationKind(TSK_ImplicitInstantiation); + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } + } + + if (NewMember->isInvalidDecl()) Invalid = true; } else { // FIXME: Eventually, a NULL return will mean that one of the diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index d0ba4db0b5..ebc43d443d 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -600,7 +600,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { // not the definitions of scoped member enumerations. // FIXME: There appears to be no wording for what happens for an enum defined // within a block scope, but we treat that like a member of a class template. - if (!Enum->isScoped()) + if (!Enum->isScoped() && D->getDefinition()) InstantiateEnumDefinition(Enum, D); return Enum; @@ -610,6 +610,9 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition( EnumDecl *Enum, EnumDecl *Pattern) { Enum->startDefinition(); + // Update the location to refer to the definition. + Enum->setLocation(Pattern->getLocation()); + SmallVector Enumerators; EnumConstantDecl *LastEnumConst = 0; diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp new file mode 100644 index 0000000000..f8cc009474 --- /dev/null +++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp @@ -0,0 +1,152 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +template struct A { + enum E : T; // expected-note {{here}} + E v; + E f() { return A::e1; } // expected-error {{no member named 'e1' in 'A'}} + E g() { return E::e1; } + E h(); +}; + +A a; +A::E a0 = A().v; +int n = A::E::e1; // expected-error {{implicit instantiation of undefined member}} + +template enum A::E : T { e1, e2 }; + +// FIXME: Now that A::E is defined, we are supposed to inject its enumerators +// into the already-instantiated class A. This seems like a really bad idea, +// though, so we don't implement that, but what we do implement is inconsistent. +// +// Either do as the standard says, or only include enumerators lexically defined +// within the class in its scope. +A::E a1 = A::e1; // expected-error {{no member named 'e1' in 'A'}} + +A::E a2 = A::e2; + +template typename A::E A::h() { return e2; } +A::E a3 = A().h(); + + +template struct B { + enum class E; + E v; + E f() { return E::e1; } + E g(); +}; + +B b; +B::E b0 = B().v; + +template enum class B::E { e1, e2 }; +B::E b1 = B::E::e1; + +B::E b2 = B::E::e2; + +template typename B::E B::g() { return e2; } +B::E b3 = B().g(); + + +// Enumeration members of class templates can be explicitly specialized. For +// unscoped enumerations, specializations must be defined before the primary +// template is, since otherwise the primary template will be implicitly +// instantiated when we parse the nested name specifier. +template<> enum A::E : long long { e3, e4 }; // expected-error {{explicit specialization of 'E' after instantiation}} expected-note {{first required here}} + +template<> enum class B::E { e3, e4 }; +B::E b4 = B::E::e4; + +B::E b5; +template<> enum class B::E { e5 }; +void fb5() { b5 = decltype(b5)::e5; } +B::E b6 = B::E::e5; + + +template struct C { + enum class E : T; +}; + +template<> enum class C::E : long long { e3, e4 }; +C::E c0 = C::E::e3; + +C::E c1; +template<> enum class C::E : long { e5 }; +void fc1() { c1 = decltype(c1)::e5; } +C::E c2 = C::E::e5; + +template<> enum class C::E : int { e6 }; +template enum class C::E : T { e0 }; +C::E c3 = C::E::e6; +C::E c4 = C::E::e0; // expected-error {{no member named 'e0' in 'C::E'}} + + +// Enumeration members can't be partially-specialized. +template enum class B::E { e5, e6 }; // expected-error {{nested name specifier for a declaration cannot depend on a template parameter}} + + +// Explicit specializations can be forward-declared. +template +struct D { + enum class E { e1 }; +}; +template<> enum class D::E; +D::E d1 = D::E::e1; // expected-error {{incomplete type 'D::E'}} +template<> enum class D::E { e2 }; +D::E d2 = D::E::e2; +D::E d3 = D::E::e1; // expected-note {{first required here}} +D::E d4 = D::E::e2; // expected-error {{no member named 'e2'}} +template<> enum class D::E { e3 }; // expected-error {{explicit specialization of 'E' after instantiation}} + +template<> enum class D::E; +struct F { + // Per C++11 [class.friend]p3, these friend declarations have no effect. + // Only classes and functions can be friends. + template friend enum D::E; + template<> friend enum D::E; + + template<> friend enum D::E { e3 }; // expected-error {{cannot define a type in a friend declaration}} + +private: + static const int n = 1; // expected-note {{private here}} +}; +template<> enum class D::E { + e = F::n // expected-error {{private member}} +}; + +class Access { + friend class X; + + template + class Priv { + friend class X; + + enum class E : T; + }; + + class S { + typedef int N; // expected-note {{here}} + static const int k = 3; // expected-note {{here}} + + friend class Priv; + }; + + static const int k = 5; +}; + +template<> enum class Access::Priv::E + : Access::S::N { // expected-error {{private member}} + a = Access::k, // ok + b = Access::S::k // expected-error {{private member}} +}; + +template enum class Access::Priv::E : T { + c = Access::k, + d = Access::S::k +}; + +class X { + Access::Priv::E a = Access::Priv::E::a; + Access::Priv::E c = Access::Priv::E::d; + // FIXME: We should see an access error for this enumerator. + Access::Priv::E b = Access::Priv::E::d; +}; diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp index 97e78fd791..80f0598cb1 100644 --- a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp +++ b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp @@ -13,3 +13,12 @@ struct Y { }; template constexpr int Y::f(); // expected-error{{explicit instantiation cannot be 'constexpr'}} + +template +struct Z { + enum E : T { e1, e2 }; + T t; // expected-note {{refers here}} +}; + +template enum Z::E; // expected-error {{enumerations cannot be explicitly instantiated}} +template int Z::t; // expected-error {{explicit instantiation of 't' does not refer to}} -- 2.40.0