[Clang] Fix the assertion condition after b8d1f3d6 (#132669)

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.
This commit is contained in:
Younan Zhang 2025-03-24 16:46:48 +08:00 committed by GitHub
parent ec9546d169
commit 38d71c9bdc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 65 additions and 20 deletions

View File

@ -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<ClassTemplateSpecializationDecl>(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<bool(const TemplateArgument &TA)> 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<TemplateArgument> DeducedArgs;
SmallVector<unsigned> NonDeducedTemplateParamsInFIndex;
// !!NOTE: DeduceResults respects the sequence of template parameters of

View File

@ -723,3 +723,51 @@ void test() { NewDeleteAllocator abc(42); } // expected-error {{no viable constr
// CHECK-NEXT: `-ParmVarDecl {{.+}} 'T'
} // namespace GH128691
namespace GH132616_DeductionGuide {
template <class T> struct A {
template <class U>
A(U);
};
template <typename>
struct B : A<int> {
using A::A;
};
template <class T>
B(T) -> B<T>;
B b(24);
// CHECK-LABEL: Dumping GH132616_DeductionGuide::<deduction guide for B>:
// CHECK-NEXT: FunctionTemplateDecl {{.+}} implicit <deduction guide for B>
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} typename depth 0 index 0
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} class depth 0 index 1 U
// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for B> 'auto (U) -> B<type-parameter-0-0>'
// CHECK-NEXT: `-ParmVarDecl {{.+}} 'U'
struct C {
template <class U>
C(U);
};
template <typename>
struct D : C {
using C::C;
};
template <class T>
D(T) -> D<T>;
D d(24);
// CHECK-LABEL: Dumping GH132616_DeductionGuide::<deduction guide for D>:
// CHECK-NEXT: FunctionTemplateDecl {{.+}} implicit <deduction guide for D>
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} typename depth 0 index 0
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} class depth 0 index 1 U
// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for D> 'auto (U) -> D<type-parameter-0-0>'
// CHECK-NEXT: `-ParmVarDecl {{.+}} 'U'
} // namespace GH132616_DeductionGuide