aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaExpr.cpp9
-rw-r--r--lib/Sema/SemaOverload.cpp34
-rw-r--r--test/SemaCXX/member-pointer.cpp23
-rw-r--r--www/cxx_status.html6
4 files changed, 60 insertions, 12 deletions
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<FunctionDecl>(dcl)) {
// Okay: we can take the address of a function.
+ // As above.
+ if (isa<QualifiedDeclRefExpr>(op)) {
+ DeclContext *Ctx = dcl->getDeclContext();
+ if (Ctx && Ctx->isRecord())
+ return Context.getMemberPointerType(op->getType(),
+ Context.getTypeDeclType(cast<RecordDecl>(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<CXXMethodDecl>(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<CXXMethodDecl>(*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<CXXMethodDecl>(*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!</p>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p2-5 Unary &amp;</td>
<td class="complete" align="center">&#x2713;</td>
- <td class="basic" align="center"></td>
- <td class="basic" align="center"></td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td></td>
<td></td>
- <td>Member pointers not supported in any way</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3.1p6 Unary +</td>