r206457 - Fix PR19408 - Missing static this adjustment in a vtordisp thunk

Timur Iskhodzhanov timurrrr at google.com
Thu Apr 17 04:01:42 PDT 2014


Author: timurrrr
Date: Thu Apr 17 06:01:41 2014
New Revision: 206457

URL: http://llvm.org/viewvc/llvm-project?rev=206457&view=rev
Log:
Fix PR19408 - Missing static this adjustment in a vtordisp thunk

Also fix a few other vtordisp-related bugs.

Reviewed at http://reviews.llvm.org/D3400

Modified:
    cfe/trunk/lib/AST/VTableBuilder.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp

Modified: cfe/trunk/lib/AST/VTableBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/VTableBuilder.cpp?rev=206457&r1=206456&r2=206457&view=diff
==============================================================================
--- cfe/trunk/lib/AST/VTableBuilder.cpp (original)
+++ cfe/trunk/lib/AST/VTableBuilder.cpp Thu Apr 17 06:01:41 2014
@@ -2715,27 +2715,45 @@ void VFTableBuilder::CalculateVtordispAd
       VBaseMap.find(WhichVFPtr.getVBaseWithVPtr());
   assert(VBaseMapEntry != VBaseMap.end());
 
-  // Check if we need a vtordisp adjustment at all.
+  // If there's no vtordisp, we don't need any vtordisp adjustment.
   if (!VBaseMapEntry->second.hasVtorDisp())
     return;
 
-  CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
+  const CXXRecordDecl *OverriderRD = Overrider.Method->getParent();
+  const CXXRecordDecl *OverriderVBase = 0;
+  if (OverriderRD != MostDerivedClass) {
+    OverriderVBase =
+        ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase;
+  }
+
+  // If the final overrider is defined in the same vbase as the initial
+  // declaration, we don't need a vtordisp thunk at all.
+  if (OverriderVBase == WhichVFPtr.getVBaseWithVPtr())
+    return;
+
+  // OK, now we know we need to use a vtordisp thunk.
   // The implicit vtordisp field is located right before the vbase.
