aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard@metafoo.co.uk>2020-02-10 06:05:59 -0800
committerRichard Smith <richard@metafoo.co.uk>2020-02-10 06:07:48 -0800
commitfcea7fbdba1bdf26e2a858a6be2865e6267da023 (patch)
tree4c2c7916030169cabb447cb4947ee25ab5f2110e
parent7cddd15e5616a1872106a6664e1d622a3adad7cc (diff)
downloadllvm-fcea7fbdba1bdf26e2a858a6be2865e6267da023.zip
llvm-fcea7fbdba1bdf26e2a858a6be2865e6267da023.tar.gz
llvm-fcea7fbdba1bdf26e2a858a6be2865e6267da023.tar.bz2
CWG2445: For function template partial ordering, take reversal of
function arguments into account when forming P/A pairs.
-rw-r--r--clang/include/clang/Sema/Overload.h2
-rw-r--r--clang/include/clang/Sema/Sema.h10
-rw-r--r--clang/lib/Sema/SemaOverload.cpp25
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp24
-rw-r--r--clang/test/SemaTemplate/operator-template.cpp11
5 files changed, 48 insertions, 24 deletions
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 1394c62..a274102 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -850,6 +850,8 @@ class Sema;
return static_cast<OverloadCandidateRewriteKind>(RewriteKind);
}
+ bool isReversed() const { return getRewriteKind() & CRK_Reversed; }
+
/// hasAmbiguousConversion - Returns whether this overload
/// candidate requires an ambiguous conversion or not.
bool hasAmbiguousConversion() const {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 3e68560..d664e48 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7964,12 +7964,10 @@ public:
SourceLocation ReturnLoc,
Expr *&RetExpr, AutoType *AT);
- FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
- FunctionTemplateDecl *FT2,
- SourceLocation Loc,
- TemplatePartialOrderingContext TPOC,
- unsigned NumCallArguments1,
- unsigned NumCallArguments2);
+ FunctionTemplateDecl *getMoreSpecializedTemplate(
+ FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
+ TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1,
+ unsigned NumCallArguments2, bool Reversed = false);
UnresolvedSetIterator
getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd,
TemplateSpecCandidateSet &FailedCandidates,
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 858e7ae..003d9bb 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -8392,7 +8392,7 @@ public:
// We interpret "same parameter-type-list" as applying to the
// "synthesized candidate, with the order of the two parameters
// reversed", not to the original function.
- bool Reversed = C->RewriteKind & CRK_Reversed;
+ bool Reversed = C->isReversed();
QualType FirstParamType = C->Function->getParamDecl(Reversed ? 1 : 0)
->getType()
.getUnqualifiedType();
@@ -9478,7 +9478,7 @@ bool clang::isBetterOverloadCandidate(
case ImplicitConversionSequence::Worse:
if (Cand1.Function && Cand1.Function == Cand2.Function &&
- (Cand2.RewriteKind & CRK_Reversed) != 0) {
+ Cand2.isReversed()) {
// Work around large-scale breakage caused by considering reversed
// forms of operator== in C++20:
//
@@ -9566,14 +9566,13 @@ bool clang::isBetterOverloadCandidate(
// according to the partial ordering rules described in 14.5.5.2, or,
// if not that,
if (Cand1IsSpecialization && Cand2IsSpecialization) {
- if (FunctionTemplateDecl *BetterTemplate
- = S.getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
- Cand2.Function->getPrimaryTemplate(),
- Loc,
- isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion
- : TPOC_Call,
- Cand1.ExplicitCallArguments,
- Cand2.ExplicitCallArguments))
+ if (FunctionTemplateDecl *BetterTemplate = S.getMoreSpecializedTemplate(
+ Cand1.Function->getPrimaryTemplate(),
+ Cand2.Function->getPrimaryTemplate(), Loc,
+ isa<CXXConversionDecl>(Cand1.Function) ? TPOC_Conversion
+ : TPOC_Call,
+ Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments,
+ Cand1.isReversed() ^ Cand2.isReversed()))
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
@@ -11298,7 +11297,7 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
unsigned ConvIdx = 0;
unsigned ArgIdx = 0;
ArrayRef<QualType> ParamTypes;
- bool Reversed = Cand->RewriteKind & CRK_Reversed;
+ bool Reversed = Cand->isReversed();
if (Cand->IsSurrogate) {
QualType ConvType
@@ -13232,7 +13231,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// We found a built-in operator or an overloaded operator.
FunctionDecl *FnDecl = Best->Function;
- bool IsReversed = (Best->RewriteKind & CRK_Reversed);
+ bool IsReversed = Best->isReversed();
if (IsReversed)
std::swap(Args[0], Args[1]);
@@ -13264,7 +13263,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// formally ambiguous, and allowing it is an extension.
for (OverloadCandidate &Cand : CandidateSet) {
if (Cand.Viable && Cand.Function == FnDecl &&
- Cand.RewriteKind & CRK_Reversed) {
+ Cand.isReversed()) {
for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {
if (CompareImplicitConversionSequences(
*this, OpLoc, Cand.Conversions[ArgIdx],
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 1a71f27..7451bf6 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -4847,7 +4847,10 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC,
- unsigned NumCallArguments1) {
+ unsigned NumCallArguments1,
+ bool Reversed) {
+ assert(!Reversed || TPOC == TPOC_Call);
+
FunctionDecl *FD1 = FT1->getTemplatedDecl();
FunctionDecl *FD2 = FT2->getTemplatedDecl();
const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
@@ -4896,6 +4899,12 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
} else if (!Method1 && Method2 && !Method2->isStatic()) {
// Compare 'this' from Method2 against first parameter from Method1.
AddImplicitObjectParameterType(S.Context, Method2, Args2);
+ } else if (Method1 && Method2 && Reversed) {
+ // Compare 'this' from Method1 against second parameter from Method2
+ // and 'this' from Method2 against second parameter from Method1.
+ AddImplicitObjectParameterType(S.Context, Method1, Args1);
+ AddImplicitObjectParameterType(S.Context, Method2, Args2);
+ ++NumComparedArguments;
}
Args1.insert(Args1.end(), Proto1->param_type_begin(),
@@ -4910,6 +4919,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
Args1.resize(NumComparedArguments);
if (Args2.size() > NumComparedArguments)
Args2.resize(NumComparedArguments);
+ if (Reversed)
+ std::reverse(Args2.begin(), Args2.end());
if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
Args1.data(), Args1.size(), Info, Deduced,
TDF_None, /*PartialOrdering=*/true))
@@ -5028,6 +5039,10 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
/// \param NumCallArguments2 The number of arguments in the call to FT2, used
/// only when \c TPOC is \c TPOC_Call.
///
+/// \param Reversed If \c true, exactly one of FT1 and FT2 is an overload
+/// candidate with a reversed parameter order. In this case, the corresponding
+/// P/A pairs between FT1 and FT2 are reversed.
+///
/// \returns the more specialized function template. If neither
/// template is more specialized, returns NULL.
FunctionTemplateDecl *
@@ -5036,7 +5051,8 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
SourceLocation Loc,
TemplatePartialOrderingContext TPOC,
unsigned NumCallArguments1,
- unsigned NumCallArguments2) {
+ unsigned NumCallArguments2,
+ bool Reversed) {
auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * {
llvm::SmallVector<const Expr *, 3> AC1, AC2;
@@ -5053,9 +5069,9 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
};
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
- NumCallArguments1);
+ NumCallArguments1, Reversed);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
- NumCallArguments2);
+ NumCallArguments2, Reversed);
if (Better1 != Better2) // We have a clear winner
return Better1 ? FT1 : FT2;
diff --git a/clang/test/SemaTemplate/operator-template.cpp b/clang/test/SemaTemplate/operator-template.cpp
index 4166250..e60216f 100644
--- a/clang/test/SemaTemplate/operator-template.cpp
+++ b/clang/test/SemaTemplate/operator-template.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s
// Make sure we accept this
template<class X>struct A{typedef X Y;};
@@ -15,3 +15,12 @@ template<class X>bool operator==(B<X>*,typename B<X>::Y); // \
// expected-note{{candidate template ignored: substitution failure [with X = int]}}
int a(B<int> x) { return operator==(&x,1); } // expected-error{{no matching function for call to 'operator=='}} \
// expected-note{{in instantiation of function template specialization}}
+
+// Ensure we take parameter list reversal into account in partial oredring.
+namespace CompareOrdering {
+ template<typename T> struct A {};
+ template<typename T> int operator<=>(A<T>, int) = delete;
+ template<typename T> int operator<=>(int, A<T*>);
+ // OK, selects the more-specialized reversed function.
+ bool b = A<int*>() < 0;
+}