Skip to content

Commit 77b9abf

Browse files
committed
[libc++] Complete overhaul of constexpr support in std::array
This commit adds missing support for constexpr in std::array under all standard modes up to and including C++20. It also transforms the <array> tests to check for constexpr-friendliness under the right standard modes. Fixes https://llvm.org/PR40124 Fixes rdar://57522096 Supersedes https://reviews.llvm.org/D60666 Differential Revision: https://reviews.llvm.org/D80452
1 parent b726d07 commit 77b9abf

38 files changed

+1159
-788
lines changed

libcxx/docs/FeatureTestMacroTable.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ Status
168168
------------------------------------------------- -----------------
169169
**C++ 2a**
170170
-------------------------------------------------------------------
171+
``__cpp_lib_array_constexpr`` ``201811L``
172+
------------------------------------------------- -----------------
171173
``__cpp_lib_atomic_ref`` *unimplemented*
172174
------------------------------------------------- -----------------
173175
``__cpp_lib_bind_front`` *unimplemented*

libcxx/include/array

Lines changed: 89 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -32,71 +32,76 @@ struct array
3232
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
3333
3434
// No explicit construct/copy/destroy for aggregate type
35-
void fill(const T& u);
36-
void swap(array& a) noexcept(is_nothrow_swappable_v<T>);
35+
void fill(const T& u); // constexpr in C++20
36+
void swap(array& a) noexcept(is_nothrow_swappable_v<T>); // constexpr in C++20
3737
3838
// iterators:
39-
iterator begin() noexcept;
40-
const_iterator begin() const noexcept;
41-
iterator end() noexcept;
42-
const_iterator end() const noexcept;
39+
iterator begin() noexcept; // constexpr in C++17
40+
const_iterator begin() const noexcept; // constexpr in C++17
41+
iterator end() noexcept; // constexpr in C++17
42+
const_iterator end() const noexcept; // constexpr in C++17
4343
44-
reverse_iterator rbegin() noexcept;
45-
const_reverse_iterator rbegin() const noexcept;
46-
reverse_iterator rend() noexcept;
47-
const_reverse_iterator rend() const noexcept;
44+
reverse_iterator rbegin() noexcept; // constexpr in C++17
45+
const_reverse_iterator rbegin() const noexcept; // constexpr in C++17
46+
reverse_iterator rend() noexcept; // constexpr in C++17
47+
const_reverse_iterator rend() const noexcept; // constexpr in C++17
4848
49-
const_iterator cbegin() const noexcept;
50-
const_iterator cend() const noexcept;
51-
const_reverse_iterator crbegin() const noexcept;
52-
const_reverse_iterator crend() const noexcept;
49+
const_iterator cbegin() const noexcept; // constexpr in C++17
50+
const_iterator cend() const noexcept; // constexpr in C++17
51+
const_reverse_iterator crbegin() const noexcept; // constexpr in C++17
52+
const_reverse_iterator crend() const noexcept; // constexpr in C++17
5353
5454
// capacity:
5555
constexpr size_type size() const noexcept;
5656
constexpr size_type max_size() const noexcept;
5757
constexpr bool empty() const noexcept;
5858
5959
// element access:
60-
reference operator[](size_type n);
61-
const_reference operator[](size_type n) const; // constexpr in C++14
62-
const_reference at(size_type n) const; // constexpr in C++14
63-
reference at(size_type n);
64-
65-
reference front();
66-
const_reference front() const; // constexpr in C++14
67-
reference back();
68-
const_reference back() const; // constexpr in C++14
69-
70-
T* data() noexcept;
71-
const T* data() const noexcept;
60+
reference operator[](size_type n); // constexpr in C++17
61+
const_reference operator[](size_type n) const; // constexpr in C++14
62+
reference at(size_type n); // constexpr in C++17
63+
const_reference at(size_type n) const; // constexpr in C++14
64+
65+
reference front(); // constexpr in C++17
66+
const_reference front() const; // constexpr in C++14
67+
reference back(); // constexpr in C++17
68+
const_reference back() const; // constexpr in C++14
69+
70+
T* data() noexcept; // constexpr in C++17
71+
const T* data() const noexcept; // constexpr in C++17
7272
};
7373
74-
template <class T, class... U>
75-
array(T, U...) -> array<T, 1 + sizeof...(U)>;
74+
template <class T, class... U>
75+
array(T, U...) -> array<T, 1 + sizeof...(U)>; // C++17
7676
7777
template <class T, size_t N>
78-
bool operator==(const array<T,N>& x, const array<T,N>& y);
78+
bool operator==(const array<T,N>& x, const array<T,N>& y); // constexpr in C++20
7979
template <class T, size_t N>
80-
bool operator!=(const array<T,N>& x, const array<T,N>& y);
80+
bool operator!=(const array<T,N>& x, const array<T,N>& y); // constexpr in C++20
8181
template <class T, size_t N>
82-
bool operator<(const array<T,N>& x, const array<T,N>& y);
82+
bool operator<(const array<T,N>& x, const array<T,N>& y); // constexpr in C++20
8383
template <class T, size_t N>
84-
bool operator>(const array<T,N>& x, const array<T,N>& y);
84+
bool operator>(const array<T,N>& x, const array<T,N>& y); // constexpr in C++20
8585
template <class T, size_t N>
86-
bool operator<=(const array<T,N>& x, const array<T,N>& y);
86+
bool operator<=(const array<T,N>& x, const array<T,N>& y); // constexpr in C++20
8787
template <class T, size_t N>
88-
bool operator>=(const array<T,N>& x, const array<T,N>& y);
88+
bool operator>=(const array<T,N>& x, const array<T,N>& y); // constexpr in C++20
8989
9090
template <class T, size_t N >
91-
void swap(array<T,N>& x, array<T,N>& y) noexcept(noexcept(x.swap(y))); // C++17
91+
void swap(array<T,N>& x, array<T,N>& y) noexcept(noexcept(x.swap(y))); // constexpr in C++20
92+
93+
template <class T, size_t N>
94+
constexpr array<remove_cv_t<T>, N> to_array(T (&a)[N]); // C++20
95+
template <class T, size_t N>
96+
constexpr array<remove_cv_t<T>, N> to_array(T (&&a)[N]); // C++20
9297
9398
template <class T> struct tuple_size;
9499
template <size_t I, class T> struct tuple_element;
95100
template <class T, size_t N> struct tuple_size<array<T, N>>;
96101
template <size_t I, class T, size_t N> struct tuple_element<I, array<T, N>>;
97-
template <size_t I, class T, size_t N> T& get(array<T, N>&) noexcept; // constexpr in C++14
98-
template <size_t I, class T, size_t N> const T& get(const array<T, N>&) noexcept; // constexpr in C++14
99-
template <size_t I, class T, size_t N> T&& get(array<T, N>&&) noexcept; // constexpr in C++14
102+
template <size_t I, class T, size_t N> T& get(array<T, N>&) noexcept; // constexpr in C++14
103+
template <size_t I, class T, size_t N> const T& get(const array<T, N>&) noexcept; // constexpr in C++14
104+
template <size_t I, class T, size_t N> T&& get(array<T, N>&&) noexcept; // constexpr in C++14
100105
template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexcept; // constexpr in C++14
101106
102107
} // std
@@ -143,11 +148,12 @@ struct _LIBCPP_TEMPLATE_VIS array
143148
_Tp __elems_[_Size];
144149

