xref: /aosp_15_r20/external/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li // 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 %s
2*67e74705SXin Li // RUN: %clang_cc1 -std=c++11 -emit-llvm -O3 -disable-llvm-optzns %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 %s
3*67e74705SXin Li 
4*67e74705SXin Li struct A {
5*67e74705SXin Li   A();
6*67e74705SXin Li   ~A();
7*67e74705SXin Li   int a;
8*67e74705SXin Li };
9*67e74705SXin Li 
10*67e74705SXin Li A getA();
11*67e74705SXin Li 
12*67e74705SXin Li int TakesTwo(A a, A b);
HasEHCleanup()13*67e74705SXin Li void HasEHCleanup() {
14*67e74705SXin Li   TakesTwo(getA(), getA());
15*67e74705SXin Li }
16*67e74705SXin Li 
17*67e74705SXin Li // With exceptions, we need to clean up at least one of these temporaries.
18*67e74705SXin Li // WIN32-LABEL: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} {
19*67e74705SXin Li // WIN32:   %[[base:.*]] = call i8* @llvm.stacksave()
20*67e74705SXin Li //    If this call throws, we have to restore the stack.
21*67e74705SXin Li // WIN32:   call void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
22*67e74705SXin Li //    If this call throws, we have to cleanup the first temporary.
23*67e74705SXin Li // WIN32:   invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
24*67e74705SXin Li //    If this call throws, we have to cleanup the stacksave.
25*67e74705SXin Li // WIN32:   call i32 @"\01?TakesTwo@@YAHUA@@0@Z"
26*67e74705SXin Li // WIN32:   call void @llvm.stackrestore
27*67e74705SXin Li // WIN32:   ret void
28*67e74705SXin Li //
29*67e74705SXin Li //    There should be one dtor call for unwinding from the second getA.
30*67e74705SXin Li // WIN32:   cleanuppad
31*67e74705SXin Li // WIN32:   call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
32*67e74705SXin Li // WIN32-NOT: @"\01??1A@@QAE@XZ"
33*67e74705SXin Li // WIN32: }
34*67e74705SXin Li 
35*67e74705SXin Li void TakeRef(const A &a);
HasDeactivatedCleanups()36*67e74705SXin Li int HasDeactivatedCleanups() {
37*67e74705SXin Li   return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A()));
38*67e74705SXin Li }
39*67e74705SXin Li 
40*67e74705SXin Li // WIN32-LABEL: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} {
41*67e74705SXin Li // WIN32:   %[[isactive:.*]] = alloca i1
42*67e74705SXin Li // WIN32:   call i8* @llvm.stacksave()
43*67e74705SXin Li // WIN32:   %[[argmem:.*]] = alloca inalloca [[argmem_ty:<{ %struct.A, %struct.A }>]]
44*67e74705SXin Li // WIN32:   %[[arg1:.*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 1
45*67e74705SXin Li // WIN32:   call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
46*67e74705SXin Li // WIN32:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
47*67e74705SXin Li //
48*67e74705SXin Li // WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]])
49*67e74705SXin Li // WIN32:   store i1 true, i1* %[[isactive]]
50*67e74705SXin Li //
51*67e74705SXin Li // WIN32:   %[[arg0:.*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 0
52*67e74705SXin Li // WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
53*67e74705SXin Li // WIN32:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
54*67e74705SXin Li // WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
55*67e74705SXin Li // WIN32:   store i1 false, i1* %[[isactive]]
56*67e74705SXin Li //
57*67e74705SXin Li // WIN32:   invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* inalloca %[[argmem]])
58*67e74705SXin Li //        Destroy the two const ref temporaries.
59*67e74705SXin Li // WIN32:   call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
60*67e74705SXin Li // WIN32:   call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
61*67e74705SXin Li // WIN32:   ret i32
62*67e74705SXin Li //
63*67e74705SXin Li //        Conditionally destroy arg1.
64*67e74705SXin Li // WIN32:   %[[cond:.*]] = load i1, i1* %[[isactive]]
65*67e74705SXin Li // WIN32:   br i1 %[[cond]]
66*67e74705SXin Li // WIN32:   call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
67*67e74705SXin Li // WIN32: }
68*67e74705SXin Li 
69*67e74705SXin Li // Test putting the cleanups inside a conditional.
70*67e74705SXin Li int CouldThrow();
HasConditionalCleanup(bool cond)71*67e74705SXin Li int HasConditionalCleanup(bool cond) {
72*67e74705SXin Li   return (cond ? TakesTwo(A(), A()) : CouldThrow());
73*67e74705SXin Li }
74*67e74705SXin Li 
75*67e74705SXin Li // WIN32-LABEL: define i32 @"\01?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} {
76*67e74705SXin Li // WIN32:   store i1 false
77*67e74705SXin Li // WIN32:   br i1
78*67e74705SXin Li // WIN32:   call i8* @llvm.stacksave()
79*67e74705SXin Li // WIN32:   call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}})
80*67e74705SXin Li // WIN32:   store i1 true
81*67e74705SXin Li // WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}})
82*67e74705SXin Li // WIN32:   call i32 @"\01?TakesTwo@@YAHUA@@0@Z"
83*67e74705SXin Li //
84*67e74705SXin Li // WIN32:   call void @llvm.stackrestore
85*67e74705SXin Li //
86*67e74705SXin Li // WIN32:   call i32 @"\01?CouldThrow@@YAHXZ"()
87*67e74705SXin Li //
88*67e74705SXin Li //        Only one dtor in the invoke for arg1
89*67e74705SXin Li // WIN32:   call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
90*67e74705SXin Li // WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
91*67e74705SXin Li // WIN32: }
92*67e74705SXin Li 
93*67e74705SXin Li // Now test both.
HasConditionalDeactivatedCleanups(bool cond)94*67e74705SXin Li int HasConditionalDeactivatedCleanups(bool cond) {
95*67e74705SXin Li   return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow());
96*67e74705SXin Li }
97*67e74705SXin Li 
98*67e74705SXin Li // WIN32-O0-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} {
99*67e74705SXin Li // WIN32-O0:   alloca i1
100*67e74705SXin Li // WIN32-O0:   %[[arg1_cond:.*]] = alloca i1
101*67e74705SXin Li //        Start all four cleanups as deactivated.
102*67e74705SXin Li // WIN32-O0:   store i1 false
103*67e74705SXin Li // WIN32-O0:   store i1 false
104*67e74705SXin Li // WIN32-O0:   store i1 false
105*67e74705SXin Li // WIN32-O0:   store i1 false
106*67e74705SXin Li // WIN32-O0:   br i1
107*67e74705SXin Li //        True condition.
108*67e74705SXin Li // WIN32-O0:   call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
109*67e74705SXin Li // WIN32-O0:   store i1 true
110*67e74705SXin Li // WIN32-O0:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
111*67e74705SXin Li // WIN32-O0:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
112*67e74705SXin Li // WIN32-O0:   store i1 true, i1* %[[arg1_cond]]
113*67e74705SXin Li // WIN32-O0:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
114*67e74705SXin Li // WIN32-O0:   store i1 true
115*67e74705SXin Li // WIN32-O0:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
116*67e74705SXin Li // WIN32-O0:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
117*67e74705SXin Li // WIN32-O0:   store i1 true
118*67e74705SXin Li // WIN32-O0:   store i1 false, i1* %[[arg1_cond]]
119*67e74705SXin Li // WIN32-O0:   invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"
120*67e74705SXin Li //        False condition.
121*67e74705SXin Li // WIN32-O0:   invoke i32 @"\01?CouldThrow@@YAHXZ"()
122*67e74705SXin Li //        Two normal cleanups for TakeRef args.
123*67e74705SXin Li // WIN32-O0:   call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
124*67e74705SXin Li // WIN32-O0-NOT:   invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
125*67e74705SXin Li // WIN32-O0:   ret i32
126*67e74705SXin Li //
127*67e74705SXin Li //        Somewhere in the landing pad soup, we conditionally destroy arg1.
128*67e74705SXin Li // WIN32-O0:   %[[isactive:.*]] = load i1, i1* %[[arg1_cond]]
129*67e74705SXin Li // WIN32-O0:   br i1 %[[isactive]]
130*67e74705SXin Li // WIN32-O0:   call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
131*67e74705SXin Li // WIN32-O0: }
132*67e74705SXin Li 
133*67e74705SXin Li // WIN32-O3-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} {
134*67e74705SXin Li // WIN32-O3:   alloca i1
135*67e74705SXin Li // WIN32-O3:   alloca i1
136*67e74705SXin Li // WIN32-O3:   %[[arg1_cond:.*]] = alloca i1
137*67e74705SXin Li //        Start all four cleanups as deactivated.
138*67e74705SXin Li // WIN32-O3:   store i1 false
139*67e74705SXin Li // WIN32-O3:   store i1 false
140*67e74705SXin Li // WIN32-O3:   store i1 false
141*67e74705SXin Li // WIN32-O3:   store i1 false
142*67e74705SXin Li // WIN32-O3:   store i1 false
143*67e74705SXin Li // WIN32-O3:   store i1 false
144*67e74705SXin Li // WIN32-O3:   br i1
145*67e74705SXin Li //        True condition.
146*67e74705SXin Li // WIN32-O3:   call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
147*67e74705SXin Li // WIN32-O3:   store i1 true
148*67e74705SXin Li // WIN32-O3:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
149*67e74705SXin Li // WIN32-O3:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
150*67e74705SXin Li // WIN32-O3:   store i1 true, i1* %[[arg1_cond]]
151*67e74705SXin Li // WIN32-O3:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
152*67e74705SXin Li // WIN32-O3:   store i1 true
153*67e74705SXin Li // WIN32-O3:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
154*67e74705SXin Li // WIN32-O3:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
155*67e74705SXin Li // WIN32-O3:   store i1 true
156*67e74705SXin Li // WIN32-O3:   store i1 false, i1* %[[arg1_cond]]
157*67e74705SXin Li // WIN32-O3:   invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"
158*67e74705SXin Li //        False condition.
159*67e74705SXin Li // WIN32-O3:   invoke i32 @"\01?CouldThrow@@YAHXZ"()
160*67e74705SXin Li //        Two normal cleanups for TakeRef args.
161*67e74705SXin Li // WIN32-O3:   call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
162*67e74705SXin Li // WIN32-O3-NOT:   invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
163*67e74705SXin Li // WIN32-O3:   ret i32
164*67e74705SXin Li //
165*67e74705SXin Li //        Somewhere in the landing pad soup, we conditionally destroy arg1.
166*67e74705SXin Li // WIN32-O3:   %[[isactive:.*]] = load i1, i1* %[[arg1_cond]]
167*67e74705SXin Li // WIN32-O3:   br i1 %[[isactive]]
168*67e74705SXin Li // WIN32-O3:   call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
169*67e74705SXin Li // WIN32-O3: }
170*67e74705SXin Li 
171*67e74705SXin Li namespace crash_on_partial_destroy {
172*67e74705SXin Li struct A {
173*67e74705SXin Li   virtual ~A();
174*67e74705SXin Li };
175*67e74705SXin Li 
176*67e74705SXin Li struct B : virtual A {
177*67e74705SXin Li   // Has an implicit destructor.
178*67e74705SXin Li };
179*67e74705SXin Li 
180*67e74705SXin Li struct C : B {
181*67e74705SXin Li   C();
182*67e74705SXin Li };
183*67e74705SXin Li 
184*67e74705SXin Li void foo();
185*67e74705SXin Li // We used to crash when emitting this.
C()186*67e74705SXin Li C::C() { foo(); }
187*67e74705SXin Li 
188*67e74705SXin Li // Verify that we don't bother with a vbtable lookup when adjusting the this
189*67e74705SXin Li // pointer to call a base destructor from a constructor while unwinding.
190*67e74705SXin Li // WIN32-LABEL: define {{.*}} @"\01??0C@crash_on_partial_destroy@@QAE@XZ"{{.*}} {
191*67e74705SXin Li // WIN32:      cleanuppad
192*67e74705SXin Li //
193*67e74705SXin Li //        We shouldn't do any vbptr loads, just constant GEPs.
194*67e74705SXin Li // WIN32-NOT:  load
195*67e74705SXin Li // WIN32:      getelementptr i8, i8* %{{.*}}, i32 4
196*67e74705SXin Li // WIN32-NOT:  load
197*67e74705SXin Li // WIN32:      bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::B"*
198*67e74705SXin Li // WIN32:      call x86_thiscallcc void @"\01??1B@crash_on_partial_destroy@@UAE@XZ"
199*67e74705SXin Li //
200*67e74705SXin Li // WIN32-NOT:  load
201*67e74705SXin Li // WIN32:      bitcast %"struct.crash_on_partial_destroy::C"* %{{.*}} to i8*
202*67e74705SXin Li // WIN32-NOT:  load
203*67e74705SXin Li // WIN32:      getelementptr inbounds i8, i8* %{{.*}}, i32 4
204*67e74705SXin Li // WIN32-NOT:  load
205*67e74705SXin Li // WIN32:      bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::A"*
206*67e74705SXin Li // WIN32:      call x86_thiscallcc void @"\01??1A@crash_on_partial_destroy@@UAE@XZ"({{.*}})
207*67e74705SXin Li // WIN32: }
208*67e74705SXin Li }
209*67e74705SXin Li 
210*67e74705SXin Li namespace dont_call_terminate {
211*67e74705SXin Li struct C {
212*67e74705SXin Li   ~C();
213*67e74705SXin Li };
214*67e74705SXin Li void g();
f()215*67e74705SXin Li void f() {
216*67e74705SXin Li   C c;
217*67e74705SXin Li   g();
218*67e74705SXin Li }
219*67e74705SXin Li 
220*67e74705SXin Li // WIN32-LABEL: define void @"\01?f@dont_call_terminate@@YAXXZ"()
221*67e74705SXin Li // WIN32: invoke void @"\01?g@dont_call_terminate@@YAXXZ"()
222*67e74705SXin Li // WIN32-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
223*67e74705SXin Li //
224*67e74705SXin Li // WIN32: [[cont]]
225*67e74705SXin Li // WIN32: call x86_thiscallcc void @"\01??1C@dont_call_terminate@@QAE@XZ"({{.*}})
226*67e74705SXin Li //
227*67e74705SXin Li // WIN32: [[lpad]]
228*67e74705SXin Li // WIN32-NEXT: cleanuppad
229*67e74705SXin Li // WIN32: call x86_thiscallcc void @"\01??1C@dont_call_terminate@@QAE@XZ"({{.*}})
230*67e74705SXin Li }
231*67e74705SXin Li 
232*67e74705SXin Li namespace noexcept_false_dtor {
233*67e74705SXin Li struct D {
234*67e74705SXin Li   ~D() noexcept(false);
235*67e74705SXin Li };
f()236*67e74705SXin Li void f() {
237*67e74705SXin Li   D d;
238*67e74705SXin Li   CouldThrow();
239*67e74705SXin Li }
240*67e74705SXin Li }
241*67e74705SXin Li 
242*67e74705SXin Li // WIN32-LABEL: define void @"\01?f@noexcept_false_dtor@@YAXXZ"()
243*67e74705SXin Li // WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"()
244*67e74705SXin Li // WIN32: call x86_thiscallcc void @"\01??1D@noexcept_false_dtor@@QAE@XZ"(%"struct.noexcept_false_dtor::D"* %{{.*}})
245*67e74705SXin Li // WIN32: cleanuppad
246*67e74705SXin Li // WIN32: call x86_thiscallcc void @"\01??1D@noexcept_false_dtor@@QAE@XZ"(%"struct.noexcept_false_dtor::D"* %{{.*}})
247*67e74705SXin Li // WIN32: cleanupret
248*67e74705SXin Li 
249*67e74705SXin Li namespace lifetime_marker {
250*67e74705SXin Li struct C {
251*67e74705SXin Li   ~C();
252*67e74705SXin Li };
253*67e74705SXin Li void g();
f()254*67e74705SXin Li void f() {
255*67e74705SXin Li   C c;
256*67e74705SXin Li   g();
257*67e74705SXin Li }
258*67e74705SXin Li 
259*67e74705SXin Li // WIN32-LIFETIME-LABEL: define void @"\01?f@lifetime_marker@@YAXXZ"()
260*67e74705SXin Li // WIN32-LIFETIME: %[[c:.*]] = alloca %"struct.lifetime_marker::C"
261*67e74705SXin Li // WIN32-LIFETIME: %[[bc0:.*]] = bitcast %"struct.lifetime_marker::C"* %c to i8*
262*67e74705SXin Li // WIN32-LIFETIME: call void @llvm.lifetime.start(i64 1, i8* %[[bc0]])
263*67e74705SXin Li // WIN32-LIFETIME: invoke void @"\01?g@lifetime_marker@@YAXXZ"()
264*67e74705SXin Li // WIN32-LIFETIME-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad0:[^ ]*]]
265*67e74705SXin Li //
266*67e74705SXin Li // WIN32-LIFETIME: [[cont]]
267*67e74705SXin Li // WIN32-LIFETIME: call x86_thiscallcc void @"\01??1C@lifetime_marker@@QAE@XZ"({{.*}})
268*67e74705SXin Li // WIN32-LIFETIME: %[[bc1:.*]] = bitcast %"struct.lifetime_marker::C"* %[[c]] to i8*
269*67e74705SXin Li // WIN32-LIFETIME: call void @llvm.lifetime.end(i64 1, i8* %[[bc1]])
270*67e74705SXin Li //
271*67e74705SXin Li // WIN32-LIFETIME: [[lpad0]]
272*67e74705SXin Li // WIN32-LIFETIME-NEXT: cleanuppad
273*67e74705SXin Li // WIN32-LIFETIME: call x86_thiscallcc void @"\01??1C@lifetime_marker@@QAE@XZ"({{.*}})
274*67e74705SXin Li // WIN32-LIFETIME: cleanupret {{.*}} unwind label %[[lpad1:[^ ]*]]
275*67e74705SXin Li //
276*67e74705SXin Li // WIN32-LIFETIME: [[lpad1]]
277*67e74705SXin Li // WIN32-LIFETIME-NEXT: cleanuppad
278*67e74705SXin Li // WIN32-LIFETIME: %[[bc2:.*]] = bitcast %"struct.lifetime_marker::C"* %[[c]] to i8*
279*67e74705SXin Li // WIN32-LIFETIME: call void @llvm.lifetime.end(i64 1, i8* %[[bc2]])
280*67e74705SXin Li }
281