forked from OSchip/llvm-project
CWG issue 727: Fix numerous bugs in support for class-scope explicit
specializations for variable templates. llvm-svn: 359947
This commit is contained in:
parent
5a36558c5b
commit
a6b41d7c52
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos,
|
||||
VarTemplateArgsInfo, Converted);
|
||||
// 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(
|
||||
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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, "");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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, "");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue