]> granicus.if.org Git - clang/commitdiff
[MS ABI] Account for the virtual inheritance quirk when mangling
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 23 Jun 2015 20:34:18 +0000 (20:34 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 23 Jun 2015 20:34:18 +0000 (20:34 +0000)
Virtual inheritance member pointers are always relative to the vbindex,
even when the member pointer doesn't point into a virtual base.  This is
corrected by adjusting the non-virtual offset backwards from the vbptr
back to the top of the most derived class.  While we performed this
adjustment when manifesting member pointers as constants or when
performing conversions, we didn't perform the adjustment when mangling
them.

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

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/AST/MicrosoftMangle.cpp
lib/CodeGen/MicrosoftCXXABI.cpp
test/CodeGenCXX/mangle-ms-templates-memptrs.cpp

index da288c4fe5ede3532005d039a921b41f0a55faba..75334eabacb0d287d50b3931288cfd14b768ad18 100644 (file)
@@ -1780,6 +1780,17 @@ public:
   /// \param method should be the declaration from the class definition
   void setNonKeyFunction(const CXXMethodDecl *method);
 
+  /// Loading virtual member pointers using the virtual inheritance model
+  /// always results in an adjustment using the vbtable even if the index is
+  /// zero.
+  ///
+  /// This is usually OK because the first slot in the vbtable points
+  /// backwards to the top of the MDC.  However, the MDC might be reusing a
+  /// vbptr from an nv-base.  In this case, the first slot in the vbtable
+  /// points to the start of the nv-base which introduced the vbptr and *not*
+  /// the MDC.  Modify the NonVirtualBaseAdjustment to account for this.
+  CharUnits getOffsetOfBaseWithVBPtr(const CXXRecordDecl *RD) const;
+
   /// Get the offset of a FieldDecl or IndirectFieldDecl, in bits.
   uint64_t getFieldOffset(const ValueDecl *FD) const;
 
index 049eebd82b66b1fbffabdb7ae856c36d5a791fa0..e88ea946e724d1c646786cc0a82426739b133363 100644 (file)
@@ -1866,6 +1866,16 @@ CharUnits ASTContext::getAlignOfGlobalVarInChars(QualType T) const {
   return toCharUnitsFromBits(getAlignOfGlobalVar(T));
 }
 
+CharUnits ASTContext::getOffsetOfBaseWithVBPtr(const CXXRecordDecl *RD) const {
+  CharUnits Offset = CharUnits::Zero();
+  const ASTRecordLayout *Layout = &getASTRecordLayout(RD);
+  while (const CXXRecordDecl *Base = Layout->getBaseSharingVBPtr()) {
+    Offset += Layout->getBaseClassOffset(Base);
+    Layout = &getASTRecordLayout(Base);
+  }
+  return Offset;
+}
+
 /// DeepCollectObjCIvars -
 /// This routine first collects all declared, but not synthesized, ivars in
 /// super class and then collects all ivars, including those synthesized for
index 26894bb91eb2c4d87912db728f0514eef230e06f..c50db60abe5a055252cd2b96ef522a8405f24513 100644 (file)
@@ -502,6 +502,9 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
     FieldOffset /= getASTContext().getCharWidth();
 
     VBTableOffset = 0;
+
+    if (IM == MSInheritanceAttr::Keyword_virtual_inheritance)
+      FieldOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity();
   } else {
     FieldOffset = RD->nullFieldOffsetIsZero() ? 0 : -1;
 
@@ -570,6 +573,10 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
       mangleName(MD);
       mangleFunctionEncoding(MD, /*ShouldMangle=*/true);
     }
+
+    if (VBTableOffset == 0 &&
+        IM == MSInheritanceAttr::Keyword_virtual_inheritance)
+      NVOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity();
   } else {
     // Null single inheritance member functions are encoded as a simple nullptr.
     if (IM == MSInheritanceAttr::Keyword_single_inheritance) {
@@ -582,7 +589,7 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
   }
 
   if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM))
-    mangleNumber(NVOffset);
+    mangleNumber(static_cast<uint32_t>(NVOffset));
   if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
     mangleNumber(VBPtrOffset);
   if (MSInheritanceAttr::hasVBTableOffsetField(IM))
index fabdef3d158d33cca03b336438383cc9a12ba55d..de1d4dae69bb9851f9475cf4601f09c3a6deeea7 100644 (file)
@@ -2514,33 +2514,13 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
   return llvm::ConstantStruct::getAnon(fields);
 }
 
