Skip to content

Commit aa01604

Browse files
committed
[clang] CWG2398: improve overload resolution backwards compat
With this change, we discriminate if the primary template and which partial specializations would have participated in overload resolution prior to P0522 changes. We collect those in an initial set. If this set is not empty, or the primary template would have matched, we proceed with this set as the candidates for overload resolution. Otherwise, we build a new overload set with everything else, and proceed as usual.
1 parent 439394d commit aa01604

File tree

8 files changed

+97
-53
lines changed

8 files changed

+97
-53
lines changed

clang/docs/ReleaseNotes.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ Resolutions to C++ Defect Reports
204204
(`CWG2351: void{} <https://cplusplus.github.io/CWG/issues/2351.html>`_).
205205

206206
- Clang now has improved resolution to CWG2398, allowing class templates to have
207-
default arguments deduced when partial ordering.
207+
default arguments deduced when partial ordering, and better backwards compatibility
208+
in overload resolution.
208209

209210
- Clang now allows comparing unequal object pointers that have been cast to ``void *``
210211
in constant expressions. These comparisons always worked in non-constant expressions.

clang/include/clang/Sema/Sema.h

+9-5
Original file line numberDiff line numberDiff line change
@@ -11637,7 +11637,8 @@ class Sema final : public SemaBase {
1163711637
SourceLocation RAngleLoc, unsigned ArgumentPackIndex,
1163811638
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1163911639
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
11640-
CheckTemplateArgumentKind CTAK);
11640+
CheckTemplateArgumentKind CTAK,
11641+
bool *MatchedPackOnParmToNonPackOnArg);
1164111642

1164211643
/// Check that the given template arguments can be provided to
1164311644
/// the given template, converting the arguments along the way.
@@ -11684,7 +11685,8 @@ class Sema final : public SemaBase {
1168411685
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1168511686
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
1168611687
bool UpdateArgsWithConversions = true,
11687-
bool *ConstraintsNotSatisfied = nullptr, bool PartialOrderingTTP = false);
11688+
bool *ConstraintsNotSatisfied = nullptr, bool PartialOrderingTTP = false,
11689+
bool *MatchedPackOnParmToNonPackOnArg = nullptr);
1168811690

1168911691
bool CheckTemplateTypeArgument(
1169011692
TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
@@ -11718,7 +11720,8 @@ class Sema final : public SemaBase {
1171811720
/// It returns true if an error occurred, and false otherwise.
1171911721
bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
1172011722
TemplateParameterList *Params,
11721-
TemplateArgumentLoc &Arg, bool IsDeduced);
11723+
TemplateArgumentLoc &Arg, bool IsDeduced,
11724+
bool *MatchedPackOnParmToNonPackOnArg);
1172211725

1172311726
void NoteTemplateLocation(const NamedDecl &Decl,
1172411727
std::optional<SourceRange> ParamRange = {});
@@ -12419,7 +12422,7 @@ class Sema final : public SemaBase {
1241912422
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
1242012423
TemplateParameterList *PParam, TemplateDecl *PArg, TemplateDecl *AArg,
1242112424
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
12422-
bool IsDeduced);
12425+
bool IsDeduced, bool *MatchedPackOnParmToNonPackOnArg);
1242312426

1242412427
/// Mark which template parameters are used in a given expression.
1242512428
///
@@ -13410,7 +13413,8 @@ class Sema final : public SemaBase {
1341013413
bool InstantiateClassTemplateSpecialization(
1341113414
SourceLocation PointOfInstantiation,
1341213415
ClassTemplateSpecializationDecl *ClassTemplateSpec,
13413-
TemplateSpecializationKind TSK, bool Complain = true);
13416+
TemplateSpecializationKind TSK, bool Complain = true,
13417+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false);
1341413418

1341513419
/// Instantiates the definitions of all of the member
1341613420
/// of the given class, which is an instantiation of a class template

clang/include/clang/Sema/TemplateDeduction.h

