lebedev.ri updated this revision to Diff 344877.
lebedev.ri marked 2 inline comments as done.
lebedev.ri added a comment.

In D100388#2749115 <https://reviews.llvm.org/D100388#2749115>, @efriedma wrote:

> Made a couple suggestions to make this easier to review.
>
> The test changes you've made so far seem reasonable.
>
> Is there some specific section of the code you want feedback on?

Thank you for taking a look!
Basically, i'm not sure this is right, and i'm not sure what is going wrong.
For example

  $ ./bin/llvm-lit 
/repositories/llvm-project/clang/test/CodeGen/available-externally-hidden.cpp -v
  llvm-lit: /repositories/llvm-project/llvm/utils/lit/lit/llvm/config.py:428: 
note: using clang: /builddirs/llvm-project/build-Clang12/bin/clang
  -- Testing: 1 tests, 1 workers --
  FAIL: Clang :: CodeGen/available-externally-hidden.cpp (1 of 1)
  ******************** TEST 'Clang :: CodeGen/available-externally-hidden.cpp' 
FAILED ********************
  Script:
  --
  : 'RUN: at line 1';   /builddirs/llvm-project/build-Clang12/bin/clang -cc1 
-internal-isystem 
/builddirs/llvm-project/build-Clang12/lib/clang/13.0.0/include -nostdsysteminc 
-O2 -fvisibility hidden -std=c++11 -emit-llvm -o - -triple 
x86_64-apple-darwin10 
/repositories/llvm-project/clang/test/CodeGen/available-externally-hidden.cpp | 
/builddirs/llvm-project/build-Clang12/bin/FileCheck 
/repositories/llvm-project/clang/test/CodeGen/available-externally-hidden.cpp
  --
  Exit Code: 2
  
  Command Output (stderr):
  --
  
/repositories/llvm-project/clang/test/CodeGen/available-externally-hidden.cpp:14:16:
 error: cannot compile this thunk for forward declaration yet
    virtual bool Send(Message* msg) = 0;
                 ^
  1 error generated.
  FileCheck error: '<stdin>' is empty.
  FileCheck command line:  /builddirs/llvm-project/build-Clang12/bin/FileCheck 
/repositories/llvm-project/clang/test/CodeGen/available-externally-hidden.cpp
  
  --
  
  ********************
  ********************
  Failed Tests (1):
    Clang :: CodeGen/available-externally-hidden.cpp
  
  
  Testing Time: 0.18s
    Failed: 1

Would it be reasonable to instead start with a stopgap measure of not adding 
attributes for `this`/return of thunks?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100388/new/

https://reviews.llvm.org/D100388

Files:
  clang/include/clang/AST/VTableBuilder.h
  clang/include/clang/Basic/Thunk.h
  clang/lib/AST/MicrosoftMangle.cpp
  clang/lib/AST/VTableBuilder.cpp
  clang/lib/CodeGen/CGVTables.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/CodeGen/MicrosoftCXXABI.cpp
  clang/test/CodeGen/available-externally-hidden.cpp
  clang/test/CodeGenCXX/RelativeVTablesABI/diamond-inheritance.cpp
  clang/test/CodeGenCXX/RelativeVTablesABI/multiple-inheritance.cpp
  clang/test/CodeGenCXX/thunk-linkonce-odr.cpp
  clang/test/CodeGenCXX/thunk-returning-memptr.cpp
  clang/test/CodeGenCXX/thunk-wrong-return-type.cpp
  clang/test/CodeGenCXX/thunk-wrong-this.cpp
  clang/test/CodeGenCXX/thunks.cpp

Index: clang/test/CodeGenCXX/thunks.cpp
===================================================================
--- clang/test/CodeGenCXX/thunks.cpp
+++ clang/test/CodeGenCXX/thunks.cpp
@@ -410,7 +410,7 @@
   // CHECK: getelementptr inbounds i8, i8* {{.*}}, i64 -32
   // CHECK: getelementptr inbounds i8, i8* {{.*}}, i64 -24
   // CHECK: getelementptr inbounds i8, i8* {{.*}}, i64 8
-  // CHECK: ret %"struct.Test13::D"*
+  // CHECK: ret %"struct.Test13::B1"*
 
   // WIN64-LABEL: define weak_odr dso_local nonnull align 8 dereferenceable(8) %"struct.Test13::D"* @"?foo1@D@Test13@@$4PPPPPPPE@A@EAAAEAUB1@2@XZ"(
   //    This adjustment.
