Skip to content

Commit 549216e

Browse files
committed
[Clang] Correct the order of substituted arguments in CTAD alias guides
We missed a case of type constraints referencing deduced template parameters when constructing a deduction guide for the type alias. This patch fixes the issue by swapping the order of constructing 'template arguments not appearing in the type alias parameters' and 'template arguments that are not yet deduced'.
1 parent 9190e1c commit 549216e

File tree

3 files changed

+75
-26
lines changed

3 files changed

+75
-26
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,7 @@ Bug Fixes to C++ Support
907907
(`LWG3929 <https://wg21.link/LWG3929>`__.) (#GH121278)
908908
- Clang now identifies unexpanded parameter packs within the type constraint on a non-type template parameter. (#GH88866)
909909
- Fixed an issue while resolving type of expression indexing into a pack of values of non-dependent type (#GH121242)
910+
- Fixed incorrect construction of template arguments for CTAD alias guides when type constraints are applied. (#GH122134)
910911

911912
Bug Fixes to AST Handling
912913
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaTemplateDeductionGuide.cpp

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
996996
F->getTemplateParameters()->size());
997997

998998
// FIXME: DeduceTemplateArguments stops immediately at the first
999-
// non-deducible template argument. However, this doesn't seem to casue
999+
// non-deducible template argument. However, this doesn't seem to cause
10001000
// issues for practice cases, we probably need to extend it to continue
10011001
// performing deduction for rest of arguments to align with the C++
10021002
// standard.
@@ -1053,25 +1053,6 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
10531053
TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
10541054
}
10551055
unsigned FirstUndeducedParamIdx = FPrimeTemplateParams.size();
1056-
// ...followed by the template parameters of f that were not deduced
1057-
// (including their default template arguments)
1058-
for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
1059-
auto *TP = F->getTemplateParameters()->getParam(FTemplateParamIdx);
1060-
MultiLevelTemplateArgumentList Args;
1061-
Args.setKind(TemplateSubstitutionKind::Rewrite);
1062-
// We take a shortcut here, it is ok to reuse the
1063-
// TemplateArgsForBuildingFPrime.
1064-
Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
1065-
NamedDecl *NewParam = transformTemplateParameter(
1066-
SemaRef, F->getDeclContext(), TP, Args, FPrimeTemplateParams.size(),
1067-
getDepthAndIndex(TP).first);
1068-
FPrimeTemplateParams.push_back(NewParam);
1069-
1070-
assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
1071-
"The argument must be null before setting");
1072-
TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
1073-
Context.getInjectedTemplateArg(NewParam);
1074-
}
10751056

10761057
// To form a deduction guide f' from f, we leverage clang's instantiation
10771058
// mechanism, we construct a template argument list where the template
@@ -1086,18 +1067,14 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
10861067
// 2) non-deduced template parameters of f: rebuild a
10871068
// template argument;
10881069
//
1089-
// 2) has been built already (when rebuilding the new template
1090-
// parameters), we now perform 1).
1070+
// We now perform 1), as case 2) might refer to substituted 1).
10911071
MultiLevelTemplateArgumentList Args;
10921072
Args.setKind(TemplateSubstitutionKind::Rewrite);
10931073
Args.addOuterTemplateArguments(TransformedDeducedAliasArgs);
10941074
for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
10951075
const auto &D = DeduceResults[Index];
10961076
if (D.isNull()) {
1097-
// 2): Non-deduced template parameter has been built already.
1098-
assert(!TemplateArgsForBuildingFPrime[Index].isNull() &&
1099-
"template arguments for non-deduced template parameters should "
1100-
"be been set!");
1077+
// 2): Non-deduced template parameters would be substituted later.
11011078
continue;
11021079
}
11031080
TemplateArgumentLoc Input =
@@ -1110,6 +1087,27 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
11101087
}
11111088
}
11121089

