Skip to content

Commit 159aacb

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 7bb90d1 commit 159aacb

File tree

8 files changed

+97
-53
lines changed

8 files changed

+97
-53
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,8 @@ Resolutions to C++ Defect Reports
355355
(`CWG2351: void{} <https://cplusplus.github.io/CWG/issues/2351.html>`_).
356356

357357
- Clang now has improved resolution to CWG2398, allowing class templates to have
358-
default arguments deduced when partial ordering.
358+
default arguments deduced when partial ordering, and better backwards compatibility
359+
in overload resolution.
359360

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

clang/include/clang/Sema/Sema.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11678,7 +11678,8 @@ class Sema final : public SemaBase {
1167811678
SourceLocation RAngleLoc, unsigned ArgumentPackIndex,
1167911679
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1168011680
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
11681-
CheckTemplateArgumentKind CTAK);
11681+
CheckTemplateArgumentKind CTAK,
11682+
bool *MatchedPackOnParmToNonPackOnArg);
1168211683

1168311684
/// Check that the given template arguments can be provided to
1168411685
/// the given template, converting the arguments along the way.
@@ -11725,7 +11726,8 @@ class Sema final : public SemaBase {
1172511726
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1172611727
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
1172711728
bool UpdateArgsWithConversions = true,
11728-
bool *ConstraintsNotSatisfied = nullptr, bool PartialOrderingTTP = false);
11729+
bool *ConstraintsNotSatisfied = nullptr, bool PartialOrderingTTP = false,
11730+
bool *MatchedPackOnParmToNonPackOnArg = nullptr);
1172911731

1173011732
bool CheckTemplateTypeArgument(
1173111733
TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
@@ -11759,7 +11761,8 @@ class Sema final : public SemaBase {
1175911761
/// It returns true if an error occurred, and false otherwise.
1176011762
bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
1176111763
TemplateParameterList *Params,
11762-
TemplateArgumentLoc &Arg, bool IsDeduced);
11764+
TemplateArgumentLoc &Arg, bool IsDeduced,
11765+
bool *MatchedPackOnParmToNonPackOnArg);
1176311766

1176411767
void NoteTemplateLocation(const NamedDecl &Decl,
1176511768
std::optional<SourceRange> ParamRange = {});
@@ -12460,7 +12463,7 @@ class Sema final : public SemaBase {
1246012463
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
1246112464
TemplateParameterList *PParam, TemplateDecl *PArg, TemplateDecl *AArg,
1246212465
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
12463-
bool IsDeduced);
12466+
bool IsDeduced, bool *MatchedPackOnParmToNonPackOnArg);
1246412467

1246512468
/// Mark which template parameters are used in a given expression.
1246612469
///
@@ -13460,7 +13463,8 @@ class Sema final : public SemaBase {
1346013463
bool InstantiateClassTemplateSpecialization(
1346113464
SourceLocation PointOfInstantiation,
1346213465
ClassTemplateSpecializationDecl *ClassTemplateSpec,
13463-
TemplateSpecializationKind TSK, bool Complain = true);
13466+
TemplateSpecializationKind TSK, bool Complain = true,
13467+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false);
1346413468

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

clang/include/clang/Sema/TemplateDeduction.h

Lines changed: 13 additions & 0 deletions
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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3675,7 +3675,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
36753675
TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
36763676
if (CheckTemplateArgument(
36773677
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
3678-
0, SugaredChecked, CanonicalChecked, CTAK_Specified) ||
3678+
0, SugaredChecked, CanonicalChecked, CTAK_Specified,
3679+
/*MatchedPackOnParmToNonPackOnArg=*/nullptr) ||
36793680
Trap.hasErrorOccurred())
36803681
IsTemplate = false;
36813682
}

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5204,7 +5204,7 @@ bool Sema::CheckTemplateArgument(
52045204
unsigned ArgumentPackIndex,
52055205
SmallVectorImpl<TemplateArgument> &SugaredConverted,
52065206
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
5207-
CheckTemplateArgumentKind CTAK) {
5207+
CheckTemplateArgumentKind CTAK, bool *MatchedPackOnParmToNonPackOnArg) {
52085208
// Check template type parameters.
52095209
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
52105210
return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
@@ -5420,7 +5420,8 @@ bool Sema::CheckTemplateArgument(
54205420
case TemplateArgument::Template:
54215421
case TemplateArgument::TemplateExpansion:
54225422
if (CheckTemplateTemplateArgument(TempParm, Params, Arg,
5423-
/*IsDeduced=*/CTAK != CTAK_Specified))
5423+
/*IsDeduced=*/CTAK != CTAK_Specified,
5424+
MatchedPackOnParmToNonPackOnArg))
54245425
return true;
54255426