145150
// No explicit construct/copy/destroy for aggregate type
146-
_LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u) {
151+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
152+
void fill(const value_type& __u) {
147153
_VSTD::fill_n(__elems_, _Size, __u);
148154
}
149155

150-
_LIBCPP_INLINE_VISIBILITY
156+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
151157
void swap(array& __a) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) {
152158
std::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);
153159
}
@@ -236,50 +242,71 @@ struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0>
236242
typedef std::reverse_iterator<iterator> reverse_iterator;
237243
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
238244

245+
#ifndef _LIBCPP_CXX03_LANG
246+
union __wrapper {
247+
_LIBCPP_CONSTEXPR __wrapper() : __b() { }
248+
~__wrapper() = default;
249+
250+
bool __b;
251+
_Tp __t;
252+
} __w;
253+
254+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
255+
value_type* data() _NOEXCEPT {return &__w.__t;}
256+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
257+
const value_type* data() const _NOEXCEPT {return &__w.__t;}
258+
#else // C++03
239259
typedef typename conditional<is_const<_Tp>::value, const char,
240260
char>::type _CharType;
241261

242262
struct _ArrayInStructT { _Tp __data_[1]; };
243263
_ALIGNAS_TYPE(_ArrayInStructT) _CharType __elems_[sizeof(_ArrayInStructT)];
244264

