[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