54265427
SugaredConverted.push_back(Arg.getArgument());
@@ -5494,7 +5495,7 @@ bool Sema::CheckTemplateArgumentList(
54945495
SmallVectorImpl<TemplateArgument> &SugaredConverted,
54955496
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
54965497
bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied,
5497-
bool PartialOrderingTTP) {
5498+
bool PartialOrderingTTP, bool *MatchedPackOnParmToNonPackOnArg) {
54985499

54995500
if (ConstraintsNotSatisfied)
55005501
*ConstraintsNotSatisfied = false;
@@ -5570,10 +5571,10 @@ bool Sema::CheckTemplateArgumentList(
55705571

55715572
if (ArgIdx < NumArgs) {
55725573
// Check the template argument we were given.
5573-
if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
5574-
RAngleLoc, SugaredArgumentPack.size(),
5575-
SugaredConverted, CanonicalConverted,
5576-
CTAK_Specified))
5574+
if (CheckTemplateArgument(
5575+
*Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc,
5576+
SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted,
5577+
CTAK_Specified, MatchedPackOnParmToNonPackOnArg))
55775578
return true;
55785579

55795580
CanonicalConverted.back().setIsDefaulted(
@@ -5731,7 +5732,8 @@ bool Sema::CheckTemplateArgumentList(
57315732
// Check the default template argument.
57325733
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
57335734
SugaredConverted, CanonicalConverted,
5734-
CTAK_Specified))
5735+
CTAK_Specified,
5736+
/*MatchedPackOnParmToNonPackOnArg=*/nullptr))
57355737
return true;
57365738

57375739
SugaredConverted.back().setIsDefaulted(true);
@@ -7321,10 +7323,10 @@ static void DiagnoseTemplateParameterListArityMismatch(
73217323
Sema &S, TemplateParameterList *New, TemplateParameterList *Old,
73227324
Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc);
73237325

7324-
bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
7325-
TemplateParameterList *Params,
7326-
TemplateArgumentLoc &Arg,
7327-
bool IsDeduced) {
7326+
bool Sema::CheckTemplateTemplateArgument(
7327+
TemplateTemplateParmDecl *Param, TemplateParameterList *Params,
7328+
TemplateArgumentLoc &Arg, bool IsDeduced,
7329+
bool *MatchedPackOnParmToNonPackOnArg) {
73287330
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
73297331
auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
73307332
if (!Template) {
@@ -7368,7 +7370,8 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
73687370
// A template-argument matches a template template-parameter P when P
73697371
// is at least as specialized as the template-argument A.
73707372
if (!isTemplateTemplateParameterAtLeastAsSpecializedAs(
7371-
Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced))
7373+
Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced,
7374+
MatchedPackOnParmToNonPackOnArg))
73727375
return true;
73737376
// P2113
73747377
// C++20[temp.func.order]p2
@@ -9798,11 +9801,14 @@ DeclResult Sema::ActOnExplicitInstantiation(
97989801

97999802
// Check that the template argument list is well-formed for this
98009803
// template.
9804+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false;
98019805
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
9802-
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
9803-
/*DefaultArgs=*/{}, false, SugaredConverted,
9804-
CanonicalConverted,
9805-
/*UpdateArgsWithConversions=*/true))
9806+
if (CheckTemplateArgumentList(
9807+
ClassTemplate, TemplateNameLoc, TemplateArgs,
9808+
/*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted,
9809+
/*UpdateArgsWithConversions=*/true,
9810+
/*ConstraintsNotSatisfied=*/nullptr, /*PartialOrderingTTP=*/false,
9811+
&PrimaryHasMatchedPackOnParmToNonPackOnArg))
98069812
return true;
98079813