265+
_LIBCPP_INLINE_VISIBILITY
266+
value_type* data() _NOEXCEPT {return reinterpret_cast<value_type*>(__elems_);}
267+
_LIBCPP_INLINE_VISIBILITY
268+
const value_type* data() const _NOEXCEPT {return reinterpret_cast<const value_type*>(__elems_);}
269+
#endif
270+
245271
// No explicit construct/copy/destroy for aggregate type
246-
_LIBCPP_INLINE_VISIBILITY void fill(const value_type&) {
272+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
273+
void fill(const value_type&) {
247274
static_assert(!is_const<_Tp>::value,
248275
"cannot fill zero-sized array of type 'const T'");
249276
}
250277

251-
_LIBCPP_INLINE_VISIBILITY
278+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
252279
void swap(array&) _NOEXCEPT {
253280
static_assert(!is_const<_Tp>::value,
254281
"cannot swap zero-sized array of type 'const T'");
255282
}
256283

257284
// iterators:
258-
_LIBCPP_INLINE_VISIBILITY
285+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
259286
iterator begin() _NOEXCEPT {return iterator(data());}
260-
_LIBCPP_INLINE_VISIBILITY
287+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
261288
const_iterator begin() const _NOEXCEPT {return const_iterator(data());}
262-
_LIBCPP_INLINE_VISIBILITY
289+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
263290
iterator end() _NOEXCEPT {return iterator(data());}
264-
_LIBCPP_INLINE_VISIBILITY
291+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
265292
const_iterator end() const _NOEXCEPT {return const_iterator(data());}
266293

267-
_LIBCPP_INLINE_VISIBILITY
294+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
268295
reverse_iterator rbegin() _NOEXCEPT {return reverse_iterator(end());}
269-
_LIBCPP_INLINE_VISIBILITY
296+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
270297
const_reverse_iterator rbegin() const _NOEXCEPT {return const_reverse_iterator(end());}
271-
_LIBCPP_INLINE_VISIBILITY
298+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
272299
reverse_iterator rend() _NOEXCEPT {return reverse_iterator(begin());}
273-
_LIBCPP_INLINE_VISIBILITY
300+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
274301
const_reverse_iterator rend() const _NOEXCEPT {return const_reverse_iterator(begin());}
275302

276-
_LIBCPP_INLINE_VISIBILITY
303+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
277304
const_iterator cbegin() const _NOEXCEPT {return begin();}
278-
_LIBCPP_INLINE_VISIBILITY
305+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
279306
const_iterator cend() const _NOEXCEPT {return end();}
280-
_LIBCPP_INLINE_VISIBILITY
307+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
281308
const_reverse_iterator crbegin() const _NOEXCEPT {return rbegin();}
282-
_LIBCPP_INLINE_VISIBILITY
309+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
283310
const_reverse_iterator crend() const _NOEXCEPT {return rend();}
284311

285312
// capacity:
@@ -291,7 +318,7 @@ struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0>
291318
_LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT {return true;}
292319

293320
// element access:
294-
_LIBCPP_INLINE_VISIBILITY
321+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
295322
reference operator[](size_type) _NOEXCEPT {
296323
_LIBCPP_ASSERT(false, "cannot call array<T, 0>::operator[] on a zero-sized array");
297324
_LIBCPP_UNREACHABLE();
@@ -303,46 +330,41 @@ struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0>
303330
_LIBCPP_UNREACHABLE();
304331
}
305332

306-
_LIBCPP_INLINE_VISIBILITY
333+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
307334
reference at(size_type) {
308335
__throw_out_of_range("array<T, 0>::at");
309336
_LIBCPP_UNREACHABLE();
310337
}
311338

312-
_LIBCPP_INLINE_VISIBILITY
339+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
313340
const_reference at(size_type) const {
314341
__throw_out_of_range("array<T, 0>::at");
315342
_LIBCPP_UNREACHABLE();
316343
}
317344

318-
_LIBCPP_INLINE_VISIBILITY
345+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
319346
reference front() _NOEXCEPT {
320347
_LIBCPP_ASSERT(false, "cannot call array<T, 0>::front() on a zero-sized array");
321348
_LIBCPP_UNREACHABLE();
322349
}
323350

324-
_LIBCPP_INLINE_VISIBILITY
351+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
325352
const_reference front() const _NOEXCEPT {
326353
_LIBCPP_ASSERT(false, "cannot call array<T, 0>::front() on a zero-sized array");
327354
_LIBCPP_UNREACHABLE();
328355
}
329356

330-
_LIBCPP_INLINE_VISIBILITY
357+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
331358
reference back() _NOEXCEPT {
332359
_LIBCPP_ASSERT(false, "cannot call array<T, 0>::back() on a zero-sized array");
333360
_LIBCPP_UNREACHABLE();
334361
}
335362

336-
_LIBCPP_INLINE_VISIBILITY
363+
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
337364
const_reference back() const _NOEXCEPT {
338365
_LIBCPP_ASSERT(false, "cannot call array<T, 0>::back() on a zero-sized array");
339366
_LIBCPP_UNREACHABLE();
340367
}
341-
342-
_LIBCPP_INLINE_VISIBILITY
343-
value_type* data() _NOEXCEPT {return reinterpret_cast<value_type*>(__elems_);}
344-
_LIBCPP_INLINE_VISIBILITY
345-
const value_type* data() const _NOEXCEPT {return reinterpret_cast<const value_type*>(__elems_);}
346368
};
347369