+13
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ class TemplateDeductionInfo {
5151
/// Have we suppressed an error during deduction?
5252
bool HasSFINAEDiagnostic = false;
5353

54+
/// Have we matched any packs on the parameter side, versus any non-packs on
55+
/// the argument side, in a context where the opposite matching is also
56+
/// allowed?
57+
bool MatchedPackOnParmToNonPackOnArg = false;
58+
5459
/// The template parameter depth for which we're performing deduction.
5560
unsigned DeducedDepth;
5661

@@ -87,6 +92,14 @@ class TemplateDeductionInfo {
8792
return DeducedDepth;
8893
}
8994

95+
bool hasMatchedPackOnParmToNonPackOnArg() const {
96+
return MatchedPackOnParmToNonPackOnArg;
97+
}
98+
99+
void setMatchedPackOnParmToNonPackOnArg() {
100+
MatchedPackOnParmToNonPackOnArg = true;
101+
}
102+
90103
/// Get the number of explicitly-specified arguments.
91104
unsigned getNumExplicitArgs() const {
92105
return ExplicitArgs;

clang/lib/Sema/SemaLookup.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -3666,7 +3666,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
36663666
TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
36673667
if (CheckTemplateArgument(
36683668
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
3669-
0, SugaredChecked, CanonicalChecked, CTAK_Specified) ||
3669+
0, SugaredChecked, CanonicalChecked, CTAK_Specified,
3670+
/*MatchedPackOnParmToNonPackOnArg=*/nullptr) ||
36703671
Trap.hasErrorOccurred())
36713672
IsTemplate = false;
36723673
}

clang/lib/Sema/SemaTemplate.cpp

+26-18
Original file line numberDiff line numberDiff line change
@@ -5175,7 +5175,7 @@ bool Sema::CheckTemplateArgument(
51755175
unsigned ArgumentPackIndex,
51765176
SmallVectorImpl<TemplateArgument> &SugaredConverted,
51775177
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
5178-
CheckTemplateArgumentKind CTAK) {
5178+
CheckTemplateArgumentKind CTAK, bool *MatchedPackOnParmToNonPackOnArg) {
51795179
// Check template type parameters.
51805180
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
51815181
return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
@@ -5391,7 +5391,8 @@ bool Sema::CheckTemplateArgument(
53915391
case TemplateArgument::Template:
53925392
case TemplateArgument::TemplateExpansion:
53935393
if (CheckTemplateTemplateArgument(TempParm, Params, Arg,
5394-
/*IsDeduced=*/CTAK != CTAK_Specified))
5394+
/*IsDeduced=*/CTAK != CTAK_Specified,
5395+
MatchedPackOnParmToNonPackOnArg))
53955396
return true;
53965397

53975398
SugaredConverted.push_back(Arg.getArgument());
@@ -5465,7 +5466,7 @@ bool Sema::CheckTemplateArgumentList(
54655466
SmallVectorImpl<TemplateArgument> &SugaredConverted,
54665467
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
54675468
bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied,
5468-
bool PartialOrderingTTP) {
5469+
bool PartialOrderingTTP, bool *MatchedPackOnParmToNonPackOnArg) {
54695470

54705471
if (ConstraintsNotSatisfied)
54715472
*ConstraintsNotSatisfied = false;
@@ -5541,10 +5542,10 @@ bool Sema::CheckTemplateArgumentList(
55415542

55425543
if (ArgIdx < NumArgs) {
55435544
// Check the template argument we were given.
5544-
if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
5545-
RAngleLoc, SugaredArgumentPack.size(),
5546-
SugaredConverted, CanonicalConverted,
5547-
CTAK_Specified))
5545+
if (CheckTemplateArgument(
5546+
*Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc,
5547+
SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted,
5548+
CTAK_Specified, MatchedPackOnParmToNonPackOnArg))
55485549
return true;
55495550

55505551
CanonicalConverted.back().setIsDefaulted(
@@ -5702,7 +5703,8 @@ bool Sema::CheckTemplateArgumentList(
57025703
// Check the default template argument.
57035704
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
57045705
SugaredConverted, CanonicalConverted,
5705-
CTAK_Specified))
5706+
CTAK_Specified,
5707+
/*MatchedPackOnParmToNonPackOnArg=*/nullptr))
57065708
return true;
57075709

