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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits