Skip to content

Commit e3ac79a

Browse files
zygoloidtstellar
authored andcommitted
Teach TreeTransform to substitute into resolved TemplateArguments.
This comes up when substituting into an already-substituted template argument during constraint satisfaction checking. (cherry picked from commit b20ab41)
1 parent 321d929 commit e3ac79a

File tree

2 files changed

+72
-47
lines changed

2 files changed

+72
-47
lines changed

clang/lib/Sema/TreeTransform.h

Lines changed: 38 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4022,50 +4022,8 @@ template<typename Derived>
40224022
void TreeTransform<Derived>::InventTemplateArgumentLoc(
40234023
const TemplateArgument &Arg,
40244024
TemplateArgumentLoc &Output) {
4025-
SourceLocation Loc = getDerived().getBaseLocation();
4026-
switch (Arg.getKind()) {
4027-
case TemplateArgument::Null:
4028-
llvm_unreachable("null template argument in TreeTransform");
4029-
break;
4030-
4031-
case TemplateArgument::Type:
4032-
Output = TemplateArgumentLoc(Arg,
4033-
SemaRef.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
4034-
4035-
break;
4036-
4037-
case TemplateArgument::Template:
4038-
case TemplateArgument::TemplateExpansion: {
4039-
NestedNameSpecifierLocBuilder Builder;
4040-
TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
4041-
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
4042-
Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc);
4043-
else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
4044-
Builder.MakeTrivial(SemaRef.Context, QTN->getQualifier(), Loc);
4045-
4046-
if (Arg.getKind() == TemplateArgument::Template)
4047-
Output = TemplateArgumentLoc(Arg,
4048-
Builder.getWithLocInContext(SemaRef.Context),
4049-
Loc);
4050-
else
4051-
Output = TemplateArgumentLoc(Arg,
4052-
Builder.getWithLocInContext(SemaRef.Context),
4053-
Loc, Loc);
4054-
4055-
break;
4056-
}
4057-
4058-
case TemplateArgument::Expression:
4059-
Output = TemplateArgumentLoc(Arg, Arg.getAsExpr());
4060-
break;
4061-
4062-
case TemplateArgument::Declaration:
4063-
case TemplateArgument::Integral:
4064-
case TemplateArgument::Pack:
4065-
case TemplateArgument::NullPtr:
4066-
Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo());
4067-
break;
4068-
}
4025+
Output = getSema().getTrivialTemplateArgumentLoc(
4026+
Arg, QualType(), getDerived().getBaseLocation());
40694027
}
40704028

40714029
template<typename Derived>
@@ -4075,12 +4033,45 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
40754033
const TemplateArgument &Arg = Input.getArgument();
40764034
switch (Arg.getKind()) {
40774035
case TemplateArgument::Null:
4078-
case TemplateArgument::Integral:
40794036
case TemplateArgument::Pack:
4080-
case TemplateArgument::Declaration:
4081-
case TemplateArgument::NullPtr:
40824037
llvm_unreachable("Unexpected TemplateArgument");
40834038

4039+
case TemplateArgument::Integral:
4040+
case TemplateArgument::NullPtr:
4041+
case TemplateArgument::Declaration: {
4042+
// Transform a resolved template argument straight to a resolved template
4043+
// argument. We get here when substituting into an already-substituted
4044+
// template type argument during concept satisfaction checking.
4045+
QualType T = Arg.getNonTypeTemplateArgumentType();
4046+
QualType NewT = getDerived().TransformType(T);
4047+
if (NewT.isNull())
4048+
return true;
4049+
4050+
ValueDecl *D = Arg.getKind() == TemplateArgument::Declaration
4051+
? Arg.getAsDecl()
4052+
: nullptr;
4053+
ValueDecl *NewD = D ? cast_or_null<ValueDecl>(getDerived().TransformDecl(
4054+
getDerived().getBaseLocation(), D))
4055+
: nullptr;
4056+
if (D && !NewD)
4057+
return true;
4058+
4059+
if (NewT == T && D == NewD)
4060+
Output = Input;
4061+
else if (Arg.getKind() == TemplateArgument::Integral)
4062+
Output = TemplateArgumentLoc(
4063+
TemplateArgument(getSema().Context, Arg.getAsIntegral(), NewT),
4064+
TemplateArgumentLocInfo());
4065+
else if (Arg.getKind() == TemplateArgument::NullPtr)
4066+
Output = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true),
4067+
TemplateArgumentLocInfo());
4068+
else
4069+
Output = TemplateArgumentLoc(TemplateArgument(NewD, NewT),
4070+
TemplateArgumentLocInfo());
4071+
4072+
return false;
4073+
}
4074+
40844075
case TemplateArgument::Type: {
40854076
TypeSourceInfo *DI = Input.getTypeSourceInfo();
40864077
if (!DI)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_cc1 -std=c++2a -verify %s
2+
3+
// When forming and checking satisfaction of atomic constraints, we will
4+
// substitute still-dependent template arguments into an expression, and later
5+
// substitute into the result. This creates some unique situations; check that
6+
// they work.
7+
8+
namespace SubstIntoResolvedTypeTemplateArg {
9+
template<int, class> struct X {};
10+
11+
template<class T> concept A = true;
12+
template<class T> concept B = sizeof(T) != 0;
13+
template<class T> concept C = B<X<1, T>>;
14+
15+
int f(A auto); // expected-note {{candidate}}
16+
int f(C auto); // expected-note {{candidate}}
17+
int k1 = f(0); // expected-error {{ambiguous}}
18+
19+
template<class T> concept D = A<T> && B<X<1, T>>;
20+
int f(D auto);
21+
int k2 = f(0); // ok
22+
23+
// The atomic constraint formed from B<X<(int)'\1', T>> is identical to the
24+
// one formed from C, even though the template arguments are written as
25+
// different expressions; the "equivalent" rules are used rather than the
26+
// "identical" rules when matching template arguments in concept-ids.
27+
template<class T> concept E = A<T> && B<X<(int)'\1', T>>;
28+
int g(C auto);
29+
int g(E auto); // expected-note {{candidate}}
30+
int k3 = g(0);
31+
32+
int g(D auto); // expected-note {{candidate}}
33+
int k4 = g(0); // expected-error {{ambiguous}}
34+
}

0 commit comments

Comments
 (0)