On 9/1/26 5:20 PM, Jakub Jelinek wrote:
On Tue, Sep 01, 2026 at 05:07:34PM -0400, Jason Merrill wrote:
where because of CWG2867 the first CLEANUP_POINT_EXPR wraps the whole
structured binding initialization.  The <anonymous> var is D.2759
above, we need to remember the return value from operator bool,
but it is then used in the if condition after the initialization.

Why do we call operator bool so soon?  The comment says

           /* For structured bindings used in conditions we need to
evaluate                                                           the
conversion of decl (aka e in the standard) to bool or
integral/enumeral type (the latter for switch conditions)
before the get methods.  */

but doesn't say why.

http://eel.is/c++draft/dcl.struct.bind#7.sentence-10
requires that.
The paper had
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0963r3.html#Testing-is-sequenced-before-decomposing
about that, argues about the case of get performing moves out of the e
object and then the operator bool etc. accessing members after being moved
out.
Ah, indeed.

The patch below fixes it by creating a TARGET_EXPR for it with
false initializer instead of the operator bool call (tried void_node
initialization but that didn't work) and in the spot where the TARGET_EXPR
appears above it instead emits a MODIFY_EXPR with TARGET_EXPR on the lhs
and operator bool on the rhs.  And later on cp_finish_decl prepends the
DECL_DECOMP_BASE (the TARGET_EXPR) before the CLEANUP_POINT_EXPR, so we get
-    <<cleanup_point <<< Unknown tree: expr_stmt
+    (void) TARGET_EXPR <D.2759, 0>, <<cleanup_point <<< Unknown tree: expr_stmt
       D.2723.a = v >>>;
     <<< Unknown tree: expr_stmt
       D.2723.b = v * 2 >>>;
     <<< Unknown tree: expr_stmt
       D.2723.c = v != 0 >>>;
     D.2758 = 1;
-    TARGET_EXPR <D.2759, A::operator bool (&D.2723)>;
+    TARGET_EXPR <D.2759, 0> = A::operator bool (&D.2723);
This way the if (D.2759) use is not out of lifetime read anymore.
But now you have a TARGET_EXPR outside of any CLEANUP_POINT_EXPR. Since you're effectively declaring a non-temporary variable, better to do that directly rather than with a TARGET_EXPR, like the get_temp_regvar change I made for the cleanup guards.

Jason

Reply via email to