Skip to content

Commit 3ffc53b

Browse files
committed
[libc++] Implements concept default_initializable.
Implements: - LWG3149 DefaultConstructible should require default initialization Implements parts of: - P0898R3 Standard Library Concepts - P1754 Rename concepts to standard_case for C++20, while we still can Depends on D91986 Reviewed By: ldionne, #libc Differential Revision: https://reviews.llvm.org/D93461
1 parent cf2be5e commit 3ffc53b

File tree

4 files changed

+345
-1
lines changed

4 files changed

+345
-1
lines changed

libcxx/docs/Cxx2aStatusIssuesStatus.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
"`3274 <https://wg21.link/LWG3274>`__","Missing feature test macro for ``<span>``\ ","Belfast","",""
187187
"`3276 <https://wg21.link/LWG3276>`__","Class ``split_view::outer_iterator::value_type``\ should inherit from ``view_interface``\ ","Belfast","",""
188188
"`3277 <https://wg21.link/LWG3277>`__","Pre-increment on prvalues is not a requirement of ``weakly_incrementable``\ ","Belfast","",""
189-
"`3149 <https://wg21.link/LWG3149>`__","``DefaultConstructible``\ should require default initialization","Belfast","",""
189+
"`3149 <https://wg21.link/LWG3149>`__","``DefaultConstructible``\ should require default initialization","Belfast","|Complete|","13.0"
190190
"","","","",""
191191
"`1203 <https://wg21.link/LWG1203>`__","More useful rvalue stream insertion","Prague","|Complete|","12.0"
192192
"`2859 <https://wg21.link/LWG2859>`__","Definition of *reachable* in [ptr.launder] misses pointer arithmetic from pointer-interconvertible object","Prague","",""

libcxx/include/concepts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,16 @@ template<class _Tp, class... _Args>
167167
concept constructible_from =
168168
destructible<_Tp> && _VSTD::is_constructible_v<_Tp, _Args...>;
169169

170+
// [concept.default.init]
171+
172+
template<class _Tp>
173+
concept __default_initializable = requires { ::new _Tp; };
174+
175+
template<class _Tp>
176+
concept default_initializable = constructible_from<_Tp> &&
177+
requires { _Tp{}; } && __default_initializable<_Tp>;
178+
179+
170180
#endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L
171181