Index: clang/test/CodeGenCXX/thunk-wrong-this.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/thunk-wrong-this.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple %itanium_abi_triple %s -emit-llvm -o - %s | FileCheck %s
+
+class Base1 {
+  virtual void Foo1();
+};
+
+class Base2 {
+  virtual void Foo2();
+};
+
+class alignas(16) Obj : public Base1, public Base2 {
+  void Foo1() override;
+  void Foo2() override;
+  ~Obj();
+};
+
+void Obj::Foo1() {}
+void Obj::Foo2() {}
+
+// CHECK: define dso_local void @_ZThn8_N3Obj4Foo2Ev(%class.Base2.2* nonnull dereferenceable(8) %this) #1 align 2 {
+// CHECK: tail call void @_ZN3Obj4Foo2Ev(%class.Obj.0* nonnull dereferenceable(16) %3)
Index: clang/test/CodeGenCXX/thunk-wrong-return-type.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/thunk-wrong-return-type.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple %itanium_abi_triple %s -emit-llvm -o - %s | FileCheck %s
+
+struct A {};
+struct alignas(32) B : virtual A {
+  char c[32];
+};
+struct Pad {
+  char c[7];
+};
+struct C : B, Pad, virtual A {};
+
+struct X {
+  virtual A &f();
+};
+struct U {
+  virtual ~U();
+};
+C c;
+struct Y : U, X {
+  virtual B &f() override { return c; }
+};
+
+Y y;
+
+// CHECK: define linkonce_odr nonnull align 1 dereferenceable(1) %struct.A.8* @_ZTchn8_v0_n24_N1Y1fEv(%struct.X.7* nonnull dereferenceable(8) %this.coerce) #1 comdat align 2 {
Index: clang/test/CodeGenCXX/thunk-returning-memptr.cpp
===================================================================
--- clang/test/CodeGenCXX/thunk-returning-memptr.cpp
+++ clang/test/CodeGenCXX/thunk-returning-memptr.cpp
@@ -23,5 +23,5 @@
 // Because of the tail call, the return value cannot be copied into a local
 // alloca. (PR39901)
 
-// CHECK-LABEL: define linkonce_odr void @_ZThn4_N1C1fEv({ i32, i32 }* noalias sret({ i32, i32 }) align 4 %agg.result, %struct.C* {{[^,]*}} %this)
+// CHECK-LABEL: define linkonce_odr void @_ZThn4_N1C1fEv({ i32, i32 }* noalias sret({ i32, i32 }) align 4 %agg.result, %struct.B* {{[^,]*}} %this.coerce)
 // CHECK: tail call void @_ZN1C1fEv({ i32, i32 }* sret({ i32, i32 }) align 4 %agg.result
Index: clang/test/CodeGenCXX/thunk-linkonce-odr.cpp
===================================================================
--- clang/test/CodeGenCXX/thunk-linkonce-odr.cpp
+++ clang/test/CodeGenCXX/thunk-linkonce-odr.cpp
@@ -29,5 +29,5 @@
 
 // Thunks should be marked as "linkonce ODR" not "weak".
 //
-// CHECK: define linkonce_odr i32 @_ZThn{{[48]}}_N1D1fEv
 // CHECK: define linkonce_odr i32 @_ZThn{{[48]}}_N1C1fEv
+// CHECK: define linkonce_odr i32 @_ZThn{{[48]}}_N1D1fEv
Index: clang/test/CodeGenCXX/RelativeVTablesABI/multiple-inheritance.cpp
===================================================================
--- clang/test/CodeGenCXX/RelativeVTablesABI/multiple-inheritance.cpp
+++ clang/test/CodeGenCXX/RelativeVTablesABI/multiple-inheritance.cpp
@@ -9,7 +9,7 @@
 // VTable for C contains 2 sub-vtables (represented as 2 structs). The first contains the components for B and the second contains the components for C. The RTTI ptr in both arrays still point to the RTTI struct for C.
 // The component for bar() instead points to a thunk which redirects to C::bar() which overrides B::bar().
 // Now that we have a class with 2 parents, the offset to top in the second array is non-zero.
-// CHECK: @_ZTV1C.local = private unnamed_addr constant { [4 x i32], [3 x i32] } { [4 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }** @_ZTI1C.rtti_proxy to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.C*)* dso_local_equivalent @_ZN1C3fooEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.C*)* dso_local_equivalent @_ZN1C3barEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local, i32 0, i32 0, i32 2) to i64)) to i32)], [3 x i32] [i32 -8, i32 trunc (i64 sub (i64 ptrtoint ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }** @_ZTI1C.rtti_proxy to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local, i32 0, i32 1, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.C*)* dso_local_equivalent @_ZThn8_N1C3barEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local, i32 0, i32 1, i32 2) to i64)) to i32)] }, align 4
+// CHECK: @_ZTV1C.local = private unnamed_addr constant { [4 x i32], [3 x i32] } { [4 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }** @_ZTI1C.rtti_proxy to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.C*)* dso_local_equivalent @_ZN1C3fooEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.C*)* dso_local_equivalent @_ZN1C3barEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local, i32 0, i32 0, i32 2) to i64)) to i32)], [3 x i32] [i32 -8, i32 trunc (i64 sub (i64 ptrtoint ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }** @_ZTI1C.rtti_proxy to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local, i32 0, i32 1, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.B*)* dso_local_equivalent @_ZThn8_N1C3barEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local, i32 0, i32 1, i32 2) to i64)) to i32)] }, align 4
 
 // CHECK: @_ZTV1C ={{.*}} unnamed_addr alias { [4 x i32], [3 x i32] }, { [4 x i32], [3 x i32] }* @_ZTV1C.local
 
Index: clang/test/CodeGenCXX/RelativeVTablesABI/diamond-inheritance.cpp
===================================================================
--- clang/test/CodeGenCXX/RelativeVTablesABI/diamond-inheritance.cpp
+++ clang/test/CodeGenCXX/RelativeVTablesABI/diamond-inheritance.cpp
@@ -18,7 +18,7 @@
 // vtable contains 2 inner vtables:
 // - 1st table containing D::foo(), B::barB(), and D::baz().
 // - 2nd table containing a thunk to D::foo() and C::barC().
