Skip to content

Commit 6170072

Browse files
committed
Improve modeling of variable template specializations with dependent
arguments. Don't build a variable template specialization declaration until its scope and template arguments are non-dependent. No functionality change intended, but the AST representation is now more consistent with how we model other templates.
1 parent dee812a commit 6170072

File tree

5 files changed

+122
-144
lines changed

5 files changed

+122
-144
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4957,6 +4957,8 @@ def err_mismatched_exception_spec_explicit_instantiation : Error<
49574957
def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn<
49584958
err_mismatched_exception_spec_explicit_instantiation.Text>,
49594959
InGroup<MicrosoftExceptionSpec>;
4960+
def err_explicit_instantiation_dependent : Error<
4961+
"explicit instantiation has dependent template arguments">;
49604962

49614963
// C++ typename-specifiers
49624964
def err_typename_nested_not_found : Error<"no type named %0 in %1">;

clang/include/clang/Sema/Sema.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7342,11 +7342,17 @@ class Sema final {
73427342
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
73437343
StorageClass SC, bool IsPartialSpecialization);
73447344

7345+
/// Get the specialization of the given variable template corresponding to
7346+
/// the specified argument list, or a null-but-valid result if the arguments
7347+
/// are dependent.
73457348
DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
73467349
SourceLocation TemplateLoc,
73477350
SourceLocation TemplateNameLoc,
73487351
const TemplateArgumentListInfo &TemplateArgs);
73497352

7353+
/// Form a reference to the specialization of the given variable template
7354+
/// corresponding to the specified argument list, or a null-but-valid result
7355+
/// if the arguments are dependent.
73507356
ExprResult CheckVarTemplateId(const CXXScopeSpec &SS,
73517357
const DeclarationNameInfo &NameInfo,
73527358
VarTemplateDecl *Template,
@@ -9169,10 +9175,6 @@ class Sema final {
91699175
bool InstantiatingVarTemplate = false,
91709176
VarTemplateSpecializationDecl *PrevVTSD = nullptr);
91719177

9172-
VarDecl *getVarTemplateSpecialization(
9173-
VarTemplateDecl *VarTempl, const TemplateArgumentListInfo *TemplateArgs,
9174-
const DeclarationNameInfo &MemberNameInfo, SourceLocation TemplateKWLoc);
9175-
91769178
void InstantiateVariableInitializer(
91779179
VarDecl *Var, VarDecl *OldVar,
91789180
const MultiLevelTemplateArgumentList &TemplateArgs);

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -944,28 +944,6 @@ static bool IsInFnTryBlockHandler(const Scope *S) {
944944
return false;
945945
}
946946

947-
VarDecl *
948-
Sema::getVarTemplateSpecialization(VarTemplateDecl *VarTempl,
949-
const TemplateArgumentListInfo *TemplateArgs,
950-
const DeclarationNameInfo &MemberNameInfo,
951-
SourceLocation TemplateKWLoc) {
952-
if (!TemplateArgs) {
953-
diagnoseMissingTemplateArguments(TemplateName(VarTempl),
954-
MemberNameInfo.getBeginLoc());
955-
return nullptr;
956-
}
957-
958-
DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
959-
MemberNameInfo.getLoc(), *TemplateArgs);
960-
if (VDecl.isInvalid())
961-
return nullptr;
962-
VarDecl *Var = cast<VarDecl>(VDecl.get());
963-
if (!Var->getTemplateSpecializationKind())
964-
Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation,
965-
MemberNameInfo.getLoc());
966-
return Var;
967-
}
968-
969947
ExprResult
970948
Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
971949
SourceLocation OpLoc, bool IsArrow,
@@ -1097,19 +1075,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
10971075
if (!BaseExpr) {
10981076
// If this is not an instance member, convert to a non-member access.
10991077
if (!MemberDecl->isCXXInstanceMember()) {
1100-
// If this is a variable template, get the instantiated variable
1101-
// declaration corresponding to the supplied template arguments
1102-
// (while emitting diagnostics as necessary) that will be referenced
1103-
// by this expression.
1104-
assert((!TemplateArgs || isa<VarTemplateDecl>(MemberDecl)) &&
1105-
"How did we get template arguments here sans a variable template");
1106-
if (isa<VarTemplateDecl>(MemberDecl)) {
1107-
MemberDecl = getVarTemplateSpecialization(
1108-
cast<VarTemplateDecl>(MemberDecl), TemplateArgs,
1109-
R.getLookupNameInfo(), TemplateKWLoc);
1110-
if (!MemberDecl)
1111-
return ExprError();
1112-
}
1078+
// We might have a variable template specialization (or maybe one day a
1079+
// member concept-id).
1080+
if (TemplateArgs || TemplateKWLoc.isValid())
1081+
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/false, TemplateArgs);
1082+
11131083
return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl,
11141084
FoundDecl, TemplateArgs);
11151085
}
@@ -1168,14 +1138,32 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
11681138
MemberNameInfo, Enum->getType(), VK_RValue,
11691139
OK_Ordinary);
11701140
}
1141+
11711142
if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
1172-
if (VarDecl *Var = getVarTemplateSpecialization(
1173-
VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc))
1174-
return BuildMemberExpr(
1175-
BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl,
1176-
/*HadMultipleCandidates=*/false, MemberNameInfo,
1177-
Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary);
1178-
return ExprError();
1143+
if (!TemplateArgs) {
1144+
diagnoseMissingTemplateArguments(TemplateName(VarTempl), MemberLoc);
1145+
return ExprError();
1146+
}
1147+
1148+
DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
1149+
MemberNameInfo.getLoc(), *TemplateArgs);
1150+
if (VDecl.isInvalid())
1151+
return ExprError();
1152+
1153+
// Non-dependent member, but dependent template arguments.
1154+
if (!VDecl.get())
1155+
return ActOnDependentMemberExpr(
1156+
BaseExpr, BaseExpr->getType(), IsArrow, OpLoc, SS, TemplateKWLoc,
1157+
FirstQualifierInScope, MemberNameInfo, TemplateArgs);
1158+
1159+
VarDecl *Var = cast<VarDecl>(VDecl.get());
1160+
if (!Var->getTemplateSpecializationKind())
1161+
Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc);
1162+
1163+
return BuildMemberExpr(
1164+
BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl,
1165+
/*HadMultipleCandidates=*/false, MemberNameInfo,
1166+
Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary);
11791167
}
11801168

