public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] libstdc++: Add Filesystem TS and std::stacktrace symbols to libstdc++exp.a
@ 2023-09-08 17:06 Jonathan Wakely
  2023-09-08 18:16 ` Jonathan Wakely
  0 siblings, 1 reply; 2+ messages in thread
From: Jonathan Wakely @ 2023-09-08 17:06 UTC (permalink / raw)
  To: libstdc++, gcc-patches

This consolidates the three static archives for extensions into one, so
that -lstdc++exp can be used to provide the definitions of all unstable
library features.

The libstdc++_libbacktrace.a archive is now just a "noinst" convenience
library that is only used during the build, not installed. Its contents
are added to libstdc++exp.a, along with the new non-inline definitions
of std::stacktrace symbols.

The libstdc++fs.a archive is still installed, but its contents are
duplicated in libstdc++exp.a now. This means -lstdc++exp can be used
instead of -lstdc++fs. For targets using the GNU linker we should
consider replacing libstdc++fs.a with a linker script that does
INPUT(libstdc++exp.a).

The tests for <experimental/filesystem> could be changed to use
-lstdc++exp instead of -lstdc++fs, which would allow removing
src/filesystem/.libs from the LDFLAGS in scripts/testsuite_flags.in,
but that can be done at a later date.

libstdc++-v3/ChangeLog:

	* acinclude.m4 (GLIBCXX_CONFIGURE): Add c++23 directory.
	* configure: Regenerate.
	* doc/html/manual/*: Regenerate.
	* doc/xml/manual/using.xml: Update documentation on linking.
	* include/std/stacktrace: Remove declarations of libbacktrace
	APIs.
	(stacktrace_entry::_S_err_handler, stacktrace_entry::_S_init):
	Remove.
	(stacktrace_entry::_Info): New class.
	(stacktrace_entry::_M_get_info): Use _Info.
	(__stacktrace_impl): New class.
	(basic_stacktrace): Derive from __stacktrace_impl.
	(basic_stacktrace::current): Use __stacktrace_impl::_S_current.
	* scripts/testsuite_flags.in: Adjust LDFLAGS to find
	libstdc++exp instead of libstdc++_libbacktrace.
	* src/Makefile.am (SUBDIRS): Add c++23 directory.
	* src/Makefile.in: Regenerate.
	* src/c++20/Makefile.am: Fix comment.
	* src/c++20/Makefile.in: Regenerate.
	* src/c++23/Makefile.am: New file.
	* src/c++23/Makefile.in: New file.
	* src/c++23/stacktrace.cc: New file with definitions of
	stacktrace_entry::_Info and __stacktrace_impl members.
	* src/experimental/Makefile.am: Use LIBADD to include other
	libraries.
	* src/experimental/Makefile.in: Regenerate.
	* src/libbacktrace/Makefile.am: Use noinst_LTLIBRARIES.
	* src/libbacktrace/Makefile.in: Regenerate.
	* testsuite/19_diagnostics/stacktrace/current.cc: Adjust
	dg-options to use -lstdc++exp.
	* testsuite/19_diagnostics/stacktrace/entry.cc: Likewise.
	* testsuite/19_diagnostics/stacktrace/stacktrace.cc: Likewise.
	* testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc:
	Likewise.
---
 libstdc++-v3/acinclude.m4                     |   2 +-
 libstdc++-v3/configure                        |  16 +-
 libstdc++-v3/doc/html/manual/using.html       |  26 +-
 .../html/manual/using_dynamic_or_shared.html  |   4 +
 libstdc++-v3/doc/xml/manual/using.xml         |  37 +-
 libstdc++-v3/include/std/stacktrace           | 144 +---
 libstdc++-v3/scripts/testsuite_flags.in       |   8 +-
 libstdc++-v3/src/Makefile.am                  |   4 +-
 libstdc++-v3/src/Makefile.in                  |   7 +-
 libstdc++-v3/src/c++20/Makefile.am            |   2 +-
 libstdc++-v3/src/c++20/Makefile.in            |   2 +-
 libstdc++-v3/src/c++23/Makefile.am            | 109 +++
 libstdc++-v3/src/c++23/Makefile.in            | 747 ++++++++++++++++++
 libstdc++-v3/src/c++23/stacktrace.cc          | 171 ++++
 libstdc++-v3/src/experimental/Makefile.am     |  20 +
 libstdc++-v3/src/experimental/Makefile.in     |  15 +-
 libstdc++-v3/src/libbacktrace/Makefile.am     |   3 +-
 libstdc++-v3/src/libbacktrace/Makefile.in     |  88 +--
 .../19_diagnostics/stacktrace/current.cc      |   2 +-
 .../19_diagnostics/stacktrace/entry.cc        |   2 +-
 .../19_diagnostics/stacktrace/stacktrace.cc   |   2 +-
 .../vector/debug/assign4_backtrace_neg.cc     |   2 +-
 22 files changed, 1185 insertions(+), 228 deletions(-)
 create mode 100644 libstdc++-v3/src/c++23/Makefile.am
 create mode 100644 libstdc++-v3/src/c++23/Makefile.in
 create mode 100644 libstdc++-v3/src/c++23/stacktrace.cc

diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index fcf79503265..34faa3c049f 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 src/libbacktrace src/experimental doc po testsuite python])
+  m4_define([glibcxx_SUBDIRS],[include libsupc++ src src/c++98 src/c++11 src/c++17 src/c++20 src/c++23 src/filesystem src/libbacktrace src/experimental doc po testsuite python])
   SUBDIRS='glibcxx_SUBDIRS'
 
   # These need to be absolute paths, yet at the same time need to
diff --git a/libstdc++-v3/doc/xml/manual/using.xml b/libstdc++-v3/doc/xml/manual/using.xml
index 3a507fc1671..7276cad0feb 100644
--- a/libstdc++-v3/doc/xml/manual/using.xml
+++ b/libstdc++-v3/doc/xml/manual/using.xml
@@ -100,30 +100,27 @@
       </entry>
     </row>
 
-    <row>
-      <entry><literal>-lstdc++fs</literal></entry>
-      <entry>Linking to <filename class="libraryfile">libstdc++fs</filename>
-        is required for use of the Filesystem library extensions in
-        <filename class="headerfile">&lt;experimental/filesystem&gt;</filename>.
-      </entry>
-    </row>
-
     <row>
       <entry><literal>-lstdc++exp</literal></entry>
-      <entry>Linking to <filename class="libraryfile">libstdc++exp</filename>
-        is required for use of the C++ Contracts extensions enabled by
-        <literal>-fcontracts</literal>.
+      <entry>Linking to <filename class="libraryfile">libstdc++exp.a</filename>
+        is required for use of experimental C++ library features.
+        This currently provides support for the C++23 types defined in the
+        <filename class="headerfile">&lt;stacktrace&gt;</filename> header,
+        the Filesystem library extensions defined in the
+        <filename class="headerfile">&lt;experimental/filesystem&gt;</filename>
+        header,
+        and the Contracts extensions enabled by <literal>-fcontracts</literal>.
       </entry>
     </row>
 
     <row>
-      <entry><literal>-lstdc++_libbacktrace</literal></entry>
-      <entry>Until C++23 support is non-experimental, linking to
-	<filename class="libraryfile">libstdc++_libbacktrace.a</filename>
-	is required for use of the C++23 type
-	<classname>std::stacktrace</classname>
-	and related types in
-	<filename class="headerfile">&lt;stacktrace&gt;</filename>.
+      <entry><literal>-lstdc++fs</literal></entry>
+      <entry>Linking to <filename class="libraryfile">libstdc++fs.a</filename>
+        is another way to use the Filesystem library extensions defined in the
+        <filename class="headerfile">&lt;experimental/filesystem&gt;</filename>
+        header.
+        The <filename class="libraryfile">libstdc++exp.a</filename> library
+        also provides all the symbols contained in this library.
       </entry>
     </row>
 
@@ -1710,6 +1707,10 @@ A quick read of the relevant part of the GCC
       and link with <option>-lstdc++fs</option>. The library implementation
       is incomplete on non-POSIX platforms, specifically Windows is only
       partially supported.
+      Since GCC 14, <filename class="libraryfile">libstdc++exp.a</filename>
+      also contains the definitions for this library,
+      so <option>-lstdc++exp</option> can be used instead of
+      <option>-lstdc++fs</option>.
     </para>
 
     <para>
diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace
index 07949e70861..358a81b82e5 100644
--- a/libstdc++-v3/include/std/stacktrace
+++ b/libstdc++-v3/include/std/stacktrace
@@ -45,43 +45,6 @@
 #include <bits/stl_uninitialized.h>
 #include <ext/numeric_traits.h>
 
-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_TYPE__),
-			   void(*)(void*, const char*, int),
-			   void*);
-int
-__glibcxx_backtrace_pcinfo(__glibcxx_backtrace_state*, __UINTPTR_TYPE__,
-			   int (*)(void*, __UINTPTR_TYPE__,
-				   const char*, int, const char*),
-			   void(*)(void*, const char*, int),
-			   void*);
-
-int
-__glibcxx_backtrace_syminfo(__glibcxx_backtrace_state*, __UINTPTR_TYPE__ addr,
-			    void (*) (void*, __UINTPTR_TYPE__, const char*,
-				      __UINTPTR_TYPE__, __UINTPTR_TYPE__),
-			    void(*)(void*, const char*, int),
-			    void*);
-}
-
-namespace __cxxabiv1
-{
-  extern "C" char*
-  __cxa_demangle(const char* __mangled_name, char* __output_buffer,
-		 size_t* __length, int* __status);
-}
-
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -156,80 +119,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     template<typename _Allocator> friend class basic_stacktrace;
 
-    static void _S_err_handler(void*, const char*, int) { }
-
-    static __glibcxx_backtrace_state*
-    _S_init()
-    {
-      static __glibcxx_backtrace_state* __state
-	= __glibcxx_backtrace_create_state(nullptr, 1, _S_err_handler, nullptr);
-      return __state;
-    }
-
     friend ostream&
     operator<<(ostream&, const stacktrace_entry&);
 
+    // Type-erased wrapper for the fields of a stacktrace entry.
+    // This type is independent of which std::string ABI is in use.
+    struct _Info
+    {
+      void* _M_desc;
+      void* _M_file;
+      int* _M_line;
+      void (*_M_set)(void*, const char*);
+
+      _GLIBCXX_DEFAULT_ABI_TAG
+      static void
+      _S_set(void* __dest, const char* __str)
+      { static_cast<string*>(__dest)->assign(__str); }
+
+      _Info(string* __desc, string* __file, int* __line)
+      : _M_desc(__desc), _M_file(__file), _M_line(__line), _M_set(_S_set)
+      { }
+
+      bool
+      _M_populate(native_handle_type);
+
+      void _M_set_file(const char*);
+      void _M_set_desc(const char*);
+    };
+
     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, _S_err_handler,
-				       &__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,
-					    _S_err_handler, &__data))
-	    return true;
-	}
-      return false;
+      return _Info(__desc, __file, __line)._M_populate(_M_pc);
     }
+  };
 
-    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;
-      else
-	__s = __name;
-      __builtin_free(__str);
-      return __s;
-    }
+  class __stacktrace_impl
+  {
+  protected:
+    static int _S_current(int (*) (void*, __UINTPTR_TYPE__), void*, int = 0);
   };
 
   // [stacktrace.basic], class template basic_stacktrace
   template<typename _Allocator>
     class basic_stacktrace
+    : private __stacktrace_impl
     {
       using _AllocTraits = allocator_traits<_Allocator>;
       using uintptr_t = __UINTPTR_TYPE__;
@@ -256,10 +192,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	basic_stacktrace __ret(__alloc);
 	if (auto __cb = __ret._M_prepare()) [[likely]]
 	  {
-	    auto __state = stacktrace_entry::_S_init();
-	    if (__glibcxx_backtrace_simple(__state, 1, __cb,
-					   stacktrace_entry::_S_err_handler,
-					   std::__addressof(__ret)))
+	    if (_S_current(__cb, std::__addressof(__ret)))
 	      __ret._M_clear();
 	  }
 	return __ret;
@@ -275,10 +208,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  return __ret;
 	if (auto __cb = __ret._M_prepare()) [[likely]]
 	  {
-	    auto __state = stacktrace_entry::_S_init();
-	    if (__glibcxx_backtrace_simple(__state, __skip + 1, __cb,
-					   stacktrace_entry::_S_err_handler,
-					   std::__addressof(__ret)))
+	    if (_S_current(__cb, std::__addressof(__ret), __skip))
 	      __ret._M_clear();
 	  }
 
@@ -299,11 +229,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  return __ret;
 	if (auto __cb = __ret._M_prepare(__max_depth)) [[likely]]
 	  {
-	    auto __state = stacktrace_entry::_S_init();
-	    int __err = __glibcxx_backtrace_simple(__state, __skip + 1, __cb,
-						   stacktrace_entry::_S_err_handler,
-						   std::__addressof(__ret));
-	    if (__err < 0)
+	    if (_S_current(__cb, std::__addressof(__ret), __skip) < 0)
 	      __ret._M_clear();
 	    else if (__ret.size() > __max_depth)
 	      {
diff --git a/libstdc++-v3/scripts/testsuite_flags.in b/libstdc++-v3/scripts/testsuite_flags.in
index 18748f0f9ce..8bf4918287a 100755
--- a/libstdc++-v3/scripts/testsuite_flags.in
+++ b/libstdc++-v3/scripts/testsuite_flags.in
@@ -78,14 +78,14 @@ case ${query} in
       ;;
     --cxxldflags)
       FS_LDFLAGS=
-      BT_LDFLAGS=
+      EXP_LDFLAGS=
       if [ -d ${BUILD_DIR}/src/filesystem/.libs ]; then
         FS_LDFLAGS=-L${BUILD_DIR}/src/filesystem/.libs
       fi
-      if [ -d ${BUILD_DIR}/src/libbacktrace/.libs ]; then
-        BT_LDFLAGS=-L${BUILD_DIR}/src/libbacktrace/.libs
+      if [ -d ${BUILD_DIR}/src/experimental/.libs ]; then
+        EXP_LDFLAGS=-L${BUILD_DIR}/src/experimental/.libs
       fi
-      SECTIONLDFLAGS="@SECTION_LDFLAGS@ @LIBICONV@ $FS_LDFLAGS $BT_LDFLAGS"
+      SECTIONLDFLAGS="@SECTION_LDFLAGS@ @LIBICONV@ $FS_LDFLAGS $EXP_LDFLAGS"
       echo ${SECTIONLDFLAGS}
       ;;
     *)
diff --git a/libstdc++-v3/src/Makefile.am b/libstdc++-v3/src/Makefile.am
index 5b9af41cdb9..32de5304122 100644
--- a/libstdc++-v3/src/Makefile.am
+++ b/libstdc++-v3/src/Makefile.am
@@ -43,7 +43,8 @@ experimental_dir =
 endif
 
 ## Keep this list sync'd with acinclude.m4:GLIBCXX_CONFIGURE.
-SUBDIRS = c++98 c++11 c++17 c++20 $(filesystem_dir) $(backtrace_dir) $(experimental_dir)
+SUBDIRS = c++98 c++11 c++17 c++20 c++23 \
+	$(filesystem_dir) $(backtrace_dir) $(experimental_dir)
 
 # Cross compiler support.
 if VTV_CYGMIN
@@ -75,6 +76,7 @@ vpath % $(top_srcdir)/src/c++98
 vpath % $(top_srcdir)/src/c++11
 vpath % $(top_srcdir)/src/c++17
 vpath % $(top_srcdir)/src/c++20
+vpath % $(top_srcdir)/src/c++23
 if ENABLE_FILESYSTEM_TS
 vpath % $(top_srcdir)/src/filesystem
 endif
diff --git a/libstdc++-v3/src/c++20/Makefile.am b/libstdc++-v3/src/c++20/Makefile.am
index 0bc8a7b832a..e947855e6ae 100644
--- a/libstdc++-v3/src/c++20/Makefile.am
+++ b/libstdc++-v3/src/c++20/Makefile.am
@@ -22,7 +22,7 @@
 
 include $(top_srcdir)/fragment.am
 
-# Convenience library for C++17 runtime.
+# Convenience library for C++20 runtime.
 noinst_LTLIBRARIES = libc++20convenience.la
 
 headers =
diff --git a/libstdc++-v3/src/c++23/Makefile.am b/libstdc++-v3/src/c++23/Makefile.am
new file mode 100644
index 00000000000..da988c352f8
--- /dev/null
+++ b/libstdc++-v3/src/c++23/Makefile.am
@@ -0,0 +1,109 @@
+## Makefile for the C++23 sources of the GNU C++ Standard library.
+##
+## Copyright (C) 1997-2023 Free Software Foundation, Inc.
+##
+## This file is part of the libstdc++ version 3 distribution.
+## Process this file with automake to produce Makefile.in.
+
+## 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, or (at your option)
+## any later version.
+
+## 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.
+
+## You should have received a copy of the GNU General Public License along
+## with this library; see the file COPYING3.  If not see
+## <http://www.gnu.org/licenses/>.
+
+include $(top_srcdir)/fragment.am
+
+# Convenience library for C++23 runtime.
+noinst_LTLIBRARIES = libc++23convenience.la
+
+headers =
+
+if ENABLE_EXTERN_TEMPLATE
+# XTEMPLATE_FLAGS = -fno-implicit-templates
+inst_sources =
+else
+# XTEMPLATE_FLAGS =
+inst_sources =
+endif
+
+sources = stacktrace.cc
+
+vpath % $(top_srcdir)/src/c++23
+
+
+if GLIBCXX_HOSTED
+libc__23convenience_la_SOURCES = $(sources)  $(inst_sources)
+else
+libc__23convenience_la_SOURCES =
+endif
+
+# AM_CXXFLAGS needs to be in each subdirectory so that it can be
+# modified in a per-library or per-sub-library way.  Need to manually
+# set this option because CONFIG_CXXFLAGS has to be after
+# OPTIMIZE_CXXFLAGS on the compile line so that -O2 can be overridden
+# as the occasion calls for it.
+AM_CXXFLAGS = \
+	-std=gnu++23 \
+	$(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
+	$(XTEMPLATE_FLAGS) $(VTV_CXXFLAGS) \
+	$(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS) \
+	-fimplicit-templates
+
+AM_MAKEFLAGS = \
+	"gxx_include_dir=$(gxx_include_dir)"
+
+# Libtool notes
+
+# 1) In general, libtool expects an argument such as `--tag=CXX' when
+# using the C++ compiler, because that will enable the settings
+# detected when C++ support was being configured.  However, when no
+# such flag is given in the command line, libtool attempts to figure
+# it out by matching the compiler name in each configuration section
+# against a prefix of the command line.  The problem is that, if the
+# compiler name and its initial flags stored in the libtool
+# configuration file don't match those in the command line, libtool
+# can't decide which configuration to use, and it gives up.  The
+# correct solution is to add `--tag CXX' to LTCXXCOMPILE and maybe
+# CXXLINK, just after $(LIBTOOL), so that libtool doesn't have to
+# attempt to infer which configuration to use.
+#
+# The second tag argument, `--tag disable-shared` means that libtool
+# only compiles each source once, for static objects. In actuality,
+# glibcxx_lt_pic_flag and glibcxx_compiler_shared_flag are added to
+# the libtool command that is used create the object, which is
+# suitable for shared libraries.  The `--tag disable-shared` must be
+# placed after --tag CXX lest things CXX undo the affect of
+# disable-shared.
+
+# 2) Need to explicitly set LTCXXCOMPILE so that EXTRA_CXX_FLAGS is
+# last. (That way, things like -O2 passed down from the toplevel can
+# be overridden by --enable-debug.)
+LTCXXCOMPILE = \
+	$(LIBTOOL) --tag CXX --tag disable-shared \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CXX) $(TOPLEVEL_INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(EXTRA_CXX_FLAGS)
+
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
+
+# 3) We'd have a problem when building the shared libstdc++ object if
+# the rules automake generates would be used.  We cannot allow g++ to
+# be used since this would add -lstdc++ to the link line which of
+# course is problematic at this point.  So, we get the top-level
+# directory to configure libstdc++-v3 to use gcc as the C++
+# compilation driver.
+CXXLINK = \
+	$(LIBTOOL) --tag CXX --tag disable-shared \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CXX) \
+	$(VTV_CXXLINKFLAGS) \
+	$(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
diff --git a/libstdc++-v3/src/c++23/stacktrace.cc b/libstdc++-v3/src/c++23/stacktrace.cc
new file mode 100644
index 00000000000..10cfa44e4f5
--- /dev/null
+++ b/libstdc++-v3/src/c++23/stacktrace.cc
@@ -0,0 +1,171 @@
+// Implementation of <stacktrace> -*- 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
+// <http://www.gnu.org/licenses/>.
+
+#include <stacktrace>
+#include <cstdlib>
+
+#ifdef __cpp_lib_stacktrace // C++ >= 23 && hosted && HAVE_STACKTRACE
+struct __glibcxx_backtrace_state;
+
+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_TYPE__),
+			   void(*)(void*, const char*, int),
+			   void*);
+int
+__glibcxx_backtrace_pcinfo(__glibcxx_backtrace_state*, __UINTPTR_TYPE__,
+			   int (*)(void*, __UINTPTR_TYPE__,
+				   const char*, int, const char*),
+			   void(*)(void*, const char*, int),
+			   void*);
+
+int
+__glibcxx_backtrace_syminfo(__glibcxx_backtrace_state*, __UINTPTR_TYPE__ addr,
+			    void (*) (void*, __UINTPTR_TYPE__, const char*,
+				      __UINTPTR_TYPE__, __UINTPTR_TYPE__),
+			    void(*)(void*, const char*, int),
+			    void*);
+}
+
+namespace __cxxabiv1
+{
+  extern "C" char*
+  __cxa_demangle(const char* mangled_name, char* output_buffer, size_t* length,
+		 int* status);
+}
+
+namespace std
+{
+namespace
+{
+  char*
+  demangle(const char* name)
+  {
+    int status;
+    char* str = __cxxabiv1::__cxa_demangle(name, nullptr, nullptr, &status);
+    if (status == 0)
+      return str;
+    else
+      {
+	std::free(str);
+	return nullptr;
+      }
+  }
+
+  void
+  err_handler(void*, const char*, int)
+  { }
+
+  __glibcxx_backtrace_state*
+  init()
+  {
+#if __GTHREADS && ! defined(__cpp_threadsafe_static_init)
+# warning "std::stacktrace initialization will not be thread-safe"
+#endif
+    static __glibcxx_backtrace_state* state
+      = __glibcxx_backtrace_create_state(nullptr, 1, err_handler, nullptr);
+    return state;
+  }
+}
+
+void
+stacktrace_entry::_Info::_M_set_file(const char* filename)
+{
+  if (filename && _M_file)
+    _M_set(_M_file, filename);
+}
+
+void
+stacktrace_entry::_Info::_M_set_desc(const char* function)
+{
+  if (function && _M_desc)
+    {
+      if (char* s = demangle(function))
+	{
+	  _M_set(_M_desc, s);
+	  std::free(s);
+	}
+      else
+	_M_set(_M_desc, function);
+    }
+}
+
+#pragma GCC diagnostic push
+// The closure types below don't escape so we don't care about their mangling.
+#pragma GCC diagnostic ignored "-Wabi"
+bool
+stacktrace_entry::_Info::_M_populate(native_handle_type pc)
+{
+  auto cb = [](void* self, uintptr_t, const char* filename, int lineno,
+	       const char* function) -> int
+  {
+    auto& info = *static_cast<_Info*>(self);
+    info._M_set_desc(function);
+    info._M_set_file(filename);
+    if (info._M_line)
+      *info._M_line = lineno;
+    return function != nullptr;
+  };
+  const auto state = init();
+  if (::__glibcxx_backtrace_pcinfo(state, pc, +cb, err_handler, this))
+    return true;
+
+  // If we get here then backtrace_pcinfo did not give us a function name.
+  // If the caller wanted a function name, try again using backtrace_syminfo.
+  if (_M_desc)
+    {
+      auto cb2 = [](void* self, uintptr_t, const char* symname,
+		    uintptr_t, uintptr_t)
+      {
+	static_cast<_Info*>(self)->_M_set_desc(symname);
+      };
+      if (::__glibcxx_backtrace_syminfo(state, pc, +cb2, err_handler, this))
+	return true;
+    }
+  return false;
+}
+#pragma GCC diagnostic pop
+
+// Ensure no tail-call optimization, so that this frame isn't reused for the
+// backtrace_simple call, so that the number of frames to skip doesn't vary.
+[[gnu::optimize("no-optimize-sibling-calls")]]
+int
+__stacktrace_impl::_S_current(int (*cb) (void*, __UINTPTR_TYPE__), void* obj,
+			      int skip)
+{
+  const auto state = init();
+  // skip+2 because we don't want this function or its caller to be included.
+  int r = ::__glibcxx_backtrace_simple(state, skip + 2, cb, err_handler, obj);
+  // Could also use this to prevent tail-call optim: __asm ("" : "+g" (r));
+  return r;
+}
+
+}
+#endif
diff --git a/libstdc++-v3/src/experimental/Makefile.am b/libstdc++-v3/src/experimental/Makefile.am
index 3b962e7d804..a61465f4eaf 100644
--- a/libstdc++-v3/src/experimental/Makefile.am
+++ b/libstdc++-v3/src/experimental/Makefile.am
@@ -24,6 +24,18 @@ include $(top_srcdir)/fragment.am
 
 toolexeclib_LTLIBRARIES = libstdc++exp.la
 