-// CHECK: @_ZTV1D.local = private unnamed_addr constant { [5 x i32], [4 x i32] } { [5 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }** @_ZTI1D.rtti_proxy to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.D*)* dso_local_equivalent @_ZN1D3fooEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.B*)* dso_local_equivalent @_ZN1B4barBEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.D*)* dso_local_equivalent @_ZN1D3bazEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 0, i32 2) to i64)) to i32)], [4 x i32] [i32 -8, i32 trunc (i64 sub (i64 ptrtoint ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }** @_ZTI1D.rtti_proxy to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 1, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.D*)* dso_local_equivalent @_ZThn8_N1D3fooEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 1, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.C*)* dso_local_equivalent @_ZN1C4barCEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 1, i32 2) to i64)) to i32)] }, align 4
+// CHECK: @_ZTV1D.local = private unnamed_addr constant { [5 x i32], [4 x i32] } { [5 x i32] [i32 0, i32 trunc (i64 sub (i64 ptrtoint ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }** @_ZTI1D.rtti_proxy to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.D*)* dso_local_equivalent @_ZN1D3fooEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.B*)* dso_local_equivalent @_ZN1B4barBEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.D*)* dso_local_equivalent @_ZN1D3bazEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 0, i32 2) to i64)) to i32)], [4 x i32] [i32 -8, i32 trunc (i64 sub (i64 ptrtoint ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }** @_ZTI1D.rtti_proxy to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 1, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.A*)* dso_local_equivalent @_ZThn8_N1D3fooEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 1, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (void (%class.C*)* dso_local_equivalent @_ZN1C4barCEv to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [5 x i32], [4 x i32] }, { [5 x i32], [4 x i32] }* @_ZTV1D.local, i32 0, i32 1, i32 2) to i64)) to i32)] }, align 4
 
 // @_ZTV1B ={{.*}} unnamed_addr alias { [4 x i32] }, { [4 x i32] }* @_ZTV1B.local
 // @_ZTV1C ={{.*}} unnamed_addr alias { [4 x i32] }, { [4 x i32] }* @_ZTV1C.local
Index: clang/test/CodeGen/available-externally-hidden.cpp
===================================================================
--- clang/test/CodeGen/available-externally-hidden.cpp
+++ clang/test/CodeGen/available-externally-hidden.cpp
@@ -21,6 +21,7 @@
 class SyncMessageFilter : public Filter, public Sender {
  public:
   bool Send(Message* message) override;
+  // expected-error@-1 {{cannot compile this thunk for forward declaration yet}}
 };
 
 class TestSyncMessageFilter : public SyncMessageFilter {
Index: clang/lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -2084,7 +2084,7 @@
     CGF.Builder.CreateAlignedLoad(ThunkTy->getPointerTo(), VFuncPtr,
                                   CGF.getPointerAlign());
 
-  CGF.EmitMustTailThunk(MD, getThisValue(CGF), {ThunkTy, Callee});
+  CGF.EmitMustTailThunk(MD, getThisValue(CGF), FnInfo, {ThunkTy, Callee});
 
   return ThunkFn;
 }
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -2183,18 +2183,21 @@
                   const CGFunctionInfo &FnInfo, bool IsUnprototyped);
 
   void EmitCallAndReturnForThunk(llvm::FunctionCallee Callee,
-                                 const ThunkInfo *Thunk, bool IsUnprototyped);
+                                 const CGFunctionInfo &CalleeFnInfo,
+                                 GlobalDecl CalleeGD, const ThunkInfo *Thunk,
+                                 bool IsUnprototyped);
 
   void FinishThunk();
 
   /// Emit a musttail call for a thunk with a potentially adjusted this pointer.
-  void EmitMustTailThunk(GlobalDecl GD, llvm::Value *AdjustedThisPtr,
+  void EmitMustTailThunk(GlobalDecl CalleeGD, llvm::Value *AdjustedThisPtr,
+                         const CGFunctionInfo &CalleeFnInfo,
                          llvm::FunctionCallee Callee);
 
   /// Generate a thunk for the given method.
-  void generateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
-                     GlobalDecl GD, const ThunkInfo &Thunk,
-                     bool IsUnprototyped);
+  void generateThunk(llvm::Function *ThunkFn, const CGFunctionInfo &ThunkFnInfo,
+                     GlobalDecl ThunkGD, GlobalDecl CalleeGD,
+                     const ThunkInfo &Thunk, bool IsUnprototyped);
 
   llvm::Function *GenerateVarArgsThunk(llvm::Function *Fn,
                                        const CGFunctionInfo &FnInfo,
Index: clang/lib/CodeGen/CGVTables.cpp
===================================================================
--- clang/lib/CodeGen/CGVTables.cpp
+++ clang/lib/CodeGen/CGVTables.cpp
@@ -163,8 +163,12 @@
 
   // Get the original function
   assert(FnInfo.isVariadic());
-  llvm::Type *Ty = CGM.getTypes().GetFunctionType(FnInfo);
-  llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
+
+  const CGFunctionInfo &CalleeFnInfo =
+      CGM.getTypes().arrangeGlobalDeclaration(GD);
+  llvm::FunctionType *CalleeFnTy = CGM.getTypes().GetFunctionType(CalleeFnInfo);
+  llvm::Constant *Callee =
+      CGM.GetAddrOfFunction(GD, CalleeFnTy, /*ForVTable=*/true);
   llvm::Function *BaseFn = cast<llvm::Function>(Callee);
 
   // Cloning can't work if we don't have a definition. The Microsoft ABI may
@@ -183,7 +187,7 @@
   // Ensure that the value mapper does not encounter any of them.
   resolveTopLevelMetadata(BaseFn, VMap);
   llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap);
