- Add a test-case for PR18479.
Hi rnk, rsmith,
http://llvm-reviews.chandlerc.com/D2548
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D2548?vs=6455&id=6456#toc
Files:
include/clang/AST/DeclCXX.h
include/clang/Basic/Attr.td
lib/AST/MicrosoftCXXABI.cpp
lib/CodeGen/MicrosoftCXXABI.cpp
lib/Sema/SemaType.cpp
test/SemaCXX/microsoft-abi-ptm.cpp
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -261,9 +261,7 @@
/// The inheritance model to use for member pointers of a given CXXRecordDecl.
enum MSInheritanceModel {
MSIM_Single,
- MSIM_SinglePolymorphic,
MSIM_Multiple,
- MSIM_MultiplePolymorphic,
MSIM_Virtual,
MSIM_Unspecified
};
@@ -1609,6 +1607,7 @@
/// \brief Returns the inheritance model used for this record.
MSInheritanceModel getMSInheritanceModel() const;
+ void setMSInheritanceModel();
/// \brief Determine whether this lambda expression was known to be dependent
/// at the time it was created, even if its context does not appear to be
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1354,7 +1354,12 @@
Accessor<"IsUnspecified", [Keyword<"">]>];
// This index is based off the Spellings list and corresponds to the empty
// keyword "spelling."
- let AdditionalMembers = [{static const int UnspecifiedSpellingIndex = 3;}];
+ let AdditionalMembers = [{
+ static const unsigned SingleSpellingIndex = 0;
+ static const unsigned MultipleSpellingIndex = 1;
+ static const unsigned VirtualSpellingIndex = 2;
+ static const unsigned UnspecifiedSpellingIndex = 3;
+ }];
}
def Unaligned : IgnoredAttr {
Index: lib/AST/MicrosoftCXXABI.cpp
===================================================================
--- lib/AST/MicrosoftCXXABI.cpp
+++ lib/AST/MicrosoftCXXABI.cpp
@@ -92,7 +92,8 @@
return false;
}
-static MSInheritanceModel MSInheritanceAttrToModel(MSInheritanceAttr *Attr) {
+static MSInheritanceModel
+MSInheritanceAttrToModel(const MSInheritanceAttr *Attr) {
if (Attr->IsSingle())
return MSIM_Single;
else if (Attr->IsMultiple())
@@ -104,16 +105,44 @@
return MSIM_Unspecified;
}
+static unsigned MSInheritanceModelToSpellingKind(MSInheritanceModel MSIM) {
+ switch (MSIM) {
+ case MSIM_Single:
+ return MSInheritanceAttr::SingleSpellingIndex;
+ case MSIM_Multiple:
+ return MSInheritanceAttr::MultipleSpellingIndex;
+ case MSIM_Virtual:
+ return MSInheritanceAttr::VirtualSpellingIndex;
+ case MSIM_Unspecified:
+ return MSInheritanceAttr::UnspecifiedSpellingIndex;
+ }
+}
+
+
+static MSInheritanceModel calculateInheritanceModel(const CXXRecordDecl *RD) {
+ if (!RD->hasDefinition())
+ return MSIM_Unspecified;
+ if (RD->getNumVBases() > 0)
+ return MSIM_Virtual;
+ if (usesMultipleInheritanceModel(RD))
+ return MSIM_Multiple;
+ return MSIM_Single;
+}
+
MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const {
- if (MSInheritanceAttr *IA = this->getAttr<MSInheritanceAttr>())
+ if (MSInheritanceAttr *IA = getAttr<MSInheritanceAttr>())
return MSInheritanceAttrToModel(IA);
- // If there was no explicit attribute, the record must be defined already, and
- // we can figure out the inheritance model from its other properties.
- if (this->getNumVBases() > 0)
- return MSIM_Virtual;
- if (usesMultipleInheritanceModel(this))
- return this->isPolymorphic() ? MSIM_MultiplePolymorphic : MSIM_Multiple;
- return this->isPolymorphic() ? MSIM_SinglePolymorphic : MSIM_Single;
+
+ return calculateInheritanceModel(this);
+}
+
+void CXXRecordDecl::setMSInheritanceModel() {
+ if (hasAttr<MSInheritanceAttr>())
+ return;
+
+ MSInheritanceModel MSIM = calculateInheritanceModel(this);
+ addAttr(::new (getASTContext()) MSInheritanceAttr(
+ SourceRange(), getASTContext(), MSInheritanceModelToSpellingKind(MSIM)));
}
// Returns the number of pointer and integer slots used to represent a member
@@ -148,7 +177,7 @@
getMSMemberPointerSlots(const MemberPointerType *MPT) {
const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
- unsigned Ptrs;
+ unsigned Ptrs = 0;
unsigned Ints = 0;
if (MPT->isMemberFunctionPointer()) {
// Member function pointers are a struct of a function pointer followed by a
@@ -160,22 +189,18 @@
switch (Inheritance) {
case MSIM_Unspecified: ++Ints; // VBTableOffset
case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset
- case MSIM_MultiplePolymorphic:
case MSIM_Multiple: ++Ints; // NonVirtualBaseAdjustment
- case MSIM_SinglePolymorphic:
case MSIM_Single: break; // Nothing
}
} else {
// Data pointers are an aggregate of ints. The first int is an offset
// followed by vbtable-related offsets.
- Ptrs = 0;
+ Ints = 1; // We always have a field offset.
switch (Inheritance) {
case MSIM_Unspecified: ++Ints; // VBTableOffset
case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset
- case MSIM_MultiplePolymorphic:
- case MSIM_Multiple: // Nothing
- case MSIM_SinglePolymorphic:
- case MSIM_Single: ++Ints; // Field offset
+ case MSIM_Multiple:
+ case MSIM_Single: break; // Nothing
}
}
return std::make_pair(Ptrs, Ints);
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1328,8 +1328,8 @@
static bool hasOnlyOneField(bool IsMemberFunction,
MSInheritanceModel Inheritance) {
- return Inheritance <= MSIM_SinglePolymorphic ||
- (!IsMemberFunction && Inheritance <= MSIM_MultiplePolymorphic);
+ return Inheritance <= MSIM_Single ||
+ (!IsMemberFunction && Inheritance <= MSIM_Multiple);
}
// Only member pointers to functions need a this adjustment, since it can be
@@ -1349,8 +1349,10 @@
// use zero for null. If there are multiple fields, we can use zero even if it
// is a valid field offset because null-ness testing will check the other
// fields.
-static bool nullFieldOffsetIsZero(MSInheritanceModel Inheritance) {
- return Inheritance != MSIM_Multiple && Inheritance != MSIM_Single;
+static bool nullFieldOffsetIsZero(const CXXRecordDecl *RD) {
+ if (RD->getMSInheritanceModel() >= MSIM_Virtual)
+ return true;
+ return RD->isPolymorphic();
}
bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
@@ -1365,7 +1367,7 @@
const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
return (!hasVirtualBaseAdjustmentField(Inheritance) &&
- nullFieldOffsetIsZero(Inheritance));
+ nullFieldOffsetIsZero(RD));
}
llvm::Type *
@@ -1401,7 +1403,7 @@
// FunctionPointerOrVirtualThunk
fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy));
} else {
- if (nullFieldOffsetIsZero(Inheritance))
+ if (nullFieldOffsetIsZero(RD))
fields.push_back(getZeroInt()); // FieldOffset
else
fields.push_back(getAllOnesInt()); // FieldOffset
@@ -1817,15 +1819,14 @@
const MemberPointerType *SrcTy =
E->getSubExpr()->getType()->castAs<MemberPointerType>();
const MemberPointerType *DstTy = E->getType()->castAs<MemberPointerType>();
- MSInheritanceModel SrcInheritance = getInheritanceFromMemptr(SrcTy);
- MSInheritanceModel DstInheritance = getInheritanceFromMemptr(DstTy);
bool IsFunc = SrcTy->isMemberFunctionPointer();
// If the classes use the same null representation, reinterpret_cast is a nop.
bool IsReinterpret = E->getCastKind() == CK_ReinterpretMemberPointer;
- if (IsReinterpret && (IsFunc ||
- nullFieldOffsetIsZero(SrcInheritance) ==
- nullFieldOffsetIsZero(DstInheritance)))
+ if (IsReinterpret &&
+ (IsFunc ||
+ nullFieldOffsetIsZero(SrcTy->getClass()->getAsCXXRecordDecl()) ==
+ nullFieldOffsetIsZero(DstTy->getClass()->getAsCXXRecordDecl())))
return Src;
CGBuilderTy &Builder = CGF.Builder;
@@ -1854,6 +1855,7 @@
llvm::Value *NonVirtualBaseAdjustment = 0;
llvm::Value *VirtualBaseAdjustmentOffset = 0;
llvm::Value *VBPtrOffset = 0;
+ MSInheritanceModel SrcInheritance = getInheritanceFromMemptr(SrcTy);
if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
// We need to extract values.
unsigned I = 0;
@@ -1884,6 +1886,7 @@
// FIXME PR15713: Support conversions through virtually derived classes.
// Recompose dst from the null struct and the adjusted fields from src.
+ MSInheritanceModel DstInheritance = getInheritanceFromMemptr(DstTy);
llvm::Value *Dst;
if (hasOnlyOneField(IsFunc, DstInheritance)) {
Dst = FirstField;
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -1751,35 +1751,6 @@
return QualType();
}
- // C++ allows the class type in a member pointer to be an incomplete type.
- // In the Microsoft ABI, the size of the member pointer can vary
- // according to the class type, which means that we really need a
- // complete type if possible, which means we need to instantiate templates.
- //
- // If template instantiation fails or the type is just incomplete, we have to
- // add an extra slot to the member pointer. Yes, this does cause problems
- // when passing pointers between TUs that disagree about the size.
- if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
- CXXRecordDecl *RD = Class->getAsCXXRecordDecl();
- if (RD && !RD->hasAttr<MSInheritanceAttr>()) {
- // Lock in the inheritance model on the first use of a member pointer.
- // Otherwise we may disagree about the size at different points in the TU.
- // FIXME: MSVC picks a model on the first use that needs to know the size,
- // rather than on the first mention of the type, e.g. typedefs.
- if (RequireCompleteType(Loc, Class, 0) && !RD->isBeingDefined()) {
- // We know it doesn't have an attribute and it's incomplete, so use the
- // unspecified inheritance model. If we're in the record body, we can
- // figure out the inheritance model.
- for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
- E = RD->redecls_end(); I != E; ++I) {
- I->addAttr(::new (Context) MSInheritanceAttr(RD->getSourceRange(),
- Context,
- MSInheritanceAttr::UnspecifiedSpellingIndex));
- }
- }
- }
- }
-
// Adjust the default free function calling convention to the default method
// calling convention.
if (T->isFunctionType())
@@ -5094,6 +5065,21 @@
}
}
+ // We lock-in the inheritance model once somebody has asked us to ensure
+ // that a pointer-to-member type is complete.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) {
+ if (!MPTy->getClass()->isDependentType()) {
+ RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), 0);
+
+ MPTy->getClass()
+ ->getAsCXXRecordDecl()
+ ->getMostRecentDecl()
+ ->setMSInheritanceModel();
+ }
+ }
+ }
+
return false;
}
Index: test/SemaCXX/microsoft-abi-ptm.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/microsoft-abi-ptm.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple %ms_abi_triple -std=c++11 -fsyntax-only %s
+
+struct A;
+void f(int A::*mp);
+struct A { };
+static_assert(sizeof(int A::*) == sizeof(int), "pointer-to-member should be sizeof(int)");
+
+struct B;
+void f(int B::*mp);
+static_assert(sizeof(int B::*) == sizeof(int) * 3, "pointer-to-member should be sizeof(int)*4");
+struct B { };
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits