[PATCH] [ms-cxxabi] Correctly compute the size of member pointers

Reid Kleckner rnk at google.com
Thu Mar 21 14:46:05 PDT 2013


Hi rjmccall,

This also relaxes the requirement on Windows that the member pointer
class type be a complete type (http://llvm.org/PR12070).  We still ask
for a complete type to instantiate any templates (MSVC does this), but
if that fails we continue as normal, relying on any inheritance
attributes on the declaration.

http://llvm-reviews.chandlerc.com/D568

Files:
  lib/AST/MicrosoftCXXABI.cpp
  lib/Sema/SemaType.cpp
  test/SemaCXX/member-pointer-ms.cpp

Index: lib/AST/MicrosoftCXXABI.cpp
===================================================================
--- lib/AST/MicrosoftCXXABI.cpp
+++ lib/AST/MicrosoftCXXABI.cpp
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CXXABI.h"
+#include "clang/AST/Attr.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/RecordLayout.h"
@@ -52,17 +53,57 @@
 };
 }
 
+// getNumBases() seems to only give us the number of direct bases, and not the
+// total.  This function tells us if we inherit from anybody that uses MI.
+static bool recordHasMultipleInheritance(const CXXRecordDecl *RD) {
+  while (RD->getNumBases() > 0) {
+    if (RD->getNumBases() > 1)
+      return true;
+    assert(RD->getNumBases() == 1);
+    RD = RD->bases_begin()->getType()->getAsCXXRecordDecl();
+  }
+  return false;
+}
+
 unsigned MicrosoftCXXABI::getMemberPointerSize(const MemberPointerType *MPT) const {
   QualType Pointee = MPT->getPointeeType();
   CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
-  if (RD->getNumVBases() > 0) {
-    if (Pointee->isFunctionType())
-      return 3;
+  attr::Kind Inheritance;
+
+  if (RD->getTypeForDecl()->isIncompleteType()) {
+    if (Attr *IA = RD->getAttr<SingleInheritanceAttr>())
+      Inheritance = IA->getKind();
+    else if (Attr *IA = RD->getAttr<MultipleInheritanceAttr>())
+      Inheritance = IA->getKind();
+    else if (Attr *IA = RD->getAttr<VirtualInheritanceAttr>())
+      Inheritance = IA->getKind();
+    else {
+      // This last case seems like an error, but MSVC allocates one more slot
+      // than is used for virtual inheritance.  We follow suit for
+      // compatibility.
+      // FIXME: Issue a warning.
+      return 3 + int(Pointee->isFunctionType());
+    }
+  } else {
+    if (RD->getNumVBases() > 0)
+      Inheritance = attr::VirtualInheritance;
+    else if (recordHasMultipleInheritance(RD))
+      Inheritance = attr::MultipleInheritance;
     else
-      return 2;
-  } else if (RD->getNumBases() > 1 && Pointee->isFunctionType())
-    return 2;
-  return 1;
+      Inheritance = attr::SingleInheritance;
+  }
+
+  switch (Inheritance) {
+  case attr::SingleInheritance:
+    return 1;
+  case attr::MultipleInheritance:
+    return 1 + int(Pointee->isFunctionType());
+  case attr::VirtualInheritance:
+    return 2 + int(Pointee->isFunctionType());
+  default:
+    llvm_unreachable("unknown inheritance model");
+    return 0;
+  }
 }
 
 CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -1719,13 +1719,11 @@
   // according to the class type, which means that we really need a
   // complete type if possible, which means we need to instantiate templates.
   //
-  // For now, just require a complete type, which will instantiate
-  // templates.  This will also error if the type is just forward-declared,
-  // which is a bug, but it's a bug that saves us from dealing with some
-  // complexities at the moment.
-  if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
-      RequireCompleteType(Loc, Class, diag::err_incomplete_type))
-    return QualType();
+  // If template instantiation fails or the type is just incomplete, the ABI has
+  // a poorly understood fallback mechanism in place, so we continue without any
+  // diagnostics.
+  if (Context.getTargetInfo().getCXXABI().isMicrosoft())
+    RequireCompleteType(Loc, Class, 0);
 
   return Context.getMemberPointerType(T, Class.getTypePtr());
 }
Index: test/SemaCXX/member-pointer-ms.cpp
===================================================================
--- test/SemaCXX/member-pointer-ms.cpp
+++ test/SemaCXX/member-pointer-ms.cpp
@@ -1,14 +1,74 @@
-// RUN: %clang_cc1 -cxx-abi microsoft -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -cxx-abi microsoft -fms-compatibility -fsyntax-only -verify %s
+//
+// This file should also give no diagnostics when run through cl.exe from MSVS
+// 2012, which supports C++11 and static_assert.
+// expected-no-diagnostics
 
