https://gcc.gnu.org/g:a4744558b6a1d0a1c203acc827b6ad0cfe039212
commit r14-10812-ga4744558b6a1d0a1c203acc827b6ad0cfe039212 Author: Richard Biener <rguent...@suse.de> Date: Sun Oct 13 12:44:04 2024 +0200 tree-optimization/116907 - stale BLOCK reference from DECL_VALUE_EXPR When we remove unused BLOCKs we fail to clean references to them from DECL_VALUE_EXPRs of variables in other BLOCKs which in the PR causes LTO streaming to walk into pointers to GGC freed blocks. There's the question of whether such DECL_VALUE_EXPRs should keep variables and blocks referenced live (it doesn't seem to do that) and whether such DECL_VALUE_EXPRs should have survived in the first place. PR tree-optimization/116907 * tree-ssa-live.cc (clear_unused_block_pointer_in_block): New helper. (clear_unused_block_pointer): Call it. (cherry picked from commit 7d15248d41dc45a4ba2d38ff532b672a5c0651d0) Diff: --- gcc/tree-ssa-live.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/gcc/tree-ssa-live.cc b/gcc/tree-ssa-live.cc index 122d8e245dd0..8b559f2dbd85 100644 --- a/gcc/tree-ssa-live.cc +++ b/gcc/tree-ssa-live.cc @@ -609,6 +609,22 @@ clear_unused_block_pointer_1 (tree *tp, int *, void *) return NULL_TREE; } +/* Clear references to unused BLOCKs from DECL_VALUE_EXPRs of variables + in BLOCK. */ + +static void +clear_unused_block_pointer_in_block (tree block) +{ + for (tree t = BLOCK_VARS (block); t; t = DECL_CHAIN (t)) + if (VAR_P (t) && DECL_HAS_VALUE_EXPR_P (t)) + { + tree val = DECL_VALUE_EXPR (t); + walk_tree (&val, clear_unused_block_pointer_1, NULL, NULL); + } + for (tree t = BLOCK_SUBBLOCKS (block); t; t = BLOCK_CHAIN (t)) + clear_unused_block_pointer_in_block (t); +} + /* Set all block pointer in debug or clobber stmt to NULL if the block is unused, so that they will not be streamed out. */ @@ -664,6 +680,10 @@ clear_unused_block_pointer (void) walk_tree (gimple_op_ptr (stmt, i), clear_unused_block_pointer_1, NULL, NULL); } + + /* Walk all variables mentioned in the functions BLOCK tree and clear + DECL_VALUE_EXPR from unused blocks where present. */ + clear_unused_block_pointer_in_block (DECL_INITIAL (current_function_decl)); } /* Dump scope blocks starting at SCOPE to FILE. INDENT is the