+if ENABLE_FILESYSTEM_TS
+filesystem_lib = $(top_builddir)/src/filesystem/libstdc++fs.la
+else
+filesystem_lib =
+endif
+
+if ENABLE_BACKTRACE
+backtrace_lib = $(top_builddir)/src/libbacktrace/libstdc++_libbacktrace.la
+else
+backtrace_lib =
+endif
+
 headers =
 
 sources = \
@@ -33,6 +45,14 @@ sources = \
 
 libstdc__exp_la_SOURCES = $(sources)
 
+libstdc__exp_la_LIBADD = \
+	$(top_builddir)/src/c++23/libc++23convenience.la \
+	$(filesystem_lib) $(backtrace_lib)
+
+libstdc__exp_la_DEPENDENCIES = \
+	$(top_builddir)/src/c++23/libc++23convenience.la \
+	$(filesystem_lib) $(backtrace_lib)
+
 # AM_CXXFLAGS needs to be in each subdirectory so that it can be
 # modified in a per-library or per-sub-library way.  Need to manually
 # set this option because CONFIG_CXXFLAGS has to be after
diff --git a/libstdc++-v3/src/libbacktrace/Makefile.am b/libstdc++-v3/src/libbacktrace/Makefile.am
index 27c1ea570e0..492d3b6e952 100644
--- a/libstdc++-v3/src/libbacktrace/Makefile.am
+++ b/libstdc++-v3/src/libbacktrace/Makefile.am
@@ -31,7 +31,8 @@
 
 include $(top_srcdir)/fragment.am
 
