summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Decl.h10
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td31
-rw-r--r--include/clang/Sema/Sema.h20
-rw-r--r--lib/AST/Decl.cpp18
-rw-r--r--lib/Parse/ParseDecl.cpp71
-rw-r--r--lib/Parse/ParseDeclCXX.cpp15
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp12
-rw-r--r--lib/Sema/SemaDecl.cpp17
-rw-r--r--lib/Sema/SemaLookup.cpp3
-rw-r--r--lib/Sema/SemaTemplate.cpp34
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp15
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp5
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp152
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp9
15 files changed, 344 insertions, 70 deletions
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<CXX11>;
+ "function template|member function|static data member|member class|"
+ "member enumeration}0 specialization of %1 outside namespace %2 is a "
+ "C++11 extension">, InGroup<CXX11>;
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<CXX98Compat>, 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<CXX98CompatPedantic>, 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<EnumDecl>(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<CXXRecordDecl>(Def) ||
- cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind()
- == TSK_ExplicitSpecialization) {
+ bool IsExplicitSpecializationAfterInstantiation = false;
+ if (isExplicitSpecialization) {
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Def))
+ IsExplicitSpecializationAfterInstantiation =
+ RD->getTemplateSpecializationKind() !=
+ TSK_ExplicitSpecialization;
+ else if (EnumDecl *ED = dyn_cast<EnumDecl>(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<TagDecl>(LookupCtx) ||
LookupCtx->isDependentContext() ||
cast<TagDecl>(LookupCtx)->isCompleteDefinition() ||
- Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>()
- ->isBeingDefined()) &&
+ cast<TagDecl>(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<RecordDecl>(Specialized))
EntityKind = 5;
+ else if (isa<EnumDecl>(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<EnumDecl>(Member)) {
+ EnumDecl *PrevEnum;
+ if (Previous.isSingleResult() &&
+ (PrevEnum = dyn_cast<EnumDecl>(Previous.getFoundDecl()))) {
+ Instantiation = PrevEnum;
+ InstantiatedFrom = PrevEnum->getInstantiatedFromMemberEnum();
+ MSInfo = PrevEnum->getMemberSpecializationInfo();
+ }
}
if (!Instantiation) {
@@ -5906,8 +5917,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
cast<VarDecl>(InstantiatedFrom),
TSK_ExplicitSpecialization);
MarkUnusedFileScopedDecl(InstantiationVar);
- } else {
- assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
+ } else if (isa<CXXRecordDecl>(Member)) {
CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
if (InstantiationClass->getTemplateSpecializationKind() ==
TSK_ImplicitInstantiation) {
@@ -5919,6 +5929,18 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
cast<CXXRecordDecl>(InstantiatedFrom),
TSK_ExplicitSpecialization);
+ } else {
+ assert(isa<EnumDecl>(Member) && "Only member enums remain");
+ EnumDecl *InstantiationEnum = cast<EnumDecl>(Instantiation);
+ if (InstantiationEnum->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationEnum->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationEnum->setLocation(Member->getLocation());
+ }
+
+ cast<EnumDecl>(Member)->setInstantiationOfMemberEnum(
+ cast<EnumDecl>(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<TagDecl>(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<EnumDecl>(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<Decl*, 4> 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<typename T> struct A {
+ enum E : T; // expected-note {{here}}
+ E v;
+ E f() { return A::e1; } // expected-error {{no member named 'e1' in 'A<T>'}}
+ E g() { return E::e1; }
+ E h();
+};
+
+A<int> a;
+A<int>::E a0 = A<int>().v;
+int n = A<int>::E::e1; // expected-error {{implicit instantiation of undefined member}}
+
+template<typename T> enum A<T>::E : T { e1, e2 };
+
+// FIXME: Now that A<T>::E is defined, we are supposed to inject its enumerators
+// into the already-instantiated class A<T>. 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<int>::E a1 = A<int>::e1; // expected-error {{no member named 'e1' in 'A<int>'}}
+
+A<char>::E a2 = A<char>::e2;
+
+template<typename T> typename A<T>::E A<T>::h() { return e2; }
+A<short>::E a3 = A<short>().h();
+
+
+template<typename T> struct B {
+ enum class E;
+ E v;
+ E f() { return E::e1; }
+ E g();
+};
+
+B<int> b;
+B<int>::E b0 = B<int>().v;
+
+template<typename T> enum class B<T>::E { e1, e2 };
+B<int>::E b1 = B<int>::E::e1;
+
+B<char>::E b2 = B<char>::E::e2;
+
+template<typename T> typename B<T>::E B<T>::g() { return e2; }
+B<short>::E b3 = B<short>().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<long long>::E : long long { e3, e4 }; // expected-error {{explicit specialization of 'E' after instantiation}} expected-note {{first required here}}
+
+template<> enum class B<long long>::E { e3, e4 };
+B<long long>::E b4 = B<long long>::E::e4;
+
+B<long>::E b5;
+template<> enum class B<long>::E { e5 };
+void fb5() { b5 = decltype(b5)::e5; }
+B<long>::E b6 = B<long>::E::e5;
+
+
+template<typename T> struct C {
+ enum class E : T;
+};
+
+template<> enum class C<long long>::E : long long { e3, e4 };
+C<long long>::E c0 = C<long long>::E::e3;
+
+C<long>::E c1;
+template<> enum class C<long>::E : long { e5 };
+void fc1() { c1 = decltype(c1)::e5; }
+C<long>::E c2 = C<long>::E::e5;
+
+template<> enum class C<int>::E : int { e6 };
+template<typename T> enum class C<T>::E : T { e0 };
+C<int>::E c3 = C<int>::E::e6;
+C<int>::E c4 = C<int>::E::e0; // expected-error {{no member named 'e0' in 'C<int>::E'}}
+
+
+// Enumeration members can't be partially-specialized.
+template<typename T> enum class B<T*>::E { e5, e6 }; // expected-error {{nested name specifier for a declaration cannot depend on a template parameter}}
+
+
+// Explicit specializations can be forward-declared.
+template<typename T>
+struct D {
+ enum class E { e1 };
+};
+template<> enum class D<int>::E;
+D<int>::E d1 = D<int>::E::e1; // expected-error {{incomplete type 'D<int>::E'}}
+template<> enum class D<int>::E { e2 };
+D<int>::E d2 = D<int>::E::e2;
+D<char>::E d3 = D<char>::E::e1; // expected-note {{first required here}}
+D<char>::E d4 = D<char>::E::e2; // expected-error {{no member named 'e2'}}
+template<> enum class D<char>::E { e3 }; // expected-error {{explicit specialization of 'E' after instantiation}}
+
+template<> enum class D<short>::E;
+struct F {
+ // Per C++11 [class.friend]p3, these friend declarations have no effect.
+ // Only classes and functions can be friends.
+ template<typename T> friend enum D<T>::E;
+ template<> friend enum D<short>::E;
+
+ template<> friend enum D<double>::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<short>::E {
+ e = F::n // expected-error {{private member}}
+};
+
+class Access {
+ friend class X;
+
+ template<typename T>
+ 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<char>;
+ };
+
+ static const int k = 5;
+};
+
+template<> enum class Access::Priv<Access::S::N>::E
+ : Access::S::N { // expected-error {{private member}}
+ a = Access::k, // ok
+ b = Access::S::k // expected-error {{private member}}
+};
+
+template<typename T> enum class Access::Priv<T>::E : T {
+ c = Access::k,
+ d = Access::S::k
+};
+
+class X {
+ Access::Priv<int>::E a = Access::Priv<int>::E::a;
+ Access::Priv<char>::E c = Access::Priv<char>::E::d;
+ // FIXME: We should see an access error for this enumerator.
+ Access::Priv<short>::E b = Access::Priv<short>::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<int>::f(); // expected-error{{explicit instantiation cannot be 'constexpr'}}
+
+template<typename T>
+struct Z {
+ enum E : T { e1, e2 };
+ T t; // expected-note {{refers here}}
+};
+
+template enum Z<int>::E; // expected-error {{enumerations cannot be explicitly instantiated}}
+template int Z<int>::t; // expected-error {{explicit instantiation of 't' does not refer to}}