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