11811169
// We found something that we didn't expect. Complain.
@@ -1852,7 +1840,6 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
18521840

18531841
// If this is known to be an instance access, go ahead and build an
18541842
// implicit 'this' expression now.
1855-
// 'this' expression now.
18561843
QualType ThisTy = getCurrentThisType();
18571844
assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
18581845

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 83 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4362,6 +4362,13 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
43624362
Converted, /*UpdateArgsWithConversion=*/true))
43634363
return true;
43644364

4365+
// Produce a placeholder value if the specialization is dependent.
4366+
bool InstantiationDependent = false;
4367+
if (Template->getDeclContext()->isDependentContext() ||
4368+
TemplateSpecializationType::anyDependentTemplateArguments(
4369+
TemplateArgs, InstantiationDependent))
4370+
return DeclResult();
4371+
43654372
// Find the variable template specialization declaration that
43664373
// corresponds to these arguments.
43674374
void *InsertPos = nullptr;
@@ -4389,84 +4396,75 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
43894396

43904397
// 1. Attempt to find the closest partial specialization that this
43914398
// specializes, if any.
4392-
// If any of the template arguments is dependent, then this is probably
4393-
// a placeholder for an incomplete declarative context; which must be
4394-
// complete by instantiation time. Thus, do not search through the partial
4395-
// specializations yet.
43964399
// TODO: Unify with InstantiateClassTemplateSpecialization()?
43974400
// Perhaps better after unification of DeduceTemplateArguments() and
43984401
// getMoreSpecializedPartialSpecialization().
4399-
bool InstantiationDependent = false;
4400-
if (!TemplateSpecializationType::anyDependentTemplateArguments(
4401-
TemplateArgs, InstantiationDependent)) {
4402-
4403-
SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
4404-
Template->getPartialSpecializations(PartialSpecs);
4402+
SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
4403+
Template->getPartialSpecializations(PartialSpecs);
44054404

4406-
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
4407-
VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
4408-
TemplateDeductionInfo Info(FailedCandidates.getLocation());
4405+
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
4406+
VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
4407+
TemplateDeductionInfo Info(FailedCandidates.getLocation());
44094408

4410-
if (TemplateDeductionResult Result =
4411-
DeduceTemplateArguments(Partial, TemplateArgList, Info)) {
4412-
// Store the failed-deduction information for use in diagnostics, later.
4413-
// TODO: Actually use the failed-deduction info?
4414-
FailedCandidates.addCandidate().set(
4415-
DeclAccessPair::make(Template, AS_public), Partial,
4416-
MakeDeductionFailureInfo(Context, Result, Info));
4417-
(void)Result;
4418-
} else {
4419-
Matched.push_back(PartialSpecMatchResult());
4420-
Matched.back().Partial = Partial;
4421-
Matched.back().Args = Info.take();
4422-
}
4409+
if (TemplateDeductionResult Result =
4410+
DeduceTemplateArguments(Partial, TemplateArgList, Info)) {
4411+
// Store the failed-deduction information for use in diagnostics, later.
4412+
// TODO: Actually use the failed-deduction info?
4413+
FailedCandidates.addCandidate().set(
4414+
DeclAccessPair::make(Template, AS_public), Partial,
4415+
MakeDeductionFailureInfo(Context, Result, Info));
4416+
(void)Result;
4417+
} else {
4418+
Matched.push_back(PartialSpecMatchResult());
4419+
Matched.back().Partial = Partial;
4420+
Matched.back().Args = Info.take();
44234421
}
4422+
}
44244423

