https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84704
--- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Ugh, this one is really nasty. If a statement-expression has side-effects, like for: a[({ i++; 0; })] %= 5; the FE wraps the statement expression with a SAVE_EXPR: # DEBUG BEGIN STMT; <<cleanup_point <<< Unknown tree: expr_stmt (void) (a[SAVE_EXPR <# DEBUG BEGIN STMT; <<cleanup_point <<< Unknown tree: expr_stmt (void) i++ >>>>>; # DEBUG BEGIN STMT; 0>] = a[SAVE_EXPR <# DEBUG BEGIN STMT; <<cleanup_point <<< Unknown tree: expr_stmt (void) i++ >>>>>; # DEBUG BEGIN STMT; 0>] % 5) >>>>>; But as it doesn't have side-effects in this case, it isn't duplicated, and unshare_expr/unshare_body uses mostly_copy_tree_r, which actually doesn't copy STATEMENT_LISTs; and the gimplifier is destructive, so when the STATEMENT_LISTs are shared by both ARRAY_REFs (which were unshared by unshare_body), the first ARRAY_REF's index is gimplified fine, but turns the STATEMENT_LIST into void typed one that only holds the DEBUG_BEGIN_STMT, and moves the constant out into a temporary's initializer (which also looks problematic for -fcompare-debug) and when we gimplify the second ARRAY_REF, we ICE, because ARRAY_REF index really shouldn't have void type.