]> granicus.if.org Git - clang/commitdiff
[MS ABI] Allow a member pointers' converted type to change
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 26 Jan 2016 19:30:26 +0000 (19:30 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 26 Jan 2016 19:30:26 +0000 (19:30 +0000)
Member pointers in the MS ABI are tricky for a variety of reasons.
The size of a member pointer is indeterminate until the program reaches
a point where the representation is required to be known.  However,
*pointers* to member pointers may exist without knowing the pointee
type's representation.  In these cases, we synthesize an opaque LLVM
type for the pointee type.

However, we can be in a situation where the underlying member pointer's
representation became known mid-way through the program.  To account for
this, we attempted to manicure CodeGen's type-cache so that we can
replace the opaque member pointer type with the real deal while leaving
the pointer types unperturbed.  This, unfortunately, is a problematic
approach to take as we will violate CodeGen's invariants.

These violations are mostly harmless but let's do the right thing
instead: invalidate the type-cache if a member pointer's LLVM
representation changes.

This fixes PR26313.

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

13 files changed:
include/clang/AST/ASTConsumer.h
include/clang/Frontend/MultiplexConsumer.h
lib/CodeGen/CodeGenAction.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/CodeGen/CodeGenTypes.cpp
lib/CodeGen/CodeGenTypes.h
lib/CodeGen/ModuleBuilder.cpp
lib/Frontend/MultiplexConsumer.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaType.cpp
test/CodeGenCXX/microsoft-abi-member-pointers.cpp

index 02f64a66efee8c442bb60b9cce93db40363949d3..7c0acbc6b365755fa74fb338a6217ab091d563c0 100644 (file)
@@ -121,6 +121,10 @@ public:
   /// modified by the introduction of an implicit zero initializer.
   virtual void CompleteTentativeDefinition(VarDecl *D) {}
 
+  /// \brief Callback invoked when an MSInheritanceAttr has been attached to a
+  /// CXXRecordDecl.
+  virtual void AssignInheritanceModel(CXXRecordDecl *RD) {}
+
   /// HandleCXXStaticMemberVarInstantiation - Tell the consumer that this
   // variable has been instantiated.
   virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *D) {}
index 978282933877f868de832a05da7c192a84119336..f92e9bf6c52f70e6b1b7666700135e0ee8a0b5c4 100644 (file)
@@ -49,6 +49,7 @@ public:
                             llvm::StringRef Value) override;
   void HandleDependentLibrary(llvm::StringRef Lib) override;
   void CompleteTentativeDefinition(VarDecl *D) override;
+  void AssignInheritanceModel(CXXRecordDecl *RD) override;
   void HandleVTable(CXXRecordDecl *RD) override;
   ASTMutationListener *GetASTMutationListener() override;
   ASTDeserializationListener *GetASTDeserializationListener() override;
index cdd9d09d048b620c87970ea182019118cb4607d2..f8ae031f0f3bbc6dad6990de9296b764f07f69b4 100644 (file)
@@ -210,6 +210,10 @@ namespace clang {
       Gen->CompleteTentativeDefinition(D);
     }
 
+    void AssignInheritanceModel(CXXRecordDecl *RD) override {
+      Gen->AssignInheritanceModel(RD);
+    }
+
     void HandleVTable(CXXRecordDecl *RD) override {
       Gen->HandleVTable(RD);
     }
index ae46b12b80da4c3960adf9aeb69c3df940c9c8a8..be8171971bb61a0752a16aefcc5d4d3b2ed9137e 100644 (file)
@@ -489,6 +489,11 @@ void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
   Types.UpdateCompletedType(TD);
 }
 
+void CodeGenModule::RefreshTypeCacheForClass(const CXXRecordDecl *RD) {
+  // Make sure that this type is translated.
+  Types.RefreshTypeCacheForClass(RD);
+}
+
 llvm::MDNode *CodeGenModule::getTBAAInfo(QualType QTy) {
   if (!TBAA)
     return nullptr;
index 046bc2a9fe523b102c052735c9f7772ecd659bb2..74087be3f6a1b75e6a43c2625b11d14a8033bd20 100644 (file)
@@ -994,6 +994,8 @@ public:
 
   void EmitVTable(CXXRecordDecl *Class);
 
+  void RefreshTypeCacheForClass(const CXXRecordDecl *Class);
+
   /// \brief Appends Opts to the "Linker Options" metadata value.
   void AppendLinkerOptions(StringRef Opts);
 
index 09d9bf17b3bf3419761c34e9edbda9e0cc5e56be..554f9ff640a93d182983a22b73f60fd6b6025c47 100644 (file)
@@ -272,6 +272,17 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
     DI->completeType(RD);
 }
 
+void CodeGenTypes::RefreshTypeCacheForClass(const CXXRecordDecl *RD) {
+  QualType T = Context.getRecordType(RD);
+  T = Context.getCanonicalType(T);
+
+  const Type *Ty = T.getTypePtr();
+  if (RecordsWithOpaqueMemberPointers.count(Ty)) {
+    TypeCache.clear();
+    RecordsWithOpaqueMemberPointers.clear();
+  }
+}
+
 static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext,
                                     const llvm::fltSemantics &format,
                                     bool UseNativeHalf = false) {
@@ -603,10 +614,13 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
   }
 
   case Type::MemberPointer: {
-    if (!getCXXABI().isMemberPointerConvertible(cast<MemberPointerType>(Ty)))
-      return llvm::StructType::create(getLLVMContext());
-    ResultType = 
-      getCXXABI().ConvertMemberPointerType(cast<MemberPointerType>(Ty));
+    auto *MPTy = cast<MemberPointerType>(Ty);
+    if (!getCXXABI().isMemberPointerConvertible(MPTy)) {
+      RecordsWithOpaqueMemberPointers.insert(MPTy->getClass());
+      ResultType = llvm::StructType::create(getLLVMContext());
+    } else {
+      ResultType = getCXXABI().ConvertMemberPointerType(MPTy);
+    }
     break;
   }
 
index a96f23c44894e6299393e906a7b7b10c009ce933..a673fa668104e7e6150384bcd8beb752d199b434 100644 (file)
@@ -162,6 +162,8 @@ class CodeGenTypes {
   /// corresponding llvm::Type.
   llvm::DenseMap<const Type *, llvm::Type *> TypeCache;
 
+  llvm::SmallSet<const Type *, 8> RecordsWithOpaqueMemberPointers;
+
 public:
   CodeGenTypes(CodeGenModule &cgm);
   ~CodeGenTypes();
@@ -214,6 +216,10 @@ public:
   /// replace the 'opaque' type we previously made for it if applicable.
   void UpdateCompletedType(const TagDecl *TD);
 
+  /// \brief Remove stale types from the type cache when an inheritance model
+  /// gets assigned to a class.
+  void RefreshTypeCacheForClass(const CXXRecordDecl *RD);
+
   /// getNullaryFunctionInfo - Get the function info for a void()
   /// function with standard CC.
   const CGFunctionInfo &arrangeNullaryFunction();
index bce19ab2fdb569ee3c374623e44029dae76c9af1..9428bdf1db3e54650c1da23e851818247f3f6ec4 100644 (file)
@@ -210,6 +210,13 @@ namespace {
         Builder->Release();
     }
 
+    void AssignInheritanceModel(CXXRecordDecl *RD) override {
+      if (Diags.hasErrorOccurred())
+        return;
+
+      Builder->RefreshTypeCacheForClass(RD);
+    }
+
     void CompleteTentativeDefinition(VarDecl *D) override {
       if (Diags.hasErrorOccurred())
         return;
index fdeb04f624867f28d1f7cd6f64c418a65b200bc9..15f876b7bdf6b0f4d4c8459674ebf331e2b2805d 100644 (file)
@@ -337,6 +337,11 @@ void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) {
     Consumer->CompleteTentativeDefinition(D);
 }
 
+void MultiplexConsumer::AssignInheritanceModel(CXXRecordDecl *RD) {
+  for (auto &Consumer : Consumers)
+    Consumer->AssignInheritanceModel(RD);
+}
+
 void MultiplexConsumer::HandleVTable(CXXRecordDecl *RD) {
   for (auto &Consumer : Consumers)
     Consumer->HandleVTable(RD);
index 166bd8ca24e5ff9810175355be8e844e262a0bbc..da2bec38e8eddde38d2c9f85ad3ce8c33665044b 100644 (file)
@@ -2255,6 +2255,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
   if (NewAttr) {
     NewAttr->setInherited(true);
     D->addAttr(NewAttr);
+    if (isa<MSInheritanceAttr>(NewAttr))
+      S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D));
     return true;
   }
 