4425-
if (Matched.size() >= 1) {
4426-
SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
4427-
if (Matched.size() == 1) {
4428-
// -- If exactly one matching specialization is found, the
4429-
// instantiation is generated from that specialization.
4430-
// We don't need to do anything for this.
4431-
} else {
4432-
// -- If more than one matching specialization is found, the
4433-
// partial order rules (14.5.4.2) are used to determine
4434-
// whether one of the specializations is more specialized
4435-
// than the others. If none of the specializations is more
4436-
// specialized than all of the other matching
4437-
// specializations, then the use of the variable template is
4438-
// ambiguous and the program is ill-formed.
4439-
for (SmallVector<MatchResult, 4>::iterator P = Best + 1,
4440-
PEnd = Matched.end();
4441-
P != PEnd; ++P) {
4442-
if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
4443-
PointOfInstantiation) ==
4444-
P->Partial)
4445-
Best = P;
4446-
}
4424+
if (Matched.size() >= 1) {
4425+
SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
4426+
if (Matched.size() == 1) {
4427+
// -- If exactly one matching specialization is found, the
4428+
// instantiation is generated from that specialization.
4429+
// We don't need to do anything for this.
4430+
} else {
4431+
// -- If more than one matching specialization is found, the
4432+
// partial order rules (14.5.4.2) are used to determine
4433+
// whether one of the specializations is more specialized
4434+
// than the others. If none of the specializations is more
4435+
// specialized than all of the other matching
4436+
// specializations, then the use of the variable template is
4437+
// ambiguous and the program is ill-formed.
4438+
for (SmallVector<MatchResult, 4>::iterator P = Best + 1,
4439+
PEnd = Matched.end();
4440+
P != PEnd; ++P) {
4441+
if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
4442+
PointOfInstantiation) ==
4443+
P->Partial)
4444+
Best = P;
4445+
}
44474446

4448-
// Determine if the best partial specialization is more specialized than
4449-
// the others.
4450-
for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
4451-
PEnd = Matched.end();
4452-
P != PEnd; ++P) {
4453-
if (P != Best && getMoreSpecializedPartialSpecialization(
4454-
P->Partial, Best->Partial,
4455-
PointOfInstantiation) != Best->Partial) {
4456-
AmbiguousPartialSpec = true;
4457-
break;
4458-
}
4447+
// Determine if the best partial specialization is more specialized than
4448+
// the others.
4449+
for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
4450+
PEnd = Matched.end();
4451+
P != PEnd; ++P) {
4452+
if (P != Best && getMoreSpecializedPartialSpecialization(
4453+
P->Partial, Best->Partial,
4454+
PointOfInstantiation) != Best->Partial) {
4455+
AmbiguousPartialSpec = true;
4456+
break;
44594457
}
44604458
}
4461-
4462-
// Instantiate using the best variable template partial specialization.
4463-
InstantiationPattern = Best->Partial;
4464-
InstantiationArgs = Best->Args;
4465-
} else {
4466-
// -- If no match is found, the instantiation is generated
4467-
// from the primary template.
4468-
// InstantiationPattern = Template->getTemplatedDecl();
44694459
}
4460+
4461+
// Instantiate using the best variable template partial specialization.
4462+
InstantiationPattern = Best->Partial;
4463+
InstantiationArgs = Best->Args;
4464+
} else {
4465+
// -- If no match is found, the instantiation is generated
4466+
// from the primary template.
4467+
// InstantiationPattern = Template->getTemplatedDecl();
44704468
}
44714469

