blob: 369f4bab681ed84c9882df33dc8fbe69b1c1ebd3 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
/* 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());
}
static void nondead_after_dead_return(void)
{
/* This statement expr is not entered, and hence that fact that it
doesn't fall-through should not influence the surrounding code. */
0 && ({ return; 0;});
printf ("nondead works\n");
return;
}
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();
nondead_after_dead_return();
return 0;
}
|