From 20f09db7a04c4b80baf653c1c335baaeb2cf16b7 Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Mon, 14 Jul 2025 15:50:42 -0600 Subject: [PATCH] :bug: Fix `CX_WRAP` for expressions Problem: - When `CX_WRAP` wraps expressions, it can cause a compiler error with `is_type` and `type_of`. Solution: - Use `__typeof__` to get around this. Note: - The test passes GCC 12, 13 and trunk; however GCC 14 seems to have a regression. --- include/stdx/utility.hpp | 24 ++++++++++++++---------- test/ct_format.cpp | 15 +++++++++++++++ test/utility.cpp | 16 ++++++++++++++++ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/include/stdx/utility.hpp b/include/stdx/utility.hpp index 8d65bf2..e85ba0f 100644 --- a/include/stdx/utility.hpp +++ b/include/stdx/utility.hpp @@ -163,10 +163,14 @@ struct type_val { } }; -template constexpr auto is_type() -> std::false_type; -template constexpr auto is_type() -> std::true_type; +template +constexpr inline auto is_type = [] { return std::true_type{}; }; +template <> +constexpr inline auto is_type = [] { return std::false_type{}; }; -template struct typer; +template struct typer { + using type = void; +}; template struct typer { using type = T; }; @@ -239,8 +243,8 @@ template constexpr auto is_ct_v = is_ct_v; STDX_PRAGMA(diagnostic ignored "-Wold-style-cast") \ STDX_PRAGMA(diagnostic ignored "-Wunused-value") \ if constexpr (decltype(::stdx::cxv_detail::is_type< \ - ::stdx::cxv_detail::from_any( \ - __VA_ARGS__)>())::value) { \ + __typeof__(::stdx::cxv_detail::from_any( \ + __VA_ARGS__))>())::value) { \ return ::stdx::overload{ \ ::stdx::cxv_detail::cx_base{}, [] { \ return ::stdx::type_identity< \ @@ -299,14 +303,14 @@ constexpr auto cx_detect1(auto) { return 0; } STDX_PRAGMA(diagnostic push) \ STDX_PRAGMA(diagnostic ignored "-Wold-style-cast") \ if constexpr (decltype(::stdx::cxv_detail::is_type< \ - ::stdx::cxv_detail::from_any( \ - __VA_ARGS__)>())::value) { \ + __typeof__(::stdx::cxv_detail::from_any( \ + __VA_ARGS__))>())::value) { \ return ::stdx::overload{ \ ::stdx::cxv_detail::cx_base{}, [&] { \ return ::stdx::type_identity< \ - decltype(::stdx::cxv_detail::type_of< \ - ::stdx::cxv_detail::from_any( \ - __VA_ARGS__)>())>{}; \ + typename ::stdx::cxv_detail::typer< \ + __typeof__(::stdx::cxv_detail::from_any( \ + __VA_ARGS__))>::type>{}; \ }}; \ } else if constexpr (::stdx::is_cx_value_v< \ std::invoke_result_t> or \ diff --git a/test/ct_format.cpp b/test/ct_format.cpp index 941b592..df6f87c 100644 --- a/test/ct_format.cpp +++ b/test/ct_format.cpp @@ -301,3 +301,18 @@ TEST_CASE("FORMAT an integral_constant argument", "[ct_format]") { auto I = std::integral_constant{}; STATIC_REQUIRE(STDX_CT_FORMAT("Hello {}", I) == "Hello 17"_fmt_res); } + +#ifdef __clang__ +namespace { +struct expression_test { + int f(int x) { return x; } +}; +} // namespace + +TEST_CASE("FORMAT non-constexpr expression", "[utility]") { + auto x = 17; + constexpr auto expected = + stdx::format_result{"Hello {}"_ctst, stdx::make_tuple(17)}; + CHECK(STDX_CT_FORMAT("Hello {}", expression_test{}.f(x)) == expected); +} +#endif diff --git a/test/utility.cpp b/test/utility.cpp index 087b07a..e9aa348 100644 --- a/test/utility.cpp +++ b/test/utility.cpp @@ -376,4 +376,20 @@ TEST_CASE("CX_WRAP integral_constant arg", "[utility]") { STATIC_REQUIRE(std::is_same_v); CHECK(CX_WRAP(x)() == 17); } + +#ifdef __clang__ +namespace { +struct expression_test { + int f(int x) { return x; } +}; +} // namespace + +TEST_CASE("CX_WRAP non-constexpr expression", "[utility]") { + auto x = 17; + STATIC_REQUIRE( + std::is_same_v); + CHECK(CX_WRAP(expression_test{}.f(x)) == 17); +} +#endif + #endif