diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -342,7 +342,7 @@ ------------------------------------------------- ----------------- ``__cpp_lib_spanstream`` *unimplemented* ------------------------------------------------- ----------------- - ``__cpp_lib_stacktrace`` *unimplemented* + ``__cpp_lib_stacktrace`` ``202011L`` ------------------------------------------------- ----------------- ``__cpp_lib_stdatomic_h`` *unimplemented* ------------------------------------------------- ----------------- diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -389,6 +389,8 @@ __split_buffer __std_stream __string + __stacktrace/stacktrace_entry.h + __stacktrace/basic_stacktrace.h __support/android/locale_bionic.h __support/fuchsia/xlocale.h __support/ibm/gettod_zos.h @@ -549,6 +551,7 @@ span sstream stack + stacktrace stdbool.h stddef.h stdexcept diff --git a/libcxx/include/__availability b/libcxx/include/__availability --- a/libcxx/include/__availability +++ b/libcxx/include/__availability @@ -176,6 +176,8 @@ // should be avoided. # define _LIBCPP_AVAILABILITY_DEFAULT_ASSERTION_HANDLER +# define _LIBCPP_AVAILABILITY_STACKTRACE + #elif defined(__APPLE__) # define _LIBCPP_AVAILABILITY_SHARED_MUTEX \ @@ -280,6 +282,9 @@ # define _LIBCPP_AVAILABILITY_DEFAULT_ASSERTION_HANDLER \ __attribute__((unavailable)) + +#define _LIBCPP_AVAILABILITY_STACKTRACE __attribute__((unavailable)) + #else // ...New vendors can add availability markup here... diff --git a/libcxx/include/__stacktrace/basic_stacktrace.h b/libcxx/include/__stacktrace/basic_stacktrace.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__stacktrace/basic_stacktrace.h @@ -0,0 +1,138 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___STACKTRACE_BASIC_STACKTRACE_H +#define _LIBCPP___STACKTRACE_BASIC_STACKTRACE_H + +#include <__availability> +#include <__config> +#include <__stacktrace/stacktrace_entry.h> +#include +#include +#include +#include +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +using __stacktrace_emplace_callback = void(stacktrace_entry&&, void*); +_LIBCPP_AVAILABILITY_STACKTRACE _LIBCPP_FUNC_VIS +void __get_stacktrace(size_t __skip, size_t __max_depth, __stacktrace_emplace_callback* __emplace_back, void* __vector); + +template +class basic_stacktrace { +public: + using _Vec = vector; + using value_type = stacktrace_entry; + using const_reference = const value_type&; + using reference = value_type&; + using const_iterator = typename _Vec::const_iterator; + using iterator = const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using difference_type = typename _Vec::difference_type; + using size_type = typename _Vec::size_type; + using allocator_type = _Alloc; + + static _LIBCPP_HIDE_FROM_ABI basic_stacktrace current(const allocator_type& __alloc = allocator_type()) noexcept { + return current(0, __alloc); + } + + static _LIBCPP_HIDE_FROM_ABI basic_stacktrace current(size_type __skip, + const allocator_type& __alloc = allocator_type()) noexcept { + return current(__skip, numeric_limits::max(), __alloc); + } + + static _LIBCPP_HIDE_FROM_ABI basic_stacktrace current(size_type __skip, size_type __max_depth, + const allocator_type& __alloc = allocator_type()) noexcept { + if (__max_depth == 0) + return {}; + basic_stacktrace __ret(__alloc); + std::__get_stacktrace(__skip, __max_depth, + [](stacktrace_entry&& __entry, void* __vec) { static_cast<_Vec*>(__vec)->emplace_back(std::move(__entry)); }, + &__ret.__stack_); + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI basic_stacktrace() noexcept(is_nothrow_default_constructible_v) = default; + _LIBCPP_HIDE_FROM_ABI explicit basic_stacktrace(const allocator_type& __alloc) noexcept : __stack_{__alloc} {} + + _LIBCPP_HIDE_FROM_ABI basic_stacktrace(const basic_stacktrace& other) = default; + _LIBCPP_HIDE_FROM_ABI basic_stacktrace(basic_stacktrace&& other) noexcept = default; + _LIBCPP_HIDE_FROM_ABI basic_stacktrace(const basic_stacktrace& __other, const allocator_type& __alloc) + : __stack_{__other.__stack_, __alloc} {} + _LIBCPP_HIDE_FROM_ABI basic_stacktrace(basic_stacktrace&& __other, const allocator_type& __alloc) + : __stack_{std::move(__other.__stack_), __alloc} {} + _LIBCPP_HIDE_FROM_ABI basic_stacktrace& operator=(const basic_stacktrace& other) = default; + _LIBCPP_HIDE_FROM_ABI basic_stacktrace& operator=(basic_stacktrace&& other) noexcept( + allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value) = default; + _LIBCPP_HIDE_FROM_ABI ~basic_stacktrace() = default; + + _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __stack_.get_allocator(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __stack_.cbegin(); } + _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __stack_.cend(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return __stack_.crbegin(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return __stack_.crend(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return __stack_.cbegin(); } + _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return __stack_.cend(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return __stack_.crbegin(); } + _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return __stack_.crend(); } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() { return __stack_.empty(); } + _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __stack_.size(); } + _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { return __stack_.max_size(); } + + _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __pos) const { return __stack_[__pos]; } + _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __pos) const { return __stack_.at(__pos); } + + template + _LIBCPP_HIDE_FROM_ABI friend + bool operator==(const basic_stacktrace& __lhs, const basic_stacktrace<_Alloc2> __rhs) noexcept { + return std::equal(__lhs.begin(), __lhs.end(), __rhs.begin(), __rhs.end()); + } + + template + _LIBCPP_HIDE_FROM_ABI friend + strong_ordering operator<=>(const basic_stacktrace& __lhs, const basic_stacktrace<_Alloc2>& __rhs) noexcept { + if (__lhs.size() != __rhs.size()) + return __lhs.size() <=> __rhs.size(); + // TODO: use std::lexicographical_compare_three_way once available + // return std::lexicographical_compare_three_way(__lhs.begin(), __lhs.end(), __rhs.begin(), __rhs.end()); + return std::strong_ordering::less; + } + +private: + _Vec __stack_{}; +}; + +using stacktrace = basic_stacktrace>; + +template +_LIBCPP_HIDE_FROM_ABI inline string to_string(const basic_stacktrace<_Alloc>& __trace) { + constexpr auto __function_name_length = 75; + constexpr auto __formatting_character_count = 5; + string __ret; + __ret.reserve(__trace.size() * (__function_name_length + __formatting_character_count)); + size_t __counter = 0; + for (const auto& __e : __trace) { + __ret += ' '; + __ret += std::to_string(__counter); + __ret += "# "; + __ret += std::to_string(__e); + __ret += '\n'; + ++__counter; + } + return __ret; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif diff --git a/libcxx/include/__stacktrace/stacktrace_entry.h b/libcxx/include/__stacktrace/stacktrace_entry.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__stacktrace/stacktrace_entry.h @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___STACKTRACE_STACKTRACE_ENTRY_H +#define _LIBCPP___STACKTRACE_STACKTRACE_ENTRY_H + +#include <__availability> +#include <__config> +#include +#include +#include +#include + +#pragma push_macro("_U") +#undef _U +#define UNW_LOCAL_ONLY +#include +#pragma pop_macro("_U") + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct __stacktrace_entry_cursor_ctor_tag {}; + +class stacktrace_entry { + +public: + using native_handle_type = unw_cursor_t; + +public: + // [stacktrace.entry.ctor] + _LIBCPP_HIDE_FROM_ABI constexpr stacktrace_entry() noexcept = default; + _LIBCPP_HIDE_FROM_ABI stacktrace_entry(__stacktrace_entry_cursor_ctor_tag, native_handle_type __cursor) + : __cursor_{__cursor}, __engaged_{true} {} + + _LIBCPP_HIDE_FROM_ABI constexpr stacktrace_entry(const stacktrace_entry&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr stacktrace_entry& operator=(const stacktrace_entry&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI ~stacktrace_entry() = default; + + // [stacktrace.entry.obs] + _LIBCPP_HIDE_FROM_ABI constexpr native_handle_type native_handle() const noexcept { return __cursor_; } + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { + return __engaged_; + } + + // [stacktrace.entry.query] + _LIBCPP_HIDE_FROM_ABI string description() const { + if (!__engaged_) + return {}; + return __unwind_description(); + } + + _LIBCPP_HIDE_FROM_ABI string source_file() const { return {}; } + _LIBCPP_HIDE_FROM_ABI uint_least32_t source_line() const { return {}; } + + // [stacktrace.entry.cmp] + _LIBCPP_HIDE_FROM_ABI friend + constexpr bool operator==(const stacktrace_entry& __lhs, const stacktrace_entry& __rhs) noexcept { + if (!__lhs.__engaged_ && !__rhs.__engaged_) + return false; + return (__lhs.__engaged_ == __rhs.__engaged_) + && ::__builtin_memcmp(&__lhs.__cursor_, &__rhs.__cursor_, sizeof(native_handle_type)) == 0; + } + + _LIBCPP_HIDE_FROM_ABI friend + constexpr strong_ordering operator<=>(const stacktrace_entry& __lhs, const stacktrace_entry& __rhs) noexcept { + return ::__builtin_memcmp(&__lhs.__cursor_, &__rhs.__cursor_, sizeof(native_handle_type)) <=> 0; + } + +private: + native_handle_type __cursor_{}; + bool __engaged_{}; + + _LIBCPP_AVAILABILITY_STACKTRACE string __unwind_description() const; +}; + +_LIBCPP_FUNC_VIS string to_string(const stacktrace_entry&); + +_LIBCPP_END_NAMESPACE_STD + +#endif diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -912,6 +912,15 @@ export initializer_list export * } + module stacktrace { + header "stacktrace" + export * + + module __stacktrace { + module basic_stacktrace { private header "__stacktrace/basic_stacktrace.h" } + module stacktrace_entry { private header "__stacktrace/stacktrace_entry.h" } + } + } module stdexcept { header "stdexcept" export * diff --git a/libcxx/include/stacktrace b/libcxx/include/stacktrace new file mode 100644 --- /dev/null +++ b/libcxx/include/stacktrace @@ -0,0 +1,151 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_STACKTRACE +#define _LIBCPP_STACKTRACE + +/* +namespace std { + // [stacktrace.entry], class stacktrace_entry + class stacktrace_entry { + public: + using native_handle_type = implementation-defined; + + // [stacktrace.entry.ctor], constructors + constexpr stacktrace_entry() noexcept; + constexpr stacktrace_entry(const stacktrace_entry& other) noexcept; + constexpr stacktrace_entry& operator=(const stacktrace_entry& other) noexcept; + + ~stacktrace_entry(); + + // [stacktrace.entry.obs], observers + constexpr native_handle_type native_handle() const noexcept; + constexpr explicit operator bool() const noexcept; + + // [stacktrace.entry.query], query + string description() const; + string source_file() const; + uint_least32_t source_line() const; + + // [stacktrace.entry.cmp], comparison + friend constexpr bool operator==(const stacktrace_entry& x, + const stacktrace_entry& y) noexcept; + friend constexpr strong_ordering operator<=>(const stacktrace_entry& x, + const stacktrace_entry& y) noexcept; + }; + + // [stacktrace.basic], class template basic_stacktrace + template + class basic_stacktrace { + public: + using value_type = stacktrace_entry; + using const_reference = const value_type&; + using reference = value_type&; + using const_iterator = implementation-defined; // see [stacktrace.basic.obs] + using iterator = const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using difference_type = implementation-defined; + using size_type = implementation-defined; + using allocator_type = Allocator; + + // [stacktrace.basic.ctor], creation and assignment + static basic_stacktrace current(const allocator_type& alloc = allocator_type()) noexcept; + static basic_stacktrace current(size_type skip, + const allocator_type& alloc = allocator_type()) noexcept; + static basic_stacktrace current(size_type skip, size_type max_depth, + const allocator_type& alloc = allocator_type()) noexcept; + + basic_stacktrace() noexcept(is_nothrow_default_constructible_v); + explicit basic_stacktrace(const allocator_type& alloc) noexcept; + + basic_stacktrace(const basic_stacktrace& other); + basic_stacktrace(basic_stacktrace&& other) noexcept; + basic_stacktrace(const basic_stacktrace& other, const allocator_type& alloc); + basic_stacktrace(basic_stacktrace&& other, const allocator_type& alloc); + basic_stacktrace& operator=(const basic_stacktrace& other); + basic_stacktrace& operator=(basic_stacktrace&& other) + noexcept(allocator_traits::propagate_on_container_move_assignment::value || + allocator_traits::is_always_equal::value); + + ~basic_stacktrace(); + + // [stacktrace.basic.obs], observers + allocator_type get_allocator() const noexcept; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_reverse_iterator rbegin() const noexcept; + const_reverse_iterator rend() const noexcept; + + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + [[nodiscard]] bool empty() const noexcept; + size_type size() const noexcept; + size_type max_size() const noexcept; + + const_reference operator[](size_type) const; + const_reference at(size_type) const; + + // [stacktrace.basic.cmp], comparisons + template + friend bool operator==(const basic_stacktrace& x, + const basic_stacktrace& y) noexcept; + template + friend strong_ordering operator<=>(const basic_stacktrace& x, + const basic_stacktrace& y) noexcept; + + // [stacktrace.basic.mod], modifiers + void swap(basic_stacktrace& other) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); + + private: + vector frames_; // exposition only + }; + + // basic_stacktrace typedef-names + using stacktrace = basic_stacktrace>; + + // [stacktrace.basic.nonmem], non-member functions + template + void swap(basic_stacktrace& a, basic_stacktrace& b) + noexcept(noexcept(a.swap(b))); + + string to_string(const stacktrace_entry& f); + + template + string to_string(const basic_stacktrace& st); + + template + basic_ostream& + operator<<(basic_ostream& os, const stacktrace_entry& f); + + template + basic_ostream& + operator<<(basic_ostream& os, const basic_stacktrace& st); + + namespace pmr { + using stacktrace = basic_stacktrace>; + } + + // [stacktrace.basic.hash], hash support + template struct hash; + template<> struct hash; + template struct hash>; +} +*/ + +#include <__config> +#include <__stacktrace/basic_stacktrace.h> +#include <__stacktrace/stacktrace_entry.h> + +#endif diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -395,7 +395,7 @@ // # define __cpp_lib_ranges_zip 202110L // # define __cpp_lib_reference_from_temporary 202202L // # define __cpp_lib_spanstream 202106L -// # define __cpp_lib_stacktrace 202011L +# define __cpp_lib_stacktrace 202011L // # define __cpp_lib_stdatomic_h 202011L # define __cpp_lib_string_contains 202011L # define __cpp_lib_string_resize_and_overwrite 202110L diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -41,6 +41,8 @@ ryu/d2s.cpp ryu/f2s.cpp shared_mutex.cpp + stacktrace/basic_stacktrace.cpp + stacktrace/stacktrace_entry.cpp stdexcept.cpp string.cpp support/runtime/exception_fallback.ipp @@ -227,6 +229,8 @@ cxx_add_common_build_flags(cxx_shared) cxx_set_common_defines(cxx_shared) + set(LIBCXX_USE_LIBUNWIND True) + # Link against LLVM libunwind if (LIBCXXABI_USE_LLVM_UNWINDER) if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) @@ -235,7 +239,27 @@ # libunwind is already included in libc++abi else() target_link_libraries(cxx_shared PUBLIC unwind) + set(LIBCXX_USE_LIBUNWIND False) + endif() + if (${LIBCXX_USE_LIBUNWIND}) + find_path(LIBCXX_LIBUNWIND_INCLUDES libunwind.h + PATHS ${LLVM_MAIN_SRC_DIR}/projects/libunwind/include + ${LLVM_MAIN_SRC_DIR}/runtimes/libunwind/include + ${LLVM_MAIN_SRC_DIR}/../libunwind/include + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH + ) endif() + else() + target_link_libraries(cxx_shared PUBLIC unwind) + endif() + + if (LIBCXX_LIBUNWIND_INCLUDES STREQUAL "LIBCXX_LIBUNWIND_INCLUDES-NOTFOUND") + set(LIBCXX_LIBUNWIND_INCLUDES "") + endif() + + if (NOT LIBCXX_LIBUNWIND_INCLUDES STREQUAL "") + target_include_directories(cxx_shared PRIVATE "${LIBCXX_LIBUNWIND_INCLUDES}") endif() # Link against libc++abi diff --git a/libcxx/src/stacktrace/basic_stacktrace.cpp b/libcxx/src/stacktrace/basic_stacktrace.cpp new file mode 100644 --- /dev/null +++ b/libcxx/src/stacktrace/basic_stacktrace.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 +// +//===----------------------------------------------------------------------===// + +#include <__config> +#include + +#define UNW_LOCAL_ONLY +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_FUNC_VIS void __get_stacktrace(const size_t skip, + const size_t max_depth, + __stacktrace_emplace_callback* const emplace, + void* const vec) { + unw_context_t context; + unw_getcontext(&context); + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + for (size_t i = 0; i != skip; ++i) { + if (unw_step(&cursor) < 0) + return; + } + + for (size_t i = 0; i != max_depth; ++i) { + if (const auto ret = unw_step(&cursor); ret <= 0) + return; + try { + emplace({__stacktrace_entry_cursor_ctor_tag{}, cursor}, vec); + } catch (...) { + return; + } + } +} + +_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/src/stacktrace/stacktrace_entry.cpp b/libcxx/src/stacktrace/stacktrace_entry.cpp new file mode 100644 --- /dev/null +++ b/libcxx/src/stacktrace/stacktrace_entry.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 +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include +#include + +#define UNW_LOCAL_ONLY +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_FUNC_VIS string stacktrace_entry::__unwind_description() const { + constexpr auto initial_buffer_size = 128; + auto mangled_name = std::make_unique(initial_buffer_size); + size_t alloc_size = initial_buffer_size * 2; + unw_word_t off; + auto cursor = __cursor_; + + if (int ret_val = unw_get_proc_name(&cursor, mangled_name.get(), initial_buffer_size, &off); ret_val != 0) { + while (ret_val == UNW_ENOMEM) { + mangled_name = std::make_unique(alloc_size); + alloc_size *= 2; + ret_val = unw_get_proc_name(&cursor, mangled_name.get(), alloc_size, &off); + } + if (ret_val != 0) + return {}; + } + + int status; + unique_ptr demangeled_name = + {__cxxabiv1::__cxa_demangle(mangled_name.get(), nullptr, 0, &status), std::free}; + + if (demangeled_name == nullptr) + return {mangled_name.get(), strlen(mangled_name.get())}; + + string __ret{demangeled_name.get(), strlen(demangeled_name.get())}; + return __ret; +} + +_LIBCPP_FUNC_VIS string to_string(const stacktrace_entry& entry) { + return entry.description(); +} + +_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp b/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp --- a/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp +++ b/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp @@ -532,236 +532,242 @@ using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_92 -#if defined(TEST_92) -# include +// RUN: %{build} -DTEST_90 +#if defined(TEST_90) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_96 -#if defined(TEST_96) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +// RUN: %{build} -DTEST_93 +#if defined(TEST_93) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_97 -#if defined(TEST_97) -# include +#if defined(TEST_97) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_99 -#if defined(TEST_99) -# include +// RUN: %{build} -DTEST_98 +#if defined(TEST_98) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_100 -#if defined(TEST_100) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +#if defined(TEST_100) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_101 -#if defined(TEST_101) -# include +#if defined(TEST_101) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_103 -#if defined(TEST_103) && !defined(_LIBCPP_HAS_NO_THREADS) -# include +// RUN: %{build} -DTEST_102 +#if defined(TEST_102) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_104 -#if defined(TEST_104) -# include +#if defined(TEST_104) && !defined(_LIBCPP_HAS_NO_THREADS) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_105 #if defined(TEST_105) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_106 #if defined(TEST_106) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_107 #if defined(TEST_107) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_109 -#if defined(TEST_109) -# include +// RUN: %{build} -DTEST_108 +#if defined(TEST_108) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_110 #if defined(TEST_110) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_111 #if defined(TEST_111) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_112 #if defined(TEST_112) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_113 #if defined(TEST_113) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_114 #if defined(TEST_114) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_115 #if defined(TEST_115) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_118 -#if defined(TEST_118) -# include +// RUN: %{build} -DTEST_116 +#if defined(TEST_116) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_119 -#if defined(TEST_119) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) -# include +#if defined(TEST_119) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_120 -#if defined(TEST_120) && __cplusplus >= 201103L -# include +#if defined(TEST_120) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_121 #if defined(TEST_121) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_122 -#if defined(TEST_122) -# include +#if defined(TEST_122) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_123 #if defined(TEST_123) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_124 -#if defined(TEST_124) && __cplusplus >= 201103L -# include +#if defined(TEST_124) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_125 #if defined(TEST_125) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_126 #if defined(TEST_126) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_127 -#if defined(TEST_127) -# include +#if defined(TEST_127) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_128 -#if defined(TEST_128) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L -# include +#if defined(TEST_128) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_129 -#if defined(TEST_129) && __cplusplus >= 201103L -# include +#if defined(TEST_129) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_130 -#if defined(TEST_130) -# include +#if defined(TEST_130) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_131 -#if defined(TEST_131) && __cplusplus >= 201103L -# include +#if defined(TEST_131) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_132 -#if defined(TEST_132) -# include +#if defined(TEST_132) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_133 -#if defined(TEST_133) && __cplusplus >= 201103L -# include +#if defined(TEST_133) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_134 #if defined(TEST_134) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_135 -#if defined(TEST_135) -# include +#if defined(TEST_135) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_136 -#if defined(TEST_136) && __cplusplus >= 201103L -# include +#if defined(TEST_136) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_137 -#if defined(TEST_137) -# include +#if defined(TEST_137) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_138 #if defined(TEST_138) +# include + using HandlerType = decltype(std::__libcpp_assertion_handler); +#endif + +// RUN: %{build} -DTEST_139 +#if defined(TEST_139) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif diff --git a/libcxx/test/libcxx/clang_tidy.sh.cpp b/libcxx/test/libcxx/clang_tidy.sh.cpp --- a/libcxx/test/libcxx/clang_tidy.sh.cpp +++ b/libcxx/test/libcxx/clang_tidy.sh.cpp @@ -166,6 +166,7 @@ # include #endif #include +#include #include #include #include diff --git a/libcxx/test/libcxx/double_include.sh.cpp b/libcxx/test/libcxx/double_include.sh.cpp --- a/libcxx/test/libcxx/double_include.sh.cpp +++ b/libcxx/test/libcxx/double_include.sh.cpp @@ -169,6 +169,7 @@ # include #endif #include +#include #include #include #include diff --git a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp --- a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp @@ -259,6 +259,8 @@ #endif #include TEST_MACROS(); +#include +TEST_MACROS(); #include TEST_MACROS(); #include diff --git a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp --- a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp @@ -279,6 +279,7 @@ # include #endif #include +#include #include #include #include diff --git a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp --- a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp +++ b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp @@ -166,6 +166,7 @@ # include #endif #include +#include #include #include #include diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -418,6 +418,8 @@ #include <__ranges/view_interface.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/view_interface.h'}} #include <__ranges/views.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/views.h'}} #include <__split_buffer> // expected-error@*:* {{use of private header from outside its module: '__split_buffer'}} +#include <__stacktrace/basic_stacktrace.h> // expected-error@*:* {{use of private header from outside its module: '__stacktrace/basic_stacktrace.h'}} +#include <__stacktrace/stacktrace_entry.h> // expected-error@*:* {{use of private header from outside its module: '__stacktrace/stacktrace_entry.h'}} #include <__std_stream> // expected-error@*:* {{use of private header from outside its module: '__std_stream'}} #include <__string> // expected-error@*:* {{use of private header from outside its module: '__string'}} #include <__thread/poll_with_backoff.h> // expected-error@*:* {{use of private header from outside its module: '__thread/poll_with_backoff.h'}} diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/stacktrace.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/stacktrace.version.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/stacktrace.version.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 +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_stacktrace 202011L [C++2b] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_stacktrace +# error "__cpp_lib_stacktrace should not be defined before c++2b" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_stacktrace +# error "__cpp_lib_stacktrace should not be defined before c++2b" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_stacktrace +# error "__cpp_lib_stacktrace should not be defined before c++2b" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_stacktrace +# error "__cpp_lib_stacktrace should not be defined before c++2b" +# endif + +#elif TEST_STD_VER > 20 + +# ifndef __cpp_lib_stacktrace +# error "__cpp_lib_stacktrace should be defined in c++2b" +# endif +# if __cpp_lib_stacktrace != 202011L +# error "__cpp_lib_stacktrace should have the value 202011L in c++2b" +# endif + +#endif // TEST_STD_VER > 20 + +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -4799,17 +4799,11 @@ # error "__cpp_lib_ssize should have the value 201902L in c++2b" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_stacktrace -# error "__cpp_lib_stacktrace should be defined in c++2b" -# endif -# if __cpp_lib_stacktrace != 202011L -# error "__cpp_lib_stacktrace should have the value 202011L in c++2b" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_stacktrace -# error "__cpp_lib_stacktrace should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_stacktrace +# error "__cpp_lib_stacktrace should be defined in c++2b" +# endif +# if __cpp_lib_stacktrace != 202011L +# error "__cpp_lib_stacktrace should have the value 202011L in c++2b" # endif # ifndef __cpp_lib_starts_ends_with diff --git a/libcxx/test/std/utilities/stacktrace/basic_stacktrace/assignment.pass.cpp b/libcxx/test/std/utilities/stacktrace/basic_stacktrace/assignment.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/basic_stacktrace/assignment.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include +#include + +#include "test_allocator.h" + +static_assert(std::is_nothrow_assignable_v); +static_assert(!std::is_nothrow_assignable_v>, + std::basic_stacktrace>>); + +int main(int, char**) { + { // (const basic_stacktrace&) + std::stacktrace tr = std::stacktrace::current(); + std::stacktrace tr2; + assert(tr != tr2); + tr2 = tr; + assert(tr == tr2); + } + { // (basic_stacktrace&&) + std::stacktrace tr = std::stacktrace::current(); + std::stacktrace tr2; + assert(tr != tr2); + tr2 = std::move(tr); + LIBCPP_ASSERT(tr.empty()); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/stacktrace/basic_stacktrace/ctors.pass.cpp b/libcxx/test/std/utilities/stacktrace/basic_stacktrace/ctors.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/basic_stacktrace/ctors.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include +#include + +#include "test_allocator.h" + +static_assert(std::is_nothrow_default_constructible_v); +static_assert(!std::is_nothrow_default_constructible_v>>); + +template +void test() { + using ST = std::basic_stacktrace; + { // () + ST st; + assert(st.empty()); + } + + { // (const basic_stacktrace&) + ST st = ST::current(); + ST st2 = st; + assert(st.size() == st2.size());; + for (size_t i = 0; i != st.size(); ++i) { + assert(st[i] == st2[i]); + } + } + + { // (basic_stacktrace&&) + ST st = ST::current(); + ST st2 = std::move(st); + LIBCPP_ASSERT(st.empty()); + } +} + +int main(int, char**) { + test>(); + test>(); + using Alloc = test_allocator; + using ST = std::basic_stacktrace; + { // (const allocator_type&) + test_allocator_statistics stats; + ST st{Alloc(&stats)}; + assert(st.get_allocator().get_stats() == &stats); + } + { // (const basic_stacktrace&, const allocator_type&) + test_allocator_statistics stats; + ST st = ST::current(); + ST st2 = {st, Alloc(&stats)}; + assert(st2.get_allocator().get_stats() == &stats); + assert(st.get_allocator().get_stats() == nullptr); + } + { // (basic_stacktrace&&, const allocator_type&) + test_allocator_statistics stats; + ST st = ST::current(); + ST st2 = {std::move(st), Alloc(&stats)}; + assert(st2.get_allocator().get_stats() == &stats); + } +} diff --git a/libcxx/test/std/utilities/stacktrace/basic_stacktrace/current.pass.cpp b/libcxx/test/std/utilities/stacktrace/basic_stacktrace/current.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/basic_stacktrace/current.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +template +void test() { + using ST = std::basic_stacktrace; + { + auto st = ST::current(); + assert(std::all_of(st.begin(), st.end(), [](auto& e) { return bool(e); })); + } + { + auto st = ST::current(0); + assert(std::all_of(st.begin(), st.end(), [](auto& e) { return bool(e); })); + } + { + auto st = ST::current(0, 0); + assert(st.empty()); + } + { + auto st = ST::current(0, 1); + assert(st.size() <= 1); + if (!st.empty()) + assert(st[0]); + } +} + +int main(int, char**) { +} diff --git a/libcxx/test/std/utilities/stacktrace/basic_stacktrace/member_types.compile.pass.cpp b/libcxx/test/std/utilities/stacktrace/basic_stacktrace/member_types.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/basic_stacktrace/member_types.compile.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include + +#include "test_allocator.h" + +namespace N1 { + using ST = std::stacktrace; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); +} // namespace N1 + +namespace N2 { + using ST = std::basic_stacktrace>; + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v>); +} // namespace N2 diff --git a/libcxx/test/std/utilities/stacktrace/basic_stacktrace/to_string.pass.cpp b/libcxx/test/std/utilities/stacktrace/basic_stacktrace/to_string.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/basic_stacktrace/to_string.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +int main(int, char**) { + auto stacktrace = std::stacktrace::current(); + if (!stacktrace.empty()) { + assert(!std::to_string(stacktrace).empty()); + } else { + assert(std::to_string(stacktrace).empty()); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/stacktrace/stacktrace_entry/assignment.pass.cpp b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/assignment.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/assignment.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// constexpr stacktrace_entry& operator=(const stacktrace_entry& other) noexcept; + +#include +#include + +constexpr bool test_constexpr() { + std::stacktrace_entry entry; + assert(!entry); + std::stacktrace_entry entry2; + entry2 = entry; + assert(!entry2); + + return true; +} + +void test() { + std::stacktrace trace = std::stacktrace::current(); + if (!trace.empty()) { + auto entry = trace[0]; + std::stacktrace_entry entry2; + assert(!entry2); + assert(entry != entry2); + entry2 = entry; + assert(entry2); + assert(entry == entry2); + } +} + +int main(int, char**) { + test(); + test_constexpr(); + static_assert(test_constexpr()); +} diff --git a/libcxx/test/std/utilities/stacktrace/stacktrace_entry/compare.pass.cpp b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/compare.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/compare.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 + +// + +// string source_file() const; + +#include +#include +#include + +constexpr bool test_constexpr() { + std::stacktrace_entry entry; + std::stacktrace_entry entry2; + + assert(entry == entry2); + assert(entry <=> entry2 == std::strong_ordering::equal); + + return true; +} + +void test() { + std::stacktrace trace = std::stacktrace::current(); + if (trace.size() >= 2) { + assert(trace[0] != trace[1]); + assert(trace[0] <=> trace[1] != std::strong_ordering::equal); + + assert(trace[0] == trace[0]); + assert(trace[0] <=> trace[0] == std::strong_ordering::equal); + } +} + +int main(int, char**) { + test(); +} diff --git a/libcxx/test/std/utilities/stacktrace/stacktrace_entry/ctors.pass.cpp b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/ctors.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/ctors.pass.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// constexpr stacktrace_entry() noexcept; +// constexpr stacktrace_entry(const stacktrace_entry& other) noexcept; + +#include +#include + +constexpr bool test_constexpr() { + std::stacktrace_entry entry; + assert(!entry); + auto entry2 = entry; + assert(!entry2); + + return true; +} + +int main(int, char**) { + test_constexpr(); + static_assert(test_constexpr()); +} diff --git a/libcxx/test/std/utilities/stacktrace/stacktrace_entry/description.pass.cpp b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/description.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/description.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// string description() const; + +#include +#include +#include +#include + +void test() { + std::stacktrace trace = std::stacktrace::current(); + if (!trace.empty()) { + auto entry = trace[0]; + const std::stacktrace_entry entry2 = entry; + static_assert(std::is_same_v); + assert(entry.description() == entry2.description()); + } +} + +int main(int, char**) { + test(); +} diff --git a/libcxx/test/std/utilities/stacktrace/stacktrace_entry/native_handle.compile.pass.cpp b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/native_handle.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/native_handle.compile.pass.cpp @@ -0,0 +1,19 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// constexpr native_handle_type native_handle() const noexcept; + +#include +#include + +static_assert(std::is_same_v().native_handle()), + std::stacktrace_entry::native_handle_type>); diff --git a/libcxx/test/std/utilities/stacktrace/stacktrace_entry/source_file.pass.cpp b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/source_file.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/source_file.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// string source_file() const; + +#include +#include +#include +#include + +void test() { + std::stacktrace trace = std::stacktrace::current(); + if (!trace.empty()) { + auto entry = trace[0]; + const std::stacktrace_entry entry2 = entry; + static_assert(std::is_same_v); + assert(entry.source_file() == entry2.source_file()); + } +} + +int main(int, char**) { + test(); +} diff --git a/libcxx/test/std/utilities/stacktrace/stacktrace_entry/source_line.pass.cpp b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/source_line.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/stacktrace/stacktrace_entry/source_line.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// uint_least32_t source_line() const; + +#include +#include +#include +#include + +void test() { + std::stacktrace trace = std::stacktrace::current(); + if (!trace.empty()) { + auto entry = trace[0]; + const std::stacktrace_entry entry2 = entry; + static_assert(std::is_same_v); + assert(entry.source_line() == entry2.source_line()); + } +} + +int main(int, char**) { + test(); +} diff --git a/libcxx/test/support/test_allocator.h b/libcxx/test/support/test_allocator.h --- a/libcxx/test/support/test_allocator.h +++ b/libcxx/test/support/test_allocator.h @@ -180,6 +180,7 @@ TEST_CONSTEXPR int get_data() const { return data_; } TEST_CONSTEXPR int get_id() const { return id_; } + TEST_CONSTEXPR test_allocator_statistics* get_stats() { return stats_; }; }; template diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -650,7 +650,6 @@ "name": "__cpp_lib_stacktrace", "values": { "c++2b": 202011 }, "headers": ["stacktrace"], - "unimplemented": True, }, { "name": "__cpp_lib_starts_ends_with", "values": { "c++20": 201711 },