Skip to content

Commit 71886c5

Browse files
committed
Where possible, don't try to ask whether a template argument is
dependent until it's been converted to match its parameter. The type of a non-type template parameter can in general affect whether the template argument is dependent. Note that this is not always possible. For template arguments that name static local variables in templates, the type of the template parameter affects whether the argument is dependent, so the query is imprecise until we know the parameter type. For example, in: template<typename T> void f() { static const int n = 5; typename T::template X<n> x; } ... we don't know whether 'n' is dependent until we know whether the corresponding template parameter is of type 'int' or 'const int&'.
1 parent 638867a commit 71886c5

File tree

6 files changed

+85
-63
lines changed

6 files changed

+85
-63
lines changed

clang/include/clang/AST/Type.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5112,11 +5112,24 @@ class alignas(8) TemplateSpecializationType
51125112

51135113
public:
51145114
/// Determine whether any of the given template arguments are dependent.
5115-
static bool anyDependentTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
5116-
bool &InstantiationDependent);
5117-
5118-
static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &,
5119-
bool &InstantiationDependent);
5115+
///
5116+
/// The converted arguments should be supplied when known; whether an
5117+
/// argument is dependent can depend on the conversions performed on it
5118+
/// (for example, a 'const int' passed as a template argument might be
5119+
/// dependent if the parameter is a reference but non-dependent if the
5120+
/// parameter is an int).
5121+
///
5122+
/// Note that the \p Args parameter is unused: this is intentional, to remind
5123+
/// the caller that they need to pass in the converted arguments, not the
5124+
/// specified arguments.
5125+
static bool
5126+
anyDependentTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
5127+
ArrayRef<TemplateArgument> Converted);
5128+
static bool
5129+
anyDependentTemplateArguments(const TemplateArgumentListInfo &,
5130+
ArrayRef<TemplateArgument> Converted);
5131+
static bool anyInstantiationDependentTemplateArguments(
5132+
ArrayRef<TemplateArgumentLoc> Args);
51205133

51215134
/// True if this template specialization type matches a current
51225135
/// instantiation in the context in which it is found.

clang/lib/AST/Type.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3590,24 +3590,24 @@ void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
35903590
ID.AddPointer(P.getAsType().getAsOpaquePtr());
35913591
}
35923592

3593-
bool TemplateSpecializationType::
3594-
anyDependentTemplateArguments(const TemplateArgumentListInfo &Args,
3595-
bool &InstantiationDependent) {
3596-
return anyDependentTemplateArguments(Args.arguments(),
3597-
InstantiationDependent);
3593+
bool TemplateSpecializationType::anyDependentTemplateArguments(
3594+
const TemplateArgumentListInfo &Args, ArrayRef<TemplateArgument> Converted) {
3595+
return anyDependentTemplateArguments(Args.arguments(), Converted);
35983596
}
35993597

3600-
bool TemplateSpecializationType::
3601-
anyDependentTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
3602-
bool &InstantiationDependent) {
3603-
for (const TemplateArgumentLoc &ArgLoc : Args) {
3604-
if (ArgLoc.getArgument().isDependent()) {
3605-
InstantiationDependent = true;
3598+
bool TemplateSpecializationType::anyDependentTemplateArguments(
3599+
ArrayRef<TemplateArgumentLoc> Args, ArrayRef<TemplateArgument> Converted) {
3600+
for (const TemplateArgument &Arg : Converted)
3601+
if (Arg.isDependent())
36063602
return true;
3607-
}
3603+
return false;
3604+
}
36083605

3606+
bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
3607+
ArrayRef<TemplateArgumentLoc> Args) {
3608+
for (const TemplateArgumentLoc &ArgLoc : Args) {
36093609
if (ArgLoc.getArgument().isInstantiationDependent())
3610-
InstantiationDependent = true;
3610+
return true;
36113611
}
36123612
return false;
36133613
}

clang/lib/Sema/SemaConcept.cpp

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,25 +1053,20 @@ ReturnTypeRequirement(TemplateParameterList *TPL) :
10531053
auto *Constraint =
10541054
cast_or_null<ConceptSpecializationExpr>(
10551055
TC->getImmediatelyDeclaredConstraint());
1056-
bool Dependent = false;
1057-
if (Constraint->getTemplateArgsAsWritten()) {
1058-
for (auto &ArgLoc :
1059-
Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1)) {
1060-
if (ArgLoc.getArgument().isDependent()) {
1061-
Dependent = true;
1062-
break;
1063-
}
1064-
}
1065-
}
1056+
bool Dependent =
1057+
Constraint->getTemplateArgsAsWritten() &&
1058+
TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
1059+
Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1));
10661060
TypeConstraintInfo.setInt(Dependent ? 1 : 0);
10671061
}
10681062