348370

@@ -404,7 +426,7 @@ operator>=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y)
404426
}
405427

406428
template <class _Tp, size_t _Size>
407-
inline _LIBCPP_INLINE_VISIBILITY
429+
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
408430
typename enable_if
409431
<
410432
_Size == 0 ||

libcxx/include/version

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ __cpp_lib_allocator_traits_is_always_equal 201411L <memory> <scoped
2121
<unordered_map> <unordered_set>
2222
__cpp_lib_any 201606L <any>
2323
__cpp_lib_apply 201603L <tuple>
24-
__cpp_lib_array_constexpr 201603L <iterator> <array>
24+
__cpp_lib_array_constexpr 201811L <iterator> <array>
25+
201603L // C++17
2526
__cpp_lib_as_const 201510L <utility>
2627
__cpp_lib_atomic_is_always_lock_free 201603L <atomic>
2728
__cpp_lib_atomic_ref 201806L <atomic>
@@ -212,6 +213,8 @@ __cpp_lib_void_t 201411L <type_traits>
212213
#endif
213214

214215
#if _LIBCPP_STD_VER > 17
216+
# undef __cpp_lib_array_constexpr
217+
# define __cpp_lib_array_constexpr 201811L
215218
# if !defined(_LIBCPP_HAS_NO_THREADS)
216219
// # define __cpp_lib_atomic_ref 201806L
217220
# endif
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// Make sure std::array is an aggregate type.
10+
11+
#include <array>
12+
#include <type_traits>
13+
14+
template <typename T>
15+
void tests()
16+
{
17+
// Test aggregate initialization
18+
{
19+
std::array<T, 0> a0 = {}; (void)a0;
20+
std::array<T, 1> a1 = {T()}; (void)a1;
21+
std::array<T, 2> a2 = {T(), T()}; (void)a2;
22+
std::array<T, 3> a3 = {T(), T(), T()}; (void)a3;
23+
}
24+
25+
// Test the is_aggregate trait.
26+
#if TEST_STD_VER >= 17 // The trait is only available in C++17 and above
27+
static_assert(std::is_aggregate<std::array<T, 0> >::value, "");
28+
static_assert(std::is_aggregate<std::array<T, 1> >::value, "");
29+
static_assert(std::is_aggregate<std::array<T, 2> >::value, "");
30+
static_assert(std::is_aggregate<std::array<T, 3> >::value, "");
31+
static_assert(std::is_aggregate<std::array<T, 4> >::value, "");
32+
#endif
33+
}
34+
35+
struct Empty { };
36+
struct NonEmpty { int i; int j; };
37+
38+
int main(int, char**)
39+
{
40+
tests<char>();
41+
tests<int>();
42+
tests<long>();
43+
tests<float>();
44+
tests<double>();
45+
tests<long double>();
46+
tests<NonEmpty>();
47+
tests<Empty>();
48+
49+
return 0;
50+
}

0 commit comments

Comments
 (0)