1090+
// Case 2)
1091+
// ...followed by the template parameters of f that were not deduced
1092+
// (including their default template arguments)
1093+
for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
1094+
auto *TP = F->getTemplateParameters()->getParam(FTemplateParamIdx);
1095+
MultiLevelTemplateArgumentList Args;
1096+
Args.setKind(TemplateSubstitutionKind::Rewrite);
1097+
// We take a shortcut here, it is ok to reuse the
1098+
// TemplateArgsForBuildingFPrime.
1099+
Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
1100+
NamedDecl *NewParam = transformTemplateParameter(
1101+
SemaRef, F->getDeclContext(), TP, Args, FPrimeTemplateParams.size(),
1102+
getDepthAndIndex(TP).first);
1103+
FPrimeTemplateParams.push_back(NewParam);
1104+
1105+
assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
1106+
"The argument must be null before setting");
1107+
TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
1108+
Context.getInjectedTemplateArg(NewParam);
1109+
}
1110+
11131111
auto *TemplateArgListForBuildingFPrime =
11141112
TemplateArgumentList::CreateCopy(Context, TemplateArgsForBuildingFPrime);
11151113
// Form the f' by substituting the template arguments into f.

clang/test/SemaTemplate/deduction-guide.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,3 +478,53 @@ A a{.f1 = {1}};
478478
// CHECK-NEXT: `-DeclRefExpr {{.+}} <col:10> 'int' NonTypeTemplateParm {{.+}} 'N' 'int'
479479

480480
} // namespace GH83368
481+
482+
namespace GH122134 {
483+
484+
template <class, class>
485+
concept Constraint = true;
486+
487+
template <class T, int> struct Struct {
488+
Struct(Constraint<T> auto) {}
489+
};
490+
491+
template <int N = 0> using Test = Struct<int, N>;
492+
493+
Test test(42);
494+
495+
// CHECK-LABEL: Dumping GH122134::<deduction guide for Test>:
496+
// CHECK-NEXT: FunctionTemplateDecl {{.*}} implicit <deduction guide for Test>
497+
// CHECK-NEXT: |-NonTypeTemplateParmDecl {{.*}} 'int' depth 0 index 0 N
498+
// CHECK-NEXT: | `-TemplateArgument {{.*}} expr '0'
499+
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 0
500+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} Concept {{.*}} 'Constraint' depth 0 index 1 auto:1
501+
// CHECK-NEXT: | `-ConceptSpecializationExpr {{.*}} 'bool' Concept {{.*}} 'Constraint'
502+
// CHECK-NEXT: | |-ImplicitConceptSpecializationDecl {{.*}}
503+
// CHECK-NEXT: | | |-TemplateArgument type 'type-parameter-0-1'
504+
// CHECK-NEXT: | | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent depth 0 index 1
505+
// CHECK-NEXT: | | `-TemplateArgument type 'int'
506+
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'int'
507+
// CHECK-NEXT: | |-TemplateArgument {{.*}} type 'auto:1':'type-parameter-0-1'
508+
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'auto:1' dependent depth 0 index 1
509+
// CHECK-NEXT: | | `-TemplateTypeParm {{.*}} 'auto:1'
510+
// CHECK-NEXT: | `-TemplateArgument {{.*}} type 'int'
511+
// CHECK-NEXT: | `-BuiltinType {{.*}} 'int'
512+
// CHECK-NEXT: |-TypeTraitExpr {{.*}} 'bool' __is_deducible
513+
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.*}} 'GH122134::Test' dependent
514+
// CHECK-NEXT: | | `-name: 'GH122134::Test'
515+
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.*}} Test
516+
// CHECK-NEXT: | `-TemplateSpecializationType {{.*}} 'Struct<int, N>' dependent
517+
// CHECK-NEXT: | |-name: 'Struct':'GH122134::Struct' qualified
518+
// CHECK-NEXT: | | `-ClassTemplateDecl {{.*}} Struct
519+
// CHECK-NEXT: | |-TemplateArgument type 'int'
520+
// CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} 'int' sugar class depth 0 index 0 T
521+
// CHECK-NEXT: | | |-FunctionTemplate {{.*}} '<deduction guide for Struct>'
522+
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'int'
523+
// CHECK-NEXT: | `-TemplateArgument expr 'N'
524+
// CHECK-NEXT: | `-SubstNonTypeTemplateParmExpr {{.*}} 'int'
525+
// CHECK-NEXT: | |-NonTypeTemplateParmDecl {{.*}} 'int' depth 0 index 1
526+
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'N' 'int'
527+
// CHECK-NEXT: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for Test> 'auto (auto:1) -> Struct<int, N>'
528+
// CHECK-NEXT: | `-ParmVarDecl {{.*}} 'auto:1'
529+
530+
} // namespace GH122134

0 commit comments

Comments
 (0)