57085710
SugaredConverted.back().setIsDefaulted(true);
@@ -7283,10 +7285,10 @@ static void DiagnoseTemplateParameterListArityMismatch(
72837285
Sema &S, TemplateParameterList *New, TemplateParameterList *Old,
72847286
Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc);
72857287

7286-
bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
7287-
TemplateParameterList *Params,
7288-
TemplateArgumentLoc &Arg,
7289-
bool IsDeduced) {
7288+
bool Sema::CheckTemplateTemplateArgument(
7289+
TemplateTemplateParmDecl *Param, TemplateParameterList *Params,
7290+
TemplateArgumentLoc &Arg, bool IsDeduced,
7291+
bool *MatchedPackOnParmToNonPackOnArg) {
72907292
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
72917293
auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
72927294
if (!Template) {
@@ -7330,7 +7332,8 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
73307332
// A template-argument matches a template template-parameter P when P
73317333
// is at least as specialized as the template-argument A.
73327334
if (!isTemplateTemplateParameterAtLeastAsSpecializedAs(
7333-
Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced))
7335+
Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced,
7336+
MatchedPackOnParmToNonPackOnArg))
73347337
return true;
73357338
// P2113
73367339
// C++20[temp.func.order]p2
@@ -9745,11 +9748,14 @@ DeclResult Sema::ActOnExplicitInstantiation(
97459748

97469749
// Check that the template argument list is well-formed for this
97479750
// template.
9751+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false;
97489752
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
9749-
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
9750-
/*DefaultArgs=*/{}, false, SugaredConverted,
9751-
CanonicalConverted,
9752-
/*UpdateArgsWithConversions=*/true))
9753+
if (CheckTemplateArgumentList(
9754+
ClassTemplate, TemplateNameLoc, TemplateArgs,
9755+
/*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted,
9756+
/*UpdateArgsWithConversions=*/true,
9757+
/*ConstraintsNotSatisfied=*/nullptr, /*PartialOrderingTTP=*/false,
9758+
&PrimaryHasMatchedPackOnParmToNonPackOnArg))
97539759
return true;
97549760