-  Fn->replaceAllUsesWith(NewFn);
+  Fn->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(NewFn, Fn->getType()));
   NewFn->takeName(Fn);
   Fn->eraseFromParent();
   Fn = NewFn;
@@ -289,9 +293,9 @@
   FinishFunction();
 }
 
-void CodeGenFunction::EmitCallAndReturnForThunk(llvm::FunctionCallee Callee,
-                                                const ThunkInfo *Thunk,
-                                                bool IsUnprototyped) {
+void CodeGenFunction::EmitCallAndReturnForThunk(
+    llvm::FunctionCallee Callee, const CGFunctionInfo &CalleeFnInfo,
+    GlobalDecl CalleeGD, const ThunkInfo *Thunk, bool IsUnprototyped) {
   assert(isa<CXXMethodDecl>(CurGD.getDecl()) &&
          "Please use a new CGF for this thunk");
   const CXXMethodDecl *MD = cast<CXXMethodDecl>(CurGD.getDecl());
@@ -317,14 +321,15 @@
         CGM.ErrorUnsupported(
             MD, "non-trivial argument copy for return-adjusting thunk");
     }
-    EmitMustTailThunk(CurGD, AdjustedThisPtr, Callee);
+    EmitMustTailThunk(CalleeGD, AdjustedThisPtr, CalleeFnInfo, Callee);
     return;
   }
 
   // Start building CallArgs.
   CallArgList CallArgs;
-  QualType ThisType = MD->getThisType();
-  CallArgs.add(RValue::get(AdjustedThisPtr), ThisType);
+  QualType CalleeThisType =
+      cast<CXXMethodDecl>(CalleeGD.getDecl())->getThisType();
+  CallArgs.add(RValue::get(AdjustedThisPtr), CalleeThisType);
 
   if (isa<CXXDestructorDecl>(MD))
     CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, CurGD, CallArgs);
@@ -356,11 +361,10 @@
 #endif
 
   // Determine whether we have a return value slot to use.
