Skip to content

Commit e348747

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 6213aa5 commit e348747

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
@@ -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

Lines changed: 9 additions & 5 deletions
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
///
@@ -13418,7 +13421,8 @@ class Sema final : public SemaBase {
1341813421
bool InstantiateClassTemplateSpecialization(
1341913422
SourceLocation PointOfInstantiation,
1342013423
ClassTemplateSpecializationDecl *ClassTemplateSpec,
13421-
TemplateSpecializationKind TSK, bool Complain = true);
13424+
TemplateSpecializationKind TSK, bool Complain = true,
13425+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false);
1342213426

1342313427
/// Instantiates the definitions of all of the member
1342413428
/// 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
@@ -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

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5179,7 +5179,7 @@ bool Sema::CheckTemplateArgument(
51795179
unsigned ArgumentPackIndex,
51805180
SmallVectorImpl<TemplateArgument> &SugaredConverted,
51815181
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
5182-
CheckTemplateArgumentKind CTAK) {
5182+
CheckTemplateArgumentKind CTAK, bool *MatchedPackOnParmToNonPackOnArg) {
51835183
// Check template type parameters.
51845184
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
51855185
return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
@@ -5395,7 +5395,8 @@ bool Sema::CheckTemplateArgument(
53955395
case TemplateArgument::Template:
53965396
case TemplateArgument::TemplateExpansion:
53975397
if (CheckTemplateTemplateArgument(TempParm, Params, Arg,
5398-
/*IsDeduced=*/CTAK != CTAK_Specified))
5398+
/*IsDeduced=*/CTAK != CTAK_Specified,
5399+
MatchedPackOnParmToNonPackOnArg))
53995400
return true;
54005401

54015402
SugaredConverted.push_back(Arg.getArgument());
@@ -5469,7 +5470,7 @@ bool Sema::CheckTemplateArgumentList(
54695470
SmallVectorImpl<TemplateArgument> &SugaredConverted,
54705471
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
54715472
bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied,
5472-
bool PartialOrderingTTP) {
5473+
bool PartialOrderingTTP, bool *MatchedPackOnParmToNonPackOnArg) {
54735474

54745475
if (ConstraintsNotSatisfied)
54755476
*ConstraintsNotSatisfied = false;
@@ -5545,10 +5546,10 @@ bool Sema::CheckTemplateArgumentList(
55455546

55465547
if (ArgIdx < NumArgs) {
55475548
// Check the template argument we were given.
5548-
if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
5549-
RAngleLoc, SugaredArgumentPack.size(),
5550-
SugaredConverted, CanonicalConverted,
5551-
CTAK_Specified))
5549+
if (CheckTemplateArgument(
5550+
*Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc,
5551+
SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted,
5552+
CTAK_Specified, MatchedPackOnParmToNonPackOnArg))
55525553
return true;
55535554

55545555
CanonicalConverted.back().setIsDefaulted(
@@ -5706,7 +5707,8 @@ bool Sema::CheckTemplateArgumentList(
57065707
// Check the default template argument.
57075708
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
57085709
SugaredConverted, CanonicalConverted,
5709-
CTAK_Specified))
5710+
CTAK_Specified,
5711+
/*MatchedPackOnParmToNonPackOnArg=*/nullptr))
57105712
return true;
57115713

57125714
SugaredConverted.back().setIsDefaulted(true);
@@ -7289,10 +7291,10 @@ static void DiagnoseTemplateParameterListArityMismatch(
72897291
Sema &S, TemplateParameterList *New, TemplateParameterList *Old,
72907292
Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc);
72917293

