https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120608
--- Comment #19 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Why are you using the attribute at -O0? In any case, this boils down to roughly -O0 -fsanitize=address [[gnu::noipa]] int foo (int x) { return x; } [[gnu::noipa]] void bar (int *x, int *y, int *z) { (void) x; (void) y; (void) z; } [[gnu::noipa]] int baz (int x) { int a = 4; { int b = 8; { int c = 10; bar (&a, &b, &c); if (a + b + c == 22) [[gnu::musttail]] return foo (x); bar (&a, &b, &c); } bar (&a, &b, &a); } bar (&a, &a, &a); return 42; } During gimplification, .ASAN_MARK (POISON, ...); calls are added as try ... finally. So we get something like: try { .ASAN_MARK (UNPOISON, &a, 4); a = 4; { int b; try { .ASAN_MARK (UNPOISON, &b, 4); b = 8; { int c; try { .ASAN_MARK (UNPOISON, &c, 4); c = 10; ... D.3414 = foo (x); [must tail call] // predicted unlikely by early return (on trees) predictor. return D.3414; ... } finally { .ASAN_MARK (POISON, &c, 4); } ... } finally { .ASAN_MARK (POISON, &b, 4); } ... } finally { .ASAN_MARK (POISON, &a, 4); } Now, the eh pass turns those into D.3414 = foo (x); [must tail call] // predicted unlikely by early return (on trees) predictor. finally_tmp.3 = 0; goto <D.3417>; ... <D.3417>: .ASAN_MARK (POISON, &c, 4); switch (finally_tmp.3) <default: <D.3420>, case 1: <D.3418>> <D.3418>: goto <D.3419>; <D.3420>: finally_tmp.4 = 0; goto <D.3422>; ... <D.3422>: .ASAN_MARK (POISON, &b, 4); switch (finally_tmp.4) <default: <D.3425>, case 1: <D.3423>> <D.3423>: goto <D.3424>; <D.3425>: goto <D.3426>; ... <D.3426>: .ASAN_MARK (POISON, &a, 4); goto <D.3415>; <D.3415>: return D.3414; And note we've been asked not to optimize anything and so we don't. Before sanopt0 pass we still have _26 = foo (x_24(D)); [must tail call] // predicted unlikely by early return (on trees) predictor. finally_tmp.3_27 = 0; goto <bb 5>; [INV] ... <bb 5> : # _6 = PHI <_26(3), _23(D)(4)> # finally_tmp.3_8 = PHI <finally_tmp.3_27(3), finally_tmp.3_22(4)> .ASAN_MARK (POISON, &c, 4); if (finally_tmp.3_8 == 1) goto <bb 7>; [INV] else goto <bb 6>; [INV] <bb 6> : <L4>: finally_tmp.4_31 = 0; goto <bb 8>; [INV] ... <bb 8> : # finally_tmp.4_9 = PHI <finally_tmp.4_31(6), finally_tmp.4_30(7)> .ASAN_MARK (POISON, &b, 4); if (finally_tmp.4_9 == 1) goto <bb 9>; [INV] else goto <bb 10>; [INV] ... <bb 10> : # _7 = PHI <_6(8), _34(9)> .ASAN_MARK (POISON, &a, 4); <bb 11> : <L11>: return _7; And then sanopt0 actually comes before musttail pass (the -O0 special copy of that), so .ASAN_MARK calls are lowered into something musttail pass has no easy way to match. So, in order to deal with this, we'd need to do something with pass ordering: NEXT_PASS (pass_sanopt); NEXT_PASS (pass_cleanup_eh); NEXT_PASS (pass_musttail); We want the musttail pass before sanopt, but am not sure if we still rely on cleanup_eh or not (I think tailc/musttail pass has workarounds for that), so maybe simply moving pass_musttail 2 lines up would work. And another problem is the lack of forward propagation of the finally_tmp.* SSA_NAMEs into PHI nodes and whether tailc/musttail will be able to deal with the GIMPLE_CONDs in there. If we track through which edges we go from the musttail call to the return path and we see GIMPLE_CONDs on that path, we could look it up; e.g. for the if (finally_tmp.3_8 == 1) case, see it defined in # finally_tmp.3_8 = PHI <finally_tmp.3_27(3), finally_tmp.3_22(4)> and because we came to bb 5 through the 3->5 edge, look at finally_tmp.3_27 SSA_NAME_DEF_STMT and because it is 0, figure out the condition is false, etc.