[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
This commit is contained in:
Mark de Wever 2020-12-17 07:48:26 +01:00
parent cf2be5e3bb
commit 3ffc53ba16
4 changed files with 345 additions and 1 deletions

View File

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

1 Issue # Issue Name Meeting Status First released version
186 `3274 <https://wg21.link/LWG3274>`__ Missing feature test macro for ``<span>``\ Belfast
187 `3276 <https://wg21.link/LWG3276>`__ Class ``split_view::outer_iterator::value_type``\ should inherit from ``view_interface``\ Belfast
188 `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 |Complete| 13.0
190
191 `1203 <https://wg21.link/LWG1203>`__ More useful rvalue stream insertion Prague |Complete| 12.0
192 `2859 <https://wg21.link/LWG2859>`__ Definition of *reachable* in [ptr.launder] misses pointer arithmetic from pointer-interconvertible object Prague

View File

@ -167,6 +167,16 @@ template<class _Tp, class... _Args>
concept constructible_from =
destructible<_Tp> && _VSTD::is_constructible_v<_Tp, _Args...>;
// [concept.default.init]
template<class _Tp>
concept __default_initializable = requires { ::new _Tp; };
template<class _Tp>
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

View File

@ -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<class T>
// concept default_initializable = constructible_from<T> &&
// requires { T{}; } &&
// is-default-initializable<T>;
#include <array>
#include <concepts>
#include <deque>
#include <forward_list>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <span>
#include <stack>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#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 <class T>
struct NoexceptDependant {
~NoexceptDependant() noexcept(std::is_same_v<T, int>);
};
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<class T>
void test_not_const()
{
static_assert( std::default_initializable< T>);
static_assert(!std::default_initializable<const T>);
static_assert( std::default_initializable< volatile T>);
static_assert(!std::default_initializable<const volatile T>);
}
template<class T>
void test_true()
{
static_assert( std::default_initializable< T>);
static_assert( std::default_initializable<const T>);
static_assert( std::default_initializable< volatile T>);
static_assert( std::default_initializable<const volatile T>);
}
template<class T>
void test_false()
{
static_assert(!std::default_initializable< T>);
static_assert(!std::default_initializable<const T>);
static_assert(!std::default_initializable< volatile T>);
static_assert(!std::default_initializable<const volatile T>);
}
void test()
{
test_not_const<bool>();
test_not_const<char>();
test_not_const<int>();
test_not_const<double>();
test_false <void>();
test_not_const<void*>();
test_not_const<int*>();
test_false <int[]>();
test_not_const<int[1]>();
test_false <int&>();
test_false <int&&>();
test_true <Empty>();
test_true <CtorDefaulted>();
test_false <CtorDeleted>();
test_true <DtorDefaulted>();
test_false <DtorDeleted>();
test_true <Noexcept>();
test_true <NoexceptTrue>();
test_false <NoexceptFalse>();
test_false <CtorProtected>();
test_false <CtorPrivate>();
test_false <DtorProtected>();
test_false <DtorPrivate>();
test_true <NoexceptDependant<int>>();
test_false <NoexceptDependant<double>>();
test_true <CtorExplicit>();
test_false <CtorArgument>();
test_true <CtorDefaultArgument>();
test_true <CtorExplicitDefaultArgument>();
test_true <Derived>();
test_false <Abstract>();
test_false <AbstractDestructor>();
test_true <OperatorNewDeleted>();
test_true <decltype(Lambda)>();
test_not_const<void(*)(const int&)>();
test_not_const<void(Empty::*)(const int&) >();
test_not_const<void(Empty::*)(const int&) const >();
test_not_const<void(Empty::*)(const int&) volatile>();
test_not_const<void(Empty::*)(const int&) const volatile>();
test_not_const<void(Empty::*)(const int&) &>();
test_not_const<void(Empty::*)(const int&) &&>();
test_not_const<void(Empty::*)(const int&) noexcept>();
test_not_const<void(Empty::*)(const int&) noexcept(true)>();
test_not_const<void(Empty::*)(const int&) noexcept(false)>();
// Sequence containers
test_not_const<std::array< int, 0>>();
test_not_const<std::array< int, 1>>();
test_false <std::array<const int, 1>>();
test_not_const<std::array< volatile int, 1>>();
test_false <std::array<const volatile int, 1>>();
test_true <std::deque< int>>();
test_true <std::deque<const int>>();
test_true <std::deque< volatile int>>();
test_true <std::deque<const volatile int>>();
test_true <std::forward_list<int>>();
test_true <std::list<int>>();
test_true <std::vector<int>>();
// Associative containers
test_true <std::set<int>>();
test_true <std::map<int, int>>();
test_true <std::multiset<int>>();
test_true <std::multimap<int, int>>();
// Unordered associative containers
test_true <std::unordered_set<int>>();
test_true <std::unordered_map<int, int>>();
test_true <std::unordered_multiset<int>>();
test_true <std::unordered_multimap<int, int>>();
// Container adaptors
test_true <std::stack< int>>();
test_true <std::stack<const int>>();
test_true <std::stack< volatile int>>();
test_true <std::stack<const volatile int>>();
test_true <std::queue<int>>();
test_true <std::priority_queue<int>>();
test_true <std::span< int>>();
test_true <std::span<const int>>();
test_true <std::span< volatile int>>();
test_true <std::span<const volatile int>>();
// Strings
test_true <std::string>();
test_true <std::wstring>();
test_true <std::u8string>();
test_true <std::u16string>();
test_true <std::u32string>();
// String views
test_true <std::string_view>();
test_true <std::wstring_view>();
test_true <std::u8string_view>();
test_true <std::u16string_view>();
test_true <std::u32string_view>();
// Smart pointers
test_true <std::unique_ptr<int>>();
test_true <std::shared_ptr<int>>();
test_true <std::weak_ptr<int>>();
}
// Required for MSVC internal test runner compatibility.
int main(int, char**) {
return 0;
}

View File

@ -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<class T>
// concept default_initializable = constructible_from<T> &&
// requires { T{}; } &&
// is-default-initializable<T>;
#include <concepts>
#include <cassert>
#include "test_macros.h"
template<class T>
concept brace_initializable = requires { T{}; };
void test() {
// LWG3149
// Changed the concept from constructible_from<T>
// to constructible_from<T> &&
// requires { T{}; } && is-default-initializable <T>
struct S0 { explicit S0() = default; };
S0 x0;
S0 y0{};
static_assert( std::constructible_from<S0>);
static_assert( brace_initializable<S0>);
LIBCPP_STATIC_ASSERT( std::__default_initializable<S0>);
static_assert( std::default_initializable<S0>);
struct S1 { S0 x; }; // Note: aggregate
S1 x1;
S1 y1{}; // expected-error {{chosen constructor is explicit in copy-initialization}}
static_assert( std::constructible_from<S1>);
static_assert(!brace_initializable<S1>);
LIBCPP_STATIC_ASSERT( std::__default_initializable<S1>);
static_assert(!std::default_initializable<S1>);
const int x2; // expected-error {{default initialization of an object of const type 'const int'}}
const int y2{};
static_assert( std::constructible_from<const int>);
static_assert( brace_initializable<const int>);
LIBCPP_STATIC_ASSERT(!std::__default_initializable<const int>);
static_assert(!std::default_initializable<const int>);
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<const int[1]>);
static_assert( brace_initializable<const int[1]>);
LIBCPP_STATIC_ASSERT(!std::__default_initializable<const int[1]>);
static_assert(!std::default_initializable<const int[1]>);
// 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<const int[]>);
static_assert( brace_initializable<const int[]>);
LIBCPP_STATIC_ASSERT(!std::__default_initializable<const int[]>);
static_assert(!std::default_initializable<const int[]>);
}
int main(int, char**) {
test();
return 0;
}