forked from OSchip/llvm-project
Variable templates: handle instantiation of static data member templates
appropriately, especially when they appear within class templates. llvm-svn: 191548
This commit is contained in:
parent
23e43cdda6
commit
8809a0c95e
|
@ -1146,10 +1146,16 @@ public:
|
||||||
/// from which it was instantiated.
|
/// from which it was instantiated.
|
||||||
VarDecl *getInstantiatedFromStaticDataMember() const;
|
VarDecl *getInstantiatedFromStaticDataMember() const;
|
||||||
|
|
||||||
/// \brief If this variable is a static data member, determine what kind of
|
/// \brief If this variable is an instantiation of a variable template or a
|
||||||
|
/// static data member of a class template, determine what kind of
|
||||||
/// template specialization or instantiation this is.
|
/// template specialization or instantiation this is.
|
||||||
TemplateSpecializationKind getTemplateSpecializationKind() const;
|
TemplateSpecializationKind getTemplateSpecializationKind() const;
|
||||||
|
|
||||||
|
/// \brief If this variable is an instantiation of a variable template or a
|
||||||
|
/// static data member of a class template, determine its point of
|
||||||
|
/// instantiation.
|
||||||
|
SourceLocation getPointOfInstantiation() const;
|
||||||
|
|
||||||
/// \brief If this variable is an instantiation of a static data member of a
|
/// \brief If this variable is an instantiation of a static data member of a
|
||||||
/// class template specialization, retrieves the member specialization
|
/// class template specialization, retrieves the member specialization
|
||||||
/// information.
|
/// information.
|
||||||
|
|
|
@ -1387,7 +1387,7 @@ class ClassTemplateSpecializationDecl
|
||||||
|
|
||||||
/// \brief The template argument list deduced for the class template
|
/// \brief The template argument list deduced for the class template
|
||||||
/// partial specialization itself.
|
/// partial specialization itself.
|
||||||
TemplateArgumentList *TemplateArgs;
|
const TemplateArgumentList *TemplateArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief The template that this specialization specializes
|
/// \brief The template that this specialization specializes
|
||||||
|
@ -1412,7 +1412,7 @@ class ClassTemplateSpecializationDecl
|
||||||
ExplicitSpecializationInfo *ExplicitInfo;
|
ExplicitSpecializationInfo *ExplicitInfo;
|
||||||
|
|
||||||
/// \brief The template arguments used to describe this specialization.
|
/// \brief The template arguments used to describe this specialization.
|
||||||
TemplateArgumentList *TemplateArgs;
|
const TemplateArgumentList *TemplateArgs;
|
||||||
|
|
||||||
/// \brief The point where this template was instantiated (if any)
|
/// \brief The point where this template was instantiated (if any)
|
||||||
SourceLocation PointOfInstantiation;
|
SourceLocation PointOfInstantiation;
|
||||||
|
@ -1563,7 +1563,7 @@ public:
|
||||||
/// instantiation of the given class template partial specialization whose
|
/// instantiation of the given class template partial specialization whose
|
||||||
/// template arguments have been deduced.
|
/// template arguments have been deduced.
|
||||||
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
|
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
|
||||||
TemplateArgumentList *TemplateArgs) {
|
const TemplateArgumentList *TemplateArgs) {
|
||||||
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
|
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
|
||||||
"Already set to a class template partial specialization!");
|
"Already set to a class template partial specialization!");
|
||||||
SpecializedPartialSpecialization *PS
|
SpecializedPartialSpecialization *PS
|
||||||
|
@ -2250,7 +2250,7 @@ class VarTemplateSpecializationDecl : public VarDecl,
|
||||||
|
|
||||||
/// \brief The template argument list deduced for the variable template
|
/// \brief The template argument list deduced for the variable template
|
||||||
/// partial specialization itself.
|
/// partial specialization itself.
|
||||||
TemplateArgumentList *TemplateArgs;
|
const TemplateArgumentList *TemplateArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief The template that this specialization specializes.
|
/// \brief The template that this specialization specializes.
|
||||||
|
@ -2275,7 +2275,7 @@ class VarTemplateSpecializationDecl : public VarDecl,
|
||||||
ExplicitSpecializationInfo *ExplicitInfo;
|
ExplicitSpecializationInfo *ExplicitInfo;
|
||||||
|
|
||||||
/// \brief The template arguments used to describe this specialization.
|
/// \brief The template arguments used to describe this specialization.
|
||||||
TemplateArgumentList *TemplateArgs;
|
const TemplateArgumentList *TemplateArgs;
|
||||||
TemplateArgumentListInfo TemplateArgsInfo;
|
TemplateArgumentListInfo TemplateArgsInfo;
|
||||||
|
|
||||||
/// \brief The point where this template was instantiated (if any).
|
/// \brief The point where this template was instantiated (if any).
|
||||||
|
@ -2421,7 +2421,7 @@ public:
|
||||||
/// instantiation of the given variable template partial specialization whose
|
/// instantiation of the given variable template partial specialization whose
|
||||||
/// template arguments have been deduced.
|
/// template arguments have been deduced.
|
||||||
void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
|
void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
|
||||||
TemplateArgumentList *TemplateArgs) {
|
const TemplateArgumentList *TemplateArgs) {
|
||||||
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
|
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
|
||||||
"Already set to a variable template partial specialization!");
|
"Already set to a variable template partial specialization!");
|
||||||
SpecializedPartialSpecialization *PS =
|
SpecializedPartialSpecialization *PS =
|
||||||
|
|
|
@ -3302,11 +3302,11 @@ def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning<
|
||||||
InGroup<CXX11Compat>, DefaultIgnore;
|
InGroup<CXX11Compat>, DefaultIgnore;
|
||||||
def err_explicit_instantiation_undefined_member : Error<
|
def err_explicit_instantiation_undefined_member : Error<
|
||||||
"explicit instantiation of undefined %select{member class|member function|"
|
"explicit instantiation of undefined %select{member class|member function|"
|
||||||
"static data member|static data member template}0 %1 of class template %2">;
|
"static data member}0 %1 of class template %2">;
|
||||||
def err_explicit_instantiation_undefined_func_template : Error<
|
def err_explicit_instantiation_undefined_func_template : Error<
|
||||||
"explicit instantiation of undefined function template %0">;
|
"explicit instantiation of undefined function template %0">;
|
||||||
def err_explicit_instantiation_undefined_var_template : Error<
|
def err_explicit_instantiation_undefined_var_template : Error<
|
||||||
"explicit instantiation of undefined variable template %0">;
|
"explicit instantiation of undefined variable template %q0">;
|
||||||
def err_explicit_instantiation_declaration_after_definition : Error<
|
def err_explicit_instantiation_declaration_after_definition : Error<
|
||||||
"explicit instantiation declaration (with 'extern') follows explicit "
|
"explicit instantiation declaration (with 'extern') follows explicit "
|
||||||
"instantiation definition (without 'extern')">;
|
"instantiation definition (without 'extern')">;
|
||||||
|
|
|
@ -493,7 +493,7 @@ namespace clang {
|
||||||
Decl *VisitVarTemplateSpecializationDecl(
|
Decl *VisitVarTemplateSpecializationDecl(
|
||||||
VarTemplateDecl *VarTemplate, VarDecl *FromVar, void *InsertPos,
|
VarTemplateDecl *VarTemplate, VarDecl *FromVar, void *InsertPos,
|
||||||
const TemplateArgumentListInfo &TemplateArgsInfo,
|
const TemplateArgumentListInfo &TemplateArgsInfo,
|
||||||
SmallVectorImpl<TemplateArgument> &Converted);
|
llvm::ArrayRef<TemplateArgument> Converted);
|
||||||
|
|
||||||
Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
|
Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
|
||||||
ClassTemplatePartialSpecializationDecl *
|
ClassTemplatePartialSpecializationDecl *
|
||||||
|
|
|
@ -7864,14 +7864,7 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
|
||||||
if (!VD->isExternallyVisible())
|
if (!VD->isExternallyVisible())
|
||||||
return GVA_Internal;
|
return GVA_Internal;
|
||||||
|
|
||||||
// If this is a static data member, compute the kind of template
|
switch (VD->getTemplateSpecializationKind()) {
|
||||||
// specialization. Otherwise, this variable is not part of a
|
|
||||||
// template.
|
|
||||||
TemplateSpecializationKind TSK = TSK_Undeclared;
|
|
||||||
if (VD->isStaticDataMember())
|
|
||||||
TSK = VD->getTemplateSpecializationKind();
|
|
||||||
|
|
||||||
switch (TSK) {
|
|
||||||
case TSK_Undeclared:
|
case TSK_Undeclared:
|
||||||
case TSK_ExplicitSpecialization:
|
case TSK_ExplicitSpecialization:
|
||||||
return GVA_StrongExternal;
|
return GVA_StrongExternal;
|
||||||
|
|
|
@ -1689,13 +1689,24 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
|
||||||
// A declaration is a definition unless [...] it contains the 'extern'
|
// A declaration is a definition unless [...] it contains the 'extern'
|
||||||
// specifier or a linkage-specification and neither an initializer [...],
|
// specifier or a linkage-specification and neither an initializer [...],
|
||||||
// it declares a static data member in a class declaration [...].
|
// it declares a static data member in a class declaration [...].
|
||||||
// C++ [temp.expl.spec]p15:
|
// C++1y [temp.expl.spec]p15:
|
||||||
// An explicit specialization of a static data member of a template is a
|
// An explicit specialization of a static data member or an explicit
|
||||||
// definition if the declaration includes an initializer; otherwise, it is
|
// specialization of a static data member template is a definition if the
|
||||||
// a declaration.
|
// declaration includes an initializer; otherwise, it is a declaration.
|
||||||
|
//
|
||||||
|
// FIXME: How do you declare (but not define) a partial specialization of
|
||||||
|
// a static data member template outside the containing class?
|
||||||
if (isStaticDataMember()) {
|
if (isStaticDataMember()) {
|
||||||
if (isOutOfLine() && (hasInit() ||
|
if (isOutOfLine() &&
|
||||||
getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
|
(hasInit() ||
|
||||||
|
// If the first declaration is out-of-line, this may be an
|
||||||
|
// instantiation of an out-of-line partial specialization of a variable
|
||||||
|
// template for which we have not yet instantiated the initializer.
|
||||||
|
(getFirstDeclaration()->isOutOfLine()
|
||||||
|
? getTemplateSpecializationKind() == TSK_Undeclared
|
||||||
|
: getTemplateSpecializationKind() !=
|
||||||
|
TSK_ExplicitSpecialization) ||
|
||||||
|
isa<VarTemplatePartialSpecializationDecl>(this)))
|
||||||
return Definition;
|
return Definition;
|
||||||
else
|
else
|
||||||
return DeclarationOnly;
|
return DeclarationOnly;
|
||||||
|
@ -1710,6 +1721,13 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
|
||||||
if (hasInit())
|
if (hasInit())
|
||||||
return Definition;
|
return Definition;
|
||||||
|
|
||||||
|
// A variable template specialization (other than a static data member
|
||||||
|
// template or an explicit specialization) is a declaration until we
|
||||||
|
// instantiate its initializer.
|
||||||
|
if (isa<VarTemplateSpecializationDecl>(this) &&
|
||||||
|
getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
|
||||||
|
return DeclarationOnly;
|
||||||
|
|
||||||
if (hasExternalStorage())
|
if (hasExternalStorage())
|
||||||
return DeclarationOnly;
|
return DeclarationOnly;
|
||||||
|
|
||||||
|
@ -1978,10 +1996,21 @@ TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
|
||||||
|
|
||||||
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
|
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
|
||||||
return MSI->getTemplateSpecializationKind();
|
return MSI->getTemplateSpecializationKind();
|
||||||
|
|
||||||
return TSK_Undeclared;
|
return TSK_Undeclared;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceLocation VarDecl::getPointOfInstantiation() const {
|
||||||
|
if (const VarTemplateSpecializationDecl *Spec =
|
||||||
|
dyn_cast<VarTemplateSpecializationDecl>(this))
|
||||||
|
return Spec->getPointOfInstantiation();
|
||||||
|
|
||||||
|
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
|
||||||
|
return MSI->getPointOfInstantiation();
|
||||||
|
|
||||||
|
return SourceLocation();
|
||||||
|
}
|
||||||
|
|
||||||
VarTemplateDecl *VarDecl::getDescribedVarTemplate() const {
|
VarTemplateDecl *VarDecl::getDescribedVarTemplate() const {
|
||||||
return getASTContext().getTemplateOrSpecializationInfo(this)
|
return getASTContext().getTemplateOrSpecializationInfo(this)
|
||||||
.dyn_cast<VarTemplateDecl *>();
|
.dyn_cast<VarTemplateDecl *>();
|
||||||
|
@ -2002,13 +2031,16 @@ MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
|
||||||
|
|
||||||
void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
|
void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
|
||||||
SourceLocation PointOfInstantiation) {
|
SourceLocation PointOfInstantiation) {
|
||||||
|
assert((isa<VarTemplateSpecializationDecl>(this) ||
|
||||||
|
getMemberSpecializationInfo()) &&
|
||||||
|
"not a variable or static data member template specialization");
|
||||||
|
|
||||||
if (VarTemplateSpecializationDecl *Spec =
|
if (VarTemplateSpecializationDecl *Spec =
|
||||||
dyn_cast<VarTemplateSpecializationDecl>(this)) {
|
dyn_cast<VarTemplateSpecializationDecl>(this)) {
|
||||||
Spec->setSpecializationKind(TSK);
|
Spec->setSpecializationKind(TSK);
|
||||||
if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
|
if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
|
||||||
Spec->getPointOfInstantiation().isInvalid())
|
Spec->getPointOfInstantiation().isInvalid())
|
||||||
Spec->setPointOfInstantiation(PointOfInstantiation);
|
Spec->setPointOfInstantiation(PointOfInstantiation);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
|
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
|
||||||
|
@ -2016,11 +2048,7 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
|
||||||
if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
|
if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
|
||||||
MSI->getPointOfInstantiation().isInvalid())
|
MSI->getPointOfInstantiation().isInvalid())
|
||||||
MSI->setPointOfInstantiation(PointOfInstantiation);
|
MSI->setPointOfInstantiation(PointOfInstantiation);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm_unreachable(
|
|
||||||
"Not a variable or static data member template specialization");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -8338,7 +8338,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
||||||
if (VDecl->getStorageClass() == SC_Extern &&
|
if (VDecl->getStorageClass() == SC_Extern &&
|
||||||
(!getLangOpts().CPlusPlus ||
|
(!getLangOpts().CPlusPlus ||
|
||||||
!(Context.getBaseElementType(VDecl->getType()).isConstQualified() ||
|
!(Context.getBaseElementType(VDecl->getType()).isConstQualified() ||
|
||||||
VDecl->isExternC())))
|
VDecl->isExternC())) &&
|
||||||
|
!isTemplateInstantiation(VDecl->getTemplateSpecializationKind()))
|
||||||
Diag(VDecl->getLocation(), diag::warn_extern_init);
|
Diag(VDecl->getLocation(), diag::warn_extern_init);
|
||||||
|
|
||||||
// C99 6.7.8p4. All file scoped initializers need to be constant.
|
// C99 6.7.8p4. All file scoped initializers need to be constant.
|
||||||
|
|
|
@ -11767,45 +11767,33 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
||||||
|
|
||||||
VarTemplateSpecializationDecl *VarSpec =
|
VarTemplateSpecializationDecl *VarSpec =
|
||||||
dyn_cast<VarTemplateSpecializationDecl>(Var);
|
dyn_cast<VarTemplateSpecializationDecl>(Var);
|
||||||
|
assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
|
||||||
|
"Can't instantiate a partial template specialization.");
|
||||||
|
|
||||||
// Implicit instantiation of static data members, static data member
|
// Implicit instantiation of static data members, static data member
|
||||||
// templates of class templates, and variable template specializations.
|
// templates of class templates, and variable template specializations.
|
||||||
// Delay instantiations of variable templates, except for those
|
// Delay instantiations of variable templates, except for those
|
||||||
// that could be used in a constant expression.
|
// that could be used in a constant expression.
|
||||||
if (VarSpec || (Var->isStaticDataMember() &&
|
TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
|
||||||
Var->getInstantiatedFromStaticDataMember())) {
|
if (isTemplateInstantiation(TSK)) {
|
||||||
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
|
bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
|
||||||
if (VarSpec)
|
|
||||||
assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
|
|
||||||
"Can't instantiate a partial template specialization.");
|
|
||||||
if (Var->isStaticDataMember())
|
|
||||||
assert(MSInfo && "Missing member specialization information?");
|
|
||||||
|
|
||||||
SourceLocation PointOfInstantiation;
|
if (TryInstantiating && !isa<VarTemplateSpecializationDecl>(Var)) {
|
||||||
bool InstantiationIsOkay = true;
|
if (Var->getPointOfInstantiation().isInvalid()) {
|
||||||
if (MSInfo) {
|
// This is a modification of an existing AST node. Notify listeners.
|
||||||
bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid();
|
if (ASTMutationListener *L = SemaRef.getASTMutationListener())
|
||||||
TemplateSpecializationKind TSK = MSInfo->getTemplateSpecializationKind();
|
L->StaticDataMemberInstantiated(Var);
|
||||||
|
} else if (!Var->isUsableInConstantExpressions(SemaRef.Context))
|
||||||
if (TSK == TSK_ImplicitInstantiation &&
|
// Don't bother trying to instantiate it again, unless we might need
|
||||||
(!AlreadyInstantiated ||
|
// its initializer before we get to the end of the TU.
|
||||||
Var->isUsableInConstantExpressions(SemaRef.Context))) {
|
TryInstantiating = false;
|
||||||
if (!AlreadyInstantiated) {
|
|
||||||
// This is a modification of an existing AST node. Notify listeners.
|
|
||||||
if (ASTMutationListener *L = SemaRef.getASTMutationListener())
|
|
||||||
L->StaticDataMemberInstantiated(Var);
|
|
||||||
MSInfo->setPointOfInstantiation(Loc);
|
|
||||||
}
|
|
||||||
PointOfInstantiation = MSInfo->getPointOfInstantiation();
|
|
||||||
} else
|
|
||||||
InstantiationIsOkay = false;
|
|
||||||
} else {
|
|
||||||
if (VarSpec->getPointOfInstantiation().isInvalid())
|
|
||||||
VarSpec->setPointOfInstantiation(Loc);
|
|
||||||
PointOfInstantiation = VarSpec->getPointOfInstantiation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InstantiationIsOkay) {
|
if (Var->getPointOfInstantiation().isInvalid())
|
||||||
|
Var->setTemplateSpecializationKind(TSK, Loc);
|
||||||
|
|
||||||
|
if (TryInstantiating) {
|
||||||
|
SourceLocation PointOfInstantiation = Var->getPointOfInstantiation();
|
||||||
bool InstantiationDependent = false;
|
bool InstantiationDependent = false;
|
||||||
bool IsNonDependent =
|
bool IsNonDependent =
|
||||||
VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments(
|
VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments(
|
||||||
|
|
|
@ -7372,13 +7372,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
|
||||||
CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true);
|
CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true);
|
||||||
|
|
||||||
// Verify that it is okay to explicitly instantiate here.
|
// Verify that it is okay to explicitly instantiate here.
|
||||||
MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo();
|
TemplateSpecializationKind PrevTSK = Prev->getTemplateSpecializationKind();
|
||||||
TemplateSpecializationKind PrevTSK =
|
SourceLocation POI = Prev->getPointOfInstantiation();
|
||||||
MSInfo ? MSInfo->getTemplateSpecializationKind()
|
|
||||||
: Prev->getTemplateSpecializationKind();
|
|
||||||
SourceLocation POI = MSInfo ? MSInfo->getPointOfInstantiation()
|
|
||||||
: cast<VarTemplateSpecializationDecl>(Prev)
|
|
||||||
->getPointOfInstantiation();
|
|
||||||
bool HasNoEffect = false;
|
bool HasNoEffect = false;
|
||||||
if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev,
|
if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev,
|
||||||
PrevTSK, POI, HasNoEffect))
|
PrevTSK, POI, HasNoEffect))
|
||||||
|
|
|
@ -2471,6 +2471,9 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
|
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
|
||||||
|
if (isa<VarTemplateSpecializationDecl>(Var))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (Var->isStaticDataMember()) {
|
if (Var->isStaticDataMember()) {
|
||||||
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
|
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
|
||||||
assert(MSInfo && "No member specialization information?");
|
assert(MSInfo && "No member specialization information?");
|
||||||
|
|
|
@ -318,7 +318,6 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
|
||||||
return Inst;
|
return Inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Revise for static member templates.
|
|
||||||
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
|
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
|
||||||
return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false);
|
return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false);
|
||||||
}
|
}
|
||||||
|
@ -2338,7 +2337,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
|
||||||
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
|
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
|
||||||
VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos,
|
VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos,
|
||||||
const TemplateArgumentListInfo &TemplateArgsInfo,
|
const TemplateArgumentListInfo &TemplateArgsInfo,
|
||||||
SmallVectorImpl<TemplateArgument> &Converted) {
|
llvm::ArrayRef<TemplateArgument> Converted) {
|
||||||
|
|
||||||
// If this is the variable for an anonymous struct or union,
|
// If this is the variable for an anonymous struct or union,
|
||||||
// instantiate the anonymous struct/union type first.
|
// instantiate the anonymous struct/union type first.
|
||||||
|
@ -2366,7 +2365,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
|
||||||
VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(),
|
VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(),
|
||||||
Converted.size());
|
Converted.size());
|
||||||
Var->setTemplateArgsInfo(TemplateArgsInfo);
|
Var->setTemplateArgsInfo(TemplateArgsInfo);
|
||||||
VarTemplate->AddSpecialization(Var, InsertPos);
|
if (InsertPos)
|
||||||
|
VarTemplate->AddSpecialization(Var, InsertPos);
|
||||||
|
|
||||||
// Substitute the nested name specifier, if any.
|
// Substitute the nested name specifier, if any.
|
||||||
if (SubstQualifier(D, Var))
|
if (SubstQualifier(D, Var))
|
||||||
|
@ -2691,12 +2691,8 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
|
||||||
// specializations. The instantiation of the initializer is not necessary.
|
// specializations. The instantiation of the initializer is not necessary.
|
||||||
VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0);
|
VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0);
|
||||||
|
|
||||||
// Set the initializer, to use as pattern for initialization.
|
|
||||||
if (VarDecl *Def = PartialSpec->getDefinition(SemaRef.getASTContext()))
|
|
||||||
PartialSpec = cast<VarTemplatePartialSpecializationDecl>(Def);
|
|
||||||
SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs,
|
SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs,
|
||||||
LateAttrs, Owner, StartingScope);
|
LateAttrs, Owner, StartingScope);
|
||||||
InstPartialSpec->setInit(PartialSpec->getInit());
|
|
||||||
|
|
||||||
return InstPartialSpec;
|
return InstPartialSpec;
|
||||||
}
|
}
|
||||||
|
@ -3309,8 +3305,15 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
|
||||||
MultiLevelTemplateArgumentList TemplateArgLists;
|
MultiLevelTemplateArgumentList TemplateArgLists;
|
||||||
TemplateArgLists.addOuterTemplateArguments(&TemplateArgList);
|
TemplateArgLists.addOuterTemplateArguments(&TemplateArgList);
|
||||||
|
|
||||||
|
// Instantiate the first declaration of the variable template: for a partial
|
||||||
|
// specialization of a static data member template, the first declaration may
|
||||||
|
// or may not be the declaration in the class; if it's in the class, we want
|
||||||
|
// to instantiate a member in the class (a declaration), and if it's outside,
|
||||||
|
// we want to instantiate a definition.
|
||||||
|
FromVar = FromVar->getFirstDeclaration();
|
||||||
|
|
||||||
TemplateDeclInstantiator Instantiator(
|
TemplateDeclInstantiator Instantiator(
|
||||||
*this, VarTemplate->getDeclContext(),
|
*this, FromVar->getDeclContext(),
|
||||||
MultiLevelTemplateArgumentList(TemplateArgList));
|
MultiLevelTemplateArgumentList(TemplateArgList));
|
||||||
|
|
||||||
// TODO: Set LateAttrs and StartingScope ...
|
// TODO: Set LateAttrs and StartingScope ...
|
||||||
|
@ -3327,10 +3330,8 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
||||||
|
|
||||||
// Do substitution on the type of the declaration
|
// Do substitution on the type of the declaration
|
||||||
MultiLevelTemplateArgumentList Innermost;
|
|
||||||
Innermost.addOuterTemplateArguments(TemplateArgs.getInnermost());
|
|
||||||
TypeSourceInfo *DI =
|
TypeSourceInfo *DI =
|
||||||
SubstType(PatternDecl->getTypeSourceInfo(), Innermost,
|
SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs,
|
||||||
PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
|
PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
|
||||||
if (!DI)
|
if (!DI)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3429,14 +3430,9 @@ void Sema::BuildVariableInstantiation(
|
||||||
NewVar->setInstantiationOfStaticDataMember(OldVar,
|
NewVar->setInstantiationOfStaticDataMember(OldVar,
|
||||||
TSK_ImplicitInstantiation);
|
TSK_ImplicitInstantiation);
|
||||||
|
|
||||||
if (isa<VarTemplateSpecializationDecl>(NewVar)) {
|
// Delay instantiation of the initializer for variable templates until a
|
||||||
// Do not instantiate the variable just yet.
|
// definition of the variable is needed.
|
||||||
} else if (InstantiatingVarTemplate) {
|
if (!isa<VarTemplateSpecializationDecl>(NewVar) && !InstantiatingVarTemplate)
|
||||||
assert(!NewVar->getInit() &&
|
|
||||||
"A variable should not have an initializer if it is templated"
|
|
||||||
" and we are instantiating its template");
|
|
||||||
NewVar->setInit(OldVar->getInit());
|
|
||||||
} else
|
|
||||||
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
|
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
|
||||||
|
|
||||||
// Diagnose unused local variables with dependent types, where the diagnostic
|
// Diagnose unused local variables with dependent types, where the diagnostic
|
||||||
|
@ -3513,19 +3509,18 @@ void Sema::InstantiateStaticDataMemberDefinition(
|
||||||
void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
|
void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
|
||||||
VarDecl *Var, bool Recursive,
|
VarDecl *Var, bool Recursive,
|
||||||
bool DefinitionRequired) {
|
bool DefinitionRequired) {
|
||||||
|
|
||||||
if (Var->isInvalidDecl())
|
if (Var->isInvalidDecl())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VarTemplateSpecializationDecl *VarSpec =
|
VarTemplateSpecializationDecl *VarSpec =
|
||||||
dyn_cast<VarTemplateSpecializationDecl>(Var);
|
dyn_cast<VarTemplateSpecializationDecl>(Var);
|
||||||
assert((VarSpec || Var->isStaticDataMember()) &&
|
VarDecl *PatternDecl = 0, *Def = 0;
|
||||||
"Not a static data member, nor a variable template specialization?");
|
MultiLevelTemplateArgumentList TemplateArgs =
|
||||||
VarDecl *PatternDecl = 0;
|
getTemplateInstantiationArgs(Var);
|
||||||
|
|
||||||
// If this is a variable template specialization, make sure that it is
|
|
||||||
// non-dependent, then find its instantiation pattern.
|
|
||||||
if (VarSpec) {
|
if (VarSpec) {
|
||||||
|
// If this is a variable template specialization, make sure that it is
|
||||||
|
// non-dependent, then find its instantiation pattern.
|
||||||
bool InstantiationDependent = false;
|
bool InstantiationDependent = false;
|
||||||
assert(!TemplateSpecializationType::anyDependentTemplateArguments(
|
assert(!TemplateSpecializationType::anyDependentTemplateArguments(
|
||||||
VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
|
VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
|
||||||
|
@ -3533,59 +3528,123 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
|
||||||
"not type-dependent");
|
"not type-dependent");
|
||||||
(void)InstantiationDependent;
|
(void)InstantiationDependent;
|
||||||
|
|
||||||
// Find the variable initialization that we'll be substituting.
|
// 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() &&
|
assert(VarSpec->getSpecializedTemplate() &&
|
||||||
"Specialization without specialized template?");
|
"Specialization without specialized template?");
|
||||||
llvm::PointerUnion<VarTemplateDecl *,
|
llvm::PointerUnion<VarTemplateDecl *,
|
||||||
VarTemplatePartialSpecializationDecl *> PatternPtr =
|
VarTemplatePartialSpecializationDecl *> PatternPtr =
|
||||||
VarSpec->getSpecializedTemplateOrPartial();
|
VarSpec->getSpecializedTemplateOrPartial();
|
||||||
if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) {
|
if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) {
|
||||||
PatternDecl = cast<VarDecl>(
|
VarTemplatePartialSpecializationDecl *Tmpl =
|
||||||
PatternPtr.get<VarTemplatePartialSpecializationDecl *>());
|
PatternPtr.get<VarTemplatePartialSpecializationDecl *>();
|
||||||
|
while (VarTemplatePartialSpecializationDecl *From =
|
||||||
|
Tmpl->getInstantiatedFromMember()) {
|
||||||
|
if (Tmpl->isMemberSpecialization())
|
||||||
|
break;
|
||||||
|
|
||||||
// Find actual definition
|
Tmpl = From;
|
||||||
if (VarDecl *Def = PatternDecl->getDefinition(getASTContext()))
|
}
|
||||||
PatternDecl = Def;
|
PatternDecl = Tmpl;
|
||||||
} else {
|
} else {
|
||||||
VarTemplateDecl *PatternTemplate = PatternPtr.get<VarTemplateDecl *>();
|
VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>();
|
||||||
|
while (VarTemplateDecl *From =
|
||||||
|
Tmpl->getInstantiatedFromMemberTemplate()) {
|
||||||
|
if (Tmpl->isMemberSpecialization())
|
||||||
|
break;
|
||||||
|
|
||||||
// Find actual definition
|
Tmpl = From;
|
||||||
if (VarTemplateDecl *Def = PatternTemplate->getDefinition())
|
}
|
||||||
PatternTemplate = Def;
|
PatternDecl = Tmpl->getTemplatedDecl();
|
||||||
|
|
||||||
PatternDecl = PatternTemplate->getTemplatedDecl();
|
|
||||||
}
|
}
|
||||||
assert(PatternDecl && "instantiating a non-template");
|
|
||||||
|
// If this is a static data member template, there might be an
|
||||||
|
// uninstantiated initializer on the declaration. If so, instantiate
|
||||||
|
// it now.
|
||||||
|
if (PatternDecl->isStaticDataMember() &&
|
||||||
|
(PatternDecl = PatternDecl->getFirstDeclaration())->hasInit() &&
|
||||||
|
!Var->hasInit()) {
|
||||||
|
// FIXME: Factor out the duplicated instantiation context setup/tear down
|
||||||
|
// code here.
|
||||||
|
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
|
||||||
|
if (Inst)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If we're performing recursive template instantiation, create our own
|
||||||
|
// queue of pending implicit instantiations that we will instantiate
|
||||||
|
// later, while we're still within our own instantiation context.
|
||||||
|
SmallVector<VTableUse, 16> SavedVTableUses;
|
||||||
|
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
|
||||||
|
if (Recursive) {
|
||||||
|
VTableUses.swap(SavedVTableUses);
|
||||||
|
PendingInstantiations.swap(SavedPendingInstantiations);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalInstantiationScope Local(*this);
|
||||||
|
|
||||||
|
// Enter the scope of this instantiation. We don't use
|
||||||
|
// PushDeclContext because we don't have a scope.
|
||||||
|
ContextRAII PreviousContext(*this, Var->getDeclContext());
|
||||||
|
InstantiateVariableInitializer(Var, PatternDecl, TemplateArgs);
|
||||||
|
PreviousContext.pop();
|
||||||
|
|
||||||
|
// FIXME: Need to inform the ASTConsumer that we instantiated the
|
||||||
|
// initializer?
|
||||||
|
|
||||||
|
// This variable may have local implicit instantiations that need to be
|
||||||
|
// instantiated within this scope.
|
||||||
|
PerformPendingInstantiations(/*LocalOnly=*/true);
|
||||||
|
|
||||||
|
Local.Exit();
|
||||||
|
|
||||||
|
if (Recursive) {
|
||||||
|
// Define any newly required vtables.
|
||||||
|
DefineUsedVTables();
|
||||||
|
|
||||||
|
// Instantiate any pending implicit instantiations found during the
|
||||||
|
// instantiation of this template.
|
||||||
|
PerformPendingInstantiations();
|
||||||
|
|
||||||
|
// Restore the set of pending vtables.
|
||||||
|
assert(VTableUses.empty() &&
|
||||||
|
"VTableUses should be empty before it is discarded.");
|
||||||
|
VTableUses.swap(SavedVTableUses);
|
||||||
|
|
||||||
|
// Restore the set of pending implicit instantiations.
|
||||||
|
assert(PendingInstantiations.empty() &&
|
||||||
|
"PendingInstantiations should be empty before it is discarded.");
|
||||||
|
PendingInstantiations.swap(SavedPendingInstantiations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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->getOutOfLineDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a static data member, find its out-of-line definition.
|
// If we don't have a definition of the variable template, we won't perform
|
||||||
VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
|
// any instantiation. Rather, we rely on the user to instantiate this
|
||||||
if (Var->isStaticDataMember()) {
|
// definition (or provide a specialization for it) in another translation
|
||||||
assert(Def && "This data member was not instantiated from a template?");
|
// unit.
|
||||||
assert(Def->isStaticDataMember() && "Not a static data member?");
|
if (!Def) {
|
||||||
Def = Def->getOutOfLineDefinition();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the instantiation pattern does not have an initializer, or if an
|
|
||||||
// out-of-line definition is not found, we won't perform any instantiation.
|
|
||||||
// Rather, we rely on the user to instantiate this definition (or provide
|
|
||||||
// a specialization for it) in another translation unit.
|
|
||||||
if ((VarSpec && !PatternDecl->getInit()) ||
|
|
||||||
(!VarSpec && Var->isStaticDataMember() && !Def)) {
|
|
||||||
if (DefinitionRequired) {
|
if (DefinitionRequired) {
|
||||||
if (!Var->isStaticDataMember()) {
|
if (VarSpec)
|
||||||
Diag(PointOfInstantiation,
|
Diag(PointOfInstantiation,
|
||||||
diag::err_explicit_instantiation_undefined_var_template)
|
diag::err_explicit_instantiation_undefined_var_template) << Var;
|
||||||
<< PatternDecl;
|
else
|
||||||
Diag(PatternDecl->getLocation(),
|
|
||||||
diag::note_explicit_instantiation_here);
|
|
||||||
} else {
|
|
||||||
Def = Var->getInstantiatedFromStaticDataMember();
|
|
||||||
Diag(PointOfInstantiation,
|
Diag(PointOfInstantiation,
|
||||||
diag::err_explicit_instantiation_undefined_member)
|
diag::err_explicit_instantiation_undefined_member)
|
||||||
<< 3 << Var->getDeclName() << Var->getDeclContext();
|
<< 2 << Var->getDeclName() << Var->getDeclContext();
|
||||||
Diag(Def->getLocation(), diag::note_explicit_instantiation_here);
|
Diag(PatternDecl->getLocation(),
|
||||||
}
|
diag::note_explicit_instantiation_here);
|
||||||
if (VarSpec)
|
if (VarSpec)
|
||||||
Var->setInvalidDecl();
|
Var->setInvalidDecl();
|
||||||
} else if (Var->getTemplateSpecializationKind()
|
} else if (Var->getTemplateSpecializationKind()
|
||||||
|
@ -3603,11 +3662,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
|
||||||
if (TSK == TSK_ExplicitSpecialization)
|
if (TSK == TSK_ExplicitSpecialization)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// C++0x [temp.explicit]p9:
|
|
||||||
// Except for inline functions, other explicit instantiation declarations
|
|
||||||
// have the effect of suppressing the implicit instantiation of the entity
|
|
||||||
// to which they refer.
|
|
||||||
//
|
|
||||||
// C++11 [temp.explicit]p10:
|
// C++11 [temp.explicit]p10:
|
||||||
// Except for inline functions, [...] explicit instantiation declarations
|
// Except for inline functions, [...] explicit instantiation declarations
|
||||||
// have the effect of suppressing the implicit instantiation of the entity
|
// have the effect of suppressing the implicit instantiation of the entity
|
||||||
|
@ -3624,24 +3678,17 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
|
||||||
: Consumer(Consumer), Var(Var) { }
|
: Consumer(Consumer), Var(Var) { }
|
||||||
|
|
||||||
~PassToConsumerRAII() {
|
~PassToConsumerRAII() {
|
||||||
if (Var->isStaticDataMember())
|
Consumer.HandleCXXStaticMemberVarInstantiation(Var);
|
||||||
Consumer.HandleCXXStaticMemberVarInstantiation(Var);
|
|
||||||
else {
|
|
||||||
DeclGroupRef DG(Var);
|
|
||||||
Consumer.HandleTopLevelDecl(DG);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} PassToConsumerRAII(Consumer, Var);
|
} PassToConsumerRAII(Consumer, Var);
|
||||||
|
|
||||||
if (!VarSpec) {
|
// If we already have a definition, we're done.
|
||||||
// If we already have a definition, we're done.
|
if (VarDecl *Def = Var->getDefinition()) {
|
||||||
if (VarDecl *Def = Var->getDefinition()) {
|
// We may be explicitly instantiating something we've already implicitly
|
||||||
// We may be explicitly instantiating something we've already implicitly
|
// instantiated.
|
||||||
// instantiated.
|
Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
|
||||||
Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
|
PointOfInstantiation);
|
||||||
PointOfInstantiation);
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
|
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
|
||||||
|
@ -3666,29 +3713,46 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
|
||||||
VarDecl *OldVar = Var;
|
VarDecl *OldVar = Var;
|
||||||
if (!VarSpec)
|
if (!VarSpec)
|
||||||
Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
|
Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
|
||||||
getTemplateInstantiationArgs(Var)));
|
TemplateArgs));
|
||||||
else
|
else if (Var->isStaticDataMember() &&
|
||||||
// Construct a VarTemplateSpecializationDecl to avoid name clashing with
|
Var->getLexicalDeclContext()->isRecord()) {
|
||||||
// the primary template. (Note that unlike function declarations, variable
|
// We need to instantiate the definition of a static data member template,
|
||||||
// declarations cannot be overloaded.)
|
// and all we have is the in-class declaration of it. Instantiate a separate
|
||||||
// In fact, there is no need to construct a new declaration from scratch.
|
// declaration of the definition.
|
||||||
// Thus, simply complete its definition with an appropriately substituted
|
TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(),
|
||||||
// type and initializer.
|
TemplateArgs);
|
||||||
Var = CompleteVarTemplateSpecializationDecl(
|
Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl(
|
||||||
VarSpec, PatternDecl, getTemplateInstantiationArgs(Var));
|
VarSpec->getSpecializedTemplate(), Def, 0,
|
||||||
|
VarSpec->getTemplateArgsInfo(), VarSpec->getTemplateArgs().asArray()));
|
||||||
|
if (Var) {
|
||||||
|
llvm::PointerUnion<VarTemplateDecl *,
|
||||||
|
VarTemplatePartialSpecializationDecl *> PatternPtr =
|
||||||
|
VarSpec->getSpecializedTemplateOrPartial();
|
||||||
|
if (VarTemplatePartialSpecializationDecl *Partial =
|
||||||
|
PatternPtr.dyn_cast<VarTemplatePartialSpecializationDecl *>())
|
||||||
|
cast<VarTemplateSpecializationDecl>(Var)->setInstantiationOf(
|
||||||
|
Partial, &VarSpec->getTemplateInstantiationArgs());
|
||||||
|
|
||||||
|
// Merge the definition with the declaration.
|
||||||
|
LookupResult R(*this, Var->getDeclName(), Var->getLocation(),
|
||||||
|
LookupOrdinaryName, ForRedeclaration);
|
||||||
|
R.addDecl(OldVar);
|
||||||
|
MergeVarDecl(Var, R);
|
||||||
|
|
||||||
|
// Attach the initializer.
|
||||||
|
InstantiateVariableInitializer(Var, Def, TemplateArgs);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
// Complete the existing variable's definition with an appropriately
|
||||||
|
// substituted type and initializer.
|
||||||
|
Var = CompleteVarTemplateSpecializationDecl(VarSpec, Def, TemplateArgs);
|
||||||
|
|
||||||
PreviousContext.pop();
|
PreviousContext.pop();
|
||||||
|
|
||||||
if (Var) {
|
if (Var) {
|
||||||
MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo();
|
|
||||||
if (!VarSpec)
|
|
||||||
assert(MSInfo && "Missing member specialization information?");
|
|
||||||
|
|
||||||
PassToConsumerRAII.Var = Var;
|
PassToConsumerRAII.Var = Var;
|
||||||
if (MSInfo)
|
Var->setTemplateSpecializationKind(OldVar->getTemplateSpecializationKind(),
|
||||||
Var->setTemplateSpecializationKind(
|
OldVar->getPointOfInstantiation());
|
||||||
MSInfo->getTemplateSpecializationKind(),
|
|
||||||
MSInfo->getPointOfInstantiation());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This variable may have local implicit instantiations that need to be
|
// This variable may have local implicit instantiations that need to be
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
// RUN: %clang_cc1 -std=c++1y -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||||
|
|
||||||
|
// Check that we keep the 'extern' when we instantiate the definition of this
|
||||||
|
// variable template specialization.
|
||||||
|
template<typename T> extern const int extern_redecl;
|
||||||
|
template<typename T> const int extern_redecl = 5;
|
||||||
|
template const int extern_redecl<int>;
|
||||||
|
|
||||||
|
// CHECK: @_Z13extern_redeclIiE = weak_odr constant
|
||||||
|
|
||||||
|
template<typename T> struct Outer {
|
||||||
|
template<typename U> struct Inner {
|
||||||
|
template<typename V> static int arr[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
Outer<char[100]> outer_int;
|
||||||
|
int init_arr();
|
||||||
|
template<typename T> template<typename U> template<typename V> int Outer<T>::Inner<U>::arr[sizeof(T) + sizeof(U) + sizeof(V)] = { init_arr() };
|
||||||
|
int *p = Outer<char[100]>::Inner<char[20]>::arr<char[3]>;
|
||||||
|
|
||||||
|
// CHECK: @_ZN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = weak_odr global [123 x i32] zeroinitializer
|
||||||
|
// CHECK: @_ZGVN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = weak_odr global
|
||||||
|
|
||||||
|
// CHECK: call {{.*}}@_Z8init_arrv
|
|
@ -53,59 +53,84 @@ namespace out_of_line {
|
||||||
template<typename T> CONST T B3::right<T,int>;
|
template<typename T> CONST T B3::right<T,int>;
|
||||||
|
|
||||||
class B4 {
|
class B4 {
|
||||||
template<typename T, typename T0> static CONST T right;
|
template<typename T, typename T0> static CONST T a;
|
||||||
template<typename T> static CONST T right<T,int>;
|
template<typename T> static CONST T a<T,int> = T(100);
|
||||||
template<typename T, typename T0> static CONST T right_def = T(100);
|
template<typename T, typename T0> static CONST T b = T(100);
|
||||||
template<typename T> static CONST T right_def<T,int>; // expected-note {{explicit instantiation refers here}}
|
template<typename T> static CONST T b<T,int>;
|
||||||
};
|
};
|
||||||
template<typename T, typename T0> CONST T B4::right;
|
template<typename T, typename T0> CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}}
|
||||||
template<typename T> CONST T B4::right<T,int>; // expected-note {{explicit instantiation refers here}}
|
template<typename T> CONST T B4::a<T,int>;
|
||||||
template CONST int B4::right<int,int>; // expected-error {{explicit instantiation of undefined static data member template 'right' of class}}
|
template CONST int B4::a<int,char>; // expected-note {{in instantiation of}}
|
||||||
template CONST int B4::right_def<int,int>; // expected-error {{explicit instantiation of undefined static data member template 'right_def' of class}}
|
template CONST int B4::a<int,int>;
|
||||||
|
|
||||||
|
template<typename T, typename T0> CONST T B4::b;
|
||||||
|
template<typename T> CONST T B4::b<T,int>; // expected-error {{default initialization of an object of const type 'const int'}}
|
||||||
|
template CONST int B4::b<int,char>;
|
||||||
|
template CONST int B4::b<int,int>; // expected-note {{in instantiation of}}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace non_const_init {
|
namespace non_const_init {
|
||||||
class A {
|
class A {
|
||||||
template<typename T> static T wrong_inst = T(10); // expected-error {{non-const static data member must be initialized out of line}}
|
template<typename T> static T wrong_inst_undefined = T(10); // expected-note {{refers here}}
|
||||||
template<typename T> static T wrong_inst_fixed;
|
template<typename T> static T wrong_inst_defined = T(10); // expected-error {{non-const static data member must be initialized out of line}}
|
||||||
|
template<typename T> static T wrong_inst_out_of_line;
|
||||||
};
|
};
|
||||||
template int A::wrong_inst<int>; // expected-note {{in instantiation of static data member 'non_const_init::A::wrong_inst<int>' requested here}}
|
|
||||||
template<typename T> T A::wrong_inst_fixed = T(10);
|
template const int A::wrong_inst_undefined<const int>; // expected-error {{undefined}}
|
||||||
template int A::wrong_inst_fixed<int>;
|
|
||||||
|
template<typename T> T A::wrong_inst_defined;
|
||||||
|
template const int A::wrong_inst_defined<const int>;
|
||||||
|
template int A::wrong_inst_defined<int>; // expected-note {{in instantiation of static data member 'non_const_init::A::wrong_inst_defined<int>' requested here}}
|
||||||
|
|
||||||
|
template<typename T> T A::wrong_inst_out_of_line = T(10);
|
||||||
|
template int A::wrong_inst_out_of_line<int>;
|
||||||
|
|
||||||
class B {
|
class B {
|
||||||
template<typename T> static T wrong_inst;
|
template<typename T> static T wrong_inst; // expected-note {{refers here}}
|
||||||
template<typename T> static T wrong_inst<T*> = T(100); // expected-error {{non-const static data member must be initialized out of line}}
|
template<typename T> static T wrong_inst<T*> = T(100); // expected-error {{non-const static data member must be initialized out of line}} expected-note {{refers here}}
|
||||||
|
|
||||||
template<typename T> static T wrong_inst_fixed;
|
template<typename T> static T wrong_inst_fixed;
|
||||||
template<typename T> static T wrong_inst_fixed<T*>;
|
template<typename T> static T wrong_inst_fixed<T*>;
|
||||||
};
|
};
|
||||||
template int B::wrong_inst<int*>; // expected-note {{in instantiation of static data member 'non_const_init::B::wrong_inst<int *>' requested here}}
|
template int B::wrong_inst<int>; // expected-error {{undefined}}
|
||||||
|
// FIXME: It'd be better to produce the 'explicit instantiation of undefined
|
||||||
|
// template' diagnostic here, not the 'must be initialized out of line'
|
||||||
|
// diagnostic.
|
||||||
|
template int B::wrong_inst<int*>; // expected-note {{in instantiation of static data member 'non_const_init::B::wrong_inst<int *>' requested here}}
|
||||||
|
template const int B::wrong_inst<const int*>; // expected-error {{undefined}}
|
||||||
template<typename T> T B::wrong_inst_fixed = T(100);
|
template<typename T> T B::wrong_inst_fixed = T(100);
|
||||||
template int B::wrong_inst_fixed<int>;
|
template int B::wrong_inst_fixed<int>;
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
template<typename T> static CONST T right_inst = T(10);
|
template<typename T> static CONST T right_inst = T(10); // expected-note {{here}}
|
||||||
template<typename T> static CONST T right_inst<T*> = T(100);
|
template<typename T> static CONST T right_inst<T*> = T(100); // expected-note {{here}}
|
||||||
};
|
};
|
||||||
template CONST int C::right_inst<int>;
|
template CONST int C::right_inst<int>; // expected-error {{undefined variable template}}
|
||||||
template CONST int C::right_inst<int*>;
|
template CONST int C::right_inst<int*>; // expected-error {{undefined variable template}}
|
||||||
|
|
||||||
namespace pointers {
|
namespace pointers {
|
||||||
|
|
||||||
struct C0 {
|
struct C0 {
|
||||||
template<typename U> static U Data;
|
template<typename U> static U Data;
|
||||||
template<typename U> static CONST U Data<U*> = U(); // Okay
|
template<typename U> static CONST U Data<U*> = U(); // expected-note {{here}}
|
||||||
|
|
||||||
|
template<typename U> static U Data2;
|
||||||
|
template<typename U> static CONST U Data2<U*> = U();
|
||||||
};
|
};
|
||||||
template CONST int C0::Data<int*>;
|
const int c0_test = C0::Data<int*>;
|
||||||
|
static_assert(c0_test == 0, "");
|
||||||
|
template const int C0::Data<int*>; // expected-error {{undefined}}
|
||||||
|
|
||||||
|
template<typename U> const U C0::Data2<U*>;
|
||||||
|
template const int C0::Data2<int*>;
|
||||||
|
|
||||||
struct C1a {
|
struct C1a {
|
||||||
template<typename U> static U Data;
|
template<typename U> static U Data;
|
||||||
template<typename U> static U* Data<U*>; // Okay, with out-of-line definition
|
template<typename U> static U* Data<U*>; // Okay, with out-of-line definition
|
||||||
};
|
};
|
||||||
template<typename T> T* C1a::Data<T*> = new T();
|
template<typename T> T* C1a::Data<T*> = new T();
|
||||||
template int* C1a::Data<int*>;
|
template int* C1a::Data<int*>;
|
||||||
|
|
||||||
struct C1b {
|
struct C1b {
|
||||||
template<typename U> static U Data;
|
template<typename U> static U Data;
|
||||||
template<typename U> static CONST U* Data<U*>; // Okay, with out-of-line definition
|
template<typename U> static CONST U* Data<U*>; // Okay, with out-of-line definition
|
||||||
|
@ -118,12 +143,13 @@ namespace non_const_init {
|
||||||
template<typename U> static U* Data<U*> = new U(); // expected-error {{non-const static data member must be initialized out of line}}
|
template<typename U> static U* Data<U*> = new U(); // expected-error {{non-const static data member must be initialized out of line}}
|
||||||
};
|
};
|
||||||
template int* C2a::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2a::Data<int *>' requested here}}
|
template int* C2a::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2a::Data<int *>' requested here}}
|
||||||
|
|
||||||
struct C2b { // FIXME: ?!? Should this be an error? pointer-types are automatically non-const?
|
struct C2b {
|
||||||
template<typename U> static int Data;
|
template<typename U> static int Data;
|
||||||
template<typename U> static CONST U* Data<U*> = (U*)(0); // expected-error {{non-const static data member must be initialized out of line}}
|
template<typename U> static U *const Data<U*> = (U*)(0); // expected-error {{static data member of type 'int *const'}}
|
||||||
};
|
};
|
||||||
template CONST int* C2b::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2b::Data<int *>' requested here}}
|
template<typename U> U *const C2b::Data<U*>;
|
||||||
|
template int *const C2b::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2b::Data<int *>' requested here}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,18 +172,16 @@ namespace constexpred {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct matrix_constants {
|
|
||||||
// TODO: (?)
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace in_class_template {
|
namespace in_class_template {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class D0 {
|
class D0 {
|
||||||
template<typename U> static U Data;
|
template<typename U> static U Data; // expected-note {{here}}
|
||||||
template<typename U> static CONST U Data<U*> = U();
|
template<typename U> static CONST U Data<U*> = U();
|
||||||
};
|
};
|
||||||
template CONST int D0<float>::Data<int*>;
|
template CONST int D0<float>::Data<int*>;
|
||||||
|
template int D0<float>::Data<int>; // expected-error {{undefined}}
|
||||||
|
template<typename T> template<typename U> const U D0<T>::Data<U*>;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class D1 {
|
class D1 {
|
||||||
|
@ -166,7 +190,8 @@ namespace in_class_template {
|
||||||
};
|
};
|
||||||
template<typename T>
|
template<typename T>
|
||||||
template<typename U> U* D1<T>::Data<U*> = (U*)(0);
|
template<typename U> U* D1<T>::Data<U*> = (U*)(0);
|
||||||
template int* D1<float>::Data<int*>;
|
template int* D1<float>::Data<int*>; // expected-note {{previous}}
|
||||||
|
template int* D1<float>::Data<int*>; // expected-error {{duplicate explicit instantiation}}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class D2 {
|
class D2 {
|
||||||
|
@ -175,53 +200,69 @@ namespace in_class_template {
|
||||||
};
|
};
|
||||||
template<>
|
template<>
|
||||||
template<typename U> U* D2<float>::Data<U*> = (U*)(0) + 1;
|
template<typename U> U* D2<float>::Data<U*> = (U*)(0) + 1;
|
||||||
template int* D1<float>::Data<int*>;
|
template int* D2<float>::Data<int*>; // expected-note {{previous}}
|
||||||
|
template int* D2<float>::Data<int*>; // expected-error {{duplicate explicit instantiation}}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct D3 {
|
struct D3 {
|
||||||
template<typename U> static CONST U Data = U(100);
|
template<typename U> static CONST U Data = U(100); // expected-note {{here}}
|
||||||
};
|
};
|
||||||
template CONST int D3<float>::Data<int>;
|
|
||||||
static_assert(D3<float>::Data<int> == 100, "");
|
static_assert(D3<float>::Data<int> == 100, "");
|
||||||
|
template const char D3<float>::Data<char>; // expected-error {{undefined}}
|
||||||
|
|
||||||
namespace bug_files {
|
namespace bug_files {
|
||||||
// FIXME: A bug has been filed addressing an issue similar to these.
|
|
||||||
// No error diagnosis should be produced, because an
|
|
||||||
// explicit specialization of a member templates of class
|
|
||||||
// template specialization should not inherit the partial
|
|
||||||
// specializations from the class template specialization.
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class D0 {
|
class D0a {
|
||||||
template<typename U> static U Data;
|
template<typename U> static U Data;
|
||||||
template<typename U> static CONST U Data<U*> = U(10); // expected-note {{previous definition is here}}
|
template<typename U> static CONST U Data<U*> = U(10); // expected-note {{previous definition is here}}
|
||||||
};
|
};
|
||||||
template<>
|
template<>
|
||||||
template<typename U> U D0<float>::Data<U*> = U(100); // expected-error{{redefinition of 'Data'}}
|
template<typename U> U D0a<float>::Data<U*> = U(100); // expected-error {{redefinition of 'Data'}}
|
||||||
|
|
||||||
|
// FIXME: We should accept this, and the corresponding case for class
|
||||||
|
// templates.
|
||||||
|
//
|
||||||
|
// [temp.class.spec.mfunc]/2: If the primary member template is explicitly
|
||||||
|
// specialized for a given specialization of the enclosing class template,
|
||||||
|
// the partial specializations of the member template are ignored
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class D1 {
|
class D1 {
|
||||||
template<typename U> static U Data;
|
template<typename U> static U Data;
|
||||||
template<typename U> static U* Data<U*>; // expected-note {{previous definition is here}}
|
template<typename U> static CONST U Data<U*> = U(10); // expected-note {{previous definition is here}}
|
||||||
};
|
};
|
||||||
template<typename T>
|
|
||||||
template<typename U> U* D1<T>::Data<U*> = (U*)(0);
|
|
||||||
template<>
|
template<>
|
||||||
template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1; // expected-error{{redefinition of 'Data'}}
|
template<typename U> U D1<float>::Data = U(10);
|
||||||
|
template<>
|
||||||
|
template<typename U> U D1<float>::Data<U*> = U(100); // expected-error{{redefinition of 'Data'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace other_bugs {
|
|
||||||
// FIXME: This fails to properly initialize the variables 'k1' and 'k2'.
|
|
||||||
|
|
||||||
template<typename A> struct S {
|
namespace definition_after_outer_instantiation {
|
||||||
template<typename B> static int V0;
|
template<typename A> struct S {
|
||||||
template<typename B> static int V1;
|
template<typename B> static const int V1;
|
||||||
|
template<typename B> static const int V2;
|
||||||
};
|
};
|
||||||
template struct S<int>;
|
template struct S<int>;
|
||||||
template<typename A> template<typename B> int S<A>::V0 = 123;
|
template<typename A> template<typename B> const int S<A>::V1 = 123;
|
||||||
template<typename A> template<typename B> int S<A>::V1<B*> = 123;
|
template<typename A> template<typename B> const int S<A>::V2<B*> = 456;
|
||||||
int k1 = S<int>::V0<void>;
|
|
||||||
int k2 = S<int>::V1<void*>;
|
static_assert(S<int>::V1<int> == 123, "");
|
||||||
|
|
||||||
|
// FIXME: The first and third case below possibly should be accepted. We're
|
||||||
|
// not picking up partial specializations added after the primary template
|
||||||
|
// is instantiated. This is kind of implied by [temp.class.spec.mfunc]/2,
|
||||||
|
// and matches our behavior for member class templates, but it's not clear
|
||||||
|
// that this is intentional. See PR17294 and core-24030.
|
||||||
|
static_assert(S<int>::V2<int*> == 456, ""); // FIXME expected-error {{}}
|
||||||
|
static_assert(S<int>::V2<int&> == 789, ""); // expected-error {{}}
|
||||||
|
|
||||||
|
template<typename A> template<typename B> const int S<A>::V2<B&> = 789;
|
||||||
|
static_assert(S<int>::V2<int&> == 789, ""); // FIXME expected-error {{}}
|
||||||
|
|
||||||
|
// All is OK if the partial specialization is declared before the implicit
|
||||||
|
// instantiation of the class template specialization.
|
||||||
|
static_assert(S<char>::V1<int> == 123, "");
|
||||||
|
static_assert(S<char>::V2<int*> == 456, "");
|
||||||
|
static_assert(S<char>::V2<int&> == 789, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace incomplete_array {
|
namespace incomplete_array {
|
||||||
|
@ -243,13 +284,12 @@ namespace in_class_template {
|
||||||
template<typename...U> static T y<tuple<U...> >[];
|
template<typename...U> static T y<tuple<U...> >[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: These cases should be accepted.
|
|
||||||
int *use_before_definition = A<int>::x<char>;
|
int *use_before_definition = A<int>::x<char>;
|
||||||
template<typename T> template<typename U> T A<T>::x[sizeof(U)];
|
template<typename T> template<typename U> T A<T>::x[sizeof(U)];
|
||||||
static_assert(sizeof(A<int>::x<char>) == 1, ""); // expected-error {{incomplete}}
|
static_assert(sizeof(A<int>::x<char>) == 4, "");
|
||||||
|
|
||||||
template<typename T> template<typename...U> T A<T>::y<tuple<U...> >[] = { U()... };
|
template<typename T> template<typename...U> T A<T>::y<tuple<U...> >[] = { U()... };
|
||||||
static_assert(sizeof(A<int>::y<tuple<char, char, char> >) == 12, ""); // expected-error {{incomplete}}
|
static_assert(sizeof(A<int>::y<tuple<char, char, char> >) == 12, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,3 +119,33 @@ namespace PR10086 {
|
||||||
foobar(5);
|
foobar(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace undefined_static_data_member {
|
||||||
|
template<typename T> struct A {
|
||||||
|
static int a; // expected-note {{here}}
|
||||||
|
template<typename U> static int b; // expected-note {{here}} expected-warning {{extension}}
|
||||||
|
};
|
||||||
|
struct B {
|
||||||
|
template<typename U> static int c; // expected-note {{here}} expected-warning {{extension}}
|
||||||
|
};
|
||||||
|
|
||||||
|
template int A<int>::a; // expected-error {{explicit instantiation of undefined static data member 'a' of class template 'undefined_static_data_member::A<int>'}}
|
||||||
|
template int A<int>::b<int>; // expected-error {{explicit instantiation of undefined variable template 'undefined_static_data_member::A<int>::b<int>'}}
|
||||||
|
template int B::c<int>; // expected-error {{explicit instantiation of undefined variable template 'undefined_static_data_member::B::c<int>'}}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T> struct C {
|
||||||
|
static int a;
|
||||||
|
template<typename U> static int b; // expected-warning {{extension}}
|
||||||
|
};
|
||||||
|
struct D {
|
||||||
|
template<typename U> static int c; // expected-warning {{extension}}
|
||||||
|
};
|
||||||
|
template<typename T> int C<T>::a;
|
||||||
|
template<typename T> template<typename U> int C<T>::b; // expected-warning {{extension}}
|
||||||
|
template<typename U> int D::c; // expected-warning {{extension}}
|
||||||
|
|
||||||
|
template int C<int>::a;
|
||||||
|
template int C<int>::b<int>;
|
||||||
|
template int D::c<int>;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue