Add support for overloaded operator-> when used in a member access

expression (smart_ptr->mem).

llvm-svn: 59732
This commit is contained in:
Douglas Gregor 2008-11-20 16:27:02 +00:00
parent 6bc5f3ec90
commit e0e79bdef6
5 changed files with 106 additions and 0 deletions

View File

@ -892,6 +892,8 @@ DIAG(err_ovl_ambiguous_init, ERROR,
"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,

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -150,3 +150,21 @@ void test_funcptr_call(ConvertToFunc ctf) {
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}}
}