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