1651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fno-rtti | FileCheck -check-prefix WIN32 %s 29b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner 39b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerstruct A { 49b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner A(); 59b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner ~A(); 69b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner int a; 79b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner}; 89b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner 99b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid KlecknerA getA(); 109b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner 119b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerint TakesTwo(A a, A b); 129b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknervoid HasEHCleanup() { 139b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner TakesTwo(getA(), getA()); 149b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner} 159b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner 169b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// With exceptions, we need to clean up at least one of these temporaries. 17651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-LABEL: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} { 18651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: %[[base:.*]] = call i8* @llvm.stacksave() 19651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// If this call throws, we have to restore the stack. 20651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) 219b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// If this call throws, we have to cleanup the first temporary. 229b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) 23651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// If this call throws, we have to cleanup the stacksave. 24651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" 25651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: call void @llvm.stackrestore(i8* %[[base]]) 269b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: ret void 279b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// 289b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// There should be one dtor call for unwinding from the second getA. 299b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" 30651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-NOT: @"\01??1A@@QAE@XZ" 31651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: call void @llvm.stackrestore 329b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: } 339b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner 349b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknervoid TakeRef(const A &a); 359b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerint HasDeactivatedCleanups() { 369b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())); 379b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner} 389b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner 39651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-LABEL: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} { 409b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: %[[isactive:.*]] = alloca i1 41651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: call i8* @llvm.stacksave() 42651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: %[[argmem:.*]] = alloca inalloca [[argmem_ty:<{ %struct.A, %struct.A }>]] 43651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: %[[arg1:.*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 1 44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" 459b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" 46651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// 47651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]]) 489b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 true, i1* %[[isactive]] 49651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// 50651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: %[[arg0:.*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 0 519b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" 529b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" 539b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" 549b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 false, i1* %[[isactive]] 55651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// 56651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* inalloca %[[argmem]]) 57651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: call void @llvm.stackrestore 589b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// Destroy the two const ref temporaries. 599b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" 60651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" 619b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: ret i32 629b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// 639b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// Conditionally destroy arg1. 649b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: %[[cond:.*]] = load i1* %[[isactive]] 659b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: br i1 %[[cond]] 669b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]]) 679b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: } 689b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner 699b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// Test putting the cleanups inside a conditional. 709b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerint CouldThrow(); 719b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerint HasConditionalCleanup(bool cond) { 729b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner return (cond ? TakesTwo(A(), A()) : CouldThrow()); 739b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner} 749b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner 75651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-LABEL: define i32 @"\01?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} { 769b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 false 779b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: br i1 78651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: call i8* @llvm.stacksave() 79651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}}) 809b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 true 819b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}}) 82651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" 83651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: call void @llvm.stackrestore 84651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// 859b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: call i32 @"\01?CouldThrow@@YAHXZ"() 86651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// 87651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// Only one dtor in the invoke for arg1 88651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) 89651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" 90651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: call void @llvm.stackrestore 919b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: } 929b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner 939b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// Now test both. 949b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerint HasConditionalDeactivatedCleanups(bool cond) { 959b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow()); 969b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner} 979b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner 98651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { 999b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: alloca i1 1009b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: %[[arg1_cond:.*]] = alloca i1 1019b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// Start all four cleanups as deactivated. 1029b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 false 1039b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 false 1049b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 false 1059b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 false 1069b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: br i1 1079b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// True condition. 108651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" 1099b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 true 1109b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" 111651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" 1129b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 true, i1* %[[arg1_cond]] 1139b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" 1149b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 true 1159b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" 1169b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" 1179b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 true 1189b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: store i1 false, i1* %[[arg1_cond]] 1199b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" 1209b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// False condition. 1219b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"() 1229b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// Two normal cleanups for TakeRef args. 1239b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" 124651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" 1259b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: ret i32 1269b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// 1279b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// Somewhere in the landing pad soup, we conditionally destroy arg1. 1289b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: %[[isactive:.*]] = load i1* %[[arg1_cond]] 1299b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: br i1 %[[isactive]] 130651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" 1319b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: } 132a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov 133a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanovnamespace crash_on_partial_destroy { 134a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanovstruct A { 135a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov virtual ~A(); 136a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov}; 137a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov 138a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanovstruct B : virtual A { 139a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov // Has an implicit destructor. 140a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov}; 141a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov 142a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanovstruct C : B { 143a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov C(); 144a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov}; 145a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov 146a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanovvoid foo(); 147a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// We used to crash when emitting this. 148a7c8b10c35671a19f01241c1d8aff07260597dbfTimur IskhodzhanovC::C() { foo(); } 149a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov 150a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// Verify that we don't bother with a vbtable lookup when adjusting the this 151a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// pointer to call a base destructor from a constructor while unwinding. 152a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-LABEL: define {{.*}} @"\01??0C@crash_on_partial_destroy@@QAE@XZ"{{.*}} { 153a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32: landingpad 154a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// 155a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// We shouldn't do any vbptr loads, just constant GEPs. 156a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-NOT: load 1576d87e65b8fd01b36c7d3dd121462cb95f94404d6Timur Iskhodzhanov// WIN32: getelementptr i8* %{{.*}}, i32 4 158a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-NOT: load 159a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::B"* 160a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32: invoke x86_thiscallcc void @"\01??1B@crash_on_partial_destroy@@UAE@XZ" 161a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// 162a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-NOT: load 163a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32: bitcast %"struct.crash_on_partial_destroy::C"* %{{.*}} to i8* 164a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-NOT: load 165a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32: getelementptr inbounds i8* %{{.*}}, i64 4 166a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-NOT: load 167a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::A"* 168a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32: invoke x86_thiscallcc void @"\01??1A@crash_on_partial_destroy@@UAE@XZ" 169a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32: } 170a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov} 171