Clang Project

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