diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -105,6 +105,10 @@ the shared library they shipped should turn this on and see `include/__availability` for more details." OFF) option(LIBCXX_ENABLE_CLANG_TIDY "Whether to compile and run clang-tidy checks" OFF) +option(LIBCXX_ENABLE_STD_MODULE + "Whether to enable the building the C++23 std module. This feature is experimental + and far from usable. Only enable this when interested in testing and developing + this module." OFF) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-gcc.cfg.in") @@ -401,6 +405,9 @@ # TODO: Projects that depend on libc++ should use LIBCXX_GENERATED_INCLUDE_DIR # instead of hard-coding include/c++/v1. +# TODO: The LIBCXX_GENERATED_MODULE_DIR is a placeholder. A proper directory +# needs to be determined. Maybe look at how other library vendors tackle this. + set(LIBCXX_INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}/c++/v1" CACHE PATH "Path where target-agnostic libc++ headers should be installed.") set(LIBCXX_INSTALL_RUNTIME_DIR "${CMAKE_INSTALL_BINDIR}" CACHE PATH @@ -412,6 +419,7 @@ if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) set(LIBCXX_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE}) set(LIBCXX_GENERATED_INCLUDE_DIR "${LLVM_BINARY_DIR}/include/c++/v1") + set(LIBCXX_GENERATED_MODULE_DIR "${LLVM_BINARY_DIR}/include/c++/modules") set(LIBCXX_GENERATED_INCLUDE_TARGET_DIR "${LLVM_BINARY_DIR}/include/${LLVM_DEFAULT_TARGET_TRIPLE}/c++/v1") set(LIBCXX_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE} CACHE PATH "Path where built libc++ libraries should be installed.") @@ -425,9 +433,11 @@ if(LLVM_LIBRARY_OUTPUT_INTDIR) set(LIBCXX_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) set(LIBCXX_GENERATED_INCLUDE_DIR "${LLVM_BINARY_DIR}/include/c++/v1") + set(LIBCXX_GENERATED_MODULE_DIR "${LLVM_BINARY_DIR}/include/c++/modules") else() set(LIBCXX_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXX_LIBDIR_SUFFIX}) set(LIBCXX_GENERATED_INCLUDE_DIR "${CMAKE_BINARY_DIR}/include/c++/v1") + set(LIBCXX_GENERATED_MODULE_DIR "${CMAKE_BINARY_DIR}/include/c++/modules") endif() set(LIBCXX_GENERATED_INCLUDE_TARGET_DIR "${LIBCXX_GENERATED_INCLUDE_DIR}") set(LIBCXX_INSTALL_LIBRARY_DIR lib${LIBCXX_LIBDIR_SUFFIX} CACHE PATH @@ -913,6 +923,9 @@ add_subdirectory(include) add_subdirectory(src) add_subdirectory(utils) +if (LIBCXX_ENABLE_STD_MODULE) + add_subdirectory(stdmodules) +endif() set(LIBCXX_TEST_DEPS "cxx_experimental") @@ -924,6 +937,10 @@ list(APPEND LIBCXX_TEST_DEPS cxx-tidy) endif() +if (LIBCXX_ENABLE_STD_MODULE) + list(APPEND LIBCXX_TEST_DEPS generate-cxx-modules) +endif() + if (LIBCXX_INCLUDE_BENCHMARKS) add_subdirectory(benchmarks) endif() diff --git a/libcxx/docs/Modules.rst b/libcxx/docs/Modules.rst new file mode 100644 --- /dev/null +++ b/libcxx/docs/Modules.rst @@ -0,0 +1,116 @@ +.. _ModulesInLibcxx: + +================= +Modules in libc++ +================= + +This page contains information regarding C++23 module support in libc++. +There are two kinds of modules available in Clang + + * `Clang specific modules `_ + * `C++ modules `_ + +This page mainly discusses the C++ modules. In C++ there are also header units, +these are not in this patch. + +This information is mainly to describe some of the features of this work in +progress patch. It is not intended to be committed in this form. + +Overview +======== + +The module sources are stored in ``.cppm`` files. These need to be available as +BMIs, which are ``.pcm`` files for Clang. These files are not portable, they +depend on the compiler used and its compilation flags. Therefore there needs to +be a way to distribute the ``.cppm`` files to the user and offer a way for them +to build and use the ``.pcm`` files. + +Some of the current limitations: + + * For now everything requires CMake. + * The files are not installed, but available in the build tree. + * The ``pcm`` files are regenerated when running a ``lit`` invocation. + * There is no Buildkite CI job yet. + * All tests need to be modified for modules, this can be done with a tool. + * The ``std`` module is incomplete. + * There is no ``std.compat`` module. + * Requires CMake 3.26 (soon to be released) + * Requires Ninja 1.11 + * Requires Clang 17 (Clang 16 should work, but is not tested) + * The path to the compiler may not be a symlink, ``clang-scan-deps`` does + not handle that case properly. + * There is no `P1689 style output `_ yet. + The file generated by clang-scan-deps contains absolute paths to the files + in the libc++ build directory. (These should be relative paths or paths to + the installation directory.) + +What works: + + * Building BMIs + * Running tests using modules + * Using the ``std`` module in external projects + +Discussion points: + + * The ``std`` module is a C++23 feature, currently it's available in both + ``C++20`` and ``C++23``. The simple reason is that this allows testing with + different language versions. (This will be needed once the first ``C++26`` + features become available.) Does libc++ want to retroactively supply the + module in ``C++23`` or restrict it to ``C++23`` and later? + * Do we want the feature behind a configuration flag or not? Louis already + mentioned he prefers it generally available. Then we need to restrict it on + the CMake version used. + * I'm not too unhappy with the generic approach for user project. I am quite + unhappy with how we need to do tests. I have some ideas how we can improve + this, basically by caching multiple configurations. However it would be good + to discuss that approach before spending effort in it. + * Currently the ``.cppm`` file and the generated ``CMakeLists.txt`` are not + installed. Before doing that it would be good to determine what the best + location for these files is. + +Running tests +============= + +In order to run the tests with C++23 modules the libc++ needs to be build with +the following configuration option in CMake ``LIBCXX_ENABLE_STD_MODULE``. + +The tests are executed like + +.. code-block:: bash + + $ /bin/llvm-lit -sv libcxx/test/std/containers # Run the tests without modules + $ /bin/llvm-lit -sv -Denable_modules=clang libcxx/test/std/containers # Run the tests with Clang modules + $ /bin/llvm-lit -sv -Denable_modules=c++ libcxx/test/std/containers # Run the tests with Standard modules + +The Clang modules are the modules that have been available for many libc++ releases. +The Standard modules are the new feature. + +Using in external projects +========================== + +Users need to be able to build their own BMI files. Currently this requires a +local build of libc++ with modules enabled. "Importing" libc++ is a project can +be done with the following CMake code. + +.. code-block:: cmake + + include(FetchContent) + FetchContent_Declare( + std + URL file:///include/c++/modules/ + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + FetchContent_GetProperties(std) + if(NOT std_POPULATED) + # The C++ version used in your project must match the version used here. + set(CMAKE_CXX_STANDARD 23) + # These compiler flags must match the flags used in your project. + # When they don't match the generated BMIs can't be used in your project. + set(CMAKE_CXX_FLAGS "-fexperimental-library") + FetchContent_Populate(std) + add_subdirectory(${std_SOURCE_DIR} ${std_BINARY_DIR} EXCLUDE_FROM_ALL) + endif() + +The libraries and/or executables that use the ``std`` module need to link +against the ``std`` library. This is needed for CMake to get the proper module +dependencies. diff --git a/libcxx/docs/index.rst b/libcxx/docs/index.rst --- a/libcxx/docs/index.rst +++ b/libcxx/docs/index.rst @@ -39,6 +39,7 @@ BuildingLibcxx TestingLibcxx Contributing + Modules Status/Cxx14 Status/Cxx17 Status/Cxx20 diff --git a/libcxx/stdmodules/.clang-format b/libcxx/stdmodules/.clang-format new file mode 100644 --- /dev/null +++ b/libcxx/stdmodules/.clang-format @@ -0,0 +1,3 @@ +BasedOnStyle: InheritParentConfig + +NamespaceIndentation: All diff --git a/libcxx/stdmodules/CMakeLists.txt b/libcxx/stdmodules/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libcxx/stdmodules/CMakeLists.txt @@ -0,0 +1,26 @@ +set(LIBCXX_MODULE_SOURCES + std-coroutine.cppm + std-exception.cppm + std-format.cppm + std-type_traits.cppm + std-utility.cppm + std-vector.cppm + std.cppm +) +configure_file("CMakeLists.txt.in" "${LIBCXX_GENERATED_MODULE_DIR}/CMakeLists.txt" @ONLY) + +set(_all_modules "${LIBCXX_GENERATED_MODULE_DIR}/CMakeLists.txt") +foreach(f ${LIBCXX_MODULE_SOURCES}) + set(src "${CMAKE_CURRENT_SOURCE_DIR}/${f}") + set(dst "${LIBCXX_GENERATED_MODULE_DIR}/${f}") + add_custom_command(OUTPUT ${dst} + DEPENDS ${src} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst} + COMMENT "Copying CXX module ${f}") + list(APPEND _all_modules "${dst}") +endforeach() + +add_custom_target(generate-cxx-modules + ALL DEPENDS + ${_all_modules} +) diff --git a/libcxx/stdmodules/CMakeLists.txt.in b/libcxx/stdmodules/CMakeLists.txt.in new file mode 100644 --- /dev/null +++ b/libcxx/stdmodules/CMakeLists.txt.in @@ -0,0 +1,40 @@ +# CMake 3.25 has modules support, but that does not work properly. +cmake_minimum_required(VERSION 3.26) + +project(libc++-std LANGUAGES CXX) + +# CMake specific magic +# In the future this probably is not needed and will be part of CMake itself. + +set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a") +set(CMake_TEST_CXXModules_UUID "a246741c-d067-4019-a8fb-3d16b0c9d1d3") + +set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) +string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE + "${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}" + " -format=p1689" + " --" + " " + " -x c++ -c -o " + " -MT " + " -MD -MF " + " > ") +set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "clang") +set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "@") + +# Default to C++ extensions being off. Clang's modules support have trouble +# with extensions right now. +set(CMAKE_CXX_EXTENSIONS OFF) + +add_library(std) +target_sources(std + PUBLIC + FILE_SET cxx_modules TYPE CXX_MODULES FILES +@LIBCXX_MODULE_SOURCES@ +) + +target_compile_options(std + PUBLIC + -stdlib=libc++ + @LIBCXX_COMPILE_FLAGS@ +) diff --git a/libcxx/stdmodules/std-coroutine.cppm b/libcxx/stdmodules/std-coroutine.cppm new file mode 100644 --- /dev/null +++ b/libcxx/stdmodules/std-coroutine.cppm @@ -0,0 +1,25 @@ +# 1 __FILE__ 1 3 +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +module; +#include +#include +export module std:coroutine; +export namespace std { + using std::coroutine_handle; + using std::coroutine_traits; + using std::operator==; + using std::operator<=>; + using std::noop_coroutine; + using std::suspend_always; + using std::suspend_never; + + using std::hash; +} // namespace std diff --git a/libcxx/stdmodules/std-exception.cppm b/libcxx/stdmodules/std-exception.cppm new file mode 100644 --- /dev/null +++ b/libcxx/stdmodules/std-exception.cppm @@ -0,0 +1,27 @@ +# 1 __FILE__ 1 3 +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +module; +#include +export module std:exception; +export namespace std { + using std::bad_exception; + using std::current_exception; + using std::exception; + using std::exception_ptr; + using std::get_terminate; + using std::make_exception_ptr; + using std::nested_exception; + using std::rethrow_if_nested; + using std::set_terminate; + using std::terminate; + using std::throw_with_nested; + using std::uncaught_exception; +} // namespace std diff --git a/libcxx/stdmodules/std-format.cppm b/libcxx/stdmodules/std-format.cppm new file mode 100644 --- /dev/null +++ b/libcxx/stdmodules/std-format.cppm @@ -0,0 +1,460 @@ +# 1 __FILE__ 1 3 +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// TODO This file is two-fold +// - look at how we want to integrate a synopsis +// - test whether the experimental library works properly + +module; +#include // Since C++20 + +export module std:format; +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT) +export namespace std { + + // [format.context], class template basic_format_context + // template + // class basic_format_context; + using std::basic_format_context; + /* + template + class basic_format_context { + basic_format_args args_; // exposition only + Out out_; // exposition only + + public: + using iterator = Out; + using char_type = charT; + template using formatter_type = formatter; + + basic_format_arg arg(size_t id) const noexcept; + std::locale locale(); + + iterator out(); + void advance_to(iterator it); + }; + */ + // using format_context = basic_format_context; + // using wformat_context = basic_format_context; + using std::format_context; + using std::wformat_context; + + // [format.args], class template basic_format_args + // template + // class basic_format_args; + using std::basic_format_args; + /* + template + class basic_format_args { + size_t size_; // exposition only + const basic_format_arg* data_; // exposition only + + public: + basic_format_args() noexcept; + + template + basic_format_args(const format-arg-store& store) noexcept; + + basic_format_arg get(size_t i) const noexcept; + }; + */ + // using format_args = basic_format_args; + // using wformat_args = basic_format_args; + using std::format_args; + using std::wformat_args; + + // [format.fmt.string], class template basic_format_string + // template + // struct basic_format_string; + using std::basic_format_string; + + // template + // using format_string = basic_format_string...>; + // template + // using wformat_string = basic_format_string...>; + using std::format_string; + using std::wformat_string; + + // [format.functions], formatting functions + // template + // string format(format_string fmt, Args&&... args); + // template + // wstring format(wformat_string fmt, Args&&... args); + // template + // string format(const locale& loc, format_string fmt, Args&&... args); + // template + // wstring format(const locale& loc, wformat_string fmt, Args&&... args); + using std::format; + + // string vformat(string_view fmt, format_args args); + // wstring vformat(wstring_view fmt, wformat_args args); + // string vformat(const locale& loc, string_view fmt, format_args args); + // wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); + using std::vformat; + + // template + // Out format_to(Out out, format_string fmt, Args&&... args); + // template + // Out format_to(Out out, wformat_string fmt, Args&&... args); + // template + // Out format_to(Out out, const locale& loc, format_string fmt, Args&&... args); + // template + // Out format_to(Out out, const locale& loc, wformat_string fmt, Args&&... args); + using std::format_to; + + // template + // Out vformat_to(Out out, string_view fmt, format_args args); + // template + // Out vformat_to(Out out, wstring_view fmt, wformat_args args); + // template + // Out vformat_to(Out out, const locale& loc, string_view fmt, format_args args); + // template + // Out vformat_to(Out out, const locale& loc, wstring_view fmt, wformat_args args); + using std::vformat_to; + + // template + // struct format_to_n_result { + // Out out; + // iter_difference_t size; + // }; + using std::format_to_n_result; + // template + // format_to_n_result format_to_n(Out out, iter_difference_t n, format_string fmt, Args&&... args); + // template + // format_to_n_result format_to_n(Out out, iter_difference_t n, wformat_string fmt, Args&&... + // args); template format_to_n_result format_to_n(Out out, iter_difference_t n, + // const locale& loc, format_string fmt, Args&&... args); template + // format_to_n_result + // format_to_n(Out out, iter_difference_t n, const locale& loc, wformat_string fmt, Args&&... args); + using std::format_to_n; + + // template + // size_t formatted_size(format_string fmt, Args&&... args); + // template + // size_t formatted_size(wformat_string fmt, Args&&... args); + // template + // size_t formatted_size(const locale& loc, format_string fmt, Args&&... args); + // template + // size_t formatted_size(const locale& loc, wformat_string fmt, Args&&... args); + using std::formatted_size; + + // [format.formatter], formatter + // template + // struct formatter; + using std::formatter; + + // [format.formattable], concept formattable + // template + // concept formattable = see below; // Since C++23 + using std::formattable; + + // template + // concept const-formattable-range = // exposition only + // ranges::input_range && formattable, charT>; + + // template + // using fmt-maybe-const = // exposition only + // conditional_t, const R, R>; + + // [format.parse.ctx], class template basic_format_parse_context + // template a + // class basic_format_parse_context; + using std::basic_format_parse_context; + + /* + template + class basic_format_parse_context { + public: + using char_type = charT; + using const_iterator = typename basic_string_view::const_iterator; + using iterator = const_iterator; + + private: + iterator begin_; // exposition only + iterator end_; // exposition only + enum indexing { unknown, manual, automatic }; // exposition only + indexing indexing_; // exposition only + size_t next_arg_id_; // exposition only + size_t num_args_; // exposition only + + public: + constexpr explicit basic_format_parse_context(basic_string_view fmt, + size_t num_args = 0) noexcept; + basic_format_parse_context(const basic_format_parse_context&) = delete; + basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; + + constexpr const_iterator begin() const noexcept; + constexpr const_iterator end() const noexcept; + constexpr void advance_to(const_iterator it); + + constexpr size_t next_arg_id(); + constexpr void check_arg_id(size_t id); + }; + */ + + // using format_parse_context = basic_format_parse_context; + // using wformat_parse_context = basic_format_parse_context; + using std::format_parse_context; + using std::wformat_parse_context; + + // [format.range], formatting of ranges + // [format.range.fmtkind], variable template format_kind + // enum class range_format { disabled, map, set, sequence, string, debug_string }; // Since C++23 + using std::range_format; + + // template + // constexpr unspecified format_kind = unspecified; + using std::format_kind; + + // template + // requires same_as> + // constexpr range_format format_kind = see below; + using std::format_kind; + + // [format.range.formatter], class template range_formatter + // template + // requires same_as, T> && formattable + // class range_formatter; + using std::range_formatter; + + /* + template + requires same_­as, T> && formattable + class range_formatter { + formatter underlying_; // exposition only + basic_string_view separator_ = STATICALLY-WIDEN(", "); // exposition only + basic_string_view opening-bracket_ = STATICALLY-WIDEN("["); // exposition only + basic_string_view closing-bracket_ = STATICALLY-WIDEN("]"); // exposition only + + public: + constexpr void set_separator(basic_string_view sep); + constexpr void set_brackets(basic_string_view opening, + basic_string_view closing); + constexpr formatter& underlying() { return underlying_; } + constexpr const formatter& underlying() const { return underlying_; } + + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + requires formattable, charT> && + same_­as>, T> + typename FormatContext::iterator + format(R&& r, FormatContext& ctx) const; + }; + */ + + // [format.range.fmtdef], class template range-default-formatter + // template + // struct range-default-formatter; // exposition only + /* + template + struct range-default-formatter { // exposition only + private: + using maybe-const-r = fmt-maybe-const; // exposition only + range_formatter>, + charT> underlying_; // exposition only + + public: + constexpr void set_separator(basic_string_view sep); + constexpr void set_brackets(basic_string_view opening, + basic_string_view closing); + + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(maybe-const-r& elems, FormatContext& ctx) const; + }; + */ + + // [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr], specializations for maps, sets, and strings + /* + template // Since C++23 + struct range-default-formatter { + private: + using maybe-const-map = fmt-maybe-const; // exposition only + using element-type = // exposition only + remove_cvref_t>; + range_formatter underlying_; // exposition only + + public: + constexpr range-default-formatter(); + + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(maybe-const-map& r, FormatContext& ctx) const; + }; + + template + struct range-default-formatter { // Since C++23 + private: + using maybe-const-set = fmt-maybe-const; // exposition only + range_formatter>, + charT> underlying_; // exposition only + + public: + constexpr range-default-formatter(); + + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(maybe-const-set& r, FormatContext& ctx) const; + }; + + template + requires (K == range_format::string || K == range_format::debug_string) + struct range-default-formatter { // Since C++23 + private: + formatter, charT> underlying_; // exposition only + + public: + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(see below& str, FormatContext& ctx) const; + }; + */ + // template + // requires(format_kind != range_format::disabled) && + // formattable, charT> + // struct formatter : range-default-formatter, R, charT> {}; + + // [format.arguments], arguments + // [format.arg], class template basic_format_arg + // template + // class basic_format_arg; + using std::basic_format_arg; + + /* + template + class basic_format_arg { + public: + class handle; + + private: + using char_type = typename Context::char_type; // exposition only + + variant, + const void*, handle> value; // exposition only + + template explicit basic_format_arg(T&& v) noexcept; // exposition only + explicit basic_format_arg(float n) noexcept; // exposition only + explicit basic_format_arg(double n) noexcept; // exposition only + explicit basic_format_arg(long double n) noexcept; // exposition only + explicit basic_format_arg(const char_type* s); // exposition only + + template + explicit basic_format_arg( + basic_string_view s) noexcept; // exposition only + + template + explicit basic_format_arg( + const basic_string& s) noexcept; // exposition only + + explicit basic_format_arg(nullptr_t) noexcept; // exposition only + + template + explicit basic_format_arg(T* p) noexcept; // exposition only + + public: + basic_format_arg() noexcept; + + explicit operator bool() const noexcept; + }; + + template + class basic_format_arg::handle { + const void* ptr_; // exposition only + void (*format_)(basic_format_parse_context&, + Context&, const void*); // exposition only + + template explicit handle(T&& val) noexcept; // exposition only + + friend class basic_format_arg; // exposition only + + public: + void format(basic_format_parse_context&, Context& ctx) const; + }; + */ + + // template + // decltype(auto) visit_format_arg(Visitor&& vis, basic_format_arg arg); + using std::visit_format_arg; + + // [format.arg.store], class template format-arg-store + // template + // class format-arg-store; // exposition only + /* + template + class format-arg-store { // exposition only + array, sizeof...(Args)> args; // exposition only + }; + */ + + // template + // format-arg-store make_format_args(Args&&... fmt_args); + // template + // format-arg-store make_wformat_args(Args&&... args); + using std::make_format_args; + using std::make_wformat_args; + + // [format.error], class format_error + // class format_error; + using std::format_error; + /* + class format_error : public runtime_error { + public: + explicit format_error(const string& what_arg); + explicit format_error(const char* what_arg); + }; + */ + + /* + template... Ts> + struct formatter, charT> { // Since C++23 + private: + tuple, charT>...> underlying_; // exposition only + basic_string_view separator_ = STATICALLY-WIDEN(", "); // exposition only + basic_string_view opening-bracket_ = STATICALLY-WIDEN("("); // exposition only + basic_string_view closing-bracket_ = STATICALLY-WIDEN(")"); // exposition only + + public: + constexpr void set_separator(basic_string_view sep); + constexpr void set_brackets(basic_string_view opening, + basic_string_view closing); + + template + constexpr typename ParseContext::iterator + parse(ParseContext& ctx); + + template + typename FormatContext::iterator + format(see below& elems, FormatContext& ctx) const; + }; + */ +} // namespace std +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT) diff --git a/libcxx/stdmodules/std-type_traits.cppm b/libcxx/stdmodules/std-type_traits.cppm new file mode 100644 --- /dev/null +++ b/libcxx/stdmodules/std-type_traits.cppm @@ -0,0 +1,292 @@ +# 1 __FILE__ 1 3 +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +module; +#include +export module std:type_traits; +export namespace std { + using std::false_type; + using std::integral_constant; + using std::true_type; + + // helper traits + using std::conditional; + using std::enable_if; + + // Primary classification traits: + using std::is_array; + using std::is_class; + using std::is_enum; + using std::is_floating_point; + using std::is_function; + using std::is_integral; + using std::is_lvalue_reference; + using std::is_member_function_pointer; + using std::is_member_object_pointer; + using std::is_null_pointer; // C++14 + using std::is_pointer; + using std::is_rvalue_reference; + using std::is_union; + using std::is_void; + + // Secondary classification traits: + using std::is_arithmetic; + using std::is_compound; + using std::is_fundamental; + using std::is_member_pointer; + using std::is_object; + using std::is_reference; + using std::is_scalar; +#if _LIBCPP_STD_VER >= 23 // TODO Do we want to provide std module in C++20 + using std::is_scoped_enum; // C++2b +#endif + + // Const-volatile properties and transformations: + using std::add_const; + using std::add_cv; + using std::add_volatile; + using std::is_const; + using std::is_volatile; + using std::remove_const; + using std::remove_cv; + using std::remove_volatile; + + // Reference transformations: + using std::add_lvalue_reference; + using std::add_rvalue_reference; + using std::remove_reference; + + // Pointer transformations: + using std::add_pointer; + using std::remove_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::extent; + using std::rank; + using std::remove_all_extents; + using std::remove_extent; + + using std::is_bounded_array; // C++20 + using std::is_unbounded_array; // C++20 + + // Member introspection: + using std::is_abstract; + using std::is_aggregate; // C++17 + using std::is_empty; + using std::is_final; // C++14 + using std::is_pod; + using std::is_polymorphic; + using std::is_standard_layout; + using std::is_trivial; + using std::is_trivially_copyable; + + using std::is_assignable; + using std::is_constructible; + using std::is_copy_assignable; + using std::is_copy_constructible; + using std::is_default_constructible; + using std::is_destructible; + using std::is_move_assignable; + using std::is_move_constructible; + using std::is_swappable; // C++17 + using std::is_swappable_with; // C++17 + + using std::is_trivially_assignable; + using std::is_trivially_constructible; + using std::is_trivially_copy_assignable; + using std::is_trivially_copy_constructible; + using std::is_trivially_default_constructible; + using std::is_trivially_destructible; + using std::is_trivially_move_assignable; + using std::is_trivially_move_constructible; + + using std::is_nothrow_assignable; + using std::is_nothrow_constructible; + using std::is_nothrow_copy_assignable; + using std::is_nothrow_copy_constructible; + using std::is_nothrow_default_constructible; + using std::is_nothrow_destructible; + using std::is_nothrow_move_assignable; + using std::is_nothrow_move_constructible; + using std::is_nothrow_swappable; // C++17 + using std::is_nothrow_swappable_with; // C++17 + + using std::has_virtual_destructor; + + using std::has_unique_object_representations; // C++17 + + // Relationships between types: + using std::is_base_of; + using std::is_same; + + 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::aligned_storage; + using std::aligned_union; + using std::alignment_of; + using std::remove_cvref; // C++20 + + using std::common_type; + using std::decay; + using std::invoke_result; // C++17 + using std::underlying_type; + + // const-volatile modifications: + using std::add_const_t; + using std::add_cv_t; + using std::add_volatile_t; + using std::remove_const_t; + using std::remove_cv_t; + using std::remove_volatile_t; + + // reference modifications: + using std::add_lvalue_reference_t; + using std::add_rvalue_reference_t; + using std::remove_reference_t; + + // sign modifications: + using std::make_signed_t; + using std::make_unsigned_t; + + // array modifications: + using std::remove_all_extents_t; + using std::remove_extent_t; + + using std::is_bounded_array_v; // C++20 + using std::is_unbounded_array_v; // C++20 + + // pointer modifications: + using std::add_pointer_t; // C++14 + using std::remove_pointer_t; // C++14 + + // other transformations: + using std::aligned_storage_t; // C++14 + using std::aligned_union_t; // C++14 + using std::common_type_t; // C++14 + using std::conditional_t; // C++14 + using std::decay_t; // C++14 + using std::enable_if_t; // C++14 + using std::invoke_result_t; + using std::remove_cvref_t; // C++20 + using std::underlying_type_t; + + using std::void_t; + + // See C++14 20.10.4.1, primary type categories + using std::is_array_v; + using std::is_class_v; + using std::is_enum_v; + using std::is_floating_point_v; + using std::is_function_v; + using std::is_integral_v; + using std::is_lvalue_reference_v; + using std::is_member_function_pointer_v; + using std::is_member_object_pointer_v; + using std::is_null_pointer_v; + using std::is_pointer_v; + using std::is_rvalue_reference_v; + using std::is_union_v; + using std::is_void_v; + + // See C++14 20.10.4.2, composite type categories + using std::is_arithmetic_v; + using std::is_compound_v; + using std::is_fundamental_v; + using std::is_member_pointer_v; + using std::is_object_v; + using std::is_reference_v; + using std::is_scalar_v; + +#if _LIBCPP_STD_VER >= 23 // TODO Do we want to provide std module in C++20 + using std::is_scoped_enum_v; +#endif + + // See C++14 20.10.4.3, type properties + using std::has_unique_object_representations_v; // C++17; + using std::has_virtual_destructor_v; + using std::is_abstract_v; + using std::is_aggregate_v; + using std::is_assignable_v; + using std::is_const_v; + using std::is_constructible_v; + using std::is_copy_assignable_v; + using std::is_copy_constructible_v; + using std::is_default_constructible_v; + using std::is_destructible_v; + using std::is_empty_v; + using std::is_final_v; + using std::is_move_assignable_v; + using std::is_move_constructible_v; + using std::is_nothrow_assignable_v; + using std::is_nothrow_constructible_v; + using std::is_nothrow_copy_assignable_v; + using std::is_nothrow_copy_constructible_v; + using std::is_nothrow_default_constructible_v; + using std::is_nothrow_destructible_v; + using std::is_nothrow_move_assignable_v; + using std::is_nothrow_move_constructible_v; + using std::is_nothrow_swappable_v; + using std::is_nothrow_swappable_with_v; + using std::is_pod_v; + using std::is_polymorphic_v; + using std::is_signed_v; + using std::is_standard_layout_v; + using std::is_swappable_v; + using std::is_swappable_with_v; + using std::is_trivial_v; + using std::is_trivially_assignable_v; + using std::is_trivially_constructible_v; + using std::is_trivially_copy_assignable_v; + using std::is_trivially_copy_constructible_v; + using std::is_trivially_copyable_v; + using std::is_trivially_default_constructible_v; + using std::is_trivially_destructible_v; + using std::is_trivially_move_assignable_v; + using std::is_trivially_move_constructible_v; + using std::is_unsigned_v; + using std::is_volatile_v; + + // See C++14 20.10.5, type property queries + using std::alignment_of_v; // C++17 + using std::extent_v; // C++17 + using std::rank_v; // C++17 + + // See C++14 20.10.6, type relations + using std::is_base_of_v; + using std::is_convertible_v; + using std::is_invocable_r_v; + using std::is_invocable_v; + using std::is_nothrow_invocable_r_v; + using std::is_nothrow_invocable_v; + using std::is_same_v; + + // [meta.logical], logical operator traits: // C++17 + using std::conjunction_v; + using std::disjunction_v; + using std::negation_v; +} // namespace std diff --git a/libcxx/stdmodules/std-utility.cppm b/libcxx/stdmodules/std-utility.cppm new file mode 100644 --- /dev/null +++ b/libcxx/stdmodules/std-utility.cppm @@ -0,0 +1,73 @@ +# 1 __FILE__ 1 3 +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +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>=; + } // namespace rel_ops + + using std::as_const; + using std::cmp_equal; + using std::cmp_greater; // C++20 + using std::cmp_greater_equal; // C++20 + using std::cmp_less; // C++20 + using std::cmp_less_equal; // C++20 + using std::cmp_not_equal; // C++20 + using std::declval; + using std::forward; +// TODO Even when we don't want to provide std module in C++20 this is kept for now. +// This allows testing whether this way works properly. That will be required for +// symbols that will be added in C++26. +#if _LIBCPP_STD_VER >= 23 // TODO Do we want to provide std module in C++20 + using std::forward_like; +#endif + using std::in_range; // C++20 + using std::move; + using std::move_if_noexcept; + + 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_element; + using std::tuple_size; + + using std::get; + using std::index_sequence; + using std::index_sequence_for; + using std::integer_sequence; + using std::make_index_sequence; + using std::make_integer_sequence; + + using std::exchange; + using std::in_place; + using std::in_place_t; + + using std::in_place_index_t; + using std::in_place_type; + using std::in_place_type_t; + + using std::in_place_index; +#if _LIBCPP_STD_VER >= 23 // TODO Do we want to provide std module in C++20 + using std::to_underlying; +#endif +} // namespace std diff --git a/libcxx/stdmodules/std-vector.cppm b/libcxx/stdmodules/std-vector.cppm new file mode 100644 --- /dev/null +++ b/libcxx/stdmodules/std-vector.cppm @@ -0,0 +1,25 @@ +# 1 __FILE__ 1 3 +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +module; +#include +#include +export module std:vector; + +export namespace std { + using std::hash; + using std::swap; + using std::vector; + using std::operator==; + using std::erase; + using std::erase_if; +} // namespace std + +export { using ::operator new; } diff --git a/libcxx/stdmodules/std.cppm b/libcxx/stdmodules/std.cppm new file mode 100644 --- /dev/null +++ b/libcxx/stdmodules/std.cppm @@ -0,0 +1,17 @@ +# 1 __FILE__ 1 3 +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +export module std; +export import :coroutine; +export import :exception; +export import :format; +export import :type_traits; +export import :utility; +export import :vector; diff --git a/libcxx/test/configs/cmake-bridge.cfg.in b/libcxx/test/configs/cmake-bridge.cfg.in --- a/libcxx/test/configs/cmake-bridge.cfg.in +++ b/libcxx/test/configs/cmake-bridge.cfg.in @@ -31,3 +31,8 @@ config.substitutions.append(('%{lib}', '@LIBCXX_LIBRARY_DIR@')) config.substitutions.append(('%{executor}', '@LIBCXX_EXECUTOR@')) config.substitutions.append(('%{test-tools}', '@LIBCXX_TEST_TOOLS_PATH@')) + +# These are for testing with modules. This is probably not the way forward +config.substitutions.append(('%{cmake}', '@CMAKE_COMMAND@')) +config.substitutions.append(('%{make}', '@CMAKE_MAKE_PROGRAM@')) +config.substitutions.append(('%{generator}', '@CMAKE_GENERATOR@')) diff --git a/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.capacity/operator_bool.pass.cpp b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.capacity/operator_bool.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.capacity/operator_bool.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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 explicit operator bool() const noexcept + +#ifdef TEST_MODULES +import std; +#else +# include +# include +#endif +#include +#include "test_macros.h" + +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; +} diff --git a/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.pass.cpp b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/equal_comp.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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; + +#ifdef TEST_MODULES +import std; +#else +# include +# include +#endif +#include +#include "test_macros.h" + +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; +} diff --git a/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.pass.cpp b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.compare/less_comp.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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; + +#ifdef TEST_MODULES +import std; +#else +# include +# include +#endif +#include +#include "test_macros.h" + +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; +} diff --git a/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.pass.cpp b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.completion/done.pass.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#ifdef TEST_MODULES +import std; +#else +# include +#endif +#include +#include "test_macros.h" + +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; +} diff --git a/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/assign.pass.cpp b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/assign.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/assign.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#ifdef TEST_MODULES +import std; +#else +# include +# include +#endif +#include +#include "test_macros.h" + +// For std::nullptr_t. We're not intentioned to implement std.comp yet. +#include + +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; +} diff --git a/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/construct.pass.cpp b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/construct.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std_modules/language.support/support.coroutines/coroutine.handle/coroutine.handle.con/construct.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#ifdef TEST_MODULES +import std; +#else +# include +# include +#endif +#include +#include "test_macros.h" +// For std::nullptr_t. We're not intentioned to implement std.comp yet. +#include + +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; +} diff --git a/libcxx/test/std_modules/language.support/support.coroutines/end.to.end/await_result.pass.cpp b/libcxx/test/std_modules/language.support/support.coroutines/end.to.end/await_result.pass.cpp new file mode 100644 --- /dev/null +++ b/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 + +#ifdef TEST_MODULES +import std; +#else +# include +#endif +#include +#include "test_macros.h" + +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; +} diff --git a/libcxx/test/std_modules/language.support/support.coroutines/end.to.end/generator.pass.cpp b/libcxx/test/std_modules/language.support/support.coroutines/end.to.end/generator.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std_modules/language.support/support.coroutines/end.to.end/generator.pass.cpp @@ -0,0 +1,164 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#ifdef TEST_MODULES +import std; +#else +# include +# include +#endif +#include +#include "test_macros.h" + +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; +} diff --git a/libcxx/test/std_modules/language.support/support.exception/propagation/current_exception.pass.cpp b/libcxx/test/std_modules/language.support/support.exception/propagation/current_exception.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std_modules/language.support/support.exception/propagation/current_exception.pass.cpp @@ -0,0 +1,282 @@ +//===----------------------------------------------------------------------===// +// +// 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(); + +#ifdef TEST_MODULES +import std; +#else +# include +# include +#endif +#include +#include "test_macros.h" + +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; +} diff --git a/libcxx/utils/ci/buildkite-pipeline.yml b/libcxx/utils/ci/buildkite-pipeline.yml --- a/libcxx/utils/ci/buildkite-pipeline.yml +++ b/libcxx/utils/ci/buildkite-pipeline.yml @@ -47,967 +47,3 @@ - exit_status: -1 # Agent was lost limit: 2 timeout_in_minutes: 120 - - - label: "Generated output" - command: "libcxx/utils/ci/run-buildbot check-generated-output" - artifact_paths: - - "**/generated_output.patch" - - "**/generated_output.status" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - CLANG_FORMAT: "/usr/bin/clang-format-${LLVM_STABLE_VERSION}" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Documentation" - command: "libcxx/utils/ci/run-buildbot documentation" - artifact_paths: - - "**/test-results.xml" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # - # General testing with the default configuration, under all the supported - # Standard modes, with Clang and GCC. This catches most issues upfront. - # The goal of this step is to catch most issues while being very fast. - # - - wait - - - label: "GCC ${GCC_STABLE_VERSION} / C++latest" - command: "libcxx/utils/ci/run-buildbot generic-gcc" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "gcc-${GCC_STABLE_VERSION}" - CXX: "g++-${GCC_STABLE_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++2b" - command: "libcxx/utils/ci/run-buildbot generic-cxx2b" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Modular build" - command: "libcxx/utils/ci/run-buildbot generic-modules" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++11" - command: "libcxx/utils/ci/run-buildbot generic-cxx11" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++03" - command: "libcxx/utils/ci/run-buildbot generic-cxx03" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # - # All other supported configurations of libc++. - # - - wait - - - label: "C++20" - command: "libcxx/utils/ci/run-buildbot generic-cxx20" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++17" - command: "libcxx/utils/ci/run-buildbot generic-cxx17" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++14" - command: "libcxx/utils/ci/run-buildbot generic-cxx14" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Tests with the supported compilers. - - label: "GCC ${GCC_STABLE_VERSION} / C++11" - command: "libcxx/utils/ci/run-buildbot generic-gcc-cxx11" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "gcc-${GCC_STABLE_VERSION}" - CXX: "g++-${GCC_STABLE_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Clang 15" - command: "libcxx/utils/ci/run-buildbot generic-cxx2b" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-15" - CXX: "clang++-15" - # TODO LLVM18: Enable clang-tidy - # ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Clang 16" - command: "libcxx/utils/ci/run-buildbot generic-cxx2b" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-16" - CXX: "clang++-16" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Tests with the sanitizers. - - group: "Sanitizers" - steps: - - label: "ASAN" - command: "libcxx/utils/ci/run-buildbot generic-asan" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "TSAN" - command: "libcxx/utils/ci/run-buildbot generic-tsan" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "UBSAN" - command: "libcxx/utils/ci/run-buildbot generic-ubsan" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "MSAN" - command: "libcxx/utils/ci/run-buildbot generic-msan" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Tests with the various supported ways to build libc++. - - label: "Bootstrapping build" - command: "libcxx/utils/ci/run-buildbot bootstrapping-build" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - - "**/crash_diagnostics/*" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-${LLVM_HEAD_VERSION}" - CLANG_CRASH_DIAGNOSTICS_DIR: "crash_diagnostics" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Tests with various build configurations. - - label: "Static libraries" - command: "libcxx/utils/ci/run-buildbot generic-static" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Shared library with merged ABI and unwinder libraries" - command: "libcxx/utils/ci/run-buildbot generic-merged" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Assertions enabled" - command: "libcxx/utils/ci/run-buildbot generic-assertions" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Debug mode" - command: "libcxx/utils/ci/run-buildbot generic-debug-mode" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "With LLVM's libunwind" - command: "libcxx/utils/ci/run-buildbot generic-with_llvm_unwinder" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Modular build with Local Submodule Visibility" - command: "libcxx/utils/ci/run-buildbot generic-modules-lsv" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - group: "Parts disabled" - steps: - - label: "No threads" - command: "libcxx/utils/ci/run-buildbot generic-no-threads" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No filesystem" - command: "libcxx/utils/ci/run-buildbot generic-no-filesystem" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No random device" - command: "libcxx/utils/ci/run-buildbot generic-no-random_device" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No fstream" - command: "libcxx/utils/ci/run-buildbot generic-no-fstream" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No locale" - command: "libcxx/utils/ci/run-buildbot generic-no-localization" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No Unicode" - command: "libcxx/utils/ci/run-buildbot generic-no-unicode" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No wide characters" - command: "libcxx/utils/ci/run-buildbot generic-no-wide-characters" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No experimental features" - command: "libcxx/utils/ci/run-buildbot generic-no-experimental" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No exceptions" - command: "libcxx/utils/ci/run-buildbot generic-noexceptions" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Unstable ABI" - command: "libcxx/utils/ci/run-buildbot generic-abi-unstable" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Other non-testing CI jobs - - label: "Benchmarks" - command: "libcxx/utils/ci/run-buildbot benchmarks" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Tests on non-Unix platforms - - group: ":windows: Windows" - steps: - - label: "Clang-cl (DLL)" - command: "bash libcxx/utils/ci/run-buildbot clang-cl-dll" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Clang-cl (Static)" - command: "bash libcxx/utils/ci/run-buildbot clang-cl-static" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Clang-cl (no vcruntime exceptions)" - command: "bash libcxx/utils/ci/run-buildbot clang-cl-no-vcruntime" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - - - label: "MinGW (DLL, x86_64)" - command: "bash libcxx/utils/ci/run-buildbot mingw-dll" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "MinGW (Static, x86_64)" - command: "bash libcxx/utils/ci/run-buildbot mingw-static" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "MinGW (DLL, i686)" - command: "bash libcxx/utils/ci/run-buildbot mingw-dll-i686" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - group: ":apple: Apple" - steps: - - label: "MacOS x86_64" - command: "libcxx/utils/ci/run-buildbot apple-cxx20" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders" - os: "macos" - arch: "x86_64" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "MacOS arm64" - command: "libcxx/utils/ci/run-buildbot apple-cxx20" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders" - os: "macos" - arch: "arm64" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Build with the configuration we use to generate libc++.dylib on Apple platforms - - label: "Apple system" - command: "libcxx/utils/ci/run-buildbot apple-system" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders" - os: "macos" - arch: "arm64" # This can technically run on any architecture, but we have more resources on arm64 so we pin this job to arm64 - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Test back-deployment to older Apple platforms - - label: "Apple back-deployment macosx10.9" - command: "libcxx/utils/ci/run-buildbot apple-system-backdeployment-10.9" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders" - os: "macos" - arch: "x86_64" # We need to use x86_64 for back-deployment CI on this target since macOS didn't support arm64 back then. - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Apple back-deployment macosx10.15" - command: "libcxx/utils/ci/run-buildbot apple-system-backdeployment-10.15" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders" - os: "macos" - arch: "x86_64" # We need to use x86_64 for back-deployment CI on this target since macOS didn't support arm64 back then. - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Apple back-deployment macosx11.0 arm64" - command: "libcxx/utils/ci/run-buildbot apple-system-backdeployment-11.0" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders" - os: "macos" - arch: "arm64" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Apple back-deployment with assertions enabled" - command: "libcxx/utils/ci/run-buildbot apple-system-backdeployment-assertions-11.0" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders" - os: "macos" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - group: "ARM" - steps: - - label: "AArch64" - command: "libcxx/utils/ci/run-buildbot aarch64" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "aarch64" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "AArch64 -fno-exceptions" - command: "libcxx/utils/ci/run-buildbot aarch64-noexceptions" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "aarch64" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Armv8" - command: "libcxx/utils/ci/run-buildbot armv8" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "armv8l" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Armv8 -fno-exceptions" - command: "libcxx/utils/ci/run-buildbot armv8-noexceptions" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "armv8l" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Armv7" - command: "libcxx/utils/ci/run-buildbot armv7" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "armv8l" # Compiling for v7, running on v8 hardware - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Armv7 -fno-exceptions" - command: "libcxx/utils/ci/run-buildbot armv7-noexceptions" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "armv8l" # Compiling for v7, running on v8 hardware - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - group: "AIX" - steps: - - label: "AIX (32-bit)" - command: "libcxx/utils/ci/run-buildbot aix" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang" - CXX: "clang++" - OBJECT_MODE: "32" - agents: - queue: libcxx-builders - os: aix - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "AIX (64-bit)" - command: "libcxx/utils/ci/run-buildbot aix" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang" - CXX: "clang++" - OBJECT_MODE: "64" - agents: - queue: libcxx-builders - os: aix - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 diff --git a/libcxx/utils/libcxx/test/dsl.py b/libcxx/utils/libcxx/test/dsl.py --- a/libcxx/utils/libcxx/test/dsl.py +++ b/libcxx/utils/libcxx/test/dsl.py @@ -12,6 +12,7 @@ import platform import re import shutil +import subprocess import tempfile import libcxx.test.format @@ -386,6 +387,63 @@ def pretty(self, config, litParams): return 'add {} to %{{flags}}'.format(self._getFlag(config)) +def _getSubstitution(substitution, config): + for (orig, replacement) in config.substitutions: + if orig == substitution: + return replacement + raise ValueError('Substitution {} is not in the config.'.format(substitution)) + +# TODO This solution works, but is way too slow. Running in the CI +# should trigger the build once. Running one test will also trigger this +# which gives quite a overhead when quickly testing some changes. +class AddModule(ConfigAction): + + def applyTo(self, config): + build = os.path.join(config.test_exec_root, '__config_module__') + + cxx = _getSubstitution('%{cxx}', config) + std = _getSubstitution('%{cxx_std}', config) + if std == 'cxx20': + std = '20' + elif std == 'cxx2b': + std = '23' + else: + std = '17' # Not allowed for modules + + flags = _getSubstitution('%{flags}', config) + include = _getSubstitution('%{include}', config) + source = os.path.join(include, '../modules') + + cmake = _getSubstitution('%{cmake}', config) + make = _getSubstitution('%{make}', config) + generator = _getSubstitution('%{generator}', config) + + print(f"cxx {cxx}") + print(f"std {std}") + print(f"flags {flags}") + print(f"include {include}") + print(f"source {source}") + + print(f"cmake {cmake}") + print(f"make {make}") + print(f"generator {generator}") + + subprocess.check_call([cmake, + "-G" + generator, + "-DCMAKE_MAKE_PROGRAM=" + make, + "-B" + build, + "-H" + source, + "-DCMAKE_CXX_COMPILER_WORKS=TRUE", # The compiler test fails, but forcing this works + "-DCMAKE_CXX_COMPILER=" + cxx, + "-DCMAKE_CXX_STANDARD=" + std, + "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", + "-DCMAKE_CXX_FLAGS=" + flags + " -pthread", + ], env={}) + + subprocess.check_call([cmake, "--build", build], env={}) + + def pretty(self, config, litParams): + pass class AddFlagIfSupported(ConfigAction): """ @@ -438,13 +496,13 @@ def applyTo(self, config): flag = self._getFlag(config) - assert hasCompileFlag(config, flag), "Trying to enable link flag {}, which is not supported".format(flag) + # TODO This fails when enabling the modular flags. + #assert hasCompileFlag(config, flag), "Trying to enable link flag {}, which is not supported".format(flag) config.substitutions = _appendToSubstitution(config.substitutions, '%{link_flags}', flag) def pretty(self, config, litParams): return 'append {} to %{{link_flags}}'.format(self._getFlag(config)) - class PrependLinkFlag(ConfigAction): """ This action prepends the given flag to the %{link_flags} substitution. diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py --- a/libcxx/utils/libcxx/test/params.py +++ b/libcxx/utils/libcxx/test/params.py @@ -67,6 +67,21 @@ return '-std='+fallbacks[std] return None +_allModules = ['none', 'clang', 'c++'] +def getModuleFlag(cfg, enable_modules): + # Originaly the flag was a Boolean, this maps the original Boolean values + # to the new enumerate values. + fallbacks = { + 'none': 'False', + 'clang': 'True', + } + if enable_modules in _allModules: + return enable_modules + if enable_modules in fallbacks: + return fallbacks[enable_modules] + return None + + DEFAULT_PARAMETERS = [ Parameter(name='target_triple', type=str, help="The target triple to compile the test suite for. This must be " @@ -86,13 +101,22 @@ AddCompileFlag(lambda cfg: getStdFlag(cfg, std)), ]), - Parameter(name='enable_modules', choices=[True, False], type=bool, default=False, - help="Whether to build the test suite with Clang modules enabled.", - actions=lambda modules: [ + Parameter(name='enable_modules', choices=_allModules + ['True', 'False'], type=str, + help="Whether to build the test suite with modules enabled. Select " + "Clang for Clang modules and c++ for C++ Standard modules", + default=lambda cfg: next(s for s in _allModules if getModuleFlag(cfg, s)), + actions=lambda enable_modules: [ AddFeature('modules-build'), AddCompileFlag('-fmodules'), AddCompileFlag('-fcxx-modules'), # AppleClang disregards -fmodules entirely when compiling C++. This enables modules for C++. - ] if modules else []), + ] if enable_modules == "clang" or enable_modules == "True" else [ + #AddCompileFlag(lambda cfg: '-fprebuilt-module-path=' + os.path.join(cfg.test_exec_root, '../libcxx/modules')), + # Flag to indicate we want to import std instead of library headers. + AddCompileFlag('-DTEST_MODULES'), + AddCompileFlag(lambda cfg: '-fprebuilt-module-path=' + os.path.join(cfg.test_exec_root, '__config_module__/CMakeFiles/std.dir')), + AddLinkFlag(lambda cfg: os.path.join(cfg.test_exec_root, '__config_module__/libstd.a')), + AddModule(), + ] if enable_modules == "c++" else []), Parameter(name='enable_modules_lsv', choices=[True, False], type=bool, default=False, help="Whether to enable Local Submodule Visibility in the Modules build.", diff --git a/libcxx/utils/use_modules_in_test.py b/libcxx/utils/use_modules_in_test.py new file mode 100755 --- /dev/null +++ b/libcxx/utils/use_modules_in_test.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# ===------------------------------------------------------------------------------===## +# +# 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 +# +# ===------------------------------------------------------------------------------===## + +# This script converts a regular test to a test using modules. +# +# Note this script is mainly used to test the patch https://reviews.llvm.org/D144994 +# It has not been decided that libc++ will use this approach for modules. Therefore +# the transformation uses a simple algorithm and generates not the prettiest output. +# +# The main goal is to quickly convert a batch of tests to the use modules to test +# whether the std module works for the headers that have been converted. The +# script can't be executed twice on the same header, so it's intended this +# script is executed on a not-yet converted code base. +# +# Usage +# use_modules_in_test.py +# +# If the file contains at least one of the headers that is available in the std module +# it will add a guarded import statement. All headers that are in the module std will +# be included conditionally. + +import re +import sys + + +MODULARIZED_HEADERS = [ + "coroutines", + "exception", + "format", + "type_traits", + "utility", + "vector", +] + +INCLUDE_REGEX = re.compile(r"^\s*#\s*include\s*<(?P[^>]+)>") + + +def process(filename: str) -> None: + import_written = False + + file = open(filename) + lines = file.readlines() + file.close() + + file = open(filename, "w") + for line in lines: + if m := INCLUDE_REGEX.match(line): + include = m.group("include") + if include in MODULARIZED_HEADERS: + if not import_written: + import_written = True + file.write("#ifdef TEST_MODULES\nimport std;\n#endif\n") + file.write(f"#ifndef TEST_MODULES\n{line}#endif\n") + else: + file.write(line) + else: + file.write(line) + + +if __name__ == "__main__": + if len(sys.argv) == 2: + process(sys.argv[1])