Reid Kleckner | 9b60195 | 2013-06-21 12:45:15 +0000 | [diff] [blame] | 1 | // RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -cxx-abi microsoft -fexceptions | FileCheck -check-prefix WIN32 %s |
| 2 | |
| 3 | struct A { |
| 4 | A(); |
| 5 | ~A(); |
| 6 | int a; |
| 7 | }; |
| 8 | |
| 9 | A getA(); |
| 10 | |
| 11 | int TakesTwo(A a, A b); |
| 12 | void HasEHCleanup() { |
| 13 | TakesTwo(getA(), getA()); |
| 14 | } |
| 15 | |
| 16 | // With exceptions, we need to clean up at least one of these temporaries. |
| 17 | // WIN32: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} { |
| 18 | // First one doesn't have any cleanups, no need for invoke. |
| 19 | // WIN32: call void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) |
| 20 | // If this call throws, we have to cleanup the first temporary. |
| 21 | // WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) |
| 22 | // If this call throws, we already popped our cleanups |
| 23 | // WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z" |
| 24 | // WIN32: ret void |
| 25 | // |
| 26 | // There should be one dtor call for unwinding from the second getA. |
| 27 | // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" |
| 28 | // WIN32: } |
| 29 | |
| 30 | void TakeRef(const A &a); |
| 31 | int HasDeactivatedCleanups() { |
| 32 | return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())); |
| 33 | } |
| 34 | |
| 35 | // WIN32: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} { |
| 36 | // WIN32: %[[isactive:.*]] = alloca i1 |
| 37 | // WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" |
| 38 | // WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" |
| 39 | // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]]) |
| 40 | // WIN32: store i1 true, i1* %[[isactive]] |
| 41 | // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" |
| 42 | // WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" |
| 43 | // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" |
| 44 | // WIN32: store i1 false, i1* %[[isactive]] |
| 45 | // WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" |
| 46 | // Destroy the two const ref temporaries. |
| 47 | // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" |
| 48 | // WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ" |
| 49 | // WIN32: ret i32 |
| 50 | // |
| 51 | // Conditionally destroy arg1. |
| 52 | // WIN32: %[[cond:.*]] = load i1* %[[isactive]] |
| 53 | // WIN32: br i1 %[[cond]] |
| 54 | // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]]) |
| 55 | // WIN32: } |
| 56 | |
| 57 | // Test putting the cleanups inside a conditional. |
| 58 | int CouldThrow(); |
| 59 | int HasConditionalCleanup(bool cond) { |
| 60 | return (cond ? TakesTwo(A(), A()) : CouldThrow()); |
| 61 | } |
| 62 | |
| 63 | // WIN32: define i32 @"\01?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} { |
| 64 | // WIN32: store i1 false |
| 65 | // WIN32: br i1 |
| 66 | // No cleanups, so we call and then activate a cleanup if it succeeds. |
| 67 | // WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]]) |
| 68 | // WIN32: store i1 true |
| 69 | // Now we have a cleanup for the first aggregate, so we invoke. |
| 70 | // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}}) |
| 71 | // Now we have no cleanups because TakeTwo will destruct both args. |
| 72 | // WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z" |
| 73 | // Still no cleanups, so call. |
| 74 | // WIN32: call i32 @"\01?CouldThrow@@YAHXZ"() |
| 75 | // Somewhere in the landing pad for our single invoke, call the dtor. |
| 76 | // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]]) |
| 77 | // WIN32: } |
| 78 | |
| 79 | // Now test both. |
| 80 | int HasConditionalDeactivatedCleanups(bool cond) { |
| 81 | return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow()); |
| 82 | } |
| 83 | |
| 84 | // WIN32: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { |
| 85 | // WIN32: %[[arg1:.*]] = alloca %struct.A, align 4 |
| 86 | // WIN32: alloca i1 |
| 87 | // WIN32: %[[arg1_cond:.*]] = alloca i1 |
| 88 | // Start all four cleanups as deactivated. |
| 89 | // WIN32: store i1 false |
| 90 | // WIN32: store i1 false |
| 91 | // WIN32: store i1 false |
| 92 | // WIN32: store i1 false |
| 93 | // WIN32: br i1 |
| 94 | // True condition. |
| 95 | // WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" |
| 96 | // WIN32: store i1 true |
| 97 | // WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" |
| 98 | // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]]) |
| 99 | // WIN32: store i1 true, i1* %[[arg1_cond]] |
| 100 | // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" |
| 101 | // WIN32: store i1 true |
| 102 | // WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" |
| 103 | // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" |
| 104 | // WIN32: store i1 true |
| 105 | // WIN32: store i1 false, i1* %[[arg1_cond]] |
| 106 | // WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" |
| 107 | // False condition. |
| 108 | // WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"() |
| 109 | // Two normal cleanups for TakeRef args. |
| 110 | // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" |
| 111 | // WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ" |
| 112 | // WIN32: ret i32 |
| 113 | // |
| 114 | // Somewhere in the landing pad soup, we conditionally destroy arg1. |
| 115 | // WIN32: %[[isactive:.*]] = load i1* %[[arg1_cond]] |
| 116 | // WIN32: br i1 %[[isactive]] |
| 117 | // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]]) |
| 118 | // WIN32: } |