/* This checks various ways of dead code inside if statements where there are non-obvious ways of how the code is actually not dead due to reachable by labels. */ extern int printf (const char *, ...); static void kb_wait_1(void) { unsigned long timeout = 2; do { /* Here the else arm is a statement expression that's supposed to be suppressed. The label inside the while would unsuppress code generation again if not handled correctly. And that would wreak havoc to the cond-expression because there's no jump-around emitted, the whole statement expression really needs to not generate code (perhaps except useless forward jumps). */ (1 ? printf("timeout=%ld\n", timeout) : ({ int i = 1; while (1) while (i--) some_label: printf("error\n"); goto some_label; }) ); timeout--; } while (timeout); } static int global; static void foo(int i) { global+=i; printf ("g=%d\n", global); } static int check(void) { printf ("check %d\n", global); return 1; } static void dowhile(void) { do { foo(1); if (global == 1) { continue; } else if (global == 2) { continue; } /* The following break shouldn't disable the check() call, as it's reachable by the continues above. */ break; } while (check()); } int main (void) { int i = 1; kb_wait_1(); /* Simple test of dead code at first sight which isn't actually dead. */ if (0) { yeah: printf ("yeah\n"); } else { printf ("boo\n"); } if (i--) goto yeah; /* Some more non-obvious uses where the problems are loops, so that even the first loop statements aren't actually dead. */ i = 1; if (0) { while (i--) { printf ("once\n"); enterloop: printf ("twice\n"); } } if (i >= 0) goto enterloop; /* The same with statement expressions. One might be tempted to handle them specially by counting if inside statement exprs and not unsuppressing code at loops at all then. See kb_wait_1 for the other side of the medal where that wouldn't work. */ i = ({ int j = 1; if (0) { while (j--) { printf ("SEonce\n"); enterexprloop: printf ("SEtwice\n"); } } if (j >= 0) goto enterexprloop; j; }); /* The other two loop forms: */ i = 1; if (0) { for (i = 1; i--;) { printf ("once2\n"); enterloop2: printf ("twice2\n"); } } if (i > 0) goto enterloop2; i = 1; if (0) { do { printf ("once3\n"); enterloop3: printf ("twice3\n"); } while (i--); } if (i > 0) goto enterloop3; /* And check that case and default labels have the same effect of disabling code suppression. */ i = 41; switch (i) { if (0) { printf ("error\n"); case 42: printf ("error2\n"); case 41: printf ("caseok\n"); } } i = 41; switch (i) { if (0) { printf ("error3\n"); default: printf ("caseok2\n"); break; case 42: printf ("error4\n"); } } dowhile(); return 0; }