[llvm-branch-commits] [clang] e3ac79a - Teach TreeTransform to substitute into resolved TemplateArguments.
Tom Stellard via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Apr 14 20:33:41 PDT 2020
Author: Richard Smith
Date: 2020-04-14T20:32:00-07:00
New Revision: e3ac79a649056865d47815446a95503bd4bd8908
URL: https://github.com/llvm/llvm-project/commit/e3ac79a649056865d47815446a95503bd4bd8908
DIFF: https://github.com/llvm/llvm-project/commit/e3ac79a649056865d47815446a95503bd4bd8908.diff
LOG: 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 b20ab412bf838a8a87e5cc1c8c6399c3c9255354)
Added:
clang/test/SemaTemplate/subst-into-subst.cpp
Modified:
clang/lib/Sema/TreeTransform.h
Removed:
################################################################################
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 0305954a278e..30fb089742ee 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4022,50 +4022,8 @@ template<typename Derived>
void TreeTransform<Derived>::InventTemplateArgumentLoc(
const TemplateArgument &Arg,
TemplateArgumentLoc &Output) {
- SourceLocation Loc = getDerived().getBaseLocation();
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- llvm_unreachable("null template argument in TreeTransform");
- break;
-
- case TemplateArgument::Type:
- Output = TemplateArgumentLoc(Arg,
- SemaRef.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
-
- break;
-
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion: {
- NestedNameSpecifierLocBuilder Builder;
- TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
- if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
- Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc);
- else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
- Builder.MakeTrivial(SemaRef.Context, QTN->getQualifier(), Loc);
-
- if (Arg.getKind() == TemplateArgument::Template)
- Output = TemplateArgumentLoc(Arg,
- Builder.getWithLocInContext(SemaRef.Context),
- Loc);
- else
- Output = TemplateArgumentLoc(Arg,
- Builder.getWithLocInContext(SemaRef.Context),
- Loc, Loc);
-
- break;
- }
-
- case TemplateArgument::Expression:
- Output = TemplateArgumentLoc(Arg, Arg.getAsExpr());
- break;
-
- case TemplateArgument::Declaration:
- case TemplateArgument::Integral:
- case TemplateArgument::Pack:
- case TemplateArgument::NullPtr:
- Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo());
- break;
- }
+ Output = getSema().getTrivialTemplateArgumentLoc(
+ Arg, QualType(), getDerived().getBaseLocation());
}
template<typename Derived>
@@ -4075,12 +4033,45 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
const TemplateArgument &Arg = Input.getArgument();
switch (Arg.getKind()) {
case TemplateArgument::Null:
- case TemplateArgument::Integral:
case TemplateArgument::Pack:
- case TemplateArgument::Declaration:
- case TemplateArgument::NullPtr:
llvm_unreachable("Unexpected TemplateArgument");
+ case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Declaration: {
+ // Transform a resolved template argument straight to a resolved template
+ // argument. We get here when substituting into an already-substituted
+ // template type argument during concept satisfaction checking.
+ QualType T = Arg.getNonTypeTemplateArgumentType();
+ QualType NewT = getDerived().TransformType(T);
+ if (NewT.isNull())
+ return true;
+
+ ValueDecl *D = Arg.getKind() == TemplateArgument::Declaration
+ ? Arg.getAsDecl()
+ : nullptr;
+ ValueDecl *NewD = D ? cast_or_null<ValueDecl>(getDerived().TransformDecl(
+ getDerived().getBaseLocation(), D))
+ : nullptr;
+ if (D && !NewD)
+ return true;
+
+ if (NewT == T && D == NewD)
+ Output = Input;
+ else if (Arg.getKind() == TemplateArgument::Integral)
+ Output = TemplateArgumentLoc(
+ TemplateArgument(getSema().Context, Arg.getAsIntegral(), NewT),
+ TemplateArgumentLocInfo());
+ else if (Arg.getKind() == TemplateArgument::NullPtr)
+ Output = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true),
+ TemplateArgumentLocInfo());
+ else
+ Output = TemplateArgumentLoc(TemplateArgument(NewD, NewT),
+ TemplateArgumentLocInfo());
+
+ return false;
+ }
+
case TemplateArgument::Type: {
TypeSourceInfo *DI = Input.getTypeSourceInfo();
if (!DI)
diff --git a/clang/test/SemaTemplate/subst-into-subst.cpp b/clang/test/SemaTemplate/subst-into-subst.cpp
new file mode 100644
index 000000000000..69c4a837864d
--- /dev/null
+++ b/clang/test/SemaTemplate/subst-into-subst.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+// When forming and checking satisfaction of atomic constraints, we will
+// substitute still-dependent template arguments into an expression, and later
+// substitute into the result. This creates some unique situations; check that
+// they work.
+
+namespace SubstIntoResolvedTypeTemplateArg {
+ template<int, class> struct X {};
+
+ template<class T> concept A = true;
+ template<class T> concept B = sizeof(T) != 0;
+ template<class T> concept C = B<X<1, T>>;
+
+ int f(A auto); // expected-note {{candidate}}
+ int f(C auto); // expected-note {{candidate}}
+ int k1 = f(0); // expected-error {{ambiguous}}
+
+ template<class T> concept D = A<T> && B<X<1, T>>;
+ int f(D auto);
+ int k2 = f(0); // ok
+
+ // The atomic constraint formed from B<X<(int)'\1', T>> is identical to the
+ // one formed from C, even though the template arguments are written as
+ //
diff erent expressions; the "equivalent" rules are used rather than the
+ // "identical" rules when matching template arguments in concept-ids.
+ template<class T> concept E = A<T> && B<X<(int)'\1', T>>;
+ int g(C auto);
+ int g(E auto); // expected-note {{candidate}}
+ int k3 = g(0);
+
+ int g(D auto); // expected-note {{candidate}}
+ int k4 = g(0); // expected-error {{ambiguous}}
+}
More information about the llvm-branch-commits
mailing list