]> granicus.if.org Git - clang/commitdiff
MS ABI: Don't force bases to have an inheritance model
authorDavid Majnemer <david.majnemer@gmail.com>
Fri, 8 Aug 2014 00:10:39 +0000 (00:10 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Fri, 8 Aug 2014 00:10:39 +0000 (00:10 +0000)
Previously, assigning an inheritance model to a derived class would
trigger further assiginments to the various bases of the class.  This
was done to fix a bug where we couldn't handle an implicit
base-to-derived conversion for pointers-to-members when the conversion
was ambiguous at an earlier point.

However, this is not how the MS scheme works.  Instead, assign
inheritance models to *just* the class which owns to declaration we
ended up referencing.

N.B.  This result is surprising in many ways.  It means that it is
possible for a base to have a "larger" inheritance model than it's
derived classes.  It also means that bases in the conversion path do not
get assigned a model.

struct A { void f(); void f(int); };
struct B : A {};
struct C : B {};
void f() { void (C::*x)() = &A::f; }

We can only begin to assign an inheritance model *after* we've seen the
address-of but *before* we've done the implicit conversion the more
derived pointer-to-member type.  After that point, both 'A' and 'C' will
have an inheritance model but 'B' will not.  Surprising, right?

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@215174 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaType.cpp
test/CodeGenCXX/microsoft-abi-member-pointers.cpp

index eb7924f473a93f2cb0e99260b00a68bae96a20d9..49d1fdfb3f224cc0465582fd6cfca40fd15094cc 100644 (file)
@@ -2898,6 +2898,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
       return ExprError();
     if (CheckExceptionSpecCompatibility(From, ToType))
       return ExprError();
+
+    // We may not have been able to figure out what this member pointer resolved
+    // to up until this exact point.  Attempt to lock-in it's inheritance model.
+    QualType FromType = From->getType();
+    if (FromType->isMemberPointerType())
+      if (Context.getTargetInfo().getCXXABI().isMicrosoft())
+        RequireCompleteType(From->getExprLoc(), FromType, 0);
+
     From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
              .get();
     break;
index b6b024c89abfa840c31e92202039b0848a5b31a0..029d2c2806cf2bdcba89c290450536a72f6ea011 100644 (file)
@@ -5163,14 +5163,6 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
             ? S.ImplicitMSInheritanceAttrLoc
             : RD->getSourceRange()));
   }
-
-  if (RD->hasDefinition()) {
-    // Assign inheritance models to all of the base classes, because now we can
-    // form pointers to members of base classes without calling
-    // RequireCompleteType on the pointer to member of the base class type.
-    for (const CXXBaseSpecifier &BS : RD->bases())
-      assignInheritanceModel(S, BS.getType()->getAsCXXRecordDecl());
-  }
 }
 
 /// \brief The implementation of RequireCompleteType
index 18e8c827eebe97fdadbb04b9aceca0869e736ae7..80d92de3ec3822ee7c13aad147c967215ad21889 100644 (file)
@@ -630,6 +630,34 @@ void test() { void (B::*a)() = &B::f; }
 // CHECK: store i8* bitcast (void (%"struct.pr20007_kw::A"*)* @"\01?f@A@pr20007_kw@@QAEXXZ" to i8*)
 }
 
+namespace pr20007_pragma {
+struct A {
+  void f();
+  void f(int);
+};
+struct B : public A {};
+void test() { (void)(void (B::*)()) &B::f; }
+#pragma pointers_to_members(full_generality, virtual_inheritance)
+static_assert(sizeof(int B::*) == 4, "");
+static_assert(sizeof(int A::*) == 4, "");
+#pragma pointers_to_members(best_case)
+// CHECK-LABEL: define void @"\01?test@pr20007_pragma@@YAXXZ"
+}
+
+namespace pr20007_pragma2 {
+struct A {
+};
+struct B : public A {
+  void f();
+};
+void test() { (void)&B::f; }
+#pragma pointers_to_members(full_generality, virtual_inheritance)
+static_assert(sizeof(int B::*) == 4, "");
+static_assert(sizeof(int A::*) == 12, "");
+#pragma pointers_to_members(best_case)
+// CHECK-LABEL: define void @"\01?test@pr20007_pragma2@@YAXXZ"
+}
+
 namespace pr19987 {
 template <typename T>
 struct S {