/* 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;}
/* 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;
}