[libcxx-commits] [libcxx] 3ffc53b - [libc++] Implements concept default_initializable.

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Mon Feb 1 10:13:33 PST 2021


Author: Mark de Wever
Date: 2021-02-01T19:13:24+01:00
New Revision: 3ffc53ba16272b6475ff49c05ab6aa72f7720383

URL: https://github.com/llvm/llvm-project/commit/3ffc53ba16272b6475ff49c05ab6aa72f7720383
DIFF: https://github.com/llvm/llvm-project/commit/3ffc53ba16272b6475ff49c05ab6aa72f7720383.diff

LOG: [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

Added: 
    libcxx/test/std/concepts/concept.default.init/default_initializable.compile.pass.cpp
    libcxx/test/std/concepts/concept.default.init/default_initializable.verify.cpp

Modified: 
    libcxx/docs/Cxx2aStatusIssuesStatus.csv
    libcxx/include/concepts

Removed: 
    


################################################################################
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 <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","",""

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<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

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<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;
+}

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<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;
+}


        


More information about the libcxx-commits mailing list