- 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

Reply via email to