aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2008-12-22 05:46:06 +0000
committerDouglas Gregor <dgregor@apple.com>2008-12-22 05:46:06 +0000
commit88a3514f36de96b19cdf50141c640df1a5f13f6c (patch)
treea15713eacba3dc51acc9af629d852ace77db9ea7 /lib/Sema/SemaOverload.cpp
parentb595509bf5c07b65616d9c7ef26dca4858768ac7 (diff)
Add support for calls to overloaded member functions. Things to note:
- Overloading has to cope with having both static and non-static member functions in the overload set. - The call may or may not have an implicit object argument, depending on the syntax (x.f() vs. f()) and the context (static vs. non-static member function). - We now generate MemberExprs for implicit member access expression. - We now cope with mutable whenever we're building MemberExprs. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61329 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r--lib/Sema/SemaOverload.cpp148
1 files changed, 136 insertions, 12 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index fe4b763502..5fb1b14b98 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1759,11 +1759,26 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
assert(!isa<CXXConversionDecl>(Function) &&
"Use AddConversionCandidate for conversion functions");
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
+ // If we get here, it's because we're calling a member function
+ // that is named without a member access expression (e.g.,
+ // "this->f") that was either written explicitly or created
+ // implicitly. This can happen with a qualified call to a member
+ // function, e.g., X::f(). We use a NULL object as the implied
+ // object argument (C++ [over.call.func]p3).
+ AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet,
+ SuppressUserConversions);
+ return;
+ }
+
+
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = Function;
+ Candidate.Viable = true;
Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
unsigned NumArgsInProto = Proto->getNumArgs();
@@ -1789,7 +1804,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// Determine the implicit conversion sequences for each of the
// arguments.
- Candidate.Viable = true;
Candidate.Conversions.resize(NumArgs);
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
if (ArgIdx < NumArgsInProto) {
@@ -1840,6 +1854,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = Method;
Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
unsigned NumArgsInProto = Proto->getNumArgs();
@@ -1866,13 +1881,18 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
Candidate.Viable = true;
Candidate.Conversions.resize(NumArgs + 1);
- // Determine the implicit conversion sequence for the object
- // parameter.
- Candidate.Conversions[0] = TryObjectArgumentInitialization(Object, Method);
- if (Candidate.Conversions[0].ConversionKind
- == ImplicitConversionSequence::BadConversion) {
- Candidate.Viable = false;
- return;
+ if (Method->isStatic() || !Object)
+ // The implicit object argument is ignored.
+ Candidate.IgnoreObjectArgument = true;
+ else {
+ // Determine the implicit conversion sequence for the object
+ // parameter.
+ Candidate.Conversions[0] = TryObjectArgumentInitialization(Object, Method);
+ if (Candidate.Conversions[0].ConversionKind
+ == ImplicitConversionSequence::BadConversion) {
+ Candidate.Viable = false;
+ return;
+ }
}
// Determine the implicit conversion sequences for each of the
@@ -1917,6 +1937,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = Conversion;
Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
Candidate.FinalConversion.setAsIdentityConversion();
Candidate.FinalConversion.FromTypePtr
= Conversion->getConversionType().getAsOpaquePtr();
@@ -1980,6 +2001,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Candidate.Surrogate = Conversion;
Candidate.Viable = true;
Candidate.IsSurrogate = true;
+ Candidate.IgnoreObjectArgument = false;
Candidate.Conversions.resize(NumArgs + 1);
// Determine the implicit conversion sequence for the implicit
@@ -2193,6 +2215,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = 0;
Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
Candidate.BuiltinTypes.ResultTy = ResultTy;
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
Candidate.BuiltinTypes.ParamTypes[ArgIdx] = ParamTys[ArgIdx];
@@ -2983,8 +3006,15 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
else if (!Cand1.Viable)
return false;
- // FIXME: Deal with the implicit object parameter for static member
- // functions. (C++ 13.3.3p1).
+ // C++ [over.match.best]p1:
+ //
+ // -- if F is a static member function, ICS1(F) is defined such
+ // that ICS1(F) is neither better nor worse than ICS1(G) for
+ // any function G, and, symmetrically, ICS1(G) is neither
+ // better nor worse than ICS1(F).
+ unsigned StartArg = 0;
+ if (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument)
+ StartArg = 1;
// (C++ 13.3.3p1): a viable function F1 is defined to be a better
// function than another viable function F2 if for all arguments i,
@@ -2993,7 +3023,7 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
unsigned NumArgs = Cand1.Conversions.size();
assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch");
bool HasBetterConversion = false;
- for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
switch (CompareImplicitConversionSequences(Cand1.Conversions[ArgIdx],
Cand2.Conversions[ArgIdx])) {
case ImplicitConversionSequence::Better:
@@ -3255,11 +3285,102 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, OverloadedFunctionDecl *Ov
return 0;
}
+/// BuildCallToMemberFunction - Build a call to a member
+/// function. MemExpr is the expression that refers to the member
+/// function (and includes the object parameter), Args/NumArgs are the
+/// arguments to the function call (not including the object
+/// parameter). The caller needs to validate that the member
+/// expression refers to a member function or an overloaded member
+/// function.
+Sema::ExprResult
+Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
+ SourceLocation LParenLoc, Expr **Args,
+ unsigned NumArgs, SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ // Dig out the member expression. This holds both the object
+ // argument and the member function we're referring to.
+ MemberExpr *MemExpr = 0;
+ if (ParenExpr *ParenE = dyn_cast<ParenExpr>(MemExprE))
+ MemExpr = dyn_cast<MemberExpr>(ParenE->getSubExpr());
+ else
+ MemExpr = dyn_cast<MemberExpr>(MemExprE);
+ assert(MemExpr && "Building member call without member expression");
+
+ // Extract the object argument.
+ Expr *ObjectArg = MemExpr->getBase();
+ if (MemExpr->isArrow())
+ ObjectArg = new UnaryOperator(ObjectArg, UnaryOperator::Deref,
+ ObjectArg->getType()->getAsPointerType()->getPointeeType(),
+ SourceLocation());
+ CXXMethodDecl *Method = 0;
+ if (OverloadedFunctionDecl *Ovl
+ = dyn_cast<OverloadedFunctionDecl>(MemExpr->getMemberDecl())) {
+ // Add overload candidates
+ OverloadCandidateSet CandidateSet;
+ for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
+ FuncEnd = Ovl->function_end();
+ Func != FuncEnd; ++Func) {
+ assert(isa<CXXMethodDecl>(*Func) && "Function is not a method");
+ Method = cast<CXXMethodDecl>(*Func);
+ AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
+ /*SuppressUserConversions=*/false);
+ }
+
+ OverloadCandidateSet::iterator Best;
+ switch (BestViableFunction(CandidateSet, Best)) {
+ case OR_Success:
+ Method = cast<CXXMethodDecl>(Best->Function);
+ break;
+
+ case OR_No_Viable_Function:
+ Diag(MemExpr->getSourceRange().getBegin(),
+ diag::err_ovl_no_viable_member_function_in_call)
+ << Ovl->getDeclName() << (unsigned)CandidateSet.size()
+ << MemExprE->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ // FIXME: Leaking incoming expressions!
+ return true;
+
+ case OR_Ambiguous:
+ Diag(MemExpr->getSourceRange().getBegin(),
+ diag::err_ovl_ambiguous_member_call)
+ << Ovl->getDeclName() << MemExprE->getSourceRange();
+ PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+ // FIXME: Leaking incoming expressions!
+ return true;
+ }
+
+ FixOverloadedFunctionReference(MemExpr, Method);
+ } else {
+ Method = dyn_cast<CXXMethodDecl>(MemExpr->getMemberDecl());
+ }
+
+ assert(Method && "Member call to something that isn't a method?");
+ llvm::OwningPtr<CXXMemberCallExpr>
+ TheCall(new CXXMemberCallExpr(MemExpr, Args, NumArgs,
+ Method->getResultType().getNonReferenceType(),
+ RParenLoc));
+
+ // Convert the object argument (for a non-static member function call).
+ if (!Method->isStatic() &&
+ PerformObjectArgumentInitialization(ObjectArg, Method))
+ return true;
+ MemExpr->setBase(ObjectArg);
+
+ // Convert the rest of the arguments
+ const FunctionTypeProto *Proto = cast<FunctionTypeProto>(Method->getType());
+ if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs,
+ RParenLoc))
+ return true;
+
+ return CheckFunctionCall(Method, TheCall.take());
+}
+
/// BuildCallToObjectOfClassType - Build a call to an object of class
/// type (C++ [over.call.object]), which can end up invoking an
/// overloaded function call operator (@c operator()) or performing a
/// user-defined conversion on the object argument.
-Action::ExprResult
+Sema::ExprResult
Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
@@ -3552,6 +3673,9 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
"Expected overloaded function");
DR->setDecl(Fn);
E->setType(Fn->getType());
+ } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) {
+ MemExpr->setMemberDecl(Fn);
+ E->setType(Fn->getType());
} else {
assert(false && "Invalid reference to overloaded function");
}