diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-12-22 05:46:06 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-12-22 05:46:06 +0000 |
commit | 88a3514f36de96b19cdf50141c640df1a5f13f6c (patch) | |
tree | a15713eacba3dc51acc9af629d852ace77db9ea7 | |
parent | b595509bf5c07b65616d9c7ef26dca4858768ac7 (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
-rw-r--r-- | include/clang/AST/Expr.h | 13 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 25 | ||||
-rw-r--r-- | include/clang/AST/StmtNodes.def | 1 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 7 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 11 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 8 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 13 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 238 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 148 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.h | 9 | ||||
-rw-r--r-- | test/SemaCXX/overload-member-call.cpp | 39 |
12 files changed, 417 insertions, 99 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 48267bafa6..62a93b51e8 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -31,7 +31,9 @@ namespace clang { class NamedDecl; class ValueDecl; class BlockDecl; - + class CXXOperatorCallExpr; + class CXXMemberCallExpr; + /// Expr - This represents one expression. Note that Expr's are subclasses of /// Stmt. This allows an expression to be transparently used any place a Stmt /// is required. @@ -815,10 +817,13 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == CallExprClass || - T->getStmtClass() == CXXOperatorCallExprClass; + T->getStmtClass() == CXXOperatorCallExprClass || + T->getStmtClass() == CXXMemberCallExprClass; } static bool classof(const CallExpr *) { return true; } - + static bool classof(const CXXOperatorCallExpr *) { return true; } + static bool classof(const CXXMemberCallExpr *) { return true; } + // Iterators virtual child_iterator child_begin(); virtual child_iterator child_end(); @@ -841,8 +846,10 @@ public: : Expr(MemberExprClass, ty), Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow) {} + void setBase(Expr *E) { Base = E; } Expr *getBase() const { return cast<Expr>(Base); } NamedDecl *getMemberDecl() const { return MemberDecl; } + void setMemberDecl(NamedDecl *D) { MemberDecl = D; } bool isArrow() const { return IsArrow; } virtual SourceRange getSourceRange() const { diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 74df215293..31dfd25833 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -54,6 +54,31 @@ public: static bool classof(const CXXOperatorCallExpr *) { return true; } }; +/// CXXMemberCallExpr - Represents a call to a member function that +/// may be written either with member call syntax (e.g., "obj.func()" +/// or "objptr->func()") or with normal function-call syntax +/// ("func()") within a member function that ends up calling a member +/// function. The callee in either case is a MemberExpr that contains +/// both the object argument and the member function, while the +/// arguments are the arguments within the parentheses (not including +/// the object argument). +class CXXMemberCallExpr : public CallExpr { +public: + CXXMemberCallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t, + SourceLocation rparenloc) + : CallExpr(CXXMemberCallExprClass, fn, args, numargs, t, rparenloc) { } + + /// getImplicitObjectArgument - Retrieves the implicit object + /// argument for the member call. For example, in "x.f(5)", this + /// operation would return "x". + Expr *getImplicitObjectArgument(); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXMemberCallExprClass; + } + static bool classof(const CXXMemberCallExpr *) { return true; } +}; + /// CXXNamedCastExpr - Abstract class common to all of the C++ "named" /// casts, @c static_cast, @c dynamic_cast, @c reinterpret_cast, or @c /// const_cast. diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index b49ad8a232..939325ac1f 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -92,6 +92,7 @@ STMT(GNUNullExpr , Expr) // C++ Expressions. STMT(CXXOperatorCallExpr , CallExpr) +STMT(CXXMemberCallExpr , CallExpr) STMT(CXXNamedCastExpr , ExplicitCastExpr) STMT(CXXStaticCastExpr , CXXNamedCastExpr) STMT(CXXDynamicCastExpr , CXXNamedCastExpr) diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 510f3ff916..bad9819ec8 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -937,8 +937,13 @@ DIAG(err_ovl_static_nonstatic_member, ERROR, DIAG(err_ovl_no_viable_function_in_call, ERROR, "no matching function for call to %0" "%plural{0:|1:; candidate is|:; candidates are:}1") +DIAG(err_ovl_no_viable_member_function_in_call, ERROR, + "no matching member function for call to %0" + "%plural{0:|1:; candidate is|:; candidates are:}1") DIAG(err_ovl_ambiguous_call, ERROR, "call to %0 is ambiguous; candidates are:") +DIAG(err_ovl_ambiguous_member_call, ERROR, + "call to member function %0 is ambiguous; candidates are:") DIAG(err_ovl_candidate, NOTE, "candidate function") DIAG(err_ovl_builtin_candidate, NOTE, @@ -959,6 +964,8 @@ DIAG(err_ovl_ambiguous_object_call, ERROR, "call to object of type %0 is ambiguous; candidates are:") DIAG(err_ovl_surrogate_cand, NOTE, "conversion candidate of type %0") +DIAG(err_member_call_without_object, ERROR, + "call to non-static member function without an object argument") /// C++ Templates Semantic Analysis DIAG(err_template_param_shadow, ERROR, diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index adad2a472a..6cfcdc4914 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -487,16 +487,17 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { return LV_InvalidExpression; } case CallExprClass: - case CXXOperatorCallExprClass: { + case CXXOperatorCallExprClass: + case CXXMemberCallExprClass: { // C++ [expr.call]p10: // A function call is an lvalue if and only if the result type // is a reference. QualType CalleeType = cast<CallExpr>(this)->getCallee()->getType(); if (const PointerType *FnTypePtr = CalleeType->getAsPointerType()) - if (const FunctionType *FnType - = FnTypePtr->getPointeeType()->getAsFunctionType()) - if (FnType->getResultType()->isReferenceType()) - return LV_Valid; + CalleeType = FnTypePtr->getPointeeType(); + if (const FunctionType *FnType = CalleeType->getAsFunctionType()) + if (FnType->getResultType()->isReferenceType()) + return LV_Valid; break; } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index b5d5b4c12f..4cc5c741cf 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -166,6 +166,14 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const { } } +Expr *CXXMemberCallExpr::getImplicitObjectArgument() { + if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) + return MemExpr->getBase(); + + // FIXME: Will eventually need to cope with member pointers. + return 0; +} + //===----------------------------------------------------------------------===// // Named casts //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 4061aa1497..81e158e657 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -864,6 +864,10 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { } } +void StmtPrinter::VisitCXXMemberCallExpr(CXXMemberCallExpr *Node) { + VisitCallExpr(cast<CallExpr>(Node)); +} + void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { OS << Node->getCastName() << '<'; OS << Node->getTypeAsWritten().getAsString() << ">("; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b620b70be0..f8923b4bf8 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -431,7 +431,7 @@ public: void AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = true); + bool SuppressUserConversions = false); void AddConversionCandidate(CXXConversionDecl *Conversion, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet); @@ -468,7 +468,11 @@ public: Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, SourceLocation RParenLoc); - + ExprResult + BuildCallToMemberFunction(Scope *S, Expr *MemExpr, + SourceLocation LParenLoc, Expr **Args, + unsigned NumArgs, SourceLocation *CommaLocs, + SourceLocation RParenLoc); ExprResult BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -696,6 +700,11 @@ public: tok::TokenKind OpKind, SourceLocation MemberLoc, IdentifierInfo &Member); + bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, + FunctionDecl *FDecl, + const FunctionTypeProto *Proto, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc); /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 7fafb14591..307e1ad45e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -455,28 +455,78 @@ Sema::ExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, } } + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { + if (!MD->isStatic()) { + // C++ [class.mfct.nonstatic]p2: + // [...] if name lookup (3.4.1) resolves the name in the + // id-expression to a nonstatic nontype member of class X or of + // a base class of X, the id-expression is transformed into a + // class member access expression (5.2.5) using (*this) (9.3.2) + // as the postfix-expression to the left of the '.' operator. + DeclContext *Ctx = 0; + QualType MemberType; + if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + Ctx = FD->getDeclContext(); + MemberType = FD->getType(); + + if (const ReferenceType *RefType = MemberType->getAsReferenceType()) + MemberType = RefType->getPointeeType(); + else if (!FD->isMutable()) { + unsigned combinedQualifiers + = MemberType.getCVRQualifiers() | MD->getTypeQualifiers(); + MemberType = MemberType.getQualifiedType(combinedQualifiers); + } + } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (!Method->isStatic()) { + Ctx = Method->getParent(); + MemberType = Method->getType(); + } + } else if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(D)) { + for (OverloadedFunctionDecl::function_iterator + Func = Ovl->function_begin(), + FuncEnd = Ovl->function_end(); + Func != FuncEnd; ++Func) { + if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(*Func)) + if (!DMethod->isStatic()) { + Ctx = Ovl->getDeclContext(); + MemberType = Context.OverloadTy; + break; + } + } + } + + if (Ctx && Ctx->isCXXRecord()) { + QualType CtxType = Context.getTagDeclType(cast<CXXRecordDecl>(Ctx)); + QualType ThisType = Context.getTagDeclType(MD->getParent()); + if ((Context.getCanonicalType(CtxType) + == Context.getCanonicalType(ThisType)) || + IsDerivedFrom(ThisType, CtxType)) { + // Build the implicit member access expression. + Expr *This = new CXXThisExpr(SourceLocation(), + MD->getThisType(Context)); + return new MemberExpr(This, true, cast<NamedDecl>(D), + SourceLocation(), MemberType); + } + } + } + } + if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { if (MD->isStatic()) // "invalid use of member 'x' in static member function" return Diag(Loc, diag::err_invalid_member_use_in_static_method) - << FD->getDeclName(); - if (MD->getParent() != FD->getDeclContext()) - // "invalid use of nonstatic data member 'x'" - return Diag(Loc, diag::err_invalid_non_static_member_use) << FD->getDeclName(); - - if (FD->isInvalidDecl()) - return true; - - // FIXME: Handle 'mutable'. - return new DeclRefExpr(FD, - FD->getType().getWithAdditionalQualifiers(MD->getTypeQualifiers()),Loc); } + // Any other ways we could have found the field in a well-formed + // program would have been turned into implicit member expressions + // above. return Diag(Loc, diag::err_invalid_non_static_member_use) << FD->getDeclName(); } + if (isa<TypedefDecl>(D)) return Diag(Loc, diag::err_unexpected_typedef) << Name; if (isa<ObjCInterfaceDecl>(D)) @@ -1409,13 +1459,87 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc, << BaseType << BaseExpr->getSourceRange(); } +/// ConvertArgumentsForCall - Converts the arguments specified in +/// Args/NumArgs to the parameter types of the function FDecl with +/// function prototype Proto. Call is the call expression itself, and +/// Fn is the function expression. For a C++ member function, this +/// routine does not attempt to convert the object argument. Returns +/// true if the call is ill-formed. +bool +Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, + FunctionDecl *FDecl, + const FunctionTypeProto *Proto, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc) { + // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by + // assignment, to the types of the corresponding parameter, ... + unsigned NumArgsInProto = Proto->getNumArgs(); + unsigned NumArgsToCheck = NumArgs; + + // If too few arguments are available (and we don't have default + // arguments for the remaining parameters), don't make the call. + if (NumArgs < NumArgsInProto) { + if (!FDecl || NumArgs < FDecl->getMinRequiredArguments()) + return Diag(RParenLoc, diag::err_typecheck_call_too_few_args) + << Fn->getType()->isBlockPointerType() << Fn->getSourceRange(); + // Use default arguments for missing arguments + NumArgsToCheck = NumArgsInProto; + Call->setNumArgs(NumArgsInProto); + } + + // If too many are passed and not variadic, error on the extras and drop + // them. + if (NumArgs > NumArgsInProto) { + if (!Proto->isVariadic()) { + Diag(Args[NumArgsInProto]->getLocStart(), + diag::err_typecheck_call_too_many_args) + << Fn->getType()->isBlockPointerType() << Fn->getSourceRange() + << SourceRange(Args[NumArgsInProto]->getLocStart(), + Args[NumArgs-1]->getLocEnd()); + // This deletes the extra arguments. + Call->setNumArgs(NumArgsInProto); + } + NumArgsToCheck = NumArgsInProto; + } + + // Continue to check argument types (even if we have too few/many args). + for (unsigned i = 0; i != NumArgsToCheck; i++) { + QualType ProtoArgType = Proto->getArgType(i); + + Expr *Arg; + if (i < NumArgs) + Arg = Args[i]; + else + Arg = new CXXDefaultArgExpr(FDecl->getParamDecl(i)); + QualType ArgType = Arg->getType(); + + // Pass the argument. + if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) + return true; + + Call->setArg(i, Arg); + } + + // If this is a variadic call, handle args passed through "...". + if (Proto->isVariadic()) { + // Promote the arguments (C99 6.5.2.2p7). + for (unsigned i = NumArgsInProto; i != NumArgs; i++) { + Expr *Arg = Args[i]; + DefaultArgumentPromotion(Arg); + Call->setArg(i, Arg); + } + } + + return false; +} + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. -Action::ExprResult Sema:: -ActOnCallExpr(Scope *S, ExprTy *fn, SourceLocation LParenLoc, - ExprTy **args, unsigned NumArgs, - SourceLocation *CommaLocs, SourceLocation RParenLoc) { +Action::ExprResult +Sema::ActOnCallExpr(Scope *S, ExprTy *fn, SourceLocation LParenLoc, + ExprTy **args, unsigned NumArgs, + SourceLocation *CommaLocs, SourceLocation RParenLoc) { Expr *Fn = static_cast<Expr *>(fn); Expr **Args = reinterpret_cast<Expr**>(args); assert(Fn && "no function call expression"); @@ -1454,6 +1578,20 @@ ActOnCallExpr(Scope *S, ExprTy *fn, SourceLocation LParenLoc, if (Dependent) return new CallExpr(Fn, Args, NumArgs, Context.DependentTy, RParenLoc); + // Determine whether this is a call to an object (C++ [over.call.object]). + if (getLangOptions().CPlusPlus && Fn->getType()->isRecordType()) + return BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc); + + // Determine whether this is a call to a member function. + if (getLangOptions().CPlusPlus) { + if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens())) + if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) || + isa<CXXMethodDecl>(MemExpr->getMemberDecl())) + return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc); + } + // If we're directly calling a function or a set of overloaded // functions, get the appropriate declaration. { @@ -1482,10 +1620,6 @@ ActOnCallExpr(Scope *S, ExprTy *fn, SourceLocation LParenLoc, Fn = NewFn; } - if (getLangOptions().CPlusPlus && Fn->getType()->isRecordType()) - return BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc); - // Promote the function operand. UsualUnaryConversions(Fn); @@ -1515,64 +1649,9 @@ ActOnCallExpr(Scope *S, ExprTy *fn, SourceLocation LParenLoc, TheCall->setType(FuncT->getResultType().getNonReferenceType()); if (const FunctionTypeProto *Proto = dyn_cast<FunctionTypeProto>(FuncT)) { - // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by - // assignment, to the types of the corresponding parameter, ... - unsigned NumArgsInProto = Proto->getNumArgs(); - unsigned NumArgsToCheck = NumArgs; - - // If too few arguments are available (and we don't have default - // arguments for the remaining parameters), don't make the call. - if (NumArgs < NumArgsInProto) { - if (!FDecl || NumArgs < FDecl->getMinRequiredArguments()) - return Diag(RParenLoc, diag::err_typecheck_call_too_few_args) - << Fn->getType()->isBlockPointerType() << Fn->getSourceRange(); - // Use default arguments for missing arguments - NumArgsToCheck = NumArgsInProto; - TheCall->setNumArgs(NumArgsInProto); - } - - // If too many are passed and not variadic, error on the extras and drop - // them. - if (NumArgs > NumArgsInProto) { - if (!Proto->isVariadic()) { - Diag(Args[NumArgsInProto]->getLocStart(), - diag::err_typecheck_call_too_many_args) - << Fn->getType()->isBlockPointerType() << Fn->getSourceRange() - << SourceRange(Args[NumArgsInProto]->getLocStart(), - Args[NumArgs-1]->getLocEnd()); - // This deletes the extra arguments. - TheCall->setNumArgs(NumArgsInProto); - } - NumArgsToCheck = NumArgsInProto; - } - - // Continue to check argument types (even if we have too few/many args). - for (unsigned i = 0; i != NumArgsToCheck; i++) { - QualType ProtoArgType = Proto->getArgType(i); - - Expr *Arg; - if (i < NumArgs) - Arg = Args[i]; - else - Arg = new CXXDefaultArgExpr(FDecl->getParamDecl(i)); - QualType ArgType = Arg->getType(); - - // Pass the argument. - if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) - return true; - - TheCall->setArg(i, Arg); - } - - // If this is a variadic call, handle args passed through "...". - if (Proto->isVariadic()) { - // Promote the arguments (C99 6.5.2.2p7). - for (unsigned i = NumArgsInProto; i != NumArgs; i++) { - Expr *Arg = Args[i]; - DefaultArgumentPromotion(Arg); - TheCall->setArg(i, Arg); - } - } + if (ConvertArgumentsForCall(&*TheCall, Fn, FDecl, Proto, Args, NumArgs, + RParenLoc)) + return true; } else { assert(isa<FunctionTypeNoProto>(FuncT) && "Unknown FunctionType!"); @@ -1584,6 +1663,11 @@ ActOnCallExpr(Scope *S, ExprTy *fn, SourceLocation LParenLoc, } } + if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl)) + if (!Method->isStatic()) + return Diag(LParenLoc, diag::err_member_call_without_object) + << Fn->getSourceRange(); + // Do special checking on direct calls to functions. if (FDecl) return CheckFunctionCall(FDecl, TheCall.take()); 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"); } diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index c7bf8b2d6d..096bbf56c9 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -231,6 +231,15 @@ namespace clang { /// (C++ [over.call.object]). bool IsSurrogate; + /// IgnoreObjectArgument - True to indicate that the first + /// argument's conversion, which for this function represents the + /// implicit object argument, should be ignored. This will be true + /// when the candidate is a static member function (where the + /// implicit object argument is just a placeholder) or a + /// non-static member function when the call doesn't have an + /// object argument. + bool IgnoreObjectArgument; + /// FinalConversion - For a conversion function (where Function is /// a CXXConversionDecl), the standard conversion that occurs /// after the call to the overload candidate to convert the result diff --git a/test/SemaCXX/overload-member-call.cpp b/test/SemaCXX/overload-member-call.cpp new file mode 100644 index 0000000000..9c0117f9b1 --- /dev/null +++ b/test/SemaCXX/overload-member-call.cpp @@ -0,0 +1,39 @@ +// RUN: clang -fsyntax-only -verify %s + +struct X { + int& f(int) const; // expected-note{{candidate function}} + float& f(int); // expected-note{{candidate function}} + + void test_f(int x) const { + int& i = f(x); + } + + void test_f2(int x) { + float& f2 = f(x); + } + + int& g(int) const; // expected-note{{candidate function}} + float& g(int); // expected-note{{candidate function}} + static double& g(double); // expected-note{{candidate function}} + + void h(int); +}; + +void test(X x, const X xc, X* xp, const X* xcp, volatile X xv, volatile X* xvp) { + int& i1 = xc.f(0); + int& i2 = xcp->f(0); + float& f1 = x.f(0); + float& f2 = xp->f(0); + xv.f(0); // expected-error{{no matching member function for call to 'f'; candidates are:}} + xvp->f |