-  QualType ResultType = CGM.getCXXABI().HasThisReturn(CurGD)
-                            ? ThisType
-                            : CGM.getCXXABI().hasMostDerivedReturn(CurGD)
-                                  ? CGM.getContext().VoidPtrTy
-                                  : FPT->getReturnType();
+  QualType ResultType = CGM.getCXXABI().HasThisReturn(CurGD) ? CalleeThisType
+                        : CGM.getCXXABI().hasMostDerivedReturn(CurGD)
+                            ? CGM.getContext().VoidPtrTy
+                            : FPT->getReturnType();
   ReturnValueSlot Slot;
   if (!ResultType->isVoidType() &&
       (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect ||
@@ -370,8 +374,8 @@
 
   // Now emit our call.
   llvm::CallBase *CallOrInvoke;
-  RValue RV = EmitCall(*CurFnInfo, CGCallee::forDirect(Callee, CurGD), Slot,
-                       CallArgs, &CallOrInvoke);
+  RValue RV = EmitCall(CalleeFnInfo, CGCallee::forDirect(Callee, CalleeGD),
+                       Slot, CallArgs, &CallOrInvoke);
 
   // Consider return adjustment if we have ThunkInfo.
   if (Thunk && !Thunk->Return.isEmpty())
@@ -380,8 +384,12 @@
     Call->setTailCallKind(llvm::CallInst::TCK_Tail);
 
   // Emit return.
-  if (!ResultType->isVoidType() && Slot.isNull())
+  if (!ResultType->isVoidType() && Slot.isNull()) {
+    if (RV.getScalarVal())
+      RV = RValue::get(
+          Builder.CreateBitCast(RV.getScalarVal(), CurFn->getReturnType()));
     CGM.getCXXABI().EmitReturnFromThunk(*this, RV, ResultType);
+  }
 
   // Disable the final ARC autorelease.
   AutoreleaseResult = false;
@@ -389,8 +397,9 @@
   FinishThunk();
 }
 
-void CodeGenFunction::EmitMustTailThunk(GlobalDecl GD,
+void CodeGenFunction::EmitMustTailThunk(GlobalDecl CalleeGD,
                                         llvm::Value *AdjustedThisPtr,
+                                        const CGFunctionInfo &CalleeFnInfo,
                                         llvm::FunctionCallee Callee) {
   // Emitting a musttail call thunk doesn't use any of the CGCall.cpp machinery
   // to translate AST arguments into LLVM IR arguments.  For thunks, we know
@@ -401,11 +410,11 @@
     Args.push_back(&A);
 
   // Set the adjusted 'this' pointer.
-  const ABIArgInfo &ThisAI = CurFnInfo->arg_begin()->info;
+  const ABIArgInfo &ThisAI = CalleeFnInfo.arg_begin()->info;
   if (ThisAI.isDirect()) {
-    const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo();
+    const ABIArgInfo &RetAI = CalleeFnInfo.getReturnInfo();
     int ThisArgNo = RetAI.isIndirect() && !RetAI.isSRetAfterThis() ? 1 : 0;
-    llvm::Type *ThisType = Args[ThisArgNo]->getType();
+    llvm::Type *ThisType = Callee.getFunctionType()->getParamType(ThisArgNo);
     if (ThisType != AdjustedThisPtr->getType())
       AdjustedThisPtr = Builder.CreateBitCast(AdjustedThisPtr, ThisType);
     Args[ThisArgNo] = AdjustedThisPtr;
@@ -426,15 +435,16 @@
   // Apply the standard set of call attributes.
   unsigned CallingConv;
   llvm::AttributeList Attrs;
-  CGM.ConstructAttributeList(Callee.getCallee()->getName(), *CurFnInfo, GD,
-                             Attrs, CallingConv, /*AttrOnCallSite=*/true);
+  CGM.ConstructAttributeList(Callee.getCallee()->getName(), CalleeFnInfo,
+                             CalleeGD, Attrs, CallingConv,
+                             /*AttrOnCallSite=*/true);
   Call->setAttributes(Attrs);
   Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
 
   if (Call->getType()->isVoidTy())
     Builder.CreateRetVoid();
   else
-    Builder.CreateRet(Call);
+    Builder.CreateRet(Builder.CreateBitCast(Call, CurFn->getReturnType()));
 
   // Finish the function to maintain CodeGenFunction invariants.
   // FIXME: Don't emit unreachable code.
@@ -443,31 +453,34 @@
   FinishThunk();
 }
 
-void CodeGenFunction::generateThunk(llvm::Function *Fn,
-                                    const CGFunctionInfo &FnInfo, GlobalDecl GD,
+void CodeGenFunction::generateThunk(llvm::Function *ThunkFn,
+                                    const CGFunctionInfo &ThunkFnInfo,
+                                    GlobalDecl ThunkGD, GlobalDecl CalleeGD,
                                     const ThunkInfo &Thunk,
                                     bool IsUnprototyped) {
-  StartThunk(Fn, GD, FnInfo, IsUnprototyped);
+  StartThunk(ThunkFn, ThunkGD, ThunkFnInfo, IsUnprototyped);
   // Create a scope with an artificial location for the body of this function.
   auto AL = ApplyDebugLocation::CreateArtificial(*this);
 
-  // Get our callee. Use a placeholder type if this method is unprototyped so
-  // that CodeGenModule doesn't try to set attributes.
-  llvm::Type *Ty;
-  if (IsUnprototyped)
-    Ty = llvm::StructType::get(getLLVMContext());
-  else
-    Ty = CGM.getTypes().GetFunctionType(FnInfo);
+  auto *CalleeMD = cast<CXXMethodDecl>(CalleeGD.getDecl());
+  if (!CalleeMD->isDefined()) {
+    CGM.ErrorUnsupported(ThunkGD.getDecl(), "thunk for forward declaration");
+    return;
+  }
 
-  llvm::Constant *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
+  const CGFunctionInfo &CalleeFnInfo =
+      CGM.getTypes().arrangeGlobalDeclaration(CalleeGD);
+  llvm::FunctionType *CalleeFnTy = CGM.getTypes().GetFunctionType(CalleeFnInfo);
+  llvm::Constant *Callee =
+      CGM.GetAddrOfFunction(CalleeGD, CalleeFnTy, /*ForVTable=*/true);
 
   // Fix up the function type for an unprototyped musttail call.
   if (IsUnprototyped)
-    Callee = llvm::ConstantExpr::getBitCast(Callee, Fn->getType());
+    Callee = llvm::ConstantExpr::getBitCast(Callee, CalleeFnTy);
 
   // Make the call and return the result.
-  EmitCallAndReturnForThunk(llvm::FunctionCallee(Fn->getFunctionType(), Callee),
-                            &Thunk, IsUnprototyped);
+  EmitCallAndReturnForThunk(llvm::FunctionCallee(CalleeFnTy, Callee),
+                            CalleeFnInfo, CalleeGD, &Thunk, IsUnprototyped);
 }
 
 static bool shouldEmitVTableThunk(CodeGenModule &CGM, const CXXMethodDecl *MD,
@@ -503,21 +516,25 @@
     MCtx.mangleCXXDtorThunk(DD, GD.getDtorType(), TI.This, Out);
   else
     MCtx.mangleThunk(MD, TI, Out);
+
   llvm::Type *ThunkVTableTy = CGM.getTypes().GetFunctionTypeForVTable(GD);
   llvm::Constant *Thunk = CGM.GetAddrOfThunk(Name, ThunkVTableTy, GD);
 
   // If we don't need to emit a definition, return this declaration as is.
   bool IsUnprototyped = !CGM.getTypes().isFuncTypeConvertible(
-      MD->getType()->castAs<FunctionType>());
+      cast<CXXMethodDecl>(TI.BaseMethod.getDecl())
+          ->getType()
+          ->castAs<FunctionType>());
   if (!shouldEmitVTableThunk(CGM, MD, IsUnprototyped, ForVTable))
     return Thunk;
 
-  // Arrange a function prototype appropriate for a function definition. In some
+  // Arrange a thunk function prototype appropriate for a function def. In some
   // cases in the MS ABI, we may need to build an unprototyped musttail thunk.
-  const CGFunctionInfo &FnInfo =
-      IsUnprototyped ? CGM.getTypes().arrangeUnprototypedMustTailThunk(MD)
-                     : CGM.getTypes().arrangeGlobalDeclaration(GD);
-  llvm::FunctionType *ThunkFnTy = CGM.getTypes().GetFunctionType(FnInfo);
+  const CGFunctionInfo &ThunkFnInfo =
+      IsUnprototyped ? CGM.getTypes().arrangeUnprototypedMustTailThunk(
+                           cast<CXXMethodDecl>(TI.BaseMethod.getDecl()))
+                     : CGM.getTypes().arrangeGlobalDeclaration(TI.BaseMethod);
+  llvm::FunctionType *ThunkFnTy = CGM.getTypes().GetFunctionType(ThunkFnInfo);
 
   // If the type of the underlying GlobalValue is wrong, we'll have to replace
   // it. It should be a declaration.
@@ -525,13 +542,15 @@
   if (ThunkFn->getFunctionType() != ThunkFnTy) {
     llvm::GlobalValue *OldThunkFn = ThunkFn;
 
-    assert(OldThunkFn->isDeclaration() && "Shouldn't replace non-declaration");
+    // FIXME: ???
+    // assert(OldThunkFn->isDeclaration() && "Shouldn't replace
+    // non-declaration");
 
     // Remove the name from the old thunk function and get a new thunk.
     OldThunkFn->setName(StringRef());
     ThunkFn = llvm::Function::Create(ThunkFnTy, llvm::Function::ExternalLinkage,
                                      Name.str(), &CGM.getModule());
-    CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn);
+    CGM.SetLLVMFunctionAttributes(GD, ThunkFnInfo, ThunkFn);
 
     // If needed, replace the old thunk with a bitcast.
     if (!OldThunkFn->use_empty()) {
@@ -564,7 +583,7 @@
   if (IsUnprototyped)
     ThunkFn->addFnAttr("thunk");
 
-  CGM.SetLLVMFunctionAttributesForDefinition(GD.getDecl(), ThunkFn);
+  CGM.SetLLVMFunctionAttributesForDefinition(MD, ThunkFn);
 
   // Thunks for variadic methods are special because in general variadic
   // arguments cannot be perfectly forwarded. In the general case, clang
@@ -591,10 +610,11 @@
     if (UseAvailableExternallyLinkage)
       return ThunkFn;
     ThunkFn =
-        CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, TI);
+        CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, ThunkFnInfo, GD, TI);
   } else {
     // Normal thunk body generation.
-    CodeGenFunction(CGM).generateThunk(ThunkFn, FnInfo, GD, TI, IsUnprototyped);
+    CodeGenFunction(CGM).generateThunk(ThunkFn, ThunkFnInfo, TI.BaseMethod, GD,
+                                       TI, IsUnprototyped);
   }
 
   setThunkProperties(CGM, TI, ThunkFn, ForVTable, GD);
Index: clang/lib/AST/VTableBuilder.cpp
===================================================================
--- clang/lib/AST/VTableBuilder.cpp
+++ clang/lib/AST/VTableBuilder.cpp
@@ -913,7 +913,8 @@
 
   /// AddMethod - Add a single virtual member function to the vtable
   /// components vector.
-  void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment);
+  void AddMethod(const CXXMethodDecl *BaseMethod, const CXXMethodDecl *MD,
+                 ReturnAdjustment ReturnAdjustment);
 
   /// IsOverriderUsed - Returns whether the overrider will ever be used in this
   /// part of the vtable.
@@ -1115,10 +1116,12 @@
 
     // Ignore adjustments for unused function pointers.
     uint64_t VTableIndex = MethodInfo.VTableIndex;
-    if (Components[VTableIndex].getKind() ==
-        VTableComponent::CK_UnusedFunctionPointer)
+    const VTableComponent &component = Components[VTableIndex];
+    if (component.getKind() == VTableComponent::CK_UnusedFunctionPointer)
       continue;
 
+    GlobalDecl GD = component.getGlobalDecl();
+
     // Get the final overrider for this method.
     FinalOverriders::OverriderInfo Overrider =
       Overriders.getOverrider(MD, MethodInfo.BaseOffset);
@@ -1130,7 +1133,8 @@
       // While the thunk itself might be needed by vtables in subclasses or
       // in construction vtables, there doesn't seem to be a reason for using
       // the thunk in this vtable. Still, we do so to match gcc.
-      if (VTableThunks.lookup(VTableIndex).Return.isEmpty())
+      auto it = VTableThunks.find(VTableIndex);
+      if (it == VTableThunks.end() || it->second.Return.isEmpty())
         continue;
     }
 
