[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