diff --git a/libcxx/docs/Cxx2aStatusIssuesStatus.csv b/libcxx/docs/Cxx2aStatusIssuesStatus.csv index 55a9d9b4818c..859c52ae2b21 100644 --- a/libcxx/docs/Cxx2aStatusIssuesStatus.csv +++ b/libcxx/docs/Cxx2aStatusIssuesStatus.csv @@ -186,7 +186,7 @@ "`3274 `__","Missing feature test macro for ````\ ","Belfast","","" "`3276 `__","Class ``split_view::outer_iterator::value_type``\ should inherit from ``view_interface``\ ","Belfast","","" "`3277 `__","Pre-increment on prvalues is not a requirement of ``weakly_incrementable``\ ","Belfast","","" -"`3149 `__","``DefaultConstructible``\ should require default initialization","Belfast","","" +"`3149 `__","``DefaultConstructible``\ should require default initialization","Belfast","|Complete|","13.0" "","","","","" "`1203 `__","More useful rvalue stream insertion","Prague","|Complete|","12.0" "`2859 `__","Definition of *reachable* in [ptr.launder] misses pointer arithmetic from pointer-interconvertible object","Prague","","" diff --git a/libcxx/include/concepts b/libcxx/include/concepts index 86e0325c2b10..e245e54d0a36 100644 --- a/libcxx/include/concepts +++ b/libcxx/include/concepts @@ -167,6 +167,16 @@ template concept constructible_from = destructible<_Tp> && _VSTD::is_constructible_v<_Tp, _Args...>; +// [concept.default.init] + +template +concept __default_initializable = requires { ::new _Tp; }; + +template +concept default_initializable = constructible_from<_Tp> && + requires { _Tp{}; } && __default_initializable<_Tp>; + + #endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/concepts/concept.default.init/default_initializable.compile.pass.cpp b/libcxx/test/std/concepts/concept.default.init/default_initializable.compile.pass.cpp new file mode 100644 index 000000000000..2a0ebb2076a2 --- /dev/null +++ b/libcxx/test/std/concepts/concept.default.init/default_initializable.compile.pass.cpp @@ -0,0 +1,260 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// template +// concept default_initializable = constructible_from && +// requires { T{}; } && +// is-default-initializable; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +struct Empty {}; + +struct CtorDefaulted { + CtorDefaulted() = default; +}; +struct CtorDeleted { + CtorDeleted() = delete; +}; +struct DtorDefaulted { + ~DtorDefaulted() = default; +}; +struct DtorDeleted { + ~DtorDeleted() = delete; +}; + +struct Noexcept { + ~Noexcept() noexcept; +}; +struct NoexceptTrue { + ~NoexceptTrue() noexcept(true); +}; +struct NoexceptFalse { + ~NoexceptFalse() noexcept(false); +}; + +struct CtorProtected { +protected: + CtorProtected() = default; +}; +struct CtorPrivate { +private: + CtorPrivate() = default; +}; +struct DtorProtected { +protected: + ~DtorProtected() = default; +}; +struct DtorPrivate { +private: + ~DtorPrivate() = default; +}; + +template +struct NoexceptDependant { + ~NoexceptDependant() noexcept(std::is_same_v); +}; + +struct CtorExplicit { + explicit CtorExplicit() = default; +}; +struct CtorArgument { + CtorArgument(int) {} +}; +struct CtorDefaultArgument { + CtorDefaultArgument(int = 0) {} +}; +struct CtorExplicitDefaultArgument { + explicit CtorExplicitDefaultArgument(int = 0) {} +}; + +struct Derived : public Empty {}; + +class Abstract { + virtual void foo() = 0; +}; + +class AbstractDestructor { + virtual ~AbstractDestructor() = 0; +}; + +class OperatorNewDeleted { + void* operator new(std::size_t) = delete; + void operator delete(void* ptr) = delete; +}; + +[[maybe_unused]] auto Lambda = [](const int&, int&&, double){}; + +template +void test_not_const() +{ + static_assert( std::default_initializable< T>); + static_assert(!std::default_initializable); + static_assert( std::default_initializable< volatile T>); + static_assert(!std::default_initializable); +} + +template +void test_true() +{ + static_assert( std::default_initializable< T>); + static_assert( std::default_initializable); + static_assert( std::default_initializable< volatile T>); + static_assert( std::default_initializable); +} + +template +void test_false() +{ + static_assert(!std::default_initializable< T>); + static_assert(!std::default_initializable); + static_assert(!std::default_initializable< volatile T>); + static_assert(!std::default_initializable); +} + +void test() +{ + test_not_const(); + test_not_const(); + test_not_const(); + test_not_const(); + + test_false (); + test_not_const(); + + test_not_const(); + test_false (); + test_not_const(); + test_false (); + test_false (); + + test_true (); + + test_true (); + test_false (); + test_true (); + test_false (); + + test_true (); + test_true (); + test_false (); + + test_false (); + test_false (); + test_false (); + test_false (); + + test_true >(); + test_false >(); + + test_true (); + test_false (); + test_true (); + test_true (); + + test_true (); + test_false (); + test_false (); + + test_true (); + + test_true (); + test_not_const(); + test_not_const(); + test_not_const(); + test_not_const(); + test_not_const(); + test_not_const(); + test_not_const(); + test_not_const(); + test_not_const(); + test_not_const(); + + // Sequence containers + test_not_const>(); + test_not_const>(); + test_false >(); + test_not_const>(); + test_false >(); + test_true >(); + test_true >(); + test_true >(); + test_true >(); + test_true >(); + test_true >(); + test_true >(); + + // Associative containers + test_true >(); + test_true >(); + test_true >(); + test_true >(); + + // Unordered associative containers + test_true >(); + test_true >(); + test_true >(); + test_true >(); + + // Container adaptors + test_true >(); + test_true >(); + test_true >(); + test_true >(); + test_true >(); + test_true >(); + + test_true >(); + test_true >(); + test_true >(); + test_true >(); + + // Strings + test_true (); + test_true (); + test_true (); + test_true (); + test_true (); + + // String views + test_true (); + test_true (); + test_true (); + test_true (); + test_true (); + + // Smart pointers + test_true >(); + test_true >(); + test_true >(); + +} + +// Required for MSVC internal test runner compatibility. +int main(int, char**) { + return 0; +} diff --git a/libcxx/test/std/concepts/concept.default.init/default_initializable.verify.cpp b/libcxx/test/std/concepts/concept.default.init/default_initializable.verify.cpp new file mode 100644 index 000000000000..789846e21b24 --- /dev/null +++ b/libcxx/test/std/concepts/concept.default.init/default_initializable.verify.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// template +// concept default_initializable = constructible_from && +// requires { T{}; } && +// is-default-initializable; + +#include +#include + +#include "test_macros.h" + +template +concept brace_initializable = requires { T{}; }; + +void test() { + // LWG3149 + // Changed the concept from constructible_from + // to constructible_from && + // requires { T{}; } && is-default-initializable + struct S0 { explicit S0() = default; }; + S0 x0; + S0 y0{}; + static_assert( std::constructible_from); + static_assert( brace_initializable); + LIBCPP_STATIC_ASSERT( std::__default_initializable); + static_assert( std::default_initializable); + + struct S1 { S0 x; }; // Note: aggregate + S1 x1; + S1 y1{}; // expected-error {{chosen constructor is explicit in copy-initialization}} + static_assert( std::constructible_from); + static_assert(!brace_initializable); + LIBCPP_STATIC_ASSERT( std::__default_initializable); + static_assert(!std::default_initializable); + + const int x2; // expected-error {{default initialization of an object of const type 'const int'}} + const int y2{}; + + static_assert( std::constructible_from); + static_assert( brace_initializable); + LIBCPP_STATIC_ASSERT(!std::__default_initializable); + static_assert(!std::default_initializable); + + const int x3[1]; // expected-error {{default initialization of an object of const type 'const int [1]'}} + const int y3[1]{}; + static_assert( std::constructible_from); + static_assert( brace_initializable); + LIBCPP_STATIC_ASSERT(!std::__default_initializable); + static_assert(!std::default_initializable); + + // Zero-length array extension + const int x4[]; // expected-error {{definition of variable with array type needs an explicit size or an initializer}} + const int y4[]{}; + static_assert(!std::constructible_from); + static_assert( brace_initializable); + LIBCPP_STATIC_ASSERT(!std::__default_initializable); + static_assert(!std::default_initializable); +} + +int main(int, char**) { + test(); + + return 0; +}