10691063
concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) :
1070-
Requirement(RK_Type, T->getType()->isDependentType(),
1064+
Requirement(RK_Type, T->getType()->isInstantiationDependentType(),
10711065
T->getType()->containsUnexpandedParameterPack(),
10721066
// We reach this ctor with either dependent types (in which
10731067
// IsSatisfied doesn't matter) or with non-dependent type in
10741068
// which the existence of the type indicates satisfaction.
1075-
/*IsSatisfied=*/true
1076-
), Value(T),
1077-
Status(T->getType()->isDependentType() ? SS_Dependent : SS_Satisfied) {}
1069+
/*IsSatisfied=*/true),
1070+
Value(T),
1071+
Status(T->getType()->isInstantiationDependentType() ? SS_Dependent
1072+
: SS_Satisfied) {}

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9516,12 +9516,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
95169516
// that either the specialized function type or the specialized
95179517
// template is dependent, and therefore matching will fail. In
95189518
// this case, don't check the specialization yet.
9519-
bool InstantiationDependent = false;
95209519
if (isFunctionTemplateSpecialization && isFriend &&
95219520
(NewFD->getType()->isDependentType() || DC->isDependentContext() ||
9522-
TemplateSpecializationType::anyDependentTemplateArguments(
9523-
TemplateArgs,
9524-
InstantiationDependent))) {
9521+
TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
9522+
TemplateArgs.arguments()))) {
95259523
assert(HasExplicitTemplateArgs &&
95269524
"friend function specialization without template args");
95279525
if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs,

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3661,7 +3661,6 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
36613661

36623662
QualType CanonType;
36633663

3664-
bool InstantiationDependent = false;
36653664
if (TypeAliasTemplateDecl *AliasTemplate =
36663665
dyn_cast<TypeAliasTemplateDecl>(Template)) {
36673666

@@ -3724,7 +3723,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
37243723
}
37253724
} else if (Name.isDependent() ||
37263725
TemplateSpecializationType::anyDependentTemplateArguments(
3727-
TemplateArgs, InstantiationDependent)) {
3726+
TemplateArgs, Converted)) {
37283727
// This class template specialization is a dependent
37293728
// type. Therefore, its canonical type is another class template
37303729
// specialization type that contains all of the converted
@@ -4315,11 +4314,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
43154314

43164315
// FIXME: Move these checks to CheckTemplatePartialSpecializationArgs so we
43174316
// also do them during instantiation.
4318-
bool InstantiationDependent;
43194317
if (!Name.isDependent() &&
4320-
!TemplateSpecializationType::anyDependentTemplateArguments(
4321-
TemplateArgs.arguments(),
4322-
InstantiationDependent)) {
4318+
!TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
4319+
Converted)) {
43234320
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
43244321
<< VarTemplate->getDeclName();
43254322
IsPartialSpecialization = false;
@@ -4480,10 +4477,9 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
44804477
return true;
44814478

44824479
// Produce a placeholder value if the specialization is dependent.
4483-
bool InstantiationDependent = false;
44844480
if (Template->getDeclContext()->isDependentContext() ||
4485-
TemplateSpecializationType::anyDependentTemplateArguments(
4486-
TemplateArgs, InstantiationDependent))
4481+
TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
4482+
Converted))
44874483
return DeclResult();
44884484

44894485
// Find the variable template specialization declaration that
@@ -4669,22 +4665,16 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
46694665
return ExprError();
46704666

46714667
ConstraintSatisfaction Satisfaction;
4672-
bool AreArgsDependent = false;
4673-
for (TemplateArgument &Arg : Converted) {
4674-
if (Arg.isDependent()) {
4675-
AreArgsDependent = true;
4676-
break;
4677-
}
4678-
}
4668+
bool AreArgsDependent =
4669+
TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs,
4670+
Converted);
46794671
if (!AreArgsDependent &&
4680-
CheckConstraintSatisfaction(NamedConcept,
4681-
{NamedConcept->getConstraintExpr()},
4682-
Converted,
4683-
SourceRange(SS.isSet() ? SS.getBeginLoc() :
4684-
ConceptNameInfo.getLoc(),
4685-
TemplateArgs->getRAngleLoc()),
4686-
Satisfaction))
4687-
return ExprError();
4672+
CheckConstraintSatisfaction(
4673+
NamedConcept, {NamedConcept->getConstraintExpr()}, Converted,
4674+
SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
4675+
TemplateArgs->getRAngleLoc()),
4676+
Satisfaction))
4677+
return ExprError();
46884678

46894679
return ConceptSpecializationExpr::Create(Context,
46904680
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
@@ -8345,10 +8335,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
83458335

83468336
// FIXME: Move this to CheckTemplatePartialSpecializationArgs so we
83478337
// also do it during instantiation.
8348-
bool InstantiationDependent;
83498338
if (!Name.isDependent() &&
8350-
!TemplateSpecializationType::anyDependentTemplateArguments(
8351-
TemplateArgs.arguments(), InstantiationDependent)) {
8339+
!TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
8340+
Converted)) {
83528341
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
83538342
<< ClassTemplate->getDeclName();
83548343
isPartialSpecialization = false;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
2+
3+
namespace use_after_instantiation {
4+
template<int &R> struct A { static constexpr int &value = R; };
5+
6+
template<typename = void> auto S() {
7+
static int s;
8+
return A<s>{};
9+
}
10+
11+
auto &s = decltype(S())::value;
12+
13+
// This is ill-formed, but it should not crash.
14+
// FIXME: Right now, it does crash.
15+
// expected-no-diagnostics
16+
#if 0
17+
template<typename = void> auto T() {
18+
static int s;
19+
struct A {
20+
static constexpr int &value = s; // expected-error {{static}}
21+
};
22+
return A{};
23+
}
24+
25+
auto &t = decltype(T())::value;
26+
#endif
27+
}

0 commit comments

Comments
 (0)