From c3c6d0c2d2ff32179c9312c70b25da8582458505 Mon Sep 17 00:00:00 2001 From: vsol Date: Tue, 10 Mar 2020 11:17:44 +0300 Subject: [PATCH] Fixed a lifetime issue in test and minor build fixes. --- include/fmt/dyn-args.h | 4 ++-- test/format-dyn-args-test.cc | 31 +++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/include/fmt/dyn-args.h b/include/fmt/dyn-args.h index 849cf4c2..e80f810a 100644 --- a/include/fmt/dyn-args.h +++ b/include/fmt/dyn-args.h @@ -159,8 +159,8 @@ class dynamic_format_arg_store } public: - dynamic_format_arg_store() FMT_NOEXCEPT = default; - ~dynamic_format_arg_store() FMT_NOEXCEPT = default; + dynamic_format_arg_store() = default; + ~dynamic_format_arg_store() = default; dynamic_format_arg_store(const dynamic_format_arg_store&) = delete; dynamic_format_arg_store& operator=(const dynamic_format_arg_store&) = delete; diff --git a/test/format-dyn-args-test.cc b/test/format-dyn-args-test.cc index 1ea2991e..ee486374 100644 --- a/test/format-dyn-args-test.cc +++ b/test/format-dyn-args-test.cc @@ -37,20 +37,25 @@ TEST(FormatDynArgsTest, StringsAndRefs) { } struct Custom{ int i{0}; }; +FMT_BEGIN_NAMESPACE + template <> -struct fmt::formatter { - constexpr auto parse(format_parse_context& ctx) { +struct formatter { + auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) + { return ctx.begin(); } template - auto format(const Custom& p, FormatContext& ctx) { - // ctx.out() is an output iterator to write to. - return format_to( + auto format(const Custom& p, FormatContext& ctx) -> + decltype(format_to(ctx.out(), + std::declval())) { + return format_to( ctx.out(), "cust={}", p.i); } }; +FMT_END_NAMESPACE #ifdef FMT_HAS_VARIANT @@ -75,9 +80,19 @@ TEST(FormatDynArgsTest, CustomFormat) { TEST(FormatDynArgsTest, NamedArgByRef) { fmt::dynamic_format_arg_store store; - auto a1 = fmt::arg("a1_", 42); - auto ref = std::cref(a1); - store.push_back(ref); + + // Note: fmt::arg() constructs an object which holds a reference + // to its value. It's not an aggregate, so it doesn't extend the + // reference lifetime. As a result, it's a very bad idea passing temporary + // as a named argument value. Only GCC with optimization level >0 + // complains about this. + // + // A real life usecase is when you have both name and value alive + // guarantee their lifetime and thus don't want them to be copied into + // storages. + int a1_val{42}; + auto a1 = fmt::arg("a1_", a1_val); + store.push_back(std::cref(a1)); std::string result = fmt::vformat( "{a1_}", // and {} and {}",