98089814
// Find the class template specialization declaration that
@@ -9923,7 +9929,9 @@ DeclResult Sema::ActOnExplicitInstantiation(
99239929
= cast_or_null<ClassTemplateSpecializationDecl>(
99249930
Specialization->getDefinition());
99259931
if (!Def)
9926-
InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
9932+
InstantiateClassTemplateSpecialization(
9933+
TemplateNameLoc, Specialization, TSK,
9934+
/*Complain=*/true, PrimaryHasMatchedPackOnParmToNonPackOnArg);
99279935
else if (TSK == TSK_ExplicitInstantiationDefinition) {
99289936
MarkVTableUsed(TemplateNameLoc, Specialization, true);
99299937
Specialization->setPointOfInstantiation(Def->getPointOfInstantiation());

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2773,8 +2773,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
27732773
for (; hasTemplateArgumentForDeduction(As, ArgIdx) &&
27742774
PackScope.hasNextElement();
27752775
++ArgIdx) {
2776-
if (!FoldPackParameter && !As[ArgIdx].isPackExpansion())
2777-
return TemplateDeductionResult::MiscellaneousDeductionFailure;
2776+
if (!As[ArgIdx].isPackExpansion()) {
2777+
if (!FoldPackParameter)
2778+
return TemplateDeductionResult::MiscellaneousDeductionFailure;
2779+
if (FoldPackArgument)
2780+
Info.setMatchedPackOnParmToNonPackOnArg();
2781+
}
27782782
// Deduce template arguments from the pattern.
27792783
if (auto Result = DeduceTemplateArguments(
27802784
S, TemplateParams, Pattern, As[ArgIdx], Info, PartialOrdering,
@@ -2968,15 +2972,20 @@ static bool ConvertDeducedTemplateArgument(
29682972
TemplateArgumentLoc ArgLoc = S.getTrivialTemplateArgumentLoc(
29692973
Arg, QualType(), Info.getLocation(), Param);
29702974

2975+
bool MatchedPackOnParmToNonPackOnArg = false;
29712976
// Check the template argument, converting it as necessary.
2972-
return S.CheckTemplateArgument(
2977+
auto Res = S.CheckTemplateArgument(
29732978
Param, ArgLoc, Template, Template->getLocation(),
29742979
Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput,
29752980
CanonicalOutput,
29762981
IsDeduced
29772982
? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound
29782983
: Sema::CTAK_Deduced)
2979-
: Sema::CTAK_Specified);
2984+
: Sema::CTAK_Specified,
2985+
&MatchedPackOnParmToNonPackOnArg);
2986+
if (MatchedPackOnParmToNonPackOnArg)
2987+
Info.setMatchedPackOnParmToNonPackOnArg();
2988+
return Res;
29802989
};
29812990

29822991
if (Arg.getKind() == TemplateArgument::Pack) {
@@ -3171,7 +3180,8 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
31713180
// Check whether we can actually use the default argument.
31723181
if (S.CheckTemplateArgument(
31733182
Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(),
3174-
0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) {
3183+
0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified,
3184+
/*MatchedPackOnParmToNonPackOnArg=*/nullptr)) {
31753185
Info.Param = makeTemplateParameter(
31763186
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
31773187
// FIXME: These template arguments are temporary. Free them!
@@ -3320,16 +3330,20 @@ FinishTemplateArgumentDeduction(
33203330
return TemplateDeductionResult::SubstitutionFailure;
33213331
}
33223332

3333+
bool MatchedPackOnParmToNonPackOnArg = false;
33233334
bool ConstraintsNotSatisfied;
33243335
SmallVector<TemplateArgument, 4> SugaredConvertedInstArgs,
33253336
CanonicalConvertedInstArgs;
33263337
if (S.CheckTemplateArgumentList(
33273338
Template, Partial->getLocation(), InstArgs, /*DefaultArgs=*/{}, false,
33283339
SugaredConvertedInstArgs, CanonicalConvertedInstArgs,
3329-
/*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied))
3340+
/*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied,
3341+
/*PartialOrderingTTP=*/false, &MatchedPackOnParmToNonPackOnArg))
33303342
return ConstraintsNotSatisfied
33313343
? TemplateDeductionResult::ConstraintsNotSatisfied
33323344
: TemplateDeductionResult::SubstitutionFailure;
3345+
if (MatchedPackOnParmToNonPackOnArg)
3346+
Info.setMatchedPackOnParmToNonPackOnArg();
33333347

33343348
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
33353349
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
@@ -6470,8 +6484,8 @@ bool Sema::isMoreSpecializedThanPrimary(
64706484

64716485
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
64726486
TemplateParameterList *P, TemplateDecl *PArg, TemplateDecl *AArg,
6473-
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
6474-
bool IsDeduced) {
6487+
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, bool IsDeduced,
6488+
bool *MatchedPackOnParmToNonPackOnArg) {
64756489
// C++1z [temp.arg.template]p4: (DR 150)
64766490
// A template template-parameter P is at least as specialized as a
64776491
// template template-argument A if, given the following rewrite to two
@@ -6521,11 +6535,11 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
65216535
// If the rewrite produces an invalid type, then P is not at least as
65226536
// specialized as A.
65236537
SmallVector<TemplateArgument, 4> CanonicalPArgs;
6524-
if (CheckTemplateArgumentList(AArg, ArgLoc, PArgList, DefaultArgs, false,
6525-
PArgs, CanonicalPArgs,
6526-
/*UpdateArgsWithConversions=*/true,
6527-
/*ConstraintsNotSatisfied=*/nullptr,
6528-
/*PartialOrderingTTP=*/true))
6538+
if (CheckTemplateArgumentList(
6539+
AArg, ArgLoc, PArgList, DefaultArgs, false, PArgs, CanonicalPArgs,
6540+
/*UpdateArgsWithConversions=*/true,
6541+
/*ConstraintsNotSatisfied=*/nullptr,
6542+
/*PartialOrderingTTP=*/true, MatchedPackOnParmToNonPackOnArg))
65296543
return false;
65306544
}
65316545

@@ -6551,6 +6565,9 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
65516565
IsDeduced ? PackFold::ArgumentToParameter : PackFold::Both,
65526566
/*HasDeducedAnyParam=*/nullptr)) {
65536567
case clang::TemplateDeductionResult::Success:
6568+
if (MatchedPackOnParmToNonPackOnArg &&
6569+
Info.hasMatchedPackOnParmToNonPackOnArg())
6570+
*MatchedPackOnParmToNonPackOnArg = true;
65546571
break;
65556572

65566573
case TemplateDeductionResult::MiscellaneousDeductionFailure:

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4054,11 +4054,11 @@ bool Sema::usesPartialOrExplicitSpecialization(
40544054
/// Get the instantiation pattern to use to instantiate the definition of a
40554055
/// given ClassTemplateSpecializationDecl (either the pattern of the primary
40564056
/// template or of a partial specialization).
4057-
static ActionResult<CXXRecordDecl *>
4058-
getPatternForClassTemplateSpecialization(
4057+
static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization(
40594058
Sema &S, SourceLocation PointOfInstantiation,
40604059
ClassTemplateSpecializationDecl *ClassTemplateSpec,
4061-
TemplateSpecializationKind TSK) {
4060+
TemplateSpecializationKind TSK,
4061+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg) {
40624062
Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec);
40634063
if (Inst.isInvalid())
40644064
return {/*Invalid=*/true};
@@ -4081,7 +4081,7 @@ getPatternForClassTemplateSpecialization(
40814081
// specialization with the template argument lists of the partial
40824082
// specializations.
40834083
typedef PartialSpecMatchResult MatchResult;
4084-
SmallVector<MatchResult, 4> Matched;
4084+
SmallVector<MatchResult, 4> Matched, ExtraMatched;
40854085
SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
40864086
Template->getPartialSpecializations(PartialSpecs);
40874087
TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
@@ -4111,11 +4111,13 @@ getPatternForClassTemplateSpecialization(
41114111
MakeDeductionFailureInfo(S.Context, Result, Info));
41124112
(void)Result;
41134113
} else {
4114-
Matched.push_back(PartialSpecMatchResult());
4115-
Matched.back().Partial = Partial;
4116-
Matched.back().Args = Info.takeCanonical();
4114+
auto &List =
4115+
Info.hasMatchedPackOnParmToNonPackOnArg() ? ExtraMatched : Matched;
4116+
List.push_back(MatchResult{Partial, Info.takeCanonical()});
41174117
}
41184118
}
4119+
if (Matched.empty() && PrimaryHasMatchedPackOnParmToNonPackOnArg)
4120+
Matched = std::move(ExtraMatched);
41194121

41204122
// If we're dealing with a member template where the template parameters
41214123
// have been instantiated, this provides the original template parameters
@@ -4218,16 +4220,18 @@ getPatternForClassTemplateSpecialization(
42184220
bool Sema::InstantiateClassTemplateSpecialization(
42194221
SourceLocation PointOfInstantiation,
42204222
ClassTemplateSpecializationDecl *ClassTemplateSpec,
4221-
TemplateSpecializationKind TSK, bool Complain) {
4223+
TemplateSpecializationKind TSK, bool Complain,
4224+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg) {
42224225
// Perform the actual instantiation on the canonical declaration.
42234226
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
42244227
ClassTemplateSpec->getCanonicalDecl());
42254228
if (ClassTemplateSpec->isInvalidDecl())
42264229
return true;
42274230

42284231
ActionResult<CXXRecordDecl *> Pattern =
4229-
getPatternForClassTemplateSpecialization(*this, PointOfInstantiation,
4230-
ClassTemplateSpec, TSK);
4232+
getPatternForClassTemplateSpecialization(
4233+
*this, PointOfInstantiation, ClassTemplateSpec, TSK,
4234+
PrimaryHasMatchedPackOnParmToNonPackOnArg);
42314235
if (!Pattern.isUsable())
42324236
return Pattern.isInvalid();
42334237

0 commit comments

Comments
 (0)