[PATCH v4] libstdc++: Implement C++26 <debugging> features (P2546R5)
Tomasz Kaminski
tkaminsk@redhat.com
Mon May 5 08:19:38 GMT 2025
On Thu, May 1, 2025 at 12:59 PM Jonathan Wakely <jwakely@redhat.com> wrote:
> This includes the P2810R4 (is_debugger_present is_replaceable) changes,
> allowing std::is_debugger_present to be replaced by the program.
>
> It would be good to provide a macOS definition of is_debugger_present as
> per https://developer.apple.com/library/archive/qa/qa1361/_index.html
> but that isn't included in this change.
>
> The src/c++26/debugging.cc file defines a global volatile int which can
> be set by debuggers to indicate when they are attached and detached from
> a running process. This allows std::is_debugger_present() to give a
> reliable answer, and additionally allows a debugger to choose how
> std::breakpoint() should behave. Setting the global to a positive value
> will cause std::breakpoint() to use that value as an argument to
> std::raise, so debuggers that prefer SIGABRT for breakpoints can select
> that. By default std::breakpoint() will use a platform-specific action
> such as the INT3 instruction on x86, or GCC's __builtin_trap().
>
> On Linux the std::is_debugger_present() function checks whether the
> process is being traced by a process named "gdb", "gdbserver" or
> "lldb-server", to try to avoid interpreting other tracing processes
> (such as strace) as a debugger. There have been comments suggesting this
> isn't desirable and that std::is_debugger_present() should just return
> true for any tracing process (which is the case for non-Linux targets
> that support the ptrace system call).
>
> libstdc++-v3/ChangeLog:
>
> * config.h.in: Regenerate.
> * configure: Regenerate.
> * configure.ac: Check for facilities needed by <debugging>.
> * include/Makefile.am: Add new header.
> * include/Makefile.in: Regenerate.
> * include/bits/version.def (debugging): Add.
> * include/bits/version.h: Regenerate.
> * include/precompiled/stdc++.h: Add new header.
> * src/c++26/Makefile.am: Add new file.
> * src/c++26/Makefile.in: Regenerate.
> * include/std/debugging: New file.
> * src/c++26/debugging.cc: New file.
> * testsuite/19_diagnostics/debugging/breakpoint.cc: New test.
> * testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc:
> New test.
> * testsuite/19_diagnostics/debugging/is_debugger_present.cc: New
> test.
> * testsuite/19_diagnostics/debugging/is_debugger_present-2.cc:
> New test.
> ---
>
> Patch v4 replaces the attach_debugger(bool) function with a global
> variable debugger_signal_for_breakpoint which indicates whether a
> debugger is present but also
>
> On the LLVM discourse there were concerns about requiring debuggers to
> execute a function in the inferior process, and I got similar feedback
> from John DelSignore of TotalView. Setting an int value is simpler, and
> what's proposed in this patch also allows customizing std::breakpoint()
> for debuggers that would prefer to deal with signals than trap
> instructions.
>
> Tested x86_64-linux.
>
LGTM
>
> libstdc++-v3/config.h.in | 9 +
> libstdc++-v3/configure | 22 +++
> libstdc++-v3/configure.ac | 9 +
> libstdc++-v3/include/Makefile.am | 1 +
> libstdc++-v3/include/Makefile.in | 1 +
> libstdc++-v3/include/bits/version.def | 8 +
> libstdc++-v3/include/bits/version.h | 10 +
> libstdc++-v3/include/precompiled/stdc++.h | 1 +
> libstdc++-v3/include/std/debugging | 77 ++++++++
> libstdc++-v3/src/c++26/Makefile.am | 4 +-
> libstdc++-v3/src/c++26/Makefile.in | 7 +-
> libstdc++-v3/src/c++26/debugging.cc | 174 ++++++++++++++++++
> .../19_diagnostics/debugging/breakpoint.cc | 13 ++
> .../debugging/breakpoint_if_debugging.cc | 13 ++
> .../debugging/is_debugger_present-2.cc | 19 ++
> .../debugging/is_debugger_present.cc | 14 ++
> 16 files changed, 379 insertions(+), 3 deletions(-)
> create mode 100644 libstdc++-v3/include/std/debugging
> create mode 100644 libstdc++-v3/src/c++26/debugging.cc
> create mode 100644
> libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc
> create mode 100644
> libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc
> create mode 100644
> libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present-2.cc
> create mode 100644
> libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc
>
> diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in
> index ed067717a20..6c468973b93 100644
> --- a/libstdc++-v3/config.h.in
> +++ b/libstdc++-v3/config.h.in
> @@ -70,6 +70,9 @@
> /* Define to 1 if you have the `cosl' function. */
> #undef HAVE_COSL
>
> +/* Define to 1 if you have the <debugapi.h> header file. */
> +#undef HAVE_DEBUGAPI_H
> +
> /* Define to 1 if you have the declaration of `strnlen', and to 0 if you
> don't. */
> #undef HAVE_DECL_STRNLEN
> @@ -439,6 +442,9 @@
> /* Define to 1 if you have the <sys/param.h> header file. */
> #undef HAVE_SYS_PARAM_H
>
> +/* Define to 1 if you have the <sys/ptrace.h> header file. */
> +#undef HAVE_SYS_PTRACE_H
> +
> /* Define to 1 if you have the <sys/resource.h> header file. */
> #undef HAVE_SYS_RESOURCE_H
>
> @@ -850,6 +856,9 @@
> /* Define if nl_langinfo_l should be used for std::text_encoding. */
> #undef _GLIBCXX_USE_NL_LANGINFO_L
>
> +/* Define if /proc/self/status should be used for <debugging>. */
> +#undef _GLIBCXX_USE_PROC_SELF_STATUS
> +
> /* Define if pthreads_num_processors_np is available in <pthread.h>. */
> #undef _GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP
>
> diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
> index 684cc83d01a..77bbc0df2fe 100755
> --- a/libstdc++-v3/configure
> +++ b/libstdc++-v3/configure
> @@ -54749,6 +54749,28 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
>
>
>
> +# For std::is_debugger_present
> +case "$target_os" in
> + linux*)
> +
> +$as_echo "#define _GLIBCXX_USE_PROC_SELF_STATUS 1" >>confdefs.h
> +
> + ;;
> +esac
> +for ac_header in sys/ptrace.h debugapi.h
> +do :
> + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
> +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header"
> "$ac_includes_default"
> +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
> + cat >>confdefs.h <<_ACEOF
> +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
> +_ACEOF
> +
> +fi
> +
> +done
> +
> +
> # Define documentation rules conditionally.
>
> # See if makeinfo has been installed and is modern enough
> diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
> index a6c01b29e94..83adb46454e 100644
> --- a/libstdc++-v3/configure.ac
> +++ b/libstdc++-v3/configure.ac
> @@ -587,6 +587,15 @@ GLIBCXX_CHECK_FILEBUF_NATIVE_HANDLES
> # For std::text_encoding
> GLIBCXX_CHECK_TEXT_ENCODING
>
> +# For std::is_debugger_present
> +case "$target_os" in
> + linux*)
> + AC_DEFINE([_GLIBCXX_USE_PROC_SELF_STATUS],1,
> + [Define if /proc/self/status should be used for
> <debugging>.])
> + ;;
> +esac
> +AC_CHECK_HEADERS([sys/ptrace.h debugapi.h])
> +
> # Define documentation rules conditionally.
>
> # See if makeinfo has been installed and is modern enough
> diff --git a/libstdc++-v3/include/Makefile.am
> b/libstdc++-v3/include/Makefile.am
> index 537774c2668..6bb3f3dc3d6 100644
> --- a/libstdc++-v3/include/Makefile.am
> +++ b/libstdc++-v3/include/Makefile.am
> @@ -67,6 +67,7 @@ std_headers = \
> ${std_srcdir}/codecvt \
> ${std_srcdir}/complex \
> ${std_srcdir}/condition_variable \
> + ${std_srcdir}/debugging \
> ${std_srcdir}/deque \
> ${std_srcdir}/execution \
> ${std_srcdir}/filesystem \
> diff --git a/libstdc++-v3/include/Makefile.in
> b/libstdc++-v3/include/Makefile.in
> index 7b96b2207f8..81c3cfce4c4 100644
> --- a/libstdc++-v3/include/Makefile.in
> +++ b/libstdc++-v3/include/Makefile.in
> @@ -423,6 +423,7 @@ std_freestanding = \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/codecvt \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/complex \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/condition_variable \
> +@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/debugging \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/deque \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/execution \
> @GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/filesystem \
> diff --git a/libstdc++-v3/include/bits/version.def
> b/libstdc++-v3/include/bits/version.def
> index 282667eabda..27b58103044 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -1841,6 +1841,14 @@ ftms = {
> };
> };
>
> +ftms = {
> + name = debugging;
> + values = {
> + v = 202403;
> + cxxmin = 26;
> + };
> +};
> +
> ftms = {
> name = fstream_native_handle;
> values = {
> diff --git a/libstdc++-v3/include/bits/version.h
> b/libstdc++-v3/include/bits/version.h
> index bb7c0479c72..c361ec9e29c 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -2054,6 +2054,16 @@
> #endif /* !defined(__cpp_lib_constexpr_new) &&
> defined(__glibcxx_want_constexpr_new) */
> #undef __glibcxx_want_constexpr_new
>
> +#if !defined(__cpp_lib_debugging)
> +# if (__cplusplus > 202302L)
> +# define __glibcxx_debugging 202403L
> +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_debugging)
> +# define __cpp_lib_debugging 202403L
> +# endif
> +# endif
> +#endif /* !defined(__cpp_lib_debugging) &&
> defined(__glibcxx_want_debugging) */
> +#undef __glibcxx_want_debugging
> +
> #if !defined(__cpp_lib_fstream_native_handle)
> # if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
> # define __glibcxx_fstream_native_handle 202306L
> diff --git a/libstdc++-v3/include/precompiled/stdc++.h
> b/libstdc++-v3/include/precompiled/stdc++.h
> index f4b312d9e47..ac428db591f 100644
> --- a/libstdc++-v3/include/precompiled/stdc++.h
> +++ b/libstdc++-v3/include/precompiled/stdc++.h
> @@ -236,6 +236,7 @@
> #endif
>
> #if __cplusplus > 202302L
> +#include <debugging>
> #include <text_encoding>
> #include <stdbit.h>
> #include <stdckdint.h>
> diff --git a/libstdc++-v3/include/std/debugging
> b/libstdc++-v3/include/std/debugging
> new file mode 100644
> index 00000000000..4cf7e4acbc4
> --- /dev/null
> +++ b/libstdc++-v3/include/std/debugging
> @@ -0,0 +1,77 @@
> +// Debugging support -*- 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/>.
> +
> +/** @file include/debugging
> + * This is a Standard C++ Library header.
> + */
> +
> +#ifndef _GLIBCXX_DEBUGGING
> +#define _GLIBCXX_DEBUGGING 1
> +
> +#define __glibcxx_want_debugging
> +#include <bits/version.h>
> +
> +#if __cpp_lib_debugging // C++ >= 26
> +namespace std _GLIBCXX_VISIBILITY(default)
> +{
> +// N.B. _GLIBCXX_BEGIN_NAMESPACE_VERSION is not used here.
> +
> +/** Try to determine if the program is running under control of a
> debugger.
> + *
> + * On GNU/Linux systems this function will only return true if the program
> + * is being traced by another program which is known to be a debugger.
> + * This is determined by checking the command name of the tracing program
> + * against a list of known debuggers, such as "gdb".
> + *
> + * On other POSIX-based systems, this function will return true if the
> + * program is being traced by any other process, which means it can return
> + * true for non-debugger utilities that use the ptrace system call.
> + *
> + * @since C++26
> + */
> +bool
> +is_debugger_present() noexcept;
> +
> +/** Stop the program with a breakpoint or debug trap.
> + *
> + * The details of how a breakpoint is implemented are platform-specific.
> + * Some systems provide a special instruction, such as `int3` in x86.
> + * When no more appropriate mechanism is available, this will stop the
> + * program using `__builtin_trap()`. It might not be possible for the
> + * program to continue after such a breakpoint.
> + *
> + * @since C++26
> + */
> +void
> +breakpoint() noexcept;
> +
> +/** Stop the program if it is running under control of a debugger.
> + *
> + * @since C++26
> + */
> +void
> +breakpoint_if_debugging() noexcept;
> +
> +} // namespace std
> +#endif
> +#endif // _GLIBCXX_DEBUGGING
> diff --git a/libstdc++-v3/src/c++26/Makefile.am
> b/libstdc++-v3/src/c++26/Makefile.am
> index 5defa4ac481..4123b7dd369 100644
> --- a/libstdc++-v3/src/c++26/Makefile.am
> +++ b/libstdc++-v3/src/c++26/Makefile.am
> @@ -35,7 +35,9 @@ else
> inst_sources =
> endif
>
> -sources = text_encoding.cc
> +sources = \
> + debugging.cc \
> + text_encoding.cc
>
> vpath % $(top_srcdir)/src/c++26
>
> diff --git a/libstdc++-v3/src/c++26/Makefile.in
> b/libstdc++-v3/src/c++26/Makefile.in
> index 77e73b2b265..1c317d6ac7c 100644
> --- a/libstdc++-v3/src/c++26/Makefile.in
> +++ b/libstdc++-v3/src/c++26/Makefile.in
> @@ -121,7 +121,7 @@ CONFIG_CLEAN_FILES =
> CONFIG_CLEAN_VPATH_FILES =
> LTLIBRARIES = $(noinst_LTLIBRARIES)
> libc__26convenience_la_LIBADD =
> -am__objects_1 = text_encoding.lo
> +am__objects_1 = debugging.lo text_encoding.lo
> am__objects_2 =
> @GLIBCXX_HOSTED_TRUE@am_libc__26convenience_la_OBJECTS = \
> @GLIBCXX_HOSTED_TRUE@ $(am__objects_1) $(am__objects_2)
> @@ -430,7 +430,10 @@ headers =
>
> # XTEMPLATE_FLAGS = -fno-implicit-templates
> @ENABLE_EXTERN_TEMPLATE_TRUE@inst_sources =
> -sources = text_encoding.cc
> +sources = \
> + debugging.cc \
> + text_encoding.cc
> +
> @GLIBCXX_HOSTED_FALSE@libc__26convenience_la_SOURCES =
> @GLIBCXX_HOSTED_TRUE@libc__26convenience_la_SOURCES = $(sources)
> $(inst_sources)
>
> diff --git a/libstdc++-v3/src/c++26/debugging.cc
> b/libstdc++-v3/src/c++26/debugging.cc
> new file mode 100644
> index 00000000000..fe894eb6d69
> --- /dev/null
> +++ b/libstdc++-v3/src/c++26/debugging.cc
> @@ -0,0 +1,174 @@
> +// Implementation of <debugging> -*- 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 <debugging>
> +
> +#if __cpp_lib_debugging
> +
> +#include <csignal> // std::raise
> +
> +#if _GLIBCXX_USE_PROC_SELF_STATUS
> +# include <fstream>
> +# include <string>
> +#endif
> +
> +#if _GLIBCXX_HAVE_SYS_PTRACE_H
> +# include <sys/ptrace.h>
> +# include <errno.h>
> +#endif
> +
> +#if _GLIBCXX_HAVE_DEBUGAPI_H
> +# include <debugapi.h>
> +#endif
> +
> +#ifdef _GLIBCXX_HAVE_SYS_SDT_H
> +# include <sys/sdt.h>
> +/* We only want to use stap probes starting with v3. Earlier versions
> + added too much startup cost. */
> +# if defined (STAP_PROBE) && _SDT_NOTE_TYPE >= 3
> +# define PROBE(name) STAP_PROBE(libstdcxx, name)
> +# endif
> +#endif
> +
> +#ifndef PROBE
> +# define PROBE(name)
> +#endif
> +
> +namespace __gnu_cxx
> +{
> + // This should be changed to non-zero by debuggers when they attach
> + // and back to zero when they detach.
> + // If the value is positive, std::breakpoint() will use it as the
> argument
> + // to std::raise, so it should be a valid signal number, e.g. SIGABRT or
> + // SIGTRAP.
> + // If the value is negative, std::breakpoint() will use a
> target-specific
> + // trap, e.g. asm("int3") or __builtin_trap().
> + volatile int debugger_signal_for_breakpoint = 0;
> +}
> +
> +_GLIBCXX_WEAK_DEFINITION
> +bool
> +std::is_debugger_present() noexcept
> +{
> + PROBE(std::is_debugger_present);
> +
> + if (__gnu_cxx::debugger_signal_for_breakpoint != 0)
> + return true;
> +
> +#if _GLIBCXX_HOSTED
> +# if _GLIBCXX_USE_PROC_SELF_STATUS
> + const string_view prefix = "TracerPid:\t"; // populated since Linux
> 2.6.0
> + ifstream in("/proc/self/status");
> + string line;
> + while (std::getline(in, line))
> + {
> + if (!line.starts_with(prefix))
> + continue;
> +
> + string_view tracer = line;
> + tracer.remove_prefix(prefix.size());
> + if (tracer.size() == 1 && tracer[0] == '0') [[likely]]
> + return false; // Not being traced.
> +
> + in.close();
> + string_view cmd;
> + string proc_dir = "/proc/" + string(tracer) + '/';
> + in.open(proc_dir + "comm"); // since Linux 2.6.33
> + if (std::getline(in, line)) [[likely]]
> + cmd = line;
> + else
> + {
> + in.close();
> + in.open(proc_dir + "cmdline");
> + if (std::getline(in, line))
> + cmd = line.c_str(); // Only up to first '\0'
> + else
> + return false;
> + }
> +
> + for (auto i : {"gdb", "gdbserver", "lldb-server"}) // known
> debuggers
> + if (cmd.ends_with(i))
> + return true;
> +
> + // We found the TracerPid line, no need to do any more work.
> + return false;
> + }
> +# elif _GLIBCXX_HAVE_SYS_PTRACE_H
> + if (::ptrace(PTRACE_TRACEME, 0, 1, 0) == -1)
> + return errno == EPERM;
> +# endif
> +# if _GLIBCXX_HAVE_DEBUGAPI_H && defined(_WIN32) && !defined(__CYGWIN__)
> + return IsDebuggerPresent();
> +# endif
> +#endif // HOSTED
> + return false;
> +}
> +
> +void
> +std::breakpoint() noexcept
> +{
> + PROBE(std::breakpoint);
> +
> + if (__gnu_cxx::debugger_signal_for_breakpoint > 0)
> + std::raise(__gnu_cxx::debugger_signal_for_breakpoint);
> +
> +#if _GLIBCXX_HAVE_DEBUGAPI_H && defined(_WIN32) && !defined(__CYGWIN__)
> + DebugBreak();
> +#elif __has_builtin(__builtin_debugtrap)
> + __builtin_debugtrap(); // Clang
> +#elif defined(__i386__) || defined(__x86_64__)
> + __asm__ volatile ("int3; nop");
> +#elifdef __thumb__
> + __asm__ volatile (".inst 0xde01");
> +#elifdef __aarch64__
> + __asm__ volatile (".inst 0xd4200000");
> +#elifdef __arm__
> + __asm__ volatile (".inst 0xe7f001f0");
> +#elifdef __riscv
> + /* section 2.8 in the RISC-V unprivileged ISA manual says for
> semi-hosted
> + * environments we want the sequence:
> + * slli x0, x0, 0x1f # Entry NOP
> + * ebreak # Break to debugger
> + * srai x0, x0, 7 # NOP encoding the semihosting call number 7
> + */
> + __asm__ volatile (".4byte 0x00100073");
> +#elifdef __powerpc__
> + __asm__ volatile(".4byte 0x7d821008");
> +#else
> + __builtin_trap();
> +#endif
> +} // If the debugger stops here, std::breakpoint() was called.
> +
> +// This is intentionally not defined inline. A non-inline definition
> allows
> +// debuggers to insert a breakpoint on calls to the function, avoiding the
> +// overhead of calling `is_debugger_present()`.
> +void
> +std::breakpoint_if_debugging() noexcept
> +{
> + PROBE(std::breakpoint_if_debugging);
> +
> + if (std::is_debugger_present()) [[unlikely]]
> + std::breakpoint();
> +}
> +
> +#endif // __cpp_lib_debugging
> diff --git a/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc
> b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc
> new file mode 100644
> index 00000000000..ad24177f644
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint.cc
> @@ -0,0 +1,13 @@
> +// { dg-do run { target c++26 xfail c++26 } }
> +// { dg-options "-lstdc++exp" }
> +// { dg-require-cpp-feature-test __cpp_lib_debugging }
> +#include <debugging>
> +#include <type_traits>
> +
> +static_assert( noexcept(std::breakpoint()) );
> +static_assert( std::is_void_v<decltype(std::breakpoint())> );
> +
> +int main()
> +{
> + std::breakpoint();
> +}
> diff --git
> a/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc
> b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc
> new file mode 100644
> index 00000000000..26461836ef7
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/19_diagnostics/debugging/breakpoint_if_debugging.cc
> @@ -0,0 +1,13 @@
> +// { dg-do run { target c++26 } }
> +// { dg-options "-lstdc++exp" }
> +// { dg-require-cpp-feature-test __cpp_lib_debugging }
> +#include <debugging>
> +#include <type_traits>
> +
> +static_assert( noexcept(std::breakpoint_if_debugging()) );
> +static_assert( std::is_void_v<decltype(std::breakpoint_if_debugging())> );
> +
> +int main()
> +{
> + std::breakpoint_if_debugging();
> +}
> diff --git
> a/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present-2.cc
> b/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present-2.cc
> new file mode 100644
> index 00000000000..aa4690c5540
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present-2.cc
> @@ -0,0 +1,19 @@
> +// { dg-do run { target c++26 } }
> +// { dg-options "-lstdc++exp" }
> +// { dg-require-cpp-feature-test __cpp_lib_debugging }
> +// { dg-xfail-run-if "no replaceable functions on AIX" { powerpc-ibm-aix*
> } }
> +
> +// P2810R4 is_debugger_present is_replaceable
> +
> +#include <debugging>
> +#include <testsuite_hooks.h>
> +
> +bool called = false;
> +
> +bool std::is_debugger_present() noexcept { called = true; return true; }
> +
> +int main()
> +{
> + VERIFY( std::is_debugger_present() );
> + VERIFY( called );
> +}
> diff --git
> a/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc
> b/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc
> new file mode 100644
> index 00000000000..8dbfa694243
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/19_diagnostics/debugging/is_debugger_present.cc
> @@ -0,0 +1,14 @@
> +// { dg-do run { target c++26 } }
> +// { dg-options "-lstdc++exp" }
> +// { dg-require-cpp-feature-test __cpp_lib_debugging }
> +#include <debugging>
> +#include <type_traits>
> +#include <testsuite_hooks.h>
> +
> +static_assert( noexcept(std::is_debugger_present()) );
> +static_assert( std::is_same_v<decltype(std::is_debugger_present()), bool>
> );
> +
> +int main()
> +{
> + VERIFY( ! std::is_debugger_present() );
> +}
> --
> 2.49.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250505/3608e939/attachment-0001.htm>
More information about the Libstdc++
mailing list