97559761
// Find the class template specialization declaration that
@@ -9870,7 +9876,9 @@ DeclResult Sema::ActOnExplicitInstantiation(
98709876
= cast_or_null<ClassTemplateSpecializationDecl>(
98719877
Specialization->getDefinition());
98729878
if (!Def)
9873-
InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
9879+
InstantiateClassTemplateSpecialization(
9880+
TemplateNameLoc, Specialization, TSK,
9881+
/*Complain=*/true, PrimaryHasMatchedPackOnParmToNonPackOnArg);
98749882
else if (TSK == TSK_ExplicitInstantiationDefinition) {
98759883
MarkVTableUsed(TemplateNameLoc, Specialization, true);
98769884
Specialization->setPointOfInstantiation(Def->getPointOfInstantiation());

clang/lib/Sema/SemaTemplateDeduction.cpp

+30-13
Original file line numberDiff line numberDiff line change
@@ -2767,8 +2767,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
27672767
for (; hasTemplateArgumentForDeduction(As, ArgIdx) &&
27682768
PackScope.hasNextElement();
27692769
++ArgIdx) {
2770-
if (!FoldPackParameter && !As[ArgIdx].isPackExpansion())
2771-
return TemplateDeductionResult::MiscellaneousDeductionFailure;
2770+
if (!As[ArgIdx].isPackExpansion()) {
2771+
if (!FoldPackParameter)
2772+
return TemplateDeductionResult::MiscellaneousDeductionFailure;
2773+
if (FoldPackArgument)
2774+
Info.setMatchedPackOnParmToNonPackOnArg();
2775+
}
27722776
// Deduce template arguments from the pattern.
27732777
if (auto Result = DeduceTemplateArguments(
27742778
S, TemplateParams, Pattern, As[ArgIdx], Info, PartialOrdering,
@@ -2962,15 +2966,20 @@ static bool ConvertDeducedTemplateArgument(
29622966
TemplateArgumentLoc ArgLoc = S.getTrivialTemplateArgumentLoc(
29632967
Arg, QualType(), Info.getLocation(), Param);
29642968

2969+
bool MatchedPackOnParmToNonPackOnArg = false;
29652970
// Check the template argument, converting it as necessary.
2966-
return S.CheckTemplateArgument(
2971+
auto Res = S.CheckTemplateArgument(
29672972
Param, ArgLoc, Template, Template->getLocation(),
29682973
Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput,
29692974
CanonicalOutput,
29702975
IsDeduced
29712976
? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound
29722977
: Sema::CTAK_Deduced)
2973-
: Sema::CTAK_Specified);
2978+
: Sema::CTAK_Specified,
2979+
&MatchedPackOnParmToNonPackOnArg);
2980+
if (MatchedPackOnParmToNonPackOnArg)
2981+
Info.setMatchedPackOnParmToNonPackOnArg();
2982+
return Res;
29742983
};
29752984

29762985
if (Arg.getKind() == TemplateArgument::Pack) {
@@ -3165,7 +3174,8 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
31653174
// Check whether we can actually use the default argument.
31663175
if (S.CheckTemplateArgument(
31673176
Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(),
3168-
0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) {
3177+
0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified,
3178+
/*MatchedPackOnParmToNonPackOnArg=*/nullptr)) {
31693179
Info.Param = makeTemplateParameter(
31703180
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
31713181
// FIXME: These template arguments are temporary. Free them!
@@ -3287,16 +3297,20 @@ FinishTemplateArgumentDeduction(
32873297
return TemplateDeductionResult::SubstitutionFailure;
32883298
}
32893299

3300+
bool MatchedPackOnParmToNonPackOnArg = false;
32903301
bool ConstraintsNotSatisfied;
32913302
SmallVector<TemplateArgument, 4> SugaredConvertedInstArgs,
32923303
CanonicalConvertedInstArgs;
32933304
if (S.CheckTemplateArgumentList(
32943305
Template, Partial->getLocation(), InstArgs, /*DefaultArgs=*/{}, false,
32953306
SugaredConvertedInstArgs, CanonicalConvertedInstArgs,
3296-
/*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied))
3307+
/*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied,
3308+
/*PartialOrderingTTP=*/false, &MatchedPackOnParmToNonPackOnArg))
32973309
return ConstraintsNotSatisfied
32983310
? TemplateDeductionResult::ConstraintsNotSatisfied
32993311
: TemplateDeductionResult::SubstitutionFailure;
3312+
if (MatchedPackOnParmToNonPackOnArg)
3313+
Info.setMatchedPackOnParmToNonPackOnArg();
33003314

33013315
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
33023316
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
@@ -6423,8 +6437,8 @@ bool Sema::isMoreSpecializedThanPrimary(
64236437

64246438
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
64256439
TemplateParameterList *P, TemplateDecl *PArg, TemplateDecl *AArg,
6426-
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
6427-
bool IsDeduced) {
6440+
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, bool IsDeduced,
6441+
bool *MatchedPackOnParmToNonPackOnArg) {
64286442
// C++1z [temp.arg.template]p4: (DR 150)
64296443
// A template template-parameter P is at least as specialized as a
64306444
// template template-argument A if, given the following rewrite to two
@@ -6476,11 +6490,11 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
64766490
// If the rewrite produces an invalid type, then P is not at least as
64776491
// specialized as A.
64786492
SmallVector<TemplateArgument, 4> CanonicalPArgs;
6479-
if (CheckTemplateArgumentList(AArg, ArgLoc, PArgList, DefaultArgs, false,
6480-
PArgs, CanonicalPArgs,
6481-
/*UpdateArgsWithConversions=*/true,
6482-
/*ConstraintsNotSatisfied=*/nullptr,
6483-
/*PartialOrderingTTP=*/true))
6493+
if (CheckTemplateArgumentList(
6494+
AArg, ArgLoc, PArgList, DefaultArgs, false, PArgs, CanonicalPArgs,
6495+
/*UpdateArgsWithConversions=*/true,
6496+
/*ConstraintsNotSatisfied=*/nullptr,
6497+
/*PartialOrderingTTP=*/true, MatchedPackOnParmToNonPackOnArg))
64846498
return false;
64856499
}
64866500

@@ -6506,6 +6520,9 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
65066520
IsDeduced ? PackFold::ArgumentToParameter : PackFold::Both,
65076521
/*HasDeducedAnyParam=*/nullptr)) {
65086522
case clang::TemplateDeductionResult::Success:
6523+
if (MatchedPackOnParmToNonPackOnArg &&
6524+
Info.hasMatchedPackOnParmToNonPackOnArg())
6525+
*MatchedPackOnParmToNonPackOnArg = true;
65096526
break;
65106527

65116528
case TemplateDeductionResult::MiscellaneousDeductionFailure:

clang/lib/Sema/SemaTemplateInstantiate.cpp

+14-10
Original file line numberDiff line numberDiff line change
@@ -4003,11 +4003,11 @@ bool Sema::usesPartialOrExplicitSpecialization(
40034003
/// Get the instantiation pattern to use to instantiate the definition of a
40044004
/// given ClassTemplateSpecializationDecl (either the pattern of the primary
40054005
/// template or of a partial specialization).
4006-
static ActionResult<CXXRecordDecl *>
4007-
getPatternForClassTemplateSpecialization(
4006+
static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization(
40084007
Sema &S, SourceLocation PointOfInstantiation,
40094008
ClassTemplateSpecializationDecl *ClassTemplateSpec,
4010-
TemplateSpecializationKind TSK) {
4009+
TemplateSpecializationKind TSK,
4010+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg) {
40114011
Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec);
40124012
if (Inst.isInvalid())
40134013
return {/*Invalid=*/true};
@@ -4030,7 +4030,7 @@ getPatternForClassTemplateSpecialization(
40304030
// specialization with the template argument lists of the partial
40314031
// specializations.
40324032
typedef PartialSpecMatchResult MatchResult;
4033-
SmallVector<MatchResult, 4> Matched;
4033+
SmallVector<MatchResult, 4> Matched, ExtraMatched;
40344034
SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
40354035
Template->getPartialSpecializations(PartialSpecs);
40364036
TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
@@ -4047,11 +4047,13 @@ getPatternForClassTemplateSpecialization(
40474047
MakeDeductionFailureInfo(S.Context, Result, Info));
40484048
(void)Result;
40494049
} else {
4050-
Matched.push_back(PartialSpecMatchResult());
4051-
Matched.back().Partial = Partial;
4052-
Matched.back().Args = Info.takeCanonical();
4050+
auto &List =
4051+
Info.hasMatchedPackOnParmToNonPackOnArg() ? ExtraMatched : Matched;
4052+
List.push_back(MatchResult{Partial, Info.takeCanonical()});
40534053
}
40544054
}
4055+
if (Matched.empty() && PrimaryHasMatchedPackOnParmToNonPackOnArg)
4056+
Matched = std::move(ExtraMatched);
40554057

40564058
// If we're dealing with a member template where the template parameters
40574059
// have been instantiated, this provides the original template parameters
@@ -4154,16 +4156,18 @@ getPatternForClassTemplateSpecialization(
41544156
bool Sema::InstantiateClassTemplateSpecialization(
41554157
SourceLocation PointOfInstantiation,
41564158
ClassTemplateSpecializationDecl *ClassTemplateSpec,
4157-
TemplateSpecializationKind TSK, bool Complain) {
4159+
TemplateSpecializationKind TSK, bool Complain,
4160+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg) {
41584161
// Perform the actual instantiation on the canonical declaration.
41594162
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
41604163
ClassTemplateSpec->getCanonicalDecl());
41614164
if (ClassTemplateSpec->isInvalidDecl())
41624165
return true;
41634166

41644167
ActionResult<CXXRecordDecl *> Pattern =
4165-
getPatternForClassTemplateSpecialization(*this, PointOfInstantiation,
4166-
ClassTemplateSpec, TSK);
4168+
getPatternForClassTemplateSpecialization(
4169+
*this, PointOfInstantiation, ClassTemplateSpec, TSK,
4170+
PrimaryHasMatchedPackOnParmToNonPackOnArg);
41674171
if (!Pattern.isUsable())
41684172
return Pattern.isInvalid();
41694173

0 commit comments

Comments
 (0)