Skip to content

Commit b0b8d5b

Browse files
committed
[clang] CTAD alias: fix transformation for require-clause expr Part2.
In the #90961 fix, we miss a case where the undeduced template parameters of the underlying deduction guide is not transformed, which leaves incorrect depth/index information, and causes crash when evaluating the constraints. This patch fix this missing case. Fixes #92596 Fixes #92212
1 parent 79d6f52 commit b0b8d5b

File tree

3 files changed

+76
-6
lines changed

3 files changed

+76
-6
lines changed

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2743,6 +2743,7 @@ Expr *
27432743
buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
27442744
TypeAliasTemplateDecl *AliasTemplate,
27452745
ArrayRef<DeducedTemplateArgument> DeduceResults,
2746+
unsigned UndeducedTemplateParameterStartIndex,
27462747
Expr *IsDeducible) {
27472748
Expr *RC = F->getTemplateParameters()->getRequiresClause();
27482749
if (!RC)
@@ -2803,8 +2804,22 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
28032804

28042805
for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
28052806
const auto &D = DeduceResults[Index];
2806-
if (D.isNull())
2807+
if (D.isNull()) { // non-deduced template parameters of f
2808+
auto TP = F->getTemplateParameters()->getParam(Index);
2809+
MultiLevelTemplateArgumentList Args;
2810+
Args.setKind(TemplateSubstitutionKind::Rewrite);
2811+
Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
2812+
// Rebuild the template parameter with updated depth and index.
2813+
NamedDecl *NewParam = transformTemplateParameter(
2814+
SemaRef, F->getDeclContext(), TP, Args,
2815+
/*NewIndex=*/UndeducedTemplateParameterStartIndex++,
2816+
getTemplateParameterDepth(TP) + AdjustDepth);
2817+
2818+
assert(TemplateArgsForBuildingRC[Index].isNull());
2819+
TemplateArgsForBuildingRC[Index] = Context.getCanonicalTemplateArgument(
2820+
Context.getInjectedTemplateArg(NewParam));
28072821
continue;
2822+
}
28082823
TemplateArgumentLoc Input =
28092824
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
28102825
TemplateArgumentLoc Output;
@@ -2820,9 +2835,11 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
28202835
MultiLevelTemplateArgumentList ArgsForBuildingRC;
28212836
ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
28222837
ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
2823-
// For 2), if the underlying F is instantiated from a member template, we need
2824-
// the entire template argument list, as the constraint AST in the
2825-
// require-clause of F remains completely uninstantiated.
2838+
// For 2), if the underlying function template F is nested in a class template
2839+
// (either instantiated from an explicitly-written deduction guide, or
2840+
// synthesized from a constructor), we need the entire template argument list,
2841+
// as the constraint AST in the require-clause of F remains completely
2842+
// uninstantiated.
28262843
//
28272844
// For example:
28282845
// template <typename T> // depth 0
@@ -2845,7 +2862,8 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
28452862
// We add the outer template arguments which is [int] to the multi-level arg
28462863
// list to ensure that the occurrence U in `C<U>` will be replaced with int
28472864
// during the substitution.
2848-
if (F->getInstantiatedFromMemberTemplate()) {
2865+
if (F->getLexicalDeclContext()->getDeclKind() ==
2866+
clang::Decl::ClassTemplateSpecialization) {
28492867
auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
28502868
F, F->getLexicalDeclContext(),
28512869
/*Final=*/false, /*Innermost=*/std::nullopt,
@@ -3063,6 +3081,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
30633081
Context.getInjectedTemplateArg(NewParam));
30643082
TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
30653083
}
3084+
unsigned UndeducedTemplateParameterStartIndex = FPrimeTemplateParams.size();
30663085
// ...followed by the template parameters of f that were not deduced
30673086
// (including their default template arguments)
30683087
for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
@@ -3132,7 +3151,8 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
31323151
Expr *IsDeducible = buildIsDeducibleConstraint(
31333152
SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams);
31343153
Expr *RequiresClause = buildAssociatedConstraints(
3135-
SemaRef, F, AliasTemplate, DeduceResults, IsDeducible);
3154+
SemaRef, F, AliasTemplate, DeduceResults,
3155+
UndeducedTemplateParameterStartIndex, IsDeducible);
31363156

31373157
auto *FPrimeTemplateParamList = TemplateParameterList::Create(
31383158
Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),

clang/test/AST/ast-dump-ctad-alias.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,31 @@ Out2<double>::AInner t(1.0);
5353
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'double'
5454
// CHECK-NEXT: | `-ParmVarDecl {{.*}} 'double'
5555

56+
// GH92596
57+
template <typename T0>
58+
struct Out3 {
59+
template<class T1, typename T2>
60+
struct Foo {
61+
// Deduction guide: Foo(T1, T2, V) -> Foo<T1, T2, V>;
62+
template<class V> requires Concept<T0, V> // V in require clause of Foo deduction guide: depth 1, index: 2
63+
Foo(V, T1);
64+
};
65+
};
66+
template<class T3>
67+
using AFoo3 = Out3<int>::Foo<T3, T3>;
68+
AFoo3 afoo3{0, 1};
69+
// Verify occurrence V in the require-clause is transformed (depth: 1 => 0, index: 2 => 1) correctly.
70+
71+
// CHECK: FunctionTemplateDecl {{.*}} implicit <deduction guide for AFoo3>
72+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} class depth 0 index 0 T3
73+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} class depth 0 index 1 V
74+
// CHECK-NEXT: |-BinaryOperator {{.*}} '<dependent type>' '&&'
75+
// CHECK-NEXT: | |-UnresolvedLookupExpr {{.*}} '<dependent type>' lvalue (no ADL) = 'Concept'
76+
// CHECK-NEXT: | | |-TemplateArgument type 'int'
77+
// CHECK-NEXT: | | | `-BuiltinType {{.*}} 'int'
78+
// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-0-1'
79+
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent depth 0 index 1
80+
5681
template <typename... T1>
5782
struct Foo {
5883
Foo(T1...);

clang/test/SemaCXX/cxx20-ctad-type-alias.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,4 +414,29 @@ struct A1 {
414414
template <typename U>
415415
using AFoo = A1<int>::A2<int>::Foo<U>;
416416
AFoo case3(1);
417+
418+
// Case4: crashes on the constexpr evaluator due to the mixed-up index for the
419+
// template parameters `V`.
420+
template<class T, typename T2>
421+
struct Case4 {
422+
template<class V> requires C<V>
423+
Case4(V, T);
424+
};
425+
426+
template<class T2>
427+
using ACase4 = Case4<T2, T2>;
428+
ACase4 case4{0, 1};
429+
417430
} // namespace test24
431+
432+
namespace GH92212 {
433+
template<typename T, typename...Us>
434+
struct A{
435+
template<typename V> requires __is_same(V, int)
436+
A(V);
437+
};
438+
439+
template<typename...TS>
440+
using AA = A<int, TS...>;
441+
AA a{0};
442+
}

0 commit comments

Comments
 (0)