diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-11-20 16:27:02 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-11-20 16:27:02 +0000 |
commit | 8ba10745f525467e91bbaec21044bf4d9017a988 (patch) | |
tree | 8860100e2499e1da10c95555a4989cc6c6afe243 /lib | |
parent | 81d24e135c60dcbe421864e6a4334ba99b8fe7ec (diff) |
Add support for overloaded operator-> when used in a member access
expression (smart_ptr->mem).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59732 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 80 |
3 files changed, 86 insertions, 0 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3e5a511d33..ba647cae89 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -444,6 +444,10 @@ public: 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); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 50025b284e..cb06b0fe66 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1122,6 +1122,8 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc, 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(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 36f2def2f1..677696aa55 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3148,6 +3148,86 @@ Sema::BuildCallToObjectOfClassType(Expr *Object, SourceLocation LParenLoc, 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 |