@@ -1140,12 +1144,33 @@
     if (ThisAdjustment.isEmpty())
       continue;
 
-    // Add it.
-    VTableThunks[VTableIndex].This = ThisAdjustment;
+    auto ApplyThisAdjustment = [&](unsigned Idx) {
+      Optional<ThunkInfo> TI;
+
+      auto it = VTableThunks.find(Idx);
+      if (it != VTableThunks.end()) {
+        TI = it->second;
+        TI->This = ThisAdjustment;
+      } else {
+        GlobalDecl BaseMethod;
+        if (auto *DD = dyn_cast<CXXDestructorDecl>(MD))
+          BaseMethod = GlobalDecl(DD, GD.getDtorType());
+        else
+          BaseMethod = MD;
+
+        TI = {BaseMethod, ThisAdjustment, ReturnAdjustment()};
+      }
+
+      // Override it. Note that there may or may not be a thunk already.
+      VTableThunks.erase(Idx);
+      VTableThunks.insert({Idx, *TI});
+    };
+
+    ApplyThisAdjustment(VTableIndex);
 
     if (isa<CXXDestructorDecl>(MD)) {
       // Add an adjustment for the deleting destructor as well.
-      VTableThunks[VTableIndex + 1].This = ThisAdjustment;
+      ApplyThisAdjustment(VTableIndex + 1);
     }
   }
 
@@ -1300,7 +1325,8 @@
   return Adjustment;
 }
 
