xref: /llvm-project/clang/test/CodeGenCXX/partial-destruction.cpp (revision 94473f4db6a6f5f12d7c4081455b5b596094eac5)
1 // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions -std=c++03 | FileCheck %s -check-prefixes=CHECK,CHECKv03
2 // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions -std=c++11 | FileCheck %s -check-prefixes=CHECK,CHECKv11
3 
4 // Test IR generation for partial destruction of aggregates.
5 
6 void opaque();
7 
8 // Initializer lists.
9 namespace test0 {
10   struct A { A(int); A(); ~A(); void *v; };
11   void test() {
12     A as[10] = { 5, 7 };
13     opaque();
14   }
15   // CHECK-LABEL:    define{{.*}} void @_ZN5test04testEv()
16   // CHECK-SAME: personality ptr @__gxx_personality_v0
17   // CHECK:      [[AS:%.*]] = alloca [10 x [[A:%.*]]], align
18   // CHECK-NEXT: [[ENDVAR:%.*]] = alloca ptr
19   // CHECK-NEXT: [[EXN:%.*]] = alloca ptr
20   // CHECK-NEXT: [[SEL:%.*]] = alloca i32
21 
22   // Initialize.
23   // CHECK-NEXT: store ptr [[AS]], ptr [[ENDVAR]]
24   // CHECK-NEXT: invoke void @_ZN5test01AC1Ei(ptr {{[^,]*}} [[AS]], i32 noundef 5)
25   // CHECK:      [[E1:%.*]] = getelementptr inbounds [[A]], ptr [[AS]], i64 1
26   // CHECK-NEXT: store ptr [[E1]], ptr [[ENDVAR]]
27   // CHECK-NEXT: invoke void @_ZN5test01AC1Ei(ptr {{[^,]*}} [[E1]], i32 noundef 7)
28   // CHECK:      [[E2:%.*]] = getelementptr inbounds [[A]], ptr [[AS]], i64 2
29   // CHECK-NEXT: store ptr [[E2]], ptr [[ENDVAR]]
30   // CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]], ptr [[AS]], i64 10
31   // CHECK-NEXT: br label
32   // CHECK:      [[E_CUR:%.*]] = phi ptr [ [[E2]], {{%.*}} ], [ [[E_NEXT:%.*]], {{%.*}} ]
33   // CHECK-NEXT: invoke void @_ZN5test01AC1Ev(ptr {{[^,]*}} [[E_CUR]])
34   // CHECK:      [[E_NEXT]] = getelementptr inbounds [[A]], ptr [[E_CUR]], i64 1
35   // CHECK-NEXT: store ptr [[E_NEXT]], ptr [[ENDVAR]]
36   // CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[E_NEXT]], [[E_END]]
37   // CHECK-NEXT: br i1 [[T0]],
38 
39   // Run.
40   // CHECK:      invoke void @_Z6opaquev()
41 
42   // Normal destroy.
43   // CHECK:      [[ED_BEGIN:%.*]] = getelementptr inbounds [10 x [[A]]], ptr [[AS]], i32 0, i32 0
44   // CHECK-NEXT: [[ED_END:%.*]] = getelementptr inbounds [[A]], ptr [[ED_BEGIN]], i64 10
45   // CHECK-NEXT: br label
46   // CHECK:      [[ED_AFTER:%.*]] = phi ptr [ [[ED_END]], {{%.*}} ], [ [[ED_CUR:%.*]], {{%.*}} ]
47   // CHECK-NEXT: [[ED_CUR]] = getelementptr inbounds [[A]], ptr [[ED_AFTER]], i64 -1
48   // CHECKv03-NEXT: invoke void @_ZN5test01AD1Ev(ptr {{[^,]*}} [[ED_CUR]])
49   // CHECKv11-NEXT: call   void @_ZN5test01AD1Ev(ptr {{[^,]*}} [[ED_CUR]])
50   // CHECK:      [[T0:%.*]] = icmp eq ptr [[ED_CUR]], [[ED_BEGIN]]
51   // CHECK-NEXT: br i1 [[T0]],
52   // CHECK:      ret void
53 
54   // Partial destroy for initialization.
55   // CHECK:      landingpad { ptr, i32 }
56   // CHECK-NEXT:   cleanup
57   // CHECK:      [[PARTIAL_END:%.*]] = load ptr, ptr [[ENDVAR]]
58   // CHECK-NEXT: [[T0:%.*]] = icmp eq ptr [[AS]], [[PARTIAL_END]]
59   // CHECK-NEXT: br i1 [[T0]],
60   // CHECK:      [[E_AFTER:%.*]] = phi ptr [ [[PARTIAL_END]], {{%.*}} ], [ [[E_CUR:%.*]], {{%.*}} ]
61   // CHECK-NEXT: [[E_CUR]] = getelementptr inbounds [[A]], ptr [[E_AFTER]], i64 -1
62   // CHECKv03-NEXT: invoke void @_ZN5test01AD1Ev(ptr {{[^,]*}} [[E_CUR]])
63   // CHECKv11-NEXT: call   void @_ZN5test01AD1Ev(ptr {{[^,]*}} [[E_CUR]])
64   // CHECK:      [[T0:%.*]] = icmp eq ptr [[E_CUR]], [[AS]]
65   // CHECK-NEXT: br i1 [[T0]],
66 
67   // Primary EH destructor.
68   // CHECK:      landingpad { ptr, i32 }
69   // CHECK-NEXT:   cleanup
70   // CHECK:      [[E0:%.*]] = getelementptr inbounds [10 x [[A]]], ptr [[AS]], i32 0, i32 0
71   // CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]], ptr [[E0]], i64 10
72   // CHECK-NEXT: br label
73 
74   // Partial destructor for primary normal destructor.
75   // FIXME: There's some really bad block ordering here which causes
76   // the partial destroy for the primary normal destructor to fall
77   // within the primary EH destructor.
78   // CHECKv03:      landingpad { ptr, i32 }
79   // CHECKv03-NEXT:   cleanup
80   // CHECKv03:      [[T0:%.*]] = icmp eq ptr [[ED_BEGIN]], [[ED_CUR]]
81   // CHECKv03-NEXT: br i1 [[T0]]
82   // CHECKv03:      [[EDD_AFTER:%.*]] = phi ptr [ [[ED_CUR]], {{%.*}} ], [ [[EDD_CUR:%.*]], {{%.*}} ]
83   // CHECKv03-NEXT: [[EDD_CUR]] = getelementptr inbounds [[A]], ptr [[EDD_AFTER]], i64 -1
84   // CHECKv03-NEXT: invoke void @_ZN5test01AD1Ev(ptr {{[^,]*}} [[EDD_CUR]])
85   // CHECKv03:      [[T0:%.*]] = icmp eq ptr [[EDD_CUR]], [[ED_BEGIN]]
86   // CHECKv03-NEXT: br i1 [[T0]]
87 
88   // Back to the primary EH destructor.
89   // CHECK:      [[E_AFTER:%.*]] = phi ptr [ [[E_END]], {{%.*}} ], [ [[E_CUR:%.*]], {{%.*}} ]
90   // CHECK-NEXT: [[E_CUR]] = getelementptr inbounds [[A]], ptr [[E_AFTER]], i64 -1
91   // CHECKv03-NEXT: invoke void @_ZN5test01AD1Ev(ptr {{[^,]*}} [[E_CUR]])
92   // CHECKv11-NEXT: call   void @_ZN5test01AD1Ev(ptr {{[^,]*}} [[E_CUR]])
93   // CHECK:      [[T0:%.*]] = icmp eq ptr [[E_CUR]], [[E0]]
94   // CHECK-NEXT: br i1 [[T0]],
95 
96 }
97 
98 namespace test1 {
99   struct A { A(); A(int); ~A(); };
100   struct B { A x, y, z; int w; };
101 
102   void test() {
103     B v = { 5, 6, 7, 8 };
104   }
105   // CHECK-LABEL:    define{{.*}} void @_ZN5test14testEv()
106   // CHECK-SAME: personality ptr @__gxx_personality_v0
107   // CHECK:      [[V:%.*]] = alloca [[B:%.*]], align 4
108   // CHECK-NEXT: alloca ptr
109   // CHECK-NEXT: alloca i32
110   // CHECK-NEXT: call void @_ZN5test11AC1Ei(ptr {{[^,]*}} [[V]], i32 noundef 5)
111   // CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds i8, ptr [[V]], i64 1
112   // CHECK-NEXT: invoke void @_ZN5test11AC1Ei(ptr {{[^,]*}} [[Y]], i32 noundef 6)
113   // CHECK:      [[Z:%.*]] = getelementptr inbounds i8, ptr [[V]], i64 2
114   // CHECK-NEXT: invoke void @_ZN5test11AC1Ei(ptr {{[^,]*}} [[Z]], i32 noundef 7)
115   // CHECK:      [[W:%.*]] = getelementptr inbounds nuw [[B]], ptr [[V]], i32 0, i32 1
116   // CHECK-NEXT: store i32 8, ptr [[W]], align 4
117   // CHECK-NEXT: call void @_ZN5test11BD1Ev(ptr {{[^,]*}} [[V]])
118   // CHECK-NEXT: ret void
119 
120   // FIXME: again, the block ordering is pretty bad here
121   // CHECK:      landingpad { ptr, i32 }
122   // CHECK-NEXT:   cleanup
123   // CHECK:      landingpad { ptr, i32 }
124   // CHECK-NEXT:   cleanup
125   // CHECKv03:      invoke void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[Y]])
126   // CHECKv03:      invoke void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[V]])
127   // CHECKv11:      call   void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[Y]])
128   // CHECKv11:      call   void @_ZN5test11AD1Ev(ptr {{[^,]*}} [[V]])
129 }
130 
131 namespace test2 {
132   struct A { A(); ~A(); };
133 
134   void test() {
135     A v[4][7];
136 
137     // CHECK-LABEL:    define{{.*}} void @_ZN5test24testEv()
138     // CHECK-SAME: personality ptr @__gxx_personality_v0
139     // CHECK:      [[V:%.*]] = alloca [4 x [7 x [[A:%.*]]]], align 1
140     // CHECK-NEXT: alloca ptr
141     // CHECK-NEXT: alloca i32
142 
143     // Main initialization loop.
144     // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [4 x [7 x [[A]]]], ptr [[V]], i32 0, i32 0, i32 0
145     // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]], ptr [[BEGIN]], i64 28
146     // CHECK-NEXT: br label
147     // CHECK:      [[CUR:%.*]] = phi ptr [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
148     // CHECK-NEXT: invoke void @_ZN5test21AC1Ev(ptr {{[^,]*}} [[CUR]])
149     // CHECK:      [[NEXT:%.*]] = getelementptr inbounds [[A]], ptr [[CUR]], i64 1
150     // CHECK-NEXT: [[DONE:%.*]] = icmp eq ptr [[NEXT]], [[END]]
151     // CHECK-NEXT: br i1 [[DONE]],
152 
153     // Partial destruction landing pad.
154     // CHECK:      landingpad { ptr, i32 }
155     // CHECK-NEXT:   cleanup
156     // CHECK:      [[EMPTY:%.*]] = icmp eq ptr [[BEGIN]], [[CUR]]
157     // CHECK-NEXT: br i1 [[EMPTY]],
158     // CHECK:      [[PAST:%.*]] = phi ptr [ [[CUR]], {{%.*}} ], [ [[DEL:%.*]], {{%.*}} ]
159     // CHECK-NEXT: [[DEL]] = getelementptr inbounds [[A]], ptr [[PAST]], i64 -1
160     // CHECKv03-NEXT: invoke void @_ZN5test21AD1Ev(ptr {{[^,]*}} [[DEL]])
161     // CHECKv11-NEXT: call   void @_ZN5test21AD1Ev(ptr {{[^,]*}} [[DEL]])
162     // CHECK:      [[T0:%.*]] = icmp eq ptr [[DEL]], [[BEGIN]]
163     // CHECK-NEXT: br i1 [[T0]],
164   }
165 
166 }
167 
168 // PR10351
169 namespace test3 {
170   struct A { A(); ~A(); void *p; };
171   struct B {
172     B() {}
173     A a;
174   };
175 
176   B *test() {
177     return new B[10];
178     // invoke void @_ZN5test31BD1Ev(
179   }
180 }
181 
182 namespace test4 {
183   struct A { A(unsigned i); ~A(); };
184   void test() {
185     A v[2][3] = { { A(0), A(1), A(2) }, { A(3), A(4), A(5) } };
186   }
187 }
188 // CHECK-LABEL: define{{.*}} void @_ZN5test44testEv()
189 // CHECK:       [[ARRAY:%.*]] = alloca [2 x [3 x [[A:%.*]]]], align
190 // CHECK:       store ptr [[ARRAY]],
191 // CHECK-NEXT:  store ptr [[ARRAY]],
192 // CHECK-NEXT:  invoke void @_ZN5test41AC1Ej(ptr {{[^,]*}} [[ARRAY]], i32 noundef 0)
193 // CHECK:       [[A01:%.*]] = getelementptr inbounds [[A]], ptr [[ARRAY]], i64 1
194 // CHECK-NEXT:  store ptr [[A01]],
195 // CHECK-NEXT:  invoke void @_ZN5test41AC1Ej(ptr {{[^,]*}} [[A01]], i32 noundef 1)
196 // CHECK:       [[A02:%.*]] = getelementptr inbounds [[A]], ptr [[ARRAY]], i64 2
197 // CHECK-NEXT:  store ptr [[A02]],
198 // CHECK-NEXT:  invoke void @_ZN5test41AC1Ej(ptr {{[^,]*}} [[A02]], i32 noundef 2)
199 // CHECK:       [[A1:%.*]] = getelementptr inbounds [3 x [[A]]], ptr [[ARRAY]], i64 1
200 // CHECK-NEXT:  store ptr [[A1]],
201 // CHECK-NEXT:  store ptr [[A1]],
202 // CHECK-NEXT:  invoke void @_ZN5test41AC1Ej(ptr {{[^,]*}} [[A1]], i32 noundef 3)
203 // CHECK:       [[A11:%.*]] = getelementptr inbounds [[A]], ptr [[A1]], i64 1
204 // CHECK-NEXT:  store ptr [[A11]],
205 // CHECK-NEXT:  invoke void @_ZN5test41AC1Ej(ptr {{[^,]*}} [[A11]], i32 noundef 4)
206 // CHECK:       [[A12:%.*]] = getelementptr inbounds [[A]], ptr [[A1]], i64 2
207 // CHECK-NEXT:  store ptr [[A12]],
208 // CHECK-NEXT:  invoke void @_ZN5test41AC1Ej(ptr {{[^,]*}} [[A12]], i32 noundef 5)
209