-toolexeclib_LTLIBRARIES = libstdc++_libbacktrace.la
+# Convenience library for C++23 runtime.
+noinst_LTLIBRARIES = libstdc++_libbacktrace.la
 
 ACLOCAL_AMFLAGS = -I ../.. -I ../../config
 
diff --git a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/current.cc b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/current.cc
index 184e23b460e..f6c860fc7a4 100644
--- a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/current.cc
+++ b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/current.cc
@@ -1,4 +1,4 @@
-// { dg-options "-std=gnu++23 -lstdc++_libbacktrace" }
+// { dg-options "-std=gnu++23 -lstdc++exp" }
 // { dg-do run { target c++23 } }
 // { dg-require-effective-target stacktrace }
 
diff --git a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc
index a222c425b20..f0406953d03 100644
--- a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc
+++ b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc
@@ -1,4 +1,4 @@
-// { dg-options "-std=gnu++23 -lstdc++_libbacktrace" }
+// { dg-options "-std=gnu++23 -lstdc++exp" }
 // { dg-do run { target c++23 } }
 // { dg-require-effective-target stacktrace }
 
diff --git a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/stacktrace.cc b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/stacktrace.cc
index 8dfdf4739be..0a358b7b8ff 100644
--- a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/stacktrace.cc
+++ b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/stacktrace.cc
@@ -1,4 +1,4 @@
-// { dg-options "-std=gnu++23 -lstdc++_libbacktrace" }
+// { dg-options "-std=gnu++23 -lstdc++exp" }
 // { dg-do run { target c++23 } }
 // { dg-require-effective-target stacktrace }
 
diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc
index 520788d5cb7..43a82fb1201 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc
@@ -1,5 +1,5 @@
 // { dg-do run { xfail *-*-* } }
-// { dg-options "-D_GLIBCXX_DEBUG_BACKTRACE -lstdc++_libbacktrace" }
+// { dg-options "-D_GLIBCXX_DEBUG_BACKTRACE -lstdc++exp" }
 // { dg-require-effective-target stacktrace }
 
 #include <debug/vector>
-- 
2.41.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [committed] libstdc++: Add Filesystem TS and std::stacktrace symbols to libstdc++exp.a
  2023-09-08 17:06 [committed] libstdc++: Add Filesystem TS and std::stacktrace symbols to libstdc++exp.a Jonathan Wakely
@ 2023-09-08 18:16 ` Jonathan Wakely
  0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2023-09-08 18:16 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

I forgot to say:

Tested x86_64-linux and aarch64-linux, built for avr, arm-eabi and
cris-elf.

Pushed to trunk.


On Fri, 8 Sept 2023 at 18:09, Jonathan Wakely via Libstdc++
<libstdc++@gcc.gnu.org> wrote:
>
> This consolidates the three static archives for extensions into one, so
> that -lstdc++exp can be used to provide the definitions of all unstable
> library features.
>
> The libstdc++_libbacktrace.a archive is now just a "noinst" convenience
> library that is only used during the build, not installed. Its contents
> are added to libstdc++exp.a, along with the new non-inline definitions
> of std::stacktrace symbols.
>
> The libstdc++fs.a archive is still installed, but its contents are
> duplicated in libstdc++exp.a now. This means -lstdc++exp can be used
> instead of -lstdc++fs. For targets using the GNU linker we should
> consider replacing libstdc++fs.a with a linker script that does
> INPUT(libstdc++exp.a).
>
> The tests for <experimental/filesystem> could be changed to use
> -lstdc++exp instead of -lstdc++fs, which would allow removing
> src/filesystem/.libs from the LDFLAGS in scripts/testsuite_flags.in,
> but that can be done at a later date.
>
> libstdc++-v3/ChangeLog:
>
>         * acinclude.m4 (GLIBCXX_CONFIGURE): Add c++23 directory.
>         * configure: Regenerate.
>         * doc/html/manual/*: Regenerate.
>         * doc/xml/manual/using.xml: Update documentation on linking.
>         * include/std/stacktrace: Remove declarations of libbacktrace
>         APIs.
>         (stacktrace_entry::_S_err_handler, stacktrace_entry::_S_init):
>         Remove.
>         (stacktrace_entry::_Info): New class.
>         (stacktrace_entry::_M_get_info): Use _Info.
>         (__stacktrace_impl): New class.
>         (basic_stacktrace): Derive from __stacktrace_impl.
>         (basic_stacktrace::current): Use __stacktrace_impl::_S_current.
>         * scripts/testsuite_flags.in: Adjust LDFLAGS to find
>         libstdc++exp instead of libstdc++_libbacktrace.
>         * src/Makefile.am (SUBDIRS): Add c++23 directory.
>         * src/Makefile.in: Regenerate.
>         * src/c++20/Makefile.am: Fix comment.
>         * src/c++20/Makefile.in: Regenerate.
>         * src/c++23/Makefile.am: New file.
>         * src/c++23/Makefile.in: New file.
>         * src/c++23/stacktrace.cc: New file with definitions of
>         stacktrace_entry::_Info and __stacktrace_impl members.
>         * src/experimental/Makefile.am: Use LIBADD to include other
>         libraries.
>         * src/experimental/Makefile.in: Regenerate.
>         * src/libbacktrace/Makefile.am: Use noinst_LTLIBRARIES.
>         * src/libbacktrace/Makefile.in: Regenerate.
>         * testsuite/19_diagnostics/stacktrace/current.cc: Adjust
>         dg-options to use -lstdc++exp.
>         * testsuite/19_diagnostics/stacktrace/entry.cc: Likewise.
>         * testsuite/19_diagnostics/stacktrace/stacktrace.cc: Likewise.
>         * testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc:
>         Likewise.
> ---
>  libstdc++-v3/acinclude.m4                     |   2 +-
>  libstdc++-v3/configure                        |  16 +-
>  libstdc++-v3/doc/html/manual/using.html       |  26 +-
>  .../html/manual/using_dynamic_or_shared.html  |   4 +
>  libstdc++-v3/doc/xml/manual/using.xml         |  37 +-
>  libstdc++-v3/include/std/stacktrace           | 144 +---
>  libstdc++-v3/scripts/testsuite_flags.in       |   8 +-
>  libstdc++-v3/src/Makefile.am                  |   4 +-
>  libstdc++-v3/src/Makefile.in                  |   7 +-
>  libstdc++-v3/src/c++20/Makefile.am            |   2 +-
>  libstdc++-v3/src/c++20/Makefile.in            |   2 +-
>  libstdc++-v3/src/c++23/Makefile.am            | 109 +++
>  libstdc++-v3/src/c++23/Makefile.in            | 747 ++++++++++++++++++
>  libstdc++-v3/src/c++23/stacktrace.cc          | 171 ++++
>  libstdc++-v3/src/experimental/Makefile.am     |  20 +
>  libstdc++-v3/src/experimental/Makefile.in     |  15 +-
>  libstdc++-v3/src/libbacktrace/Makefile.am     |   3 +-
>  libstdc++-v3/src/libbacktrace/Makefile.in     |  88 +--
>  .../19_diagnostics/stacktrace/current.cc      |   2 +-
>  .../19_diagnostics/stacktrace/entry.cc        |   2 +-
>  .../19_diagnostics/stacktrace/stacktrace.cc   |   2 +-
>  .../vector/debug/assign4_backtrace_neg.cc     |   2 +-
>  22 files changed, 1185 insertions(+), 228 deletions(-)
>  create mode 100644 libstdc++-v3/src/c++23/Makefile.am
>  create mode 100644 libstdc++-v3/src/c++23/Makefile.in
>  create mode 100644 libstdc++-v3/src/c++23/stacktrace.cc
>
> diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
> index fcf79503265..34faa3c049f 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 src/libbacktrace src/experimental doc po testsuite python])
> +  m4_define([glibcxx_SUBDIRS],[include libsupc++ src src/c++98 src/c++11 src/c++17 src/c++20 src/c++23 src/filesystem src/libbacktrace src/experimental doc po testsuite python])
>    SUBDIRS='glibcxx_SUBDIRS'
>
>    # These need to be absolute paths, yet at the same time need to
> diff --git a/libstdc++-v3/doc/xml/manual/using.xml b/libstdc++-v3/doc/xml/manual/using.xml
> index 3a507fc1671..7276cad0feb 100644
> --- a/libstdc++-v3/doc/xml/manual/using.xml
> +++ b/libstdc++-v3/doc/xml/manual/using.xml
> @@ -100,30 +100,27 @@
>        </entry>
>      </row>
>
> -    <row>
> -      <entry><literal>-lstdc++fs</literal></entry>
> -      <entry>Linking to <filename class="libraryfile">libstdc++fs</filename>
> -        is required for use of the Filesystem library extensions in
> -        <filename class="headerfile">&lt;experimental/filesystem&gt;</filename>.
> -      </entry>
> -    </row>
> -
>      <row>
>        <entry><literal>-lstdc++exp</literal></entry>
> -      <entry>Linking to <filename class="libraryfile">libstdc++exp</filename>
> -        is required for use of the C++ Contracts extensions enabled by
> -        <literal>-fcontracts</literal>.
> +      <entry>Linking to <filename class="libraryfile">libstdc++exp.a</filename>
> +        is required for use of experimental C++ library features.
> +        This currently provides support for the C++23 types defined in the
> +        <filename class="headerfile">&lt;stacktrace&gt;</filename> header,
> +        the Filesystem library extensions defined in the
> +        <filename class="headerfile">&lt;experimental/filesystem&gt;</filename>
> +        header,
> +        and the Contracts extensions enabled by <literal>-fcontracts</literal>.
>        </entry>
>      </row>
>
>      <row>
> -      <entry><literal>-lstdc++_libbacktrace</literal></entry>
> -      <entry>Until C++23 support is non-experimental, linking to
> -       <filename class="libraryfile">libstdc++_libbacktrace.a</filename>
> -       is required for use of the C++23 type
> -       <classname>std::stacktrace</classname>
> -       and related types in
> -       <filename class="headerfile">&lt;stacktrace&gt;</filename>.
> +      <entry><literal>-lstdc++fs</literal></entry>
> +      <entry>Linking to <filename class="libraryfile">libstdc++fs.a</filename>
> +        is another way to use the Filesystem library extensions defined in the
> +        <filename class="headerfile">&lt;experimental/filesystem&gt;</filename>
> +        header.
> +        The <filename class="libraryfile">libstdc++exp.a</filename> library
> +        also provides all the symbols contained in this library.
>        </entry>
>      </row>
>
> @@ -1710,6 +1707,10 @@ A quick read of the relevant part of the GCC
>        and link with <option>-lstdc++fs</option>. The library implementation
>        is incomplete on non-POSIX platforms, specifically Windows is only
>        partially supported.
> +      Since GCC 14, <filename class="libraryfile">libstdc++exp.a</filename>
> +      also contains the definitions for this library,
> +      so <option>-lstdc++exp</option> can be used instead of
> +      <option>-lstdc++fs</option>.
>      </para>
>
>      <para>
> diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace
> index 07949e70861..358a81b82e5 100644
> --- a/libstdc++-v3/include/std/stacktrace
> +++ b/libstdc++-v3/include/std/stacktrace
> @@ -45,43 +45,6 @@
>  #include <bits/stl_uninitialized.h>
>  #include <ext/numeric_traits.h>
>
> -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_TYPE__),
> -                          void(*)(void*, const char*, int),
> -                          void*);
> -int
> -__glibcxx_backtrace_pcinfo(__glibcxx_backtrace_state*, __UINTPTR_TYPE__,
> -                          int (*)(void*, __UINTPTR_TYPE__,
> -                                  const char*, int, const char*),
> -                          void(*)(void*, const char*, int),
> -                          void*);
> -
> -int
> -__glibcxx_backtrace_syminfo(__glibcxx_backtrace_state*, __UINTPTR_TYPE__ addr,
> -                           void (*) (void*, __UINTPTR_TYPE__, const char*,
> -                                     __UINTPTR_TYPE__, __UINTPTR_TYPE__),
> -                           void(*)(void*, const char*, int),
> -                           void*);
> -}
> -
> -namespace __cxxabiv1
> -{
> -  extern "C" char*
> -  __cxa_demangle(const char* __mangled_name, char* __output_buffer,
> -                size_t* __length, int* __status);
> -}
> -
>  namespace std _GLIBCXX_VISIBILITY(default)
>  {
>  _GLIBCXX_BEGIN_NAMESPACE_VERSION
> @@ -156,80 +119,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
>      template<typename _Allocator> friend class basic_stacktrace;
>
> -    static void _S_err_handler(void*, const char*, int) { }
> -
> -    static __glibcxx_backtrace_state*
> -    _S_init()
> -    {
> -      static __glibcxx_backtrace_state* __state
> -       = __glibcxx_backtrace_create_state(nullptr, 1, _S_err_handler, nullptr);
> -      return __state;
> -    }
> -
>      friend ostream&
>      operator<<(ostream&, const stacktrace_entry&);
>
> +    // Type-erased wrapper for the fields of a stacktrace entry.
> +    // This type is independent of which std::string ABI is in use.
> +    struct _Info
> +    {
> +      void* _M_desc;
> +      void* _M_file;
> +      int* _M_line;
> +      void (*_M_set)(void*, const char*);
> +
> +      _GLIBCXX_DEFAULT_ABI_TAG
> +      static void
> +      _S_set(void* __dest, const char* __str)
> +      { static_cast<string*>(__dest)->assign(__str); }
> +
> +      _Info(string* __desc, string* __file, int* __line)
> +      : _M_desc(__desc), _M_file(__file), _M_line(__line), _M_set(_S_set)
> +      { }
> +
> +      bool
> +      _M_populate(native_handle_type);
> +
> +      void _M_set_file(const char*);
> +      void _M_set_desc(const char*);
> +    };
> +
>      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, _S_err_handler,
> -                                      &__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,
> -                                           _S_err_handler, &__data))
> -           return true;
> -       }
> -      return false;
> +      return _Info(__desc, __file, __line)._M_populate(_M_pc);
>      }
> +  };
>
> -    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;
> -      else
> -       __s = __name;
> -      __builtin_free(__str);
> -      return __s;
> -    }
> +  class __stacktrace_impl
> +  {
> +  protected:
> +    static int _S_current(int (*) (void*, __UINTPTR_TYPE__), void*, int = 0);
>    };
>
>    // [stacktrace.basic], class template basic_stacktrace
>    template<typename _Allocator>
>      class basic_stacktrace
> +    : private __stacktrace_impl
>      {
>        using _AllocTraits = allocator_traits<_Allocator>;
>        using uintptr_t = __UINTPTR_TYPE__;
> @@ -256,10 +192,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         basic_stacktrace __ret(__alloc);
>         if (auto __cb = __ret._M_prepare()) [[likely]]
>           {
> -           auto __state = stacktrace_entry::_S_init();
> -           if (__glibcxx_backtrace_simple(__state, 1, __cb,
> -                                          stacktrace_entry::_S_err_handler,
> -                                          std::__addressof(__ret)))
> +           if (_S_current(__cb, std::__addressof(__ret)))
>               __ret._M_clear();
>           }
>         return __ret;
> @@ -275,10 +208,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>           return __ret;
>         if (auto __cb = __ret._M_prepare()) [[likely]]
>           {
> -           auto __state = stacktrace_entry::_S_init();
> -           if (__glibcxx_backtrace_simple(__state, __skip + 1, __cb,
> -                                          stacktrace_entry::_S_err_handler,
> -                                          std::__addressof(__ret)))
> +           if (_S_current(__cb, std::__addressof(__ret), __skip))
>               __ret._M_clear();
>           }
>
> @@ -299,11 +229,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>           return __ret;
>         if (auto __cb = __ret._M_prepare(__max_depth)) [[likely]]
>           {
> -           auto __state = stacktrace_entry::_S_init();
> -           int __err = __glibcxx_backtrace_simple(__state, __skip + 1, __cb,
> -                                                  stacktrace_entry::_S_err_handler,
> -                                                  std::__addressof(__ret));
> -           if (__err < 0)
> +           if (_S_current(__cb, std::__addressof(__ret), __skip) < 0)
>               __ret._M_clear();
>             else if (__ret.size() > __max_depth)
>               {
> diff --git a/libstdc++-v3/scripts/testsuite_flags.in b/libstdc++-v3/scripts/testsuite_flags.in
> index 18748f0f9ce..8bf4918287a 100755
> --- a/libstdc++-v3/scripts/testsuite_flags.in
> +++ b/libstdc++-v3/scripts/testsuite_flags.in
> @@ -78,14 +78,14 @@ case ${query} in
>        ;;
>      --cxxldflags)
>        FS_LDFLAGS=
> -      BT_LDFLAGS=
> +      EXP_LDFLAGS=
>        if [ -d ${BUILD_DIR}/src/filesystem/.libs ]; then
>          FS_LDFLAGS=-L${BUILD_DIR}/src/filesystem/.libs
>        fi
> -      if [ -d ${BUILD_DIR}/src/libbacktrace/.libs ]; then
> -        BT_LDFLAGS=-L${BUILD_DIR}/src/libbacktrace/.libs
> +      if [ -d ${BUILD_DIR}/src/experimental/.libs ]; then
> +        EXP_LDFLAGS=-L${BUILD_DIR}/src/experimental/.libs
>        fi
> -      SECTIONLDFLAGS="@SECTION_LDFLAGS@ @LIBICONV@ $FS_LDFLAGS $BT_LDFLAGS"
> +      SECTIONLDFLAGS="@SECTION_LDFLAGS@ @LIBICONV@ $FS_LDFLAGS $EXP_LDFLAGS"
>        echo ${SECTIONLDFLAGS}
>        ;;
>      *)
> diff --git a/libstdc++-v3/src/Makefile.am b/libstdc++-v3/src/Makefile.am
> index 5b9af41cdb9..32de5304122 100644
> --- a/libstdc++-v3/src/Makefile.am
> +++ b/libstdc++-v3/src/Makefile.am
> @@ -43,7 +43,8 @@ experimental_dir =
>  endif
>
>  ## Keep this list sync'd with acinclude.m4:GLIBCXX_CONFIGURE.
> -SUBDIRS = c++98 c++11 c++17 c++20 $(filesystem_dir) $(backtrace_dir) $(experimental_dir)
> +SUBDIRS = c++98 c++11 c++17 c++20 c++23 \
> +       $(filesystem_dir) $(backtrace_dir) $(experimental_dir)
>
>  # Cross compiler support.
>  if VTV_CYGMIN
> @@ -75,6 +76,7 @@ vpath % $(top_srcdir)/src/c++98
>  vpath % $(top_srcdir)/src/c++11
>  vpath % $(top_srcdir)/src/c++17
>  vpath % $(top_srcdir)/src/c++20
> +vpath % $(top_srcdir)/src/c++23
>  if ENABLE_FILESYSTEM_TS
>  vpath % $(top_srcdir)/src/filesystem
>  endif
> diff --git a/libstdc++-v3/src/c++20/Makefile.am b/libstdc++-v3/src/c++20/Makefile.am
> index 0bc8a7b832a..e947855e6ae 100644
> --- a/libstdc++-v3/src/c++20/Makefile.am
> +++ b/libstdc++-v3/src/c++20/Makefile.am
> @@ -22,7 +22,7 @@
>
>  include $(top_srcdir)/fragment.am
>
> -# Convenience library for C++17 runtime.
> +# Convenience library for C++20 runtime.
>  noinst_LTLIBRARIES = libc++20convenience.la
>
>  headers =
> diff --git a/libstdc++-v3/src/c++23/Makefile.am b/libstdc++-v3/src/c++23/Makefile.am
> new file mode 100644
> index 00000000000..da988c352f8
> --- /dev/null
> +++ b/libstdc++-v3/src/c++23/Makefile.am
> @@ -0,0 +1,109 @@
> +## Makefile for the C++23 sources of the GNU C++ Standard library.
> +##
> +## Copyright (C) 1997-2023 Free Software Foundation, Inc.
> +##
> +## This file is part of the libstdc++ version 3 distribution.
> +## Process this file with automake to produce Makefile.in.
> +
> +## 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, or (at your option)
> +## any later version.
> +
> +## 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.
> +
> +## You should have received a copy of the GNU General Public License along
> +## with this library; see the file COPYING3.  If not see
> +## <http://www.gnu.org/licenses/>.
> +
> +include $(top_srcdir)/fragment.am
> +
> +# Convenience library for C++23 runtime.
> +noinst_LTLIBRARIES = libc++23convenience.la
> +
> +headers =
> +
> +if ENABLE_EXTERN_TEMPLATE
> +# XTEMPLATE_FLAGS = -fno-implicit-templates
> +inst_sources =
> +else
> +# XTEMPLATE_FLAGS =
> +inst_sources =
> +endif
> +
> +sources = stacktrace.cc
> +
> +vpath % $(top_srcdir)/src/c++23
> +
> +
> +if GLIBCXX_HOSTED
> +libc__23convenience_la_SOURCES = $(sources)  $(inst_sources)
> +else
> +libc__23convenience_la_SOURCES =
> +endif
> +
> +# AM_CXXFLAGS needs to be in each subdirectory so that it can be
> +# modified in a per-library or per-sub-library way.  Need to manually
> +# set this option because CONFIG_CXXFLAGS has to be after
> +# OPTIMIZE_CXXFLAGS on the compile line so that -O2 can be overridden
> +# as the occasion calls for it.
> +AM_CXXFLAGS = \
> +       -std=gnu++23 \
> +       $(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
> +       $(XTEMPLATE_FLAGS) $(VTV_CXXFLAGS) \
> +       $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS) \
> +       -fimplicit-templates
> +
> +AM_MAKEFLAGS = \
> +       "gxx_include_dir=$(gxx_include_dir)"
> +
> +# Libtool notes
> +
> +# 1) In general, libtool expects an argument such as `--tag=CXX' when
> +# using the C++ compiler, because that will enable the settings
> +# detected when C++ support was being configured.  However, when no
> +# such flag is given in the command line, libtool attempts to figure
> +# it out by matching the compiler name in each configuration section
> +# against a prefix of the command line.  The problem is that, if the
> +# compiler name and its initial flags stored in the libtool
> +# configuration file don't match those in the command line, libtool
> +# can't decide which configuration to use, and it gives up.  The
> +# correct solution is to add `--tag CXX' to LTCXXCOMPILE and maybe
> +# CXXLINK, just after $(LIBTOOL), so that libtool doesn't have to
> +# attempt to infer which configuration to use.
> +#
> +# The second tag argument, `--tag disable-shared` means that libtool
> +# only compiles each source once, for static objects. In actuality,
> +# glibcxx_lt_pic_flag and glibcxx_compiler_shared_flag are added to
> +# the libtool command that is used create the object, which is
> +# suitable for shared libraries.  The `--tag disable-shared` must be
> +# placed after --tag CXX lest things CXX undo the affect of
> +# disable-shared.
> +
> +# 2) Need to explicitly set LTCXXCOMPILE so that EXTRA_CXX_FLAGS is
> +# last. (That way, things like -O2 passed down from the toplevel can
> +# be overridden by --enable-debug.)
> +LTCXXCOMPILE = \
> +       $(LIBTOOL) --tag CXX --tag disable-shared \
> +       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
> +       --mode=compile $(CXX) $(TOPLEVEL_INCLUDES) \
> +       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(EXTRA_CXX_FLAGS)
> +
> +LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
> +
> +# 3) We'd have a problem when building the shared libstdc++ object if
> +# the rules automake generates would be used.  We cannot allow g++ to
> +# be used since this would add -lstdc++ to the link line which of
> +# course is problematic at this point.  So, we get the top-level
> +# directory to configure libstdc++-v3 to use gcc as the C++
> +# compilation driver.
> +CXXLINK = \
> +       $(LIBTOOL) --tag CXX --tag disable-shared \
> +       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
> +       --mode=link $(CXX) \
> +       $(VTV_CXXLINKFLAGS) \
> +       $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
> diff --git a/libstdc++-v3/src/c++23/stacktrace.cc b/libstdc++-v3/src/c++23/stacktrace.cc
> new file mode 100644
> index 00000000000..10cfa44e4f5
> --- /dev/null
> +++ b/libstdc++-v3/src/c++23/stacktrace.cc
> @@ -0,0 +1,171 @@
> +// Implementation of <stacktrace> -*- 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
> +// <http://www.gnu.org/licenses/>.
> +
> +#include <stacktrace>
> +#include <cstdlib>
> +
> +#ifdef __cpp_lib_stacktrace // C++ >= 23 && hosted && HAVE_STACKTRACE
> +struct __glibcxx_backtrace_state;
> +
> +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_TYPE__),
> +                          void(*)(void*, const char*, int),
> +                          void*);
> +int
> +__glibcxx_backtrace_pcinfo(__glibcxx_backtrace_state*, __UINTPTR_TYPE__,
> +                          int (*)(void*, __UINTPTR_TYPE__,
> +                                  const char*, int, const char*),
> +                          void(*)(void*, const char*, int),
> +                          void*);
> +
> +int
> +__glibcxx_backtrace_syminfo(__glibcxx_backtrace_state*, __UINTPTR_TYPE__ addr,
> +                           void (*) (void*, __UINTPTR_TYPE__, const char*,
> +                                     __UINTPTR_TYPE__, __UINTPTR_TYPE__),
> +                           void(*)(void*, const char*, int),
> +                           void*);
> +}
> +
> +namespace __cxxabiv1
> +{
> +  extern "C" char*
> +  __cxa_demangle(const char* mangled_name, char* output_buffer, size_t* length,
> +                int* status);
> +}
> +
> +namespace std
> +{
> +namespace
> +{
> +  char*
> +  demangle(const char* name)
> +  {
> +    int status;
> +    char* str = __cxxabiv1::__cxa_demangle(name, nullptr, nullptr, &status);
> +    if (status == 0)
> +      return str;
> +    else
> +      {
> +       std::free(str);
> +       return nullptr;
> +      }
> +  }
> +
> +  void
> +  err_handler(void*, const char*, int)
> +  { }
> +
> +  __glibcxx_backtrace_state*
> +  init()
> +  {
> +#if __GTHREADS && ! defined(__cpp_threadsafe_static_init)
> +# warning "std::stacktrace initialization will not be thread-safe"
> +#endif
> +    static __glibcxx_backtrace_state* state
> +      = __glibcxx_backtrace_create_state(nullptr, 1, err_handler, nullptr);
> +    return state;
> +  }
> +}
> +
> +void
> +stacktrace_entry::_Info::_M_set_file(const char* filename)
> +{
> +  if (filename && _M_file)
> +    _M_set(_M_file, filename);
> +}
> +
> +void
> +stacktrace_entry::_Info::_M_set_desc(const char* function)
> +{
> +  if (function && _M_desc)
> +    {
> +      if (char* s = demangle(function))
> +       {
> +         _M_set(_M_desc, s);
> +         std::free(s);
> +       }
> +      else
> +       _M_set(_M_desc, function);
> +    }
> +}
> +
> +#pragma GCC diagnostic push
> +// The closure types below don't escape so we don't care about their mangling.
> +#pragma GCC diagnostic ignored "-Wabi"
> +bool
> +stacktrace_entry::_Info::_M_populate(native_handle_type pc)
> +{
> +  auto cb = [](void* self, uintptr_t, const char* filename, int lineno,
> +              const char* function) -> int
> +  {
> +    auto& info = *static_cast<_Info*>(self);
> +    info._M_set_desc(function);
> +    info._M_set_file(filename);
> +    if (info._M_line)
> +      *info._M_line = lineno;
> +    return function != nullptr;
> +  };
> +  const auto state = init();
> +  if (::__glibcxx_backtrace_pcinfo(state, pc, +cb, err_handler, this))
> +    return true;
> +
> +  // If we get here then backtrace_pcinfo did not give us a function name.
> +  // If the caller wanted a function name, try again using backtrace_syminfo.
> +  if (_M_desc)
> +    {
> +      auto cb2 = [](void* self, uintptr_t, const char* symname,
> +                   uintptr_t, uintptr_t)
> +      {
> +       static_cast<_Info*>(self)->_M_set_desc(symname);
> +      };
> +      if (::__glibcxx_backtrace_syminfo(state, pc, +cb2, err_handler, this))
> +       return true;
> +    }
> +  return false;
> +}
> +#pragma GCC diagnostic pop
> +
> +// Ensure no tail-call optimization, so that this frame isn't reused for the
> +// backtrace_simple call, so that the number of frames to skip doesn't vary.
> +[[gnu::optimize("no-optimize-sibling-calls")]]
> +int
> +__stacktrace_impl::_S_current(int (*cb) (void*, __UINTPTR_TYPE__), void* obj,
> +                             int skip)
> +{
> +  const auto state = init();
> +  // skip+2 because we don't want this function or its caller to be included.
> +  int r = ::__glibcxx_backtrace_simple(state, skip + 2, cb, err_handler, obj);
> +  // Could also use this to prevent tail-call optim: __asm ("" : "+g" (r));
> +  return r;
> +}
> +
> +}
> +#endif
> diff --git a/libstdc++-v3/src/experimental/Makefile.am b/libstdc++-v3/src/experimental/Makefile.am
> index 3b962e7d804..a61465f4eaf 100644
> --- a/libstdc++-v3/src/experimental/Makefile.am
> +++ b/libstdc++-v3/src/experimental/Makefile.am
> @@ -24,6 +24,18 @@ include $(top_srcdir)/fragment.am
>
>  toolexeclib_LTLIBRARIES = libstdc++exp.la
>
> +if ENABLE_FILESYSTEM_TS
> +filesystem_lib = $(top_builddir)/src/filesystem/libstdc++fs.la
> +else
> +filesystem_lib =
> +endif
> +
> +if ENABLE_BACKTRACE
> +backtrace_lib = $(top_builddir)/src/libbacktrace/libstdc++_libbacktrace.la
> +else
> +backtrace_lib =
> +endif
> +
>  headers =
>
>  sources = \
> @@ -33,6 +45,14 @@ sources = \
>
>  libstdc__exp_la_SOURCES = $(sources)
>
> +libstdc__exp_la_LIBADD = \
> +       $(top_builddir)/src/c++23/libc++23convenience.la \
> +       $(filesystem_lib) $(backtrace_lib)
> +
> +libstdc__exp_la_DEPENDENCIES = \
> +       $(top_builddir)/src/c++23/libc++23convenience.la \
> +       $(filesystem_lib) $(backtrace_lib)
> +
>  # AM_CXXFLAGS needs to be in each subdirectory so that it can be
>  # modified in a per-library or per-sub-library way.  Need to manually
>  # set this option because CONFIG_CXXFLAGS has to be after
> diff --git a/libstdc++-v3/src/libbacktrace/Makefile.am b/libstdc++-v3/src/libbacktrace/Makefile.am
> index 27c1ea570e0..492d3b6e952 100644
> --- a/libstdc++-v3/src/libbacktrace/Makefile.am
> +++ b/libstdc++-v3/src/libbacktrace/Makefile.am
> @@ -31,7 +31,8 @@
>
>  include $(top_srcdir)/fragment.am
>
> -toolexeclib_LTLIBRARIES = libstdc++_libbacktrace.la
> +# Convenience library for C++23 runtime.
> +noinst_LTLIBRARIES = libstdc++_libbacktrace.la
>
>  ACLOCAL_AMFLAGS = -I ../.. -I ../../config
>
> diff --git a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/current.cc b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/current.cc
> index 184e23b460e..f6c860fc7a4 100644
> --- a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/current.cc
> +++ b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/current.cc
> @@ -1,4 +1,4 @@
> -// { dg-options "-std=gnu++23 -lstdc++_libbacktrace" }
> +// { dg-options "-std=gnu++23 -lstdc++exp" }
>  // { dg-do run { target c++23 } }
>  // { dg-require-effective-target stacktrace }
>
> diff --git a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc
> index a222c425b20..f0406953d03 100644
> --- a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc
> +++ b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/entry.cc
> @@ -1,4 +1,4 @@
> -// { dg-options "-std=gnu++23 -lstdc++_libbacktrace" }
> +// { dg-options "-std=gnu++23 -lstdc++exp" }
>  // { dg-do run { target c++23 } }
>  // { dg-require-effective-target stacktrace }
>
> diff --git a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/stacktrace.cc b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/stacktrace.cc
> index 8dfdf4739be..0a358b7b8ff 100644
> --- a/libstdc++-v3/testsuite/19_diagnostics/stacktrace/stacktrace.cc
> +++ b/libstdc++-v3/testsuite/19_diagnostics/stacktrace/stacktrace.cc
> @@ -1,4 +1,4 @@
> -// { dg-options "-std=gnu++23 -lstdc++_libbacktrace" }
> +// { dg-options "-std=gnu++23 -lstdc++exp" }
>  // { dg-do run { target c++23 } }
>  // { dg-require-effective-target stacktrace }
>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc
> index 520788d5cb7..43a82fb1201 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/debug/assign4_backtrace_neg.cc
> @@ -1,5 +1,5 @@
>  // { dg-do run { xfail *-*-* } }
> -// { dg-options "-D_GLIBCXX_DEBUG_BACKTRACE -lstdc++_libbacktrace" }
> +// { dg-options "-D_GLIBCXX_DEBUG_BACKTRACE -lstdc++exp" }
>  // { dg-require-effective-target stacktrace }
>
>  #include <debug/vector>
> --
> 2.41.0
>


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-09-08 18:17 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-08 17:06 [committed] libstdc++: Add Filesystem TS and std::stacktrace symbols to libstdc++exp.a Jonathan Wakely
2023-09-08 18:16 ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).