1 /* PR middle-end/88232 - Please implement -Winfinite-recursion
2 Verify simple cases without optimization.
3 { dg-do compile }
4 { dg-options "-Wall -Winfinite-recursion" } */
5
6 #define NORETURN __attribute__ ((noreturn))
7
8 typedef __SIZE_TYPE__ size_t;
9
10 extern void abort (void);
11 extern void exit (int);
12
13 extern int ei;
14 int (*pfi_v)(void);
15
16
17 /* Make sure the warning doesn't assume every call has a DECL. */
18
19 int nowarn_pfi_v (void)
20 {
21 return pfi_v ();
22 }
23
24
25 int warn_fi_v (void) // { dg-warning "-Winfinite-recursion" }
26 {
27 return warn_fi_v (); // { dg-message "recursive call" }
28 }
29
30 /* Verify #pragma suppression works. */
31
32 #pragma GCC diagnostic push
33 #pragma GCC diagnostic ignored "-Winfinite-recursion"
34
35 int suppress_warn_fi_v (void)
36 {
37 return warn_fi_v ();
38 }
39
40 #pragma GCC diagnostic pop
41
42
43 int nowarn_fi_v (void)
44 {
45 if (ei++ == 0)
46 return nowarn_fi_v ();
47 return 0;
48 }
49
50 int warn_if_i (int i) // { dg-warning "-Winfinite-recursion" }
51 {
52 if (i > 0)
53 return warn_if_i (--i); // { dg-message "recursive call" }
54 else if (i < 0)
55 return warn_if_i (-i); // { dg-message "recursive call" }
56 else
57 return warn_if_i (7); // { dg-message "recursive call" }
58 }
59
60
61 int nowarn_if_i (int i)
62 {
63 if (i > 0)
64 return nowarn_if_i (--i);
65 else if (i < 0)
66 return nowarn_if_i (-i);
67 else
68 return -1;
69 }
70
71 int nowarn_switch (int i, int a[])
72 {
73 switch (i)
74 {
75 case 0: return nowarn_switch (a[3], a + 1);
76 case 1: return nowarn_switch (a[5], a + 2);
77 case 2: return nowarn_switch (a[7], a + 3);
78 case 3: return nowarn_switch (a[9], a + 4);
79 }
80 return 77;
81 }
82
83 int warn_switch (int i, int a[]) // { dg-warning "-Winfinite-recursion" }
84 {
85 switch (i)
86 {
87 case 0: return warn_switch (a[3], a + 1);
88 case 1: return warn_switch (a[5], a + 2);
89 case 2: return warn_switch (a[7], a + 3);
90 case 3: return warn_switch (a[9], a + 4);
91 default: return warn_switch (a[1], a + 5);
92 }
93 }
94
95 NORETURN void fnoreturn (void);
96
97 /* Verify there's no warning for a function that doesn't return. */
98 int nowarn_call_noret (void)
99 {
100 fnoreturn ();
101 }
102
103 int warn_call_noret_r (void) // { dg-warning "-Winfinite-recursion" }
104 {
105 warn_call_noret_r (); // { dg-message "recursive call" }
106 fnoreturn ();
107 }
108
109 /* Verify a warning even though the abort() call would prevent the infinite
110 recursion. There's no good way to tell the two cases apart and letting
111 a simple abort prevent the warning would make it ineffective in cases
112 where it's the result of assert() expansion and not meant to actually
113 prevent recursion. */
114
115 int
116 warn_noret_call_abort_r (char *s, int n) // { dg-warning "-Winfinite-recursion" }
117 {
118 if (!s)
119 abort ();
120
121 if (n > 7)
122 abort ();
123
124 return n + warn_noret_call_abort_r (s, n - 1); // { dg-message "recursive call" }
125 }
126
127 /* Verify that a warning is not issued for an apparently infinitely
128 recursive function like the one above where the recursion would be
129 prevented by a call to a noreturn function if the recursive function
130 is itself declared noreturn. */
131
132 NORETURN void nowarn_noret_call_abort_r (int n)
133 {
134 if (n > 7)
135 abort ();
136
137 nowarn_noret_call_abort_r (n - 1);
138 }
139
140 int warn_call_abort_r (int n) // { dg-warning "-Winfinite-recursion" }
141 {
142 n += warn_call_abort_r (n - 1); // { dg-message "recursive call" }
143 if (n > 7) // unreachable
144 abort ();
145 return n;
146 }
147
148
149 /* And again with exit() for good measure. */
150
151 int warn_call_exit_r (int n) // { dg-warning "-Winfinite-recursion" }
152 {
153 n += warn_call_exit_r (n - 1); // { dg-message "recursive call" }
154 if (n > 7)
155 exit (0);
156 return n;
157 }
158
159 struct __jmp_buf_tag { };
160 typedef struct __jmp_buf_tag jmp_buf[1];
161
162 extern jmp_buf jmpbuf;
163
164 /* A call to longjmp() breaks infinite recursion. Verify it suppresses
165 the warning. */
166
167 int nowarn_call_longjmp_r (int n)
168 {
169 if (n > 7)
170 __builtin_longjmp (jmpbuf, 1);
171 return n + nowarn_call_longjmp_r (n - 1);
172 }
173
174 int warn_call_longjmp_r (int n) // { dg-warning "-Winfinite-recursion" }
175 {
176 n += warn_call_longjmp_r (n - 1); // { dg-message "recursive call" }
177 if (n > 7)
178 __builtin_longjmp (jmpbuf, 1);
179 return n;
180 }
181
182
183 struct __sigjmp_buf_tag { };
184 typedef struct __sigjmp_buf_tag sigjmp_buf[1];
185
186 extern sigjmp_buf sigjmpbuf;
187
188 /* GCC has no __builtin_siglongjmp(). */
189 extern void siglongjmp (sigjmp_buf, int);
190
191 /* A call to longjmp() breaks infinite recursion. Verify it suppresses
192 the warning. */
193
194 int nowarn_call_siglongjmp_r (int n)
195 {
196 if (n > 7)
197 siglongjmp (sigjmpbuf, 1);
198 return n + nowarn_call_siglongjmp_r (n - 1);
199 }
200
201
202 int nowarn_while_do_call_r (int n)
203 {
204 int z = 0;
205 while (n)
206 z += nowarn_while_do_call_r (n--);
207 return z;
208 }
209
210 int warn_do_while_call_r (int n) // { dg-warning "-Winfinite-recursion" }
211 {
212 int z = 0;
213 do
214 z += warn_do_while_call_r (n); // { dg-message "recursive call" }
215 while (--n);
216 return z;
217 }
218
219 /* Verify warnings for a naive replacement of a built-in fucntion. */
220
221 void* malloc (size_t n) // { dg-warning "-Winfinite-recursion" }
222 {
223 size_t *p =
224 (size_t*)__builtin_malloc (n + sizeof n); // { dg-message "recursive call" }
225 *p = n;
226 return p + 1;
227 }