MS ABI: Handle member function pointers returning a member data pointer

MSVC doesn't decide what the inheritance model for a returned member
pointer *until* a call expression returns it.

This fixes PR20017.

llvm-svn: 215164
This commit is contained in:
David Majnemer 2014-08-07 22:56:13 +00:00
parent 76e8af88b8
commit b3e5654923
5 changed files with 39 additions and 1 deletions

View File

@ -156,6 +156,11 @@ public:
/// (in the C++ sense) with an LLVM zeroinitializer.
virtual bool isZeroInitializable(const MemberPointerType *MPT);
/// Return whether or not a member pointers type is convertible to an IR type.
virtual bool isMemberPointerConvertible(const MemberPointerType *MPT) const {
return true;
}
/// Create a null member pointer of the given type.
virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);

View File

@ -187,6 +187,11 @@ static bool isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT) {
/// we've temporarily deferred expanding the type because we're in a recursive
/// context.
bool CodeGenTypes::isFuncParamTypeConvertible(QualType Ty) {
// Some ABIs cannot have their member pointers represented in IR unless
// certain circumstances have been reached.
if (const auto *MPT = Ty->getAs<MemberPointerType>())
return getCXXABI().isMemberPointerConvertible(MPT);
// If this isn't a tagged type, we can convert it!
const TagType *TT = Ty->getAs<TagType>();
if (!TT) return true;
@ -194,7 +199,7 @@ bool CodeGenTypes::isFuncParamTypeConvertible(QualType Ty) {
// Incomplete types cannot be converted.
if (TT->isIncompleteType())
return false;
// If this is an enum, then it is always safe to convert.
const RecordType *RT = dyn_cast<RecordType>(TT);
if (!RT) return true;

View File

@ -482,6 +482,11 @@ public:
bool isZeroInitializable(const MemberPointerType *MPT) override;
bool isMemberPointerConvertible(const MemberPointerType *MPT) const override {
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
return RD->getAttr<MSInheritanceAttr>() != nullptr;
}
llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT) override;
llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,

View File

@ -11353,6 +11353,10 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
<< (qualsString.find(' ') == std::string::npos ? 1 : 2);
}
if (resultType->isMemberPointerType())
if (Context.getTargetInfo().getCXXABI().isMicrosoft())
RequireCompleteType(LParenLoc, resultType, 0);
CXXMemberCallExpr *call
= new (Context) CXXMemberCallExpr(Context, MemExprE, Args,
resultType, valueKind, RParenLoc);

View File

@ -249,6 +249,25 @@ struct __virtual_inheritance D;
struct D : virtual B {};
}
#ifdef VMB
namespace PR20017 {
template <typename T>
struct A {
int T::*f();
};
struct B;
auto a = &A<B>::f;
struct B {};
void q() {
A<B> b;
(b.*a)();
}
}
#pragma pointers_to_members(full_generality, multiple_inheritance)
struct TrulySingleInheritance;
static_assert(sizeof(int TrulySingleInheritance::*) == kMultipleDataSize, "");