Skip to content

Commit 20f09db

Browse files
committed
🐛 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.
1 parent 3023efe commit 20f09db

File tree

3 files changed

+45
-10
lines changed

3 files changed

+45
-10
lines changed

include/stdx/utility.hpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,14 @@ struct type_val {
163163
}
164164
};
165165

166-
template <int> constexpr auto is_type() -> std::false_type;
167-
template <typename> constexpr auto is_type() -> std::true_type;
166+
template <typename>
167+
constexpr inline auto is_type = [] { return std::true_type{}; };
168+
template <>
169+
constexpr inline auto is_type<from_any> = [] { return std::false_type{}; };
168170

169-
template <typename> struct typer;
171+
template <typename> struct typer {
172+
using type = void;
173+
};
170174
template <typename T> struct typer<from_any(T)> {
171175
using type = T;
172176
};
@@ -239,8 +243,8 @@ template <typename T> constexpr auto is_ct_v<T const> = is_ct_v<T>;
239243
STDX_PRAGMA(diagnostic ignored "-Wold-style-cast") \
240244
STDX_PRAGMA(diagnostic ignored "-Wunused-value") \
241245
if constexpr (decltype(::stdx::cxv_detail::is_type< \
242-
::stdx::cxv_detail::from_any( \
243-
__VA_ARGS__)>())::value) { \
246+
__typeof__(::stdx::cxv_detail::from_any( \
247+
__VA_ARGS__))>())::value) { \
244248
return ::stdx::overload{ \
245249
::stdx::cxv_detail::cx_base{}, [] { \
246250
return ::stdx::type_identity< \
@@ -299,14 +303,14 @@ constexpr auto cx_detect1(auto) { return 0; }
299303
STDX_PRAGMA(diagnostic push) \
300304
STDX_PRAGMA(diagnostic ignored "-Wold-style-cast") \
301305
if constexpr (decltype(::stdx::cxv_detail::is_type< \
302-
::stdx::cxv_detail::from_any( \
303-
__VA_ARGS__)>())::value) { \
306+
__typeof__(::stdx::cxv_detail::from_any( \
307+
__VA_ARGS__))>())::value) { \
304308
return ::stdx::overload{ \
305309
::stdx::cxv_detail::cx_base{}, [&] { \
306310
return ::stdx::type_identity< \
307-
decltype(::stdx::cxv_detail::type_of< \
308-
::stdx::cxv_detail::from_any( \
309-
__VA_ARGS__)>())>{}; \
311+
typename ::stdx::cxv_detail::typer< \
312+
__typeof__(::stdx::cxv_detail::from_any( \
313+
__VA_ARGS__))>::type>{}; \
310314
}}; \
311315
} else if constexpr (::stdx::is_cx_value_v< \
312316
std::invoke_result_t<decltype(f)>> or \

test/ct_format.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,18 @@ TEST_CASE("FORMAT an integral_constant argument", "[ct_format]") {
301301
auto I = std::integral_constant<int, 17>{};
302302
STATIC_REQUIRE(STDX_CT_FORMAT("Hello {}", I) == "Hello 17"_fmt_res);
303303
}
304+
305+
#ifdef __clang__
306+
namespace {
307+
struct expression_test {
308+
int f(int x) { return x; }
309+
};
310+
} // namespace
311+
312+
TEST_CASE("FORMAT non-constexpr expression", "[utility]") {
313+
auto x = 17;
314+
constexpr auto expected =
315+
stdx::format_result{"Hello {}"_ctst, stdx::make_tuple(17)};
316+
CHECK(STDX_CT_FORMAT("Hello {}", expression_test{}.f(x)) == expected);
317+
}
318+
#endif

test/utility.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,4 +376,20 @@ TEST_CASE("CX_WRAP integral_constant arg", "[utility]") {
376376
STATIC_REQUIRE(std::is_same_v<decltype(CX_WRAP(x)), decltype(x)>);
377377
CHECK(CX_WRAP(x)() == 17);
378378
}
379+
380+
#ifdef __clang__
381+
namespace {
382+
struct expression_test {
383+
int f(int x) { return x; }
384+
};
385+
} // namespace
386+
387+
TEST_CASE("CX_WRAP non-constexpr expression", "[utility]") {
388+
auto x = 17;
389+
STATIC_REQUIRE(
390+
std::is_same_v<decltype(CX_WRAP(expression_test{}.f(x))), int>);
391+
CHECK(CX_WRAP(expression_test{}.f(x)) == 17);
392+
}
393+
#endif
394+
379395
#endif

0 commit comments

Comments
 (0)