-// Test that we reject pointers to members of incomplete classes (for now)
-struct A; //expected-note{{forward declaration of 'A'}}
-int A::*pai1; //expected-error{{incomplete type 'A'}}
+// Test the size of various member pointer combinations:
+// - complete and incomplete
+// - single, multiple, and virtual inheritance (and unspecified for incomplete)
+// - data and function pointers
+// - templated with declared specializations with annotations
+// - template that can be instantiated
 
-// Test that we don't allow reinterpret_casts from pointers of one size to
-// pointers of a different size.
-struct A {};
-struct B {};
-struct C: A, B {};
+// Use std=c++11 for static_assert.
 
-void (A::*paf)();
-void (C::*pcf)() = reinterpret_cast<void (C::*)()>(paf); //expected-error{{cannot reinterpret_cast from member pointer type}}
+// http://llvm.org/PR12070
+struct Foo {
+  typedef int Foo::*FooInt;
+  int f;
+};
+
+// incomplete types
+class __single_inheritance IncSingle;
+class __multiple_inheritance IncMultiple;
+class __virtual_inheritance IncVirtual;
+static_assert(sizeof(int IncSingle::*)   == 1 * sizeof(void *), "");
+static_assert(sizeof(int IncMultiple::*) == 1 * sizeof(void *), "");
+static_assert(sizeof(int IncVirtual::*)  == 2 * sizeof(void *), "");
+static_assert(sizeof(void (IncSingle::*)())   == 1 * sizeof(void *), "");
+static_assert(sizeof(void (IncMultiple::*)()) == 2 * sizeof(void *), "");
+static_assert(sizeof(void (IncVirtual::*)())  == 3 * sizeof(void *), "");
+
+// An incomplete type with an unspecified inheritance model seems to take one
+// more slot than virtual.  It's not clear what it's used for yet.
+class IncUnspecified;
+static_assert(sizeof(int IncUnspecified::*) == 3 * sizeof(void *), "");
+static_assert(sizeof(void (IncUnspecified::*)()) == 4 * sizeof(void *), "");
+
+// complete types
+struct B1 { };
+struct B2 { };
+struct Single { };
+struct Multiple : B1, B2 { };
+struct Virtual : virtual B1 { };
+static_assert(sizeof(int Single::*)   == 1 * sizeof(void *), "");
+static_assert(sizeof(int Multiple::*) == 1 * sizeof(void *), "");
+static_assert(sizeof(int Virtual::*)  == 2 * sizeof(void *), "");
+static_assert(sizeof(void (Single::*)())   == 1 * sizeof(void *), "");
+static_assert(sizeof(void (Multiple::*)()) == 2 * sizeof(void *), "");
+static_assert(sizeof(void (Virtual::*)())  == 3 * sizeof(void *), "");
+
+// Test both declared and defined templates.
+template <typename T> class X;
+template <> class __single_inheritance   X<IncSingle>;
+template <> class __multiple_inheritance X<IncMultiple>;
+template <> class __virtual_inheritance  X<IncVirtual>;
+// Don't declare X<IncUnspecified>.
+static_assert(sizeof(int X<IncSingle>::*)           == 1 * sizeof(void *), "");
+static_assert(sizeof(int X<IncMultiple>::*)         == 1 * sizeof(void *), "");
+static_assert(sizeof(int X<IncVirtual>::*)          == 2 * sizeof(void *), "");
+static_assert(sizeof(int X<IncUnspecified>::*)      == 3 * sizeof(void *), "");
+static_assert(sizeof(void (X<IncSingle>::*)())      == 1 * sizeof(void *), "");
+static_assert(sizeof(void (X<IncMultiple>::*)())    == 2 * sizeof(void *), "");
+static_assert(sizeof(void (X<IncVirtual>::*)())     == 3 * sizeof(void *), "");
+static_assert(sizeof(void (X<IncUnspecified>::*)()) == 4 * sizeof(void *), "");
+
+template <typename T>
+struct Y : T { };
+static_assert(sizeof(int Y<Single>::*)        == 1 * sizeof(void *), "");
+static_assert(sizeof(int Y<Multiple>::*)      == 1 * sizeof(void *), "");
+static_assert(sizeof(int Y<Virtual>::*)       == 2 * sizeof(void *), "");
+static_assert(sizeof(void (Y<Single>::*)())   == 1 * sizeof(void *), "");
+static_assert(sizeof(void (Y<Multiple>::*)()) == 2 * sizeof(void *), "");
+static_assert(sizeof(void (Y<Virtual>::*)())  == 3 * sizeof(void *), "");
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D568.1.patch
Type: text/x-patch
Size: 7987 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130321/e8a8264f/attachment.bin>


More information about the cfe-commits mailing list