erichkeane updated this revision to Diff 511753.
erichkeane added a comment.

Made changes as requested by Richard.  "SkipForInstantiation" needed to be 
added when we added levels, but I think this is something that probably needs 
to be looked at and removed in the future.

I also see the change that this means to fix is reverted, so 
@alexander-shaposhnikov : feel free to take this and integrated it into your 
patch if you'd like.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D147722/new/

https://reviews.llvm.org/D147722

Files:
  clang/include/clang/Sema/Template.h
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaTemplate/concepts.cpp

Index: clang/test/SemaTemplate/concepts.cpp
===================================================================
--- clang/test/SemaTemplate/concepts.cpp
+++ clang/test/SemaTemplate/concepts.cpp
@@ -825,3 +825,53 @@
   template<C<int> U> friend constexpr auto decltype(L<int>)::operator()() const;
 };
 } // namespace TemplateInsideNonTemplateClass
+
+namespace GH61959 {
+template <typename T0>
+concept C = (sizeof(T0) >= 4);
+
+template<typename...>
+struct Orig { };
+
+template<typename T>
+struct Orig<T> {
+  template<typename> requires C<T>
+  void f() { }
+
+  template<typename> requires true
+  void f() { }
+};
+
+template <typename...> struct Mod {};
+
+template <typename T1, typename T2>
+struct Mod<T1, T2> {
+  template <typename> requires C<T1>
+  constexpr static int f() { return 1; }
+
+  template <typename> requires C<T2>
+  constexpr static int f() { return 2; }
+};
+
+static_assert(Mod<int, char>::f<double>() == 1);
+static_assert(Mod<char, int>::f<double>() == 2);
+
+template<typename T>
+struct Outer {
+  template<typename ...>
+  struct Inner {};
+
+  template<typename U>
+  struct Inner<U> {
+    template<typename V>
+    void foo()  requires C<U> && C<T> && C<V>{}
+    template<typename V>
+    void foo()  requires true{}
+  };
+};
+
+void bar() {
+  Outer<int>::Inner<float> I;
+  I.foo<char>();
+}
+}
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -131,6 +131,38 @@
   return Response::Done();
 }
 
+Response HandlePartialClassTemplateSpec(
+    const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec,
+    MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) {
+  // We don't want the arguments from the Partial Specialization, since
+  // anything instantiating here cannot access the arguments from the
+  // specialized template anyway, so any substitution we would do with these
+  // partially specialized arguments would 'wrong' and confuse constraint
+  // instantiation. We only do this in the case of a constraint check, since
+  // code elsewhere actually uses these and replaces them later with what
+  // they mean.
+  // If we know this is the 'top level', we can replace this with an
+  // OuterRetainedLevel, else we have to generate a set of identity arguments.
+
+  // If this is the top-level template entity, we can just add a retained level
+  // and be done.
+  if (!PartialClassTemplSpec->getTemplateDepth()) {
+    if (!SkipForSpecialization)
+      Result.addOuterRetainedLevel();
+    return Response::Done();
+  }
+
+  // Else, we can replace this with an 'empty' level, and the checking will just
+  // alter the 'depth', since this we don't have the 'Index' for this level.
+  if (!SkipForSpecialization)
+    Result.addOuterTemplateArguments(
+        const_cast<ClassTemplatePartialSpecializationDecl *>(
+            PartialClassTemplSpec),
+        {}, /*Final=*/false);
+
+  return Response::UseNextDecl(PartialClassTemplSpec);
+}
+
 // Add template arguments from a class template instantiation.
 Response
 HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
@@ -310,6 +342,10 @@
     if (const auto *VarTemplSpec =
             dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) {
       R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization);
+    } else if (const auto *PartialClassTemplSpec =
+                   dyn_cast<ClassTemplatePartialSpecializationDecl>(CurDecl)) {
+      R = HandlePartialClassTemplateSpec(PartialClassTemplSpec, Result,
+                                         SkipForSpecialization);
     } else if (const auto *ClassTemplSpec =
                    dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) {
       R = HandleClassTemplateSpec(ClassTemplSpec, Result,
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2854,7 +2854,7 @@
 template <>
 bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>(
     ClassTemplatePartialSpecializationDecl *Spec) {
-  return !Spec->isClassScopeExplicitSpecialization();
+  return true;
 }
 
 template <typename TemplateDeclT>
@@ -2881,7 +2881,7 @@
   // not class-scope explicit specialization, so replace with Deduced Args
   // instead of adding to inner-most.
   if (NeedsReplacement)
-    MLTAL.replaceInnermostTemplateArguments(CanonicalDeducedArgs);
+    MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);
 
   if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
                                     Info.getLocation(),
Index: clang/include/clang/Sema/Template.h
===================================================================
--- clang/include/clang/Sema/Template.h
+++ clang/include/clang/Sema/Template.h
@@ -232,9 +232,21 @@
     /// Replaces the current 'innermost' level with the provided argument list.
     /// This is useful for type deduction cases where we need to get the entire
     /// list from the AST, but then add the deduced innermost list.
-    void replaceInnermostTemplateArguments(ArgList Args) {
-      assert(TemplateArgumentLists.size() > 0 && "Replacing in an empty list?");
-      TemplateArgumentLists[0].Args = Args;
+    void replaceInnermostTemplateArguments(Decl *AssociatedDecl, ArgList Args) {
+      assert((TemplateArgumentLists.size() > 0 || NumRetainedOuterLevels) &&
+             "Replacing in an empty list?");
+
+      if (TemplateArgumentLists.size() > 0) {
+        assert((TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() ||
+                TemplateArgumentLists[0].AssociatedDeclAndFinal.getPointer() ==
+                    AssociatedDecl) &&
+               "Trying to change incorrect declaration?");
+        TemplateArgumentLists[0].Args = Args;
+      } else {
+        --NumRetainedOuterLevels;
+        TemplateArgumentLists.push_back(
+            {{AssociatedDecl, /*Final=*/false}, Args});
+      }
     }
 
     /// Add an outermost level that we are not substituting. We have no
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to