354 lines · cpp
1// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 -check-prefix WIN32-O0 %s2// RUN: %clang_cc1 -std=c++11 -emit-llvm -O3 -disable-llvm-passes %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 -check-prefix WIN32-O3 -check-prefix WIN32-LIFETIME %s3 4struct A {5 A();6 ~A();7 int a;8};9 10A getA();11 12int TakesTwo(A a, A b);13void HasEHCleanup() {14 TakesTwo(getA(), getA());15}16 17// With exceptions, we need to clean up at least one of these temporaries.18// WIN32-LABEL: define dso_local void @"?HasEHCleanup@@YAXXZ"() {{.*}} {19// WIN32: %[[base:.*]] = call ptr @llvm.stacksave.p0()20// If this call throws, we have to restore the stack.21// WIN32: call void @"?getA@@YA?AUA@@XZ"(ptr dead_on_unwind writable sret(%struct.A) align 4 %{{.*}})22// If this call throws, we have to cleanup the first temporary.23// WIN32: invoke void @"?getA@@YA?AUA@@XZ"(ptr dead_on_unwind writable sret(%struct.A) align 4 %{{.*}})24// If this call throws, we have to cleanup the stacksave.25// WIN32: call noundef i32 @"?TakesTwo@@YAHUA@@0@Z"26// WIN32: call void @llvm.stackrestore27// WIN32: ret void28//29// There should be one dtor call for unwinding from the second getA.30// WIN32: cleanuppad31// WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}})32// WIN32-NOT: @"??1A@@QAE@XZ"33// WIN32: }34 35 36// This test verifies the fix for a crash that occurred after37// fa87fa97fb79.38void HasEHCleanupNoexcept() noexcept {39 TakesTwo(getA(), getA());40}41 42// With exceptions, we need to clean up at least one of these temporaries.43// WIN32-LABEL: define dso_local void @"?HasEHCleanupNoexcept@@YAXXZ"() {{.*}} {44// WIN32: %[[base:.*]] = call ptr @llvm.stacksave.p0()45// WIN32: invoke void @"?getA@@YA?AUA@@XZ"(ptr dead_on_unwind writable sret(%struct.A) align 4 %{{.*}})46// WIN32: invoke void @"?getA@@YA?AUA@@XZ"(ptr dead_on_unwind writable sret(%struct.A) align 4 %{{.*}})47// WIN32: invoke noundef i32 @"?TakesTwo@@YAHUA@@0@Z"48// WIN32: call void @llvm.stackrestore49// WIN32: ret void50//51// Since all the calls terminate, there should be no dtors on the unwind52// WIN32: cleanuppad53// WIN32-NOT: @"??1A@@QAE@XZ"54// WIN32: }55 56 57void TakeRef(const A &a);58int HasDeactivatedCleanups() {59 return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A()));60}61 62// WIN32-LABEL: define dso_local noundef i32 @"?HasDeactivatedCleanups@@YAHXZ"() {{.*}} {63// WIN32: %[[isactive:.*]] = alloca i164// WIN32: call ptr @llvm.stacksave.p0()65// WIN32: %[[argmem:.*]] = alloca inalloca [[argmem_ty:<{ %struct.A, %struct.A }>]]66// WIN32: %[[arg1:.*]] = getelementptr inbounds nuw [[argmem_ty]], ptr %[[argmem]], i32 0, i32 167// WIN32: call x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"68// WIN32: invoke void @"?TakeRef@@YAXABUA@@@Z"69//70// WIN32: invoke x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"(ptr {{[^,]*}} %[[arg1]])71// WIN32: store i1 true, ptr %[[isactive]]72//73// WIN32: %[[arg0:.*]] = getelementptr inbounds nuw [[argmem_ty]], ptr %[[argmem]], i32 0, i32 074// WIN32: invoke x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"75// WIN32: invoke void @"?TakeRef@@YAXABUA@@@Z"76// WIN32: invoke x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"77// WIN32: store i1 false, ptr %[[isactive]]78//79// WIN32: invoke noundef i32 @"?TakesTwo@@YAHUA@@0@Z"(ptr inalloca([[argmem_ty]]) %[[argmem]])80// Destroy the two const ref temporaries.81// WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}})82// WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}})83// WIN32: ret i3284//85// Conditionally destroy arg1.86// WIN32: %[[cond:.*]] = load i1, ptr %[[isactive]]87// WIN32: br i1 %[[cond]]88// WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"(ptr {{[^,]*}} %[[arg1]])89// WIN32: }90 91// Test putting the cleanups inside a conditional.92int CouldThrow();93int HasConditionalCleanup(bool cond) {94 return (cond ? TakesTwo(A(), A()) : CouldThrow());95}96 97// WIN32-LABEL: define dso_local noundef i32 @"?HasConditionalCleanup@@YAH_N@Z"(i1 noundef zeroext %{{.*}}) {{.*}} {98// WIN32: store i1 false99// WIN32: br i1100// WIN32: call ptr @llvm.stacksave.p0()101// WIN32: call x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})102// WIN32: store i1 true103// WIN32: invoke x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})104// WIN32: call noundef i32 @"?TakesTwo@@YAHUA@@0@Z"105//106// WIN32: call void @llvm.stackrestore107//108// WIN32: call noundef i32 @"?CouldThrow@@YAHXZ"()109//110// Only one dtor in the invoke for arg1111// WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}})112// WIN32-NOT: invoke x86_thiscallcc void @"??1A@@QAE@XZ"113// WIN32: }114 115// Now test both.116int HasConditionalDeactivatedCleanups(bool cond) {117 return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow());118}119 120// WIN32-O0-LABEL: define dso_local noundef i32 @"?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} {121// WIN32-O0: alloca i1122// WIN32-O0: %[[arg1_cond:.*]] = alloca i1123// Start all four cleanups as deactivated.124// WIN32-O0: store i1 false125// WIN32-O0: store i1 false126// WIN32-O0: store i1 false127// WIN32-O0: store i1 false128// WIN32-O0: br i1129// True condition.130// WIN32-O0: call x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"131// WIN32-O0: store i1 true132// WIN32-O0: invoke void @"?TakeRef@@YAXABUA@@@Z"133// WIN32-O0: invoke x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"134// WIN32-O0: store i1 true, ptr %[[arg1_cond]]135// WIN32-O0: invoke x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"136// WIN32-O0: store i1 true137// WIN32-O0: invoke void @"?TakeRef@@YAXABUA@@@Z"138// WIN32-O0: invoke x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"139// WIN32-O0: store i1 true140// WIN32-O0: store i1 false, ptr %[[arg1_cond]]141// WIN32-O0: invoke noundef i32 @"?TakesTwo@@YAHUA@@0@Z"142// False condition.143// WIN32-O0: invoke noundef i32 @"?CouldThrow@@YAHXZ"()144// Two normal cleanups for TakeRef args.145// WIN32-O0: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}})146// WIN32-O0-NOT: invoke x86_thiscallcc void @"??1A@@QAE@XZ"147// WIN32-O0: ret i32148//149// Somewhere in the landing pad soup, we conditionally destroy arg1.150// WIN32-O0: %[[isactive:.*]] = load i1, ptr %[[arg1_cond]]151// WIN32-O0: br i1 %[[isactive]]152// WIN32-O0: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}})153// WIN32-O0: }154 155// WIN32-O3-LABEL: define dso_local noundef i32 @"?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} {156// WIN32-O3: alloca i1157// WIN32-O3: alloca i1158// WIN32-O3: %[[arg1_cond:.*]] = alloca i1159// Start all four cleanups as deactivated.160// WIN32-O3: store i1 false161// WIN32-O3: store i1 false162// WIN32-O3: store i1 false163// WIN32-O3: store i1 false164// WIN32-O3: store i1 false165// WIN32-O3: store i1 false166// WIN32-O3: br i1167// True condition.168// WIN32-O3: call x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"169// WIN32-O3: store i1 true170// WIN32-O3: invoke void @"?TakeRef@@YAXABUA@@@Z"171// WIN32-O3: invoke x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"172// WIN32-O3: store i1 true, ptr %[[arg1_cond]]173// WIN32-O3: invoke x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"174// WIN32-O3: store i1 true175// WIN32-O3: invoke void @"?TakeRef@@YAXABUA@@@Z"176// WIN32-O3: invoke x86_thiscallcc noundef ptr @"??0A@@QAE@XZ"177// WIN32-O3: store i1 true178// WIN32-O3: store i1 false, ptr %[[arg1_cond]]179// WIN32-O3: invoke noundef i32 @"?TakesTwo@@YAHUA@@0@Z"180// False condition.181// WIN32-O3: invoke noundef i32 @"?CouldThrow@@YAHXZ"()182// Two normal cleanups for TakeRef args.183// WIN32-O3: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}})184// WIN32-O3-NOT: invoke x86_thiscallcc void @"??1A@@QAE@XZ"185// WIN32-O3: ret i32186//187// Somewhere in the landing pad soup, we conditionally destroy arg1.188// WIN32-O3: %[[isactive:.*]] = load i1, ptr %[[arg1_cond]]189// WIN32-O3: br i1 %[[isactive]]190// WIN32-O3: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}})191// WIN32-O3: }192 193namespace crash_on_partial_destroy {194struct A {195 virtual ~A();196};197 198struct B : virtual A {199 // Has an implicit destructor.200};201 202struct C : B {203 C();204};205 206void foo();207// We used to crash when emitting this.208C::C() { foo(); }209 210// Verify that we don't bother with a vbtable lookup when adjusting the this211// pointer to call a base destructor from a constructor while unwinding.212// WIN32-LABEL: define dso_local {{.*}} @"??0C@crash_on_partial_destroy@@QAE@XZ"{{.*}} {213// WIN32: cleanuppad214//215// We shouldn't do any vbptr loads, just constant GEPs.216// WIN32-NOT: load217// WIN32: getelementptr i8, ptr %{{.*}}, i32 4218// WIN32-NOT: load219// WIN32: call x86_thiscallcc void @"??1B@crash_on_partial_destroy@@UAE@XZ"220//221// WIN32-NOT: load222// WIN32-NOT: load223// WIN32: getelementptr inbounds i8, ptr %{{.*}}, i32 4224// WIN32-NOT: load225// WIN32: call x86_thiscallcc void @"??1A@crash_on_partial_destroy@@UAE@XZ"({{.*}})226// WIN32: }227}228 229namespace dont_call_terminate {230struct C {231 ~C();232};233void g();234void f() {235 C c;236 g();237}238 239// WIN32-LABEL: define dso_local void @"?f@dont_call_terminate@@YAXXZ"()240// WIN32: invoke void @"?g@dont_call_terminate@@YAXXZ"()241// WIN32-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]242//243// WIN32: [[cont]]244// WIN32: call x86_thiscallcc void @"??1C@dont_call_terminate@@QAE@XZ"({{.*}})245//246// WIN32: [[lpad]]247// WIN32-NEXT: cleanuppad248// WIN32: call x86_thiscallcc void @"??1C@dont_call_terminate@@QAE@XZ"({{.*}})249}250 251namespace noexcept_false_dtor {252struct D {253 ~D() noexcept(false);254};255void f() {256 D d;257 CouldThrow();258}259}260 261// WIN32-LABEL: define dso_local void @"?f@noexcept_false_dtor@@YAXXZ"()262// WIN32: invoke noundef i32 @"?CouldThrow@@YAHXZ"()263// WIN32: call x86_thiscallcc void @"??1D@noexcept_false_dtor@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})264// WIN32: cleanuppad265// WIN32: call x86_thiscallcc void @"??1D@noexcept_false_dtor@@QAE@XZ"(ptr {{[^,]*}} %{{.*}})266// WIN32: cleanupret267 268namespace lifetime_marker {269struct C {270 ~C();271};272void g();273void f() {274 C c;275 g();276}277 278// WIN32-LIFETIME-LABEL: define dso_local void @"?f@lifetime_marker@@YAXXZ"()279// WIN32-LIFETIME: %[[c:.*]] = alloca %"struct.lifetime_marker::C"280// WIN32-LIFETIME: call void @llvm.lifetime.start.p0(ptr %c)281// WIN32-LIFETIME: invoke void @"?g@lifetime_marker@@YAXXZ"()282// WIN32-LIFETIME-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad0:[^ ]*]]283//284// WIN32-LIFETIME: [[cont]]285// WIN32-LIFETIME: call x86_thiscallcc void @"??1C@lifetime_marker@@QAE@XZ"({{.*}})286// WIN32-LIFETIME: call void @llvm.lifetime.end.p0(ptr %[[c]])287//288// WIN32-LIFETIME: [[lpad0]]289// WIN32-LIFETIME-NEXT: cleanuppad290// WIN32-LIFETIME: call x86_thiscallcc void @"??1C@lifetime_marker@@QAE@XZ"({{.*}})291// WIN32-LIFETIME: cleanupret {{.*}} unwind label %[[lpad1:[^ ]*]]292//293// WIN32-LIFETIME: [[lpad1]]294// WIN32-LIFETIME-NEXT: cleanuppad295// WIN32-LIFETIME: call void @llvm.lifetime.end.p0(ptr %[[c]])296}297 298struct class_2 {299 class_2();300 virtual ~class_2();301};302struct class_1 : virtual class_2 {303 class_1(){throw "Unhandled exception";}304 virtual ~class_1() {}305};306struct class_0 : class_1 {307 class_0() ;308 virtual ~class_0() {}309};310 311class_0::class_0() {312 // WIN32: define dso_local x86_thiscallcc noundef ptr @"??0class_0@@QAE@XZ"(ptr {{[^,]*}} returned align 4 dereferenceable(4) %this, i32 noundef %is_most_derived)313 // WIN32: store i32 %is_most_derived, ptr %[[IS_MOST_DERIVED_VAR:.*]], align 4314 // WIN32: %[[IS_MOST_DERIVED_VAL:.*]] = load i32, ptr %[[IS_MOST_DERIVED_VAR]]315 // WIN32: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0316 // WIN32: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]317 // WIN32: [[INIT_VBASES]]318 // WIN32: br label %[[SKIP_VBASES]]319 // WIN32: [[SKIP_VBASES]]320// ehcleanup:321 // WIN32: %[[CLEANUPPAD:.*]] = cleanuppad within none []322 // WIN32-NEXT: getelementptr inbounds i8, ptr %{{.*}}, i{{.*}} {{.}}323 // WIN32-NEXT: %[[SHOULD_CALL_VBASE_DTOR:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0324 // WIN32-NEXT: br i1 %[[SHOULD_CALL_VBASE_DTOR]], label %[[DTOR_VBASE:.*]], label %[[SKIP_VBASE:.*]]325 // WIN32: [[DTOR_VBASE]]326 // WIN32-NEXT: call x86_thiscallcc void @"??1class_2@@UAE@XZ"327 // WIN32: br label %[[SKIP_VBASE]]328 // WIN32: [[SKIP_VBASE]]329}330 331namespace PR37146 {332// Check that IRGen doesn't emit calls to synthesized destructors for333// non-trival C structs.334 335// WIN32: define dso_local void @"?test@PR37146@@YAXXZ"()336// WIN32: call void @llvm.memset.p0.i32(337// WIN32: call i32 @"?getS@PR37146@@YA?AUS@1@XZ"(338// WIN32: call void @"?func@PR37146@@YAXUS@1@0@Z"(339// WIN32-NEXT: ret void340// WIN32-NEXT: {{^}$}}341 342struct S {343 int f;344};345 346void func(S, S);347S getS();348 349void test() {350 func(getS(), S());351}352 353}354