Index: lib/CodeGen/CGCXXABI.h =================================================================== --- lib/CodeGen/CGCXXABI.h +++ lib/CodeGen/CGCXXABI.h @@ -161,6 +161,10 @@ return true; } + virtual bool isTypeInfoCalculable(QualType Ty) const { + return !Ty->isIncompleteType(); + } + /// Create a null member pointer of the given type. virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -1401,18 +1401,7 @@ CGM.getTBAAInfo(T)); } - LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { - CharUnits Alignment; - if (!T->isIncompleteType()) { - Alignment = getContext().getTypeAlignInChars(T); - unsigned MaxAlign = getContext().getLangOpts().MaxTypeAlign; - if (MaxAlign && Alignment.getQuantity() > MaxAlign && - !getContext().isAlignmentRequired(T)) - Alignment = CharUnits::fromQuantity(MaxAlign); - } - return LValue::MakeAddr(V, T, Alignment, getContext(), - CGM.getTBAAInfo(T)); - } + LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T); /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. The caller is responsible for setting an appropriate alignment on Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -79,6 +79,17 @@ } } +LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { + CharUnits Alignment; + if (CGM.getCXXABI().isTypeInfoCalculable(T)) { + Alignment = getContext().getTypeAlignInChars(T); + unsigned MaxAlign = getContext().getLangOpts().MaxTypeAlign; + if (MaxAlign && Alignment.getQuantity() > MaxAlign && + !getContext().isAlignmentRequired(T)) + Alignment = CharUnits::fromQuantity(MaxAlign); + } + return LValue::MakeAddr(V, T, Alignment, getContext(), CGM.getTBAAInfo(T)); +} llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) { return CGM.getTypes().ConvertTypeForMem(T); Index: lib/CodeGen/CodeGenTypes.cpp =================================================================== --- lib/CodeGen/CodeGenTypes.cpp +++ lib/CodeGen/CodeGenTypes.cpp @@ -81,7 +81,7 @@ /// ConvertType in that it is used to convert to the memory representation for /// a type. For example, the scalar representation for _Bool is i1, but the /// memory representation is usually i8 or i32, depending on the target. -llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T){ +llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) { llvm::Type *R = ConvertType(T); // If this is a non-bool type, don't map it. @@ -587,6 +587,8 @@ } case Type::MemberPointer: { + if (!getCXXABI().isMemberPointerConvertible(cast(Ty))) + return llvm::StructType::create(getLLVMContext()); ResultType = getCXXABI().ConvertMemberPointerType(cast(Ty)); break; Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -488,7 +488,18 @@ bool isMemberPointerConvertible(const MemberPointerType *MPT) const override { const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); - return RD->getAttr() != nullptr; + return RD->hasAttr(); + } + + virtual bool isTypeInfoCalculable(QualType Ty) const { + if (!CGCXXABI::isTypeInfoCalculable(Ty)) + return false; + if (const auto *MPT = Ty->getAs()) { + const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); + if (!RD->hasAttr()) + return false; + } + return true; } llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT) override; Index: test/CodeGenCXX/microsoft-abi-member-pointers.cpp =================================================================== --- test/CodeGenCXX/microsoft-abi-member-pointers.cpp +++ test/CodeGenCXX/microsoft-abi-member-pointers.cpp @@ -1,9 +1,19 @@ -// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck %s -// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 -fms-extensions | FileCheck %s -check-prefix=X64 -// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -fms-extensions -verify -// RUN: %clang_cc1 -std=c++11 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -DMEMFUN -fms-extensions -verify -// FIXME: Test x86_64 member pointers when codegen no longer asserts on records -// with virtual bases. +// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 -fms-extensions | FileCheck %s -check-prefix=X64 +// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -fms-extensions -verify +// RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -DMEMFUN -fms-extensions -verify + +namespace PR20947 { +struct A; +int A::**a = nullptr; +// CHECK: %[[opaque0:.*]] = type opaque +// CHECK: %[[opaque1:.*]] = type opaque +// CHECK: @"\01?a@PR20947@@3PAPQA@1@HA" = global %[[opaque0]]* null, align 4 + +struct B; +int B::*&b = b; +// CHECK: @"\01?b@PR20947@@3AAPQB@1@HA" = global %[[opaque1]]* null, align 4 +} #ifndef INCOMPLETE_VIRTUAL struct B1 {