From: Sebastian Redl Date: Wed, 4 Feb 2009 21:23:32 +0000 (+0000) Subject: Implement taking address of member functions, including overloaded ones. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=33b399a8fdd0910ed86b60e61c6a02ba8258bbe3;p=clang Implement taking address of member functions, including overloaded ones. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63779 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 66cbdfd26a..66710370af 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3498,11 +3498,18 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { } } else if (isa(dcl)) { // Okay: we can take the address of a function. + // As above. + if (isa(op)) { + DeclContext *Ctx = dcl->getDeclContext(); + if (Ctx && Ctx->isRecord()) + return Context.getMemberPointerType(op->getType(), + Context.getTypeDeclType(cast(Ctx)).getTypePtr()); + } } else assert(0 && "Unknown/unexpected decl type"); } - + // If the operand has type "type", the result has type "pointer to type". return Context.getPointerType(op->getType()); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 44cd5b5e53..1edb470dd6 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -489,7 +489,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // type "pointer to T." The result is a pointer to the // function. (C++ 4.3p1). FromType = Context.getPointerType(FromType); - } + } // Address of overloaded function (C++ [over.over]). else if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, false)) { @@ -500,7 +500,17 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, FromType = Fn->getType(); if (ToType->isReferenceType()) FromType = Context.getReferenceType(FromType); - else + else if (ToType->isMemberPointerType()) { + // Resolve address only succeeds if both sides are member pointers, + // but it doesn't have to be the same class. See DR 247. + // Note that this means that the type of &Derived::fn can be + // Ret (Base::*)(Args) if the fn overload actually found is from the + // base class, even if it was brought into the derived class via a + // using declaration. The standard isn't clear on this issue at all. + CXXMethodDecl *M = cast(Fn); + FromType = Context.getMemberPointerType(FromType, + Context.getTypeDeclType(M->getParent()).getTypePtr()); + } else FromType = Context.getPointerType(FromType); } // We don't require any conversions for the first step. @@ -3409,11 +3419,17 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, /// resolved, and NULL otherwise. When @p Complain is true, this /// routine will emit diagnostics if there is an error. FunctionDecl * -Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, +Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain) { QualType FunctionType = ToType; + bool IsMember = false; if (const PointerLikeType *ToTypePtr = ToType->getAsPointerLikeType()) FunctionType = ToTypePtr->getPointeeType(); + else if (const MemberPointerType *MemTypePtr = + ToType->getAsMemberPointerType()) { + FunctionType = MemTypePtr->getPointeeType(); + IsMember = true; + } // We only look at pointers or references to functions. if (!FunctionType->isFunctionType()) @@ -3454,10 +3470,16 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // C++ [over.over]p3: // Non-member functions and static member functions match // targets of type “pointer-to-function”or - // “reference-to-function.” - if (CXXMethodDecl *Method = dyn_cast(*Fun)) - if (!Method->isStatic()) + // “reference-to-function.” Nonstatic member functions match targets of + // type "pointer-to-member-function." + // Note that according to DR 247, the containing class does not matter. + if (CXXMethodDecl *Method = dyn_cast(*Fun)) { + // Skip non-static functions when converting to pointer, and static + // when converting to member pointer. + if (Method->isStatic() == IsMember) continue; + } else if (IsMember) + continue; if (FunctionType == Context.getCanonicalType((*Fun)->getType())) return *Fun; diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp index 450fdba367..64cfc68c01 100644 --- a/test/SemaCXX/member-pointer.cpp +++ b/test/SemaCXX/member-pointer.cpp @@ -41,10 +41,19 @@ void f() { pdi1 = pdid; // expected-error {{incompatible type assigning 'int struct D::*', expected 'int struct A::*'}} } -struct HasMembers +struct TheBase +{ + void d(); +}; + +struct HasMembers : TheBase { int i; void f(); + + void g(); + void g(int); + static void g(double); }; namespace Fake @@ -54,9 +63,19 @@ namespace Fake } void g() { + HasMembers hm; + int HasMembers::*pmi = &HasMembers::i; int *pni = &Fake::i; + int *pmii = &hm.i; - // FIXME: Test the member function, too. + void (HasMembers::*pmf)() = &HasMembers::f; void (*pnf)() = &Fake::f; + &hm.f; // expected-error {{address expression must be an lvalue or a function designator}} + + void (HasMembers::*pmgv)() = &HasMembers::g; + void (HasMembers::*pmgi)(int) = &HasMembers::g; + void (*pmgd)(double) = &HasMembers::g; + + void (HasMembers::*pmd)() = &HasMembers::d; } diff --git a/www/cxx_status.html b/www/cxx_status.html index c172a2c1e9..432e9643af 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -619,10 +619,10 @@ welcome!

      5.3.1p2-5 Unary & ✓ - - + ✓ + ✓ + - Member pointers not supported in any way       5.3.1p6 Unary +