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.
This commit is contained in:
Richard Smith
2020-07-15 19:37:15 -07:00
parent dee812a297
commit 617007240c
5 changed files with 126 additions and 148 deletions

View File

@@ -4957,6 +4957,8 @@ def err_mismatched_exception_spec_explicit_instantiation : Error<
def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn<
err_mismatched_exception_spec_explicit_instantiation.Text>,
InGroup<MicrosoftExceptionSpec>;
def err_explicit_instantiation_dependent : Error<
"explicit instantiation has dependent template arguments">;
// C++ typename-specifiers
def err_typename_nested_not_found : Error<"no type named %0 in %1">;

View File

@@ -7342,11 +7342,17 @@ public:
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
StorageClass SC, bool IsPartialSpecialization);
/// Get the specialization of the given variable template corresponding to
/// the specified argument list, or a null-but-valid result if the arguments
/// are dependent.
DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation TemplateNameLoc,
const TemplateArgumentListInfo &TemplateArgs);
/// Form a reference to the specialization of the given variable template
/// corresponding to the specified argument list, or a null-but-valid result
/// if the arguments are dependent.
ExprResult CheckVarTemplateId(const CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
VarTemplateDecl *Template,
@@ -9169,10 +9175,6 @@ public:
bool InstantiatingVarTemplate = false,
VarTemplateSpecializationDecl *PrevVTSD = nullptr);
VarDecl *getVarTemplateSpecialization(
VarTemplateDecl *VarTempl, const TemplateArgumentListInfo *TemplateArgs,
const DeclarationNameInfo &MemberNameInfo, SourceLocation TemplateKWLoc);
void InstantiateVariableInitializer(
VarDecl *Var, VarDecl *OldVar,
const MultiLevelTemplateArgumentList &TemplateArgs);

View File

@@ -944,28 +944,6 @@ static bool IsInFnTryBlockHandler(const Scope *S) {
return false;
}
VarDecl *
Sema::getVarTemplateSpecialization(VarTemplateDecl *VarTempl,
const TemplateArgumentListInfo *TemplateArgs,
const DeclarationNameInfo &MemberNameInfo,
SourceLocation TemplateKWLoc) {
if (!TemplateArgs) {
diagnoseMissingTemplateArguments(TemplateName(VarTempl),
MemberNameInfo.getBeginLoc());
return nullptr;
}
DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
MemberNameInfo.getLoc(), *TemplateArgs);
if (VDecl.isInvalid())
return nullptr;
VarDecl *Var = cast<VarDecl>(VDecl.get());
if (!Var->getTemplateSpecializationKind())
Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation,
MemberNameInfo.getLoc());
return Var;
}
ExprResult
Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
SourceLocation OpLoc, bool IsArrow,
@@ -1097,19 +1075,11 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
if (!BaseExpr) {
// If this is not an instance member, convert to a non-member access.
if (!MemberDecl->isCXXInstanceMember()) {
// If this is a variable template, get the instantiated variable
// declaration corresponding to the supplied template arguments
// (while emitting diagnostics as necessary) that will be referenced
// by this expression.
assert((!TemplateArgs || isa<VarTemplateDecl>(MemberDecl)) &&
"How did we get template arguments here sans a variable template");
if (isa<VarTemplateDecl>(MemberDecl)) {
MemberDecl = getVarTemplateSpecialization(
cast<VarTemplateDecl>(MemberDecl), TemplateArgs,
R.getLookupNameInfo(), TemplateKWLoc);
if (!MemberDecl)
return ExprError();
}
// We might have a variable template specialization (or maybe one day a
// member concept-id).
if (TemplateArgs || TemplateKWLoc.isValid())
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/false, TemplateArgs);
return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl,
FoundDecl, TemplateArgs);
}
@@ -1168,14 +1138,32 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
MemberNameInfo, Enum->getType(), VK_RValue,
OK_Ordinary);
}
if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
if (VarDecl *Var = getVarTemplateSpecialization(
VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc))
return BuildMemberExpr(
BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl,
/*HadMultipleCandidates=*/false, MemberNameInfo,
Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary);
return ExprError();
if (!TemplateArgs) {
diagnoseMissingTemplateArguments(TemplateName(VarTempl), MemberLoc);
return ExprError();
}
DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
MemberNameInfo.getLoc(), *TemplateArgs);
if (VDecl.isInvalid())
return ExprError();
// Non-dependent member, but dependent template arguments.
if (!VDecl.get())
return ActOnDependentMemberExpr(
BaseExpr, BaseExpr->getType(), IsArrow, OpLoc, SS, TemplateKWLoc,
FirstQualifierInScope, MemberNameInfo, TemplateArgs);
VarDecl *Var = cast<VarDecl>(VDecl.get());
if (!Var->getTemplateSpecializationKind())
Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc);
return BuildMemberExpr(
BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl,
/*HadMultipleCandidates=*/false, MemberNameInfo,
Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary);
}
// We found something that we didn't expect. Complain.
@@ -1852,7 +1840,6 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
// If this is known to be an instance access, go ahead and build an
// implicit 'this' expression now.
// 'this' expression now.
QualType ThisTy = getCurrentThisType();
assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");

