// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 >%t 2>&1 // RUN: FileCheck --check-prefix=MANGLING %s < %t // RUN: FileCheck --check-prefix=XMANGLING %s < %t // RUN: FileCheck --check-prefix=CODEGEN %s < %t // RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 2>&1 | FileCheck --check-prefix=MANGLING-X64 %s void foo(void *); struct A { virtual ~A(); virtual void public_f(); // Make sure we don't emit unneeded thunks: // XMANGLING-NOT: @"?public_f@A@@QAEXXZ" protected: virtual void protected_f(); private: virtual void private_f(); }; struct B { virtual ~B(); virtual void public_f(); protected: virtual void protected_f(); private: virtual void private_f(); }; struct C : A, B { C(); virtual ~C(); // MANGLING-DAG: declare {{.*}} @"??1C@@UAE@XZ"({{.*}}) // MANGLING-DAG: define {{.*}} @"??_GC@@UAEPAXI@Z"({{.*}}) // MANGLING-DAG: define {{.*}} @"??_EC@@W3AEPAXI@Z"({{.*}}) {{.*}} comdat // MANGLING-X64-DAG: declare {{.*}} @"??1C@@UEAA@XZ"({{.*}}) // MANGLING-X64-DAG: define {{.*}} @"??_GC@@UEAAPEAXI@Z"({{.*}}) // MANGLING-X64-DAG: define {{.*}} @"??_EC@@W7EAAPEAXI@Z"({{.*}}) {{.*}} comdat // Overrides public_f() of two subobjects with distinct vfptrs, thus needs a thunk. virtual void public_f(); // MANGLING-DAG: @"?public_f@C@@UAEXXZ" // MANGLING-DAG: @"?public_f@C@@W3AEXXZ" // MANGLING-X64-DAG: @"?public_f@C@@UEAAXXZ" // MANGLING-X64-DAG: @"?public_f@C@@W7EAAXXZ" protected: virtual void protected_f(); // MANGLING-DAG: @"?protected_f@C@@MAEXXZ" // MANGLING-DAG: @"?protected_f@C@@O3AEXXZ" // MANGLING-X64-DAG: @"?protected_f@C@@MEAAXXZ" // MANGLING-X64-DAG: @"?protected_f@C@@O7EAAXXZ" private: virtual void private_f(); // MANGLING-DAG: @"?private_f@C@@EAEXXZ" // MANGLING-DAG: @"?private_f@C@@G3AEXXZ" // MANGLING-X64-DAG: @"?private_f@C@@EEAAXXZ" // MANGLING-X64-DAG: @"?private_f@C@@G7EAAXXZ" }; C::C() {} // Emits vftable and forces thunk generation. // CODEGEN-LABEL: define linkonce_odr dso_local x86_thiscallcc i8* @"??_EC@@W3AEPAXI@Z"(%struct.C* {{[^,]*}} %this, i32 %should_call_delete) {{.*}} comdat // CODEGEN: getelementptr i8, i8* {{.*}}, i32 -4 // FIXME: should actually call _EC, not _GC. // CODEGEN: call x86_thiscallcc i8* @"??_GC@@UAEPAXI@Z" // CODEGEN: ret // CODEGEN-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"?public_f@C@@W3AEXXZ"(%struct.C* // CODEGEN: getelementptr i8, i8* {{.*}}, i32 -4 // CODEGEN: call x86_thiscallcc void @"?public_f@C@@UAEXXZ"(%struct.C* // CODEGEN: ret void zoo(C* obj) { delete obj; } struct D { virtual B* goo(); }; struct E : D { E(); virtual C* goo(); // MANGLING-DAG: @"?goo@E@@UAEPAUC@@XZ" // MANGLING-DAG: @"?goo@E@@QAEPAUB@@XZ" // MANGLING-X64-DAG: @"?goo@E@@UEAAPEAUC@@XZ" // MANGLING-X64-DAG: @"?goo@E@@QEAAPEAUB@@XZ" }; E::E() {} // Emits vftable and forces thunk generation. // CODEGEN-LABEL: define weak_odr dso_local x86_thiscallcc %struct.C* @"?goo@E@@QAEPAUB@@XZ"{{.*}} comdat // CODEGEN: call x86_thiscallcc %struct.C* @"?goo@E@@UAEPAUC@@XZ" // CODEGEN: getelementptr inbounds i8, i8* {{.*}}, i32 4 // CODEGEN: ret struct F : virtual A, virtual B { virtual void own_method(); virtual ~F(); }; F f; // Just make sure we don't crash, e.g. mangling the complete dtor. struct G : C { }; struct H : E { virtual G* goo(); // MANGLING-DAG: @"?goo@H@@UAEPAUG@@XZ" // MANGLING-DAG: @"?goo@H@@QAEPAUB@@XZ" // MANGLING-DAG: @"?goo@H@@QAEPAUC@@XZ" // MANGLING-X64-DAG: @"?goo@H@@UEAAPEAUG@@XZ" // MANGLING-X64-DAG: @"?goo@H@@QEAAPEAUB@@XZ" // MANGLING-X64-DAG: @"?goo@H@@QEAAPEAUC@@XZ" }; H h; struct I : D { I(); virtual F* goo(); }; I::I() {} // Emits vftable and forces thunk generation. // CODEGEN-LABEL: define weak_odr dso_local x86_thiscallcc %struct.{{[BF]}}* @"?goo@I@@QAEPAUB@@XZ"{{.*}} comdat // CODEGEN: %[[ORIG_RET:.*]] = call x86_thiscallcc %struct.F* @"?goo@I@@UAEPAUF@@XZ" // CODEGEN: %[[ORIG_RET_i8:.*]] = bitcast %struct.F* %[[ORIG_RET]] to i8* // CODEGEN: %[[VBPTR_i8:.*]] = getelementptr inbounds i8, i8* %[[ORIG_RET_i8]], i32 4 // CODEGEN: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i32** // CODEGEN: %[[VBTABLE:.*]] = load i32*, i32** %[[VBPTR]] // CODEGEN: %[[VBASE_OFFSET_PTR:.*]] = getelementptr inbounds i32, i32* %[[VBTABLE]], i32 2 // CODEGEN: %[[VBASE_OFFSET:.*]] = load i32, i32* %[[VBASE_OFFSET_PTR]] // CODEGEN: %[[RES_i8:.*]] = getelementptr inbounds i8, i8* %[[VBPTR_i8]], i32 %[[VBASE_OFFSET]] // CODEGEN: %[[RES:.*]] = bitcast i8* %[[RES_i8]] to %struct.F* // CODEGEN: phi %struct.F* {{.*}} %[[RES]] // CODEGEN: ret %struct.{{[BF]}}* namespace CrashOnThunksForAttributedType { // We used to crash on this because the type of foo is an AttributedType, not // FunctionType, and we had to look through the sugar. struct A { virtual void __stdcall foo(); }; struct B { virtual void __stdcall foo(); }; struct C : A, B { virtual void __stdcall foo(); }; C c; } namespace { struct E : D { E(); virtual C* goo(); }; E::E() {} E e; // Class with internal linkage has internal linkage thunks. // CODEGEN: define internal x86_thiscallcc %struct.C* @"?goo@E@?A0x{{[^@]*}}@@QAEPAUB@@XZ" }