-void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *MD,
+void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *BaseMethod,
+                                     const CXXMethodDecl *MD,
                                      ReturnAdjustment ReturnAdjustment) {
   if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
     assert(ReturnAdjustment.isEmpty() &&
@@ -1311,8 +1337,13 @@
     Components.push_back(VTableComponent::MakeDeletingDtor(DD));
   } else {
     // Add the return adjustment if necessary.
-    if (!ReturnAdjustment.isEmpty())
-      VTableThunks[Components.size()].Return = ReturnAdjustment;
+    if (!ReturnAdjustment.isEmpty()) {
+      assert(VTableThunks.find(Components.size()) == VTableThunks.end() &&
+             "ZZZ");
+      VTableThunks.insert(
+          {Components.size(),
+           ThunkInfo(BaseMethod, ThisAdjustment(), ReturnAdjustment)});
+    }
 
     // Add the function.
     Components.push_back(VTableComponent::MakeFunction(MD));
@@ -1513,6 +1544,10 @@
         MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
                               OverriddenMethodInfo.VTableIndex);
 
+        uint64_t VTableIndex = MethodInfo.VTableIndex;
+        const VTableComponent &component = Components[VTableIndex];
+        GlobalDecl GD = component.getGlobalDecl();
+
         assert(!MethodInfoMap.count(MD) &&
                "Should not have method info for this method yet!");
 
@@ -1540,9 +1575,15 @@
             ReturnAdjustment ReturnAdjustment =
               ComputeReturnAdjustment(ReturnAdjustmentOffset);
 
+            GlobalDecl BaseMethod;
+            if (auto *DD = dyn_cast<CXXDestructorDecl>(MD))
+              BaseMethod = GlobalDecl(DD, GD.getDtorType());
+            else
+              BaseMethod = MD;
+
             // This is a virtual thunk for the most derived class, add it.
             AddThunk(Overrider.Method,
-                     ThunkInfo(ThisAdjustment, ReturnAdjustment));
+                     ThunkInfo(BaseMethod, ThisAdjustment, ReturnAdjustment));
           }
         }
 
@@ -1608,7 +1649,7 @@
     ReturnAdjustment ReturnAdjustment =
       ComputeReturnAdjustment(ReturnAdjustmentOffset);
 
-    AddMethod(Overrider.Method, ReturnAdjustment);
+    AddMethod(MD, Overrider.Method, ReturnAdjustment);
   }
 }
 
@@ -1958,8 +1999,9 @@
       if (MD->isDeleted())
         Out << " [deleted]";
 
-      ThunkInfo Thunk = VTableThunks.lookup(I);
-      if (!Thunk.isEmpty()) {
+      auto it = VTableThunks.find(I);
+      if (it != VTableThunks.end()) {
+        ThunkInfo Thunk = it->second;
         // If this function pointer has a return adjustment, dump it.
         if (!Thunk.Return.isEmpty()) {
           Out << "\n       [return adjustment: ";
@@ -2006,8 +2048,9 @@
       if (DD->isPure())
         Out << " [pure]";
 
-      ThunkInfo Thunk = VTableThunks.lookup(I);
-      if (!Thunk.isEmpty()) {
+      auto it = VTableThunks.find(I);
+      if (it != VTableThunks.end()) {
+        ThunkInfo Thunk = it->second;
         // If this destructor has a 'this' pointer adjustment, dump it.
         if (!Thunk.This.isEmpty()) {
           Out << "\n       [this adjustment: ";
@@ -2120,7 +2163,6 @@
 
       ThunkInfoVectorTy ThunksVector = Thunks[MD];
       llvm::sort(ThunksVector, [](const ThunkInfo &LHS, const ThunkInfo &RHS) {
-        assert(LHS.Method == nullptr && RHS.Method == nullptr);
         return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return);
       });
 
@@ -2513,18 +2555,29 @@
 
   /// AddMethod - Add a single virtual member function to the vftable
   /// components vector.
-  void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) {
-    if (!TI.isEmpty()) {
-      VTableThunks[Components.size()] = TI;
-      AddThunk(MD, TI);
-    }
+  void AddMethod(const CXXMethodDecl *BaseMD, const CXXMethodDecl *MD,
+                 ThisAdjustment This, ReturnAdjustment Return) {
     if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
-      assert(TI.Return.isEmpty() &&
-             "Destructor can't have return adjustment!");
+      assert(Return.isEmpty() && "Destructor can't have return adjustment!");
       Components.push_back(VTableComponent::MakeDeletingDtor(DD));
     } else {
       Components.push_back(VTableComponent::MakeFunction(MD));
     }
+
+    GlobalDecl GD;
+    if (isa<CXXDestructorDecl>(BaseMD))
+      GD = GlobalDecl(cast<CXXDestructorDecl>(BaseMD),
+                      CXXDtorType::Dtor_Deleting);
+    else
+      GD = BaseMD;
+
+    ThunkInfo TI(GD, This, Return);
+    if (!TI.isEmpty()) {
+      assert(VTableThunks.find(Components.size() - 1) == VTableThunks.end() &&
+             "ZZZ");
+      VTableThunks.insert({Components.size() - 1, TI});
+      AddThunk(MD, TI);
+    }
   }
 
   /// AddMethods - Add the methods of this base subobject and the relevant
@@ -3091,9 +3144,7 @@
       }
     }
 
-    AddMethod(FinalOverriderMD,
-              ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
-                        ForceReturnAdjustmentMangling ? MD : nullptr));
+    AddMethod(MD, FinalOverriderMD, ThisAdjustmentOffset, ReturnAdjustment);
   }
 }
 
