[cfe-commits] r59732 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/overloaded-operator.cpp

Douglas Gregor doug.gregor at gmail.com
Thu Nov 20 08:27:10 PST 2008


Author: dgregor
Date: Thu Nov 20 10:27:02 2008
New Revision: 59732

URL: http://llvm.org/viewvc/llvm-project?rev=59732&view=rev
Log:
Add support for overloaded operator-> when used in a member access
expression (smart_ptr->mem).


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/overloaded-operator.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=59732&r1=59731&r2=59732&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Thu Nov 20 10:27:02 2008
@@ -892,6 +892,8 @@
      "call to constructor of '%0' is ambiguous; candidates are:")
 DIAG(err_ovl_ambiguous_oper, ERROR,
      "use of overloaded operator '%0' is ambiguous; candidates are:")
+DIAG(err_ovl_no_viable_oper, ERROR,
+     "no viable overloaded '%0'; candidates are:")
 DIAG(err_ovl_no_viable_object_call, ERROR,
      "no matching function for call to object of type '%0'")
 DIAG(err_ovl_no_viable_object_call_with_cands, ERROR,

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=59732&r1=59731&r2=59732&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Nov 20 10:27:02 2008
@@ -444,6 +444,10 @@
                                SourceLocation *CommaLocs, 
                                SourceLocation RParenLoc);
 
+  ExprResult BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
+                                      SourceLocation MemberLoc,
+                                      IdentifierInfo &Member);
+                                           
   /// Helpers for dealing with function parameters
   bool CheckParmsForFunctionDef(FunctionDecl *FD);
   void CheckCXXDefaultArguments(FunctionDecl *FD);

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=59732&r1=59731&r2=59732&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Nov 20 10:27:02 2008
@@ -1122,6 +1122,8 @@
   if (OpKind == tok::arrow) {
     if (const PointerType *PT = BaseType->getAsPointerType())
       BaseType = PT->getPointeeType();
+    else if (getLangOptions().CPlusPlus && BaseType->isRecordType())
+      return BuildOverloadedArrowExpr(BaseExpr, OpLoc, MemberLoc, Member);
     else
       return Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
         << BaseType.getAsString() << BaseExpr->getSourceRange();

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=59732&r1=59731&r2=59732&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Nov 20 10:27:02 2008
@@ -3148,6 +3148,86 @@
   return CheckFunctionCall(Method, TheCall.take());
 }
 
+/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator->
+///  (if one exists), where @c Base is an expression of class type and 
+/// @c Member is the name of the member we're trying to find.
+Action::ExprResult 
+Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
+                               SourceLocation MemberLoc,
+                               IdentifierInfo &Member) {
+  assert(Base->getType()->isRecordType() && "left-hand side must have class type");
+  
+  // C++ [over.ref]p1:
+  //
+  //   [...] An expression x->m is interpreted as (x.operator->())->m
+  //   for a class object x of type T if T::operator->() exists and if
+  //   the operator is selected as the best match function by the
+  //   overload resolution mechanism (13.3).
+  // FIXME: look in base classes.
+  DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
+  OverloadCandidateSet CandidateSet;
+  const RecordType *BaseRecord = Base->getType()->getAsRecordType();
+  IdentifierResolver::iterator I
+    = IdResolver.begin(OpName, cast<CXXRecordType>(BaseRecord)->getDecl(),
+                       /*LookInParentCtx=*/false);
+  NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I;
+  if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(MemberOps))
+    AddMethodCandidate(Method, Base, 0, 0, CandidateSet,
+                       /*SuppressUserConversions=*/false);
+  else if (OverloadedFunctionDecl *Ovl 
+             = dyn_cast_or_null<OverloadedFunctionDecl>(MemberOps)) {
+    for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+           FEnd = Ovl->function_end();
+         F != FEnd; ++F) {
+      if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*F))
+        AddMethodCandidate(Method, Base, 0, 0, CandidateSet,
+                           /*SuppressUserConversions=*/false);
+    }
+  }
+
+  // Perform overload resolution.
+  OverloadCandidateSet::iterator Best;
+  switch (BestViableFunction(CandidateSet, Best)) {
+  case OR_Success:
+    // Overload resolution succeeded; we'll build the call below.
+    break;
+
+  case OR_No_Viable_Function:
+    if (CandidateSet.empty())
+      Diag(OpLoc, diag::err_typecheck_member_reference_arrow)
+        << Base->getType().getAsString() << Base->getSourceRange();
+    else
+      Diag(OpLoc, diag::err_ovl_no_viable_oper)
+        << "operator->" << Base->getSourceRange();
+    PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+    delete Base;
+    return true;
+
+  case OR_Ambiguous:
+    Diag(OpLoc,  diag::err_ovl_ambiguous_oper)
+      << "operator->"
+      << Base->getSourceRange();
+    PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+    delete Base;
+    return true;
+  }
+
+  // Convert the object parameter.
+  CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
+  if (PerformObjectArgumentInitialization(Base, Method)) {
+    delete Base;
+    return true;
+  }
+
+  // Build the operator call.
+  Expr *FnExpr = new DeclRefExpr(Method, Method->getType(), SourceLocation());
+  UsualUnaryConversions(FnExpr);
+  Base = new CXXOperatorCallExpr(FnExpr, &Base, 1, 
+                                 Method->getResultType().getNonReferenceType(),
+                                 OpLoc);
+  return ActOnMemberReferenceExpr(Base, OpLoc, tok::arrow, MemberLoc, Member);
+}
+
 /// FixOverloadedFunctionReference - E is an expression that refers to
 /// a C++ overloaded function (possibly with some parentheses and
 /// perhaps a '&' around it). We have resolved the overloaded function

Modified: cfe/trunk/test/SemaCXX/overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-operator.cpp?rev=59732&r1=59731&r2=59732&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-operator.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-operator.cpp Thu Nov 20 10:27:02 2008
@@ -150,3 +150,21 @@
   ctf((long int)17, 2.0); // expected-error{{error: call to object of type 'struct ConvertToFunc' is ambiguous; candidates are:}}
   ctf();
 }
+
+struct HasMember {
+  int m;
+};
+
+struct Arrow1 {
+  HasMember* operator->();
+};
+
+struct Arrow2 {
+  Arrow1 operator->(); // expected-note{{candidate function}}
+};
+
+void test_arrow(Arrow1 a1, Arrow2 a2, const Arrow2 a3) {
+  int &i1 = a1->m;
+  int &i2 = a2->m;
+  a3->m; // expected-error{{no viable overloaded 'operator->'; candidates are}}
+}





More information about the cfe-commits mailing list