+  CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
   TA.Virtual.Microsoft.VtordispOffset =
       (VFPtrVBaseOffset - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4;
 
-  // If the final overrider is defined in either:
-  // - the most derived class or its non-virtual base or
-  // - the same vbase as the initial declaration,
-  // a simple vtordisp thunk will suffice.
-  const CXXRecordDecl *OverriderRD = Overrider.Method->getParent();
+  // A simple vtordisp thunk will suffice if the final overrider is defined
+  // in either the most derived class or its non-virtual base.
   if (OverriderRD == MostDerivedClass)
     return;
 
-  const CXXRecordDecl *OverriderVBase =
-      ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase;
-  if (!OverriderVBase || OverriderVBase == WhichVFPtr.getVBaseWithVPtr())
+  if (!OverriderVBase) {
+    MethodVFTableLocation ML = VTables.getMethodVFTableLocation(Overrider.Method);
+    assert(ML.VBase && "why would we need a vtordisp if we can call the method "
+                       "without a vfptr of a vbase?");
+    // We need to offset the this parameter if the offset of the vbase is
+    // different between the overrider class and the most derived class.
+    const ASTRecordLayout &OverriderRDLayout =
+        Context.getASTRecordLayout(OverriderRD);
+    TA.NonVirtual += (OverriderRDLayout.getVBaseClassOffset(ML.VBase) +
+                     ML.VFPtrOffset - ThisOffset).getQuantity();
     return;
+  }
 
   // Otherwise, we need to do use the dynamic offset of the final overrider
   // in order to get "this" adjustment right.

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp?rev=206457&r1=206456&r2=206457&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp Thu Apr 17 06:01:41 2014
@@ -157,6 +157,67 @@ struct C : virtual V4 {
 
 C c;
 void use(C *obj) { obj->f(); }
+
+class D : B {
+  // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::B' in 'simple::D' (2 entries).
+  // CHECK-NEXT: 0 | void simple::B::f()
+  // CHECK-NEXT:     [this adjustment: vtordisp at -12, -4 non-virtual]
+  // CHECK-NEXT: 1 | simple::D::~D() [scalar deleting]
+  // CHECK-NEXT:     [this adjustment: vtordisp at -12, -8 non-virtual]
+  D();
+  int z;
+
+  // MANGLING-DAG: @"\01?f at B@simple@@$4PPPPPPPE at 3AEXXZ"
+};
+
+D::D() {}
+
+struct E : V3 {
+  virtual void f();
+};
+
+struct F : virtual E {
+  // CHECK-LABEL: VFTable for 'Z' in 'V3' in 'simple::E' in 'simple::F' (2 entries).
+  // CHECK-NEXT:   0 | void simple::F::g()
+  // CHECK-NEXT:       [this adjustment: vtordisp at -4, 0 non-virtual]
+  // CHECK-NEXT:   1 | simple::F::~F() [scalar deleting]
+  // CHECK-NEXT:       [this adjustment: vtordisp at -4, 0 non-virtual]
+
+  // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::E' in 'simple::F' (2 entries).
+  // CHECK-NEXT:   0 | void simple::E::f()
+  // CHECK-NEXT:   1 | simple::F::~F() [scalar deleting]
+  // CHECK-NEXT:       [this adjustment: vtordisp at -12, -8 non-virtual]
+
+  F();
+  virtual void g();  // Force a vtordisp.
+  int f;
+
+  // MANGLING-DAG: @"\01?g at F@simple@@$4PPPPPPPM at A@AEXXZ"{{.*}}??_EF at simple@@$4PPPPPPPM at A@AEPAXI at Z
+  // MANGLING-DAG: ?f at E@simple@@UAEXXZ{{.*}}??_EF at simple@@$4PPPPPPPE at 7AEPAXI@Z
+};
+
+F::F() {}
+
+struct G : F {
+  // CHECK-LABEL: VFTable for 'Z' in 'V3' in 'simple::E' in 'simple::F' in 'simple::G' (2 entries).
+  // CHECK-NEXT:   0 | void simple::F::g()
+  // CHECK-NEXT:       [this adjustment: vtordisp at -4, -4 non-virtual]
+  // CHECK-NEXT:   1 | simple::G::~G() [scalar deleting]
+  // CHECK-NEXT:       [this adjustment: vtordisp at -4, 0 non-virtual]
+
+  // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::E' in 'simple::F' in 'simple::G' (2 entries).
+  // CHECK-NEXT:   0 | void simple::E::f()
+  // CHECK-NEXT:   1 | simple::G::~G() [scalar deleting]
+  // CHECK-NEXT:       [this adjustment: vtordisp at -12, -8 non-virtual]
+
+  G();
+  int g;
+
+  // MANGLING-DAG: @"\01?g at F@simple@@$4PPPPPPPM at 3AEXXZ"{{.*}}@"\01??_EG at simple@@$4PPPPPPPM at A@AEPAXI at Z"
+  // MANGLING-DAG: @"\01?f at E@simple@@UAEXXZ"{{.*}}@"\01??_EG at simple@@$4PPPPPPPE at 7AEPAXI@Z"
+};
+
+G::G() {}
 }
 
 namespace extended {
@@ -355,6 +416,40 @@ A a;
 void use(A *obj) { delete obj; }
 }
 
+namespace pr19408 {
+// In this test, the vptr used to vcall D::f() is located in the A vbase.
+// The offset of A in different in C and D, so the D vtordisp thunk should
+// adjust "this" so C::f gets the right value.
+struct A {
+  A();
+  virtual void f();
+  int a;
+};
+
+struct B : virtual A {
+  B();
+  int b;
+};
+
+struct C : B {
+  C();
+  virtual void f();
+  int c;
+};
+
+struct D : C {
+  // CHECK-LABEL: VFTable for 'pr19408::A' in 'pr19408::B' in 'pr19408::C' in 'pr19408::D' (1 entry).
+  // CHECK-NEXT:   0 | void pr19408::C::f()
+  // CHECK-NEXT:       [this adjustment: vtordisp at -4, -4 non-virtual]
+
+  // MANGLING-DAG: @"\01?f at C@pr19408@@$4PPPPPPPM at 3AEXXZ"
+  D();
+  int d;
+};
+
+D::D() {}
+}
+
 namespace access {
 struct A {
   virtual ~A();





More information about the cfe-commits mailing list