summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-05-03 23:51:38 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-05-03 23:51:38 +0000
commit6cc60c9164a96f1d73ccfd302303490e0d085b87 (patch)
treef2639ec1876eaba545ef3845d3572424ae9cc621
parentdb45e9b8b840d510c5c5bc1bf7476e70312c59dd (diff)
CWG issue 727: Fix numerous bugs in support for class-scope explicit
specializations for variable templates. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359947 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Decl.h6
-rw-r--r--include/clang/Sema/Sema.h3
-rw-r--r--include/clang/Sema/Template.h3
-rw-r--r--lib/AST/Decl.cpp102
-rw-r--r--lib/Sema/SemaExpr.cpp15
-rw-r--r--lib/Sema/SemaTemplate.cpp9
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp181
-rw-r--r--test/CXX/drs/dr7xx.cpp99
-rw-r--r--test/PCH/cxx-templates.cpp34
-rw-r--r--test/PCH/cxx-templates.h27
-rw-r--r--test/SemaTemplate/explicit-specialization-member.cpp26
11 files changed, 342 insertions, 163 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 507ca73fcb..da8128937e 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1434,6 +1434,12 @@ public:
/// template specialization or instantiation this is.
TemplateSpecializationKind getTemplateSpecializationKind() const;
+ /// Get the template specialization kind of this variable for the purposes of
+ /// template instantiation. This differs from getTemplateSpecializationKind()
+ /// for an instantiation of a class-scope explicit specialization.
+ TemplateSpecializationKind
+ getTemplateSpecializationKindForInstantiation() const;
+
/// If this variable is an instantiation of a variable template or a
/// static data member of a class template, determine its point of
/// instantiation.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 64b92d2e7a..93932b4ff6 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -8043,7 +8043,8 @@ public:
LateInstantiatedAttrVec *LateAttrs,
DeclContext *Owner,
LocalInstantiationScope *StartingScope,
- bool InstantiatingVarTemplate = false);
+ bool InstantiatingVarTemplate = false,
+ VarTemplateSpecializationDecl *PrevVTSD = nullptr);
void InstantiateVariableInitializer(
VarDecl *Var, VarDecl *OldVar,
const MultiLevelTemplateArgumentList &TemplateArgs);
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index 61de93449e..98f7dd584b 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -545,7 +545,8 @@ class VarDecl;
Decl *VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate, VarDecl *FromVar, void *InsertPos,
const TemplateArgumentListInfo &TemplateArgsInfo,
- ArrayRef<TemplateArgument> Converted);
+ ArrayRef<TemplateArgument> Converted,
+ VarTemplateSpecializationDecl *PrevDecl = nullptr);
Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
ClassTemplatePartialSpecializationDecl *
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 2c1dbbd747..19fd3882bd 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2414,48 +2414,61 @@ bool VarDecl::isNonEscapingByref() const {
}
VarDecl *VarDecl::getTemplateInstantiationPattern() const {
- // If it's a variable template specialization, find the template or partial
- // specialization from which it was instantiated.
- if (auto *VDTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(this)) {
- auto From = VDTemplSpec->getInstantiatedFrom();
- if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
- while (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) {
- if (NewVTD->isMemberSpecialization())
- break;
- VTD = NewVTD;
- }
- return getDefinitionOrSelf(VTD->getTemplatedDecl());
- }
- if (auto *VTPSD =
- From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
- while (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) {
- if (NewVTPSD->isMemberSpecialization())
- break;
- VTPSD = NewVTPSD;
- }
- return getDefinitionOrSelf<VarDecl>(VTPSD);
- }
- }
+ const VarDecl *VD = this;
- if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) {
+ // If this is an instantiated member, walk back to the template from which
+ // it was instantiated.
+ if (MemberSpecializationInfo *MSInfo = VD->getMemberSpecializationInfo()) {
if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) {
- VarDecl *VD = getInstantiatedFromStaticDataMember();
+ VD = VD->getInstantiatedFromStaticDataMember();
while (auto *NewVD = VD->getInstantiatedFromStaticDataMember())
VD = NewVD;
- return getDefinitionOrSelf(VD);
}
}
- if (VarTemplateDecl *VarTemplate = getDescribedVarTemplate()) {
- while (VarTemplate->getInstantiatedFromMemberTemplate()) {
- if (VarTemplate->isMemberSpecialization())
+ // If it's an instantiated variable template specialization, find the
+ // template or partial specialization from which it was instantiated.
+ if (auto *VDTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(VD)) {
+ if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
+ auto From = VDTemplSpec->getInstantiatedFrom();
+ if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
+ while (!VTD->isMemberSpecialization()) {
+ auto *NewVTD = VTD->getInstantiatedFromMemberTemplate();
+ if (!NewVTD)
+ break;
+ VTD = NewVTD;
+ }
+ return getDefinitionOrSelf(VTD->getTemplatedDecl());
+ }
+ if (auto *VTPSD =
+ From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+ while (!VTPSD->isMemberSpecialization()) {
+ auto *NewVTPSD = VTPSD->getInstantiatedFromMember();
+ if (!NewVTPSD)
+ break;
+ VTPSD = NewVTPSD;
+ }
+ return getDefinitionOrSelf<VarDecl>(VTPSD);
+ }
+ }
+ }
+
+ // If this is the pattern of a variable template, find where it was
+ // instantiated from. FIXME: Is this necessary?
+ if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) {
+ while (!VarTemplate->isMemberSpecialization()) {
+ auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate();
+ if (!NewVT)
break;
- VarTemplate = VarTemplate->getInstantiatedFromMemberTemplate();
+ VarTemplate = NewVT;
}
return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
}
- return nullptr;
+
+ if (VD == this)
+ return nullptr;
+ return getDefinitionOrSelf(const_cast<VarDecl*>(VD));
}
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
@@ -2475,6 +2488,17 @@ TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
return TSK_Undeclared;
}
+TemplateSpecializationKind
+VarDecl::getTemplateSpecializationKindForInstantiation() const {
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
+ return MSI->getTemplateSpecializationKind();
+
+ if (const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(this))
+ return Spec->getSpecializationKind();
+
+ return TSK_Undeclared;
+}
+
SourceLocation VarDecl::getPointOfInstantiation() const {
if (const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(this))
return Spec->getPointOfInstantiation();
@@ -2535,15 +2559,14 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
if (VarTemplateSpecializationDecl *Spec =
dyn_cast<VarTemplateSpecializationDecl>(this)) {
Spec->setSpecializationKind(TSK);
- if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
+ if (TSK != TSK_ExplicitSpecialization &&
+ PointOfInstantiation.isValid() &&
Spec->getPointOfInstantiation().isInvalid()) {
Spec->setPointOfInstantiation(PointOfInstantiation);
if (ASTMutationListener *L = getASTContext().getASTMutationListener())
L->InstantiationRequested(this);
}
- }
-
- if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
+ } else if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
MSI->setTemplateSpecializationKind(TSK);
if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
MSI->getPointOfInstantiation().isInvalid()) {
@@ -3472,12 +3495,13 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
return nullptr;
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
- while (Primary->getInstantiatedFromMemberTemplate()) {
- // If we have hit a point where the user provided a specialization of
- // this template, we're done looking.
- if (Primary->isMemberSpecialization())
+ // If we hit a point where the user provided a specialization of this
+ // template, we're done looking.
+ while (!Primary->isMemberSpecialization()) {
+ auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
+ if (!NewPrimary)
break;
- Primary = Primary->getInstantiatedFromMemberTemplate();
+ Primary = NewPrimary;
}
return getDefinitionOrSelf(Primary->getTemplatedDecl());
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9564c8f0cb..2d9dbdd342 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -15721,7 +15721,12 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
"Invalid Expr argument to DoMarkVarDeclReferenced");
Var->setReferenced();
- TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+ if (Var->isInvalidDecl())
+ return;
+
+ auto *MSI = Var->getMemberSpecializationInfo();
+ TemplateSpecializationKind TSK = MSI ? MSI->getTemplateSpecializationKind()
+ : Var->getTemplateSpecializationKind();
bool OdrUseContext = isOdrUseContext(SemaRef);
bool UsableInConstantExpr =
@@ -15754,11 +15759,15 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
(TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr);
if (TryInstantiating) {
- SourceLocation PointOfInstantiation = Var->getPointOfInstantiation();
+ SourceLocation PointOfInstantiation =
+ MSI ? MSI->getPointOfInstantiation() : Var->getPointOfInstantiation();
bool FirstInstantiation = PointOfInstantiation.isInvalid();
if (FirstInstantiation) {
PointOfInstantiation = Loc;
- Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+ if (MSI)
+ MSI->setPointOfInstantiation(PointOfInstantiation);
+ else
+ Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
}
bool InstantiationDependent = false;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 939941a4c2..58ad439747 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3927,13 +3927,6 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
Specialization->setAccess(VarTemplate->getAccess());
}
- // Link instantiations of static data members back to the template from
- // which they were instantiated.
- if (Specialization->isStaticDataMember())
- Specialization->setInstantiationOfStaticDataMember(
- VarTemplate->getTemplatedDecl(),
- Specialization->getSpecializationKind());
-
return Specialization;
}
@@ -9198,7 +9191,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (!PrevTemplate) {
if (!Prev || !Prev->isStaticDataMember()) {
- // We expect to see a data data member here.
+ // We expect to see a static data member here.
Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
<< Name;
for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 90ae8989c1..653eb69326 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3132,13 +3132,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
"for a member class template");
// Lookup the already-instantiated declaration in the instantiation
- // of the class template. FIXME: Diagnose or assert if this fails?
- DeclContext::lookup_result Found
- = Owner->lookup(ClassTemplate->getDeclName());
- if (Found.empty())
- return nullptr;
- ClassTemplateDecl *InstClassTemplate
- = dyn_cast<ClassTemplateDecl>(Found.front());
+ // of the class template.
+ ClassTemplateDecl *InstClassTemplate =
+ cast_or_null<ClassTemplateDecl>(SemaRef.FindInstantiatedDecl(
+ D->getLocation(), ClassTemplate, TemplateArgs));
if (!InstClassTemplate)
return nullptr;
@@ -3247,6 +3244,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Instantiate the members of the class-scope explicit specialization eagerly.
// We don't have support for lazy instantiation of an explicit specialization
// yet, and MSVC eagerly instantiates in this case.
+ // FIXME: This is wrong in standard C++.
if (D->isThisDeclarationADefinition() &&
SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs,
TSK_ImplicitInstantiation,
@@ -3264,6 +3262,12 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
assert(VarTemplate &&
"A template specialization without specialized template?");
+ VarTemplateDecl *InstVarTemplate =
+ cast_or_null<VarTemplateDecl>(SemaRef.FindInstantiatedDecl(
+ D->getLocation(), VarTemplate, TemplateArgs));
+ if (!InstVarTemplate)
+ return nullptr;
+
// Substitute the current template arguments.
const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo();
VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc());
@@ -3275,28 +3279,33 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
// Check that the template argument list is well-formed for this template.
SmallVector<TemplateArgument, 4> Converted;
- if (SemaRef.CheckTemplateArgumentList(
- VarTemplate, VarTemplate->getBeginLoc(),
- const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false,
- Converted))
+ if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(),
+ VarTemplateArgsInfo, false, Converted))
return nullptr;
- // Find the variable template specialization declaration that
- // corresponds to these arguments.
+ // Check whether we've already seen a declaration of this specialization.
void *InsertPos = nullptr;
- if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization(
- Converted, InsertPos))
- // If we already have a variable template specialization, return it.
- return VarSpec;
+ VarTemplateSpecializationDecl *PrevDecl =
+ InstVarTemplate->findSpecialization(Converted, InsertPos);
+
+ // Check whether we've already seen a conflicting instantiation of this
+ // declaration (for instance, if there was a prior implicit instantiation).
+ bool Ignored;
+ if (PrevDecl && SemaRef.CheckSpecializationInstantiationRedecl(
+ D->getLocation(), D->getSpecializationKind(), PrevDecl,
+ PrevDecl->getSpecializationKind(),
+ PrevDecl->getPointOfInstantiation(), Ignored))
+ return nullptr;
- return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos,
- VarTemplateArgsInfo, Converted);
+ return VisitVarTemplateSpecializationDecl(
+ InstVarTemplate, D, InsertPos, VarTemplateArgsInfo, Converted, PrevDecl);
}
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos,
const TemplateArgumentListInfo &TemplateArgsInfo,
- ArrayRef<TemplateArgument> Converted) {
+ ArrayRef<TemplateArgument> Converted,
+ VarTemplateSpecializationDecl *PrevDecl) {
// Do substitution on the type of the declaration
TypeSourceInfo *DI =
@@ -3323,8 +3332,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
if (SubstQualifier(D, Var))
return nullptr;
- SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs,
- Owner, StartingScope);
+ SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner,
+ StartingScope, false, PrevDecl);
return Var;
}
@@ -4339,7 +4348,19 @@ void Sema::BuildVariableInstantiation(
const MultiLevelTemplateArgumentList &TemplateArgs,
LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner,
LocalInstantiationScope *StartingScope,
- bool InstantiatingVarTemplate) {
+ bool InstantiatingVarTemplate,
+ VarTemplateSpecializationDecl *PrevDeclForVarTemplateSpecialization) {
+ // Instantiating a partial specialization to produce a partial
+ // specialization.
+ bool InstantiatingVarTemplatePartialSpec =
+ isa<VarTemplatePartialSpecializationDecl>(OldVar) &&
+ isa<VarTemplatePartialSpecializationDecl>(NewVar);
+ // Instantiating from a variable template (or partial specialization) to
+ // produce a variable template specialization.
+ bool InstantiatingSpecFromTemplate =
+ isa<VarTemplateSpecializationDecl>(NewVar) &&
+ (OldVar->getDescribedVarTemplate() ||
+ isa<VarTemplatePartialSpecializationDecl>(OldVar));
// If we are instantiating a local extern declaration, the
// instantiation belongs lexically to the containing function.
@@ -4385,8 +4406,11 @@ void Sema::BuildVariableInstantiation(
NewVar->getLocation(), OldVar->getPreviousDecl(), TemplateArgs))
Previous.addDecl(NewPrev);
} else if (!isa<VarTemplateSpecializationDecl>(NewVar) &&
- OldVar->hasLinkage())
+ OldVar->hasLinkage()) {
LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
+ } else if (PrevDeclForVarTemplateSpecialization) {
+ Previous.addDecl(PrevDeclForVarTemplateSpecialization);
+ }
CheckVariableDeclaration(NewVar, Previous);
if (!InstantiatingVarTemplate) {
@@ -4402,23 +4426,44 @@ void Sema::BuildVariableInstantiation(
// Link instantiations of static data members back to the template from
// which they were instantiated.
- if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate)
+ //
+ // Don't do this when instantiating a template (we link the template itself
+ // back in that case) nor when instantiating a static data member template
+ // (that's not a member specialization).
+ if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate &&
+ !InstantiatingSpecFromTemplate)
NewVar->setInstantiationOfStaticDataMember(OldVar,
TSK_ImplicitInstantiation);
+ // If the pattern is an (in-class) explicit specialization, then the result
+ // is also an explicit specialization.
+ if (VarTemplateSpecializationDecl *OldVTSD =
+ dyn_cast<VarTemplateSpecializationDecl>(OldVar)) {
+ if (OldVTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<VarTemplatePartialSpecializationDecl>(OldVTSD))
+ cast<VarTemplateSpecializationDecl>(NewVar)->setSpecializationKind(
+ TSK_ExplicitSpecialization);
+ }
+
// Forward the mangling number from the template to the instantiated decl.
Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar));
Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
- // Delay instantiation of the initializer for variable templates or inline
- // static data members until a definition of the variable is needed. We need
- // it right away if the type contains 'auto'.
- if ((!isa<VarTemplateSpecializationDecl>(NewVar) &&
- !InstantiatingVarTemplate &&
- !(OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
- !NewVar->isThisDeclarationADefinition())) ||
- NewVar->getType()->isUndeducedType())
+ // Figure out whether to eagerly instantiate the initializer.
+ if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) {
+ // We're producing a template. Don't instantiate the initializer yet.
+ } else if (NewVar->getType()->isUndeducedType()) {
+ // We need the type to complete the declaration of the variable.
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
+ } else if (InstantiatingSpecFromTemplate ||
+ (OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
+ !NewVar->isThisDeclarationADefinition())) {
+ // Delay instantiation of the initializer for variable template
+ // specializations or inline static data members until a definition of the
+ // variable is needed.
+ } else {
+ InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
+ }
// Diagnose unused local variables with dependent types, where the diagnostic
// will have been deferred.
@@ -4518,15 +4563,23 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
if (Var->isInvalidDecl())
return;
- VarTemplateSpecializationDecl *VarSpec =
- dyn_cast<VarTemplateSpecializationDecl>(Var);
- VarDecl *PatternDecl = nullptr, *Def = nullptr;
+ // Never instantiate an explicitly-specialized entity.
+ TemplateSpecializationKind TSK =
+ Var->getTemplateSpecializationKindForInstantiation();
+ if (TSK == TSK_ExplicitSpecialization)
+ return;
+
+ // Find the pattern and the arguments to substitute into it.
+ VarDecl *PatternDecl = Var->getTemplateInstantiationPattern();
+ assert(PatternDecl && "no pattern for templated variable");
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Var);
+ VarTemplateSpecializationDecl *VarSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(Var);
if (VarSpec) {
// If this is a variable template specialization, make sure that it is
- // non-dependent, then find its instantiation pattern.
+ // non-dependent.
bool InstantiationDependent = false;
assert(!TemplateSpecializationType::anyDependentTemplateArguments(
VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
@@ -4534,37 +4587,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
"not type-dependent");
(void)InstantiationDependent;
- // Find the variable initialization that we'll be substituting. If the
- // pattern was instantiated from a member template, look back further to
- // find the real pattern.
- assert(VarSpec->getSpecializedTemplate() &&
- "Specialization without specialized template?");
- llvm::PointerUnion<VarTemplateDecl *,
- VarTemplatePartialSpecializationDecl *> PatternPtr =
- VarSpec->getSpecializedTemplateOrPartial();
- if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) {
- VarTemplatePartialSpecializationDecl *Tmpl =
- PatternPtr.get<VarTemplatePartialSpecializationDecl *>();
- while (VarTemplatePartialSpecializationDecl *From =
- Tmpl->getInstantiatedFromMember()) {
- if (Tmpl->isMemberSpecialization())
- break;
-
- Tmpl = From;
- }
- PatternDecl = Tmpl;
- } else {
- VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>();
- while (VarTemplateDecl *From =
- Tmpl->getInstantiatedFromMemberTemplate()) {
- if (Tmpl->isMemberSpecialization())
- break;
-
- Tmpl = From;
- }
- PatternDecl = Tmpl->getTemplatedDecl();
- }
-
// If this is a static data member template, there might be an
// uninstantiated initializer on the declaration. If so, instantiate
// it now.
@@ -4608,20 +4630,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
Local.Exit();
GlobalInstantiations.perform();
}
-
- // Find actual definition
- Def = PatternDecl->getDefinition(getASTContext());
} else {
- // If this is a static data member, find its out-of-line definition.
- assert(Var->isStaticDataMember() && "not a static data member?");
- PatternDecl = Var->getInstantiatedFromStaticDataMember();
-
- assert(PatternDecl && "data member was not instantiated from a template?");
- assert(PatternDecl->isStaticDataMember() && "not a static data member?");
- Def = PatternDecl->getDefinition();
+ assert(Var->isStaticDataMember() && PatternDecl->isStaticDataMember() &&
+ "not a static data member?");
}
- TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+ VarDecl *Def = PatternDecl->getDefinition(getASTContext());
// If we don't have a definition of the variable template, we won't perform
// any instantiation. Rather, we rely on the user to instantiate this
@@ -4643,7 +4657,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
}
return;
}
-
}
// FIXME: We need to track the instantiation stack in order to know which
@@ -4655,11 +4668,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
/*Complain*/DefinitionRequired))
return;
-
- // Never instantiate an explicit specialization.
- if (TSK == TSK_ExplicitSpecialization)
- return;
-
// C++11 [temp.explicit]p10:
// Except for inline functions, const variables of literal types, variables
// of reference types, [...] explicit instantiation declarations
@@ -5495,7 +5503,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
// Check if the most recent declaration has changed the specialization kind
// and removed the need for implicit instantiation.
- switch (Var->getMostRecentDecl()->getTemplateSpecializationKind()) {
+ switch (Var->getMostRecentDecl()
+ ->getTemplateSpecializationKindForInstantiation()) {
case TSK_Undeclared:
llvm_unreachable("Cannot instantitiate an undeclared specialization.");
case TSK_ExplicitInstantiationDeclaration:
diff --git a/test/CXX/drs/dr7xx.cpp b/test/CXX/drs/dr7xx.cpp
index 2760bdad0f..2d9d396018 100644
--- a/test/CXX/drs/dr7xx.cpp
+++ b/test/CXX/drs/dr7xx.cpp
@@ -1,7 +1,8 @@
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
namespace dr705 { // dr705: yes
namespace N {
@@ -66,7 +67,7 @@ namespace dr727 { // dr727: partial
struct D {
template<typename T> struct C { typename T::error e; }; // expected-error {{no members}}
template<typename T> void f() { T::error; } // expected-error {{no members}}
- template<typename T> static const int N = T::error; // expected-error 2{{no members}} expected-error 0-1{{C++14}}
+ template<typename T> static const int N = T::error; // expected-error {{no members}} expected-error 0-1{{C++14}}
template<> struct C<int> {};
template<> void f<int>() {}
@@ -79,7 +80,7 @@ namespace dr727 { // dr727: partial
void d(D<int> di) {
D<int>::C<int>();
di.f<int>();
- int a = D<int>::N<int>; // FIXME: expected-note {{instantiation of}}
+ int a = D<int>::N<int>;
D<int>::C<int*>();
int b = D<int>::N<int*>;
@@ -88,6 +89,98 @@ namespace dr727 { // dr727: partial
di.f<float>(); // expected-note {{instantiation of}}
int c = D<int>::N<float>; // expected-note {{instantiation of}}
}
+
+ namespace mixed_inner_outer_specialization {
+#if __cplusplus >= 201103L
+ template<int> struct A {
+ template<int> constexpr int f() const { return 1; }
+ template<> constexpr int f<0>() const { return 2; }
+ };
+ template<> template<int> constexpr int A<0>::f() const { return 3; }
+ template<> template<> constexpr int A<0>::f<0>() const { return 4; }
+ static_assert(A<1>().f<1>() == 1, "");
+ static_assert(A<1>().f<0>() == 2, "");
+ static_assert(A<0>().f<1>() == 3, "");
+ static_assert(A<0>().f<0>() == 4, "");
+#endif
+
+#if __cplusplus >= 201402L
+ template<int> struct B {
+ template<int> static const int u = 1;
+ template<> static const int u<0> = 2; // expected-note {{here}}
+
+ // Note that in C++17 onwards, these are implicitly inline, and so the
+ // initializer of v<0> is not instantiated with the declaration. In
+ // C++14, v<0> is a non-defining declaration and its initializer is
+ // instantiated with the class.
+ template<int> static constexpr int v = 1;
+ template<> static constexpr int v<0> = 2; // #v0
+
+ template<int> static const inline int w = 1; // expected-error 0-1{{C++17 extension}}
+ template<> static const inline int w<0> = 2; // expected-error 0-1{{C++17 extension}}
+ };
+
+ template<> template<int> constexpr int B<0>::u = 3;
+ template<> template<> constexpr int B<0>::u<0> = 4; // expected-error {{already has an initializer}}
+
+ template<> template<int> constexpr int B<0>::v = 3;
+ template<> template<> constexpr int B<0>::v<0> = 4;
+#if __cplusplus < 201702L
+ // expected-error@-2 {{already has an initializer}}
+ // expected-note@#v0 {{here}}
+#endif
+
+ template<> template<int> constexpr int B<0>::w = 3;
+ template<> template<> constexpr int B<0>::w<0> = 4;
+
+ static_assert(B<1>().u<1> == 1, "");
+ static_assert(B<1>().u<0> == 2, "");
+ static_assert(B<0>().u<1> == 3, "");
+
+ static_assert(B<1>().v<1> == 1, "");
+ static_assert(B<1>().v<0> == 2, "");
+ static_assert(B<0>().v<1> == 3, "");
+ static_assert(B<0>().v<0> == 4, "");
+#if __cplusplus < 201702L
+ // expected-error@-2 {{failed}}
+#endif
+
+ static_assert(B<1>().w<1> == 1, "");
+ static_assert(B<1>().w<0> == 2, "");
+ static_assert(B<0>().w<1> == 3, "");
+ static_assert(B<0>().w<0> == 4, "");
+#endif
+ }
+
+ template<typename T, typename U> struct Collision {
+ // FIXME: Missing diagnostic for duplicate function explicit specialization declaration.
+ template<typename> int f1();
+ template<> int f1<T>();
+ template<> int f1<U>();
+
+ // FIXME: Missing diagnostic for fucntion redefinition!
+ template<typename> int f2();
+ template<> int f2<T>() {}
+ template<> int f2<U>() {}
+
+ template<typename> static int v1; // expected-error 0-1{{C++14 extension}}
+ template<> static int v1<T>; // expected-note {{previous}}
+ template<> static int v1<U>; // expected-error {{duplicate member}}
+
+ template<typename> static inline int v2; // expected-error 0-1{{C++17 extension}} expected-error 0-1{{C++14 extension}}
+ template<> static inline int v2<T>; // expected-error 0-1{{C++17 extension}} expected-note {{previous}}
+ template<> static inline int v2<U>; // expected-error 0-1{{C++17 extension}} expected-error {{duplicate member}}
+
+ // FIXME: Missing diagnostic for duplicate class explicit specialization.
+ template<typename> struct S1;
+ template<> struct S1<T>;
+ template<> struct S1<U>;
+
+ template<typename> struct S2;
+ template<> struct S2<T> {}; // expected-note {{previous}}
+ template<> struct S2<U> {}; // expected-error {{redefinition}}
+ };
+ Collision<int, int> c; // expected-note {{in instantiation of}}
}
namespace dr777 { // dr777: 3.7
diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp
index f41646dd5e..78898f7d26 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -1,21 +1,21 @@
// Test this without pch.
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include %S/cxx-templates.h %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include %S/cxx-templates.h %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
// Test with pch.
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t -verify %s
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS | FileCheck %s
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t -verify %s
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS | FileCheck %s
// Test with modules.
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -x c++-header -emit-pch -o %t %S/cxx-templates.h
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -x c++-header -emit-pch -o %t %S/cxx-templates.h
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s
// Test with pch and delayed template parsing.
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t -verify %s
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t -verify %s
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s
// CHECK: define weak_odr {{.*}}void @_ZN2S4IiE1mEv
// CHECK: define linkonce_odr {{.*}}void @_ZN2S3IiE1mEv
@@ -143,14 +143,16 @@ namespace ClassScopeExplicitSpecializations {
template int A<4>::f<1>() const;
// expected-note@cxx-templates.h:403 2{{here}}
- static_assert(A<0>().f<1>() == 3, "");
static_assert(A<0>().f<0>() == 4, "");
- static_assert(A<1>().f<1>() == 1, "");
+ static_assert(A<0>().f<1>() == 5, "");
+ static_assert(A<0>().f<2>() == 3, "");
static_assert(A<1>().f<0>() == 2, "");
- static_assert(A<2>().f<1>() == 1, "");
+ static_assert(A<1>().f<1>() == 1, "");
+ static_assert(A<1>().f<2>() == 1, "");
static_assert(A<2>().f<0>() == 2, "");
- static_assert(A<3>().f<1>() == 1, "");
+ static_assert(A<2>().f<1>() == 1, "");
static_assert(A<3>().f<0>() == 2, "");
- static_assert(A<4>().f<1>() == 1, "");
+ static_assert(A<3>().f<1>() == 1, "");
static_assert(A<4>().f<0>() == 2, "");
+ static_assert(A<4>().f<1>() == 1, "");
}
diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h
index f2111428ac..bfdb3b8b3d 100644
--- a/test/PCH/cxx-templates.h
+++ b/test/PCH/cxx-templates.h
@@ -402,8 +402,11 @@ namespace ClassScopeExplicitSpecializations {
template<int> constexpr int f() const { return 1; }
template<> constexpr int f<0>() const { return 2; }
};
+
template<> template<int> constexpr int A<0>::f() const { return 3; }
template<> template<> constexpr int A<0>::f<0>() const { return 4; }
+ template<> template<> constexpr int A<0>::f<1>() const { return 5; }
+
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winstantiation-after-specialization"
template int A<2>::f<0>() const;
@@ -411,4 +414,28 @@ namespace ClassScopeExplicitSpecializations {
template int A<2>::f<1>() const;
extern template int A<3>::f<0>() const;
extern template int A<3>::f<1>() const;
+
+ template<int> struct B {
+ template<typename> static const int v = 1;
+ template<typename T> static const int v<T*> = 2;
+ template<> static const int v<int> = 3;
+
+ template<typename> static constexpr int w = 1;
+ template<typename T> static constexpr int w<T*> = 2;
+ template<> static constexpr int w<int> = 3;
+ };
+
+ template<> template<typename> constexpr int B<0>::v = 4;
+ template<> template<typename T> constexpr int B<0>::v<T*> = 5;
+ template<> template<typename T> constexpr int B<0>::v<T&> = 6;
+ // This is ill-formed: the initializer of v<int> is instantiated with the
+ // class.
+ //template<> template<> constexpr int B<0>::v<int> = 7;
+ template<> template<> constexpr int B<0>::v<float> = 8;
+
+ template<> template<typename> constexpr int B<0>::w = 4;
+ template<> template<typename T> constexpr int B<0>::w<T*> = 5;
+ template<> template<typename T> constexpr int B<0>::w<T&> = 6;
+ template<> template<> constexpr int B<0>::w<int> = 7;
+ template<> template<> constexpr int B<0>::w<float> = 8;
}
diff --git a/test/SemaTemplate/explicit-specialization-member.cpp b/test/SemaTemplate/explicit-specialization-member.cpp
index e84364a508..5dc8118556 100644
--- a/test/SemaTemplate/explicit-specialization-member.cpp
+++ b/test/SemaTemplate/explicit-specialization-member.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -fcxx-exceptions
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s -fcxx-exceptions
template<typename T>
struct X0 {
typedef T* type;
@@ -70,12 +70,26 @@ namespace PR41607 {
static constexpr int f() { return N; }
};
- template<typename...> static int a; // expected-note 2{{}}
- template<> static constexpr int a<> = 42;
+ template<typename...> static int a;
+ template<> static constexpr int a<> = N;
+
+ template<typename...> static inline int b;
+ template<> static inline constexpr int b<> = N;
+
+ template<typename...> static constexpr int f();
+ template<> static constexpr int f() {
+ return N;
+ }
};
static_assert(Outer<123>::Inner<>::f() == 123, "");
static_assert(Outer<123>::Inner<>::f() != 125, "");
- // FIXME: The class-scope explicit specialization of the variable template doesn't work!
- static_assert(Outer<123>::a<> == 42, ""); // expected-error {{}} expected-note {{}}
- static_assert(Outer<123>::a<> != 43, ""); // expected-error {{}} expected-note {{}}
+
+ static_assert(Outer<123>::a<> == 123, "");
+ static_assert(Outer<123>::a<> != 125, "");
+
+ static_assert(Outer<123>::b<> == 123, "");
+ static_assert(Outer<123>::b<> != 125, "");
+
+ static_assert(Outer<123>::f<>() == 123, "");
+ static_assert(Outer<123>::f<>() != 125, "");
}