aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-04 16:44:47 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-04 16:44:47 +0000
commitf680a0fe2dcab32b59fe6fdf71145b5313c40950 (patch)
tree5edd7174472b922d5c58a071f997c9cb33823b0c
parent09413dca1be4b3e78597bdf706de39ec70cf0ee4 (diff)
Bring operator name lookup (as required for C++ operator overloading)
into the general name-lookup fold. This cleans up some ugly, not-quite-working code in the handling of operator overloading. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63735 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/Sema.h19
-rw-r--r--lib/Sema/SemaExpr.cpp15
-rw-r--r--lib/Sema/SemaLookup.cpp5
-rw-r--r--lib/Sema/SemaOverload.cpp73
-rw-r--r--test/SemaCXX/overloaded-operator.cpp3
5 files changed, 50 insertions, 65 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 6b8d852db3..724a57ed42 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -488,9 +488,11 @@ public:
const FunctionTypeProto *Proto,
Expr *Object, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
- void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
+ bool AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
+ SourceLocation OpLoc,
Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet);
+ OverloadCandidateSet& CandidateSet,
+ SourceRange OpRange = SourceRange());
void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -502,10 +504,6 @@ public:
void AddArgumentDependentLookupCandidates(DeclarationName Name,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
- void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl,
- Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions = false);
bool isBetterOverloadCandidate(const OverloadCandidate& Cand1,
const OverloadCandidate& Cand2);
OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
@@ -585,6 +583,11 @@ public:
/// Member name lookup, which finds the names of
/// class/struct/union members.
LookupMemberName,
+ // Look up of an operator name (e.g., operator+) for use with
+ // operator overloading. This lookup is similar to ordinary name
+ // lookup, but will ignore any declarations that are class
+ // members.
+ LookupOperatorName,
/// Look up of a name that precedes the '::' scope resolution
/// operator in C++. This lookup completely ignores operator,
/// function, and enumerator names (C++ [basic.lookup.qual]p1).
@@ -839,6 +842,10 @@ public:
case Sema::LookupMemberName:
return D->isInIdentifierNamespace(IDNS);
+ case Sema::LookupOperatorName:
+ return D->isInIdentifierNamespace(IDNS) &&
+ !D->getDeclContext()->isRecord();
+
case Sema::LookupNestedNameSpecifierName:
return isa<TypedefDecl>(D) || D->isInIdentifierNamespace(Decl::IDNS_Tag);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c1e4c0ecdd..d408defbff 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1190,7 +1190,8 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
// Build the candidate set for overloading
OverloadCandidateSet CandidateSet;
- AddOperatorCandidates(OverOp, S, Args, 2, CandidateSet);
+ if (AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet))
+ return ExprError();
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
@@ -1281,7 +1282,9 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
// to the candidate set.
OverloadCandidateSet CandidateSet;
Expr *Args[2] = { LHSExp, RHSExp };
- AddOperatorCandidates(OO_Subscript, S, Args, 2, CandidateSet);
+ if (AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
+ SourceRange(LLoc, RLoc)))
+ return ExprError();
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
@@ -3738,7 +3741,8 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
// to the candidate set.
OverloadCandidateSet CandidateSet;
Expr *Args[2] = { lhs, rhs };
- AddOperatorCandidates(OverOp, S, Args, 2, CandidateSet);
+ if (AddOperatorCandidates(OverOp, S, TokLoc, Args, 2, CandidateSet))
+ return ExprError();
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
@@ -3840,8 +3844,9 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
// Add the appropriate overloaded operators (C++ [over.match.oper])
// to the candidate set.
OverloadCandidateSet CandidateSet;
- if (OverOp != OO_None)
- AddOperatorCandidates(OverOp, S, &Input, 1, CandidateSet);
+ if (OverOp != OO_None &&
+ AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet))
+ return ExprError();
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 09431492b9..4cdd4abab3 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -313,6 +313,7 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind,
unsigned IDNS = 0;
switch (NameKind) {
case Sema::LookupOrdinaryName:
+ case Sema::LookupOperatorName:
IDNS = Decl::IDNS_Ordinary;
if (CPlusPlus)
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member;
@@ -531,6 +532,7 @@ Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() {
Decl ** I = reinterpret_cast<Decl**>(Current);
++I;
Current = reinterpret_cast<uintptr_t>(I);
+ break;
}
case OverloadedDeclFromIdResolver: {
@@ -587,7 +589,7 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
LookupNameKind NameKind, bool RedeclarationOnly) {
assert(getLangOptions().CPlusPlus &&
"Can perform only C++ lookup");
-unsigned IDNS
+ unsigned IDNS
= getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true);
Scope *Initial = S;
IdentifierResolver::iterator
@@ -841,6 +843,7 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
IDNS = Decl::IDNS_Member;
break;
+ case Sema::LookupOperatorName:
case Sema::LookupNestedNameSpecifierName:
case Sema::LookupNamespaceName:
assert(false && "C does not perform these kinds of name lookup");
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 01b9829c66..44cd5b5e53 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -2258,9 +2258,11 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
/// name lookup of the operator), Args/NumArgs provides the operator
/// arguments, and CandidateSet will store the added overload
/// candidates. (C++ [over.match.oper]).
-void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
+bool Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
+ SourceLocation OpLoc,
Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet) {
+ OverloadCandidateSet& CandidateSet,
+ SourceRange OpRange) {
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
// C++ [over.match.oper]p3:
@@ -2300,45 +2302,29 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
// type, or (if there is a right operand) a second parameter
// of type T2 or “reference to (possibly cv-qualified) T2”,
// when T2 is an enumeration type, are candidate functions.
- {
- // FIXME: Don't use the IdentifierResolver here! We need to
- // perform proper, unqualified lookup starting with the first
- // enclosing non-class scope.
- IdentifierResolver::iterator I = IdResolver.begin(OpName),
- IEnd = IdResolver.end();
- for (; I != IEnd; ++I) {
- // We don't need to check the identifier namespace, because
- // operator names can only be ordinary identifiers.
-
- // Ignore member functions.
- if ((*I)->getDeclContext()->isRecord())
- continue;
-
- // We found something with this name. We're done.
- break;
- }
-
- if (I != IEnd) {
- Decl *FirstDecl = *I;
- for (; I != IEnd; ++I) {
- if (FirstDecl->getDeclContext() != (*I)->getDeclContext())
- break;
-
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I))
- if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
- AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
- /*SuppressUserConversions=*/false);
- }
+ LookupResult Operators = LookupName(S, OpName, LookupOperatorName);
+
+ if (Operators.isAmbiguous())
+ return DiagnoseAmbiguousLookup(Operators, OpName, OpLoc, OpRange);
+ else if (Operators) {
+ for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end();
+ Op != OpEnd; ++Op) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op))
+ if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
+ AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+ /*SuppressUserConversions=*/false);
}
-
- // Since the set of non-member candidates corresponds to
- // *unqualified* lookup of the operator name, we also perform
- // argument-dependent lookup.
- AddArgumentDependentLookupCandidates(OpName, Args, NumArgs, CandidateSet);
}
+ // Since the set of non-member candidates corresponds to
+ // *unqualified* lookup of the operator name, we also perform
+ // argument-dependent lookup (C++ [basic.lookup.argdep]).
+ AddArgumentDependentLookupCandidates(OpName, Args, NumArgs, CandidateSet);
+
// Add builtin overload candidates (C++ [over.built]).
AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet);
+
+ return false;
}
/// AddBuiltinCandidate - Add a candidate for a built-in
@@ -3230,21 +3216,6 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
}
}
-/// AddOverloadCandidates - Add all of the function overloads in Ovl
-/// to the candidate set.
-void
-Sema::AddOverloadCandidates(const OverloadedFunctionDecl *Ovl,
- Expr **Args, unsigned NumArgs,
- OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions)
-{
- for (OverloadedFunctionDecl::function_const_iterator Func
- = Ovl->function_begin();
- Func != Ovl->function_end(); ++Func)
- AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet,
- SuppressUserConversions);
-}
-
/// isBetterOverloadCandidate - Determines whether the first overload
/// candidate is a better candidate than the second (C++ 13.3.3p1).
bool
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 6c7a8d7621..7a5e06e5fa 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -206,7 +206,6 @@ namespace M {
namespace M {
void test_X(N::X x) {
- // FIXME: this should work! See comment in Sema::AddOperatorCandidates.
- // (void)(x + x);
+ (void)(x + x);
}
}