Skip to content

Commit 1481708

Browse files
committed
[clang] CTAD alias: fix transformation for require-clause expr Part2.
In the llvm#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 llvm#92596 Fixes llvm#92212
1 parent b6240c3 commit 1481708

File tree

3 files changed

+76
-6
lines changed

3 files changed

+76
-6
lines changed

clang/lib/Sema/SemaTemplate.cpp

+26-6
Original file line numberDiff line numberDiff line change
@@ -2779,6 +2779,7 @@ Expr *
27792779
buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
27802780
TypeAliasTemplateDecl *AliasTemplate,
27812781
ArrayRef<DeducedTemplateArgument> DeduceResults,
2782+
unsigned UndeducedTemplateParameterStartIndex,
27822783
Expr *IsDeducible) {
27832784
Expr *RC = F->getTemplateParameters()->getRequiresClause();
27842785
if (!RC)
@@ -2839,8 +2840,22 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
28392840

28402841
for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
28412842
const auto &D = DeduceResults[Index];
2842-
if (D.isNull())
2843+
if (D.isNull()) { // non-deduced template parameters of f
2844+
auto TP = F->getTemplateParameters()->getParam(Index);
2845+
MultiLevelTemplateArgumentList Args;
2846+
Args.setKind(TemplateSubstitutionKind::Rewrite);
2847+
Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
2848+
// Rebuild the template parameter with updated depth and index.
2849+
NamedDecl *NewParam = transformTemplateParameter(
2850+
SemaRef, F->getDeclContext(), TP, Args,
2851+
/*NewIndex=*/UndeducedTemplateParameterStartIndex++,
2852+
getTemplateParameterDepth(TP) + AdjustDepth);
2853+
2854+
assert(TemplateArgsForBuildingRC[Index].isNull());
2855+
TemplateArgsForBuildingRC[Index] = Context.getCanonicalTemplateArgument(
2856+
Context.getInjectedTemplateArg(NewParam));
28432857
continue;
2858+
}
28442859
TemplateArgumentLoc Input =
28452860
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
28462861
TemplateArgumentLoc Output;
@@ -2856,9 +2871,11 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
28562871
MultiLevelTemplateArgumentList ArgsForBuildingRC;
28572872
ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
28582873
ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
2859-
// For 2), if the underlying F is instantiated from a member template, we need
2860-
// the entire template argument list, as the constraint AST in the
2861-
// require-clause of F remains completely uninstantiated.
2874+
// For 2), if the underlying function template F is nested in a class template
2875+
// (either instantiated from an explicitly-written deduction guide, or
2876+
// synthesized from a constructor), we need the entire template argument list,
2877+
// as the constraint AST in the require-clause of F remains completely
2878+
// uninstantiated.
28622879
//
28632880
// For example:
28642881
// template <typename T> // depth 0
@@ -2881,7 +2898,8 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
28812898
// We add the outer template arguments which is [int] to the multi-level arg
28822899
// list to ensure that the occurrence U in `C<U>` will be replaced with int
28832900
// during the substitution.
2884-
if (F->getInstantiatedFromMemberTemplate()) {
2901+
if (F->getLexicalDeclContext()->getDeclKind() ==
2902+
clang::Decl::ClassTemplateSpecialization) {
28852903
auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
28862904
F, F->getLexicalDeclContext(),
28872905
/*Final=*/false, /*Innermost=*/std::nullopt,
@@ -3099,6 +3117,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
30993117
Context.getInjectedTemplateArg(NewParam));
31003118
TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
31013119
}
3120+
unsigned UndeducedTemplateParameterStartIndex = FPrimeTemplateParams.size();
31023121
// ...followed by the template parameters of f that were not deduced
31033122
// (including their default template arguments)
31043123
for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
@@ -3168,7 +3187,8 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
31683187
Expr *IsDeducible = buildIsDeducibleConstraint(
31693188
SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams);
31703189
Expr *RequiresClause = buildAssociatedConstraints(
3171-
SemaRef, F, AliasTemplate, DeduceResults, IsDeducible);
3190+
SemaRef, F, AliasTemplate, DeduceResults,
3191+
UndeducedTemplateParameterStartIndex, IsDeducible);
31723192

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

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

+25
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

+25
Original file line numberDiff line numberDiff line change
@@ -401,4 +401,29 @@ struct A1 {
401401
template <typename U>
402402
using AFoo = A1<int>::A2<int>::Foo<U>;
403403
AFoo case3(1);
404+
405+
// Case4: crashes on the constexpr evaluator due to the mixed-up index for the
406+
// template parameters `V`.
407+
template<class T, typename T2>
408+
struct Case4 {
409+
template<class V> requires C<V>
410+
Case4(V, T);
411+
};
412+
413+
template<class T2>
414+
using ACase4 = Case4<T2, T2>;
415+
ACase4 case4{0, 1};
416+
404417
} // namespace test24
418+
419+
namespace GH92212 {
420+
template<typename T, typename...Us>
421+
struct A{
422+
template<typename V> requires __is_same(V, int)
423+
A(V);
424+
};
425+
426+
template<typename...TS>
427+
using AA = A<int, TS...>;
428+
AA a{0};
429+
}

0 commit comments

Comments
 (0)