MS ABI: Fix inheritance model calculation in CRTP
authorDavid Majnemer <david.majnemer@gmail.com>
Fri, 13 Jun 2014 06:43:46 +0000 (06:43 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Fri, 13 Jun 2014 06:43:46 +0000 (06:43 +0000)
CRTP-like patterns involve a class which inherits from another class
using itself as a template parameter.

However, the base class itself may try to create a pointer-to-member
which involves the derived class.  This is problematic because we
may not have finished parsing the most derived classes' base specifiers
yet.

It turns out that MSVC simply uses the unspecified inheritance model
instead of doing anything fancy.

This fixes PR19987.

llvm-svn: 210886

clang/include/clang/AST/DeclCXX.h
clang/lib/AST/DeclCXX.cpp
clang/lib/AST/MicrosoftCXXABI.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp

index 56bbbb16910c58eb17a9d2f3116007a6d5f221f4..72fad7c28e496bd8939b979d93df93f7809a0ff0 100644 (file)
@@ -462,6 +462,9 @@ class CXXRecordDecl : public RecordDecl {
     /// \brief Whether this class describes a C++ lambda.
     bool IsLambda : 1;
 
+    /// \brief Whether we are currently parsing base specifiers.
+    bool IsParsingBaseSpecifiers : 1;
+
     /// \brief The number of base class specifiers in Bases.
     unsigned NumBases;
 
@@ -685,6 +688,12 @@ public:
     return data().Polymorphic || data().NumVBases != 0;
   }
 
+  void setIsParsingBaseSpecifiers() { data().IsParsingBaseSpecifiers = true; }
+
+  bool isParsingBaseSpecifiers() const {
+    return data().IsParsingBaseSpecifiers;
+  }
+
   /// \brief Sets the base classes of this struct or class.
   void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
 
index 0ac8b73e306ea63b6fd63d5a1825a8da1b368468..43d0fca9f924826909bc53f406b1a1218349539c 100644 (file)
@@ -70,7 +70,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
     ImplicitCopyAssignmentHasConstParam(true),
     HasDeclaredCopyConstructorWithConstParam(false),
     HasDeclaredCopyAssignmentWithConstParam(false),
-    IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
+    IsLambda(false), IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0),
+    Bases(), VBases(),
     Definition(D), FirstFriend() {
 }
 
@@ -334,8 +335,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
     addedClassSubobject(BaseClassDecl);
   }
   
-  if (VBases.empty())
+  if (VBases.empty()) {
+    data().IsParsingBaseSpecifiers = false;
     return;
+  }
 
   // Create base specifier for any direct or indirect virtual bases.
   data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
@@ -346,6 +349,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
       addedClassSubobject(Type->getAsCXXRecordDecl());
     data().getVBases()[I] = *VBases[I];
   }
+
+  data().IsParsingBaseSpecifiers = false;
 }
 
 void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
index 359e8648278e705b4b8de8940b7d2c543aa7e101..6870315b2160c227a069a7430735f1110a35580a 100644 (file)
@@ -93,7 +93,7 @@ static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
 }
 
 MSInheritanceAttr::Spelling CXXRecordDecl::calculateInheritanceModel() const {
-  if (!hasDefinition())
+  if (!hasDefinition() || isParsingBaseSpecifiers())
     return MSInheritanceAttr::Keyword_unspecified_inheritance;
   if (getNumVBases() > 0)
     return MSInheritanceAttr::Keyword_virtual_inheritance;
index 57e6550cec522b084a76ace52f9e8b56bc4d46cb..ed7908dfc924105c1e7a2df8d2246470b145fa27 100644 (file)
@@ -1431,6 +1431,9 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
   if (!Class)
     return true;
 
+  // We haven't yet attached the base specifiers.
+  Class->setIsParsingBaseSpecifiers();
+
   // We do not support any C++11 attributes on base-specifiers yet.
   // Diagnose any attributes we see.
   if (!Attributes.empty()) {
index 48bc2c721f04abd9f30f580b0b75b6303925f258..18e8c827eebe97fdadbb04b9aceca0869e736ae7 100644 (file)
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -fms-extensions | FileCheck %s
-// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 -fms-extensions | FileCheck %s -check-prefix=X64
-// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -fms-extensions -verify
-// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -DMEMFUN -fms-extensions -verify
+// 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.
 
@@ -630,6 +630,17 @@ 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 pr19987 {
+template <typename T>
+struct S {
+  int T::*x;
+};
+
+struct U : S<U> {};
+
+static_assert(sizeof(S<U>::x) == 12, "");
+}
+
 #else
 struct __virtual_inheritance A;
 #ifdef MEMFUN