44724470
// 2. Create the canonical declaration.
@@ -4514,6 +4512,9 @@ Sema::CheckVarTemplateId(const CXXScopeSpec &SS,
45144512
if (Decl.isInvalid())
45154513
return ExprError();
45164514

4515+
if (!Decl.get())
4516+
return ExprResult();
4517+
45174518
VarDecl *Var = cast<VarDecl>(Decl.get());
45184519
if (!Var->getTemplateSpecializationKind())
45194520
Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation,
@@ -4601,18 +4602,14 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
46014602
}
46024603
}
46034604

4604-
auto AnyDependentArguments = [&]() -> bool {
4605-
bool InstantiationDependent;
4606-
return TemplateArgs &&
4607-
TemplateSpecializationType::anyDependentTemplateArguments(
4608-
*TemplateArgs, InstantiationDependent);
4609-
};
4610-
46114605
// In C++1y, check variable template ids.
4612-
if (R.getAsSingle<VarTemplateDecl>() && !AnyDependentArguments()) {
4613-
return CheckVarTemplateId(SS, R.getLookupNameInfo(),
4614-
R.getAsSingle<VarTemplateDecl>(),
4615-
TemplateKWLoc, TemplateArgs);
4606+
if (R.getAsSingle<VarTemplateDecl>()) {
4607+
ExprResult Res = CheckVarTemplateId(SS, R.getLookupNameInfo(),
4608+
R.getAsSingle<VarTemplateDecl>(),
4609+
TemplateKWLoc, TemplateArgs);
4610+
if (Res.isInvalid() || Res.isUsable())
4611+
return Res;
4612+
// Result is dependent. Carry on to build an UnresolvedLookupEpxr.
46164613
}
46174614

46184615
if (R.getAsSingle<ConceptDecl>()) {
@@ -9921,6 +9918,14 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
99219918
if (Res.isInvalid())
99229919
return true;
99239920

9921+
if (!Res.isUsable()) {
9922+
// We somehow specified dependent template arguments in an explicit
9923+
// instantiation. This should probably only happen during error
9924+
// recovery.
9925+
Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_dependent);
9926+
return true;
9927+
}
9928+
99249929
// Ignore access control bits, we don't need them for redeclaration
99259930
// checking.
99269931
Prev = cast<VarDecl>(Res.get());

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5134,15 +5134,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
51345134
VarTemplateSpecializationDecl *VarSpec =
51355135
dyn_cast<VarTemplateSpecializationDecl>(Var);
51365136
if (VarSpec) {
5137-
// If this is a variable template specialization, make sure that it is
5138-
// non-dependent.
5139-
bool InstantiationDependent = false;
5140-
assert(!TemplateSpecializationType::anyDependentTemplateArguments(
5141-
VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
5142-
"Only instantiate variable template specializations that are "
5143-
"not type-dependent");
5144-
(void)InstantiationDependent;
5145-
51465137
// If this is a static data member template, there might be an
51475138
// uninstantiated initializer on the declaration. If so, instantiate
51485139
// it now.
@@ -5963,16 +5954,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
59635954
return nullptr;
59645955
DeclContext::lookup_result Found = ParentDC->lookup(Name);
59655956

5966-
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
5967-
VarTemplateDecl *Templ = cast_or_null<VarTemplateDecl>(
5968-
findInstantiationOf(Context, VTSD->getSpecializedTemplate(),
5969-
Found.begin(), Found.end()));
5970-
if (!Templ)
5971-
return nullptr;
5972-
Result = getVarTemplateSpecialization(
5973-
Templ, &VTSD->getTemplateArgsInfo(), NewNameInfo, SourceLocation());
5974-
} else
5975-
Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
5957+
Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
59765958
} else {
59775959
// Since we don't have a name for the entity we're looking for,
59785960
// our only option is to walk through all of the declarations to

0 commit comments

Comments
 (0)