Skip to content

Commit cfe331b

Browse files
authored
[clang] function template non-call partial ordering fixes (#106829)
This applies to function template non-call partial ordering the same provisional wording change applied in the call context: Don't perform the consistency check on return type and parameters which didn't have any template parameters deduced from. Fixes regression introduced in #100692, which was reported on the PR.
1 parent 2afa975 commit cfe331b

File tree

2 files changed

+181
-155
lines changed

2 files changed

+181
-155
lines changed

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 102 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,9 +1187,8 @@ class PackDeductionScope {
11871187

11881188
template <class T>
11891189
static TemplateDeductionResult DeduceForEachType(
1190-
Sema &S, TemplateParameterList *TemplateParams, const QualType *Params,
1191-
unsigned NumParams, const QualType *Args, unsigned NumArgs,
1192-
TemplateDeductionInfo &Info,
1190+
Sema &S, TemplateParameterList *TemplateParams, ArrayRef<QualType> Params,
1191+
ArrayRef<QualType> Args, TemplateDeductionInfo &Info,
11931192
SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool PartialOrdering,
11941193
bool FinishingDeduction, T &&DeductFunc) {
11951194
// C++0x [temp.deduct.type]p10:
@@ -1198,15 +1197,15 @@ static TemplateDeductionResult DeduceForEachType(
11981197
// corresponding parameter type Ai of the corresponding parameter-type-list
11991198
// of A. [...]
12001199
unsigned ArgIdx = 0, ParamIdx = 0;
1201-
for (; ParamIdx != NumParams; ++ParamIdx) {
1200+
for (; ParamIdx != Params.size(); ++ParamIdx) {
12021201
// Check argument types.
12031202
const PackExpansionType *Expansion
12041203
= dyn_cast<PackExpansionType>(Params[ParamIdx]);
12051204
if (!Expansion) {
12061205
// Simple case: compare the parameter and argument types at this point.
12071206

12081207
// Make sure we have an argument.
1209-
if (ArgIdx >= NumArgs)
1208+
if (ArgIdx >= Args.size())
12101209
return TemplateDeductionResult::MiscellaneousDeductionFailure;
12111210

12121211
if (isa<PackExpansionType>(Args[ArgIdx])) {
@@ -1243,8 +1242,8 @@ static TemplateDeductionResult DeduceForEachType(
12431242

12441243
// A pack scope with fixed arity is not really a pack any more, so is not
12451244
// a non-deduced context.
1246-
if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) {
1247-
for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) {
1245+
if (ParamIdx + 1 == Params.size() || PackScope.hasFixedArity()) {
1246+
for (; ArgIdx < Args.size() && PackScope.hasNextElement(); ++ArgIdx) {
12481247
// Deduce template arguments from the pattern.
12491248
if (TemplateDeductionResult Result = DeductFunc(
12501249
S, TemplateParams, ParamIdx, ArgIdx,
@@ -1274,7 +1273,7 @@ static TemplateDeductionResult DeduceForEachType(
12741273
// by the expansion.
12751274
std::optional<unsigned> NumExpansions = Expansion->getNumExpansions();
12761275
if (NumExpansions && !PackScope.isPartiallyExpanded()) {
1277-
for (unsigned I = 0; I != *NumExpansions && ArgIdx < NumArgs;
1276+
for (unsigned I = 0; I != *NumExpansions && ArgIdx < Args.size();
12781277
++I, ++ArgIdx)
12791278
PackScope.nextPackElement();
12801279
}
@@ -1293,12 +1292,12 @@ static TemplateDeductionResult DeduceForEachType(
12931292
// During partial ordering, if Ai was originally a function parameter pack:
12941293
// - if P does not contain a function parameter type corresponding to Ai then
12951294
// Ai is ignored;
1296-
if (PartialOrdering && ArgIdx + 1 == NumArgs &&
1295+
if (PartialOrdering && ArgIdx + 1 == Args.size() &&
12971296
isa<PackExpansionType>(Args[ArgIdx]))
12981297
return TemplateDeductionResult::Success;
12991298

13001299
// Make sure we don't have any extra arguments.
1301-
if (ArgIdx < NumArgs)
1300+
if (ArgIdx < Args.size())
13021301
return TemplateDeductionResult::MiscellaneousDeductionFailure;
13031302

13041303
return TemplateDeductionResult::Success;
@@ -1314,12 +1313,8 @@ static TemplateDeductionResult DeduceForEachType(
13141313
///
13151314
/// \param Params The list of parameter types
13161315
///
1317-
/// \param NumParams The number of types in \c Params
1318-
///
13191316
/// \param Args The list of argument types
13201317
///
1321-
/// \param NumArgs The number of types in \c Args
1322-
///
13231318
/// \param Info information about the template argument deduction itself
13241319
///
13251320
/// \param Deduced the deduced template arguments
@@ -1341,15 +1336,14 @@ static TemplateDeductionResult DeduceForEachType(
13411336
/// "success" result means that template argument deduction has not yet failed,
13421337
/// but it may still fail, later, for other reasons.
13431338
static TemplateDeductionResult DeduceTemplateArguments(
1344-
Sema &S, TemplateParameterList *TemplateParams, const QualType *Params,
1345-
unsigned NumParams, const QualType *Args, unsigned NumArgs,
1346-
TemplateDeductionInfo &Info,
1339+
Sema &S, TemplateParameterList *TemplateParams, ArrayRef<QualType> Params,
1340+
ArrayRef<QualType> Args, TemplateDeductionInfo &Info,
13471341
SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
13481342
bool PartialOrdering, bool *HasDeducedAnyParam,
13491343
llvm::SmallBitVector *HasDeducedParam) {
13501344
return ::DeduceForEachType(
1351-
S, TemplateParams, Params, NumParams, Args, NumArgs, Info, Deduced,
1352-
PartialOrdering, /*FinishingDeduction=*/false,
1345+
S, TemplateParams, Params, Args, Info, Deduced, PartialOrdering,
1346+
/*FinishingDeduction=*/false,
13531347
[&](Sema &S, TemplateParameterList *TemplateParams, int ParamIdx,
13541348
int ArgIdx, QualType P, QualType A, TemplateDeductionInfo &Info,
13551349
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
@@ -2028,9 +2022,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
20282022

20292023
// Check parameter types.
20302024
if (auto Result = DeduceTemplateArguments(
2031-
S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(),
2032-
FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced,
2033-
TDF & TDF_TopLevelParameterTypeList, PartialOrdering,
2025+
S, TemplateParams, FPP->param_types(), FPA->param_types(), Info,
2026+
Deduced, TDF & TDF_TopLevelParameterTypeList, PartialOrdering,
20342027
HasDeducedAnyParam, /*HasDeducedParam=*/nullptr);
20352028
Result != TemplateDeductionResult::Success)
20362029
return Result;
@@ -5623,135 +5616,109 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc,
56235616
FunctionTemplateDecl *FT1,
56245617
FunctionTemplateDecl *FT2,
56255618
TemplatePartialOrderingContext TPOC,
5626-
bool Reversed,
5627-
const SmallVector<QualType> &Args1,
5628-
const SmallVector<QualType> &Args2) {
5629-
assert(!Reversed || TPOC == TPOC_Call);
5630-
5619+
ArrayRef<QualType> Args1,
5620+
ArrayRef<QualType> Args2) {
56315621
FunctionDecl *FD1 = FT1->getTemplatedDecl();
56325622
FunctionDecl *FD2 = FT2->getTemplatedDecl();
56335623
const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
56345624
const FunctionProtoType *Proto2 = FD2->getType()->getAs<FunctionProtoType>();
5635-
56365625
assert(Proto1 && Proto2 && "Function templates must have prototypes");
5637-
TemplateParameterList *TemplateParams = FT2->getTemplateParameters();
5638-
SmallVector<DeducedTemplateArgument, 4> Deduced;
5639-
Deduced.resize(TemplateParams->size());
56405626

5641-
// C++0x [temp.deduct.partial]p3:
5627+
// C++26 [temp.deduct.partial]p3:
56425628
// The types used to determine the ordering depend on the context in which
56435629
// the partial ordering is done:
5644-
TemplateDeductionInfo Info(Loc);
5645-
switch (TPOC) {
5646-
case TPOC_Call: {
5647-
llvm::SmallBitVector HasDeducedParam(Args2.size());
5648-
if (DeduceTemplateArguments(
5649-
S, TemplateParams, Args2.data(), Args2.size(), Args1.data(),
5650-
Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true,
5651-
/*HasDeducedAnyParam=*/nullptr,
5652-
&HasDeducedParam) != TemplateDeductionResult::Success)
5653-
return false;
5630+
// - In the context of a function call, the types used are those function
5631+
// parameter types for which the function call has arguments.
5632+
// - In the context of a call to a conversion operator, the return types
5633+
// of the conversion function templates are used.
5634+
// - In other contexts (14.6.6.2) the function template's function type
5635+
// is used.
5636+
5637+
if (TPOC == TPOC_Other) {
5638+
// We wouldn't be partial ordering these candidates if these didn't match.
5639+
assert(Proto1->getMethodQuals() == Proto2->getMethodQuals() &&
5640+
Proto1->getRefQualifier() == Proto2->getRefQualifier() &&
5641+
Proto1->isVariadic() == Proto2->isVariadic() &&
5642+
"shouldn't partial order functions with different qualifiers in a "
5643+
"context where the function type is used");
5644+
5645+
assert(Args1.empty() && Args2.empty() &&
5646+
"Only call context should have arguments");
5647+
Args1 = Proto1->getParamTypes();
5648+
Args2 = Proto2->getParamTypes();
5649+
}
56545650

5655-
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
5656-
Deduced.end());
5657-
Sema::InstantiatingTemplate Inst(
5658-
S, Info.getLocation(), FT2, DeducedArgs,
5659-
Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
5660-
if (Inst.isInvalid())
5661-
return false;
5651+
TemplateParameterList *TemplateParams = FT2->getTemplateParameters();
5652+
SmallVector<DeducedTemplateArgument, 4> Deduced(TemplateParams->size());
5653+
TemplateDeductionInfo Info(Loc);
56625654

5663-
bool AtLeastAsSpecialized = true;
5664-
S.runWithSufficientStackSpace(Info.getLocation(), [&] {
5665-
AtLeastAsSpecialized =
5666-
::FinishTemplateArgumentDeduction(
5667-
S, FT2, Deduced, Info,
5668-
[&](Sema &S, FunctionTemplateDecl *FTD,
5669-
ArrayRef<TemplateArgument> DeducedArgs) {
5670-
return ::DeduceForEachType(
5671-
S, TemplateParams, Args2.data(), Args2.size(), Args1.data(),
5672-
Args1.size(), Info, Deduced,
5673-
/*PartialOrdering=*/true, /*FinishingDeduction=*/true,
5674-
[&](Sema &S, TemplateParameterList *, int ParamIdx,
5675-
int ArgIdx, QualType P, QualType A,
5676-
TemplateDeductionInfo &Info,
5677-
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
5678-
bool) {
5679-
// As a provisional fix for a core issue that does not
5680-
// exist yet, only check the consistency of parameters
5681-
// which participated in deduction. We still try to
5682-
// substitute them though.
5683-
return ::CheckDeductionConsistency(
5684-
S, FTD, ArgIdx, P, A, DeducedArgs,
5685-
HasDeducedParam[ParamIdx]);
5686-
});
5687-
}) == TemplateDeductionResult::Success;
5688-
});
5689-
if (!AtLeastAsSpecialized)
5690-
return false;
5691-
} break;
5692-
case TPOC_Conversion:
5693-
case TPOC_Other: {
5694-
// - In the context of a call to a conversion operator, the return types
5695-
// of the conversion function templates are used.
5696-
// - In other contexts (14.6.6.2) the function template's function type
5697-
// is used.
5698-
auto [A, P, TDF] = TPOC == TPOC_Other
5699-
? std::make_tuple(FD1->getType(), FD2->getType(),
5700-
TDF_AllowCompatibleFunctionType)
5701-
: std::make_tuple(Proto1->getReturnType(),
5702-
Proto2->getReturnType(), TDF_None);
5655+
bool HasDeducedAnyParamFromReturnType = false;
5656+
if (TPOC != TPOC_Call) {
57035657
if (DeduceTemplateArgumentsByTypeMatch(
5704-
S, TemplateParams, P, A, Info, Deduced, TDF,
5658+
S, TemplateParams, Proto2->getReturnType(), Proto1->getReturnType(),
5659+
Info, Deduced, TDF_None,
57055660
/*PartialOrdering=*/true, /*DeducedFromArrayBound=*/false,
5706-
/*HasDeducedAnyParam=*/nullptr) != TemplateDeductionResult::Success)
5661+
&HasDeducedAnyParamFromReturnType) !=
5662+
TemplateDeductionResult::Success)
57075663
return false;
5664+
}
57085665

5709-
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
5710-
Deduced.end());
5711-
Sema::InstantiatingTemplate Inst(
5712-
S, Info.getLocation(), FT2, DeducedArgs,
5713-
Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
5714-
if (Inst.isInvalid())
5666+
llvm::SmallBitVector HasDeducedParam;
5667+
if (TPOC != TPOC_Conversion) {
5668+
HasDeducedParam.resize(Args2.size());
5669+
if (DeduceTemplateArguments(S, TemplateParams, Args2, Args1, Info, Deduced,
5670+
TDF_None, /*PartialOrdering=*/true,
5671+
/*HasDeducedAnyParam=*/nullptr,
5672+
&HasDeducedParam) !=
5673+
TemplateDeductionResult::Success)
57155674
return false;
5675+
}
57165676

5717-
bool AtLeastAsSpecialized;
5718-
S.runWithSufficientStackSpace(Info.getLocation(), [&] {
5719-
AtLeastAsSpecialized =
5720-
::FinishTemplateArgumentDeduction(
5721-
S, FT2, Deduced, Info,
5722-
[&](Sema &S, FunctionTemplateDecl *FTD,
5723-
ArrayRef<TemplateArgument> DeducedArgs) {
5677+
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
5678+
Sema::InstantiatingTemplate Inst(
5679+
S, Info.getLocation(), FT2, DeducedArgs,
5680+
Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
5681+
if (Inst.isInvalid())
5682+
return false;
5683+
5684+
bool AtLeastAsSpecialized;
5685+
S.runWithSufficientStackSpace(Info.getLocation(), [&] {
5686+
AtLeastAsSpecialized =
5687+
::FinishTemplateArgumentDeduction(
5688+
S, FT2, Deduced, Info,
5689+
[&](Sema &S, FunctionTemplateDecl *FTD,
5690+
ArrayRef<TemplateArgument> DeducedArgs) {
5691+
// As a provisional fix for a core issue that does not
5692+
// exist yet, which may be related to CWG2160, only check the
5693+
// consistency of parameters and return types which participated
5694+
// in deduction. We will still try to substitute them though.
5695+
if (TPOC != TPOC_Call) {
57245696
if (auto TDR = ::CheckDeductionConsistency(
57255697
S, FTD, /*ArgIdx=*/-1, Proto2->getReturnType(),
57265698
Proto1->getReturnType(), DeducedArgs,
5727-
/*CheckConsistency=*/true);
5699+
/*CheckConsistency=*/HasDeducedAnyParamFromReturnType);
57285700
TDR != TemplateDeductionResult::Success)
57295701
return TDR;
5702+
}
57305703

5731-
if (TPOC != TPOC_Conversion)
5732-
return TemplateDeductionResult::Success;
5733-
5734-
return ::DeduceForEachType(
5735-
S, TemplateParams, Proto2->getParamTypes().data(),
5736-
Proto2->getParamTypes().size(),
5737-
Proto1->getParamTypes().data(),
5738-
Proto1->getParamTypes().size(), Info, Deduced,
5739-
/*PartialOrdering=*/true, /*FinishingDeduction=*/true,
5740-
[&](Sema &S, TemplateParameterList *, int ParamIdx,
5741-
int ArgIdx, QualType P, QualType A,
5742-
TemplateDeductionInfo &Info,
5743-
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
5744-
bool) {
5745-
return ::CheckDeductionConsistency(
5746-
S, FTD, ArgIdx, P, A, DeducedArgs,
5747-
/*CheckConsistency=*/true);
5748-
});
5749-
}) == TemplateDeductionResult::Success;
5750-
});
5751-
if (!AtLeastAsSpecialized)
5752-
return false;
5753-
} break;
5754-
}
5704+
if (TPOC == TPOC_Conversion)
5705+
return TemplateDeductionResult::Success;
5706+
5707+
return ::DeduceForEachType(
5708+
S, TemplateParams, Args2, Args1, Info, Deduced,
5709+
/*PartialOrdering=*/true, /*FinishingDeduction=*/true,
5710+
[&](Sema &S, TemplateParameterList *, int ParamIdx,
5711+
int ArgIdx, QualType P, QualType A,
5712+
TemplateDeductionInfo &Info,
5713+
SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool) {
5714+
return ::CheckDeductionConsistency(
5715+
S, FTD, ArgIdx, P, A, DeducedArgs,
5716+
/*CheckConsistency=*/HasDeducedParam[ParamIdx]);
5717+
});
5718+
}) == TemplateDeductionResult::Success;
5719+
});
5720+
if (!AtLeastAsSpecialized)
5721+
return false;
57555722

57565723
// C++0x [temp.deduct.partial]p11:
57575724
// In most cases, all template parameters must have values in order for
@@ -5907,11 +5874,13 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
59075874

59085875
if (Reversed)
59095876
std::reverse(Args2.begin(), Args2.end());
5877+
} else {
5878+
assert(!Reversed && "Only call context could have reversed arguments");
59105879
}
5911-
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, Reversed,
5912-
Args1, Args2);
5913-
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, Reversed,
5914-
Args2, Args1);
5880+
bool Better1 =
5881+
isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, Args1, Args2);
5882+
bool Better2 =
5883+
isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, Args2, Args1);
59155884
// C++ [temp.deduct.partial]p10:
59165885
// F is more specialized than G if F is at least as specialized as G and G
59175886
// is not at least as specialized as F.

0 commit comments

Comments
 (0)