View File

@@ -4362,6 +4362,13 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
Converted, /*UpdateArgsWithConversion=*/true))
return true;
// Produce a placeholder value if the specialization is dependent.
bool InstantiationDependent = false;
if (Template->getDeclContext()->isDependentContext() ||
TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs, InstantiationDependent))
return DeclResult();
// Find the variable template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
@@ -4389,86 +4396,77 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// 1. Attempt to find the closest partial specialization that this
// specializes, if any.
// If any of the template arguments is dependent, then this is probably
// a placeholder for an incomplete declarative context; which must be
// complete by instantiation time. Thus, do not search through the partial
// specializations yet.
// TODO: Unify with InstantiateClassTemplateSpecialization()?
// Perhaps better after unification of DeduceTemplateArguments() and
// getMoreSpecializedPartialSpecialization().
bool InstantiationDependent = false;
if (!TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs, InstantiationDependent)) {
SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
Template->getPartialSpecializations(PartialSpecs);
SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
Template->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
TemplateDeductionInfo Info(FailedCandidates.getLocation());
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
TemplateDeductionInfo Info(FailedCandidates.getLocation());
if (TemplateDeductionResult Result =
DeduceTemplateArguments(Partial, TemplateArgList, Info)) {
// Store the failed-deduction information for use in diagnostics, later.
// TODO: Actually use the failed-deduction info?
FailedCandidates.addCandidate().set(
DeclAccessPair::make(Template, AS_public), Partial,
MakeDeductionFailureInfo(Context, Result, Info));
(void)Result;
} else {
Matched.push_back(PartialSpecMatchResult());
Matched.back().Partial = Partial;
Matched.back().Args = Info.take();
}
}
if (Matched.size() >= 1) {
SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
if (Matched.size() == 1) {
// -- If exactly one matching specialization is found, the
// instantiation is generated from that specialization.
// We don't need to do anything for this.
} else {
// -- If more than one matching specialization is found, the
// partial order rules (14.5.4.2) are used to determine
// whether one of the specializations is more specialized
// than the others. If none of the specializations is more
// specialized than all of the other matching
// specializations, then the use of the variable template is
// ambiguous and the program is ill-formed.
for (SmallVector<MatchResult, 4>::iterator P = Best + 1,
PEnd = Matched.end();
P != PEnd; ++P) {
if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
PointOfInstantiation) ==
P->Partial)
Best = P;
}
// Determine if the best partial specialization is more specialized than
// the others.
for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
PEnd = Matched.end();
P != PEnd; ++P) {
if (P != Best && getMoreSpecializedPartialSpecialization(
P->Partial, Best->Partial,
PointOfInstantiation) != Best->Partial) {
AmbiguousPartialSpec = true;
break;
}
}
}
// Instantiate using the best variable template partial specialization.
InstantiationPattern = Best->Partial;
InstantiationArgs = Best->Args;
if (TemplateDeductionResult Result =
DeduceTemplateArguments(Partial, TemplateArgList, Info)) {
// Store the failed-deduction information for use in diagnostics, later.
// TODO: Actually use the failed-deduction info?
FailedCandidates.addCandidate().set(
DeclAccessPair::make(Template, AS_public), Partial,
MakeDeductionFailureInfo(Context, Result, Info));
(void)Result;
} else {
// -- If no match is found, the instantiation is generated
// from the primary template.
// InstantiationPattern = Template->getTemplatedDecl();
Matched.push_back(PartialSpecMatchResult());
Matched.back().Partial = Partial;
Matched.back().Args = Info.take();
}
}
if (Matched.size() >= 1) {
SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
if (Matched.size() == 1) {
// -- If exactly one matching specialization is found, the
// instantiation is generated from that specialization.
// We don't need to do anything for this.
} else {
// -- If more than one matching specialization is found, the
// partial order rules (14.5.4.2) are used to determine
// whether one of the specializations is more specialized
// than the others. If none of the specializations is more
// specialized than all of the other matching
// specializations, then the use of the variable template is
// ambiguous and the program is ill-formed.
for (SmallVector<MatchResult, 4>::iterator P = Best + 1,
PEnd = Matched.end();
P != PEnd; ++P) {
if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial,
PointOfInstantiation) ==
P->Partial)
Best = P;
}
// Determine if the best partial specialization is more specialized than
// the others.
for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
PEnd = Matched.end();
P != PEnd; ++P) {
if (P != Best && getMoreSpecializedPartialSpecialization(
P->Partial, Best->Partial,
PointOfInstantiation) != Best->Partial) {
AmbiguousPartialSpec = true;
break;
}
}
}
// Instantiate using the best variable template partial specialization.
InstantiationPattern = Best->Partial;
InstantiationArgs = Best->Args;
} else {
// -- If no match is found, the instantiation is generated
// from the primary template.
// InstantiationPattern = Template->getTemplatedDecl();
}
// 2. Create the canonical declaration.
// Note that we do not instantiate a definition until we see an odr-use
// in DoMarkVarDeclReferenced().
@@ -4514,6 +4512,9 @@ Sema::CheckVarTemplateId(const CXXScopeSpec &SS,
if (Decl.isInvalid())
return ExprError();
if (!Decl.get())
return ExprResult();
VarDecl *Var = cast<VarDecl>(Decl.get());
if (!Var->getTemplateSpecializationKind())
Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation,
@@ -4601,18 +4602,14 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
}
}
auto AnyDependentArguments = [&]() -> bool {
bool InstantiationDependent;
return TemplateArgs &&
TemplateSpecializationType::anyDependentTemplateArguments(
*TemplateArgs, InstantiationDependent);
};
// In C++1y, check variable template ids.
if (R.getAsSingle<VarTemplateDecl>() && !AnyDependentArguments()) {
return CheckVarTemplateId(SS, R.getLookupNameInfo(),
R.getAsSingle<VarTemplateDecl>(),
TemplateKWLoc, TemplateArgs);
if (R.getAsSingle<VarTemplateDecl>()) {
ExprResult Res = CheckVarTemplateId(SS, R.getLookupNameInfo(),
R.getAsSingle<VarTemplateDecl>(),
TemplateKWLoc, TemplateArgs);
if (Res.isInvalid() || Res.isUsable())
return Res;
// Result is dependent. Carry on to build an UnresolvedLookupEpxr.
}
if (R.getAsSingle<ConceptDecl>()) {
@@ -9921,6 +9918,14 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (Res.isInvalid())
return true;
if (!Res.isUsable()) {
// We somehow specified dependent template arguments in an explicit
// instantiation. This should probably only happen during error
// recovery.
Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_dependent);
return true;
}
// Ignore access control bits, we don't need them for redeclaration
// checking.
Prev = cast<VarDecl>(Res.get());

View File

@@ -5134,15 +5134,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
if (VarSpec) {
// If this is a variable template specialization, make sure that it is
// non-dependent.
bool InstantiationDependent = false;
assert(!TemplateSpecializationType::anyDependentTemplateArguments(
VarSpec->getTemplateArgsInfo(), InstantiationDependent) &&
"Only instantiate variable template specializations that are "
"not type-dependent");
(void)InstantiationDependent;
// If this is a static data member template, there might be an
// uninstantiated initializer on the declaration. If so, instantiate
// it now.
@@ -5963,16 +5954,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
return nullptr;
DeclContext::lookup_result Found = ParentDC->lookup(Name);
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
VarTemplateDecl *Templ = cast_or_null<VarTemplateDecl>(
findInstantiationOf(Context, VTSD->getSpecializedTemplate(),
Found.begin(), Found.end()));
if (!Templ)
return nullptr;
Result = getVarTemplateSpecialization(
Templ, &VTSD->getTemplateArgsInfo(), NewNameInfo, SourceLocation());
} else
Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
} else {
// Since we don't have a name for the entity we're looking for,
// our only option is to walk through all of the declarations to