[cfe-commits] r61329 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/AST/ExprCXX.h include/clang/AST/StmtNodes.def include/clang/Basic/DiagnosticKinds.def lib/AST/Expr.cpp lib/AST/ExprCXX.cpp lib/AST/StmtPrinter.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/SemaCXX/overload-member-call.cpp
Douglas Gregor
dgregor at apple.com
Sun Dec 21 21:46:10 PST 2008
Author: dgregor
Date: Sun Dec 21 23:46:06 2008
New Revision: 61329
URL: http://llvm.org/viewvc/llvm-project?rev=61329&view=rev
Log:
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.
Added:
cfe/trunk/test/SemaCXX/overload-member-call.cpp
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/AST/ExprCXX.h
cfe/trunk/include/clang/AST/StmtNodes.def
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/AST/StmtPrinter.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaOverload.h
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Sun Dec 21 23:46:06 2008
@@ -31,7 +31,9 @@
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 @@
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 @@
: 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 {
Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Sun Dec 21 23:46:06 2008
@@ -54,6 +54,31 @@
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.
Modified: cfe/trunk/include/clang/AST/StmtNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtNodes.def?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtNodes.def (original)
+++ cfe/trunk/include/clang/AST/StmtNodes.def Sun Dec 21 23:46:06 2008
@@ -92,6 +92,7 @@
// C++ Expressions.
STMT(CXXOperatorCallExpr , CallExpr)
+STMT(CXXMemberCallExpr , CallExpr)
STMT(CXXNamedCastExpr , ExplicitCastExpr)
STMT(CXXStaticCastExpr , CXXNamedCastExpr)
STMT(CXXDynamicCastExpr , CXXNamedCastExpr)
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Sun Dec 21 23:46:06 2008
@@ -937,8 +937,13 @@
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 @@
"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,
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Sun Dec 21 23:46:06 2008
@@ -487,16 +487,17 @@
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;
}
Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Sun Dec 21 23:46:06 2008
@@ -166,6 +166,14 @@
}
}
+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
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Sun Dec 21 23:46:06 2008
@@ -864,6 +864,10 @@
}
}
+void StmtPrinter::VisitCXXMemberCallExpr(CXXMemberCallExpr *Node) {
+ VisitCallExpr(cast<CallExpr>(Node));
+}
+
void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
OS << Node->getCastName() << '<';
OS << Node->getTypeAsWritten().getAsString() << ">(";
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sun Dec 21 23:46:06 2008
@@ -431,7 +431,7 @@
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 @@
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 @@
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
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sun Dec 21 23:46:06 2008
@@ -455,28 +455,78 @@
}
}
+ 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 @@
<< 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 @@
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 @@
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 @@
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 @@
}
}
+ 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());
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sun Dec 21 23:46:06 2008
@@ -1759,11 +1759,26 @@
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 @@
// 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 @@
OverloadCandidate& Candidate = CandidateSet.back();
Candidate.Function = Method;
Candidate.IsSurrogate = false;
+ Candidate.IgnoreObjectArgument = false;
unsigned NumArgsInProto = Proto->getNumArgs();
@@ -1866,13 +1881,18 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
"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");
}
Modified: cfe/trunk/lib/Sema/SemaOverload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.h?rev=61329&r1=61328&r2=61329&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Sun Dec 21 23:46:06 2008
@@ -231,6 +231,15 @@
/// (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
Added: cfe/trunk/test/SemaCXX/overload-member-call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-member-call.cpp?rev=61329&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/overload-member-call.cpp (added)
+++ cfe/trunk/test/SemaCXX/overload-member-call.cpp Sun Dec 21 23:46:06 2008
@@ -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(0); // expected-error{{no matching member function for call to 'f'; candidates are:}}
+
+ int& i3 = xc.g(0);
+ int& i4 = xcp->g(0);
+ float& f3 = x.g(0);
+ float& f4 = xp->g(0);
+ double& d1 = xp->g(0.0);
+ double& d2 = X::g(0.0);
+ X::g(0); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+
+ X::h(0); // expected-error{{call to non-static member function without an object argument}}
+}
More information about the cfe-commits
mailing list