@@ -3111,11 +3162,14 @@
   const ReturnAdjustment &R = TI.Return;
   bool Multiline = false;
   const char *LinePrefix = "\n       ";
-  if (!R.isEmpty() || TI.Method) {
+  if (!R.isEmpty()) {
     if (!ContinueFirstLine)
       Out << LinePrefix;
     Out << "[return adjustment (to type '"
-        << TI.Method->getReturnType().getCanonicalType().getAsString()
+        << cast<CXXMethodDecl>(TI.BaseMethod.getDecl())
+               ->getReturnType()
+               .getCanonicalType()
+               .getAsString()
         << "'): ";
     if (R.Virtual.Microsoft.VBPtrOffset)
       Out << "vbptr at offset " << R.Virtual.Microsoft.VBPtrOffset << ", ";
@@ -3179,9 +3233,11 @@
       if (MD->isDeleted())
         Out << " [deleted]";
 
-      ThunkInfo Thunk = VTableThunks.lookup(I);
-      if (!Thunk.isEmpty())
+      auto it = VTableThunks.find(I);
+      if (it != VTableThunks.end()) {
+        ThunkInfo Thunk = it->second;
         dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
+      }
 
       break;
     }
@@ -3195,8 +3251,9 @@
       if (DD->isPure())
         Out << " [pure]";
 
-      ThunkInfo Thunk = VTableThunks.lookup(I);
-      if (!Thunk.isEmpty()) {
+      auto it = VTableThunks.find(I);
+      if (it != VTableThunks.end()) {
+        ThunkInfo Thunk = it->second;
         assert(Thunk.Return.isEmpty() &&
                "No return adjustment needed for destructors!");
         dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
Index: clang/lib/AST/MicrosoftMangle.cpp
===================================================================
--- clang/lib/AST/MicrosoftMangle.cpp
+++ clang/lib/AST/MicrosoftMangle.cpp
@@ -3466,13 +3466,10 @@
   AccessSpecifier AS = Thunk.Return.isEmpty() ? MD->getAccess() : AS_public;
   mangleThunkThisAdjustment(AS, Thunk.This, Mangler, MHO);
 
-  if (!Thunk.Return.isEmpty())
-    assert(Thunk.Method != nullptr &&
-           "Thunk info should hold the overridee decl");
-
-  const CXXMethodDecl *DeclForFPT = Thunk.Method ? Thunk.Method : MD;
-  Mangler.mangleFunctionType(
-      DeclForFPT->getType()->castAs<FunctionProtoType>(), MD);
+  Mangler.mangleFunctionType(cast<FunctionDecl>(Thunk.BaseMethod.getDecl())
+                                 ->getType()
+                                 ->castAs<FunctionProtoType>(),
+                             MD);
 }
 
 void MicrosoftMangleContextImpl::mangleCXXDtorThunk(
Index: clang/include/clang/Basic/Thunk.h
===================================================================
--- clang/include/clang/Basic/Thunk.h
+++ clang/include/clang/Basic/Thunk.h
@@ -151,33 +151,29 @@
 /// The \c this pointer adjustment as well as an optional return
 /// adjustment for a thunk.
 struct ThunkInfo {
+  /// Holds a pointer to the overridden (i.e. base) method this thunk is for.
+  /// CAUTION: In the unlikely event you need to sort ThunkInfos, consider using
+  /// an ABI-specific comparator.
+  GlobalDecl BaseMethod;
+
   /// The \c this pointer adjustment.
   ThisAdjustment This;
 
   /// The return adjustment.
   ReturnAdjustment Return;
 
-  /// Holds a pointer to the overridden method this thunk is for,
-  /// if needed by the ABI to distinguish different thunks with equal
-  /// adjustments. Otherwise, null.
-  /// CAUTION: In the unlikely event you need to sort ThunkInfos, consider using
-  /// an ABI-specific comparator.
-  const CXXMethodDecl *Method;
+  ThunkInfo() = delete;
 
-  ThunkInfo() : Method(nullptr) {}
-
-  ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return,
-            const CXXMethodDecl *Method = nullptr)
-      : This(This), Return(Return), Method(Method) {}
+  ThunkInfo(GlobalDecl BaseMethod, const ThisAdjustment &This,
+            const ReturnAdjustment &Return)
+      : BaseMethod(BaseMethod), This(This), Return(Return) {}
 
   friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
-    return LHS.This == RHS.This && LHS.Return == RHS.Return &&
-           LHS.Method == RHS.Method;
+    return LHS.BaseMethod == RHS.BaseMethod && LHS.This == RHS.This &&
+           LHS.Return == RHS.Return;
   }
 
-  bool isEmpty() const {
-    return This.isEmpty() && Return.isEmpty() && Method == nullptr;
-  }
+  bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); }
 };
 
 } // end namespace clang
Index: clang/include/clang/AST/VTableBuilder.h
===================================================================
--- clang/include/clang/AST/VTableBuilder.h
+++ clang/include/clang/AST/VTableBuilder.h
@@ -254,7 +254,7 @@
   OwningArrayRef<VTableComponent> VTableComponents;
 
   /// Contains thunks needed by vtables, sorted by indices.
-  OwningArrayRef<VTableThunkTy> VTableThunks;
+  std::vector<VTableThunkTy> VTableThunks;
 
   /// Address points for all vtables.
   AddressPointsMapTy AddressPoints;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to