index b0a9a009f0ff5642a3fce4f10fd27bcd86e5d2cf..b2169962a5d500f7bfe9152bdfe5e79d97612b1d 100644 (file)
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclCXX.h"
@@ -4431,8 +4432,10 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr)
       D, Attr.getRange(), /*BestCase=*/true,
       Attr.getAttributeSpellingListIndex(),
       (MSInheritanceAttr::Spelling)Attr.getSemanticSpelling());
-  if (IA)
+  if (IA) {
     D->addAttr(IA);
+    S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D));
+  }
 }
 
 static void handleDeclspecThreadAttr(Sema &S, Decl *D,
index fb8e1e76206f5a64510d94035b9b6da74a8186a4..91a26a4371aa128ec066950bae6e09995936355a 100644 (file)
@@ -6611,6 +6611,7 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
         S.ImplicitMSInheritanceAttrLoc.isValid()
             ? S.ImplicitMSInheritanceAttrLoc
             : RD->getSourceRange()));
+    S.Consumer.AssignInheritanceModel(RD);
   }
 }
 
index fd22c0034203c494970cd3655460e741b22fdff8..a3985ba09c02861e682abd7ab327bf3ef85bac60 100644 (file)
@@ -3,16 +3,29 @@
 // RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -fms-extensions -verify
 // RUN: %clang_cc1 -std=c++11 -Wno-uninitialized -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -DMEMFUN -fms-extensions -verify
 
+struct PR26313_Y;
+typedef void (PR26313_Y::*PR26313_FUNC)();
+struct PR26313_X {
+  PR26313_FUNC *ptr;
+  PR26313_X();
+};
+PR26313_X::PR26313_X() {}
+void PR26313_f(PR26313_FUNC *p) { delete p; }
+
+struct PR26313_Z;
+int PR26313_Z::**a = nullptr;
+int PR26313_Z::*b = *a;
+// CHECK-DAG: @"\01?a@@3PAPQPR26313_Z@@HA" = global %0* null, align 4
+// CHECK-DAG: @"\01?b@@3PQPR26313_Z@@HQ1@" = global { i32, i32, i32 } { i32 0, i32 0, i32 -1 }, align 4
+
 namespace PR20947 {
 struct A;
 int A::**a = nullptr;
-// CHECK: %[[opaque0:.*]] = type opaque
-// CHECK: %[[opaque1:.*]] = type opaque
-// CHECK: @"\01?a@PR20947@@3PAPQA@1@HA" = global %[[opaque0]]* null, align 4
+// CHECK-DAG: @"\01?a@PR20947@@3PAPQA@1@HA" = global %{{.*}}* null, align 4
 
 struct B;
 int B::*&b = b;
-// CHECK: @"\01?b@PR20947@@3AAPQB@1@HA" = global %[[opaque1]]* null, align 4
+// CHECK-DAG: @"\01?b@PR20947@@3AAPQB@1@HA" = global %{{.*}}* null, align 4
 }
 
 namespace PR20017 {