CWG issue 727: Fix numerous bugs in support for class-scope explicit

specializations for variable templates.

llvm-svn: 359947
This commit is contained in:
Richard Smith 2019-05-03 23:51:38 +00:00
parent 5a36558c5b
commit a6b41d7c52
11 changed files with 342 additions and 163 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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 *

View File

@ -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());

View File

@ -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;

View File

@ -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();

View File

@ -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:

View File

@ -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

View File

@ -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, "");
}

View File

@ -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;
}

View File

@ -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, "");
}