https://gcc.gnu.org/g:ab3f04b73e5a1dd734d3bab64b4878d2d0cc29ad
commit r16-1508-gab3f04b73e5a1dd734d3bab64b4878d2d0cc29ad Author: Iain Sandoe <i...@sandoe.co.uk> Date: Mon Jun 9 11:00:47 2025 +0100 c++, coroutines: Handle builtin_constant_p [PR116775]. Since the folding of this builtin happens after the main coroutine FE lowering, we need to account for await expressions in that lowering. Since these expressions have a property of being not evaluated, but do not have the full constraints of an unevaluatated context, we want to apply the checks and then remove the await expressions so that they no longer participate in the analysis and lowering. When a builtin_constant_p call is encountered, and the operand contains any await expression, we check to see if the operand can be a constant and replace the call with its result. PR c++/116775 gcc/cp/ChangeLog: * coroutines.cc (analyze_expression_awaits): When we see a builtin_constant_p call, and that contains one or more await expressions, then replace the call with its result and discard the unevaluated operand. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr116775.C: New test. Signed-off-by: Iain Sandoe <i...@sandoe.co.uk> Diff: --- gcc/cp/coroutines.cc | 23 +++++++++- gcc/testsuite/g++.dg/coroutines/pr116775.C | 68 ++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index bd61785a4ef5..1fbdee1b4f63 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -3425,7 +3425,8 @@ maybe_promote_temps (tree *stmt, void *d) return cp_walk_tree (stmt, register_awaits, d, &visited); } -/* Lightweight callback to determine two key factors: +/* Relatively lightweight callback to do initial assessment: + 0) Rewrite some await expressions. 1) If the statement/expression contains any await expressions. 2) If the statement/expression potentially requires a re-write to handle TRUTH_{AND,OR}IF_EXPRs since, in most cases, they will need expansion @@ -3442,6 +3443,26 @@ analyze_expression_awaits (tree *stmt, int *do_subtree, void *d) switch (TREE_CODE (*stmt)) { default: return NULL_TREE; + case CALL_EXPR: + { + tree fn = cp_get_callee_fndecl_nofold (*stmt); + /* Special-cases where we want to re-write await expressions to some + other value before they are otherwise processed. */ + if (fn && DECL_IS_BUILTIN_CONSTANT_P (fn)) + { + gcc_checking_assert (call_expr_nargs (*stmt) == 1); + tree expr = CALL_EXPR_ARG (*stmt, 0); + if (cp_walk_tree (&expr, find_any_await, nullptr, NULL)) + { + if (TREE_CONSTANT (maybe_constant_value (expr))) + *stmt = integer_one_node; + else + *stmt = integer_zero_node; + } + *do_subtree = 0; + } + } + break; case CO_YIELD_EXPR: /* co_yield is syntactic sugar, re-write it to co_await. */ *stmt = TREE_OPERAND (*stmt, 1); diff --git a/gcc/testsuite/g++.dg/coroutines/pr116775.C b/gcc/testsuite/g++.dg/coroutines/pr116775.C new file mode 100644 index 000000000000..981e27af27b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr116775.C @@ -0,0 +1,68 @@ +// { dg-additional-options "-fsyntax-only" } +// PR116775 +#include <coroutine> +#ifndef OUTPUT +# define PRINT(X) +# define PRINTF(...) +#else +#include <cstdio> +# define PRINT(X) puts(X) +# define PRINTF(...) printf(__VA_ARGS__) +#endif + +struct awaitable { + awaitable(int n) : delay{n} {} + + constexpr bool await_ready() const noexcept { return false; } + auto await_suspend(std::coroutine_handle<> h) const { + __builtin_trap (); + return false; + } + int await_resume() const noexcept { + return delay; + } + + int delay; +}; + +struct Task { + struct promise_type { + promise_type() = default; + Task get_return_object() { return {}; } + std::suspend_never initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void unhandled_exception() {} + void return_void () {} + awaitable yield_value (int v) { return {v}; } + }; +}; + +Task foo() noexcept { + if (__builtin_constant_p (true ? 1 : co_await awaitable{10})) + PRINT ("const OK"); + else + { + PRINT ("failed : should be const"); + __builtin_abort (); + } + if (__builtin_constant_p (false ? 1 : co_await awaitable{15})) + { + PRINT ("failed : should not be const"); + __builtin_abort (); + } + else + PRINT ("not const, OK"); + if (__builtin_constant_p (5 == (co_yield 42))) + { + PRINT ("failed : should not be const"); + __builtin_abort (); + } + else + PRINT ("not const, OK"); + co_return; +} + +//call foo +int main() { + foo(); +}