172182
_LIBCPP_END_NAMESPACE_STD
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
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+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
// UNSUPPORTED: libcpp-no-concepts
11+
12+
// template<class T>
13+
// concept default_initializable = constructible_from<T> &&
14+
// requires { T{}; } &&
15+
// is-default-initializable<T>;
16+
17+
#include <array>
18+
#include <concepts>
19+
#include <deque>
20+
#include <forward_list>
21+
#include <list>
22+
#include <map>
23+
#include <queue>
24+
#include <set>
25+
#include <span>
26+
#include <stack>
27+
#include <string>
28+
#include <string_view>
29+
#include <unordered_map>
30+
#include <unordered_set>
31+
#include <vector>
32+
33+
#include "test_macros.h"
34+
35+
struct Empty {};
36+
37+
struct CtorDefaulted {
38+
CtorDefaulted() = default;
39+
};
40+
struct CtorDeleted {
41+
CtorDeleted() = delete;
42+
};
43+
struct DtorDefaulted {
44+
~DtorDefaulted() = default;
45+
};
46+
struct DtorDeleted {
47+
~DtorDeleted() = delete;
48+
};
49+
50+
struct Noexcept {
51+
~Noexcept() noexcept;
52+
};
53+
struct NoexceptTrue {
54+
~NoexceptTrue() noexcept(true);
55+
};
56+
struct NoexceptFalse {
57+
~NoexceptFalse() noexcept(false);
58+
};
59+
60+
struct CtorProtected {
61+
protected:
62+
CtorProtected() = default;
63+
};
64+
struct CtorPrivate {
65+
private:
66+
CtorPrivate() = default;
67+
};
68+
struct DtorProtected {
69+
protected:
70+
~DtorProtected() = default;
71+
};
72+
struct DtorPrivate {
73+
private:
74+
~DtorPrivate() = default;
75+
};
76+
77+
template <class T>
78+
struct NoexceptDependant {
79+
~NoexceptDependant() noexcept(std::is_same_v<T, int>);
80+
};
81+
82+
struct CtorExplicit {
83+
explicit CtorExplicit() = default;
84+
};
85+
struct CtorArgument {
86+
CtorArgument(int) {}
87+
};
88+
struct CtorDefaultArgument {
89+
CtorDefaultArgument(int = 0) {}
90+
};
91+
struct CtorExplicitDefaultArgument {
92+
explicit CtorExplicitDefaultArgument(int = 0) {}
93+
};
94+
95+
struct Derived : public Empty {};
96+
97+
class Abstract {
98+
virtual void foo() = 0;
99+
};
100+
101+
class AbstractDestructor {
102+
virtual ~AbstractDestructor() = 0;
103+
};
104+
105+
class OperatorNewDeleted {
106+
void* operator new(std::size_t) = delete;
107+
void operator delete(void* ptr) = delete;
108+
};
109+
110+
[[maybe_unused]] auto Lambda = [](const int&, int&&, double){};
111+
112+
template<class T>
113+
void test_not_const()
114+
{
115+
static_assert( std::default_initializable< T>);
116+
static_assert(!std::default_initializable<const T>);
117+
static_assert( std::default_initializable< volatile T>);
118+
static_assert(!std::default_initializable<const volatile T>);
119+
}
120+
121+
template<class T>
122+
void test_true()
123+
{
124+
static_assert( std::default_initializable< T>);
125+
static_assert( std::default_initializable<const T>);
126+
static_assert( std::default_initializable< volatile T>);
127+
static_assert( std::default_initializable<const volatile T>);
128+
}
129+
130+
template<class T>
131+
void test_false()
132+
{
133+
static_assert(!std::default_initializable< T>);
134+
static_assert(!std::default_initializable<const T>);
135+
static_assert(!std::default_initializable< volatile T>);
136+
static_assert(!std::default_initializable<const volatile T>);
137+
}
138+
139+
void test()
140+
{
141+
test_not_const<bool>();
142+
test_not_const<char>();
143+
test_not_const<int>();
144+
test_not_const<double>();
145+
146+
test_false <void>();
147+
test_not_const<void*>();
148+
149+
test_not_const<int*>();
150+
test_false <int[]>();
151+
test_not_const<int[1]>();
152+
test_false <int&>();
153+
test_false <int&&>();
154+
155+
test_true <Empty>();
156+
157+
test_true <CtorDefaulted>();
158+
test_false <CtorDeleted>();
159+
test_true <DtorDefaulted>();
160+
test_false <DtorDeleted>();
161+
162+
test_true <Noexcept>();
163+
test_true <NoexceptTrue>();
164+
test_false <NoexceptFalse>();
165+
166+
test_false <CtorProtected>();
167+
test_false <CtorPrivate>();
168+
test_false <DtorProtected>();
169+
test_false <DtorPrivate>();
170+
171+
test_true <NoexceptDependant<int>>();
172+
test_false <NoexceptDependant<double>>();
173+
174+
test_true <CtorExplicit>();
175+
test_false <CtorArgument>();
176+
test_true <CtorDefaultArgument>();
177+
test_true <CtorExplicitDefaultArgument>();
178+
179+
test_true <Derived>();
180+
test_false <Abstract>();
181+
test_false <AbstractDestructor>();
182+
183+
test_true <OperatorNewDeleted>();
184+
185+
test_true <decltype(Lambda)>();
186+
test_not_const<void(*)(const int&)>();
187+
test_not_const<void(Empty::*)(const int&) >();
188+
test_not_const<void(Empty::*)(const int&) const >();
189+
test_not_const<void(Empty::*)(const int&) volatile>();
190+
test_not_const<void(Empty::*)(const int&) const volatile>();
191+
test_not_const<void(Empty::*)(const int&) &>();
192+
test_not_const<void(Empty::*)(const int&) &&>();
193+
test_not_const<void(Empty::*)(const int&) noexcept>();
194+
test_not_const<void(Empty::*)(const int&) noexcept(true)>();
195+
test_not_const<void(Empty::*)(const int&) noexcept(false)>();
196+
197+
// Sequence containers
198+
test_not_const<std::array< int, 0>>();
199+
test_not_const<std::array< int, 1>>();
200+
test_false <std::array<const int, 1>>();
201+
test_not_const<std::array< volatile int, 1>>();
202+
test_false <std::array<const volatile int, 1>>();
203+
test_true <std::deque< int>>();
204+
test_true <std::deque<const int>>();
205+
test_true <std::deque< volatile int>>();
206+
test_true <std::deque<const volatile int>>();
207+
test_true <std::forward_list<int>>();
208+
test_true <std::list<int>>();
209+
test_true <std::vector<int>>();
210+
211+
// Associative containers
212+
test_true <std::set<int>>();
213+
test_true <std::map<int, int>>();
214+
test_true <std::multiset<int>>();
215+
test_true <std::multimap<int, int>>();
216+
217+
// Unordered associative containers
218+
test_true <std::unordered_set<int>>();
219+
test_true <std::unordered_map<int, int>>();
220+
test_true <std::unordered_multiset<int>>();
221+
test_true <std::unordered_multimap<int, int>>();
222+
223+
// Container adaptors
224+
test_true <std::stack< int>>();
225+
test_true <std::stack<const int>>();
226+
test_true <std::stack< volatile int>>();
227+
test_true <std::stack<const volatile int>>();
228+
test_true <std::queue<int>>();
229+
test_true <std::priority_queue<int>>();
230+
231+
test_true <std::span< int>>();
232+
test_true <std::span<const int>>();
233+
test_true <std::span< volatile int>>();
234+
test_true <std::span<const volatile int>>();
235+
236+
// Strings
237+
test_true <std::string>();
238+
test_true <std::wstring>();
239+
test_true <std::u8string>();
240+
test_true <std::u16string>();
241+
test_true <std::u32string>();
242+
243+
// String views
244+
test_true <std::string_view>();
245+
test_true <std::wstring_view>();
246+
test_true <std::u8string_view>();
247+
test_true <std::u16string_view>();
248+
test_true <std::u32string_view>();
249+
250+
// Smart pointers
251+
test_true <std::unique_ptr<int>>();
252+
test_true <std::shared_ptr<int>>();
253+
test_true <std::weak_ptr<int>>();
254+
255+
}
256+
257+
// Required for MSVC internal test runner compatibility.
258+
int main(int, char**) {
259+
return 0;
260+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
// UNSUPPORTED: libcpp-no-concepts
11+
12+
// template<class T>
13+
// concept default_initializable = constructible_from<T> &&
14+
// requires { T{}; } &&
15+
// is-default-initializable<T>;
16+
17+
#include <concepts>
18+
#include <cassert>
19+
20+
#include "test_macros.h"
21+
22+
template<class T>
23+
concept brace_initializable = requires { T{}; };
24+
25+
void test() {
26+
// LWG3149
27+
// Changed the concept from constructible_from<T>
28+
// to constructible_from<T> &&
29+
// requires { T{}; } && is-default-initializable <T>
30+
struct S0 { explicit S0() = default; };
31+
S0 x0;
32+
S0 y0{};
33+
static_assert( std::constructible_from<S0>);
34+
static_assert( brace_initializable<S0>);
35+
LIBCPP_STATIC_ASSERT( std::__default_initializable<S0>);
36+
static_assert( std::default_initializable<S0>);
37+
38+
struct S1 { S0 x; }; // Note: aggregate
39+
S1 x1;
40+
S1 y1{}; // expected-error {{chosen constructor is explicit in copy-initialization}}
41+
static_assert( std::constructible_from<S1>);
42+
static_assert(!brace_initializable<S1>);
43+
LIBCPP_STATIC_ASSERT( std::__default_initializable<S1>);
44+
static_assert(!std::default_initializable<S1>);
45+
46+
const int x2; // expected-error {{default initialization of an object of const type 'const int'}}
47+
const int y2{};
48+
49+
static_assert( std::constructible_from<const int>);
50+
static_assert( brace_initializable<const int>);
51+
LIBCPP_STATIC_ASSERT(!std::__default_initializable<const int>);
52+
static_assert(!std::default_initializable<const int>);
53+
54+
const int x3[1]; // expected-error {{default initialization of an object of const type 'const int [1]'}}
55+
const int y3[1]{};
56+
static_assert( std::constructible_from<const int[1]>);
57+
static_assert( brace_initializable<const int[1]>);
58+
LIBCPP_STATIC_ASSERT(!std::__default_initializable<const int[1]>);
59+
static_assert(!std::default_initializable<const int[1]>);
60+
61+
// Zero-length array extension
62+
const int x4[]; // expected-error {{definition of variable with array type needs an explicit size or an initializer}}
63+
const int y4[]{};
64+
static_assert(!std::constructible_from<const int[]>);
65+
static_assert( brace_initializable<const int[]>);
66+
LIBCPP_STATIC_ASSERT(!std::__default_initializable<const int[]>);
67+
static_assert(!std::default_initializable<const int[]>);
68+
}
69+
70+
int main(int, char**) {
71+
test();
72+
73+
return 0;
74+
}

0 commit comments

Comments
 (0)