cxx0x-initializer-stdinitializerlist.cpp revision af130fd78267ee9e2395b758a7d827b07ce317a0
1// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s
2
3namespace 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
35void 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
55struct destroyme1 {
56  ~destroyme1();
57};
58struct destroyme2 {
59  ~destroyme2();
60};
61struct witharg1 {
62  witharg1(const destroyme1&);
63  ~witharg1();
64};
65struct wantslist1 {
66  wantslist1(std::initializer_list<destroyme1>);
67  ~wantslist1();
68};
69
70void 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
81void 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
90void 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
103void 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
115void 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
128void 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
140void 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
154void 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