]> granicus.if.org Git - clang/commitdiff
[codeview] Pass through vftable shape information
authorReid Kleckner <rnk@google.com>
Wed, 31 Aug 2016 16:11:43 +0000 (16:11 +0000)
committerReid Kleckner <rnk@google.com>
Wed, 31 Aug 2016 16:11:43 +0000 (16:11 +0000)
The shape is really just the number of methods in the vftable, since we
don't support 16 bit far calls. All calls are near. Encode this number
in the size of the artificial __vtbl_ptr_type DIDerivedType that we
generate. For DWARF, this will be a normal pointer, but for codeview
this will be a wide pointer that gets pattern matched into a
VFTableShape record. Insert this type into the element list of all
dynamic classes when emitting CodeView, so that the backend can emit the
shape even if the vptr lives in a primary base class.

Fixes PR28150

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

lib/CodeGen/CGDebugInfo.cpp
lib/CodeGen/CGDebugInfo.h
test/CodeGenCXX/debug-info-ms-abi.cpp

index 2f250d853e70bc6255ce4f0fe5bfacfadccc33e9..00e0da4d9fc570267a852dea195f37dda05369a4 100644 (file)
@@ -1549,22 +1549,49 @@ StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
 }
 
 void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit,
-                                    SmallVectorImpl<llvm::Metadata *> &EltTys) {
-  const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+                                    SmallVectorImpl<llvm::Metadata *> &EltTys,
+                                    llvm::DICompositeType *RecordTy) {
+  // If this class is not dynamic then there is not any vtable info to collect.
+  if (!RD->isDynamicClass())
+    return;
 
-  // If there is a primary base then it will hold vtable info.
+  // CodeView needs to know how large the vtable of every dynamic class is, so
+  // emit a special named pointer type into the element list. The vptr type
+  // points to this type as well.
+  llvm::DIType *VPtrTy = nullptr;
+  bool NeedVTableShape = CGM.getCodeGenOpts().EmitCodeView &&
+                         CGM.getTarget().getCXXABI().isMicrosoft();
+  if (NeedVTableShape) {
+    uint64_t PtrWidth =
+        CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
+    const VTableLayout &VFTLayout =
+        CGM.getMicrosoftVTableContext().getVFTableLayout(RD, CharUnits::Zero());
+    unsigned VSlotCount =
+        VFTLayout.getNumVTableComponents() - CGM.getLangOpts().RTTIData;
+    unsigned VTableWidth = PtrWidth * VSlotCount;
+
+    // Create a very wide void* type and insert it directly in the element list.
+    llvm::DIType *VTableType =
+        DBuilder.createPointerType(nullptr, VTableWidth, 0, "__vtbl_ptr_type");
+    EltTys.push_back(VTableType);
+
+    // The vptr is a pointer to this special vtable type.
+    VPtrTy = DBuilder.createPointerType(VTableType, PtrWidth);
+  }
+
+  // If there is a primary base then the artificial vptr member lives there.
+  const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
   if (RL.getPrimaryBase())
     return;
 
-  // If this class is not dynamic then there is not any vtable info to collect.
-  if (!RD->isDynamicClass())
-    return;
+  if (!VPtrTy)
+    VPtrTy = getOrCreateVTablePtrType(Unit);
 
   unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
-  llvm::DIType *VPTR = DBuilder.createMemberType(
+  llvm::DIType *VPtrMember = DBuilder.createMemberType(
       Unit, getVTableName(RD), Unit, 0, Size, 0, 0,
-      llvm::DINode::FlagArtificial, getOrCreateVTablePtrType(Unit));
-  EltTys.push_back(VPTR);
+      llvm::DINode::FlagArtificial, VPtrTy);
+  EltTys.push_back(VPtrMember);
 }
 
 llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy,
@@ -1761,7 +1788,7 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {
   const auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
   if (CXXDecl) {
     CollectCXXBases(CXXDecl, DefUnit, EltTys, FwdDecl);
-    CollectVTableInfo(CXXDecl, DefUnit, EltTys);
+    CollectVTableInfo(CXXDecl, DefUnit, EltTys, FwdDecl);
   }
 
   // Collect data fields (including static variables and any initializers).
index 71c0df4cbf09e188f9c09207c1d8c5ef0763fad2..501bbad53961278f3bff7b0d1217f4806f2181e2 100644 (file)
@@ -264,7 +264,8 @@ class CGDebugInfo {
   /// If the C++ class has vtable info then insert appropriate debug
   /// info entry in EltTys vector.
   void CollectVTableInfo(const CXXRecordDecl *Decl, llvm::DIFile *F,
-                         SmallVectorImpl<llvm::Metadata *> &EltTys);
+                         SmallVectorImpl<llvm::Metadata *> &EltTys,
+                         llvm::DICompositeType *RecordTy);
   /// @}
 
   /// Create a new lexical block node and push it on the stack.
index b1ce128e0f711f926c00d3d2920b8af245f5645d..c58fcc98cfed89c14328e85edf7a0f69e2f60912 100644 (file)
@@ -15,7 +15,14 @@ Foo::Nested n;
 // CHECK-SAME: elements: ![[elements:[0-9]+]]
 // CHECK-SAME: identifier: ".?AUFoo@@"
 
-// CHECK: ![[elements]] = !{![[vptr:[0-9]+]], ![[Nested:[0-9]+]], ![[f:[0-9]+]], ![[g:[0-9]+]], ![[h:[0-9]+]]}
+// CHECK: ![[elements]] = !{![[vshape:[0-9]+]], ![[vptr:[0-9]+]], ![[Nested:[0-9]+]], ![[f:[0-9]+]], ![[g:[0-9]+]], ![[h:[0-9]+]]}
+
+// CHECK: ![[vshape]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", baseType: null, size: 96)
+
+// CHECK: ![[vptr]] = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$Foo",
+// CHECK-SAME: baseType: ![[vptr_ty:[0-9]+]],
+
+// CHECK: ![[vptr_ty]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[vshape]], size: 32
 
 // CHECK: ![[Nested]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Nested",
 // CHECK-SAME: identifier: ".?AUNested@Foo@@"