From patchwork Mon Jan 17 12:23:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 50107 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BA7A63858031 for ; Mon, 17 Jan 2022 12:24:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BA7A63858031 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1642422284; bh=WhWT8Sq6qMXtN3NDwusv1UrzXTATrRkz+cVb9ZxLZHo=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=CfCspI66Fi++66UrxllBASaThei6xUSPfTdvINu593e0/mV9DFbOvCyiXunFtOqkh nk/qKxoOybpwLO3WwFghL0BIhsIfYO1MWPH6G28xyluAax/vYLlT96tsHneluup1x1 /8Vnm93jBSWg2V8L+D0HsX1QMXZ/rjXPaHU5sdTQ= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id BE9053858417 for ; Mon, 17 Jan 2022 12:23:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org BE9053858417 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-479-84-AFKGQM9iVXkL20Bip8A-1; Mon, 17 Jan 2022 07:23:25 -0500 X-MC-Unique: 84-AFKGQM9iVXkL20Bip8A-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 6119E18C89CC; Mon, 17 Jan 2022 12:23:24 +0000 (UTC) Received: from localhost (unknown [10.33.37.93]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9A2B970D43; Mon, 17 Jan 2022 12:23:23 +0000 (UTC) To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Define header for C++23 Date: Mon, 17 Jan 2022 12:23:22 +0000 Message-Id: <20220117122322.3419140-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jonathan Wakely via Gcc-patches From: Jonathan Wakely Reply-To: Jonathan Wakely Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Tested x86_64-linux, pushed to trunk. Add the header and a new libstdc++_libbacktrace.a library that provides the implementation. For now, the new library is only built if --enable-libstdcxx-backtrace=yes is used. As with the Filesystem TS, the new library is only provided as a static archive. libstdc++-v3/ChangeLog: * acinclude.m4 (GLIBCXX_ENABLE_BACKTRACE): New macro. * configure.ac: Use GLIBCXX_ENABLE_BACKTRACE. * include/Makefile.am: Add new header. * include/Makefile.in: Regenerate. * include/std/stacktrace: New header. * include/std/version (__cpp_lib_stacktrace): Define. * Makefile.in: Regenerate. * config.h.in: Regenerate. * configure: Regenerate. * doc/Makefile.in: Regenerate. * libsupc++/Makefile.in: Regenerate. * po/Makefile.in: Regenerate. * python/Makefile.in: Regenerate. * src/Makefile.am: Regenerate. * src/Makefile.in: Regenerate. * src/c++11/Makefile.in: Regenerate. * src/c++17/Makefile.in: Regenerate. * src/c++20/Makefile.in: Regenerate. * src/c++98/Makefile.in: Regenerate. * src/filesystem/Makefile.in: Regenerate. * testsuite/Makefile.in: Regenerate. * src/libbacktrace/Makefile.am: New file. * src/libbacktrace/Makefile.in: New file. * src/libbacktrace/backtrace-rename.h: New file. * src/libbacktrace/backtrace-supported.h.in: New file. * src/libbacktrace/config.h.in: New file. * testsuite/lib/libstdc++.exp (check_effective_target_stacktrace): New proc. * testsuite/20_util/stacktrace/entry.cc: New test. * testsuite/20_util/stacktrace/synopsis.cc: New test. * testsuite/20_util/stacktrace/version.cc: New test. --- libstdc++-v3/Makefile.in | 7 + libstdc++-v3/acinclude.m4 | 138 ++- libstdc++-v3/config.h.in | 10 + libstdc++-v3/configure | 317 ++++++- libstdc++-v3/configure.ac | 3 + libstdc++-v3/doc/Makefile.in | 7 + libstdc++-v3/include/Makefile.am | 1 + libstdc++-v3/include/Makefile.in | 8 + libstdc++-v3/include/std/stacktrace | 672 ++++++++++++++ libstdc++-v3/include/std/version | 3 + libstdc++-v3/libsupc++/Makefile.in | 7 + libstdc++-v3/po/Makefile.in | 7 + libstdc++-v3/python/Makefile.in | 7 + libstdc++-v3/src/Makefile.am | 11 +- libstdc++-v3/src/Makefile.in | 14 +- libstdc++-v3/src/c++11/Makefile.in | 7 + libstdc++-v3/src/c++17/Makefile.in | 7 + libstdc++-v3/src/c++20/Makefile.in | 7 + libstdc++-v3/src/c++98/Makefile.in | 7 + libstdc++-v3/src/filesystem/Makefile.in | 7 + libstdc++-v3/src/libbacktrace/Makefile.am | 101 ++ libstdc++-v3/src/libbacktrace/Makefile.in | 860 ++++++++++++++++++ .../src/libbacktrace/backtrace-rename.h | 41 + .../src/libbacktrace/backtrace-supported.h.in | 61 ++ libstdc++-v3/src/libbacktrace/config.h.in | 184 ++++ .../testsuite/20_util/stacktrace/entry.cc | 53 ++ .../testsuite/20_util/stacktrace/synopsis.cc | 46 + .../testsuite/20_util/stacktrace/version.cc | 11 + libstdc++-v3/testsuite/Makefile.in | 7 + libstdc++-v3/testsuite/lib/libstdc++.exp | 8 + 30 files changed, 2605 insertions(+), 14 deletions(-) create mode 100644 libstdc++-v3/include/std/stacktrace create mode 100644 libstdc++-v3/src/libbacktrace/Makefile.am create mode 100644 libstdc++-v3/src/libbacktrace/Makefile.in create mode 100644 libstdc++-v3/src/libbacktrace/backtrace-rename.h create mode 100644 libstdc++-v3/src/libbacktrace/backtrace-supported.h.in create mode 100644 libstdc++-v3/src/libbacktrace/config.h.in create mode 100644 libstdc++-v3/testsuite/20_util/stacktrace/entry.cc create mode 100644 libstdc++-v3/testsuite/20_util/stacktrace/synopsis.cc create mode 100644 libstdc++-v3/testsuite/20_util/stacktrace/version.cc diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index b770d5bcdc4..336c690f07b 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -49,7 +49,7 @@ AC_DEFUN([GLIBCXX_CONFIGURE], [ # Keep these sync'd with the list in Makefile.am. The first provides an # expandable list at autoconf time; the second provides an expandable list # (i.e., shell variable) at configure time. - m4_define([glibcxx_SUBDIRS],[include libsupc++ src src/c++98 src/c++11 src/c++17 src/c++20 src/filesystem doc po testsuite python]) + m4_define([glibcxx_SUBDIRS],[include libsupc++ src src/c++98 src/c++11 src/c++17 src/c++20 src/filesystem src/libbacktrace doc po testsuite python]) SUBDIRS='glibcxx_SUBDIRS' # These need to be absolute paths, yet at the same time need to @@ -4801,6 +4801,142 @@ AC_DEFUN([GLIBCXX_CHECK_ARC4RANDOM], [ AC_LANG_RESTORE ]) +dnl +dnl Check to see whether to build libstdc++_libbacktrace.a +dnl +dnl --enable-libstdcxx-backtrace +dnl +AC_DEFUN([GLIBCXX_ENABLE_BACKTRACE], [ + GLIBCXX_ENABLE(libstdcxx-backtrace,auto,, + [turns on libbacktrace support], + [permit yes|no|auto]) + + # Most of this is adapted from libsanitizer/configure.ac + + BACKTRACE_CPPFLAGS= + + # libbacktrace only needs atomics for int, which we've already tested + if test "$glibcxx_cv_atomic_int" = "yes"; then + BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DHAVE_ATOMIC_FUNCTIONS=1" + fi + + # Test for __sync support. + AC_CACHE_CHECK([__sync extensions], + [glibcxx_cv_sys_sync], + [GCC_TRY_COMPILE_OR_LINK( + [int i;], + [__sync_bool_compare_and_swap (&i, i, i); + __sync_lock_test_and_set (&i, 1); + __sync_lock_release (&i);], + [glibcxx_cv_sys_sync=yes], + [glibcxx_cv_sys_sync=no]) + ]) + if test "$glibcxx_cv_sys_sync" = "yes"; then + BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DHAVE_SYNC_FUNCTIONS=1" + fi + + # Check for dl_iterate_phdr. + AC_CHECK_HEADERS(link.h) + if test "$ac_cv_header_link_h" = "no"; then + have_dl_iterate_phdr=no + else + # When built as a GCC target library, we can't do a link test. + AC_EGREP_HEADER([dl_iterate_phdr], [link.h], [have_dl_iterate_phdr=yes], + [have_dl_iterate_phdr=no]) + fi + if test "$have_dl_iterate_phdr" = "yes"; then + BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DHAVE_DL_ITERATE_PHDR=1" + fi + + # Check for the fcntl function. + if test -n "${with_target_subdir}"; then + case "${host}" in + *-*-mingw*) have_fcntl=no ;; + *) have_fcntl=yes ;; + esac + else + AC_CHECK_FUNC(fcntl, [have_fcntl=yes], [have_fcntl=no]) + fi + if test "$have_fcntl" = "yes"; then + BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DHAVE_FCNTL=1" + fi + + AC_CHECK_DECLS(strnlen) + + # Check for getexecname function. + if test -n "${with_target_subdir}"; then + case "${host}" in + *-*-solaris2*) have_getexecname=yes ;; + *) have_getexecname=no ;; + esac + else + AC_CHECK_FUNC(getexecname, [have_getexecname=yes], [have_getexecname=no]) + fi + if test "$have_getexecname" = "yes"; then + BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DHAVE_GETEXECNAME=1" + fi + +# The library needs to be able to read the executable itself. Compile +# a file to determine the executable format. The awk script +# filetype.awk prints out the file type. +AC_CACHE_CHECK([output filetype], +[glibcxx_cv_sys_filetype], +[filetype= +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([int i;], [int j;])], + [filetype=`${AWK} -f $srcdir/../libbacktrace/filetype.awk conftest.$ac_objext`], + [AC_MSG_FAILURE([compiler failed])]) +glibcxx_cv_sys_filetype=$filetype]) + +# Match the file type to decide what files to compile. +FORMAT_FILE= +case "$glibcxx_cv_sys_filetype" in +elf*) FORMAT_FILE="elf.lo" ;; +*) AC_MSG_WARN([could not determine output file type]) + FORMAT_FILE="unknown.lo" + enable_libstdcxx_backtrace=no + ;; +esac +AC_SUBST(FORMAT_FILE) + +# ELF defines. +elfsize= +case "$glibcxx_cv_sys_filetype" in +elf32) elfsize=32 ;; +elf64) elfsize=64 ;; +esac +BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DBACKTRACE_ELF_SIZE=$elfsize" + + ALLOC_FILE=alloc.lo + AC_SUBST(ALLOC_FILE) + VIEW_FILE=read.lo + AC_SUBST(VIEW_FILE) + + AC_MSG_CHECKING([whether to build libbacktrace support]) + if test "$enable_libstdcxx_backtrace" == "auto"; then + enable_libstdcxx_backtrace=no + fi + if test "$enable_libstdcxx_backtrace" == "yes"; then + BACKTRACE_SUPPORTED=1 + BACKTRACE_USES_MALLOC=1 + if test "$ac_has_gthreads" = "yes"; then + BACKTRACE_SUPPORTS_THREADS=1 + else + BACKTRACE_SUPPORTS_THREADS=0 + fi + AC_SUBST(BACKTRACE_CPPFLAGS) + AC_SUBST(BACKTRACE_SUPPORTED) + AC_SUBST(BACKTRACE_USES_MALLOC) + AC_SUBST(BACKTRACE_SUPPORTS_THREADS) + AC_DEFINE(HAVE_STACKTRACE, 1, [Define if the header is supported.]) + else + BACKTRACE_SUPPORTED=0 + BACKTRACE_USES_MALLOC=0 + BACKTRACE_SUPPORTS_THREADS=0 + fi + AC_MSG_RESULT($enable_libstdcxx_backtrace) + GLIBCXX_CONDITIONAL(ENABLE_BACKTRACE, [test "$enable_libstdcxx_backtrace" != no]) +]) # Macros from the top-level gcc directory. m4_include([../config/gc++filt.m4]) diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac index 827d770f444..2a3bc520501 100644 --- a/libstdc++-v3/configure.ac +++ b/libstdc++-v3/configure.ac @@ -489,6 +489,8 @@ AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h utime.h]) GLIBCXX_ENABLE_FILESYSTEM_TS GLIBCXX_CHECK_FILESYSTEM_DEPS +GLIBCXX_ENABLE_BACKTRACE + # For Networking TS. AC_CHECK_HEADERS([fcntl.h sys/ioctl.h sys/socket.h sys/uio.h poll.h netdb.h arpa/inet.h netinet/in.h netinet/tcp.h]) AC_CHECK_DECL(F_GETFL,,,[#include ]) @@ -629,6 +631,7 @@ AC_CONFIG_FILES(Makefile) AC_CONFIG_FILES([scripts/testsuite_flags],[chmod +x scripts/testsuite_flags]) AC_CONFIG_FILES([scripts/extract_symvers],[chmod +x scripts/extract_symvers]) AC_CONFIG_FILES([doc/xsl/customization.xsl]) +AC_CONFIG_FILES([src/libbacktrace/backtrace-supported.h]) # Multilibs need MULTISUBDIR defined correctly in certain makefiles so # that multilib installs will end up installed in the correct place. diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 65b2b4e64af..d1431926cdd 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -80,6 +80,7 @@ std_headers = \ ${std_srcdir}/sstream \ ${std_srcdir}/syncstream \ ${std_srcdir}/stack \ + ${std_srcdir}/stacktrace \ ${std_srcdir}/stdexcept \ ${std_srcdir}/stop_token \ ${std_srcdir}/streambuf \ diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace new file mode 100644 index 00000000000..623f44bdca4 --- /dev/null +++ b/libstdc++-v3/include/std/stacktrace @@ -0,0 +1,672 @@ +// -*- C++ -*- + +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#ifndef _GLIBCXX_STACKTRACE +#define _GLIBCXX_STACKTRACE 1 + +#pragma GCC system_header + +#include + +#if __cplusplus > 202002L && _GLIBCXX_HAVE_STACKTRACE +#include +#include +#include +#include +#include +#include +#include +#include + +struct __glibcxx_backtrace_state; +struct __glibcxx_backtrace_simple_data; + +extern "C" +{ +__glibcxx_backtrace_state* +__glibcxx_backtrace_create_state(const char*, int, + void(*)(void*, const char*, int), + void*); + +int +__glibcxx_backtrace_simple(__glibcxx_backtrace_state*, int, + int (*) (void*, uintptr_t), + void(*)(void*, const char*, int), + void*); +int +__glibcxx_backtrace_pcinfo(__glibcxx_backtrace_state*, uintptr_t, + int (*)(void*, uintptr_t, + const char*, int, const char*), + void(*)(void*, const char*, int), + void*); + +int +__glibcxx_backtrace_syminfo(__glibcxx_backtrace_state*, uintptr_t addr, + void (*) (void*, uintptr_t, const char*, + uintptr_t, uintptr_t), + void(*)(void*, const char*, int), + void*); +} + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#define __cpp_lib_stacktrace 202011L + + // [stacktrace.entry], class stacktrace_entry + class stacktrace_entry + { + using uint_least32_t = __UINT_LEAST32_TYPE__; + using uintptr_t = __UINTPTR_TYPE__; + + public: + using native_handle_type = uintptr_t; + + // [stacktrace.entry.ctor], constructors + + constexpr + stacktrace_entry() noexcept = default; + + constexpr + stacktrace_entry(const stacktrace_entry& __other) noexcept = default; + + constexpr stacktrace_entry& + operator=(const stacktrace_entry& __other) noexcept = default; + + ~stacktrace_entry() = default; + + // [stacktrace.entry.obs], observers + + constexpr native_handle_type + native_handle() const noexcept { return _M_pc; } + + constexpr explicit operator bool() const noexcept { return _M_pc != -1; } + + // [stacktrace.entry.query], query + string + description() const + { + string __s; + _M_get_info(&__s, nullptr, nullptr); + return __s; + } + + string + source_file() const + { + string __s; + _M_get_info(nullptr, &__s, nullptr); + return __s; + } + + uint_least32_t + source_line() const + { + int __line = 0; + _M_get_info(nullptr, nullptr, &__line); + return __line; + } + + // [stacktrace.entry.cmp], comparison + friend constexpr bool + operator==(const stacktrace_entry& __x, + const stacktrace_entry& __y) noexcept + { return __x._M_pc == __y._M_pc; } + + friend constexpr strong_ordering + operator<=>(const stacktrace_entry& __x, + const stacktrace_entry& __y) noexcept + { return __x._M_pc <=> __y._M_pc; } + + private: + native_handle_type _M_pc = -1; + + template friend class basic_stacktrace; + + static __glibcxx_backtrace_state* + _S_init() + { + static __glibcxx_backtrace_state* __state + = __glibcxx_backtrace_create_state(nullptr, 1, nullptr, nullptr); + return __state; + } + + template + friend basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>&, const stacktrace_entry&); + + bool + _M_get_info(string* __desc, string* __file, int* __line) const + { + if (!*this) + return false; + + struct _Data + { + string* _M_desc; + string* _M_file; + int* _M_line; + } __data = { __desc, __file, __line }; + + auto __cb = [](void* __data, uintptr_t, const char* __filename, + int __lineno, const char* __function) -> int { + auto& __d = *static_cast<_Data*>(__data); + if (__function && __d._M_desc) + *__d._M_desc = _S_demangle(__function); + if (__filename && __d._M_file) + *__d._M_file = __filename; + if (__d._M_line) + *__d._M_line = __lineno; + return __function != nullptr; + }; + const auto __state = _S_init(); + if (::__glibcxx_backtrace_pcinfo(__state, _M_pc, +__cb, nullptr, &__data)) + return true; + if (__desc && __desc->empty()) + { + auto __cb2 = [](void* __data, uintptr_t, const char* __symname, + uintptr_t, uintptr_t) { + if (__symname) + *static_cast<_Data*>(__data)->_M_desc = _S_demangle(__symname); + }; + if (::__glibcxx_backtrace_syminfo(__state, _M_pc, +__cb2, nullptr, + &__data)) + return true; + } + return false; + } + + static string + _S_demangle(const char* __name) + { + string __s; + int __status; + char* __str = __cxxabiv1::__cxa_demangle(__name, nullptr, nullptr, + &__status); + if (__status == 0) + __s = __str; + __builtin_free(__str); + return __s; + } + }; + + // [stacktrace.basic], class template basic_stacktrace + template + class basic_stacktrace + { + using _AllocTraits = allocator_traits<_Allocator>; + + public: + using value_type = stacktrace_entry; + using const_reference = const value_type&; + using reference = value_type&; + using const_iterator + = __gnu_cxx::__normal_iterator; + using iterator = const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using difference_type = ptrdiff_t; + using size_type = unsigned short; + using allocator_type = _Allocator; + + // [stacktrace.basic.ctor], creation and assignment + + static basic_stacktrace + current(const allocator_type& __alloc = allocator_type()) noexcept + { + return current(0, size_type(-1), __alloc); + } + + static basic_stacktrace + current(size_type __skip, + const allocator_type& __alloc = allocator_type()) noexcept + { + return current(__skip, size_type(-1), __alloc); + } + + static basic_stacktrace + current(size_type __skip, size_type __max_depth, + const allocator_type& __alloc = allocator_type()) noexcept + { + __glibcxx_assert(__skip <= (size_type(-1) - __max_depth)); + + auto __state = stacktrace_entry::_S_init(); + basic_stacktrace __ret(__alloc); + if (!__ret._M_reserve(std::min(__max_depth, 64))) + return __ret; + + auto __cb = [](void* __data, uintptr_t __pc) { + auto& __s = *static_cast(__data); + stacktrace_entry __f; + __f._M_pc = __pc; + if (__s._M_push_back(__f)) + return 0; + return 1; + }; + + if (__glibcxx_backtrace_simple(__state, __skip, +__cb, nullptr, + std::__addressof(__ret))) + { + __ret._M_clear(); + } + return __ret; + } + + basic_stacktrace() + noexcept(is_nothrow_default_constructible_v) + { } + + explicit + basic_stacktrace(const allocator_type& __alloc) noexcept + : _M_alloc(__alloc) + { } + + basic_stacktrace(const basic_stacktrace& __other) noexcept + : basic_stacktrace(__other, __other._M_alloc) + { } + + basic_stacktrace(basic_stacktrace&& __other) noexcept + : _M_alloc(std::move(__other._M_alloc)), + _M_impl(std::__exchange(__other._M_impl, {})) + { } + + basic_stacktrace(const basic_stacktrace& __other, + const allocator_type& __alloc) noexcept + : _M_alloc(__alloc) + { + if (const auto __s = __other._M_impl._M_size) + if (auto __f = _M_impl._M_allocate(_M_alloc, __s)) + { + std::uninitialized_copy_n(__other.begin(), __s, __f); + _M_impl._M_size = __s; + } + } + + basic_stacktrace(basic_stacktrace&& __other, + const allocator_type& __alloc) noexcept + : _M_alloc(__alloc) + { + if constexpr (_Allocator::is_always_equal::value) + { + _M_impl = std::__exchange(__other._M_impl, {}); + } + else if (_M_alloc == __other._M_alloc) + { + _M_impl = std::__exchange(__other._M_impl, {}); + } + } + + basic_stacktrace& + operator=(const basic_stacktrace& __other) noexcept + { + if (std::__addressof(__other) == this) + return *this; + + constexpr bool __pocca + = _AllocTraits::propagate_on_container_copy_assignment::value; + constexpr bool __always_eq = _AllocTraits::is_always_equal::value; + + const auto __s = __other.size(); + + if constexpr (!__always_eq && __pocca) + { + if (_M_alloc != __other._M_alloc) + { + // Cannot keep the same storage, so deallocate it now. + _M_clear(); + } + } + + if (_M_impl._M_capacity < __s) + { + // Need to allocate new storage. + _M_clear(); + + // Use the allocator we will have after this function returns. + auto& __alloc = __pocca ? __other._M_alloc : _M_alloc; + if (auto __f = _M_impl._M_allocate(__alloc, __s)) + { + std::uninitialized_copy_n(__other.begin(), __s, __f); + _M_impl._M_size = __s; + } + } + else + { + // Current storage is large enough and can be freed by whichever + // allocator we will have after this function returns. + auto __to = std::copy_n(__other.begin(), __s, begin()); + std::destroy(__to, end()); + _M_impl._M_size = __s; + } + + if constexpr (__pocca) + _M_alloc = __other._M_alloc; + + return *this; + } + + basic_stacktrace& + operator=(basic_stacktrace&& __other) noexcept + { + if (std::__addressof(__other) == this) + return *this; + + constexpr bool __pocma + = _AllocTraits::propagate_on_container_move_assignment::value; + + if constexpr (_AllocTraits::is_always_equal::value) + std::swap(_M_impl, __other._M_impl); + else if (_M_alloc == __other._M_alloc) + std::swap(_M_impl, __other._M_impl); + else + { + const auto __s = __other.size(); + + if constexpr (__pocma || _M_impl._M_capacity < __s) + { + // Need to allocate new storage. + _M_clear(); + + // Use the allocator we will have after this function returns. + auto& __alloc = __pocma ? __other._M_alloc : _M_alloc; + if (auto __f = _M_impl._M_allocate(__alloc, __s)) + std::uninitialized_copy_n(__other.begin(), __s, __f); + } + else + { + // Current storage is large enough. + auto __first = __other.begin(); + auto __mid = __first + std::min(__s, _M_impl._M_size); + auto __last = __other.end(); + auto __to = std::copy(__first, __mid, begin()); + __to = std::uninitialized_copy(__mid, __last, __to); + std::destroy(__to, end()); + } + _M_impl._M_size = __s; + } + + if constexpr (__pocma) + _M_alloc = std::move(__other._M_alloc); + + return *this; + } + + constexpr ~basic_stacktrace() + { + _M_clear(); + } + + // [stacktrace.basic.obs], observers + allocator_type get_allocator() const noexcept { return _M_alloc; } + + const_iterator + begin() const noexcept + { return const_iterator{_M_impl._M_frames}; } + + const_iterator + end() const noexcept + { return begin() + size(); } + + const_reverse_iterator + rbegin() const noexcept + { return std::make_reverse_iterator(end()); } + + const_reverse_iterator + rend() const noexcept + { return std::make_reverse_iterator(begin()); } + + const_iterator cbegin() const noexcept { return begin(); } + const_iterator cend() const noexcept { return end(); } + const_reverse_iterator crbegin() const noexcept { return rbegin(); }; + const_reverse_iterator crend() const noexcept { return rend(); }; + + [[nodiscard]] bool empty() const noexcept { return size() == 0; } + size_type size() const noexcept { return _M_impl._M_size; } + size_type max_size() const noexcept { return size_type(-1); } + + const_reference + operator[](size_type __n) const noexcept + { + __glibcxx_assert(__n < size()); + return begin()[__n]; + } + + const_reference + at(size_type __n) const + { + if (__n >= size()) + __throw_out_of_range("basic_stack_trace::at: bad frame number"); + return begin()[__n]; + } + + // [stacktrace.basic.cmp], comparisons + template + friend bool + operator==(const basic_stacktrace& __x, + const basic_stacktrace<_Allocator2>& __y) noexcept + { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); } + + template + friend strong_ordering + operator<=>(const basic_stacktrace& __x, + const basic_stacktrace<_Allocator2>& __y) noexcept + { + if (auto __s = __x.size() <=> __y.size(); __s != 0) + return __s; + return std::lexicographical_compare_three_way(__x.begin(), __x.end(), + __y.begin(), __y.end()); + } + + // [stacktrace.basic.mod], modifiers + void + swap(basic_stacktrace& __other) noexcept + { + std::swap(_M_impl. __other._M_impl); + if constexpr (_AllocTraits::propagate_on_container_swap::value) + std::swap(_M_alloc, __other._M_alloc); + } + + private: + bool + _M_reserve(size_type __n) noexcept + { + return _M_impl._M_allocate(_M_alloc, __n) != nullptr; + } + + bool + _M_push_back(const value_type& __x) noexcept + { + return _M_impl._M_push_back(_M_alloc, __x); + } + + void + _M_clear() noexcept + { + _M_impl._M_destroy(); + _M_impl._M_deallocate(_M_alloc); + } + + struct _Impl + { + using pointer = typename _AllocTraits::pointer; + + pointer _M_frames = nullptr; + size_type _M_size = 0; + size_type _M_capacity = 0; + + // Precondition: _M_frames == nullptr + pointer + _M_allocate(allocator_type& __alloc, size_type __n) noexcept + { + __try + { + _M_frames = __n ? __alloc.allocate(__n) : nullptr; + _M_capacity = __n; + } + __catch (...) + { + _M_frames = nullptr; + _M_capacity = 0; + } + return _M_frames; + } + + void + _M_deallocate(allocator_type& __alloc) noexcept + { + if (_M_capacity) + { + __alloc.deallocate(_M_frames, _M_capacity); + _M_frames = nullptr; + _M_capacity = 0; + } + } + + void + _M_destroy() noexcept + { + std::destroy_n(_M_frames, _M_size); + _M_size = 0; + } + + bool + _M_push_back(allocator_type& __alloc, + const stacktrace_entry& __f) noexcept + { + if (_M_size == _M_capacity) + { + _Impl __tmp; + if (auto __f = __tmp._M_allocate(__alloc, _M_capacity * 2)) + std::uninitialized_copy_n(_M_frames, _M_size, __f); + else + return false; + _M_deallocate(__alloc); + std::swap(*this, __tmp); + } + stacktrace_entry* __addr = std::to_address(_M_frames + _M_size++); + std::construct_at(__addr, __f); + return true; + } + + }; + + [[no_unique_address]] allocator_type _M_alloc{}; + + _Impl _M_impl{}; + }; + + // basic_stacktrace typedef names + using stacktrace = basic_stacktrace>; + + // [stacktrace.basic.nonmem], non-member functions + template + inline void + swap(basic_stacktrace<_Allocator>& __a, basic_stacktrace<_Allocator>& __b) + noexcept(noexcept(__a.swap(__b))) + { __a.swap(__b); } + + template + inline basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, + const stacktrace_entry& __f) + { + string __desc, __file; + int __line; + if (__f._M_get_info(&__desc, &__file, &__line)) + { + __os.width(4); + __os << __desc << " at " << __file << ':' << __line; + } + return __os; + } + + template + inline basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, + const basic_stacktrace<_Allocator>& __st) + { + for (stacktrace::size_type __i = 0; __i < __st.size(); ++__i) + { + __os.width(4); + __os << __i << "# " << __st[__i] << '\n'; + } + return __os; + } + + inline string + to_string(const stacktrace_entry& __f) + { + std::ostringstream __os; + __os << __f; + return std::move(__os).str(); + } + + template + string + to_string(const basic_stacktrace<_Allocator>& __st) + { + std::ostringstream __os; + __os << __st; + return std::move(__os).str(); + } + + namespace pmr + { + template class polymorphic_allocator; + using stacktrace + = basic_stacktrace>; + } + + // [stacktrace.basic.hash], hash support + + template<> + struct hash + { + size_t + operator()(const stacktrace_entry& __f) const noexcept + { + using __h = hash; + return __h()(__f.native_handle()); + } + }; + + template + struct hash> + { + size_t + operator()(const basic_stacktrace<_Allocator>& __st) const noexcept + { + hash __h; + size_t __val = _Hash_impl::hash(__st.size()); + for (const auto& __f : __st) + __val = _Hash_impl::__hash_combine(__h(__f), __val); + return __val; + } + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // C++23 + +#endif /* _GLIBCXX_STACKTRACE */ diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index 7bd32f67f19..e3afe57c782 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -312,6 +312,9 @@ #if __cpp_lib_span # define __cpp_lib_spanstream 202106L #endif +#if _GLIBCXX_HAVE_STACKTRACE +# define __cpp_lib_stacktrace 202011L +#endif #define __cpp_lib_string_contains 202011L #if _GLIBCXX_USE_CXX11_ABI // Only supported with cxx11-abi # define __cpp_lib_string_resize_and_overwrite 202110L diff --git a/libstdc++-v3/src/Makefile.am b/libstdc++-v3/src/Makefile.am index 73f685b2366..71a0da2cd93 100644 --- a/libstdc++-v3/src/Makefile.am +++ b/libstdc++-v3/src/Makefile.am @@ -28,8 +28,14 @@ else filesystem_dir = endif +if ENABLE_BACKTRACE +backtrace_dir = libbacktrace +else +backtrace_dir = +endif + ## Keep this list sync'd with acinclude.m4:GLIBCXX_CONFIGURE. -SUBDIRS = c++98 c++11 c++17 c++20 $(filesystem_dir) +SUBDIRS = c++98 c++11 c++17 c++20 $(filesystem_dir) $(backtrace_dir) # Cross compiler support. if VTV_CYGMIN @@ -64,6 +70,9 @@ vpath % $(top_srcdir)/src/c++20 if ENABLE_FILESYSTEM_TS vpath % $(top_srcdir)/src/filesystem endif +if ENABLE_BACKTRACE +vpath % $(top_srcdir)/src/libbacktrace +endif if GLIBCXX_LDBL_COMPAT ldbl_compat_sources = compatibility-ldbl.cc diff --git a/libstdc++-v3/src/libbacktrace/Makefile.am b/libstdc++-v3/src/libbacktrace/Makefile.am new file mode 100644 index 00000000000..3a3195167b2 --- /dev/null +++ b/libstdc++-v3/src/libbacktrace/Makefile.am @@ -0,0 +1,101 @@ +# Makefile.am -- Backtrace in libstdc++ Makefile. +# Copyright (C) 2012-2013 Free Software Foundation, Inc. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: + +# (1) Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. + +# (2) Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. + +# (3) The name of the author may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +include $(top_srcdir)/fragment.am + +toolexeclib_LTLIBRARIES = libstdc++_libbacktrace.la + +ACLOCAL_AMFLAGS = -I ../.. -I ../../config + +AM_CPPFLAGS = -I $(top_srcdir)/../include -I $(top_srcdir)/../libgcc \ + -I ../../../libgcc -I .. -I $(top_srcdir) \ + -I $(top_srcdir)/../libbacktrace \ + -include $(top_srcdir)/src/libbacktrace/backtrace-rename.h \ + $(BACKTRACE_CPPFLAGS) + +WARN_FLAGS = -W -Wall -Wwrite-strings -Wmissing-format-attribute \ + -Wcast-qual -Werror +C_WARN_FLAGS = $(WARN_FLAGS) -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -Wno-unused-but-set-variable +CXX_WARN_FLAGS = $(WARN_FLAGS) -Wno-unused-parameter +AM_CFLAGS = $(C_WARN_FLAGS) +AM_CFLAGS += $(EXTRA_CFLAGS) +AM_CXXFLAGS = $(CXX_WARN_FLAGS) -fno-rtti -fno-exceptions +AM_CXXFLAGS += $(EXTRA_CXXFLAGS) + +libstdc___libbacktrace_la_SOURCES = \ + ../../../libbacktrace/backtrace.h \ + ../../../libbacktrace/atomic.c \ + ../../../libbacktrace/dwarf.c \ + ../../../libbacktrace/fileline.c \ + ../../../libbacktrace/internal.h \ + ../../../libbacktrace/posix.c \ + ../../../libbacktrace/sort.c \ + ../../../libbacktrace/simple.c \ + ../../../libbacktrace/state.c \ + ../../../libiberty/cp-demangle.c + +FORMAT_FILES = \ + ../../../libbacktrace/elf.c \ + ../../../libbacktrace/unknown.c + +VIEW_FILES = \ + ../../../libbacktrace/read.c \ + ../../../libbacktrace/mmapio.c + +ALLOC_FILES = \ + ../../../libbacktrace/alloc.c \ + ../../../libbacktrace/mmap.c + +EXTRA_libstdc___libbacktrace_la_SOURCES = \ + $(FORMAT_FILES) \ + $(VIEW_FILES) \ + $(ALLOC_FILES) + +libstdc___libbacktrace_la_LIBADD = \ + $(FORMAT_FILE) \ + $(VIEW_FILE) \ + $(ALLOC_FILE) + +libstdc___libbacktrace_la_DEPENDENCIES = $(libstdc___libbacktrace_la_LIBADD) + +LTCOMPILE = \ + $(LIBTOOL) --tag CC --tag disable-shared \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(TOPLEVEL_INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) + +LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) + +LINK = \ + $(LIBTOOL) --tag CC --tag disable-shared \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CC) \ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CFLAGS) $(LTLDFLAGS) -o $@ diff --git a/libstdc++-v3/src/libbacktrace/backtrace-rename.h b/libstdc++-v3/src/libbacktrace/backtrace-rename.h new file mode 100644 index 00000000000..7a59f166e62 --- /dev/null +++ b/libstdc++-v3/src/libbacktrace/backtrace-rename.h @@ -0,0 +1,41 @@ +/* Ensure we don't pollute application namespace. */ +#define backtrace_alloc __glibcxx_backtrace_alloc +#define backtrace_close __glibcxx_backtrace_close +#define backtrace_create_state __glibcxx_backtrace_create_state +#define backtrace_dwarf_add __glibcxx_backtrace_dwarf_add +#define backtrace_free __glibcxx_backtrace_free +#define backtrace_get_view __glibcxx_backtrace_get_view +#define backtrace_initialize __glibcxx_backtrace_initialize +#define backtrace_open __glibcxx_backtrace_open +#define backtrace_pcinfo __glibcxx_backtrace_pcinfo +#define backtrace_qsort __glibcxx_backtrace_qsort +#define backtrace_release_view __glibcxx_backtrace_release_view +#define backtrace_simple __glibcxx_backtrace_simple +#define backtrace_state __glibcxx_backtrace_state +#define backtrace_syminfo __glibcxx_backtrace_syminfo +#define backtrace_uncompress_lzma __glibcxx_backtrace_uncompress_lzma +#define backtrace_uncompress_zdebug __glibcxx_backtrace_uncompress_zdebug +#define backtrace_vector_finish __glibcxx_backtrace_vector_finish +#define backtrace_vector_grow __glibcxx_backtrace_vector_grow +#define backtrace_vector_release __glibcxx_backtrace_vector_release +#define backtrace_syminfo_to_full_callback __glibcxx_backtrace_syminfo_to_full_callback +#define backtrace_syminfo_to_full_error_callback __glibcxx_backtrace_syminfo_to_full_error_callback + +#define cplus_demangle_builtin_types __glibcxx_cplus_demangle_builtin_types +#define cplus_demangle_fill_ctor __glibcxx_cplus_demangle_fill_ctor +#define cplus_demangle_fill_dtor __glibcxx_cplus_demangle_fill_dtor +#define cplus_demangle_fill_extended_operator __glibcxx_cplus_demangle_fill_extended_operator +#define cplus_demangle_fill_name __glibcxx_cplus_demangle_fill_name +#define cplus_demangle_init_info __glibcxx_cplus_demangle_init_info +#define cplus_demangle_mangled_name __glibcxx_cplus_demangle_mangled_name +#define cplus_demangle_operators __glibcxx_cplus_demangle_operators +#define cplus_demangle_print __glibcxx_cplus_demangle_print +#define cplus_demangle_print_callback __glibcxx_cplus_demangle_print_callback +#define cplus_demangle_type __glibcxx_cplus_demangle_type +#define cplus_demangle_v3 __glibcxx_cplus_demangle_v3 +#define cplus_demangle_v3_callback __glibcxx_cplus_demangle_v3_callback +#define is_gnu_v3_mangled_ctor __glibcxx_is_gnu_v3_mangled_ctor +#define is_gnu_v3_mangled_dtor __glibcxx_is_gnu_v3_mangled_dtor +#define java_demangle_v3 __glibcxx_java_demangle_v3 +#define java_demangle_v3_callback __glibcxx_java_demangle_v3_callback + diff --git a/libstdc++-v3/src/libbacktrace/backtrace-supported.h.in b/libstdc++-v3/src/libbacktrace/backtrace-supported.h.in new file mode 100644 index 00000000000..a9a32d77494 --- /dev/null +++ b/libstdc++-v3/src/libbacktrace/backtrace-supported.h.in @@ -0,0 +1,61 @@ +/* backtrace-supported.h.in -- Whether stack backtrace is supported. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +/* The file backtrace-supported.h.in is used by configure to generate + the file backtrace-supported.h. The file backtrace-supported.h may + be #include'd to see whether the backtrace library will be able to + get a backtrace and produce symbolic information. */ + + +/* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library + should work, 0 if it will not. Libraries may #include this to make + other arrangements. */ + +#define BACKTRACE_SUPPORTED @BACKTRACE_SUPPORTED@ + +/* BACKTRACE_USES_MALLOC will be #define'd as 1 if the backtrace + library will call malloc as it works, 0 if it will call mmap + instead. This may be used to determine whether it is safe to call + the backtrace functions from a signal handler. In general this + only applies to calls like backtrace and backtrace_pcinfo. It does + not apply to backtrace_simple, which never calls malloc. It does + not apply to backtrace_print, which always calls fprintf and + therefore malloc. */ + +#define BACKTRACE_USES_MALLOC @BACKTRACE_USES_MALLOC@ + +/* BACKTRACE_SUPPORTS_THREADS will be #define'd as 1 if the backtrace + library is configured with threading support, 0 if not. If this is + 0, the threaded parameter to backtrace_create_state must be passed + as 0. */ + +#define BACKTRACE_SUPPORTS_THREADS @BACKTRACE_SUPPORTS_THREADS@ diff --git a/libstdc++-v3/testsuite/20_util/stacktrace/entry.cc b/libstdc++-v3/testsuite/20_util/stacktrace/entry.cc new file mode 100644 index 00000000000..0bbcabd8fae --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/stacktrace/entry.cc @@ -0,0 +1,53 @@ +// { dg-options "-std=gnu++23 -lstdc++_libbacktrace" } +// { dg-do run { target c++23 } } +// { dg-require-effective-target stacktrace } + +#include +#include "testsuite_hooks.h" + +static_assert( std::regular ); +static_assert( std::three_way_comparable ); + +constexpr bool +test_constexpr() +{ + std::stacktrace_entry empty; + VERIFY( !empty ); + VERIFY( empty == empty ); + VERIFY( std::is_eq(empty <=> empty) ); + + std::stacktrace_entry::native_handle_type native = empty.native_handle(); + VERIFY( empty.native_handle() == native ); + + return true; +} +static_assert( test_constexpr() ); + +void +test_members() +{ + std::stacktrace_entry empty; + VERIFY( empty.description().size() == 0 ); + VERIFY( empty.source_file().size() == 0 ); + VERIFY( empty.source_line() == 0 ); + + std::stacktrace_entry e1 = std::stacktrace::current().at(0); + std::stacktrace_entry e2 = std::stacktrace::current().at(0); + VERIFY( e1 != e2 ); + VERIFY( e1.description() == e2.description() ); + VERIFY( e1.source_file() == e2.source_file() ); + VERIFY( e1.source_line() != e2.source_line() ); + + std::stacktrace_entry e3 = []{ + return std::stacktrace::current().at(0); + }(); + VERIFY( e1 != e3 ); + VERIFY( e1.description() != e3.description() ); + VERIFY( e1.source_file() == e3.source_file() ); + VERIFY( e1.source_line() != e3.source_line() ); +} + +int main() +{ + test_constexpr(); +} diff --git a/libstdc++-v3/testsuite/20_util/stacktrace/synopsis.cc b/libstdc++-v3/testsuite/20_util/stacktrace/synopsis.cc new file mode 100644 index 00000000000..72582fa53c6 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/stacktrace/synopsis.cc @@ -0,0 +1,46 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } +// { dg-require-effective-target stacktrace } + +#include + +#ifndef __cpp_lib_stacktrace +# error "Feature-test macro for stacktrace missing in " +#elif __cpp_lib_stacktrace < 202011L +# error "Feature-test macro for stacktrace has wrong value in " +#endif + +namespace std +{ + class stacktrace_entry; + + template + class basic_stacktrace; + + using stacktrace = basic_stacktrace>; + + 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>; + } + + template struct hash; + template<> struct hash; + template struct hash>; +} diff --git a/libstdc++-v3/testsuite/20_util/stacktrace/version.cc b/libstdc++-v3/testsuite/20_util/stacktrace/version.cc new file mode 100644 index 00000000000..ed466be5a36 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/stacktrace/version.cc @@ -0,0 +1,11 @@ +// { dg-options "-std=gnu++23" } +// { dg-do preprocess { target c++23 } } +// { dg-require-effective-target stacktrace } + +#include + +#ifndef __cpp_lib_stacktrace +# error "Feature-test macro for stacktrace missing in " +#elif __cpp_lib_stacktrace < 202011L +# error "Feature-test macro for stacktrace has wrong value in " +#endif diff --git a/libstdc++-v3/testsuite/lib/libstdc++.exp b/libstdc++-v3/testsuite/lib/libstdc++.exp index 273a3dae827..0debbea7ee1 100644 --- a/libstdc++-v3/testsuite/lib/libstdc++.exp +++ b/libstdc++-v3/testsuite/lib/libstdc++.exp @@ -1346,6 +1346,14 @@ proc check_effective_target_std_allocator_new { } { }] } +# Return 1 if libstdc++ was built as --enable-libstdcxx-backtrace +proc check_effective_target_stacktrace { } { + return [check_v3_target_prop_cached et_stacktrace { + set cond "_GLIBCXX_HAVE_STACKTRACE" + return [v3_check_preprocessor_condition stacktrace $cond] + }] +} + set additional_prunes "" if { [info exists env(GCC_RUNTEST_PARALLELIZE_DIR)] \