12
12
13
13
#include "clang/AST/ASTContext.h"
14
14
#include "clang/AST/CXXInheritance.h"
15
+ #include "clang/AST/DeclCXX.h"
15
16
#include "clang/AST/DeclObjC.h"
16
17
#include "clang/AST/DependenceFlags.h"
17
18
#include "clang/AST/Expr.h"
18
19
#include "clang/AST/ExprCXX.h"
19
20
#include "clang/AST/ExprObjC.h"
21
+ #include "clang/AST/Type.h"
20
22
#include "clang/AST/TypeOrdering.h"
21
23
#include "clang/Basic/Diagnostic.h"
22
24
#include "clang/Basic/DiagnosticOptions.h"
25
+ #include "clang/Basic/OperatorKinds.h"
23
26
#include "clang/Basic/PartialDiagnostic.h"
24
27
#include "clang/Basic/SourceManager.h"
25
28
#include "clang/Basic/TargetInfo.h"
34
37
#include "llvm/ADT/STLExtras.h"
35
38
#include "llvm/ADT/SmallPtrSet.h"
36
39
#include "llvm/ADT/SmallString.h"
40
+ #include "llvm/Support/Casting.h"
37
41
#include <algorithm>
38
42
#include <cstdlib>
39
43
@@ -890,22 +894,99 @@ llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
890
894
}
891
895
}
892
896
893
- bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
897
+ static bool FunctionsCorrespond(ASTContext &Ctx, const FunctionDecl *X,
898
+ const FunctionDecl *Y) {
899
+ if (!X || !Y)
900
+ return false;
901
+ if (X->getNumParams() != Y->getNumParams())
902
+ return false;
903
+ for (unsigned I = 0; I < X->getNumParams(); ++I)
904
+ if (!Ctx.hasSameUnqualifiedType(X->getParamDecl(I)->getType(),
905
+ Y->getParamDecl(I)->getType()))
906
+ return false;
907
+ if (auto *FTX = X->getDescribedFunctionTemplate()) {
908
+ auto *FTY = Y->getDescribedFunctionTemplate();
909
+ if (!FTY)
910
+ return false;
911
+ if (!Ctx.isSameTemplateParameterList(FTX->getTemplateParameters(),
912
+ FTY->getTemplateParameters()))
913
+ return false;
914
+ }
915
+ return true;
916
+ }
917
+
918
+ static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc,
919
+ Expr *FirstOperand, FunctionDecl *EqFD) {
920
+ assert(EqFD->getOverloadedOperator() ==
921
+ OverloadedOperatorKind::OO_EqualEqual);
922
+ // C++2a [over.match.oper]p4:
923
+ // A non-template function or function template F named operator== is a
924
+ // rewrite target with first operand o unless a search for the name operator!=
925
+ // in the scope S from the instantiation context of the operator expression
926
+ // finds a function or function template that would correspond
927
+ // ([basic.scope.scope]) to F if its name were operator==, where S is the
928
+ // scope of the class type of o if F is a class member, and the namespace
929
+ // scope of which F is a member otherwise. A function template specialization
930
+ // named operator== is a rewrite target if its function template is a rewrite
931
+ // target.
932
+ DeclarationName NotEqOp = S.Context.DeclarationNames.getCXXOperatorName(
933
+ OverloadedOperatorKind::OO_ExclaimEqual);
934
+ if (auto *MD = dyn_cast<CXXMethodDecl>(EqFD)) {
935
+ // If F is a class member, search scope is class type of first operand.
936
+ QualType RHS = FirstOperand->getType();
937
+ auto *RHSRec = RHS->getAs<RecordType>();
938
+ if (!RHSRec)
939
+ return true;
940
+ LookupResult Members(S, NotEqOp, OpLoc,
941
+ Sema::LookupNameKind::LookupMemberName);
942
+ S.LookupQualifiedName(Members, RHSRec->getDecl());
943
+ Members.suppressDiagnostics();
944
+ for (NamedDecl *Op : Members)
945
+ if (FunctionsCorrespond(S.Context, EqFD, Op->getAsFunction()))
946
+ return false;
947
+ return true;
948
+ }
949
+ // Otherwise the search scope is the namespace scope of which F is a member.
950
+ LookupResult NonMembers(S, NotEqOp, OpLoc,
951
+ Sema::LookupNameKind::LookupOperatorName);
952
+ S.LookupName(NonMembers,
953
+ S.getScopeForContext(EqFD->getEnclosingNamespaceContext()));
954
+ NonMembers.suppressDiagnostics();
955
+ for (NamedDecl *Op : NonMembers) {
956
+ auto *FD = Op->getAsFunction();
957
+ if(auto* UD = dyn_cast<UsingShadowDecl>(Op))
958
+ FD = UD->getUnderlyingDecl()->getAsFunction();
959
+ if (FunctionsCorrespond(S.Context, EqFD, FD) &&
960
+ declaresSameEntity(cast<Decl>(EqFD->getDeclContext()),
961
+ cast<Decl>(Op->getDeclContext())))
962
+ return false;
963
+ }
964
+ return true;
965
+ }
966
+
967
+ bool OverloadCandidateSet::OperatorRewriteInfo::allowsReversed(
894
968
OverloadedOperatorKind Op) {
895
969
if (!AllowRewrittenCandidates)
896
970
return false;
897
971
return Op == OO_EqualEqual || Op == OO_Spaceship;
898
972
}
899
973
900
974
bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
901
- ASTContext &Ctx, const FunctionDecl *FD) {
902
- if (!shouldAddReversed(FD->getDeclName().getCXXOverloadedOperator()))
975
+ Sema &S, ArrayRef<Expr *> OriginalArgs, FunctionDecl *FD) {
976
+ auto Op = FD->getOverloadedOperator();
977
+ if (!allowsReversed(Op))
903
978
return false;
979
+ if (Op == OverloadedOperatorKind::OO_EqualEqual) {
980
+ assert(OriginalArgs.size() == 2);
981
+ if (!shouldAddReversedEqEq(
982
+ S, OpLoc, /*FirstOperand in reversed args*/ OriginalArgs[1], FD))
983
+ return false;
984
+ }
904
985
// Don't bother adding a reversed candidate that can never be a better
905
986
// match than the non-reversed version.
906
987
return FD->getNumParams() != 2 ||
907
- !Ctx .hasSameUnqualifiedType(FD->getParamDecl(0)->getType(),
908
- FD->getParamDecl(1)->getType()) ||
988
+ !S.Context .hasSameUnqualifiedType(FD->getParamDecl(0)->getType(),
989
+ FD->getParamDecl(1)->getType()) ||
909
990
FD->hasAttr<EnableIfAttr>();
910
991
}
911
992
@@ -7749,7 +7830,7 @@ void Sema::AddNonMemberOperatorCandidates(
7749
7830
if (FunTmpl) {
7750
7831
AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs,
7751
7832
FunctionArgs, CandidateSet);
7752
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Context , FD))
7833
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args , FD))
7753
7834
AddTemplateOverloadCandidate(
7754
7835
FunTmpl, F.getPair(), ExplicitTemplateArgs,
7755
7836
{FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false,
@@ -7758,7 +7839,7 @@ void Sema::AddNonMemberOperatorCandidates(
7758
7839
if (ExplicitTemplateArgs)
7759
7840
continue;
7760
7841
AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet);
7761
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Context , FD))
7842
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args , FD))
7762
7843
AddOverloadCandidate(FD, F.getPair(),
7763
7844
{FunctionArgs[1], FunctionArgs[0]}, CandidateSet,
7764
7845
false, false, true, false, ADLCallKind::NotADL,
@@ -7809,12 +7890,17 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
7809
7890
Operators.suppressDiagnostics();
7810
7891
7811
7892
for (LookupResult::iterator Oper = Operators.begin(),
7812
- OperEnd = Operators.end();
7813
- Oper != OperEnd;
7814
- ++Oper)
7893
+ OperEnd = Operators.end();
7894
+ Oper != OperEnd; ++Oper) {
7895
+ if (Oper->getAsFunction() &&
7896
+ PO == OverloadCandidateParamOrder::Reversed &&
7897
+ !CandidateSet.getRewriteInfo().shouldAddReversed(
7898
+ *this, {Args[1], Args[0]}, Oper->getAsFunction()))
7899
+ continue;
7815
7900
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
7816
7901
Args[0]->Classify(Context), Args.slice(1),
7817
7902
CandidateSet, /*SuppressUserConversion=*/false, PO);
7903
+ }
7818
7904
}
7819
7905
}
7820
7906
@@ -9510,7 +9596,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
9510
9596
FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false,
9511
9597
PartialOverloading, /*AllowExplicit=*/true,
9512
9598
/*AllowExplicitConversion=*/false, ADLCallKind::UsesADL);
9513
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Context , FD)) {
9599
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args , FD)) {
9514
9600
AddOverloadCandidate(
9515
9601
FD, FoundDecl, {Args[1], Args[0]}, CandidateSet,
9516
9602
/*SuppressUserConversions=*/false, PartialOverloading,
@@ -9524,7 +9610,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
9524
9610
/*SuppressUserConversions=*/false, PartialOverloading,
9525
9611
/*AllowExplicit=*/true, ADLCallKind::UsesADL);
9526
9612
if (CandidateSet.getRewriteInfo().shouldAddReversed(
9527
- Context , FTD->getTemplatedDecl())) {
9613
+ *this, Args , FTD->getTemplatedDecl())) {
9528
9614
AddTemplateOverloadCandidate(
9529
9615
FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]},
9530
9616
CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading,
@@ -13637,14 +13723,14 @@ void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet,
13637
13723
13638
13724
// Add operator candidates that are member functions.
13639
13725
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
13640
- if (CandidateSet.getRewriteInfo().shouldAddReversed (Op))
13726
+ if (CandidateSet.getRewriteInfo().allowsReversed (Op))
13641
13727
AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet,
13642
13728
OverloadCandidateParamOrder::Reversed);
13643
13729
13644
13730
// In C++20, also add any rewritten member candidates.
13645
13731
if (ExtraOp) {
13646
13732
AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet);
13647
- if (CandidateSet.getRewriteInfo().shouldAddReversed (ExtraOp))
13733
+ if (CandidateSet.getRewriteInfo().allowsReversed (ExtraOp))
13648
13734
AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},
13649
13735
CandidateSet,
13650
13736
OverloadCandidateParamOrder::Reversed);
@@ -13775,9 +13861,9 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
13775
13861
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
13776
13862
13777
13863
// Build the overload set.
13778
- OverloadCandidateSet CandidateSet(
13779
- OpLoc, OverloadCandidateSet::CSK_Operator,
13780
- OverloadCandidateSet::OperatorRewriteInfo(Op , AllowRewrittenCandidates));
13864
+ OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator,
13865
+ OverloadCandidateSet::OperatorRewriteInfo(
13866
+ Op, OpLoc , AllowRewrittenCandidates));
13781
13867
if (DefaultedFn)
13782
13868
CandidateSet.exclude(DefaultedFn);
13783
13869
LookupOverloadedBinOp(CandidateSet, Op, Fns, Args, PerformADL);
@@ -13852,6 +13938,22 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
13852
13938
if (AmbiguousWithSelf) {
13853
13939
Diag(FnDecl->getLocation(),
13854
13940
diag::note_ovl_ambiguous_oper_binary_reversed_self);
13941
+ // Mark member== const or provide matching != to disallow reversed
13942
+ // args. Eg.
13943
+ // struct S { bool operator==(const S&); };
13944
+ // S()==S();
13945
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FnDecl))
13946
+ if (Op == OverloadedOperatorKind::OO_EqualEqual &&
13947
+ !MD->isConst() &&
13948
+ Context.hasSameUnqualifiedType(
13949
+ MD->getThisObjectType(),
13950
+ MD->getParamDecl(0)->getType().getNonReferenceType()) &&
13951
+ Context.hasSameUnqualifiedType(MD->getThisObjectType(),
13952
+ Args[0]->getType()) &&
13953
+ Context.hasSameUnqualifiedType(MD->getThisObjectType(),
13954
+ Args[1]->getType()))
13955
+ Diag(FnDecl->getLocation(),
13956
+ diag::note_ovl_ambiguous_eqeq_reversed_self_non_const);
13855
13957
} else {
13856
13958
Diag(FnDecl->getLocation(),
13857
13959
diag::note_ovl_ambiguous_oper_binary_selected_candidate);
0 commit comments