https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81275
Jakub Jelinek <jakub at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |mpolacek at gcc dot gnu.org
--- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Marek, could we reuse the fallthrough warning infrastructure for this to
determine whether there is a possible fallthrough or not?
Though, trying:
int
foo (int a, int b, int c)
{
switch (c)
{
case 5:
switch (a)
{
case 0:
switch (b)
{
default:
return 0;
}
break;
#ifdef FT
case 7:
break;
#endif
default:
return 0;
}
case 6:
return 7;
}
return 8;
}
we don't warn about the fallthrough from case 5 to case 6 no matter if FT is
defined (in that case there is obvious fallthrough, say for foo (7, 0, 5), or
when FT is not defined (then there isn't, but gimple_seq_may_fallthru doesn't
know that). Whether a label is emitted after a switch (for the break; label)
is determined already in the FEs based on whether any break; is present, no
matter if reachable or not. So indeed, dead code such as the break; in your
#c0 testcase, or whatever other code followed by a break, is able to confuse
the gimplifier and eh lowering into assuming there might be fallthrough.
While the -Wreturn-type warning is emitted after cfg is built, the problem is
if we decide to emit the try/finally with a finally_tmp variable to avoid
duplicating the cleanup actions, then while after building cfg we optimize away
obviously unreachable code, we have no SSA form yet and thus determining if the
finally_tmp.N variable is always the same in all paths might be expensive.
At -O0 that actually isn't optimized by anything until assembly is emited, so
we still see in the assembly:
testl %eax, %eax
jne .L9
movl $0, %ebx
movl $0, %r12d
jmp .L4
.L9:
movl $0, %ebx
movl $0, %r12d
.L4:
// Here both %ebx and %r12d are 0 (set the same on both paths reaching this
// label.
leaq -17(%rbp), %rax
movq %rax, %rdi
// Here we run ~C()
call _ZN1CD1Ev
// Now we test whether it is 1, which is never, in that case we fall through
// into returning without a value.
cmpl $1, %r12d
jne .L10
nop
jmp .L1
.L10:
movl %ebx, %eax
.L1:
addq $32, %rsp
popq %rbx
popq %r12
popq %rbp
ret
So, if we can't do anyuthing for this at the gimplifier level, we'd need to add
an optimization in the cfg pass that would look for cases like:
;; basic block 4, loop depth 0
;; pred: 3
<L0> [0.00%] [count: INV]:
D.2315 = 0;
finally_tmp.0 = 0;
goto <bb 6>; [INV] [count: INV]
;; succ: 6
;; basic block 5, loop depth 0
;; pred: 3
<L2> [0.00%] [count: INV]:
D.2315 = 0;
finally_tmp.0 = 0;
;; succ: 6
;; basic block 6, loop depth 0
;; pred: 4
;; 5
C::~C (&c);
switch (finally_tmp.0) <default: <L12> [INV] [count: INV], case 1: <L5> [INV]
[count: INV]>
and optimize that switch into goto <L12>; after checking that finally_tmp.0 var
is not addressable, not modified in the bb with the switch and set to the same
value at the end of all predecessor bbs.
But that would be an optimization, not sure if we want to do that generally for
-O0, or limit it to somehow specially marked finally_tmp.NN variables.