-// Loading virtual member pointers using the virtual inheritance model
-// always results in an adjustment using the vbtable even if the index is
-// zero.
-//
-// This is usually OK because the first slot in the vbtable points
-// backwards to the top of the MDC.  However, the MDC might be reusing a
-// vbptr from an nv-base.  In this case, the first slot in the vbtable
-// points to the start of the nv-base which introduced the vbptr and *not*
-// the MDC.  Modify the NonVirtualBaseAdjustment to account for this.
-static CharUnits computeOffsetOfBaseWithVBPtr(const ASTContext &Ctx,
-                                              const CXXRecordDecl *RD) {
-  CharUnits Offset = CharUnits::Zero();
-  const ASTRecordLayout *Layout = &Ctx.getASTRecordLayout(RD);
-  while (const CXXRecordDecl *Base = Layout->getBaseSharingVBPtr()) {
-    Offset += Layout->getBaseClassOffset(Base);
-    Layout = &Ctx.getASTRecordLayout(Base);
-  }
-  return Offset;
-}
-
 llvm::Constant *
 MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
                                        CharUnits offset) {
   const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
   if (RD->getMSInheritanceModel() ==
       MSInheritanceAttr::Keyword_virtual_inheritance)
-    offset -= computeOffsetOfBaseWithVBPtr(getContext(), RD);
+    offset -= getContext().getOffsetOfBaseWithVBPtr(RD);
   llvm::Constant *FirstField =
     llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
   return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD,
@@ -2639,7 +2619,7 @@ MicrosoftCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) {
   if (VBTableIndex == 0 &&
       RD->getMSInheritanceModel() ==
           MSInheritanceAttr::Keyword_virtual_inheritance)
-    NonVirtualBaseAdjustment -= computeOffsetOfBaseWithVBPtr(getContext(), RD);
+    NonVirtualBaseAdjustment -= getContext().getOffsetOfBaseWithVBPtr(RD);
 
   // The rest of the fields are common with data member pointers.
   FirstField = llvm::ConstantExpr::getBitCast(FirstField, CGM.VoidPtrTy);
@@ -2987,7 +2967,7 @@ MicrosoftCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
       Builder.CreateICmpEQ(VirtualBaseAdjustmentOffset, getZeroInt());
   if (SrcInheritance == MSInheritanceAttr::Keyword_virtual_inheritance) {
     if (int64_t SrcOffsetToFirstVBase =
-            computeOffsetOfBaseWithVBPtr(getContext(), SrcRD).getQuantity()) {
+            getContext().getOffsetOfBaseWithVBPtr(SrcRD).getQuantity()) {
       llvm::Value *UndoSrcAdjustment = Builder.CreateSelect(
           SrcVBIndexEqZero,
           llvm::ConstantInt::get(CGM.IntTy, SrcOffsetToFirstVBase),
@@ -3049,7 +3029,7 @@ MicrosoftCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
   // virtual base and the top of the MDC.
   if (DstInheritance == MSInheritanceAttr::Keyword_virtual_inheritance) {
     if (int64_t DstOffsetToFirstVBase =
-            computeOffsetOfBaseWithVBPtr(getContext(), DstRD).getQuantity()) {
+            getContext().getOffsetOfBaseWithVBPtr(DstRD).getQuantity()) {
       llvm::Value *DoDstAdjustment = Builder.CreateSelect(
           DstVBIndexEqZero,
           llvm::ConstantInt::get(CGM.IntTy, DstOffsetToFirstVBase),
@@ -3155,8 +3135,7 @@ llvm::Constant *MicrosoftCXXABI::EmitMemberPointerConversion(
       llvm::ICmpInst::ICMP_EQ, VirtualBaseAdjustmentOffset, getZeroInt());
   if (SrcInheritance == MSInheritanceAttr::Keyword_virtual_inheritance) {
     llvm::Constant *SrcOffsetToFirstVBase = llvm::ConstantInt::get(
-        CGM.IntTy,
-        computeOffsetOfBaseWithVBPtr(getContext(), SrcRD).getQuantity());
+        CGM.IntTy, getContext().getOffsetOfBaseWithVBPtr(SrcRD).getQuantity());
     llvm::Constant *UndoSrcAdjustment = llvm::ConstantExpr::getSelect(
         SrcVBIndexEqZero, SrcOffsetToFirstVBase, getZeroInt());
     NVAdjustField =
@@ -3219,8 +3198,7 @@ llvm::Constant *MicrosoftCXXABI::EmitMemberPointerConversion(
   // virtual base and the top of the MDC.
   if (DstInheritance == MSInheritanceAttr::Keyword_virtual_inheritance) {
     llvm::Constant *DstOffsetToFirstVBase = llvm::ConstantInt::get(
-        CGM.IntTy,
-        computeOffsetOfBaseWithVBPtr(getContext(), DstRD).getQuantity());
+        CGM.IntTy, getContext().getOffsetOfBaseWithVBPtr(DstRD).getQuantity());
     llvm::Constant *DoDstAdjustment = llvm::ConstantExpr::getSelect(
         DstVBIndexEqZero, DstOffsetToFirstVBase, getZeroInt());
     NVAdjustField =
index 803cac3748b1c802ba9f5035818850175c5cf379..42237f5b7d4a418bd94164bb15928ef9032b743d 100644 (file)
@@ -141,3 +141,15 @@ void CallMethods() {
 // CHECK: call {{.*}} @"\01??$CallMethod@UM@@$0A@@@YAXAAUM@@@Z"
 // CHECK: call {{.*}} @"\01??$CallMethod@UV@@$0A@@@YAXAAUV@@@Z"
 // CHECK: call {{.*}} @"\01??$CallMethod@UU@@$0A@@@YAXAAUU@@@Z"
+
+namespace NegativeNVOffset {
+struct A {};
+struct B : virtual A {};
+struct C : B {
+  virtual void f();
+};
+}
+
+template void CallMethod<NegativeNVOffset::C, &NegativeNVOffset::C::f>(NegativeNVOffset::C &);
+
+// CHECK-LABEL: define {{.*}} @"\01??$CallMethod@UC@NegativeNVOffset@@$I??_912@$BA@AEPPPPPPPM@A@@@YAXAAUC@NegativeNVOffset@@@Z"