1 /* { dg-do compile } */
2 /* { dg-options "-O -fdiagnostics-show-caret" } */
3 
4 /* This is a collection of unittests for ranges within string literals,
5    using diagnostic_plugin_test_string_literals, which handles
6    "__emit_string_literal_range" by generating a warning at the given
7    subset of a string literal.
8 
9    The indices are 0-based.  It's easiest to verify things using string
10    literals that are runs of 0-based digits (to avoid having to count
11    characters).
12 
13    LITERAL is a const void * to allow testing the various kinds of wide
14    string literal, rather than just const char *.  */
15 
16 extern void __emit_string_literal_range (const void *literal, int caret_idx,
17 					 int start_idx, int end_idx);
18 
19 void
test_simple_string_literal(void)20 test_simple_string_literal (void)
21 {
22   __emit_string_literal_range ("0123456789", /* { dg-warning "range" } */
23 			       6, 6, 7);
24 /* { dg-begin-multiline-output "" }
25    __emit_string_literal_range ("0123456789",
26                                        ^~
27    { dg-end-multiline-output "" } */
28 }
29 
30 void
test_concatenated_string_literal(void)31 test_concatenated_string_literal (void)
32 {
33   __emit_string_literal_range ("01234" "56789", /* { dg-warning "range" } */
34 			       4, 3, 6);
35 /* { dg-begin-multiline-output "" }
36    __emit_string_literal_range ("01234" "56789",
37                                     ~^~~~~~
38    { dg-end-multiline-output "" } */
39 }
40 
41 void
test_multiline_string_literal(void)42 test_multiline_string_literal (void)
43 {
44   __emit_string_literal_range ("01234" /* { dg-warning "range" } */
45                                "56789",
46                                4, 3, 6);
47 /* { dg-begin-multiline-output "" }
48    __emit_string_literal_range ("01234"
49                                     ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
50                                 "56789",
51                                 ~~~
52    { dg-end-multiline-output "" } */
53   /* FIXME: why does the above need three trailing spaces?  */
54 }
55 
56 /* Tests of various unicode encodings.
57 
58    Digits 0 through 9 are unicode code points:
59       U+0030 DIGIT ZERO
60       ...
61       U+0039 DIGIT NINE
62    However, these are not always valid as UCN (see the comment in
63    libcpp/charset.c:_cpp_valid_ucn).
64 
65    Hence we need to test UCN using an alternative unicode
66    representation of numbers; let's use Roman numerals,
67    (though these start at one, not zero):
68       U+2170 SMALL ROMAN NUMERAL ONE
69       ...
70       U+2174 SMALL ROMAN NUMERAL FIVE  ("v")
71       U+2175 SMALL ROMAN NUMERAL SIX   ("vi")
72       ...
73       U+2178 SMALL ROMAN NUMERAL NINE.  */
74 
75 void
test_hex(void)76 test_hex (void)
77 {
78   /* Digits 0-9, expressing digit 5 in ASCII as "\x35"
79      and with a space in place of digit 6, to terminate the escaped
80      hex code.  */
81   __emit_string_literal_range ("01234\x35 789", /* { dg-warning "range" } */
82 			       4, 3, 7);
83 /* { dg-begin-multiline-output "" }
84    __emit_string_literal_range ("01234\x35 789"
85                                     ~^~~~~~~
86    { dg-end-multiline-output "" } */
87 }
88 
89 void
test_oct(void)90 test_oct (void)
91 {
92   /* Digits 0-9, expressing digit 5 in ASCII as "\065"
93      and with a space in place of digit 6, to terminate the escaped
94      octal code.  */
95   __emit_string_literal_range ("01234\065 789", /* { dg-warning "range" } */
96 			       4, 3, 7);
97 /* { dg-begin-multiline-output "" }
98    __emit_string_literal_range ("01234\065 789"
99                                     ~^~~~~~~
100    { dg-end-multiline-output "" } */
101 }
102 
103 void
test_multiple(void)104 test_multiple (void)
105 {
106   /* Digits 0-9, expressing digit 5 in ASCII as hex "\x35"
107      digit 6 in ASCII as octal "\066", concatenating multiple strings.  */
108   __emit_string_literal_range ("01234"  "\x35"  "\066"  "789", /* { dg-warning "range" } */
109 			       5, 3, 8);
110 /* { dg-begin-multiline-output "" }
111    __emit_string_literal_range ("01234"  "\x35"  "\066"  "789",
112                                     ~~~~~~^~~~~~~~~~~~~~~~~~
113    { dg-end-multiline-output "" } */
114 }
115 
116 void
test_ucn4(void)117 test_ucn4 (void)
118 {
119   /* Digits 0-9, expressing digits 5 and 6 as Roman numerals expressed
120      as UCN 4.
121      The resulting string is encoded as UTF-8.  Most of the digits are 1 byte
122      each, but digits 5 and 6 are encoded with 3 bytes each.
123      Hence to underline digits 4-7 we need to underling using bytes 4-11 in
124      the UTF-8 encoding.  */
125   __emit_string_literal_range ("01234\u2174\u2175789", /* { dg-warning "range" } */
126 			       5, 4, 11);
127 /* { dg-begin-multiline-output "" }
128    __emit_string_literal_range ("01234\u2174\u2175789",
129                                      ~^~~~~~~~~~~~~
130    { dg-end-multiline-output "" } */
131 }
132 
133 void
test_ucn8(void)134 test_ucn8 (void)
135 {
136   /* Digits 0-9, expressing digits 5 and 6 as Roman numerals as UCN 8.
137      The resulting string is the same as as in test_ucn4 above, and hence
138      has the same UTF-8 encoding, and so we again need to underline bytes
139      4-11 in the UTF-8 encoding in order to underline digits 4-7.  */
140   __emit_string_literal_range ("01234\U00002174\U00002175789", /* { dg-warning "range" } */
141 			       5, 4, 11);
142 /* { dg-begin-multiline-output "" }
143    __emit_string_literal_range ("01234\U00002174\U00002175789",
144                                      ~^~~~~~~~~~~~~~~~~~~~~
145    { dg-end-multiline-output "" } */
146 }
147 
148 void
test_u8(void)149 test_u8 (void)
150 {
151   /* Digits 0-9.  */
152   __emit_string_literal_range (u8"0123456789", /* { dg-warning "range" } */
153 			       6, 4, 7);
154 /* { dg-begin-multiline-output "" }
155    __emit_string_literal_range (u8"0123456789",
156                                        ~~^~
157    { dg-end-multiline-output "" } */
158 }
159 
160 void
test_u(void)161 test_u (void)
162 {
163   /* Digits 0-9.  */
164   __emit_string_literal_range (u"0123456789", /* { dg-error "unable to read substring location: execution character set != source character set" } */
165 			       6, 4, 7);
166 /* { dg-begin-multiline-output "" }
167    __emit_string_literal_range (u"0123456789",
168                                 ^~~~~~~~~~~~~
169    { dg-end-multiline-output "" } */
170 }
171 
172 void
test_U(void)173 test_U (void)
174 {
175   /* Digits 0-9.  */
176   __emit_string_literal_range (U"0123456789", /* { dg-error "unable to read substring location: execution character set != source character set" } */
177 			       6, 4, 7);
178 /* { dg-begin-multiline-output "" }
179    __emit_string_literal_range (U"0123456789",
180                                 ^~~~~~~~~~~~~
181    { dg-end-multiline-output "" } */
182 }
183 
184 void
test_L(void)185 test_L (void)
186 {
187   /* Digits 0-9.  */
188   __emit_string_literal_range (L"0123456789", /* { dg-error "unable to read substring location: execution character set != source character set" } */
189 			       6, 4, 7);
190 /* { dg-begin-multiline-output "" }
191    __emit_string_literal_range (L"0123456789",
192                                 ^~~~~~~~~~~~~
193    { dg-end-multiline-output "" } */
194 }
195 
196 void
test_raw_string_one_liner(void)197 test_raw_string_one_liner (void)
198 {
199   /* Digits 0-9.  */
200   __emit_string_literal_range (R"foo(0123456789)foo", /* { dg-warning "range" } */
201 			       6, 4, 7);
202 /* { dg-begin-multiline-output "" }
203    __emit_string_literal_range (R"foo(0123456789)foo",
204                                           ~~^~
205    { dg-end-multiline-output "" } */
206 }
207 
208 void
test_raw_string_multiline(void)209 test_raw_string_multiline (void)
210 {
211   __emit_string_literal_range (R"foo(
212 hello
213 world
214 )foo",
215 			       6, 4, 7);
216   /* { dg-error "unable to read substring location: range endpoints are on different lines" "" { target *-*-* } .-5 } */
217   /* { dg-begin-multiline-output "" }
218    __emit_string_literal_range (R"foo(
219                                 ^~~~~~
220  hello
221  ~~~~~
222  world
223  ~~~~~
224  )foo",
225  ~~~~~
226    { dg-end-multiline-output "" } */
227 }
228 
229 void
test_macro(void)230 test_macro (void)
231 {
232 #define START "01234"  /* { dg-warning "range" } */
233   __emit_string_literal_range (START
234                                "56789",
235                                4, 3, 6);
236 /* { dg-begin-multiline-output "" }
237  #define START "01234"
238                    ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
239    __emit_string_literal_range (START
240    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241                                 "56789",
242                                 ~~~
243    { dg-end-multiline-output "" } */
244 }
245 
246 void
test_multitoken_macro(void)247 test_multitoken_macro (void)
248 {
249 #define RANGE ("0123456789")  /* { dg-error "unable to read substring location: macro expansion" } */
250   __emit_string_literal_range (RANGE, 4, 3, 6);
251 /* { dg-begin-multiline-output "" }
252  #define RANGE ("0123456789")
253                ^~~~~~~~~~~~~~
254    { dg-end-multiline-output "" { target c } } */
255 /* { dg-begin-multiline-output "" }
256  #define RANGE ("0123456789")
257                ~^~~~~~~~~~~~~
258    { dg-end-multiline-output "" { target c++ } } */
259 /* { dg-begin-multiline-output "" }
260    __emit_string_literal_range (RANGE, 4, 3, 6);
261                                 ^~~~~
262    { dg-end-multiline-output "" } */
263 #undef RANGE
264 }
265 
266 /* Verify that the location of the closing quote is used
267    for the location of the null terminating character.  */
268 
269 void
test_terminator_location(void)270 test_terminator_location (void)
271 {
272   __emit_string_literal_range ("0123456789", /* { dg-warning "range" } */
273 			       10, 10, 10);
274 /* { dg-begin-multiline-output "" }
275    __emit_string_literal_range ("0123456789",
276                                            ^
277    { dg-end-multiline-output "" } */
278 }
279 
280 /* Verify that we fail gracefully when a string literal token is split
281    across multiple physical lines.  */
282 
283 void
test_backslash_continued_logical_lines(void)284 test_backslash_continued_logical_lines (void)
285 {
286   __emit_string_literal_range ("\
287 01234\
288 56789", 6, 6, 7);
289   /* { dg-error "unable to read substring location: range endpoints are on different lines" "" { target *-*-* } .-3 } */
290   /* { dg-begin-multiline-output "" }
291    __emit_string_literal_range ("\
292                                 ^~
293  01234\
294  ~~~~~~
295  56789", 6, 6, 7);
296  ~~~~~~
297    { dg-end-multiline-output "" } */
298 }
299 
300 /* Reproducer for PR 87652; this is whitespace-sensitive.  */
301 
302 #include "pr87562-a.h"
303 
304 
305 
306 
307 #include "pr87562-b.h"
308 
309 void
pr87652(const char * stem,int counter)310 pr87652 (const char *stem, int counter)
311 {
312   char label[100];
313   ASM_GENERATE_INTERNAL_LABEL (label, stem, counter);
314 
315   /* This warning is actually in "pr87562-a.h".  */
316   /* { dg-warning "39: range" "" { target *-*-* } 5 } */
317   /* { dg-begin-multiline-output "" }
318        __emit_string_literal_range ("*.%s%u", 2, 2, 3); \
319                                        ^~
320      { dg-end-multiline-output "" } */
321 }
322 
323 /* Reproducer for PR 87721.  */
324 
325 # define OFFSET __builtin_strlen (__FILE__) + __builtin_strlen(":%5d: ")
326 
327 # define DBG_ERROR(format, caret_idx, start_idx, end_idx)	\
328   do {								\
329     __emit_string_literal_range(__FILE__":%5d: " format,	\
330 				OFFSET + caret_idx,		\
331 				OFFSET + start_idx,		\
332 				OFFSET + end_idx);		\
333   } while (0)
334 
335 /* { dg-error "unable to read substring location: unable to read source line" "" { target c } 329 } */
336 /* { dg-error "unable to read substring location: failed to get ordinary maps" "" { target c++ } 329 } */
337 /* { dg-begin-multiline-output "" }
338      __emit_string_literal_range(__FILE__":%5d: " format, \
339                                  ^~~~~~~~
340      { dg-end-multiline-output "" { target c } } */
341 /* { dg-begin-multiline-output "" }
342      __emit_string_literal_range(__FILE__":%5d: " format, \
343                                  ^
344      { dg-end-multiline-output "" { target c++ } } */
345 
pr87721(void)346 void pr87721 (void) {
347   DBG_ERROR("Bad password, expected [%s], got [%s].", 24, 24, 25); /* { dg-message "in expansion of macro 'DBG_ERROR'" } */
348   /* { dg-begin-multiline-output "" }
349    DBG_ERROR("Bad password, expected [%s], got [%s].", 24, 24, 25);
350    ^~~~~~~~~
351      { dg-end-multiline-output "" } */
352 }
353