1 /* PR tree-optimization/81384 - built-in form of strnlen missing
2    Test to verify that strnlen built-in expansion works correctly
3    in the absence of tree strlen optimization.
4    { dg-do compile }
5    { dg-options "-O2 -Wall -Wno-stringop-overflow -fdump-tree-optimized" } */
6 
7 #include "strlenopt.h"
8 
9 #define PTRDIFF_MAX __PTRDIFF_MAX__
10 #define SIZE_MAX    __SIZE_MAX__
11 
12 typedef __SIZE_TYPE__ size_t;
13 
14 extern void abort (void);
15 extern size_t strnlen (const char *, size_t);
16 
17 #define CAT(x, y) x ## y
18 #define CONCAT(x, y) CAT (x, y)
19 #define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)
20 
21 #define FAIL(name) do {				\
22     extern void FAILNAME (name) (void);		\
23     FAILNAME (name)();				\
24   } while (0)
25 
26 /* Macro to emit a call to funcation named
27      call_in_true_branch_not_eliminated_on_line_NNN()
28    for each call that's expected to be eliminated.  The dg-final
29    scan-tree-dump-time directive at the bottom of the test verifies
30    that no such call appears in output.  */
31 #define ELIM(expr) \
32   if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0
33 
34 /* Macro to emit a call to a function named
35      call_made_in_{true,false}_branch_on_line_NNN()
36    for each call that's expected to be retained.  The dg-final
37    scan-tree-dump-time directive at the bottom of the test verifies
38    that the expected number of both kinds of calls appears in output
39    (a pair for each line with the invocation of the KEEP() macro.  */
40 #define KEEP(expr)				\
41   if (expr)					\
42     FAIL (made_in_true_branch);			\
43   else						\
44     FAIL (made_in_false_branch)
45 
46 extern char c;
47 extern char a1[1];
48 extern char a3[3];
49 extern char a5[5];
50 extern char a3_7[3][7];
51 extern char ax[];
52 
elim_strnlen_arr_cst(void)53 void elim_strnlen_arr_cst (void)
54 {
55   /* The length of a string stored in a one-element array must be zero.
56      The result reported by strnlen() for such an array can be non-zero
57      only when the bound is equal to 1 (in which case the result must
58      be one).  */
59   ELIM (strnlen (&c, 0) == 0);
60   ELIM (strnlen (&c, 1) < 2);
61   ELIM (strnlen (&c, 2) == 0);
62   ELIM (strnlen (&c, 9) == 0);
63   ELIM (strnlen (&c, PTRDIFF_MAX) == 0);
64   ELIM (strnlen (&c, SIZE_MAX) == 0);
65   ELIM (strnlen (&c, -1) == 0);
66 
67   ELIM (strnlen (a1, 0) == 0);
68   ELIM (strnlen (a1, 1) < 2);
69   ELIM (strnlen (a1, 2) == 0);
70   ELIM (strnlen (a1, 9) == 0);
71   ELIM (strnlen (a1, PTRDIFF_MAX) == 0);
72   ELIM (strnlen (a1, SIZE_MAX) == 0);
73   ELIM (strnlen (a1, -1) == 0);
74 
75   ELIM (strnlen (a3, 0) == 0);
76   ELIM (strnlen (a3, 1) < 2);
77   ELIM (strnlen (a3, 2) < 3);
78   ELIM (strnlen (a3, 3) < 4);
79   ELIM (strnlen (a3, 9) < 4);
80   ELIM (strnlen (a3, PTRDIFF_MAX) < 4);
81   ELIM (strnlen (a3, SIZE_MAX) < 4);
82   ELIM (strnlen (a3, -1) < 4);
83 
84   ELIM (strnlen (a3_7[0], 0) == 0);
85   ELIM (strnlen (a3_7[0], 1) < 2);
86   ELIM (strnlen (a3_7[0], 2) < 3);
87   ELIM (strnlen (a3_7[0], 3) < 4);
88   ELIM (strnlen (a3_7[0], 9) <= 9);
89   ELIM (strnlen (a3_7[0], PTRDIFF_MAX) <= sizeof a3_7);
90   ELIM (strnlen (a3_7[0], SIZE_MAX) <= sizeof a3_7);
91   ELIM (strnlen (a3_7[0], -1) <= sizeof a3_7);
92 
93   ELIM (strnlen (a3_7[2], 0) == 0);
94   ELIM (strnlen (a3_7[2], 1) < 2);
95   ELIM (strnlen (a3_7[2], 2) < 3);
96   ELIM (strnlen (a3_7[2], 3) < 4);
97   ELIM (strnlen (a3_7[2], 9) <= 9);
98   ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < sizeof a3_7);
99   ELIM (strnlen (a3_7[2], SIZE_MAX) < sizeof a3_7);
100   ELIM (strnlen (a3_7[2], -1) < sizeof a3_7);
101 
102   ELIM (strnlen ((char*)a3_7, 0) == 0);
103   ELIM (strnlen ((char*)a3_7, 1) < 2);
104   ELIM (strnlen ((char*)a3_7, 2) < 3);
105   ELIM (strnlen ((char*)a3_7, 3) < 4);
106   ELIM (strnlen ((char*)a3_7, 9) < 10);
107   ELIM (strnlen ((char*)a3_7, 19) < 20);
108   ELIM (strnlen ((char*)a3_7, 21) <= sizeof a3_7);
109   ELIM (strnlen ((char*)a3_7, 23) <= sizeof a3_7);
110   ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) <= sizeof a3_7);
111   ELIM (strnlen ((char*)a3_7, SIZE_MAX) <= sizeof a3_7);
112   ELIM (strnlen ((char*)a3_7, -1) <= sizeof a3_7);
113 
114   ELIM (strnlen (ax, 0) == 0);
115   ELIM (strnlen (ax, 1) < 2);
116   ELIM (strnlen (ax, 2) < 3);
117   ELIM (strnlen (ax, 9) < 10);
118   ELIM (strnlen (ax, PTRDIFF_MAX) < PTRDIFF_MAX);
119   ELIM (strnlen (ax, SIZE_MAX) < PTRDIFF_MAX);
120   ELIM (strnlen (ax, -1) < PTRDIFF_MAX);
121 }
122 
123 
elim_strnlen_str_cst(void)124 void elim_strnlen_str_cst (void)
125 {
126   const char *s0 = "";
127   const char *s1 = "1";
128   const char *s3 = "123";
129 
130   ELIM (strnlen (s0, 0) == 0);
131   ELIM (strnlen (s0, 1) == 0);
132   ELIM (strnlen (s0, 9) == 0);
133   ELIM (strnlen (s0, PTRDIFF_MAX) == 0);
134   ELIM (strnlen (s0, SIZE_MAX) == 0);
135   ELIM (strnlen (s0, -1) == 0);
136 
137   ELIM (strnlen (s1, 0) == 0);
138   ELIM (strnlen (s1, 1) == 1);
139   ELIM (strnlen (s1, 9) == 1);
140   ELIM (strnlen (s1, PTRDIFF_MAX) == 1);
141   ELIM (strnlen (s1, SIZE_MAX) == 1);
142   ELIM (strnlen (s1, -2) == 1);
143 
144   ELIM (strnlen (s3, 0) == 0);
145   ELIM (strnlen (s3, 1) == 1);
146   ELIM (strnlen (s3, 2) == 2);
147   ELIM (strnlen (s3, 3) == 3);
148   ELIM (strnlen (s3, 9) == 3);
149   ELIM (strnlen (s3, PTRDIFF_MAX) == 3);
150   ELIM (strnlen (s3, SIZE_MAX) == 3);
151   ELIM (strnlen (s3, -2) == 3);
152 }
153 
elim_strnlen_range(char * s)154 void elim_strnlen_range (char *s)
155 {
156   const char *s0 = "";
157   const char *s1 = "1";
158   const char *s3 = "123";
159 
160   size_t n_0_1 = (size_t)s & 1;
161   size_t n_0_2 = ((size_t)s & 3) < 3 ? ((size_t)s & 3) : 2;
162   size_t n_0_3 = (size_t)s & 3;
163   size_t n_1_2 = n_0_1 + 1;
164 
165   ELIM (strnlen (s0, n_0_1) == 0);
166   ELIM (strnlen (s0, n_0_2) == 0);
167   ELIM (strnlen (s0, n_1_2) == 0);
168 
169   ELIM (strnlen (s1, n_0_1) < 2);
170   ELIM (strnlen (s1, n_0_2) < 2);
171   ELIM (strnlen (s1, n_0_3) < 2);
172 
173   ELIM (strnlen (s1, n_1_2) > 0);
174   ELIM (strnlen (s1, n_1_2) < 2);
175 
176   ELIM (strnlen (s3, n_0_1) < 2);
177   ELIM (strnlen (s3, n_0_2) < 3);
178   ELIM (strnlen (s3, n_0_3) < 4);
179 
180   ELIM (strnlen (s3, n_1_2) > 0);
181   ELIM (strnlen (s3, n_1_2) < 4);
182 }
183 
184 
185 #line 1000
186 
keep_strnlen_arr_cst(void)187 void keep_strnlen_arr_cst (void)
188 {
189   KEEP (strnlen (&c, 1) == 0);
190   KEEP (strnlen (&c, 1) == 1);
191 
192   KEEP (strnlen (a1, 1) == 0);
193   KEEP (strnlen (a1, 1) == 1);
194 
195   KEEP (strnlen (ax, 9) < 9);
196 }
197 
198 struct FlexArrays
199 {
200   char c;
201   char a0[0];   /* Access to internal zero-length arrays are undefined.  */
202   char a1[1];
203 };
204 
keep_strnlen_memarr_cst(struct FlexArrays * p)205 void keep_strnlen_memarr_cst (struct FlexArrays *p)
206 {
207   KEEP (strnlen (&p->c, 1) == 0);
208   KEEP (strnlen (&p->c, 1) == 1);
209 
210 #if 0
211   /* Accesses to internal zero-length arrays are undefined so avoid
212      exercising them.  */
213   KEEP (strnlen (p->a0, 1) == 0);
214   KEEP (strnlen (p->a0, 1) == 1);
215   KEEP (strnlen (p->a0, 9) < 9);
216 #endif
217 
218   KEEP (strnlen (p->a1, 1) == 0);
219   KEEP (strnlen (p->a1, 1) == 1);
220 
221   KEEP (strnlen (p->a1, 2) == 0);
222   KEEP (strnlen (p->a1, 2) == 1);
223   KEEP (strnlen (p->a1, 2) == 2);
224 
225   KEEP (strnlen (p->a1, 9) < 9);
226 }
227 
228 /* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } }
229 
230    { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 13 "optimized" } }
231    { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 13 "optimized" } } */
232