1651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fno-rtti | FileCheck -check-prefix WIN32 %s
29b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner
39b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerstruct A {
49b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner  A();
59b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner  ~A();
69b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner  int a;
79b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner};
89b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner
99b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid KlecknerA getA();
109b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner
119b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerint TakesTwo(A a, A b);
129b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknervoid HasEHCleanup() {
139b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner  TakesTwo(getA(), getA());
149b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner}
159b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner
169b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// With exceptions, we need to clean up at least one of these temporaries.
17651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-LABEL: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} {
18651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   %[[base:.*]] = call i8* @llvm.stacksave()
19651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//    If this call throws, we have to restore the stack.
20651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
219b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//    If this call throws, we have to cleanup the first temporary.
229b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})
23651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//    If this call throws, we have to cleanup the stacksave.
24651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"
25651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   call void @llvm.stackrestore(i8* %[[base]])
269b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   ret void
279b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//
289b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//    There should be one dtor call for unwinding from the second getA.
299b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
30651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-NOT: @"\01??1A@@QAE@XZ"
31651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   call void @llvm.stackrestore
329b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: }
339b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner
349b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknervoid TakeRef(const A &a);
359b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerint HasDeactivatedCleanups() {
369b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner  return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A()));
379b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner}
389b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner
39651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-LABEL: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} {
409b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   %[[isactive:.*]] = alloca i1
41651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   call i8* @llvm.stacksave()
42651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   %[[argmem:.*]] = alloca inalloca [[argmem_ty:<{ %struct.A, %struct.A }>]]
43651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   %[[arg1:.*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 1
44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
459b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
46651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
47651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]])
489b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 true, i1* %[[isactive]]
49651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
50651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   %[[arg0:.*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 0
519b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
529b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
539b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
549b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 false, i1* %[[isactive]]
55651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
56651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* inalloca %[[argmem]])
57651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   call void @llvm.stackrestore
589b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//        Destroy the two const ref temporaries.
599b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
60651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
619b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   ret i32
629b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//
639b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//        Conditionally destroy arg1.
649b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   %[[cond:.*]] = load i1* %[[isactive]]
659b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   br i1 %[[cond]]
669b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])
679b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: }
689b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner
699b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// Test putting the cleanups inside a conditional.
709b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerint CouldThrow();
719b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerint HasConditionalCleanup(bool cond) {
729b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner  return (cond ? TakesTwo(A(), A()) : CouldThrow());
739b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner}
749b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner
75651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-LABEL: define i32 @"\01?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} {
769b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 false
779b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   br i1
78651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   call i8* @llvm.stacksave()
79651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}})
809b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 true
819b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}})
82651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"
83651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   call void @llvm.stackrestore
84651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
859b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   call i32 @"\01?CouldThrow@@YAHXZ"()
86651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
87651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//        Only one dtor in the invoke for arg1
88651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})
89651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
90651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   call void @llvm.stackrestore
919b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: }
929b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner
939b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// Now test both.
949b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Klecknerint HasConditionalDeactivatedCleanups(bool cond) {
959b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner  return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow());
969b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner}
979b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner
98651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} {
999b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   alloca i1
1009b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   %[[arg1_cond:.*]] = alloca i1
1019b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//        Start all four cleanups as deactivated.
1029b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 false
1039b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 false
1049b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 false
1059b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 false
1069b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   br i1
1079b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//        True condition.
108651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
1099b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 true
1109b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
111651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
1129b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 true, i1* %[[arg1_cond]]
1139b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
1149b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 true
1159b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
1169b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"
1179b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 true
1189b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   store i1 false, i1* %[[arg1_cond]]
1199b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"
1209b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//        False condition.
1219b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke i32 @"\01?CouldThrow@@YAHXZ"()
1229b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//        Two normal cleanups for TakeRef args.
1239b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
124651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
1259b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   ret i32
1269b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//
1279b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner//        Somewhere in the landing pad soup, we conditionally destroy arg1.
1289b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   %[[isactive:.*]] = load i1* %[[arg1_cond]]
1299b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32:   br i1 %[[isactive]]
130651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// WIN32:   invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"
1319b60195ad4843c9e2e231673a0dbc0d5c8c6eb2bReid Kleckner// WIN32: }
132a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov
133a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanovnamespace crash_on_partial_destroy {
134a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanovstruct A {
135a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov  virtual ~A();
136a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov};
137a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov
138a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanovstruct B : virtual A {
139a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov  // Has an implicit destructor.
140a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov};
141a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov
142a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanovstruct C : B {
143a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov  C();
144a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov};
145a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov
146a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanovvoid foo();
147a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// We used to crash when emitting this.
148a7c8b10c35671a19f01241c1d8aff07260597dbfTimur IskhodzhanovC::C() { foo(); }
149a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov
150a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// Verify that we don't bother with a vbtable lookup when adjusting the this
151a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// pointer to call a base destructor from a constructor while unwinding.
152a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-LABEL: define {{.*}} @"\01??0C@crash_on_partial_destroy@@QAE@XZ"{{.*}} {
153a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32:      landingpad
154a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov//
155a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov//        We shouldn't do any vbptr loads, just constant GEPs.
156a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-NOT:  load
1576d87e65b8fd01b36c7d3dd121462cb95f94404d6Timur Iskhodzhanov// WIN32:      getelementptr i8* %{{.*}}, i32 4
158a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-NOT:  load
159a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32:      bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::B"*
160a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32:      invoke x86_thiscallcc void @"\01??1B@crash_on_partial_destroy@@UAE@XZ"
161a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov//
162a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-NOT:  load
163a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32:      bitcast %"struct.crash_on_partial_destroy::C"* %{{.*}} to i8*
164a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-NOT:  load
165a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32:      getelementptr inbounds i8* %{{.*}}, i64 4
166a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32-NOT:  load
167a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32:      bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::A"*
168a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32:      invoke x86_thiscallcc void @"\01??1A@crash_on_partial_destroy@@UAE@XZ"
169a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov// WIN32: }
170a7c8b10c35671a19f01241c1d8aff07260597dbfTimur Iskhodzhanov}
171