From: Jonathan Wakely <jwakely@redhat.com>
To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org
Subject: [committed 1/2] libstdc++: Implement P2905R2 "Runtime format strings" for C++20
Date: Mon, 8 Jan 2024 01:19:01 +0000 [thread overview]
Message-ID: <20240108011930.3670651-1-jwakely@redhat.com> (raw)
Tested x86_64-linux and aarch64-linux. Pushed to trunk.
-- >8 --
This change makes std::make_format_args refuse to create dangling
references to temporaries. This makes the std::vformat API safer. This
was approved in Kona 2023 as a DR for C++20 so the change is implemented
unconditionally.
libstdc++-v3/ChangeLog:
* include/bits/chrono_io.h (__formatter_chrono): Always use
lvalue arguments to make_format_args.
* include/std/format (make_format_args): Change parameter pack
from forwarding references to lvalue references. Remove use of
remove_reference_t which is now unnecessary.
(format_to, formatted_size): Remove incorrect forwarding of
arguments.
* include/std/ostream (print): Remove forwarding of arguments.
* include/std/print (print): Likewise.
* testsuite/20_util/duration/io.cc: Use lvalues as arguments to
make_format_args.
* testsuite/std/format/arguments/args.cc: Likewise.
* testsuite/std/format/arguments/lwg3810.cc: Likewise.
* testsuite/std/format/functions/format.cc: Likewise.
* testsuite/std/format/functions/vformat_to.cc: Likewise.
* testsuite/std/format/string.cc: Likewise.
* testsuite/std/time/day/io.cc: Likewise.
* testsuite/std/time/month/io.cc: Likewise.
* testsuite/std/time/weekday/io.cc: Likewise.
* testsuite/std/time/year/io.cc: Likewise.
* testsuite/std/time/year_month_day/io.cc: Likewise.
* testsuite/std/format/arguments/args_neg.cc: New test.
---
libstdc++-v3/include/bits/chrono_io.h | 15 ++++++----
libstdc++-v3/include/std/format | 30 +++++++++----------
libstdc++-v3/include/std/ostream | 2 +-
libstdc++-v3/include/std/print | 2 +-
libstdc++-v3/testsuite/20_util/duration/io.cc | 3 +-
.../testsuite/std/format/arguments/args.cc | 26 ++++++++++++----
.../std/format/arguments/args_neg.cc | 12 ++++++++
.../testsuite/std/format/arguments/lwg3810.cc | 8 +++--
.../testsuite/std/format/functions/format.cc | 6 ++--
.../std/format/functions/vformat_to.cc | 9 ++++--
libstdc++-v3/testsuite/std/format/string.cc | 7 +++--
libstdc++-v3/testsuite/std/time/day/io.cc | 4 +--
libstdc++-v3/testsuite/std/time/month/io.cc | 4 +--
libstdc++-v3/testsuite/std/time/weekday/io.cc | 4 +--
libstdc++-v3/testsuite/std/time/year/io.cc | 4 +--
.../testsuite/std/time/year_month_day/io.cc | 4 +--
16 files changed, 93 insertions(+), 47 deletions(-)
create mode 100644 libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h
index c30451651ea..ec2ae9d53cc 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -2273,7 +2273,8 @@ namespace __detail
_Str __s = _GLIBCXX_WIDEN("{:02d} is not a valid day");
if (__d.ok())
__s = __s.substr(0, 6);
- __os << std::vformat(__s, make_format_args<_Ctx>((unsigned)__d));
+ auto __u = (unsigned)__d;
+ __os << std::vformat(__s, make_format_args<_Ctx>(__u));
return __os;
}
@@ -2302,8 +2303,10 @@ namespace __detail
__os << std::vformat(__os.getloc(), __s.substr(0, 6),
make_format_args<_Ctx>(__m));
else
- __os << std::vformat(__s.substr(6),
- make_format_args<_Ctx>((unsigned)__m));
+ {
+ auto __u = (unsigned)__m;
+ __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__u));
+ }
return __os;
}
@@ -2364,8 +2367,10 @@ namespace __detail
__os << std::vformat(__os.getloc(), __s.substr(0, 6),
make_format_args<_Ctx>(__wd));
else
- __os << std::vformat(__s.substr(6),
- make_format_args<_Ctx>(__wd.c_encoding()));
+ {
+ auto __c = __wd.c_encoding();
+ __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__c));
+ }
return __os;
}
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 0d9f70ee555..160efa5155c 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -3413,7 +3413,7 @@ namespace __format
template<typename _Ctx, typename... _Argz>
friend auto
- make_format_args(_Argz&&...) noexcept;
+ make_format_args(_Argz&...) noexcept;
template<typename _Visitor, typename _Ctx>
friend decltype(auto)
@@ -3583,7 +3583,7 @@ namespace __format
template<typename _Ctx, typename... _Args>
friend auto
- make_format_args(_Args&&...) noexcept;
+ make_format_args(_Args&...) noexcept;
// An array of _Arg_t enums corresponding to _Args...
template<typename... _Args>
@@ -3621,7 +3621,7 @@ namespace __format
template<typename _Context, typename... _Args>
auto
- make_format_args(_Args&&... __fmt_args) noexcept;
+ make_format_args(_Args&... __fmt_args) noexcept;
// An array of type-erased formatting arguments.
template<typename _Context, typename... _Args>
@@ -3637,7 +3637,7 @@ namespace __format
#else
std::
#endif
- make_format_args(_Argz&&...) noexcept;
+ make_format_args(_Argz&...) noexcept;
// For a sufficiently small number of arguments we only store values.
// basic_format_args can get the types from the _Args pack.
@@ -3711,11 +3711,11 @@ namespace __format
template<typename _Context = format_context, typename... _Args>
[[nodiscard,__gnu__::__always_inline__]]
inline auto
- make_format_args(_Args&&... __fmt_args) noexcept
+ make_format_args(_Args&... __fmt_args) noexcept
{
using _Fmt_arg = basic_format_arg<_Context>;
using _Store = __format::_Arg_store<_Context, typename _Fmt_arg::template
- _Normalize<remove_reference_t<_Args>>...>;
+ _Normalize<_Args>...>;
return _Store(__fmt_args...);
}
@@ -3724,7 +3724,7 @@ namespace __format
template<typename... _Args>
[[nodiscard,__gnu__::__always_inline__]]
inline auto
- make_wformat_args(_Args&&... __args) noexcept
+ make_wformat_args(_Args&... __args) noexcept
{ return std::make_format_args<wformat_context>(__args...); }
#endif
@@ -4240,7 +4240,7 @@ namespace __format
format_to(_Out __out, format_string<_Args...> __fmt, _Args&&... __args)
{
return std::vformat_to(std::move(__out), __fmt.get(),
- std::make_format_args(std::forward<_Args>(__args)...));
+ std::make_format_args(__args...));
}
#ifdef _GLIBCXX_USE_WCHAR_T
@@ -4250,7 +4250,7 @@ namespace __format
format_to(_Out __out, wformat_string<_Args...> __fmt, _Args&&... __args)
{
return std::vformat_to(std::move(__out), __fmt.get(),
- std::make_wformat_args(std::forward<_Args>(__args)...));
+ std::make_wformat_args(__args...));
}
#endif
@@ -4261,7 +4261,7 @@ namespace __format
_Args&&... __args)
{
return std::vformat_to(std::move(__out), __loc, __fmt.get(),
- std::make_format_args(std::forward<_Args>(__args)...));
+ std::make_format_args(__args...));
}
#ifdef _GLIBCXX_USE_WCHAR_T
@@ -4272,7 +4272,7 @@ namespace __format
_Args&&... __args)
{
return std::vformat_to(std::move(__out), __loc, __fmt.get(),
- std::make_wformat_args(std::forward<_Args>(__args)...));
+ std::make_wformat_args(__args...));
}
#endif
@@ -4379,7 +4379,7 @@ namespace __format
{
__format::_Counting_sink<char> __buf;
std::vformat_to(__buf.out(), __fmt.get(),
- std::make_format_args(std::forward<_Args>(__args)...));
+ std::make_format_args(__args...));
return __buf.count();
}
@@ -4391,7 +4391,7 @@ namespace __format
{
__format::_Counting_sink<wchar_t> __buf;
std::vformat_to(__buf.out(), __fmt.get(),
- std::make_wformat_args(std::forward<_Args>(__args)...));
+ std::make_wformat_args(__args...));
return __buf.count();
}
#endif
@@ -4404,7 +4404,7 @@ namespace __format
{
__format::_Counting_sink<char> __buf;
std::vformat_to(__buf.out(), __loc, __fmt.get(),
- std::make_format_args(std::forward<_Args>(__args)...));
+ std::make_format_args(__args...));
return __buf.count();
}
@@ -4417,7 +4417,7 @@ namespace __format
{
__format::_Counting_sink<wchar_t> __buf;
std::vformat_to(__buf.out(), __loc, __fmt.get(),
- std::make_wformat_args(std::forward<_Args>(__args)...));
+ std::make_wformat_args(__args...));
return __buf.count();
}
#endif
diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream
index 4dff0cf645d..7d501d67489 100644
--- a/libstdc++-v3/include/std/ostream
+++ b/libstdc++-v3/include/std/ostream
@@ -981,7 +981,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline void
print(ostream& __os, format_string<_Args...> __fmt, _Args&&... __args)
{
- auto __fmtargs = std::make_format_args(std::forward<_Args>(__args)...);
+ auto __fmtargs = std::make_format_args(__args...);
if constexpr (__unicode::__literal_encoding_is_utf8())
std::vprint_unicode(__os, __fmt.get(), __fmtargs);
else
diff --git a/libstdc++-v3/include/std/print b/libstdc++-v3/include/std/print
index f44256c5dca..492f333dfa6 100644
--- a/libstdc++-v3/include/std/print
+++ b/libstdc++-v3/include/std/print
@@ -103,7 +103,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline void
print(FILE* __stream, format_string<_Args...> __fmt, _Args&&... __args)
{
- auto __fmtargs = std::make_format_args(std::forward<_Args>(__args)...);
+ auto __fmtargs = std::make_format_args(__args...);
if constexpr (__unicode::__literal_encoding_is_utf8())
std::vprint_unicode(__stream, __fmt.get(), __fmtargs);
else
diff --git a/libstdc++-v3/testsuite/20_util/duration/io.cc b/libstdc++-v3/testsuite/20_util/duration/io.cc
index 0582c0075a5..e141baf42dc 100644
--- a/libstdc++-v3/testsuite/20_util/duration/io.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/io.cc
@@ -82,7 +82,8 @@ test_format()
char fmt[] = { '{', ':', '%', c, '}' };
try
{
- (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(1s));
+ auto s = 1s;
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(s));
// The call above should throw for any conversion-spec not in my_specs:
VERIFY(my_specs.find(c) != my_specs.npos);
}
diff --git a/libstdc++-v3/testsuite/std/format/arguments/args.cc b/libstdc++-v3/testsuite/std/format/arguments/args.cc
index a45f3fb24df..eba129ff894 100644
--- a/libstdc++-v3/testsuite/std/format/arguments/args.cc
+++ b/libstdc++-v3/testsuite/std/format/arguments/args.cc
@@ -46,7 +46,12 @@ struct std::formatter<E> : std::formatter<int>
void
test_args()
{
- auto store = std::make_format_args(false, 1, '2', 3.4);
+ bool b = false;
+ int i = 1;
+ char c = '2';
+ double d = 3.4;
+
+ auto store = std::make_format_args(b, i, c, d);
std::format_args args = store;
VERIFY(equals(args.get(0), false));
VERIFY(equals(args.get(1), 1));
@@ -54,7 +59,11 @@ test_args()
VERIFY(equals(args.get(3), 3.4));
VERIFY(!args.get(4));
- auto cstore = std::make_format_args<std::format_context>(5L, 6ULL, 7.8f);
+ long l = 5L;
+ unsigned long long ull = 6ULL;
+ float f = 7.8f;
+
+ auto cstore = std::make_format_args<std::format_context>(l, ull, f);
std::format_args cargs = cstore;
if constexpr (sizeof(long) == sizeof(int))
VERIFY(equals(cargs.get(0), 5));
@@ -64,14 +73,17 @@ test_args()
VERIFY(equals(cargs.get(2), 7.8f));
VERIFY(!cargs.get(3));
- VERIFY(equals(std::format_args(std::make_format_args(std::string("tenfour"))).get(0), std::string_view("tenfour")));
+ std::string s = "tenfour";
+ VERIFY(equals(std::format_args(std::make_format_args(s)).get(0), std::string_view("tenfour")));
+ char nine = '9';
+ wchar_t ten = L'X';
// This needs to be on the stack so that testing pointer equality works.
wchar_t eleven[] = L"eleven";
- // This needs to be on the stack so that the wstring_view doesn't dangle.
+ long double twelve13 = 12.13L;
std::wstring tenfour = L"tenfour";
- auto wstore = std::make_wformat_args('9', L'X', eleven, 12.13L, tenfour);
+ auto wstore = std::make_wformat_args(nine, ten, eleven, twelve13, tenfour);
std::wformat_args wargs = wstore;
VERIFY(equals(wargs.get(0), static_cast<wchar_t>('9')));
VERIFY(equals(wargs.get(1), L'X'));
@@ -80,7 +92,9 @@ test_args()
VERIFY(equals(wargs.get(4), std::wstring_view(tenfour)));
VERIFY(!wargs.get(5));
- auto another_store = std::make_format_args(nullptr, E::ByGum);
+ std::nullptr_t null;
+ E eebygum = E::ByGum;
+ auto another_store = std::make_format_args(null, eebygum);
args = another_store;
VERIFY(equals(args.get(0), static_cast<const void*>(nullptr)));
using handle = std::basic_format_arg<std::format_context>::handle;
diff --git a/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc b/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
new file mode 100644
index 00000000000..16ac3040146
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++20 } }
+
+// P2905R2 Runtime format strings
+
+#include <format>
+
+std::string rval() { return "path/etic/experience"; }
+
+void f()
+{
+ (void)std::make_format_args(rval()); // { dg-error "cannot bind non-const lvalue reference" }
+}
diff --git a/libstdc++-v3/testsuite/std/format/arguments/lwg3810.cc b/libstdc++-v3/testsuite/std/format/arguments/lwg3810.cc
index f89f40203cb..8a9f9edd578 100644
--- a/libstdc++-v3/testsuite/std/format/arguments/lwg3810.cc
+++ b/libstdc++-v3/testsuite/std/format/arguments/lwg3810.cc
@@ -4,7 +4,11 @@
#include <format>
-auto args_store = std::make_format_args(1,2,3);
+int x = 1;
+long y = 2;
+short z = 3;
+
+auto args_store = std::make_format_args(x, y, z);
std::basic_format_args args = args_store;
static_assert(std::is_same_v<decltype(args), std::format_args>);
@@ -20,5 +24,5 @@ test_ctad()
using SomeContext = std::wformat_context;
// foo(make_format_args<SomeContext>(...)); // won't work
- foo(basic_format_args(make_format_args<SomeContext>(1, 2, 3))); // should work
+ foo(basic_format_args(make_format_args<SomeContext>(x, y, z))); // should work
}
diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc
index 6320e20170c..63702edbd42 100644
--- a/libstdc++-v3/testsuite/std/format/functions/format.cc
+++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
@@ -267,14 +267,16 @@ test_width()
}
try {
- auto args = std::make_format_args(false, true);
+ bool no = false, yes = true;
+ auto args = std::make_format_args(no, yes);
s = std::vformat("DR 3720: restrict type of width arg-id {0:{1}}", args);
VERIFY(false);
} catch (const std::format_error&) {
}
try {
- auto args = std::make_format_args('?', '!');
+ char wat = '?', bang = '!';
+ auto args = std::make_format_args(wat, bang);
s = std::vformat("DR 3720: restrict type of width arg-id {0:{1}}", args);
VERIFY(false);
} catch (const std::format_error&) {
diff --git a/libstdc++-v3/testsuite/std/format/functions/vformat_to.cc b/libstdc++-v3/testsuite/std/format/functions/vformat_to.cc
index fe0367f7496..2be3d6f6761 100644
--- a/libstdc++-v3/testsuite/std/format/functions/vformat_to.cc
+++ b/libstdc++-v3/testsuite/std/format/functions/vformat_to.cc
@@ -29,17 +29,22 @@ private:
void
test_move_only()
{
+ const char arg1[] = "matte";
+ int arg2 = '!';
+
std::string str;
move_only_iterator<char> mo(std::back_inserter(str));
auto res = std::vformat_to(std::move(mo), "for{:.3} that{:c}",
- std::make_format_args("matte", (int)'!'));
+ std::make_format_args(arg1, arg2));
static_assert(std::is_same_v<decltype(res), decltype(mo)>);
VERIFY( str == "format that!" );
+ const wchar_t warg1[] = L"matte";
+ long warg2 = L'!';
std::wstring wstr;
move_only_iterator<wchar_t> wmo(std::back_inserter(wstr));
auto wres = std::vformat_to(std::move(wmo), L"for{:.3} that{:c}",
- std::make_wformat_args(L"matte", (long)L'!'));
+ std::make_wformat_args(warg1, warg2));
static_assert(std::is_same_v<decltype(wres), decltype(wmo)>);
VERIFY( wstr == L"format that!" );
}
diff --git a/libstdc++-v3/testsuite/std/format/string.cc b/libstdc++-v3/testsuite/std/format/string.cc
index 40aaebae04e..ddb3c5625cd 100644
--- a/libstdc++-v3/testsuite/std/format/string.cc
+++ b/libstdc++-v3/testsuite/std/format/string.cc
@@ -149,8 +149,9 @@ void
test_pr110862()
{
try {
+ int i = 1;
// PR libstdc++/110862 out-of-bounds read on invalid format string
- (void) std::vformat("{0:{0}", std::make_format_args(1));
+ (void) std::vformat("{0:{0}", std::make_format_args(i));
VERIFY( false );
} catch (const std::format_error& e) {
std::string_view what = e.what();
@@ -162,9 +163,11 @@ void
test_pr110974()
{
try {
+ double d = 1.0;
+ int i = 1;
// PR libstdc++/110974 out of bounds read on invalid format string "{:{}."
std::string_view fmt{"{:{}.0", 5}; // "0" is not part of the format string.
- (void) std::vformat(fmt, std::make_format_args(1.0, 1));
+ (void) std::vformat(fmt, std::make_format_args(d, i));
VERIFY( false );
} catch (const std::format_error& e) {
std::string_view what = e.what();
diff --git a/libstdc++-v3/testsuite/std/time/day/io.cc b/libstdc++-v3/testsuite/std/time/day/io.cc
index 3454657f69f..36ce7ec7d17 100644
--- a/libstdc++-v3/testsuite/std/time/day/io.cc
+++ b/libstdc++-v3/testsuite/std/time/day/io.cc
@@ -51,8 +51,8 @@ test_format()
char fmt[] = { '{', ':', '%', c, '}' };
try
{
- (void) std::vformat(std::string_view(fmt, 5),
- std::make_format_args(day(1)));
+ day d(1);
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(d));
// The call above should throw for any conversion-spec not in my_specs:
VERIFY(my_specs.find(c) != my_specs.npos);
}
diff --git a/libstdc++-v3/testsuite/std/time/month/io.cc b/libstdc++-v3/testsuite/std/time/month/io.cc
index 7e80a53bbb6..99ec0737305 100644
--- a/libstdc++-v3/testsuite/std/time/month/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month/io.cc
@@ -74,8 +74,8 @@ test_format()
char fmt[] = { '{', ':', '%', c, '}' };
try
{
- (void) std::vformat(std::string_view(fmt, 5),
- std::make_format_args(month(1)));
+ month m(1);
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(m));
// The call above should throw for any conversion-spec not in my_specs:
VERIFY(my_specs.find(c) != my_specs.npos);
}
diff --git a/libstdc++-v3/testsuite/std/time/weekday/io.cc b/libstdc++-v3/testsuite/std/time/weekday/io.cc
index 5ed90282f95..a56cdaef88c 100644
--- a/libstdc++-v3/testsuite/std/time/weekday/io.cc
+++ b/libstdc++-v3/testsuite/std/time/weekday/io.cc
@@ -77,8 +77,8 @@ test_format()
char fmt[] = { '{', ':', '%', c, '}' };
try
{
- (void) std::vformat(std::string_view(fmt, 5),
- std::make_format_args(weekday(1)));
+ weekday wd(1);
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(wd));
// The call above should throw for any conversion-spec not in my_specs:
VERIFY(my_specs.find(c) != my_specs.npos);
}
diff --git a/libstdc++-v3/testsuite/std/time/year/io.cc b/libstdc++-v3/testsuite/std/time/year/io.cc
index a6683ae20df..bcaa57faeb7 100644
--- a/libstdc++-v3/testsuite/std/time/year/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year/io.cc
@@ -68,8 +68,8 @@ test_format()
char fmt[] = { '{', ':', '%', c, '}' };
try
{
- (void) std::vformat(std::string_view(fmt, 5),
- std::make_format_args(year(2022)));
+ year y = 2022y;
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(y));
// The call above should throw for any conversion-spec not in my_specs:
VERIFY(my_specs.find(c) != my_specs.npos);
}
diff --git a/libstdc++-v3/testsuite/std/time/year_month_day/io.cc b/libstdc++-v3/testsuite/std/time/year_month_day/io.cc
index 15c5a9f77be..cb82ef3b612 100644
--- a/libstdc++-v3/testsuite/std/time/year_month_day/io.cc
+++ b/libstdc++-v3/testsuite/std/time/year_month_day/io.cc
@@ -97,8 +97,8 @@ test_format()
char fmt[] = { '{', ':', '%', c, '}' };
try
{
- (void) std::vformat(std::string_view(fmt, 5),
- std::make_format_args(2022y/December/19));
+ year_month_day ymd = 2022y/December/19;
+ (void) std::vformat(std::string_view(fmt, 5), std::make_format_args(ymd));
// The call above should throw for any conversion-spec not in my_specs:
VERIFY(my_specs.find(c) != my_specs.npos);
}
--
2.43.0
next reply other threads:[~2024-01-08 1:19 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-08 1:19 Jonathan Wakely [this message]
2024-01-08 1:19 ` [committed 2/2] libstdc++: Implement P2918R0 "Runtime format strings II" for C++26 Jonathan Wakely
2024-01-10 18:32 ` Daniel Krügler
2024-01-10 19:41 ` Jonathan Wakely
2024-01-11 20:23 ` [PATCH] libstdc++: Fix std::runtime_format deviations from the spec [PR113320] Jonathan Wakely
2024-01-12 6:53 ` Daniel Krügler
2024-01-12 9:49 ` Jonathan Wakely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240108011930.3670651-1-jwakely@redhat.com \
--to=jwakely@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=libstdc++@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).