1 // RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
2 
3 namespace std {
4   typedef decltype(sizeof(int)) size_t;
5 
6   // libc++'s implementation
7   template <class _E>
8   class initializer_list
9   {
10     const _E* __begin_;
11     size_t    __size_;
12 
13     initializer_list(const _E* __b, size_t __s)
14       : __begin_(__b),
15         __size_(__s)
16     {}
17 
18   public:
19     typedef _E        value_type;
20     typedef const _E& reference;
21     typedef const _E& const_reference;
22     typedef size_t    size_type;
23 
24     typedef const _E* iterator;
25     typedef const _E* const_iterator;
26 
27     initializer_list() : __begin_(nullptr), __size_(0) {}
28 
29     size_t    size()  const {return __size_;}
30     const _E* begin() const {return __begin_;}
31     const _E* end()   const {return __begin_ + __size_;}
32   };
33 }
34 
35 void fn1(int i) {
36   // CHECK: define void @_Z3fn1i
37   // temporary array
38   // CHECK: [[array:%[^ ]+]] = alloca [3 x i32]
39   // CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0
40   // CHECK-NEXT: store i32 1, i32*
41   // CHECK-NEXT: getelementptr
42   // CHECK-NEXT: store
43   // CHECK-NEXT: getelementptr
44   // CHECK-NEXT: load
45   // CHECK-NEXT: store
46   // init the list
47   // CHECK-NEXT: getelementptr
48   // CHECK-NEXT: getelementptr inbounds [3 x i32]*
49   // CHECK-NEXT: store i32*
50   // CHECK-NEXT: getelementptr
51   // CHECK-NEXT: store i{{32|64}} 3
52   std::initializer_list<int> intlist{1, 2, i};
53 }
54 
55 struct destroyme1 {
56   ~destroyme1();
57 };
58 struct destroyme2 {
59   ~destroyme2();
60 };
61 struct witharg1 {
62   witharg1(const destroyme1&);
63   ~witharg1();
64 };
65 struct wantslist1 {
66   wantslist1(std::initializer_list<destroyme1>);
67   ~wantslist1();
68 };
69 
70 void fn2() {
71   // CHECK: define void @_Z3fn2v
72   void target(std::initializer_list<destroyme1>);
73   // objects should be destroyed before dm2, after call returns
74   // CHECK: call void @_Z6targetSt16initializer_listI10destroyme1E
75   target({ destroyme1(), destroyme1() });
76   // CHECK: call void @_ZN10destroyme1D1Ev
77   destroyme2 dm2;
78   // CHECK: call void @_ZN10destroyme2D1Ev
79 }
80 
81 void fn3() {
82   // CHECK: define void @_Z3fn3v
83   // objects should be destroyed after dm2
84   auto list = { destroyme1(), destroyme1() };
85   destroyme2 dm2;
86   // CHECK: call void @_ZN10destroyme2D1Ev
87   // CHECK: call void @_ZN10destroyme1D1Ev
88 }
89 
90 void fn4() {
91   // CHECK: define void @_Z3fn4v
92   void target(std::initializer_list<witharg1>);
93   // objects should be destroyed before dm2, after call returns
94   // CHECK: call void @_ZN8witharg1C1ERK10destroyme1
95   // CHECK: call void @_Z6targetSt16initializer_listI8witharg1E
96   target({ witharg1(destroyme1()), witharg1(destroyme1()) });
97   // CHECK: call void @_ZN8witharg1D1Ev
98   // CHECK: call void @_ZN10destroyme1D1Ev
99   destroyme2 dm2;
100   // CHECK: call void @_ZN10destroyme2D1Ev
101 }
102 
103 void fn5() {
104   // CHECK: define void @_Z3fn5v
105   // temps should be destroyed before dm2
106   // objects should be destroyed after dm2
107   // CHECK: call void @_ZN8witharg1C1ERK10destroyme1
108   auto list = { witharg1(destroyme1()), witharg1(destroyme1()) };
109   // CHECK: call void @_ZN10destroyme1D1Ev
110   destroyme2 dm2;
111   // CHECK: call void @_ZN10destroyme2D1Ev
112   // CHECK: call void @_ZN8witharg1D1Ev
113 }
114 
115 void fn6() {
116   // CHECK: define void @_Z3fn6v
117   void target(const wantslist1&);
118   // objects should be destroyed before dm2, after call returns
119   // CHECK: call void @_ZN10wantslist1C1ESt16initializer_listI10destroyme1E
120   // CHECK: call void @_Z6targetRK10wantslist1
121   target({ destroyme1(), destroyme1() });
122   // CHECK: call void @_ZN10wantslist1D1Ev
123   // CHECK: call void @_ZN10destroyme1D1Ev
124   destroyme2 dm2;
125   // CHECK: call void @_ZN10destroyme2D1Ev
126 }
127 
128 void fn7() {
129   // CHECK: define void @_Z3fn7v
130   // temps should be destroyed before dm2
131   // object should be destroyed after dm2
132   // CHECK: call void @_ZN10wantslist1C1ESt16initializer_listI10destroyme1E
133   wantslist1 wl = { destroyme1(), destroyme1() };
134   // CHECK: call void @_ZN10destroyme1D1Ev
135   destroyme2 dm2;
136   // CHECK: call void @_ZN10destroyme2D1Ev
137   // CHECK: call void @_ZN10wantslist1D1Ev
138 }
139 
140 void fn8() {
141   // CHECK: define void @_Z3fn8v
142   void target(std::initializer_list<std::initializer_list<destroyme1>>);
143   // objects should be destroyed before dm2, after call returns
144   // CHECK: call void @_Z6targetSt16initializer_listIS_I10destroyme1EE
145   std::initializer_list<destroyme1> inner;
146   target({ inner, { destroyme1() } });
147   // CHECK: call void @_ZN10destroyme1D1Ev
148   // Only one destroy loop, since only one inner init list is directly inited.
149   // CHECK-NOT: call void @_ZN10destroyme1D1Ev
150   destroyme2 dm2;
151   // CHECK: call void @_ZN10destroyme2D1Ev
152 }
153 
154 void fn9() {
155   // CHECK: define void @_Z3fn9v
156   // objects should be destroyed after dm2
157   std::initializer_list<destroyme1> inner;
158   std::initializer_list<std::initializer_list<destroyme1>> list =
159       { inner, { destroyme1() } };
160   destroyme2 dm2;
161   // CHECK: call void @_ZN10destroyme2D1Ev
162   // CHECK: call void @_ZN10destroyme1D1Ev
163   // Only one destroy loop, since only one inner init list is directly inited.
164   // CHECK-NOT: call void @_ZN10destroyme1D1Ev
165   // CHECK: ret void
166 }
167 
168 struct haslist1 {
169   std::initializer_list<int> il;
170   haslist1();
171 };
172 
173 // CHECK: define void @_ZN8haslist1C2Ev
174 haslist1::haslist1()
175 // CHECK: alloca [3 x i32]
176 // CHECK: store i32 1
177 // CHECK: store i32 2
178 // CHECK: store i32 3
179 // CHECK: store i{{32|64}} 3
180   : il{1, 2, 3}
181 {
182   destroyme2 dm2;
183 }
184 
185 struct haslist2 {
186   std::initializer_list<destroyme1> il;
187   haslist2();
188 };
189 
190 // CHECK: define void @_ZN8haslist2C2Ev
191 haslist2::haslist2()
192   : il{destroyme1(), destroyme1()}
193 {
194   destroyme2 dm2;
195   // CHECK: call void @_ZN10destroyme2D1Ev
196   // CHECK: call void @_ZN10destroyme1D1Ev
197 }
198 
199 void fn10() {
200   // CHECK: define void @_Z4fn10v
201   // CHECK: alloca [3 x i32]
202   // CHECK: call noalias i8* @_Znw{{[jm]}}
203   // CHECK: store i32 1
204   // CHECK: store i32 2
205   // CHECK: store i32 3
206   // CHECK: store i32*
207   // CHECK: store i{{32|64}} 3
208   (void) new std::initializer_list<int> {1, 2, 3};
209 }
210 
211 void fn11() {
212   // CHECK: define void @_Z4fn11v
213   (void) new std::initializer_list<destroyme1> {destroyme1(), destroyme1()};
214   // CHECK: call void @_ZN10destroyme1D1Ev
215   destroyme2 dm2;
216   // CHECK: call void @_ZN10destroyme2D1Ev
217 }
218