https://gcc.gnu.org/g:4ff09eb3422c525d514c869c7e0366fd5b40b561
commit r16-1542-g4ff09eb3422c525d514c869c7e0366fd5b40b561 Author: Iain Sandoe <i...@sandoe.co.uk> Date: Mon Jun 9 11:26:01 2025 +0100 c++,coroutines: Handle await expressions in assume attributes. Here we have an expression that is not evaluated but is still seen as potentially-evaluated. We handle this by determining if the operand has side-effects, producing a warning that the assume has been ignored and eliding it. gcc/cp/ChangeLog: * coroutines.cc (analyze_expression_awaits): Elide assume attributes containing await expressions, since these have side effects. Emit a diagnostic that this has been done. gcc/testsuite/ChangeLog: * g++.dg/coroutines/assume.C: New test. Diff: --- gcc/cp/coroutines.cc | 13 +++++++++++ gcc/testsuite/g++.dg/coroutines/assume.C | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 276c6c40c785..f97bd9deae33 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -3479,6 +3479,19 @@ analyze_expression_awaits (tree *stmt, int *do_subtree, void *d) } *do_subtree = 0; } + else if (!fn && CALL_EXPR_IFN (*stmt) == IFN_ASSUME) + { + tree expr = CALL_EXPR_ARG (*stmt, 0); + if (TREE_SIDE_EFFECTS (expr)) + { + location_t loc_e = cp_expr_location (expr); + location_t loc_s = cp_expr_location (*stmt); + location_t loc_n = make_location (loc_e, loc_s, loc_s); + warning_at (loc_n, OPT_Wattributes,"assumption ignored" + " because it contains an await-expression"); + *stmt = build_empty_stmt (loc_n); + } + } } break; case CO_YIELD_EXPR: diff --git a/gcc/testsuite/g++.dg/coroutines/assume.C b/gcc/testsuite/g++.dg/coroutines/assume.C new file mode 100644 index 000000000000..d007386f6bcc --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/assume.C @@ -0,0 +1,40 @@ +// { dg-additional-options "-fsyntax-only -Wattributes" } + +#include <coroutine> + +struct awaitable { + awaitable (int n) : delay{n} {} + + constexpr bool await_ready () const noexcept { return false; } + auto await_suspend (std::coroutine_handle<> h) const { + __builtin_abort (); + 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}; } + }; +}; + +int h () { return 5; } + +Task foo() noexcept { + int x = 5; + [[assume (x == 5)]]; + [[assume (co_await awaitable{10})]]; // { dg-warning {assumption ignored because it contains an await-expression} } + [[assume ((h(),co_await awaitable{11}))]]; // { dg-warning {assumption ignored because it contains an await-expression} } + co_return; +}