Skip to content

Commit a27fe8c

Browse files
committed
[Sema]Substitue template parameter packs when deduced from function parameter
1 parent a315fb1 commit a27fe8c

File tree

1 file changed

+62
-1
lines changed

1 file changed

+62
-1
lines changed

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,7 @@ class PackDeductionScope {
730730
void addPack(unsigned Index) {
731731
// Save the deduced template argument for the parameter pack expanded
732732
// by this pack expansion, then clear out the deduction.
733+
DeducedFromEarlierParameter = !Deduced[Index].isNull();
733734
DeducedPack Pack(Index);
734735
Pack.Saved = Deduced[Index];
735736
Deduced[Index] = TemplateArgument();
@@ -858,6 +859,29 @@ class PackDeductionScope {
858859
Info.PendingDeducedPacks[Pack.Index] = Pack.Outer;
859860
}
860861

862+
std::optional<unsigned> getSavedPackSize(unsigned Index,
863+
TemplateArgument Pattern) const {
864+
865+
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
866+
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
867+
if (Unexpanded.size() == 0 ||
868+
Packs[0].Saved.getKind() != clang::TemplateArgument::Pack)
869+
return {};
870+
unsigned PackSize = Packs[0].Saved.pack_size();
871+
872+
if (std::all_of(Packs.begin() + 1, Packs.end(),
873+
[&PackSize](auto P) {
874+
return P.Saved.getKind() == TemplateArgument::Pack &&
875+
P.Saved.pack_size() == PackSize;
876+
}))
877+
return PackSize;
878+
return {};
879+
}
880+
881+
/// Determine whether this pack has already been deduced from a previous
882+
/// argument.
883+
bool isDeducedFromEarlierParameter() const {return DeducedFromEarlierParameter;}
884+
861885
/// Determine whether this pack has already been partially expanded into a
862886
/// sequence of (prior) function parameters / template arguments.
863887
bool isPartiallyExpanded() { return IsPartiallyExpanded; }
@@ -970,7 +994,6 @@ class PackDeductionScope {
970994
NewPack = Pack.DeferredDeduction;
971995
Result = checkDeducedTemplateArguments(S.Context, OldPack, NewPack);
972996
}
973-
974997
NamedDecl *Param = TemplateParams->getParam(Pack.Index);
975998
if (Result.isNull()) {
976999
Info.Param = makeTemplateParameter(Param);
@@ -1003,9 +1026,12 @@ class PackDeductionScope {
10031026
unsigned PackElements = 0;
10041027
bool IsPartiallyExpanded = false;
10051028
bool DeducePackIfNotAlreadyDeduced = false;
1029+
bool DeducedFromEarlierParameter = false;
1030+
10061031
/// The number of expansions, if we have a fully-expanded pack in this scope.
10071032
std::optional<unsigned> FixedNumExpansions;
10081033

1034+
10091035
SmallVector<DeducedPack, 2> Packs;
10101036
};
10111037

@@ -4371,6 +4397,41 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
43714397
// corresponding argument is a list?
43724398
PackScope.nextPackElement();
43734399
}
4400+
} else if (!IsTrailingPack && !PackScope.isPartiallyExpanded() &&
4401+
PackScope.isDeducedFromEarlierParameter() &&
4402+
!isa<PackExpansionType>(ParamTypes[ParamIdx + 1])) {
4403+
// [temp.deduct.general#3]
4404+
// When all template arguments have been deduced
4405+
// or obtained from default template arguments, all uses of template
4406+
// parameters in the template parameter list of the template are
4407+
// replaced with the corresponding deduced or default argument values
4408+
//
4409+
// If we have a trailing parameter pack, that has been deduced perviously
4410+
// we substitute the pack here in a similar fashion as seen above with
4411+
// the trailing parameter packs. The main difference here is that, in
4412+
// this case we are not processing all of the remaining arguments. We
4413+
// are only process as many arguments as much we have in the already
4414+
// deduced parameter.
4415+
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
4416+
collectUnexpandedParameterPacks(ParamPattern, Unexpanded);
4417+
if (Unexpanded.size() == 0)
4418+
continue;
4419+
4420+
std::optional<unsigned> ArgPosAfterSubstitution =
4421+
PackScope.getSavedPackSize(getDepthAndIndex(Unexpanded[0]).second,
4422+
ParamPattern);
4423+
if (!ArgPosAfterSubstitution)
4424+
continue;
4425+
4426+
unsigned PackArgEnd = ArgIdx + *ArgPosAfterSubstitution;
4427+
for (; ArgIdx < PackArgEnd && ArgIdx < Args.size(); ArgIdx++) {
4428+
ParamTypesForArgChecking.push_back(ParamPattern);
4429+
if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx,
4430+
/*ExplicitObjetArgument=*/false))
4431+
return Result;
4432+
4433+
PackScope.nextPackElement();
4434+
}
43744435
}
43754436
}
43764437

0 commit comments

Comments
 (0)