diff --git a/libcxx/include/concepts b/libcxx/include/concepts --- a/libcxx/include/concepts +++ b/libcxx/include/concepts @@ -326,6 +326,14 @@ constructible_from<_Tp, const _Tp&> && convertible_to && constructible_from<_Tp, const _Tp> && convertible_to; +// [concepts.object] +template +concept movable = + is_object_v && + move_constructible && + assignable_from && + swappable; + // [concept.invocable] template concept invocable = requires(_Fn&& __fn, _Args&&... __args) { diff --git a/libcxx/test/std/concepts/object/movable.compile.pass.cpp b/libcxx/test/std/concepts/object/movable.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/concepts/object/movable.compile.pass.cpp @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// 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 movable = see below; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// Movable types +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); + +struct S {}; +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); +static_assert(std::movable); + +static_assert(std::movable >); +static_assert(std::movable >); +static_assert(std::movable >); +static_assert(std::movable >); +static_assert(std::movable > >); +static_assert(std::movable >); +static_assert(std::movable >); +static_assert(std::movable >); + +struct traditional_copy_assignment_only { + traditional_copy_assignment_only& + operator=(traditional_copy_assignment_only const&); +}; +static_assert(std::is_move_assignable_v); +static_assert(std::movable); + +// Not objects +static_assert(!std::movable); +static_assert(!std::movable); +static_assert(!std::movable); +static_assert(!std::movable); +static_assert(!std::movable); +static_assert(!std::movable); +static_assert(!std::movable); +static_assert(!std::movable); +static_assert(!std::movable); +static_assert(!std::movable); +static_assert(!std::movable); + +// Not move constructible or move assignable +static_assert(!std::movable); +static_assert(!std::movable >); +static_assert(!std::movable >); + +// T not move constructible +struct no_move_constructor { + no_move_constructor(no_move_constructor&&) = delete; +}; +static_assert(!std::movable); + +// T& not assignable from T +static_assert(!std::movable); +static_assert(!std::movable); + +struct no_move_assignment { + no_move_assignment& operator=(no_move_assignment&&) = delete; +}; +static_assert(!std::movable); + +struct mutable_copy_assignment { + mutable_copy_assignment& operator=(mutable_copy_assignment&); +}; +static_assert( + !std::assignable_from); +static_assert(!std::movable); + +struct const_move_constructor { + const_move_constructor& operator=(const_move_constructor&&) const; +}; +static_assert( + !std::assignable_from); +static_assert(!std::movable); + +struct derived_from_nonmovable : std::mutex {}; +static_assert(!std::movable); + +struct has_a_nonmovable { + std::mutex m; +}; +static_assert(!std::movable); + +// `move_constructible and assignable_from` implies `swappable`, +// so there's nothing to test for the case of non-swappable. + +int main(int, char**) { return 0; }