https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118790
--- Comment #28 from Jakub Jelinek <jakub at gcc dot gnu.org> --- --- gcc/tree-ssa-live.cc.jj 2025-02-12 11:03:53.607556187 +0100 +++ gcc/tree-ssa-live.cc 2025-02-12 11:54:34.779131237 +0100 @@ -369,9 +369,17 @@ mark_all_vars_used_1 (tree *tp, int *wal { /* When a global var becomes used for the first time also walk its initializer (non global ones don't have any). */ - if (set_is_used (t) && is_global_var (t) - && DECL_CONTEXT (t) == current_function_decl) - mark_all_vars_used (&DECL_INITIAL (t)); + if (set_is_used (t)) + { + if (is_global_var (t) + && DECL_CONTEXT (t) == current_function_decl) + mark_all_vars_used (&DECL_INITIAL (t)); + if (DECL_HAS_VALUE_EXPR_P (t)) + { + tree dve = DECL_VALUE_EXPR (t); + mark_all_vars_used (&dve); + } + } } /* remove_unused_scope_block_p requires information about labels which are not DECL_IGNORED_P to tell if they might be used in the IL. */ @@ -389,7 +397,9 @@ mark_all_vars_used_1 (tree *tp, int *wal } /* Mark the scope block SCOPE and its subblocks unused when they can be - possibly eliminated if dead. */ + possibly eliminated if dead. Also, as remove_unused_scope_block_p is going + to keep all BLOCK_VARS VAR_DECLs with DECL_HAS_VALUE_EXPR_P, mark all vars + their DECL_VALUE_EXPR refers to. */ static void mark_scope_block_unused (tree scope) @@ -398,6 +408,12 @@ mark_scope_block_unused (tree scope) TREE_USED (scope) = false; if (!(*debug_hooks->ignore_block) (scope)) TREE_USED (scope) = true; + for (t = BLOCK_VARS (scope); t; t = DECL_CHAIN (t)) + if (VAR_P (t) && DECL_HAS_VALUE_EXPR_P (t)) + { + tree dve = DECL_VALUE_EXPR (t); + mark_all_vars_used (&dve); + } for (t = BLOCK_SUBBLOCKS (scope); t ; t = BLOCK_CHAIN (t)) mark_scope_block_unused (t); } @@ -792,9 +808,10 @@ remove_unused_locals (void) timevar_push (TV_REMOVE_UNUSED); + usedvars = BITMAP_ALLOC (NULL); + mark_scope_block_unused (DECL_INITIAL (current_function_decl)); - usedvars = BITMAP_ALLOC (NULL); auto_bitmap useddebug; /* Walk the CFG marking all referenced symbols. */ @@ -819,7 +836,7 @@ remove_unused_locals (void) { if (gimple_debug_bind_p (stmt)) { - tree var = gimple_debug_bind_get_var (stmt); + tree var = gimple_debug_bind_get_var (stmt); if (VAR_P (var)) { if (!gimple_debug_bind_get_value (stmt)) preserves it in local_decls where it was earlier removed. This keeps DECL_VALUE_EXPR (id_string.55) working until the expand pass. That throws the VAR_DECL from local_decls again in expand_used_vars, e.g. expand_one_var doesn't do anything for DECL_HAS_VALUE_EXPR_P VAR_DECLs. And then instantiate_decls even vec_frees the whole cfun->local_decls (though by that time DECL_VALUE_EXPR (id_string.55) has been garbage collected already. So perhaps instead we want to move such vars from local_decls to BLOCK_VARS of the outermost block or something? But how to find out if it wasn't there already? Note, normally these VLA addresses don't have DECL_VALUE_EXPR and so are usually used in the IL. It is just that tree-nested.cc in this case added DECL_VALUE_EXPR on those because they are (or were) referenced from nested function.