Skip to content

Commit b20ab41

Browse files
committed
Teach TreeTransform to substitute into resolved TemplateArguments.
This comes up when substituting into an already-substituted template argument during constraint satisfaction checking.
1 parent 0e9368c commit b20ab41

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
@@ -4057,50 +4057,8 @@ template<typename Derived>
40574057
void TreeTransform<Derived>::InventTemplateArgumentLoc(
40584058
const TemplateArgument &Arg,
40594059
TemplateArgumentLoc &Output) {
4060-
SourceLocation Loc = getDerived().getBaseLocation();
4061-
switch (Arg.getKind()) {
4062-
case TemplateArgument::Null:
4063-
llvm_unreachable("null template argument in TreeTransform");
4064-
break;
4065-
4066-
case TemplateArgument::Type:
4067-
Output = TemplateArgumentLoc(Arg,
4068-
SemaRef.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
4069-
4070-
break;
4071-
4072-
case TemplateArgument::Template:
4073-
case TemplateArgument::TemplateExpansion: {
4074-
NestedNameSpecifierLocBuilder Builder;
4075-
TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
4076-
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
4077-
Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc);
4078-
else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
4079-
Builder.MakeTrivial(SemaRef.Context, QTN->getQualifier(), Loc);
4080-
4081-
if (Arg.getKind() == TemplateArgument::Template)
4082-
Output = TemplateArgumentLoc(Arg,
4083-
Builder.getWithLocInContext(SemaRef.Context),
4084-
Loc);
4085-
else
4086-
Output = TemplateArgumentLoc(Arg,
4087-
Builder.getWithLocInContext(SemaRef.Context),
4088-
Loc, Loc);
4089-
4090-
break;
4091-
}
4092-
4093-
case TemplateArgument::Expression:
4094-
Output = TemplateArgumentLoc(Arg, Arg.getAsExpr());
4095-
break;
4096-
4097-
case TemplateArgument::Declaration:
4098-
case TemplateArgument::Integral:
4099-
case TemplateArgument::Pack:
4100-
case TemplateArgument::NullPtr:
4101-
Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo());
4102-
break;
4103-
}
4060+
Output = getSema().getTrivialTemplateArgumentLoc(
4061+
Arg, QualType(), getDerived().getBaseLocation());
41044062
}
41054063

41064064
template<typename Derived>
@@ -4110,12 +4068,45 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
41104068
const TemplateArgument &Arg = Input.getArgument();
41114069
switch (Arg.getKind()) {
41124070
case TemplateArgument::Null:
4113-
case TemplateArgument::Integral:
41144071
case TemplateArgument::Pack:
4115-
case TemplateArgument::Declaration:
4116-
case TemplateArgument::NullPtr:
41174072
llvm_unreachable("Unexpected TemplateArgument");
41184073

4074+
case TemplateArgument::Integral:
4075+
case TemplateArgument::NullPtr:
4076+
case TemplateArgument::Declaration: {
4077+
// Transform a resolved template argument straight to a resolved template
4078+
// argument. We get here when substituting into an already-substituted
4079+
// template type argument during concept satisfaction checking.
4080+
QualType T = Arg.getNonTypeTemplateArgumentType();
4081+
QualType NewT = getDerived().TransformType(T);
4082+
if (NewT.isNull())
4083+
return true;
4084+
4085+
ValueDecl *D = Arg.getKind() == TemplateArgument::Declaration
4086+
? Arg.getAsDecl()
4087+
: nullptr;
4088+
ValueDecl *NewD = D ? cast_or_null<ValueDecl>(getDerived().TransformDecl(
4089+
getDerived().getBaseLocation(), D))
4090+
: nullptr;
4091+
if (D && !NewD)
4092+
return true;
4093+
4094+
if (NewT == T && D == NewD)
4095+
Output = Input;
4096+
else if (Arg.getKind() == TemplateArgument::Integral)
4097+
Output = TemplateArgumentLoc(
4098+
TemplateArgument(getSema().Context, Arg.getAsIntegral(), NewT),
4099+
TemplateArgumentLocInfo());
4100+
else if (Arg.getKind() == TemplateArgument::NullPtr)
4101+
Output = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true),
4102+
TemplateArgumentLocInfo());
4103+
else
4104+
Output = TemplateArgumentLoc(TemplateArgument(NewD, NewT),
4105+
TemplateArgumentLocInfo());
4106+
4107+
return false;
4108+
}
4109+
41194110
case TemplateArgument::Type: {
41204111
TypeSourceInfo *DI = Input.getTypeSourceInfo();
41214112
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)