Index: libcxx/CMakeLists.txt =================================================================== --- libcxx/CMakeLists.txt +++ libcxx/CMakeLists.txt @@ -927,6 +927,7 @@ add_subdirectory(include) add_subdirectory(src) add_subdirectory(utils) +add_subdirectory(modules) set(LIBCXX_TEST_DEPS "cxx_experimental") Index: libcxx/modules/CMakeLists.txt =================================================================== --- /dev/null +++ libcxx/modules/CMakeLists.txt @@ -0,0 +1,35 @@ +set(LIBCXX_MODULES_CMAKEFILES_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/pcm.cache") + +set(STD_PARTITIONS_SOURCES + std-coroutine.cppm + std-type_traits.cppm + std-utility.cppm + std-vector.cppm + std-exception.cppm) + +file(GLOB STD_SOURCES "*.cppm") + +set_property(SOURCE ${STD_SOURCES} PROPERTY LANGUAGE CXX) + +add_target_flags_if_supported("-fmodules-cache-path=${LIBCXX_MODULES_CMAKEFILES_DIR}") + +add_library(std_partitions_objects OBJECT ${STD_PARTITIONS_SOURCES}) + +set(MODULES_COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS} -std=c++2b -pthread") + +set_target_properties(std_partitions_objects + PROPERTIES + LINKER_LANGUAGE CXX + COMPILE_FLAGS "${MODULES_COMPILE_FLAGS}" + LINK_FLAGS "${LIBCXX_LINK_FLAGS}") +file(GLOB_RECURSE LIBCXX_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../include/*) +target_include_directories(std_partitions_objects PRIVATE ${LIBCXX_GENERATED_INCLUDE_DIR}) +target_add_compile_flags_if_supported(std_partitions_objects PUBLIC -nostdinc++) + +add_library(std_modules STATIC $ std.cppm) +target_link_libraries(std_modules std_partitions_objects) +set_target_properties(std_modules + PROPERTIES + LINKER_LANGUAGE CXX + COMPILE_FLAGS "${MODULES_COMPILE_FLAGS}" + LINK_FLAGS "${LIBCXX_LINK_FLAGS}") Index: libcxx/modules/std-coroutine.cppm =================================================================== --- /dev/null +++ libcxx/modules/std-coroutine.cppm @@ -0,0 +1,14 @@ +module; +#include +export module std:coroutine; +export namespace std { + using std::coroutine_traits; + using std::coroutine_handle; + using std::operator==; + using std::operator<=>; + using std::noop_coroutine; + using std::suspend_never; + using std::suspend_always; + + using std::hash; +} Index: libcxx/modules/std-exception.cppm =================================================================== --- /dev/null +++ libcxx/modules/std-exception.cppm @@ -0,0 +1,17 @@ +module; +#include +export module std:exception; +export namespace std { + using std::exception; + using std::bad_exception; + using std::set_terminate; + using std::get_terminate; + using std::terminate; + using std::uncaught_exception; + using std::exception_ptr; + using std::current_exception; + using std::make_exception_ptr; + using std::nested_exception; + using std::throw_with_nested; + using std::rethrow_if_nested; +} Index: libcxx/modules/std-type_traits.cppm =================================================================== --- /dev/null +++ libcxx/modules/std-type_traits.cppm @@ -0,0 +1,277 @@ +module; +#include +export module std:type_traits; +export namespace std { + using std::integral_constant; + using std::true_type; + using std::false_type; + + // helper traits + using std::enable_if; + using std::conditional; + + // Primary classification traits: + using std::is_void; + using std::is_null_pointer; // C++14 + using std::is_integral; + using std::is_floating_point; + using std::is_array; + using std::is_pointer; + using std::is_lvalue_reference; + using std::is_rvalue_reference; + using std::is_member_object_pointer; + using std::is_member_function_pointer; + using std::is_enum; + using std::is_union; + using std::is_class; + using std::is_function; + + // Secondary classification traits: + using std::is_reference; + using std::is_arithmetic; + using std::is_fundamental; + using std::is_member_pointer; + using std::is_scoped_enum; // C++2b + using std::is_scalar; + using std::is_object; + using std::is_compound; + + // Const-volatile properties and transformations: + using std::is_const; + using std::is_volatile; + using std::remove_const; + using std::remove_volatile; + using std::remove_cv; + using std::add_const; + using std::add_volatile; + using std::add_cv; + + // Reference transformations: + using std::remove_reference; + using std::add_lvalue_reference; + using std::add_rvalue_reference; + + // Pointer transformations: + using std::remove_pointer; + using std::add_pointer; + + using std::type_identity; // C++20 + using std::type_identity_t; + + // Integral properties: + using std::is_signed; + using std::is_unsigned; + using std::make_signed; + using std::make_unsigned; + + // Array properties and transformations: + using std::rank; + using std::extent; + using std::remove_extent; + using std::remove_all_extents; + + using std::is_bounded_array; // C++20 + using std::is_unbounded_array; // C++20 + + // Member introspection: + using std::is_pod; + using std::is_trivial; + using std::is_trivially_copyable; + using std::is_standard_layout; + using std::is_empty; + using std::is_polymorphic; + using std::is_abstract; + using std::is_final; // C++14 + using std::is_aggregate; // C++17 + + using std::is_constructible; + using std::is_default_constructible; + using std::is_copy_constructible; + using std::is_move_constructible; + using std::is_assignable; + using std::is_copy_assignable; + using std::is_move_assignable; + using std::is_swappable_with; // C++17 + using std::is_swappable; // C++17 + using std::is_destructible; + + using std::is_trivially_constructible; + using std::is_trivially_default_constructible; + using std::is_trivially_copy_constructible; + using std::is_trivially_move_constructible; + using std::is_trivially_assignable; + using std::is_trivially_copy_assignable; + using std::is_trivially_move_assignable; + using std::is_trivially_destructible; + + using std::is_nothrow_constructible; + using std::is_nothrow_default_constructible; + using std::is_nothrow_copy_constructible; + using std::is_nothrow_move_constructible; + using std::is_nothrow_assignable; + using std::is_nothrow_copy_assignable; + using std::is_nothrow_move_assignable; + using std::is_nothrow_swappable_with; // C++17 + using std::is_nothrow_swappable; // C++17 + using std::is_nothrow_destructible; + + using std::has_virtual_destructor; + + using std::has_unique_object_representations; // C++17 + + // Relationships between types: + using std::is_same; + using std::is_base_of; + + using std::is_convertible; + using std::is_nothrow_convertible; // C++20 + using std::is_nothrow_convertible_v; // C++20 + + using std::is_invocable; + using std::is_invocable_r; + + using std::is_nothrow_invocable; + using std::is_nothrow_invocable_r; + + // Alignment properties and transformations: + using std::alignment_of; + using std::aligned_storage; + using std::aligned_union; + using std::remove_cvref; // C++20 + + using std::decay; + using std::common_type; + using std::underlying_type; + using std::invoke_result; // C++17 + + // const-volatile modifications: + using std::remove_const_t; + using std::remove_volatile_t; + using std::remove_cv_t; + using std::add_const_t; + using std::add_volatile_t; + using std::add_cv_t; + + // reference modifications: + using std::remove_reference_t; + using std::add_lvalue_reference_t; + using std::add_rvalue_reference_t; + + // sign modifications: + using std::make_signed_t; + using std::make_unsigned_t; + + // array modifications: + using std::remove_extent_t; + using std::remove_all_extents_t; + + using std::is_bounded_array_v; // C++20 + using std::is_unbounded_array_v; // C++20 + + // pointer modifications: + using std::remove_pointer_t; // C++14 + using std::add_pointer_t; // C++14 + + // other transformations: + using std::aligned_storage_t; // C++14 + using std::aligned_union_t; // C++14 + using std::remove_cvref_t; // C++20 + using std::decay_t; // C++14 + using std::enable_if_t; // C++14 + using std::conditional_t; // C++14 + using std::common_type_t; // C++14 + using std::underlying_type_t; + using std::invoke_result_t; + + using std::void_t; + + // See C++14 20.10.4.1, primary type categories + using std::is_void_v; + using std::is_null_pointer_v; + using std::is_integral_v; + using std::is_floating_point_v; + using std::is_array_v; + using std::is_pointer_v; + using std::is_lvalue_reference_v; + using std::is_rvalue_reference_v; + using std::is_member_object_pointer_v; + using std::is_member_function_pointer_v; + using std::is_enum_v; + using std::is_union_v; + using std::is_class_v; + using std::is_function_v; + + // See C++14 20.10.4.2, composite type categories + using std::is_reference_v; + using std::is_arithmetic_v; + using std::is_fundamental_v; + using std::is_object_v; + using std::is_scalar_v; + using std::is_compound_v; + using std::is_member_pointer_v; + using std::is_scoped_enum_v; + + // See C++14 20.10.4.3, type properties + using std::is_const_v; + using std::is_volatile_v; + using std::is_trivial_v; + using std::is_trivially_copyable_v; + using std::is_standard_layout_v; + using std::is_pod_v; + using std::is_empty_v; + using std::is_polymorphic_v; + using std::is_abstract_v; + using std::is_final_v; + using std::is_aggregate_v; + using std::is_signed_v; + using std::is_unsigned_v; + using std::is_constructible_v; + using std::is_default_constructible_v; + using std::is_copy_constructible_v; + using std::is_move_constructible_v; + using std::is_assignable_v; + using std::is_copy_assignable_v; + using std::is_move_assignable_v; + using std::is_swappable_with_v; + using std::is_swappable_v; + using std::is_destructible_v; + using std::is_trivially_constructible_v; + using std::is_trivially_default_constructible_v; + using std::is_trivially_copy_constructible_v; + using std::is_trivially_move_constructible_v; + using std::is_trivially_assignable_v; + using std::is_trivially_copy_assignable_v; + using std::is_trivially_move_assignable_v; + using std::is_trivially_destructible_v; + using std::is_nothrow_constructible_v; + using std::is_nothrow_default_constructible_v; + using std::is_nothrow_copy_constructible_v; + using std::is_nothrow_move_constructible_v; + using std::is_nothrow_assignable_v; + using std::is_nothrow_copy_assignable_v; + using std::is_nothrow_move_assignable_v; + using std::is_nothrow_swappable_with_v; + using std::is_nothrow_swappable_v; + using std::is_nothrow_destructible_v; + using std::has_virtual_destructor_v; + using std::has_unique_object_representations_v; // C++17; + + // See C++14 20.10.5, type property queries + using std::alignment_of_v; // C++17 + using std::rank_v; // C++17 + using std::extent_v; // C++17 + + // See C++14 20.10.6, type relations + using std::is_same_v; + using std::is_base_of_v; + using std::is_convertible_v; + using std::is_invocable_v; + using std::is_invocable_r_v; + using std::is_nothrow_invocable_v; + using std::is_nothrow_invocable_r_v; + + // [meta.logical], logical operator traits: // C++17 + using std::conjunction_v; + using std::disjunction_v; + using std::negation_v; +} Index: libcxx/modules/std-utility.cppm =================================================================== --- /dev/null +++ libcxx/modules/std-utility.cppm @@ -0,0 +1,56 @@ +module; +#include +export module std:utility; +export namespace std { + using std::swap; + + namespace rel_ops { + using rel_ops::operator!=; + using rel_ops::operator>; + using rel_ops::operator<=; + using rel_ops::operator>=; + } + + using std::forward; + using std::forward_like; + using std::move; + using std::move_if_noexcept; + using std::as_const; + using std::declval; + using std::cmp_equal; + using std::cmp_not_equal; // C++20 + using std::cmp_less; // C++20 + using std::cmp_greater; // C++20 + using std::cmp_less_equal; // C++20 + using std::cmp_greater_equal; // C++20 + using std::in_range; // C++20 + + using std::pair; + using std::operator==; + + using std::make_pair; + using std::piecewise_construct_t; + // FIXME: We can't export non-inline constexpr variables. + // using std::piecewise_construct; + + using std::tuple_size; + using std::tuple_element; + + using std::get; + using std::integer_sequence; + using std::index_sequence; + using std::make_index_sequence; + using std::make_integer_sequence; + using std::index_sequence_for; + + using std::exchange; + using std::in_place_t; + using std::in_place; + + using std::in_place_type_t; + using std::in_place_type; + using std::in_place_index_t; + + using std::in_place_index; + using std::to_underlying; +} Index: libcxx/modules/std-vector.cppm =================================================================== --- /dev/null +++ libcxx/modules/std-vector.cppm @@ -0,0 +1,15 @@ +module; +#include +export module std:vector; +export namespace std { + using std::vector; + using std::hash; + using std::swap; + using std::operator==; + using std::erase; + using std::erase_if; +} + +export { + using ::operator new; +} Index: libcxx/modules/std.cppm =================================================================== --- /dev/null +++ libcxx/modules/std.cppm @@ -0,0 +1,6 @@ +export module std; +export import :coroutine; +export import :type_traits; +export import :utility; +export import :vector; +export import :exception; Index: libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.capacity/operator_bool.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.capacity/operator_bool.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++20, c++20 +// UNSUPPORTED: libcpp-no-coroutines + +// + +// template +// struct coroutine_handle; + +// constexpr explicit operator bool() const noexcept + +// FIXME: How to get a better name than `%{lib}/../libcxx/modules/CMakeFiles/pcm.cache`? +// ADDITIONAL_COMPILE_FLAGS: -fmodules-cache-path=%{lib}/../libcxx/modules/CMakeFiles/pcm.cache -lstd_modules + +#include +#include "test_macros.h" +import std; + +template +constexpr bool do_test() { + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(!std::is_convertible::value, ""); + { + constexpr C c; + static_assert(bool(c) == false, ""); + } + { // null case + const C c = {}; + ASSERT_NOEXCEPT(bool(c)); + assert(c.address() == nullptr); + assert(bool(c) == false); + } + { // non-null case + char dummy = 42; + C c = C::from_address((void*)&dummy); + assert(c.address() == &dummy); + assert(bool(c) == true); + } + return true; +} + +int main(int, char**) +{ + do_test>(); + do_test>(); + static_assert(do_test>()); + static_assert(do_test>()); + + return 0; +} Index: libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++20 +// UNSUPPORTED: libcpp-no-coroutines + +// + +// template +// struct coroutine_handle; + +// constexpr bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept; +// FIXME: How to get a better name than `%{lib}/../libcxx/modules/CMakeFiles/pcm.cache`? +// ADDITIONAL_COMPILE_FLAGS: -fmodules-cache-path=%{lib}/../libcxx/modules/CMakeFiles/pcm.cache -lstd_modules + +#include +#include "test_macros.h" +import std; + +template +void do_test(int *LHSVal, int *RHSVal) { + const C LHS = C::from_address(LHSVal); + const C RHS = C::from_address(RHSVal); + const bool ExpectIsEqual = (LHSVal == RHSVal); + assert((LHS == RHS) == ExpectIsEqual); + assert((RHS == LHS) == ExpectIsEqual); + assert((LHS != RHS) == !ExpectIsEqual); + assert((RHS != LHS) == !ExpectIsEqual); + { + static_assert(noexcept(LHS == RHS), ""); + static_assert(noexcept(LHS != RHS), ""); + ASSERT_SAME_TYPE(decltype(LHS == RHS), bool); + ASSERT_SAME_TYPE(decltype(LHS != RHS), bool); + } +} + +int main(int, char**) +{ + int i; + std::pair const TestCases[] = { + {nullptr, nullptr}, + {&i, &i}, + {nullptr, &i}, + {&i, nullptr} + }; + for (auto& TC : TestCases) { + do_test>(TC.first, TC.second); + do_test>(TC.first, TC.second); + } + + return 0; +} Index: libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++20 +// UNSUPPORTED: libcpp-no-coroutines + +// + +// template +// struct coroutine_handle; + +// constexpr strong_ordering operator<=>(coroutine_handle<> x, coroutine_handle<> y) noexcept; + +// FIXME: How to get a better name than `%{lib}/../libcxx/modules/CMakeFiles/pcm.cache`? +// ADDITIONAL_COMPILE_FLAGS: -fmodules-cache-path=%{lib}/../libcxx/modules/CMakeFiles/pcm.cache -lstd_modules + +#include +#include "test_macros.h" +import std; + +template +void do_test(int *LHSVal, int *RHSVal) { + const C LHS = C::from_address(LHSVal); + const C RHS = C::from_address(RHSVal); + assert((LHS < RHS) == (LHSVal < RHSVal)); + assert((RHS < LHS) == (RHSVal < LHSVal)); + assert((LHS > RHS) == (LHSVal > RHSVal)); + assert((RHS > LHS) == (RHSVal > LHSVal)); + assert((LHS <= RHS) == (LHSVal <= RHSVal)); + assert((RHS <= LHS) == (RHSVal <= LHSVal)); + assert((LHS >= RHS) == (LHSVal >= RHSVal)); + assert((RHS >= LHS) == (RHSVal >= LHSVal)); + { + static_assert(noexcept(LHS < RHS), ""); + static_assert(noexcept(LHS > RHS), ""); + static_assert(noexcept(LHS <= RHS), ""); + static_assert(noexcept(LHS >= RHS), ""); + ASSERT_SAME_TYPE(decltype(LHS < RHS), bool); + ASSERT_SAME_TYPE(decltype(LHS > RHS), bool); + ASSERT_SAME_TYPE(decltype(LHS <= RHS), bool); + ASSERT_SAME_TYPE(decltype(LHS >= RHS), bool); + } +} + +int main(int, char**) +{ + int i; + std::pair const TestCases[] = { + {nullptr, nullptr}, + {&i, &i}, + {nullptr, &i}, + {&i, nullptr} + }; + for (auto& TC : TestCases) { + do_test>(TC.first, TC.second); + do_test>(TC.first, TC.second); + } + + return 0; +} Index: libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++20 +// UNSUPPORTED: libcpp-no-coroutines + +// + +// template +// struct coroutine_handle; + +// bool done() const + +// FIXME: How to get a better name than `%{lib}/../libcxx/modules/CMakeFiles/pcm.cache`? +// ADDITIONAL_COMPILE_FLAGS: -fmodules-cache-path=%{lib}/../libcxx/modules/CMakeFiles/pcm.cache -lstd_modules + +#include +#include "test_macros.h" +import std; + +template +void do_test(std::coroutine_handle const& H) { + // FIXME Add a runtime test + { + ASSERT_SAME_TYPE(decltype(H.done()), bool); + LIBCPP_ASSERT_NOT_NOEXCEPT(H.done()); + } +} + +int main(int, char**) +{ + do_test(std::coroutine_handle<>{}); + do_test(std::coroutine_handle{}); + + return 0; +} Index: libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/assign.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/assign.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++20 +// UNSUPPORTED: libcpp-no-coroutines + +// + +// template +// struct coroutine_handle; + +// coroutine_handle& operator=(nullptr_t) noexcept + +// FIXME: How to get a better name than `%{lib}/../libcxx/modules/CMakeFiles/pcm.cache`? +// ADDITIONAL_COMPILE_FLAGS: -fmodules-cache-path=%{lib}/../libcxx/modules/CMakeFiles/pcm.cache -lstd_modules + +#include +// For std::nullptr_t. We're not intentioned to implement std.comp yet. +#include +#include "test_macros.h" +import std; + +template +void do_test() { + int dummy = 42; + void* dummy_h = &dummy; + { + static_assert(std::is_nothrow_assignable::value, ""); + static_assert(!std::is_assignable::value, ""); + } + { + C c = C::from_address(dummy_h); + assert(c.address() == &dummy); + c = nullptr; + assert(c.address() == nullptr); + c = nullptr; + assert(c.address() == nullptr); + } + { + C c; + C& cr = (c = nullptr); + assert(&c == &cr); + } +} + +int main(int, char**) +{ + do_test>(); + do_test>(); + + return 0; +} Index: libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/construct.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/construct.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++20 +// UNSUPPORTED: libcpp-no-coroutines + +// + +// template +// struct coroutine_handle; + +// constexpr coroutine_handle() noexcept +// constexpr coroutine_handle(nullptr_t) noexcept + +// FIXME: How to get a better name than `%{lib}/../libcxx/modules/CMakeFiles/pcm.cache`? +// ADDITIONAL_COMPILE_FLAGS: -fmodules-cache-path=%{lib}/../libcxx/modules/CMakeFiles/pcm.cache -lstd_modules + +#include +// For std::nullptr_t. We're not intentioned to implement std.comp yet. +#include +#include "test_macros.h" +import std; + +template +constexpr bool do_test() { + static_assert(std::is_nothrow_constructible::value, ""); + static_assert(std::is_nothrow_constructible::value, ""); + { + C c; + assert(c.address() == nullptr); + } + { + C c = C(nullptr); + assert(c.address() == nullptr); + } + return true; +} + +int main(int, char**) +{ + do_test>(); + do_test>(); + static_assert(do_test>()); + static_assert(do_test>()); + + return 0; +} Index: libcxx/test/std_modules/language.support/support.coroutines/end.to.end/await_result.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std_modules/language.support/support.coroutines/end.to.end/await_result.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++20 +// UNSUPPORTED: libcpp-no-coroutines + +// FIXME: How to get a better name than `%{lib}/../libcxx/modules/CMakeFiles/pcm.cache`? +// ADDITIONAL_COMPILE_FLAGS: -fmodules-cache-path=%{lib}/../libcxx/modules/CMakeFiles/pcm.cache -lstd_modules + +#include +#include "test_macros.h" +import std; + +struct coro_t { + struct promise_type { + coro_t get_return_object() { + std::coroutine_handle{}; + return {}; + } + std::suspend_never initial_suspend() { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + void return_void() {} + static void unhandled_exception() {} + }; +}; + +struct B { + ~B() {} + bool await_ready() { return true; } + B await_resume() { return {}; } + template void await_suspend(F) {} +}; + + +struct A { + ~A() {} + bool await_ready() { return true; } + int await_resume() { return 42; } + template void await_suspend(F) {} +}; + +int last_value = -1; +void set_value(int x) { + last_value = x; +} + +coro_t f(int n) { + if (n == 0) { + set_value(0); + co_return; + } + int val = co_await A{}; + ((void)val); + set_value(42); +} + +coro_t g() { B val = co_await B{}; } + +int main(int, char**) { + last_value = -1; + f(0); + assert(last_value == 0); + f(1); + assert(last_value == 42); + + return 0; +} Index: libcxx/test/std_modules/language.support/support.coroutines/end.to.end/generator.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std_modules/language.support/support.coroutines/end.to.end/generator.pass.cpp @@ -0,0 +1,162 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++20 +// UNSUPPORTED: libcpp-no-coroutines + +// See https://llvm.org/PR33271 +// UNSUPPORTED: ubsan + +// FIXME: How to get a better name than `%{lib}/../libcxx/modules/CMakeFiles/pcm.cache`? +// ADDITIONAL_COMPILE_FLAGS: -fmodules-cache-path=%{lib}/../libcxx/modules/CMakeFiles/pcm.cache -lstd_modules + +#include +#include "test_macros.h" +import std; + +template struct generator { + struct promise_type { + Ty current_value; + std::suspend_always yield_value(Ty value) { + this->current_value = value; + return {}; + } + std::suspend_always initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + generator get_return_object() { return generator{this}; }; + void return_void() {} + void unhandled_exception() {} + }; + + struct iterator { + std::coroutine_handle Coro_; + bool Done_; + + iterator(std::coroutine_handle Coro, bool Done) + : Coro_(Coro), Done_(Done) {} + + iterator &operator++() { + Coro_.resume(); + Done_ = Coro_.done(); + return *this; + } + + bool operator==(iterator const &_Right) const { + return Done_ == _Right.Done_; + } + + bool operator!=(iterator const &_Right) const { return !(*this == _Right); } + + Ty const &operator*() const { return Coro_.promise().current_value; } + + Ty const *operator->() const { return &(operator*()); } + }; + + iterator begin() { + p.resume(); + return {p, p.done()}; + } + + iterator end() { return {p, true}; } + + generator(generator &&rhs) : p(rhs.p) { rhs.p = nullptr; } + + ~generator() { + if (p) + p.destroy(); + } + +private: + explicit generator(promise_type *promise) + : p(std::coroutine_handle::from_promise(*promise)) {} + + std::coroutine_handle p; +}; + +struct minig { + struct promise_type { + int current_value; + std::suspend_always yield_value(int value) { + this->current_value = value; + return {}; + } + std::suspend_always initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + minig get_return_object() { return minig{this}; }; + void return_void() {} + void unhandled_exception() {} + }; + + bool move_next() { + p.resume(); + return !p.done(); + } + int current_value() { return p.promise().current_value; } + + minig(minig &&rhs) : p(rhs.p) { rhs.p = nullptr; } + + ~minig() { + if (p) + p.destroy(); + } + +private: + explicit minig(promise_type *promise) + : p(std::coroutine_handle::from_promise(*promise)) {} + + std::coroutine_handle p; +}; + + +minig mini_count(int n) { + for (int i = 0; i < n; i++) { + co_yield i; + } +} + +generator count(int n) { + for (int i = 0; i < n; ++i) + co_yield i; +} + +generator range(int from, int n) { + for (int i = from; i < n; ++i) + co_yield i; +} + +void test_count() { + const std::vector expect = {0, 1, 2, 3, 4}; + std::vector got; + for (auto x : count(5)) + got.push_back(x); + assert(expect == got); +} + +void test_range() { + int sum = 0; + for (auto v: range(1, 20)) + sum += v; + assert(sum == 190); +} + +void test_mini_generator() { + int sum = 0; + auto g = mini_count(5); + while (g.move_next()) { + sum += g.current_value(); + } + assert(sum == 10); +} + +int main(int, char**) { + test_count(); + test_range(); + test_mini_generator(); + + return 0; +} Index: libcxx/test/std_modules/language.support/support.exception/propagation/current_exception.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std_modules/language.support/support.exception/propagation/current_exception.pass.cpp @@ -0,0 +1,280 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// FIXME: This test needs to be rewritten for the MSVC exception_ptr semantics +// which copy the exception each time the exception_ptr is copied. +// XFAIL: msvc + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: no-exceptions +// + +// exception_ptr current_exception(); + +// FIXME: How to get a better name than `%{lib}/../libcxx/modules/CMakeFiles/pcm.cache`? +// ADDITIONAL_COMPILE_FLAGS: -fmodules-cache-path=%{lib}/../libcxx/modules/CMakeFiles/pcm.cache -lstd_modules + +#include +#include "test_macros.h" +import std; + +struct A +{ + static int constructed; + + A() {++constructed;} + ~A() {--constructed;} + A(const A&) {++constructed;} +}; + +int A::constructed = 0; + +int main(int, char**) +{ + { + std::exception_ptr p = std::current_exception(); + assert(p == nullptr); + } + { + try + { + assert(A::constructed == 0); + throw A(); + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + } + assert(A::constructed == 0); + } + assert(A::constructed == 0); + { + std::exception_ptr p2; + try + { + assert(A::constructed == 0); + throw A(); + assert(false); + } + catch (...) + { + std::exception_ptr p = std::current_exception(); + assert(A::constructed == 1); + assert(p != nullptr); + p2 = std::current_exception(); + assert(A::constructed == 1); + assert(p == p2); + } + assert(A::constructed == 1); + } + assert(A::constructed == 0); + { + std::exception_ptr p2; + try + { + assert(A::constructed == 0); + throw A(); + assert(false); + } + catch (A&) + { + std::exception_ptr p = std::current_exception(); + assert(A::constructed == 1); + assert(p != nullptr); + p2 = std::current_exception(); + assert(A::constructed == 1); + assert(p == p2); + } + assert(A::constructed == 1); + } + assert(A::constructed == 0); + { + std::exception_ptr p2; + try + { + assert(A::constructed == 0); + throw A(); + assert(false); + } + catch (A) + { + std::exception_ptr p = std::current_exception(); + assert(A::constructed == 2); + assert(p != nullptr); + p2 = std::current_exception(); + assert(A::constructed == 2); + assert(p == p2); + } + assert(A::constructed == 1); + } + assert(A::constructed == 0); + { + try + { + assert(A::constructed == 0); + throw A(); + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + try + { + assert(A::constructed == 1); + throw; + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + } + assert(A::constructed == 1); + } + assert(A::constructed == 0); + } + assert(A::constructed == 0); + { + try + { + assert(A::constructed == 0); + throw A(); + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + try + { + std::exception_ptr p = std::current_exception(); + assert(A::constructed == 1); + assert(p != nullptr); + throw; + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + } + assert(A::constructed == 1); + } + assert(A::constructed == 0); + } + assert(A::constructed == 0); + { + try + { + assert(A::constructed == 0); + throw A(); + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + try + { + assert(A::constructed == 1); + throw; + assert(false); + } + catch (...) + { + std::exception_ptr p = std::current_exception(); + assert(A::constructed == 1); + assert(p != nullptr); + } + assert(A::constructed == 1); + } + assert(A::constructed == 0); + } + assert(A::constructed == 0); + { + try + { + assert(A::constructed == 0); + throw A(); + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + try + { + assert(A::constructed == 1); + throw; + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + } + std::exception_ptr p = std::current_exception(); + assert(A::constructed == 1); + assert(p != nullptr); + } + assert(A::constructed == 0); + } + assert(A::constructed == 0); + { + try + { + assert(A::constructed == 0); + throw A(); + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + try + { + assert(A::constructed == 1); + throw; + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + } + assert(A::constructed == 1); + } + std::exception_ptr p = std::current_exception(); + assert(A::constructed == 0); + assert(p == nullptr); + } + assert(A::constructed == 0); + { + std::exception_ptr p; + try + { + assert(A::constructed == 0); + throw A(); + assert(false); + } + catch (...) + { + assert(A::constructed == 1); + try + { + assert(A::constructed == 1); + throw; + assert(false); + } + catch (...) + { + p = std::current_exception(); + assert(A::constructed == 1); + } + assert(A::constructed == 1); + } + assert(A::constructed == 1); + assert(p != nullptr); + } + assert(A::constructed == 0); + + return 0; +}