mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-22 13:05:52 -04:00

Introduce CXXStdInitializerListExpr node, representing the implicit construction of a std::initializer_list<T> object from its underlying array. The AST representation of such an expression goes from an InitListExpr with a flag set, to a CXXStdInitializerListExpr containing a MaterializeTemporaryExpr containing an InitListExpr (possibly wrapped in a CXXBindTemporaryExpr). This more detailed representation has several advantages, the most important of which is that the new MaterializeTemporaryExpr allows us to directly model lifetime extension of the underlying temporary array. Using that, this patch *drastically* simplifies the IR generation of this construct, provides IR generation support for nested global initializer_list objects, fixes several bugs where the destructors for the underlying array would accidentally not get invoked, and provides constant expression evaluation support for std::initializer_list objects. llvm-svn: 183872
86 lines
2.4 KiB
C++
86 lines
2.4 KiB
C++
// RUN: %clang_cc1 -std=c++11 -S -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
|
|
|
namespace std {
|
|
typedef decltype(sizeof(int)) size_t;
|
|
|
|
// libc++'s implementation with __size_ replaced by __end_
|
|
template <class _E>
|
|
class initializer_list
|
|
{
|
|
const _E* __begin_;
|
|
const _E* __end_;
|
|
|
|
initializer_list(const _E* __b, const _E* __e)
|
|
: __begin_(__b),
|
|
__end_(__e)
|
|
{}
|
|
|
|
public:
|
|
typedef _E value_type;
|
|
typedef const _E& reference;
|
|
typedef const _E& const_reference;
|
|
typedef size_t size_type;
|
|
|
|
typedef const _E* iterator;
|
|
typedef const _E* const_iterator;
|
|
|
|
initializer_list() : __begin_(nullptr), __end_(nullptr) {}
|
|
|
|
size_t size() const {return __end_ - __begin_;}
|
|
const _E* begin() const {return __begin_;}
|
|
const _E* end() const {return __end_;}
|
|
};
|
|
}
|
|
|
|
// CHECK: @_ZGR15globalInitList1 = private constant [3 x i32] [i32 1, i32 2, i32 3]
|
|
// CHECK: @globalInitList1 = global {{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZGR15globalInitList1, {{[^)]*}}), i32*
|
|
std::initializer_list<int> globalInitList1 = {1, 2, 3};
|
|
|
|
void fn1(int i) {
|
|
// CHECK: define void @_Z3fn1i
|
|
// temporary array
|
|
// CHECK: [[array:%[^ ]+]] = alloca [3 x i32]
|
|
// CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0
|
|
// CHECK-NEXT: store i32 1, i32*
|
|
// CHECK-NEXT: getelementptr
|
|
// CHECK-NEXT: store
|
|
// CHECK-NEXT: getelementptr
|
|
// CHECK-NEXT: load
|
|
// CHECK-NEXT: store
|
|
// init the list
|
|
// CHECK-NEXT: getelementptr
|
|
// CHECK-NEXT: getelementptr inbounds [3 x i32]*
|
|
// CHECK-NEXT: store i32*
|
|
// CHECK-NEXT: getelementptr
|
|
// CHECK-NEXT: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0, i{{32|64}} 3
|
|
// CHECK-NEXT: store i32*
|
|
std::initializer_list<int> intlist{1, 2, i};
|
|
}
|
|
|
|
struct destroyme1 {
|
|
~destroyme1();
|
|
};
|
|
struct destroyme2 {
|
|
~destroyme2();
|
|
};
|
|
|
|
|
|
void fn2() {
|
|
// CHECK: define void @_Z3fn2v
|
|
void target(std::initializer_list<destroyme1>);
|
|
// objects should be destroyed before dm2, after call returns
|
|
target({ destroyme1(), destroyme1() });
|
|
// CHECK: call void @_ZN10destroyme1D1Ev
|
|
destroyme2 dm2;
|
|
// CHECK: call void @_ZN10destroyme2D1Ev
|
|
}
|
|
|
|
void fn3() {
|
|
// CHECK: define void @_Z3fn3v
|
|
// objects should be destroyed after dm2
|
|
auto list = { destroyme1(), destroyme1() };
|
|
destroyme2 dm2;
|
|
// CHECK: call void @_ZN10destroyme2D1Ev
|
|
// CHECK: call void @_ZN10destroyme1D1Ev
|
|
}
|