1 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -o - -emit-llvm -O1 \
2 // RUN: -fexceptions -fcxx-exceptions -mllvm -simplifycfg-sink-common=false | FileCheck %s
3 //
4 // We should emit lifetime.ends for these temporaries in both the 'exception'
5 // and 'normal' paths in functions.
6 //
7 // -O1 is necessary to make lifetime markers appear.
8
9 struct Large {
10 int cs[32];
11 };
12
13 Large getLarge();
14
15 // Used to ensure we emit invokes.
16 struct NontrivialDtor {
17 int i;
18 ~NontrivialDtor();
19 };
20
21 // CHECK-LABEL: define{{.*}} void @_Z33cleanupsAreEmittedWithoutTryCatchv
cleanupsAreEmittedWithoutTryCatch()22 void cleanupsAreEmittedWithoutTryCatch() {
23 // CHECK: call void @llvm.lifetime.start.p0({{[^,]+}}, ptr nonnull %[[CLEAN:.*]])
24 // CHECK: call void @llvm.lifetime.start.p0({{[^,]+}}, ptr nonnull %[[T1:.*]])
25 // CHECK-NEXT: invoke void @_Z8getLargev
26 // CHECK-NEXT: to label %[[CONT:[^ ]+]] unwind label %[[LPAD:[^ ]+]]
27 //
28 // CHECK: [[CONT]]:
29 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T1]])
30 // CHECK: call void @llvm.lifetime.start.p0({{[^,]+}}, ptr nonnull %[[T2:.*]])
31 // CHECK-NEXT: invoke void @_Z8getLargev
32 // CHECK-NEXT: to label %[[CONT2:[^ ]+]] unwind label %[[LPAD2:.+]]
33 //
34 // CHECK: [[CONT2]]:
35 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T2]])
36 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[CLEAN]])
37 // CHECK: ret void
38 //
39 // CHECK: [[LPAD]]:
40 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T1]])
41 // CHECK: br label %[[EHCLEANUP:.+]]
42 //
43 // CHECK: [[LPAD2]]:
44 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T2]])
45 // CHECK: br label %[[EHCLEANUP]]
46 //
47 // CHECK: [[EHCLEANUP]]:
48 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[CLEAN]])
49
50 NontrivialDtor clean;
51
52 getLarge();
53 getLarge();
54 }
55
56 // CHECK-LABEL: define{{.*}} void @_Z30cleanupsAreEmittedWithTryCatchv
cleanupsAreEmittedWithTryCatch()57 void cleanupsAreEmittedWithTryCatch() {
58 // CHECK: call void @llvm.lifetime.start.p0({{[^,]+}}, ptr nonnull %[[CLEAN:.*]])
59 // CHECK: call void @llvm.lifetime.start.p0({{[^,]+}}, ptr nonnull %[[T1:.*]])
60 // CHECK-NEXT: invoke void @_Z8getLargev
61 // CHECK-NEXT: to label %[[CONT:[^ ]+]] unwind label %[[LPAD:[^ ]+]]
62 //
63 // CHECK: [[CONT]]:
64 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T1]])
65 // CHECK: call void @llvm.lifetime.start.p0({{[^,]+}}, ptr nonnull %[[T2:.*]])
66 // CHECK-NEXT: invoke void @_Z8getLargev
67 // CHECK-NEXT: to label %[[CONT2:[^ ]+]] unwind label %[[LPAD2:.+]]
68 //
69 // CHECK: [[CONT2]]:
70 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T2]])
71 // CHECK: br label %[[TRY_CONT:.+]]
72 //
73 // CHECK: [[LPAD]]:
74 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T1]])
75 // CHECK: br label %[[CATCH:.+]]
76 //
77 // CHECK: [[LPAD2]]:
78 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T2]])
79 // CHECK: br label %[[CATCH]]
80 //
81 // CHECK: [[CATCH]]:
82 // CHECK-NOT: call void @llvm.lifetime
83 // CHECK: invoke void
84 // CHECK-NEXT: to label %[[TRY_CONT]] unwind label %[[OUTER_LPAD:.+]]
85 //
86 // CHECK: [[TRY_CONT]]:
87 // CHECK: call void @llvm.lifetime.start.p0({{[^,]+}}, ptr nonnull %[[T_OUTER:.*]])
88 // CHECK-NEXT: invoke void @_Z8getLargev
89 // CHECK-NEXT: to label %[[OUTER_CONT:[^ ]+]] unwind label %[[OUTER_LPAD2:.+]]
90 //
91 // CHECK: [[OUTER_CONT]]:
92 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T_OUTER]])
93 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[CLEAN]])
94 // CHECK: ret void
95 //
96 // CHECK: [[OUTER_LPAD]]:
97 // CHECK-NOT: call void @llvm.lifetime
98 // CHECK: br label %[[EHCLEANUP:.+]]
99 //
100 // CHECK: [[OUTER_LPAD2]]:
101 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T_OUTER]])
102 // CHECK: br label %[[EHCLEANUP]]
103 //
104 // CHECK: [[EHCLEANUP]]:
105 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[CLEAN]])
106
107 NontrivialDtor clean;
108
109 try {
110 getLarge();
111 getLarge();
112 } catch (...) {}
113
114 getLarge();
115 }
116
117 // CHECK-LABEL: define{{.*}} void @_Z39cleanupInTryHappensBeforeCleanupInCatchv
cleanupInTryHappensBeforeCleanupInCatch()118 void cleanupInTryHappensBeforeCleanupInCatch() {
119 // CHECK: call void @llvm.lifetime.start.p0({{[^,]+}}, ptr nonnull %[[T1:.*]])
120 // CHECK-NEXT: invoke void @_Z8getLargev
121 // CHECK-NEXT: to label %[[CONT:[^ ]+]] unwind label %[[LPAD:[^ ]+]]
122 //
123 // CHECK: [[CONT]]:
124 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T1]])
125 // CHECK: br label %[[TRY_CONT]]
126 //
127 // CHECK: [[LPAD]]:
128 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T1]])
129 // CHECK: br i1 {{[^,]+}}, label %[[CATCH_INT_MATCH:[^,]+]], label %[[CATCH_ALL:.+]]
130 //
131 // CHECK: [[CATCH_INT_MATCH]]:
132 // CHECK: call void @llvm.lifetime.start.p0({{[^,]+}}, ptr nonnull %[[T2:.*]])
133 // CHECK-NEXT: invoke void @_Z8getLargev
134 // CHECK-NEXT: to label %[[CATCH_INT_CONT:[^ ]+]] unwind label %[[CATCH_INT_LPAD:[^ ]+]]
135 //
136 // CHECK: [[CATCH_INT_CONT]]:
137 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T2]])
138 // CHECK: br label %[[TRY_CONT]]
139 //
140 // CHECK: [[TRY_CONT]]:
141 // CHECK: ret void
142 //
143 // CHECK: [[CATCH_ALL]]:
144 // CHECK: call void @llvm.lifetime.start.p0({{[^,]+}}, ptr nonnull %[[T3:.*]])
145 // CHECK-NEXT: invoke void @_Z8getLargev
146 // CHECK-NEXT: to label %[[CATCH_ALL_CONT:[^ ]+]] unwind label %[[CATCH_ALL_LPAD:[^ ]+]]
147 //
148 // CHECK: [[CATCH_ALL_CONT]]:
149 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T3]])
150 // CHECK: br label %[[TRY_CONT]]
151 //
152 // CHECK: [[CATCH_ALL_LPAD]]:
153 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T3]])
154 //
155 // CHECK: [[CATCH_INT_LPAD]]:
156 // CHECK: call void @llvm.lifetime.end.p0({{[^,]+}}, ptr nonnull %[[T2]])
157 // CHECK-NOT: call void @llvm.lifetime
158
159 try {
160 getLarge();
161 } catch (const int &) {
162 getLarge();
163 } catch (...) {
164 getLarge();
165 }
166 }
167
168 // FIXME: We don't currently emit lifetime markers for aggregate by-value
169 // temporaries (e.g. given a function `Large combine(Large, Large);`
170 // combine(getLarge(), getLarge()) "leaks" two `Large`s). We probably should. We
171 // also don't emit markers for things like:
172 //
173 // {
174 // Large L = getLarge();
175 // combine(L, L);
176 // }
177 //
178 // Though this arguably isn't as bad, since we pass a pointer to `L` as one of
179 // the two args.
180