Skip to content

Commit b8d1f3d

Browse files
authored
[Clang] Fix an integer overflow issue in computing CTAD's parameter depth (llvm#128704)
There were some cases where we computed incorrect template parameter depths for synthesized CTAD, invalid as they might be, we still shouldn't crash anyway. Technically the only scenario in which the inner function template's depth is 0 is when it lives within an explicit template specialization, where the template parameter list is empty. Fixes llvm#128691
1 parent d8bcb53 commit b8d1f3d

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

clang/lib/Sema/SemaTemplateDeductionGuide.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,15 @@ struct ConvertConstructorToDeductionGuideTransform {
377377
if (NestedPattern)
378378
Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());
379379
auto [Depth, Index] = getDepthAndIndex(Param);
380+
// Depth can still be 0 if FTD belongs to an explicit class template
381+
// specialization with an empty template parameter list. In that case,
382+
// we don't want the NewDepth to overflow, and it should remain 0.
383+
assert(Depth ||
384+
cast<ClassTemplateSpecializationDecl>(FTD->getDeclContext())
385+
->isExplicitSpecialization());
380386
NamedDecl *NewParam = transformTemplateParameter(
381-
SemaRef, DC, Param, Args, Index + Depth1IndexAdjustment, Depth - 1);
387+
SemaRef, DC, Param, Args, Index + Depth1IndexAdjustment,
388+
Depth ? Depth - 1 : 0);
382389
if (!NewParam)
383390
return nullptr;
384391
// Constraints require that we substitute depth-1 arguments

clang/test/SemaTemplate/deduction-guide.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -691,3 +691,35 @@ Test test(42);
691691
// CHECK-NEXT: | `-ParmVarDecl {{.*}} 'auto:1'
692692

693693
} // namespace GH122134
694+
695+
namespace GH128691 {
696+
697+
template <typename = void>
698+
class NewDeleteAllocator;
699+
700+
template <>
701+
struct NewDeleteAllocator<> {
702+
template <typename T>
703+
NewDeleteAllocator(T); // expected-note {{candidate template ignored}} \
704+
// expected-note {{implicit deduction guide declared as}}
705+
};
706+
707+
template <typename>
708+
struct NewDeleteAllocator : NewDeleteAllocator<> { // expected-note {{candidate template ignored}} \
709+
// expected-note {{implicit deduction guide declared as}}
710+
using NewDeleteAllocator<>::NewDeleteAllocator;
711+
};
712+
713+
void test() { NewDeleteAllocator abc(42); } // expected-error {{no viable constructor or deduction guide}}
714+
715+
// CHECK-LABEL: Dumping GH128691::<deduction guide for NewDeleteAllocator>:
716+
// CHECK-NEXT: FunctionTemplateDecl {{.+}} <deduction guide for NewDeleteAllocator>
717+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} typename depth 0 index 0
718+
// CHECK-NEXT: | `-TemplateArgument type 'void'
719+
// CHECK-NEXT: | |-inherited from TemplateTypeParm {{.+}} depth 0 index 0
720+
// CHECK-NEXT: | `-BuiltinType {{.+}} 'void'
721+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} typename depth 0 index 1 T
722+
// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} <deduction guide for NewDeleteAllocator> 'auto (T) -> NewDeleteAllocator<type-parameter-0-0>'
723+
// CHECK-NEXT: `-ParmVarDecl {{.+}} 'T'
724+
725+
} // namespace GH128691

0 commit comments

Comments
 (0)