From 38d71c9bdcf6b10c6fe02d5bd74fc8e6efb50a4d Mon Sep 17 00:00:00 2001 From: Younan Zhang Date: Mon, 24 Mar 2025 16:46:48 +0800 Subject: [PATCH] [Clang] Fix the assertion condition after b8d1f3d6 (#132669) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to the example provided by MagentaTreehouse, I realized the assertion I added in b8d1f3d6 didn't cover all valid cases like, when inheriting from a class template specialization, the source of a synthesized template parameter might be an implicit specialization, whose inner function template is thus living at depth 0, for which we don’t want it to overflow too. I've decided to remove that assertion because I don't think it's particularly useful: we're checking whether Depth = 0 parameters come from function templates whose parents contribute no template parameters to the depth, which is redundant given what the template depth already means. This also incorporates a drive-by fix for https://github.com/llvm/llvm-project/pull/132061#discussion_r2008756718, which I somehow missed. --- clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 37 +++++++------- clang/test/SemaTemplate/deduction-guide.cpp | 48 +++++++++++++++++++ 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 9cfdb7596b66..3b2129e0df81 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -376,12 +376,10 @@ struct ConvertConstructorToDeductionGuideTransform { if (NestedPattern) Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth()); auto [Depth, Index] = getDepthAndIndex(Param); - // Depth can still be 0 if FTD belongs to an explicit class template - // specialization with an empty template parameter list. In that case, - // we don't want the NewDepth to overflow, and it should remain 0. - assert(Depth || - cast(FTD->getDeclContext()) - ->isExplicitSpecialization()); + // Depth can be 0 if FTD belongs to a non-template class/a class + // template specialization with an empty template parameter list. In + // that case, we don't want the NewDepth to overflow, and it should + // remain 0. NamedDecl *NewParam = transformTemplateParameter( SemaRef, DC, Param, Args, Index + Depth1IndexAdjustment, Depth ? Depth - 1 : 0); @@ -970,6 +968,19 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) { return {Template, AliasRhsTemplateArgs}; } +bool IsNonDeducedArgument(const TemplateArgument &TA) { + // The following cases indicate the template argument is non-deducible: + // 1. The result is null. E.g. When it comes from a default template + // argument that doesn't appear in the alias declaration. + // 2. The template parameter is a pack and that cannot be deduced from + // the arguments within the alias declaration. + // Non-deducible template parameters will persist in the transformed + // deduction guide. + return TA.isNull() || + (TA.getKind() == TemplateArgument::Pack && + llvm::any_of(TA.pack_elements(), IsNonDeducedArgument)); +} + // Build deduction guides for a type alias template from the given underlying // deduction guide F. FunctionTemplateDecl * @@ -1033,20 +1044,6 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, AliasRhsTemplateArgs, TDeduceInfo, DeduceResults, /*NumberOfArgumentsMustMatch=*/false); - static std::function IsNonDeducedArgument = - [](const TemplateArgument &TA) { - // The following cases indicate the template argument is non-deducible: - // 1. The result is null. E.g. When it comes from a default template - // argument that doesn't appear in the alias declaration. - // 2. The template parameter is a pack and that cannot be deduced from - // the arguments within the alias declaration. - // Non-deducible template parameters will persist in the transformed - // deduction guide. - return TA.isNull() || - (TA.getKind() == TemplateArgument::Pack && - llvm::any_of(TA.pack_elements(), IsNonDeducedArgument)); - }; - SmallVector DeducedArgs; SmallVector NonDeducedTemplateParamsInFIndex; // !!NOTE: DeduceResults respects the sequence of template parameters of diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index ecd152abebd7..6db132ca37c7 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -723,3 +723,51 @@ void test() { NewDeleteAllocator abc(42); } // expected-error {{no viable constr // CHECK-NEXT: `-ParmVarDecl {{.+}} 'T' } // namespace GH128691 + +namespace GH132616_DeductionGuide { + +template struct A { + template + A(U); +}; + +template +struct B : A { + using A::A; +}; + +template +B(T) -> B; + +B b(24); + +// CHECK-LABEL: Dumping GH132616_DeductionGuide::: +// CHECK-NEXT: FunctionTemplateDecl {{.+}} implicit +// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} typename depth 0 index 0 +// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} class depth 0 index 1 U +// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit 'auto (U) -> B' +// CHECK-NEXT: `-ParmVarDecl {{.+}} 'U' + +struct C { + template + C(U); +}; + +template +struct D : C { + using C::C; +}; + +template +D(T) -> D; + +D d(24); + +// CHECK-LABEL: Dumping GH132616_DeductionGuide::: +// CHECK-NEXT: FunctionTemplateDecl {{.+}} implicit +// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} typename depth 0 index 0 +// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} class depth 0 index 1 U +// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit 'auto (U) -> D' +// CHECK-NEXT: `-ParmVarDecl {{.+}} 'U' + +} // namespace GH132616_DeductionGuide