Skip to content

Commit

Permalink
[clang] CWG2398: improve overload resolution backwards compat (llvm#1…
Browse files Browse the repository at this point in the history
…07350)

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.
  • Loading branch information
mizvekov authored Oct 10, 2024
1 parent 12ae1ea commit 224519b
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 53 deletions.
3 changes: 2 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ Resolutions to C++ Defect Reports
(`CWG2351: void{} <https://cplusplus.github.io/CWG/issues/2351.html>`_).

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

- Clang now allows comparing unequal object pointers that have been cast to ``void *``
in constant expressions. These comparisons always worked in non-constant expressions.
Expand Down
14 changes: 9 additions & 5 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -11637,7 +11637,8 @@ class Sema final : public SemaBase {
SourceLocation RAngleLoc, unsigned ArgumentPackIndex,
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
CheckTemplateArgumentKind CTAK);
CheckTemplateArgumentKind CTAK,
bool *MatchedPackOnParmToNonPackOnArg);

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

bool CheckTemplateTypeArgument(
TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
Expand Down Expand Up @@ -11718,7 +11720,8 @@ class Sema final : public SemaBase {
/// It returns true if an error occurred, and false otherwise.
bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
TemplateParameterList *Params,
TemplateArgumentLoc &Arg, bool IsDeduced);
TemplateArgumentLoc &Arg, bool IsDeduced,
bool *MatchedPackOnParmToNonPackOnArg);

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

/// Mark which template parameters are used in a given expression.
///
Expand Down Expand Up @@ -13418,7 +13421,8 @@ class Sema final : public SemaBase {
bool InstantiateClassTemplateSpecialization(
SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
TemplateSpecializationKind TSK, bool Complain = true);
TemplateSpecializationKind TSK, bool Complain = true,
bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false);

/// Instantiates the definitions of all of the member
/// of the given class, which is an instantiation of a class template
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/Sema/TemplateDeduction.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ class TemplateDeductionInfo {
/// Have we suppressed an error during deduction?
bool HasSFINAEDiagnostic = false;

/// Have we matched any packs on the parameter side, versus any non-packs on
/// the argument side, in a context where the opposite matching is also
/// allowed?
bool MatchedPackOnParmToNonPackOnArg = false;

/// The template parameter depth for which we're performing deduction.
unsigned DeducedDepth;

Expand Down Expand Up @@ -87,6 +92,14 @@ class TemplateDeductionInfo {
return DeducedDepth;
}

bool hasMatchedPackOnParmToNonPackOnArg() const {
return MatchedPackOnParmToNonPackOnArg;
}

void setMatchedPackOnParmToNonPackOnArg() {
MatchedPackOnParmToNonPackOnArg = true;
}

/// Get the number of explicitly-specified arguments.
unsigned getNumExplicitArgs() const {
return ExplicitArgs;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3666,7 +3666,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
if (CheckTemplateArgument(
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
0, SugaredChecked, CanonicalChecked, CTAK_Specified) ||
0, SugaredChecked, CanonicalChecked, CTAK_Specified,
/*MatchedPackOnParmToNonPackOnArg=*/nullptr) ||
Trap.hasErrorOccurred())
IsTemplate = false;
}
Expand Down
44 changes: 26 additions & 18 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5179,7 +5179,7 @@ bool Sema::CheckTemplateArgument(
unsigned ArgumentPackIndex,
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
CheckTemplateArgumentKind CTAK) {
CheckTemplateArgumentKind CTAK, bool *MatchedPackOnParmToNonPackOnArg) {
// Check template type parameters.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
Expand Down Expand Up @@ -5395,7 +5395,8 @@ bool Sema::CheckTemplateArgument(
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (CheckTemplateTemplateArgument(TempParm, Params, Arg,
/*IsDeduced=*/CTAK != CTAK_Specified))
/*IsDeduced=*/CTAK != CTAK_Specified,
MatchedPackOnParmToNonPackOnArg))
return true;

SugaredConverted.push_back(Arg.getArgument());
Expand Down Expand Up @@ -5469,7 +5470,7 @@ bool Sema::CheckTemplateArgumentList(
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied,
bool PartialOrderingTTP) {
bool PartialOrderingTTP, bool *MatchedPackOnParmToNonPackOnArg) {

if (ConstraintsNotSatisfied)
*ConstraintsNotSatisfied = false;
Expand Down Expand Up @@ -5545,10 +5546,10 @@ bool Sema::CheckTemplateArgumentList(

if (ArgIdx < NumArgs) {
// Check the template argument we were given.
if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
RAngleLoc, SugaredArgumentPack.size(),
SugaredConverted, CanonicalConverted,
CTAK_Specified))
if (CheckTemplateArgument(
*Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc,
SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted,
CTAK_Specified, MatchedPackOnParmToNonPackOnArg))
return true;

CanonicalConverted.back().setIsDefaulted(
Expand Down Expand Up @@ -5706,7 +5707,8 @@ bool Sema::CheckTemplateArgumentList(
// Check the default template argument.
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
SugaredConverted, CanonicalConverted,
CTAK_Specified))
CTAK_Specified,
/*MatchedPackOnParmToNonPackOnArg=*/nullptr))
return true;

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

bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
TemplateParameterList *Params,
TemplateArgumentLoc &Arg,
bool IsDeduced) {
bool Sema::CheckTemplateTemplateArgument(
TemplateTemplateParmDecl *Param, TemplateParameterList *Params,
TemplateArgumentLoc &Arg, bool IsDeduced,
bool *MatchedPackOnParmToNonPackOnArg) {
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
if (!Template) {
Expand Down Expand Up @@ -7336,7 +7338,8 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
// A template-argument matches a template template-parameter P when P
// is at least as specialized as the template-argument A.
if (!isTemplateTemplateParameterAtLeastAsSpecializedAs(
Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced))
Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced,
MatchedPackOnParmToNonPackOnArg))
return true;
// P2113
// C++20[temp.func.order]p2
Expand Down Expand Up @@ -9754,11 +9757,14 @@ DeclResult Sema::ActOnExplicitInstantiation(

// Check that the template argument list is well-formed for this
// template.
bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false;
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
/*DefaultArgs=*/{}, false, SugaredConverted,
CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
if (CheckTemplateArgumentList(
ClassTemplate, TemplateNameLoc, TemplateArgs,
/*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true,
/*ConstraintsNotSatisfied=*/nullptr, /*PartialOrderingTTP=*/false,
&PrimaryHasMatchedPackOnParmToNonPackOnArg))
return true;

// Find the class template specialization declaration that
Expand Down Expand Up @@ -9879,7 +9885,9 @@ DeclResult Sema::ActOnExplicitInstantiation(
= cast_or_null<ClassTemplateSpecializationDecl>(
Specialization->getDefinition());
if (!Def)
InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
InstantiateClassTemplateSpecialization(
TemplateNameLoc, Specialization, TSK,
/*Complain=*/true, PrimaryHasMatchedPackOnParmToNonPackOnArg);
else if (TSK == TSK_ExplicitInstantiationDefinition) {
MarkVTableUsed(TemplateNameLoc, Specialization, true);
Specialization->setPointOfInstantiation(Def->getPointOfInstantiation());
Expand Down
43 changes: 30 additions & 13 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2767,8 +2767,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
for (; hasTemplateArgumentForDeduction(As, ArgIdx) &&
PackScope.hasNextElement();
++ArgIdx) {
if (!FoldPackParameter && !As[ArgIdx].isPackExpansion())
return TemplateDeductionResult::MiscellaneousDeductionFailure;
if (!As[ArgIdx].isPackExpansion()) {
if (!FoldPackParameter)
return TemplateDeductionResult::MiscellaneousDeductionFailure;
if (FoldPackArgument)
Info.setMatchedPackOnParmToNonPackOnArg();
}
// Deduce template arguments from the pattern.
if (auto Result = DeduceTemplateArguments(
S, TemplateParams, Pattern, As[ArgIdx], Info, PartialOrdering,
Expand Down Expand Up @@ -2962,15 +2966,20 @@ static bool ConvertDeducedTemplateArgument(
TemplateArgumentLoc ArgLoc = S.getTrivialTemplateArgumentLoc(
Arg, QualType(), Info.getLocation(), Param);

bool MatchedPackOnParmToNonPackOnArg = false;
// Check the template argument, converting it as necessary.
return S.CheckTemplateArgument(
auto Res = S.CheckTemplateArgument(
Param, ArgLoc, Template, Template->getLocation(),
Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput,
CanonicalOutput,
IsDeduced
? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound
: Sema::CTAK_Deduced)
: Sema::CTAK_Specified);
: Sema::CTAK_Specified,
&MatchedPackOnParmToNonPackOnArg);
if (MatchedPackOnParmToNonPackOnArg)
Info.setMatchedPackOnParmToNonPackOnArg();
return Res;
};

if (Arg.getKind() == TemplateArgument::Pack) {
Expand Down Expand Up @@ -3165,7 +3174,8 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
// Check whether we can actually use the default argument.
if (S.CheckTemplateArgument(
Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(),
0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) {
0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified,
/*MatchedPackOnParmToNonPackOnArg=*/nullptr)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
// FIXME: These template arguments are temporary. Free them!
Expand Down Expand Up @@ -3314,16 +3324,20 @@ FinishTemplateArgumentDeduction(
return TemplateDeductionResult::SubstitutionFailure;
}

bool MatchedPackOnParmToNonPackOnArg = false;
bool ConstraintsNotSatisfied;
SmallVector<TemplateArgument, 4> SugaredConvertedInstArgs,
CanonicalConvertedInstArgs;
if (S.CheckTemplateArgumentList(
Template, Partial->getLocation(), InstArgs, /*DefaultArgs=*/{}, false,
SugaredConvertedInstArgs, CanonicalConvertedInstArgs,
/*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied))
/*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied,
/*PartialOrderingTTP=*/false, &MatchedPackOnParmToNonPackOnArg))
return ConstraintsNotSatisfied
? TemplateDeductionResult::ConstraintsNotSatisfied
: TemplateDeductionResult::SubstitutionFailure;
if (MatchedPackOnParmToNonPackOnArg)
Info.setMatchedPackOnParmToNonPackOnArg();

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

bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
TemplateParameterList *P, TemplateDecl *PArg, TemplateDecl *AArg,
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
bool IsDeduced) {
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, bool IsDeduced,
bool *MatchedPackOnParmToNonPackOnArg) {
// C++1z [temp.arg.template]p4: (DR 150)
// A template template-parameter P is at least as specialized as a
// template template-argument A if, given the following rewrite to two
Expand Down Expand Up @@ -6518,11 +6532,11 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
// If the rewrite produces an invalid type, then P is not at least as
// specialized as A.
SmallVector<TemplateArgument, 4> CanonicalPArgs;
if (CheckTemplateArgumentList(AArg, ArgLoc, PArgList, DefaultArgs, false,
PArgs, CanonicalPArgs,
/*UpdateArgsWithConversions=*/true,
/*ConstraintsNotSatisfied=*/nullptr,
/*PartialOrderingTTP=*/true))
if (CheckTemplateArgumentList(
AArg, ArgLoc, PArgList, DefaultArgs, false, PArgs, CanonicalPArgs,
/*UpdateArgsWithConversions=*/true,
/*ConstraintsNotSatisfied=*/nullptr,
/*PartialOrderingTTP=*/true, MatchedPackOnParmToNonPackOnArg))
return false;
}

Expand All @@ -6548,6 +6562,9 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
IsDeduced ? PackFold::ArgumentToParameter : PackFold::Both,
/*HasDeducedAnyParam=*/nullptr)) {
case clang::TemplateDeductionResult::Success:
if (MatchedPackOnParmToNonPackOnArg &&
Info.hasMatchedPackOnParmToNonPackOnArg())
*MatchedPackOnParmToNonPackOnArg = true;
break;

case TemplateDeductionResult::MiscellaneousDeductionFailure:
Expand Down
24 changes: 14 additions & 10 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4004,11 +4004,11 @@ bool Sema::usesPartialOrExplicitSpecialization(
/// Get the instantiation pattern to use to instantiate the definition of a
/// given ClassTemplateSpecializationDecl (either the pattern of the primary
/// template or of a partial specialization).
static ActionResult<CXXRecordDecl *>
getPatternForClassTemplateSpecialization(
static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization(
Sema &S, SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
TemplateSpecializationKind TSK) {
TemplateSpecializationKind TSK,
bool PrimaryHasMatchedPackOnParmToNonPackOnArg) {
Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec);
if (Inst.isInvalid())
return {/*Invalid=*/true};
Expand All @@ -4031,7 +4031,7 @@ getPatternForClassTemplateSpecialization(
// specialization with the template argument lists of the partial
// specializations.
typedef PartialSpecMatchResult MatchResult;
SmallVector<MatchResult, 4> Matched;
SmallVector<MatchResult, 4> Matched, ExtraMatched;
SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
Template->getPartialSpecializations(PartialSpecs);
TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
Expand All @@ -4048,11 +4048,13 @@ getPatternForClassTemplateSpecialization(
MakeDeductionFailureInfo(S.Context, Result, Info));
(void)Result;
} else {
Matched.push_back(PartialSpecMatchResult());
Matched.back().Partial = Partial;
Matched.back().Args = Info.takeCanonical();
auto &List =
Info.hasMatchedPackOnParmToNonPackOnArg() ? ExtraMatched : Matched;
List.push_back(MatchResult{Partial, Info.takeCanonical()});
}
}
if (Matched.empty() && PrimaryHasMatchedPackOnParmToNonPackOnArg)
Matched = std::move(ExtraMatched);

// If we're dealing with a member template where the template parameters
// have been instantiated, this provides the original template parameters
Expand Down Expand Up @@ -4155,16 +4157,18 @@ getPatternForClassTemplateSpecialization(
bool Sema::InstantiateClassTemplateSpecialization(
SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
TemplateSpecializationKind TSK, bool Complain) {
TemplateSpecializationKind TSK, bool Complain,
bool PrimaryHasMatchedPackOnParmToNonPackOnArg) {
// Perform the actual instantiation on the canonical declaration.
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
ClassTemplateSpec->getCanonicalDecl());
if (ClassTemplateSpec->isInvalidDecl())
return true;

ActionResult<CXXRecordDecl *> Pattern =
getPatternForClassTemplateSpecialization(*this, PointOfInstantiation,
ClassTemplateSpec, TSK);
getPatternForClassTemplateSpecialization(
*this, PointOfInstantiation, ClassTemplateSpec, TSK,
PrimaryHasMatchedPackOnParmToNonPackOnArg);
if (!Pattern.isUsable())
return Pattern.isInvalid();

Expand Down
Loading

0 comments on commit 224519b

Please sign in to comment.