7292-
bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
7293-
TemplateParameterList *Params,
7294-
TemplateArgumentLoc &Arg,
7295-
bool IsDeduced) {
7294+
bool Sema::CheckTemplateTemplateArgument(
7295+
TemplateTemplateParmDecl *Param, TemplateParameterList *Params,
7296+
TemplateArgumentLoc &Arg, bool IsDeduced,
7297+
bool *MatchedPackOnParmToNonPackOnArg) {
72967298
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
72977299
auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
72987300
if (!Template) {
@@ -7336,7 +7338,8 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
73367338
// A template-argument matches a template template-parameter P when P
73377339
// is at least as specialized as the template-argument A.
73387340
if (!isTemplateTemplateParameterAtLeastAsSpecializedAs(
7339-
Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced))
7341+
Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced,
7342+
MatchedPackOnParmToNonPackOnArg))
73407343
return true;
73417344
// P2113
73427345
// C++20[temp.func.order]p2
@@ -9754,11 +9757,14 @@ DeclResult Sema::ActOnExplicitInstantiation(
97549757

97559758
// Check that the template argument list is well-formed for this
97569759
// template.
9760+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false;
97579761
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
9758-
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
9759-
/*DefaultArgs=*/{}, false, SugaredConverted,
9760-
CanonicalConverted,
9761-
/*UpdateArgsWithConversions=*/true))
9762+
if (CheckTemplateArgumentList(
9763+
ClassTemplate, TemplateNameLoc, TemplateArgs,
9764+
/*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted,
9765+
/*UpdateArgsWithConversions=*/true,
9766+
/*ConstraintsNotSatisfied=*/nullptr, /*PartialOrderingTTP=*/false,
9767+
&PrimaryHasMatchedPackOnParmToNonPackOnArg))
97629768
return true;
97639769

