From a9e659619f592c49b352af16253ec0b79c207956 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Wed, 12 Oct 2016 07:46:20 +0000 Subject: Implement N4606 optional Summary: Adapt implementation of Library Fundamentals TS optional into an implementation of N4606 optional. - Update relational operators per http://wg21.link/P0307 - Update to requirements of http://wg21.link/P0032 - Extension: Implement trivial copy/move construction/assignment for `optional` when `T` is trivially copyable. Audit P/Rs for optional LWG issues: - 2756 "C++ WP optional should 'forward' T's implicit conversions" Implemented, which also resolves 2753 "Optional's constructors and assignments need constraints" (modulo my refusal to explicitly delete the move operations, which is a design error that I'm working on correcting in the 2756 P/R). - 2736 "nullopt_t insufficiently constrained" Already conforming. I've added a test ensuring that `nullopt_t` is not copy-initializable from an empty braced-init-list, which I believe is the root intent of the issue, to avoid regression. - 2740 "constexpr optional::operator->" Already conforming. - 2746 "Inconsistency between requirements for emplace between optional and variant" No P/R, but note that the author's '"suggested resolution" is already implemented. - 2748 "swappable traits for optionals" Already conforming. - 2753 "Optional's constructors and assignments need constraints" Implemented. Most of the work for this patch was done by Casey Carter @ Microsoft. Thank you Casey! Reviewers: mclow.lists, CaseyCarter, EricWF Differential Revision: https://reviews.llvm.org/D22741 llvm-svn: 283980 --- libcxx/test/support/archetypes.hpp | 322 ++++++++++++++++++++++++++++++++++++- libcxx/test/support/archetypes.ipp | 141 +++++++++++----- 2 files changed, 420 insertions(+), 43 deletions(-) (limited to 'libcxx/test/support') diff --git a/libcxx/test/support/archetypes.hpp b/libcxx/test/support/archetypes.hpp index 5b294049658..c09aa7085ff 100644 --- a/libcxx/test/support/archetypes.hpp +++ b/libcxx/test/support/archetypes.hpp @@ -1,10 +1,186 @@ #ifndef TEST_SUPPORT_ARCHETYPES_HPP #define TEST_SUPPORT_ARCHETYPES_HPP +#include +#include + #include "test_macros.h" #if TEST_STD_VER >= 11 +namespace ArchetypeBases { + +template +struct DepType : T {}; + +struct NullBase {}; + +template +struct TestBase { + static int alive; + static int constructed; + static int value_constructed; + static int default_constructed; + static int copy_constructed; + static int move_constructed; + static int assigned; + static int value_assigned; + static int copy_assigned; + static int move_assigned; + static int destroyed; + + static void reset() { + assert(alive == 0); + alive = 0; + reset_constructors(); + } + + static void reset_constructors() { + constructed = value_constructed = default_constructed = + copy_constructed = move_constructed = 0; + assigned = value_assigned = copy_assigned = move_assigned = destroyed = 0; + } + + TestBase() noexcept : value(0) { + ++alive; ++constructed; ++default_constructed; + } + template ::type = true> + explicit TestBase(int x) noexcept : value(x) { + ++alive; ++constructed; ++value_constructed; + } + template ::type = true> + TestBase(int x) noexcept : value(x) { + ++alive; ++constructed; ++value_constructed; + } + template ::type = true> + explicit TestBase(int x, int y) noexcept : value(y) { + ++alive; ++constructed; ++value_constructed; + } + template ::type = true> + TestBase(int x, int y) noexcept : value(y) { + ++alive; ++constructed; ++value_constructed; + } + template ::type = true> + explicit TestBase(std::initializer_list& il, int y = 0) noexcept + : value(il.size()) { + ++alive; ++constructed; ++value_constructed; + } + template ::type = true> + TestBase(std::initializer_list& il, int y = 0) noexcept : value(il.size()) { + ++alive; ++constructed; ++value_constructed; + } + TestBase& operator=(int xvalue) noexcept { + value = xvalue; + ++assigned; ++value_assigned; + return *this; + } +protected: + ~TestBase() { + assert(value != -999); assert(alive > 0); + --alive; ++destroyed; value = -999; + } + TestBase(TestBase const& o) noexcept : value(o.value) { + assert(o.value != -1); assert(o.value != -999); + ++alive; ++constructed; ++copy_constructed; + } + TestBase(TestBase && o) noexcept : value(o.value) { + assert(o.value != -1); assert(o.value != -999); + ++alive; ++constructed; ++move_constructed; + o.value = -1; + } + TestBase& operator=(TestBase const& o) noexcept { + assert(o.value != -1); assert(o.value != -999); + ++assigned; ++copy_assigned; + value = o.value; + return *this; + } + TestBase& operator=(TestBase&& o) noexcept { + assert(o.value != -1); assert(o.value != -999); + ++assigned; ++move_assigned; + value = o.value; + o.value = -1; + return *this; + } +public: + int value; +}; + +template int TestBase::alive = 0; +template int TestBase::constructed = 0; +template int TestBase::value_constructed = 0; +template int TestBase::default_constructed = 0; +template int TestBase::copy_constructed = 0; +template int TestBase::move_constructed = 0; +template int TestBase::assigned = 0; +template int TestBase::value_assigned = 0; +template int TestBase::copy_assigned = 0; +template int TestBase::move_assigned = 0; +template int TestBase::destroyed = 0; + +template +struct ValueBase { + template ::type = true> + explicit constexpr ValueBase(int x) : value(x) {} + template ::type = true> + constexpr ValueBase(int x) : value(x) {} + template ::type = true> + explicit constexpr ValueBase(int x, int y) : value(y) {} + template ::type = true> + constexpr ValueBase(int x, int y) : value(y) {} + template ::type = true> + explicit constexpr ValueBase(std::initializer_list& il, int y = 0) : value(il.size()) {} + template ::type = true> + constexpr ValueBase(std::initializer_list& il, int y = 0) : value(il.size()) {} + constexpr ValueBase& operator=(int xvalue) noexcept { + value = xvalue; + return *this; + } + //~ValueBase() { assert(value != -999); value = -999; } + int value; +protected: + constexpr ValueBase() noexcept : value(0) {} + constexpr ValueBase(ValueBase const& o) noexcept : value(o.value) { + assert(o.value != -1); assert(o.value != -999); + } + constexpr ValueBase(ValueBase && o) noexcept : value(o.value) { + assert(o.value != -1); assert(o.value != -999); + o.value = -1; + } + constexpr ValueBase& operator=(ValueBase const& o) noexcept { + assert(o.value != -1); assert(o.value != -999); + value = o.value; + return *this; + } + constexpr ValueBase& operator=(ValueBase&& o) noexcept { + assert(o.value != -1); assert(o.value != -999); + value = o.value; + o.value = -1; + return *this; + } +}; + + +template +struct TrivialValueBase { + template ::type = true> + explicit constexpr TrivialValueBase(int x) : value(x) {} + template ::type = true> + constexpr TrivialValueBase(int x) : value(x) {} + template ::type = true> + explicit constexpr TrivialValueBase(int x, int y) : value(y) {} + template ::type = true> + constexpr TrivialValueBase(int x, int y) : value(y) {} + template ::type = true> + explicit constexpr TrivialValueBase(std::initializer_list& il, int y = 0) : value(il.size()) {} + template ::type = true> + constexpr TrivialValueBase(std::initializer_list& il, int y = 0) : value(il.size()) {}; + int value; +protected: + constexpr TrivialValueBase() noexcept : value(0) {} +}; + +} + //============================================================================// // Trivial Implicit Test Types namespace ImplicitTypes { @@ -18,9 +194,18 @@ namespace ExplicitTypes { #include "archetypes.ipp" } + +//============================================================================// +// +namespace NonConstexprTypes { +#define DEFINE_CONSTEXPR +#include "archetypes.ipp" +} + //============================================================================// -// Non-Trivial Implicit Test Types +// Non-literal implicit test types namespace NonLiteralTypes { +#define DEFINE_ASSIGN_CONSTEXPR #define DEFINE_DTOR(Name) ~Name() {} #include "archetypes.ipp" } @@ -29,9 +214,144 @@ namespace NonLiteralTypes { // Non-Trivially Copyable Implicit Test Types namespace NonTrivialTypes { #define DEFINE_CTOR {} +#define DEFINE_ASSIGN { return *this; } +#define DEFINE_DEFAULT_CTOR = default +#include "archetypes.ipp" +} + +//============================================================================// +// Implicit counting types +namespace TestTypes { +#define DEFINE_CONSTEXPR +#define DEFINE_BASE(Name) ::ArchetypeBases::TestBase +#include "archetypes.ipp" + +using TestType = AllCtors; + +// Add equality operators +template +constexpr bool operator==(Tp const& L, Tp const& R) noexcept { + return L.value == R.value; +} + +template +constexpr bool operator!=(Tp const& L, Tp const& R) noexcept { + return L.value != R.value; +} + +} + +//============================================================================// +// Implicit counting types +namespace ExplicitTestTypes { +#define DEFINE_CONSTEXPR +#define DEFINE_EXPLICIT explicit +#define DEFINE_BASE(Name) ::ArchetypeBases::TestBase +#include "archetypes.ipp" + +using TestType = AllCtors; + +// Add equality operators +template +constexpr bool operator==(Tp const& L, Tp const& R) noexcept { + return L.value == R.value; +} + +template +constexpr bool operator!=(Tp const& L, Tp const& R) noexcept { + return L.value != R.value; +} + +} + +//============================================================================// +// Implicit value types +namespace ConstexprTestTypes { +#define DEFINE_BASE(Name) ::ArchetypeBases::ValueBase<> +#include "archetypes.ipp" + +using TestType = AllCtors; + +// Add equality operators +template +constexpr bool operator==(Tp const& L, Tp const& R) noexcept { + return L.value == R.value; +} + +template +constexpr bool operator!=(Tp const& L, Tp const& R) noexcept { + return L.value != R.value; +} + +} // end namespace ValueTypes + + +//============================================================================// +// +namespace ExplicitConstexprTestTypes { +#define DEFINE_EXPLICIT explicit +#define DEFINE_BASE(Name) ::ArchetypeBases::ValueBase +#include "archetypes.ipp" + +using TestType = AllCtors; + +// Add equality operators +template +constexpr bool operator==(Tp const& L, Tp const& R) noexcept { + return L.value == R.value; +} + +template +constexpr bool operator!=(Tp const& L, Tp const& R) noexcept { + return L.value != R.value; +} + +} // end namespace ValueTypes + + +//============================================================================// +// +namespace TrivialTestTypes { +#define DEFINE_BASE(Name) ::ArchetypeBases::TrivialValueBase +#include "archetypes.ipp" + +using TestType = AllCtors; + +// Add equality operators +template +constexpr bool operator==(Tp const& L, Tp const& R) noexcept { + return L.value == R.value; +} + +template +constexpr bool operator!=(Tp const& L, Tp const& R) noexcept { + return L.value != R.value; +} + +} // end namespace TrivialValueTypes + +//============================================================================// +// +namespace ExplicitTrivialTestTypes { +#define DEFINE_EXPLICIT explicit +#define DEFINE_BASE(Name) ::ArchetypeBases::TrivialValueBase #include "archetypes.ipp" + +using TestType = AllCtors; + +// Add equality operators +template +constexpr bool operator==(Tp const& L, Tp const& R) noexcept { + return L.value == R.value; } +template +constexpr bool operator!=(Tp const& L, Tp const& R) noexcept { + return L.value != R.value; +} + +} // end namespace ExplicitTrivialTestTypes + #endif // TEST_STD_VER >= 11 #endif // TEST_SUPPORT_ARCHETYPES_HPP diff --git a/libcxx/test/support/archetypes.ipp b/libcxx/test/support/archetypes.ipp index 094440a9783..1f94ddcf0c8 100644 --- a/libcxx/test/support/archetypes.ipp +++ b/libcxx/test/support/archetypes.ipp @@ -1,10 +1,22 @@ +#ifndef DEFINE_BASE +#define DEFINE_BASE(Name) ::ArchetypeBases::NullBase +#endif #ifndef DEFINE_EXPLICIT #define DEFINE_EXPLICIT #endif +#ifndef DEFINE_CONSTEXPR +#define DEFINE_CONSTEXPR constexpr +#endif +#ifndef DEFINE_ASSIGN_CONSTEXPR +#define DEFINE_ASSIGN_CONSTEXPR DEFINE_CONSTEXPR +#endif #ifndef DEFINE_CTOR #define DEFINE_CTOR = default #endif +#ifndef DEFINE_DEFAULT_CTOR +#define DEFINE_DEFAULT_CTOR DEFINE_CTOR +#endif #ifndef DEFINE_ASSIGN #define DEFINE_ASSIGN = default #endif @@ -12,78 +24,117 @@ #define DEFINE_DTOR(Name) #endif -struct NoDefault { - DEFINE_EXPLICIT NoDefault() = delete; +struct AllCtors : DEFINE_BASE(AllCtors) { + using Base = DEFINE_BASE(AllCtors); + using Base::Base; + using Base::operator=; + DEFINE_EXPLICIT DEFINE_CONSTEXPR AllCtors() DEFINE_DEFAULT_CTOR; + DEFINE_EXPLICIT DEFINE_CONSTEXPR AllCtors(AllCtors const&) DEFINE_CTOR; + DEFINE_EXPLICIT DEFINE_CONSTEXPR AllCtors(AllCtors &&) DEFINE_CTOR; + DEFINE_ASSIGN_CONSTEXPR AllCtors& operator=(AllCtors const&) DEFINE_ASSIGN; + DEFINE_ASSIGN_CONSTEXPR AllCtors& operator=(AllCtors &&) DEFINE_ASSIGN; + DEFINE_DTOR(AllCtors) +}; + +struct NoCtors : DEFINE_BASE(NoCtors) { + using Base = DEFINE_BASE(NoCtors); + using Base::Base; + DEFINE_EXPLICIT NoCtors() = delete; + DEFINE_EXPLICIT NoCtors(NoCtors const&) = delete; + NoCtors& operator=(NoCtors const&) = delete; + DEFINE_DTOR(NoCtors) +}; + +struct NoDefault : DEFINE_BASE(NoDefault) { + using Base = DEFINE_BASE(NoDefault); + using Base::Base; + DEFINE_EXPLICIT DEFINE_CONSTEXPR NoDefault() = delete; DEFINE_DTOR(NoDefault) }; -struct AllCtors { - DEFINE_EXPLICIT AllCtors() DEFINE_CTOR; - DEFINE_EXPLICIT AllCtors(AllCtors const&) DEFINE_CTOR; - DEFINE_EXPLICIT AllCtors(AllCtors &&) DEFINE_CTOR; - AllCtors& operator=(AllCtors const&) DEFINE_ASSIGN; - AllCtors& operator=(AllCtors &&) DEFINE_ASSIGN; - DEFINE_DTOR(AllCtors) +struct DefaultOnly : DEFINE_BASE(DefaultOnly) { + using Base = DEFINE_BASE(DefaultOnly); + using Base::Base; + DEFINE_EXPLICIT DEFINE_CONSTEXPR DefaultOnly() DEFINE_DEFAULT_CTOR; + DefaultOnly(DefaultOnly const&) = delete; + DefaultOnly& operator=(DefaultOnly const&) = delete; + DEFINE_DTOR(DefaultOnly) }; -struct Copyable { - DEFINE_EXPLICIT Copyable() DEFINE_CTOR; - DEFINE_EXPLICIT Copyable(Copyable const &) DEFINE_CTOR; +struct Copyable : DEFINE_BASE(Copyable) { + using Base = DEFINE_BASE(Copyable); + using Base::Base; + DEFINE_EXPLICIT DEFINE_CONSTEXPR Copyable() DEFINE_DEFAULT_CTOR; + DEFINE_EXPLICIT DEFINE_CONSTEXPR Copyable(Copyable const &) DEFINE_CTOR; Copyable &operator=(Copyable const &) DEFINE_ASSIGN; DEFINE_DTOR(Copyable) }; -struct CopyOnly { - DEFINE_EXPLICIT CopyOnly() DEFINE_CTOR; - DEFINE_EXPLICIT CopyOnly(CopyOnly const &) DEFINE_CTOR; - DEFINE_EXPLICIT CopyOnly(CopyOnly &&) = delete; +struct CopyOnly : DEFINE_BASE(CopyOnly) { + using Base = DEFINE_BASE(CopyOnly); + using Base::Base; + DEFINE_EXPLICIT DEFINE_CONSTEXPR CopyOnly() DEFINE_DEFAULT_CTOR; + DEFINE_EXPLICIT DEFINE_CONSTEXPR CopyOnly(CopyOnly const &) DEFINE_CTOR; + DEFINE_EXPLICIT DEFINE_CONSTEXPR CopyOnly(CopyOnly &&) = delete; CopyOnly &operator=(CopyOnly const &) DEFINE_ASSIGN; CopyOnly &operator=(CopyOnly &&) = delete; DEFINE_DTOR(CopyOnly) }; -struct NonCopyable { - DEFINE_EXPLICIT NonCopyable() DEFINE_CTOR; - DEFINE_EXPLICIT NonCopyable(NonCopyable const &) = delete; +struct NonCopyable : DEFINE_BASE(NonCopyable) { + using Base = DEFINE_BASE(NonCopyable); + using Base::Base; + DEFINE_EXPLICIT DEFINE_CONSTEXPR NonCopyable() DEFINE_DEFAULT_CTOR; + DEFINE_EXPLICIT DEFINE_CONSTEXPR NonCopyable(NonCopyable const &) = delete; NonCopyable &operator=(NonCopyable const &) = delete; DEFINE_DTOR(NonCopyable) }; -struct MoveOnly { - DEFINE_EXPLICIT MoveOnly() DEFINE_CTOR; - DEFINE_EXPLICIT MoveOnly(MoveOnly &&) DEFINE_CTOR; +struct MoveOnly : DEFINE_BASE(MoveOnly) { + using Base = DEFINE_BASE(MoveOnly); + using Base::Base; + DEFINE_EXPLICIT DEFINE_CONSTEXPR MoveOnly() DEFINE_DEFAULT_CTOR; + DEFINE_EXPLICIT DEFINE_CONSTEXPR MoveOnly(MoveOnly &&) DEFINE_CTOR; MoveOnly &operator=(MoveOnly &&) DEFINE_ASSIGN; DEFINE_DTOR(MoveOnly) }; -struct CopyAssignable { - DEFINE_EXPLICIT CopyAssignable() = delete; - CopyAssignable& operator=(CopyAssignable const&) DEFINE_ASSIGN; - DEFINE_DTOR(CopyAssignable) +struct CopyAssignable : DEFINE_BASE(CopyAssignable) { + using Base = DEFINE_BASE(CopyAssignable); + using Base::Base; + DEFINE_EXPLICIT DEFINE_CONSTEXPR CopyAssignable() = delete; + CopyAssignable& operator=(CopyAssignable const&) DEFINE_ASSIGN; + DEFINE_DTOR(CopyAssignable) }; -struct CopyAssignOnly { - DEFINE_EXPLICIT CopyAssignOnly() = delete; - CopyAssignOnly& operator=(CopyAssignOnly const&) DEFINE_ASSIGN; - CopyAssignOnly& operator=(CopyAssignOnly &&) = delete; - DEFINE_DTOR(CopyAssignOnly) +struct CopyAssignOnly : DEFINE_BASE(CopyAssignOnly) { + using Base = DEFINE_BASE(CopyAssignOnly); + using Base::Base; + DEFINE_EXPLICIT DEFINE_CONSTEXPR CopyAssignOnly() = delete; + CopyAssignOnly& operator=(CopyAssignOnly const&) DEFINE_ASSIGN; + CopyAssignOnly& operator=(CopyAssignOnly &&) = delete; + DEFINE_DTOR(CopyAssignOnly) }; -struct MoveAssignOnly { - DEFINE_EXPLICIT MoveAssignOnly() = delete; - MoveAssignOnly& operator=(MoveAssignOnly const&) = delete; - MoveAssignOnly& operator=(MoveAssignOnly &&) DEFINE_ASSIGN; - DEFINE_DTOR(MoveAssignOnly) +struct MoveAssignOnly : DEFINE_BASE(MoveAssignOnly) { + using Base = DEFINE_BASE(MoveAssignOnly); + using Base::Base; + DEFINE_EXPLICIT DEFINE_CONSTEXPR MoveAssignOnly() = delete; + MoveAssignOnly& operator=(MoveAssignOnly const&) = delete; + MoveAssignOnly& operator=(MoveAssignOnly &&) DEFINE_ASSIGN; + DEFINE_DTOR(MoveAssignOnly) }; -struct ConvertingType { - DEFINE_EXPLICIT ConvertingType() DEFINE_CTOR; - DEFINE_EXPLICIT ConvertingType(ConvertingType const&) DEFINE_CTOR; - DEFINE_EXPLICIT ConvertingType(ConvertingType &&) DEFINE_CTOR; +struct ConvertingType : DEFINE_BASE(ConvertingType) { + using Base = DEFINE_BASE(ConvertingType); + using Base::Base; + DEFINE_EXPLICIT DEFINE_CONSTEXPR ConvertingType() DEFINE_DEFAULT_CTOR; + DEFINE_EXPLICIT DEFINE_CONSTEXPR ConvertingType(ConvertingType const&) DEFINE_CTOR; + DEFINE_EXPLICIT DEFINE_CONSTEXPR ConvertingType(ConvertingType &&) DEFINE_CTOR; ConvertingType& operator=(ConvertingType const&) DEFINE_ASSIGN; ConvertingType& operator=(ConvertingType &&) DEFINE_ASSIGN; template - DEFINE_EXPLICIT ConvertingType(Args&&...) {} + DEFINE_EXPLICIT DEFINE_CONSTEXPR ConvertingType(Args&&...) {} template ConvertingType& operator=(Arg&&) { return *this; } DEFINE_DTOR(ConvertingType) @@ -91,8 +142,10 @@ struct ConvertingType { template