97649770
// Find the class template specialization declaration that
@@ -9879,7 +9885,9 @@ DeclResult Sema::ActOnExplicitInstantiation(
98799885
= cast_or_null<ClassTemplateSpecializationDecl>(
98809886
Specialization->getDefinition());
98819887
if (!Def)
9882-
InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
9888+
InstantiateClassTemplateSpecialization(
9889+
TemplateNameLoc, Specialization, TSK,
9890+
/*Complain=*/true, PrimaryHasMatchedPackOnParmToNonPackOnArg);
98839891
else if (TSK == TSK_ExplicitInstantiationDefinition) {
98849892
MarkVTableUsed(TemplateNameLoc, Specialization, true);
98859893
Specialization->setPointOfInstantiation(Def->getPointOfInstantiation());

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 30 additions & 13 deletions
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!
@@ -3314,16 +3324,20 @@ FinishTemplateArgumentDeduction(
33143324
return TemplateDeductionResult::SubstitutionFailure;
33153325
}
33163326

3327+
bool MatchedPackOnParmToNonPackOnArg = false;
33173328
bool ConstraintsNotSatisfied;
33183329
SmallVector<TemplateArgument, 4> SugaredConvertedInstArgs,
33193330
CanonicalConvertedInstArgs;
33203331
if (S.CheckTemplateArgumentList(
33213332
Template, Partial->getLocation(), InstArgs, /*DefaultArgs=*/{}, false,
33223333
SugaredConvertedInstArgs, CanonicalConvertedInstArgs,
3323-
/*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied))
3334+
/*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied,
3335+
/*PartialOrderingTTP=*/false, &MatchedPackOnParmToNonPackOnArg))
33243336
return ConstraintsNotSatisfied
33253337
? TemplateDeductionResult::ConstraintsNotSatisfied
33263338
: TemplateDeductionResult::SubstitutionFailure;
3339+
if (MatchedPackOnParmToNonPackOnArg)
3340+
Info.setMatchedPackOnParmToNonPackOnArg();
33273341

33283342
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
33293343
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
@@ -6465,8 +6479,8 @@ bool Sema::isMoreSpecializedThanPrimary(
64656479

64666480
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
64676481
TemplateParameterList *P, TemplateDecl *PArg, TemplateDecl *AArg,
6468-
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
6469-
bool IsDeduced) {
6482+
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, bool IsDeduced,
6483+
bool *MatchedPackOnParmToNonPackOnArg) {
64706484
// C++1z [temp.arg.template]p4: (DR 150)
64716485
// A template template-parameter P is at least as specialized as a
64726486
// template template-argument A if, given the following rewrite to two
@@ -6518,11 +6532,11 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
65186532
// If the rewrite produces an invalid type, then P is not at least as
65196533
// specialized as A.
65206534
SmallVector<TemplateArgument, 4> CanonicalPArgs;
6521-
if (CheckTemplateArgumentList(AArg, ArgLoc, PArgList, DefaultArgs, false,
6522-
PArgs, CanonicalPArgs,
6523-
/*UpdateArgsWithConversions=*/true,
6524-
/*ConstraintsNotSatisfied=*/nullptr,
6525-
/*PartialOrderingTTP=*/true))
6535+
if (CheckTemplateArgumentList(
6536+
AArg, ArgLoc, PArgList, DefaultArgs, false, PArgs, CanonicalPArgs,
6537+
/*UpdateArgsWithConversions=*/true,
6538+
/*ConstraintsNotSatisfied=*/nullptr,
6539+
/*PartialOrderingTTP=*/true, MatchedPackOnParmToNonPackOnArg))
65266540
return false;
65276541
}
65286542

@@ -6548,6 +6562,9 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
65486562
IsDeduced ? PackFold::ArgumentToParameter : PackFold::Both,
65496563
/*HasDeducedAnyParam=*/nullptr)) {
65506564
case clang::TemplateDeductionResult::Success:
6565+
if (MatchedPackOnParmToNonPackOnArg &&
6566+
Info.hasMatchedPackOnParmToNonPackOnArg())
6567+
*MatchedPackOnParmToNonPackOnArg = true;
65516568
break;
65526569

65536570
case TemplateDeductionResult::MiscellaneousDeductionFailure:

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4004,11 +4004,11 @@ bool Sema::usesPartialOrExplicitSpecialization(
40044004
/// Get the instantiation pattern to use to instantiate the definition of a
40054005
/// given ClassTemplateSpecializationDecl (either the pattern of the primary
40064006
/// template or of a partial specialization).
4007-
static ActionResult<CXXRecordDecl *>
4008-
getPatternForClassTemplateSpecialization(
4007+
static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization(
40094008
Sema &S, SourceLocation PointOfInstantiation,
40104009
ClassTemplateSpecializationDecl *ClassTemplateSpec,
4011-
TemplateSpecializationKind TSK) {
4010+
TemplateSpecializationKind TSK,
4011+
bool PrimaryHasMatchedPackOnParmToNonPackOnArg) {
40124012
Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec);
40134013
if (Inst.isInvalid())
40144014
return {/*Invalid=*/true};
@@ -4031,7 +4031,7 @@ getPatternForClassTemplateSpecialization(
40314031
// specialization with the template argument lists of the partial
40324032
// specializations.
40334033
typedef PartialSpecMatchResult MatchResult;
4034-
SmallVector<MatchResult, 4> Matched;
4034+
SmallVector<MatchResult, 4> Matched, ExtraMatched;
40354035
SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
40364036
Template->getPartialSpecializations(PartialSpecs);
40374037
TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
@@ -4048,11 +4048,13 @@ getPatternForClassTemplateSpecialization(
40484048
MakeDeductionFailureInfo(S.Context, Result, Info));
40494049
(void)Result;
40504050
} else {
4051-
Matched.push_back(PartialSpecMatchResult());
4052-
Matched.back().Partial = Partial;
4053-
Matched.back().Args = Info.takeCanonical();
4051+
auto &List =
4052+
Info.hasMatchedPackOnParmToNonPackOnArg() ? ExtraMatched : Matched;
4053+
List.push_back(MatchResult{Partial, Info.takeCanonical()});
40544054
}
40554055
}
4056+
if (Matched.empty() && PrimaryHasMatchedPackOnParmToNonPackOnArg)
4057+
Matched = std::move(ExtraMatched);
40564058

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

41654168
ActionResult<CXXRecordDecl *> Pattern =
4166-
getPatternForClassTemplateSpecialization(*this, PointOfInstantiation,
4167-
ClassTemplateSpec, TSK);
4169+
getPatternForClassTemplateSpecialization(
4170+
*this, PointOfInstantiation, ClassTemplateSpec, TSK,
4171+
PrimaryHasMatchedPackOnParmToNonPackOnArg);
41684172
if (!Pattern.isUsable())
41694173
return Pattern.isInvalid();
41704174

0 commit comments

Comments
 (0)