Branch data Line data Source code
1 : : /* Check calls to formatted I/O functions (-Wformat).
2 : : Copyright (C) 1992-2024 Free Software Foundation, Inc.
3 : :
4 : : This file is part of GCC.
5 : :
6 : : GCC is free software; you can redistribute it and/or modify it under
7 : : the terms of the GNU General Public License as published by the Free
8 : : Software Foundation; either version 3, or (at your option) any later
9 : : version.
10 : :
11 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : : for more details.
15 : :
16 : : You should have received a copy of the GNU General Public License
17 : : along with GCC; see the file COPYING3. If not see
18 : : <http://www.gnu.org/licenses/>. */
19 : :
20 : : #include "config.h"
21 : : #include "system.h"
22 : : #include "coretypes.h"
23 : : #include "tm.h"
24 : : #include "c-target.h"
25 : : #include "c-common.h"
26 : : #include "alloc-pool.h"
27 : : #include "stringpool.h"
28 : : #include "c-objc.h"
29 : : #include "intl.h"
30 : : #include "langhooks.h"
31 : : #include "c-format.h"
32 : : #include "diagnostic.h"
33 : : #include "substring-locations.h"
34 : : #include "selftest.h"
35 : : #include "selftest-diagnostic.h"
36 : : #include "builtins.h"
37 : : #include "attribs.h"
38 : : #include "gcc-rich-location.h"
39 : :
40 : : /* Handle attributes associated with format checking. */
41 : :
42 : : /* This must be in the same order as format_types, except for
43 : : format_type_error. Target-specific format types do not have
44 : : matching enum values. */
45 : : enum format_type { printf_format_type, asm_fprintf_format_type,
46 : : gcc_diag_format_type, gcc_tdiag_format_type,
47 : : gcc_cdiag_format_type,
48 : : gcc_cxxdiag_format_type, gcc_gfc_format_type,
49 : : gcc_dump_printf_format_type,
50 : : gcc_objc_string_format_type,
51 : : format_type_error = -1};
52 : :
53 : : struct function_format_info
54 : : {
55 : : enum format_type format_type; /* type of format (printf, scanf, etc.) */
56 : : /* IS_RAW is relevant only for GCC diagnostic format functions.
57 : : It is set for "raw" formatting functions like pp_printf that
58 : : are not intended to produce complete diagnostics according to
59 : : GCC guidelines, and clear for others like error and warning
60 : : whose format string is checked for proper quoting and spelling. */
61 : : bool is_raw;
62 : : unsigned HOST_WIDE_INT format_num; /* number of format argument */
63 : : unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */
64 : : };
65 : :
66 : : /* Initialized in init_dynamic_diag_info. */
67 : : static GTY(()) tree local_tree_type_node;
68 : : static GTY(()) tree local_event_ptr_node;
69 : : static GTY(()) tree local_gimple_ptr_node;
70 : : static GTY(()) tree local_cgraph_node_ptr_node;
71 : : static GTY(()) tree locus;
72 : :
73 : : static bool decode_format_attr (const_tree, tree, tree, function_format_info *,
74 : : bool);
75 : : static format_type decode_format_type (const char *, bool * = NULL);
76 : :
77 : : static bool check_format_string (const_tree argument,
78 : : unsigned HOST_WIDE_INT format_num,
79 : : int flags, bool *no_add_attrs,
80 : : int expected_format_type);
81 : : static bool validate_constant (const_tree fn, const_tree atname, tree &expr,
82 : : int argno, unsigned HOST_WIDE_INT *value,
83 : : int flags, bool validated_p);
84 : : static const char *convert_format_name_to_system_name (const char *attr_name);
85 : :
86 : : static int first_target_format_type;
87 : : static const char *format_name (int format_num);
88 : : static int format_flags (int format_num);
89 : :
90 : : /* Emit a warning as per format_warning_va, but construct the substring_loc
91 : : for the character at offset (CHAR_IDX - 1) within a string constant
92 : : FORMAT_STRING_CST at FMT_STRING_LOC. */
93 : :
94 : : ATTRIBUTE_GCC_DIAG (5,6)
95 : : static bool
96 : 2509 : format_warning_at_char (location_t fmt_string_loc, tree format_string_cst,
97 : : int char_idx, int opt, const char *gmsgid, ...)
98 : : {
99 : 2509 : va_list ap;
100 : 2509 : va_start (ap, gmsgid);
101 : 2509 : tree string_type = TREE_TYPE (format_string_cst);
102 : :
103 : : /* The callers are of the form:
104 : : format_warning (format_string_loc, format_string_cst,
105 : : format_chars - orig_format_chars,
106 : : where format_chars has already been incremented, so that
107 : : CHAR_IDX is one character beyond where the warning should
108 : : be emitted. Fix it. */
109 : 2509 : char_idx -= 1;
110 : :
111 : 2509 : substring_loc fmt_loc (fmt_string_loc, string_type, char_idx, char_idx,
112 : 2509 : char_idx);
113 : 2509 : format_string_diagnostic_t diag (fmt_loc, NULL, UNKNOWN_LOCATION, NULL,
114 : 2509 : NULL);
115 : 2509 : bool warned = diag.emit_warning_va (opt, gmsgid, &ap);
116 : 2509 : va_end (ap);
117 : :
118 : 2509 : return warned;
119 : : }
120 : :
121 : :
122 : : /* Emit a warning as per format_warning_va, but construct the substring_loc
123 : : for the substring at offset (POS1, POS2 - 1) within a string constant
124 : : FORMAT_STRING_CST at FMT_STRING_LOC. */
125 : :
126 : : ATTRIBUTE_GCC_DIAG (6,7)
127 : : static bool
128 : 334 : format_warning_substr (location_t fmt_string_loc, tree format_string_cst,
129 : : int pos1, int pos2, int opt, const char *gmsgid, ...)
130 : : {
131 : 334 : va_list ap;
132 : 334 : va_start (ap, gmsgid);
133 : 334 : tree string_type = TREE_TYPE (format_string_cst);
134 : :
135 : 334 : pos2 -= 1;
136 : :
137 : 334 : substring_loc fmt_loc (fmt_string_loc, string_type, pos1, pos1, pos2);
138 : 334 : format_string_diagnostic_t diag (fmt_loc, NULL, UNKNOWN_LOCATION, NULL,
139 : 334 : NULL);
140 : 334 : bool warned = diag.emit_warning_va (opt, gmsgid, &ap);
141 : 334 : va_end (ap);
142 : :
143 : 334 : return warned;
144 : : }
145 : :
146 : :
147 : : /* Check that we have a pointer to a string suitable for use as a format.
148 : : The default is to check for a char type.
149 : : For objective-c dialects, this is extended to include references to string
150 : : objects validated by objc_string_ref_type_p ().
151 : : Targets may also provide a string object type that can be used within c and
152 : : c++ and shared with their respective objective-c dialects. In this case the
153 : : reference to a format string is checked for validity via a hook.
154 : :
155 : : The function returns true if strref points to any string type valid for the
156 : : language dialect and target. */
157 : :
158 : : bool
159 : 24254505 : valid_format_string_type_p (tree strref)
160 : : {
161 : 24254505 : return (strref != NULL
162 : 24254505 : && TREE_CODE (strref) == POINTER_TYPE
163 : 48508996 : && (TYPE_MAIN_VARIANT (TREE_TYPE (strref)) == char_type_node
164 : 18 : || objc_string_ref_type_p (strref)
165 : 18 : || (*targetcm.string_object_ref_type_p) ((const_tree) strref)));
166 : : }
167 : :
168 : : /* Handle a "format_arg" attribute; arguments as in
169 : : struct attribute_spec.handler. */
170 : : tree
171 : 1169444 : handle_format_arg_attribute (tree *node, tree atname,
172 : : tree args, int flags, bool *no_add_attrs)
173 : : {
174 : 1169444 : tree type = *node;
175 : : /* Note that TREE_VALUE (args) is changed in the validate_constant call. */
176 : 1169444 : tree *format_num_expr = &TREE_VALUE (args);
177 : 1169444 : unsigned HOST_WIDE_INT format_num = 0;
178 : :
179 : 1169444 : if (!validate_constant (type, atname, *format_num_expr, 0, &format_num, 0,
180 : : false))
181 : : {
182 : 8 : *no_add_attrs = true;
183 : 8 : return NULL_TREE;
184 : : }
185 : :
186 : 1169436 : if (prototype_p (type))
187 : : {
188 : : /* The format arg can be any string reference valid for the language and
189 : : target. We cannot be more specific in this case. */
190 : 1169436 : if (!check_format_string (type, format_num, flags, no_add_attrs, -1))
191 : : return NULL_TREE;
192 : : }
193 : :
194 : 1169436 : if (!valid_format_string_type_p (TREE_TYPE (type)))
195 : : {
196 : 6 : if (!(flags & (int) ATTR_FLAG_BUILT_IN))
197 : 6 : error ("function does not return string type");
198 : 6 : *no_add_attrs = true;
199 : 6 : return NULL_TREE;
200 : : }
201 : :
202 : : return NULL_TREE;
203 : : }
204 : :
205 : : /* Verify that the format_num argument is actually a string reference suitable,
206 : : for the language dialect and target (in case the format attribute is in
207 : : error). When we know the specific reference type expected, this is also
208 : : checked. */
209 : : static bool
210 : 11517179 : check_format_string (const_tree fntype, unsigned HOST_WIDE_INT format_num,
211 : : int flags, bool *no_add_attrs, int expected_format_type)
212 : : {
213 : 11517179 : unsigned HOST_WIDE_INT i;
214 : 11517179 : bool is_objc_sref, is_target_sref, is_char_ref;
215 : 11517179 : tree ref;
216 : 11517179 : int fmt_flags;
217 : 11517179 : function_args_iterator iter;
218 : :
219 : 11517179 : i = 1;
220 : 26471379 : FOREACH_FUNCTION_ARGS (fntype, ref, iter)
221 : : {
222 : 26471379 : if (i == format_num)
223 : : break;
224 : 14954200 : i++;
225 : : }
226 : :
227 : 11517179 : if (!ref
228 : 11517179 : || !valid_format_string_type_p (ref))
229 : : {
230 : 0 : if (!(flags & (int) ATTR_FLAG_BUILT_IN))
231 : 0 : error ("format string argument is not a string type");
232 : 0 : *no_add_attrs = true;
233 : 0 : return false;
234 : : }
235 : :
236 : : /* We only know that we want a suitable string reference. */
237 : 11517179 : if (expected_format_type < 0)
238 : : return true;
239 : :
240 : : /* Now check that the arg matches the expected type. */
241 : 20695486 : is_char_ref =
242 : 10347743 : (TYPE_MAIN_VARIANT (TREE_TYPE (ref)) == char_type_node);
243 : :
244 : 10347743 : fmt_flags = format_flags (expected_format_type);
245 : 10347743 : is_objc_sref = is_target_sref = false;
246 : 10347743 : if (!is_char_ref)
247 : 0 : is_objc_sref = objc_string_ref_type_p (ref);
248 : :
249 : 10347743 : if (!(fmt_flags & FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL))
250 : : {
251 : 10347743 : if (is_char_ref)
252 : : return true; /* OK, we expected a char and found one. */
253 : : else
254 : : {
255 : : /* We expected a char but found an extended string type. */
256 : 0 : if (is_objc_sref)
257 : 0 : error ("found a %qs reference but the format argument should"
258 : : " be a string", format_name (gcc_objc_string_format_type));
259 : : else
260 : 0 : error ("found a %qT but the format argument should be a string",
261 : : ref);
262 : 0 : *no_add_attrs = true;
263 : 0 : return false;
264 : : }
265 : : }
266 : :
267 : : /* We expect a string object type as the format arg. */
268 : 0 : if (is_char_ref)
269 : : {
270 : 0 : error ("format argument should be a %qs reference but"
271 : : " a string was found", format_name (expected_format_type));
272 : 0 : *no_add_attrs = true;
273 : 0 : return false;
274 : : }
275 : :
276 : : /* We will assert that objective-c will support either its own string type
277 : : or the target-supplied variant. */
278 : 0 : if (!is_objc_sref)
279 : 0 : is_target_sref = (*targetcm.string_object_ref_type_p) ((const_tree) ref);
280 : :
281 : 0 : if (expected_format_type == (int) gcc_objc_string_format_type
282 : 0 : && (is_objc_sref || is_target_sref))
283 : : return true;
284 : :
285 : : /* We will allow a target string ref to match only itself. */
286 : 0 : if (first_target_format_type
287 : 0 : && expected_format_type >= first_target_format_type
288 : 0 : && is_target_sref)
289 : : return true;
290 : : else
291 : : {
292 : 0 : error ("format argument should be a %qs reference",
293 : : format_name (expected_format_type));
294 : 0 : *no_add_attrs = true;
295 : 0 : return false;
296 : : }
297 : : }
298 : :
299 : : /* Under the control of FLAGS, verify EXPR is a valid constant that
300 : : refers to a positional argument ARGNO having a string type (char*
301 : : or, for targets like Darwin, a pointer to struct CFString) to
302 : : a function FN declared with attribute ATNAME. If valid, store the
303 : : constant's integer value in *VALUE and return true. If VALIDATED_P
304 : : is true assert the validation is successful.
305 : :
306 : : N.B. This function modifies EXPR. */
307 : :
308 : : static bool
309 : 21966454 : validate_constant (const_tree fn, const_tree atname, tree &expr, int argno,
310 : : unsigned HOST_WIDE_INT *value, int flags, bool validated_p)
311 : : {
312 : : /* Require the referenced argument to have a string type. For targets
313 : : like Darwin, also accept pointers to struct CFString. */
314 : 21966454 : if (tree val = positional_argument (fn, atname, expr, STRING_CST,
315 : : argno, flags))
316 : : {
317 : 21966408 : *value = TREE_INT_CST_LOW (val);
318 : 21966408 : return true;
319 : : }
320 : :
321 : 46 : gcc_assert (!validated_p);
322 : : return false;
323 : : }
324 : :
325 : : /* Decode the arguments to a "format" attribute into a
326 : : function_format_info structure. It is already known that the list
327 : : is of the right length. If VALIDATED_P is true, then these
328 : : attributes have already been validated and must not be erroneous;
329 : : if false, it will give an error message. FN is either a function
330 : : declaration or function type. Returns true if the attributes are
331 : : successfully decoded, false otherwise. */
332 : :
333 : : static bool
334 : 10398528 : decode_format_attr (const_tree fn, tree atname, tree args,
335 : : function_format_info *info, bool validated_p)
336 : : {
337 : 10398528 : tree format_type_id = TREE_VALUE (args);
338 : : /* Note that TREE_VALUE (args) is changed in place below. Ditto
339 : : for the value of the next element on the list. */
340 : 10398528 : tree *format_num_expr = &TREE_VALUE (TREE_CHAIN (args));
341 : 10398528 : tree *first_arg_num_expr = &TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
342 : :
343 : 10398528 : if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
344 : : {
345 : 2 : gcc_assert (!validated_p);
346 : 2 : error ("unrecognized format specifier");
347 : 2 : return false;
348 : : }
349 : : else
350 : : {
351 : 10398526 : const char *p = IDENTIFIER_POINTER (format_type_id);
352 : :
353 : 10398526 : info->format_type = decode_format_type (p, &info->is_raw);
354 : :
355 : 10398526 : if (!c_dialect_objc ()
356 : 10398526 : && info->format_type == gcc_objc_string_format_type)
357 : : {
358 : 2 : gcc_assert (!validated_p);
359 : 2 : warning (OPT_Wformat_, "%qE is only allowed in Objective-C dialects",
360 : : format_type_id);
361 : 2 : info->format_type = format_type_error;
362 : 2 : return false;
363 : : }
364 : :
365 : 10398524 : if (info->format_type == format_type_error)
366 : : {
367 : 2 : gcc_assert (!validated_p);
368 : 2 : warning (OPT_Wformat_, "%qE is an unrecognized format function type",
369 : : format_type_id);
370 : 2 : return false;
371 : : }
372 : : }
373 : :
374 : 10398522 : if (!validate_constant (fn, atname, *format_num_expr, 2, &info->format_num,
375 : : 0, validated_p))
376 : : return false;
377 : :
378 : 10398488 : if (!validate_constant (fn, atname, *first_arg_num_expr, 3,
379 : : &info->first_arg_num,
380 : : (POSARG_ZERO | POSARG_ELLIPSIS), validated_p))
381 : : return false;
382 : :
383 : 10398484 : if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num)
384 : : {
385 : 4 : gcc_assert (!validated_p);
386 : 4 : error ("format string argument follows the arguments to be formatted");
387 : 4 : return false;
388 : : }
389 : :
390 : : return true;
391 : : }
392 : :
393 : : /* Check a call to a format function against a parameter list. */
394 : :
395 : : /* The C standard version C++ is treated as equivalent to
396 : : or inheriting from, for the purpose of format features supported. */
397 : : #define CPLUSPLUS_STD_VER (cxx_dialect < cxx11 ? STD_C94 : STD_C99)
398 : : /* The C standard version we are checking formats against when pedantic. */
399 : : #define C_STD_VER ((int) (c_dialect_cxx () \
400 : : ? CPLUSPLUS_STD_VER \
401 : : : (flag_isoc23 \
402 : : ? STD_C23 \
403 : : : (flag_isoc99 \
404 : : ? STD_C99 \
405 : : : (flag_isoc94 ? STD_C94 : STD_C89)))))
406 : : /* The name to give to the standard version we are warning about when
407 : : pedantic. FEATURE_VER is the version in which the feature warned out
408 : : appeared, which is higher than C_STD_VER. */
409 : : #define C_STD_NAME(FEATURE_VER) (c_dialect_cxx () \
410 : : ? (cxx_dialect < cxx11 ? "ISO C++98" \
411 : : : "ISO C++11") \
412 : : : ((FEATURE_VER) == STD_EXT \
413 : : ? "ISO C" \
414 : : : ((FEATURE_VER) == STD_C23 \
415 : : ? "ISO C17" \
416 : : : "ISO C90")))
417 : : /* Adjust a C standard version, which may be STD_C9L, to account for
418 : : -Wno-long-long. Returns other standard versions unchanged. */
419 : : #define ADJ_STD(VER) ((int) ((VER) == STD_C9L \
420 : : ? (warn_long_long ? STD_C99 : STD_C89) \
421 : : : (VER)))
422 : :
423 : : /* Enum describing the kind of specifiers present in the format and
424 : : requiring an argument. */
425 : : enum format_specifier_kind {
426 : : CF_KIND_FORMAT,
427 : : CF_KIND_FIELD_WIDTH,
428 : : CF_KIND_FIELD_PRECISION
429 : : };
430 : :
431 : : static const char *kind_descriptions[] = {
432 : : N_("format"),
433 : : N_("field width specifier"),
434 : : N_("field precision specifier")
435 : : };
436 : :
437 : : /* Structure describing details of a type expected in format checking,
438 : : and the type to check against it. */
439 : : struct format_wanted_type
440 : : {
441 : : /* The type wanted. */
442 : : tree wanted_type;
443 : : /* The name of this type to use in diagnostics. */
444 : : const char *wanted_type_name;
445 : : /* Should be type checked just for scalar width identity. */
446 : : int scalar_identity_flag;
447 : : /* The level of indirection through pointers at which this type occurs. */
448 : : int pointer_count;
449 : : /* Whether, when pointer_count is 1, to allow any character type when
450 : : pedantic, rather than just the character or void type specified. */
451 : : int char_lenient_flag;
452 : : /* Whether the argument, dereferenced once, is written into and so the
453 : : argument must not be a pointer to a const-qualified type. */
454 : : int writing_in_flag;
455 : : /* Whether the argument, dereferenced once, is read from and so
456 : : must not be a NULL pointer. */
457 : : int reading_from_flag;
458 : : /* The kind of specifier that this type is used for. */
459 : : enum format_specifier_kind kind;
460 : : /* The starting character of the specifier. This never includes the
461 : : initial percent sign. */
462 : : const char *format_start;
463 : : /* The length of the specifier. */
464 : : int format_length;
465 : : /* The actual parameter to check against the wanted type. */
466 : : tree param;
467 : : /* The argument number of that parameter. */
468 : : int arg_num;
469 : : /* The offset location of this argument with respect to the format
470 : : string location. */
471 : : unsigned int offset_loc;
472 : : /* The next type to check for this format conversion, or NULL if none. */
473 : : struct format_wanted_type *next;
474 : : };
475 : :
476 : : /* Convenience macro for format_length_info meaning unused. */
477 : : #define NO_FMT NULL, FMT_LEN_none, STD_C89
478 : :
479 : : static const format_length_info printf_length_specs[] =
480 : : {
481 : : { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 },
482 : : { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 },
483 : : { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 },
484 : : { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 },
485 : : { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 },
486 : : { "Z", FMT_LEN_z, STD_EXT, NO_FMT, 0 },
487 : : { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 },
488 : : { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 },
489 : : { "H", FMT_LEN_H, STD_C23, NO_FMT, 0 },
490 : : { "D", FMT_LEN_D, STD_C23, "DD", FMT_LEN_DD, STD_C23, 0 },
491 : : { "w8", FMT_LEN_w8, STD_C23, NO_FMT, 0 },
492 : : { "w16", FMT_LEN_w16, STD_C23, NO_FMT, 0 },
493 : : { "w32", FMT_LEN_w32, STD_C23, NO_FMT, 0 },
494 : : { "w64", FMT_LEN_w64, STD_C23, NO_FMT, 0 },
495 : : { "wf8", FMT_LEN_wf8, STD_C23, NO_FMT, 0 },
496 : : { "wf16", FMT_LEN_wf16, STD_C23, NO_FMT, 0 },
497 : : { "wf32", FMT_LEN_wf32, STD_C23, NO_FMT, 0 },
498 : : { "wf64", FMT_LEN_wf64, STD_C23, NO_FMT, 0 },
499 : : { NO_FMT, NO_FMT, 0 }
500 : : };
501 : :
502 : : /* Length specifiers valid for asm_fprintf. */
503 : : static const format_length_info asm_fprintf_length_specs[] =
504 : : {
505 : : { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 },
506 : : { "w", FMT_LEN_w, STD_C89, NO_FMT, 0 },
507 : : { NO_FMT, NO_FMT, 0 }
508 : : };
509 : :
510 : : /* Length specifiers valid for GCC diagnostics. */
511 : : static const format_length_info gcc_diag_length_specs[] =
512 : : {
513 : : { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 },
514 : : { "w", FMT_LEN_w, STD_C89, NO_FMT, 0 },
515 : : { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 },
516 : : { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 },
517 : : { NO_FMT, NO_FMT, 0 }
518 : : };
519 : :
520 : : /* The custom diagnostics all accept the same length specifiers. */
521 : : #define gcc_tdiag_length_specs gcc_diag_length_specs
522 : : #define gcc_cdiag_length_specs gcc_diag_length_specs
523 : : #define gcc_cxxdiag_length_specs gcc_diag_length_specs
524 : : #define gcc_dump_printf_length_specs gcc_diag_length_specs
525 : :
526 : : /* This differs from printf_length_specs only in that "Z" is not accepted. */
527 : : static const format_length_info scanf_length_specs[] =
528 : : {
529 : : { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 },
530 : : { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 },
531 : : { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 },
532 : : { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 },
533 : : { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 },
534 : : { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 },
535 : : { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 },
536 : : { "H", FMT_LEN_H, STD_C23, NO_FMT, 0 },
537 : : { "D", FMT_LEN_D, STD_C23, "DD", FMT_LEN_DD, STD_C23, 0 },
538 : : { "w8", FMT_LEN_w8, STD_C23, NO_FMT, 0 },
539 : : { "w16", FMT_LEN_w16, STD_C23, NO_FMT, 0 },
540 : : { "w32", FMT_LEN_w32, STD_C23, NO_FMT, 0 },
541 : : { "w64", FMT_LEN_w64, STD_C23, NO_FMT, 0 },
542 : : { "wf8", FMT_LEN_wf8, STD_C23, NO_FMT, 0 },
543 : : { "wf16", FMT_LEN_wf16, STD_C23, NO_FMT, 0 },
544 : : { "wf32", FMT_LEN_wf32, STD_C23, NO_FMT, 0 },
545 : : { "wf64", FMT_LEN_wf64, STD_C23, NO_FMT, 0 },
546 : : { NO_FMT, NO_FMT, 0 }
547 : : };
548 : :
549 : :
550 : : /* All tables for strfmon use STD_C89 everywhere, since -pedantic warnings
551 : : make no sense for a format type not part of any C standard version. */
552 : : static const format_length_info strfmon_length_specs[] =
553 : : {
554 : : /* A GNU extension. */
555 : : { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 },
556 : : { NO_FMT, NO_FMT, 0 }
557 : : };
558 : :
559 : :
560 : : /* Length modifiers used by the fortran/error.cc routines. */
561 : : static const format_length_info gcc_gfc_length_specs[] =
562 : : {
563 : : { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 },
564 : : { "w", FMT_LEN_w, STD_C89, NO_FMT, 0 },
565 : : { NO_FMT, NO_FMT, 0 }
566 : : };
567 : :
568 : :
569 : : static const format_flag_spec printf_flag_specs[] =
570 : : {
571 : : { ' ', 0, 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 },
572 : : { '+', 0, 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
573 : : { '#', 0, 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
574 : : { '0', 0, 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 },
575 : : { '-', 0, 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 },
576 : : { '\'', 0, 0, 0, N_("''' flag"), N_("the ''' printf flag"), STD_EXT },
577 : : { 'I', 0, 0, 0, N_("'I' flag"), N_("the 'I' printf flag"), STD_EXT },
578 : : { 'w', 0, 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
579 : : { 'p', 0, 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
580 : : { 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
581 : : { 0, 0, 0, 0, NULL, NULL, STD_C89 }
582 : : };
583 : :
584 : :
585 : : static const format_flag_pair printf_flag_pairs[] =
586 : : {
587 : : { ' ', '+', 1, 0 },
588 : : { '0', '-', 1, 0 },
589 : : { '0', 'p', 1, 'i' },
590 : : { 0, 0, 0, 0 }
591 : : };
592 : :
593 : : static const format_flag_spec asm_fprintf_flag_specs[] =
594 : : {
595 : : { ' ', 0, 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 },
596 : : { '+', 0, 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
597 : : { '#', 0, 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
598 : : { '0', 0, 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 },
599 : : { '-', 0, 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 },
600 : : { 'w', 0, 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
601 : : { 'p', 0, 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
602 : : { 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
603 : : { 0, 0, 0, 0, NULL, NULL, STD_C89 }
604 : : };
605 : :
606 : : static const format_flag_pair asm_fprintf_flag_pairs[] =
607 : : {
608 : : { ' ', '+', 1, 0 },
609 : : { '0', '-', 1, 0 },
610 : : { '0', 'p', 1, 'i' },
611 : : { 0, 0, 0, 0 }
612 : : };
613 : :
614 : : static const format_flag_pair gcc_diag_flag_pairs[] =
615 : : {
616 : : { 0, 0, 0, 0 }
617 : : };
618 : :
619 : : #define gcc_tdiag_flag_pairs gcc_diag_flag_pairs
620 : : #define gcc_cdiag_flag_pairs gcc_diag_flag_pairs
621 : : #define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs
622 : : #define gcc_gfc_flag_pairs gcc_diag_flag_pairs
623 : : #define gcc_dump_printf_flag_pairs gcc_diag_flag_pairs
624 : :
625 : : static const format_flag_spec gcc_diag_flag_specs[] =
626 : : {
627 : : { '+', 0, 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 },
628 : : { '#', 0, 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 },
629 : : { 'q', 0, 0, 1, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 },
630 : : { 'p', 0, 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
631 : : { 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
632 : : { 0, 0, 0, 0, NULL, NULL, STD_C89 }
633 : : };
634 : :
635 : : #define gcc_tdiag_flag_specs gcc_diag_flag_specs
636 : : #define gcc_cdiag_flag_specs gcc_diag_flag_specs
637 : : #define gcc_cxxdiag_flag_specs gcc_diag_flag_specs
638 : : #define gcc_gfc_flag_specs gcc_diag_flag_specs
639 : : #define gcc_dump_printf_flag_specs gcc_diag_flag_specs
640 : :
641 : : static const format_flag_spec scanf_flag_specs[] =
642 : : {
643 : : { '*', 0, 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
644 : : { 'a', 0, 0, 0, N_("'a' flag"), N_("the 'a' scanf flag"), STD_EXT },
645 : : { 'm', 0, 0, 0, N_("'m' flag"), N_("the 'm' scanf flag"), STD_EXT },
646 : : { 'w', 0, 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 },
647 : : { 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 },
648 : : { '\'', 0, 0, 0, N_("''' flag"), N_("the ''' scanf flag"), STD_EXT },
649 : : { 'I', 0, 0, 0, N_("'I' flag"), N_("the 'I' scanf flag"), STD_EXT },
650 : : { 0, 0, 0, 0, NULL, NULL, STD_C89 }
651 : : };
652 : :
653 : :
654 : : static const format_flag_pair scanf_flag_pairs[] =
655 : : {
656 : : { '*', 'L', 0, 0 },
657 : : { 'a', 'm', 0, 0 },
658 : : { 0, 0, 0, 0 }
659 : : };
660 : :
661 : :
662 : : static const format_flag_spec strftime_flag_specs[] =
663 : : {
664 : : { '_', 0, 0, 0, N_("'_' flag"), N_("the '_' strftime flag"), STD_EXT },
665 : : { '-', 0, 0, 0, N_("'-' flag"), N_("the '-' strftime flag"), STD_EXT },
666 : : { '0', 0, 0, 0, N_("'0' flag"), N_("the '0' strftime flag"), STD_EXT },
667 : : { '^', 0, 0, 0, N_("'^' flag"), N_("the '^' strftime flag"), STD_EXT },
668 : : { '#', 0, 0, 0, N_("'#' flag"), N_("the '#' strftime flag"), STD_EXT },
669 : : { 'w', 0, 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT },
670 : : { 'E', 0, 0, 0, N_("'E' modifier"), N_("the 'E' strftime modifier"), STD_C99 },
671 : : { 'O', 0, 0, 0, N_("'O' modifier"), N_("the 'O' strftime modifier"), STD_C99 },
672 : : { 'O', 'o', 0, 0, NULL, N_("the 'O' modifier"), STD_EXT },
673 : : { 'O', 'p', 0, 0, NULL, N_("the 'O' modifier"), STD_C23 },
674 : : { 0, 0, 0, 0, NULL, NULL, STD_C89 }
675 : : };
676 : :
677 : :
678 : : static const format_flag_pair strftime_flag_pairs[] =
679 : : {
680 : : { 'E', 'O', 0, 0 },
681 : : { '_', '-', 0, 0 },
682 : : { '_', '0', 0, 0 },
683 : : { '-', '0', 0, 0 },
684 : : { '^', '#', 0, 0 },
685 : : { 0, 0, 0, 0 }
686 : : };
687 : :
688 : :
689 : : static const format_flag_spec strfmon_flag_specs[] =
690 : : {
691 : : { '=', 0, 1, 0, N_("fill character"), N_("fill character in strfmon format"), STD_C89 },
692 : : { '^', 0, 0, 0, N_("'^' flag"), N_("the '^' strfmon flag"), STD_C89 },
693 : : { '+', 0, 0, 0, N_("'+' flag"), N_("the '+' strfmon flag"), STD_C89 },
694 : : { '(', 0, 0, 0, N_("'(' flag"), N_("the '(' strfmon flag"), STD_C89 },
695 : : { '!', 0, 0, 0, N_("'!' flag"), N_("the '!' strfmon flag"), STD_C89 },
696 : : { '-', 0, 0, 0, N_("'-' flag"), N_("the '-' strfmon flag"), STD_C89 },
697 : : { 'w', 0, 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 },
698 : : { '#', 0, 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 },
699 : : { 'p', 0, 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 },
700 : : { 'L', 0, 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 },
701 : : { 0, 0, 0, 0, NULL, NULL, STD_C89 }
702 : : };
703 : :
704 : : static const format_flag_pair strfmon_flag_pairs[] =
705 : : {
706 : : { '+', '(', 0, 0 },
707 : : { 0, 0, 0, 0 }
708 : : };
709 : :
710 : :
711 : : static const format_char_info print_char_table[] =
712 : : {
713 : : /* C89 conversion specifiers. */
714 : : { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN, T23_I8, T23_I16, T23_I32, T23_I64, T23_IF8, T23_IF16, T23_IF32, T23_IF64 }, "-wp0 +'I", "i", NULL },
715 : : { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN, T23_U8, T23_U16, T23_U32, T23_U64, T23_UF8, T23_UF16, T23_UF32, T23_UF64 }, "-wp0#", "i", NULL },
716 : : { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN, T23_U8, T23_U16, T23_U32, T23_U64, T23_UF8, T23_UF16, T23_UF32, T23_UF64 }, "-wp0'I", "i", NULL },
717 : : { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, T23_D32, T23_D64, T23_D128, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "", NULL },
718 : : { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, T23_D32, T23_D64, T23_D128, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#I", "", NULL },
719 : : { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL },
720 : : { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL },
721 : : { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c", NULL },
722 : : { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN, T23_I8, T23_I16, T23_I32, T23_I64, T23_IF8, T23_IF16, T23_IF32, T23_IF64 }, "", "W", NULL },
723 : : /* C99 conversion specifiers. */
724 : : { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, T23_D32, T23_D64, T23_D128, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "", NULL },
725 : : { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, T23_D32, T23_D64, T23_D128, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL },
726 : : /* C23 conversion specifiers. */
727 : : { "bB", 0, STD_C23, { T23_UI, T23_UC, T23_US, T23_UL, T23_ULL, TEX_ULL, T23_ST, T23_UPD, T23_UIM, BADLEN, BADLEN, BADLEN, T23_U8, T23_U16, T23_U32, T23_U64, T23_UF8, T23_UF16, T23_UF32, T23_UF64 }, "-wp0#", "i", NULL },
728 : : /* X/Open conversion specifiers. */
729 : : { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL },
730 : : { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL },
731 : : /* GNU conversion specifiers. */
732 : : { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL },
733 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
734 : : };
735 : :
736 : : static const format_char_info asm_fprintf_char_table[] =
737 : : {
738 : : /* C89 conversion specifiers. */
739 : : { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +", "i", NULL },
740 : : { "oxX", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL },
741 : : { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0", "i", NULL },
742 : : { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL },
743 : : { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL },
744 : :
745 : : /* asm_fprintf conversion specifiers. */
746 : : { "O", 0, STD_C89, NOARGUMENTS, "", "", NULL },
747 : : { "R", 0, STD_C89, NOARGUMENTS, "", "", NULL },
748 : : { "I", 0, STD_C89, NOARGUMENTS, "", "", NULL },
749 : : { "L", 0, STD_C89, NOARGUMENTS, "", "", NULL },
750 : : { "U", 0, STD_C89, NOARGUMENTS, "", "", NULL },
751 : : { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL },
752 : : { "z", 0, STD_C89, NOARGUMENTS, "", "", NULL },
753 : : { "@", 0, STD_C89, NOARGUMENTS, "", "", NULL },
754 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
755 : : };
756 : :
757 : : /* GCC-specific format_char_info arrays. */
758 : :
759 : : /* The conversion specifiers implemented within pp_format, and thus supported
760 : : by all pretty_printer instances within GCC. */
761 : :
762 : : #define PP_FORMAT_CHAR_TABLE \
763 : : { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, \
764 : : { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, T99_ST, T99_UPD, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, \
765 : : { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, T99_ST, T99_UPD, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, \
766 : : { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, \
767 : : { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, \
768 : : { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, \
769 : : { "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "//cR", NULL }, \
770 : : { "@", 1, STD_C89, { T_EVENT_PTR, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL }, \
771 : : { "<", 0, STD_C89, NOARGUMENTS, "", "<", NULL }, \
772 : : { ">", 0, STD_C89, NOARGUMENTS, "", ">", NULL }, \
773 : : { "'" , 0, STD_C89, NOARGUMENTS, "", "", NULL }, \
774 : : { "{", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL }, \
775 : : { "}", 0, STD_C89, NOARGUMENTS, "", "", NULL }, \
776 : : { "R", 0, STD_C89, NOARGUMENTS, "", "\\", NULL }, \
777 : : { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, \
778 : : { "Z", 1, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &gcc_diag_char_table[0] }
779 : :
780 : : static const format_char_info gcc_diag_char_table[] =
781 : : {
782 : : /* The conversion specifiers implemented within pp_format. */
783 : : PP_FORMAT_CHAR_TABLE,
784 : :
785 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
786 : : };
787 : :
788 : : static const format_char_info gcc_tdiag_char_table[] =
789 : : {
790 : : /* The conversion specifiers implemented within pp_format. */
791 : : PP_FORMAT_CHAR_TABLE,
792 : :
793 : : /* Custom conversion specifiers implemented by default_tree_printer. */
794 : :
795 : : /* These will require a "tree" at runtime. */
796 : : { "DFTV", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "'", NULL },
797 : : { "E", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL },
798 : :
799 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
800 : : };
801 : :
802 : : static const format_char_info gcc_cdiag_char_table[] =
803 : : {
804 : : /* The conversion specifiers implemented within pp_format. */
805 : : PP_FORMAT_CHAR_TABLE,
806 : :
807 : : /* Custom conversion specifiers implemented by c_tree_printer. */
808 : :
809 : : /* These will require a "tree" at runtime. */
810 : : { "DFTV", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "'", NULL },
811 : : { "E", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL },
812 : :
813 : : { "v", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q#", "", NULL },
814 : :
815 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
816 : : };
817 : :
818 : : static const format_char_info gcc_cxxdiag_char_table[] =
819 : : {
820 : : /* The conversion specifiers implemented within pp_format. */
821 : : PP_FORMAT_CHAR_TABLE,
822 : :
823 : : /* Custom conversion specifiers implemented by cp_printer. */
824 : :
825 : : /* These will require a "tree" at runtime. */
826 : : { "ADFHISTVX",1,STD_C89,{ T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "'", NULL },
827 : : { "E", 1,STD_C89,{ T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL },
828 : :
829 : : /* These accept either an 'int' or an 'enum tree_code' (which is handled as an 'int'.) */
830 : : { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
831 : :
832 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
833 : : };
834 : :
835 : : static const format_char_info gcc_gfc_char_table[] =
836 : : {
837 : : /* C89 conversion specifiers. */
838 : : { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
839 : : { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, T99_ST, T99_UPD, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
840 : : { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL },
841 : : { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "cR", NULL },
842 : :
843 : : /* gfc conversion specifiers. */
844 : :
845 : : { "C", 0, STD_C89, NOARGUMENTS, "", "", NULL },
846 : :
847 : : /* This will require a "locus" at runtime. */
848 : : { "L", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "R", NULL },
849 : :
850 : : /* These will require nothing. */
851 : : { "<>",0, STD_C89, NOARGUMENTS, "", "", NULL },
852 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
853 : : };
854 : :
855 : : static const format_char_info gcc_dump_printf_char_table[] =
856 : : {
857 : : /* The conversion specifiers implemented within pp_format. */
858 : : PP_FORMAT_CHAR_TABLE,
859 : :
860 : : /* Custom conversion specifiers implemented by dump_pretty_printer. */
861 : :
862 : : /* E and G require a "gimple *" argument at runtime. */
863 : : { "EG", 1, STD_C89, { T89_G, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL },
864 : :
865 : : /* C requires a "cgraph_node *" argument at runtime. */
866 : : { "C", 1, STD_C89, { T_CGRAPH_NODE, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL },
867 : :
868 : : /* T requires a "tree" at runtime. */
869 : : { "T", 1, STD_C89, { T89_T, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL },
870 : :
871 : : /* %f requires a "double"; it doesn't support modifiers. */
872 : : { "f", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL },
873 : :
874 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
875 : : };
876 : :
877 : : static const format_char_info scan_char_table[] =
878 : : {
879 : : /* C89 conversion specifiers. */
880 : : { "di", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN, T23_I8, T23_I16, T23_I32, T23_I64, T23_IF8, T23_IF16, T23_IF32, T23_IF64 }, "*w'I", "W", NULL },
881 : : { "u", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN, T23_U8, T23_U16, T23_U32, T23_U64, T23_UF8, T23_UF16, T23_UF32, T23_UF64 }, "*w'I", "W", NULL },
882 : : { "oxX", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM, BADLEN, BADLEN, BADLEN, T23_U8, T23_U16, T23_U32, T23_U64, T23_UF8, T23_UF16, T23_UF32, T23_UF64 }, "*w", "W", NULL },
883 : : { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, T23_D32, T23_D64, T23_D128, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL },
884 : : { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*mw", "cW", NULL },
885 : : { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "cW", NULL },
886 : : { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "cW[", NULL },
887 : : { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL },
888 : : { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM, BADLEN, BADLEN, BADLEN, T23_I8, T23_I16, T23_I32, T23_I64, T23_IF8, T23_IF16, T23_IF32, T23_IF64 }, "", "W", NULL },
889 : : /* C99 conversion specifiers. */
890 : : { "F", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, T23_D32, T23_D64, T23_D128, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL },
891 : : { "aA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, T23_D32, T23_D64, T23_D128, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL },
892 : : /* C23 conversion specifiers. */
893 : : { "b", 1, STD_C23, { T23_UI, T23_UC, T23_US, T23_UL, T23_ULL, TEX_ULL, T23_ST, T23_UPD, T23_UIM, BADLEN, BADLEN, BADLEN, T23_U8, T23_U16, T23_U32, T23_U64, T23_UF8, T23_UF16, T23_UF32, T23_UF64 }, "*w", "W", NULL },
894 : : /* X/Open conversion specifiers. */
895 : : { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*mw", "W", NULL },
896 : : { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "W", NULL },
897 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
898 : : };
899 : :
900 : : static const format_char_info time_char_table[] =
901 : : {
902 : : /* C89 conversion specifiers. */
903 : : { "AZa", 0, STD_C89, NOLENGTHS, "^#", "", NULL },
904 : : { "Bb", 0, STD_C89, NOLENGTHS, "O^#", "p", NULL },
905 : : { "cx", 0, STD_C89, NOLENGTHS, "E", "3", NULL },
906 : : { "HIMSUWdmw", 0, STD_C89, NOLENGTHS, "-_0Ow", "", NULL },
907 : : { "j", 0, STD_C89, NOLENGTHS, "-_0Ow", "o", NULL },
908 : : { "p", 0, STD_C89, NOLENGTHS, "#", "", NULL },
909 : : { "X", 0, STD_C89, NOLENGTHS, "E", "", NULL },
910 : : { "y", 0, STD_C89, NOLENGTHS, "EO-_0w", "4", NULL },
911 : : { "Y", 0, STD_C89, NOLENGTHS, "-_0EOw", "o", NULL },
912 : : { "%", 0, STD_C89, NOLENGTHS, "", "", NULL },
913 : : /* C99 conversion specifiers. */
914 : : { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o", NULL },
915 : : { "D", 0, STD_C99, NOLENGTHS, "", "2", NULL },
916 : : { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "", NULL },
917 : : { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "", NULL },
918 : : { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o", NULL },
919 : : { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o", NULL },
920 : : { "h", 0, STD_C99, NOLENGTHS, "^#", "", NULL },
921 : : { "z", 0, STD_C99, NOLENGTHS, "O", "o", NULL },
922 : : /* GNU conversion specifiers. */
923 : : { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "", NULL },
924 : : { "P", 0, STD_EXT, NOLENGTHS, "", "", NULL },
925 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
926 : : };
927 : :
928 : : static const format_char_info monetary_char_table[] =
929 : : {
930 : : { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "", NULL },
931 : : { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
932 : : };
933 : :
934 : : /* This must be in the same order as enum format_type. */
935 : : static const format_kind_info format_types_orig[] =
936 : : {
937 : : { "gnu_printf", printf_length_specs, print_char_table, " +#0-'I", NULL,
938 : : printf_flag_specs, printf_flag_pairs,
939 : : FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
940 : : 'w', 0, 'p', 0, 'L', 0,
941 : : &integer_type_node, &integer_type_node
942 : : },
943 : : { "asm_fprintf", asm_fprintf_length_specs, asm_fprintf_char_table, " +#0-", NULL,
944 : : asm_fprintf_flag_specs, asm_fprintf_flag_pairs,
945 : : FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK,
946 : : 'w', 0, 'p', 0, 'L', 0,
947 : : NULL, NULL
948 : : },
949 : : { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "q+#", NULL,
950 : : gcc_diag_flag_specs, gcc_diag_flag_pairs,
951 : : FMT_FLAG_ARG_CONVERT,
952 : : 0, 0, 'p', 0, 'L', 0,
953 : : NULL, &integer_type_node
954 : : },
955 : : { "gcc_tdiag", gcc_tdiag_length_specs, gcc_tdiag_char_table, "q+#", NULL,
956 : : gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs,
957 : : FMT_FLAG_ARG_CONVERT,
958 : : 0, 0, 'p', 0, 'L', 0,
959 : : NULL, &integer_type_node
960 : : },
961 : : { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "q+#", NULL,
962 : : gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs,
963 : : FMT_FLAG_ARG_CONVERT,
964 : : 0, 0, 'p', 0, 'L', 0,
965 : : NULL, &integer_type_node
966 : : },
967 : : { "gcc_cxxdiag", gcc_cxxdiag_length_specs, gcc_cxxdiag_char_table, "q+#", NULL,
968 : : gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs,
969 : : FMT_FLAG_ARG_CONVERT,
970 : : 0, 0, 'p', 0, 'L', 0,
971 : : NULL, &integer_type_node
972 : : },
973 : : { "gcc_gfc", gcc_gfc_length_specs, gcc_gfc_char_table, "q+#", NULL,
974 : : gcc_gfc_flag_specs, gcc_gfc_flag_pairs,
975 : : FMT_FLAG_ARG_CONVERT,
976 : : 0, 0, 0, 0, 0, 0,
977 : : NULL, NULL
978 : : },
979 : : { "gcc_dump_printf", gcc_dump_printf_length_specs,
980 : : gcc_dump_printf_char_table, "q+#", NULL,
981 : : gcc_dump_printf_flag_specs, gcc_dump_printf_flag_pairs,
982 : : FMT_FLAG_ARG_CONVERT,
983 : : 0, 0, 'p', 0, 'L', 0,
984 : : NULL, &integer_type_node
985 : : },
986 : : { "NSString", NULL, NULL, NULL, NULL,
987 : : NULL, NULL,
988 : : FMT_FLAG_ARG_CONVERT|FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL, 0, 0, 0, 0, 0, 0,
989 : : NULL, NULL
990 : : },
991 : : { "gnu_scanf", scanf_length_specs, scan_char_table, "*'I", NULL,
992 : : scanf_flag_specs, scanf_flag_pairs,
993 : : FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
994 : : 'w', 0, 0, '*', 'L', 'm',
995 : : NULL, NULL
996 : : },
997 : : { "gnu_strftime", NULL, time_char_table, "_-0^#", "EO",
998 : : strftime_flag_specs, strftime_flag_pairs,
999 : : FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
1000 : : NULL, NULL
1001 : : },
1002 : : { "gnu_strfmon", strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
1003 : : strfmon_flag_specs, strfmon_flag_pairs,
1004 : : FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
1005 : : NULL, NULL
1006 : : }
1007 : : };
1008 : :
1009 : : /* This layer of indirection allows GCC to reassign format_types with
1010 : : new data if necessary, while still allowing the original data to be
1011 : : const. */
1012 : : static const format_kind_info *format_types = format_types_orig;
1013 : : /* We can modify this one. We also add target-specific format types
1014 : : to the end of the array. */
1015 : : static format_kind_info *dynamic_format_types;
1016 : :
1017 : : static int n_format_types = ARRAY_SIZE (format_types_orig);
1018 : :
1019 : : /* Structure detailing the results of checking a format function call
1020 : : where the format expression may be a conditional expression with
1021 : : many leaves resulting from nested conditional expressions. */
1022 : : struct format_check_results
1023 : : {
1024 : : /* Number of leaves of the format argument that could not be checked
1025 : : as they were not string literals. */
1026 : : int number_non_literal;
1027 : : /* Number of leaves of the format argument that were null pointers or
1028 : : string literals, but had extra format arguments. */
1029 : : int number_extra_args;
1030 : : location_t extra_arg_loc;
1031 : : /* Number of leaves of the format argument that were null pointers or
1032 : : string literals, but had extra format arguments and used $ operand
1033 : : numbers. */
1034 : : int number_dollar_extra_args;
1035 : : /* Number of leaves of the format argument that were wide string
1036 : : literals. */
1037 : : int number_wide;
1038 : : /* Number of leaves of the format argument that are not array of "char". */
1039 : : int number_non_char;
1040 : : /* Number of leaves of the format argument that were empty strings. */
1041 : : int number_empty;
1042 : : /* Number of leaves of the format argument that were unterminated
1043 : : strings. */
1044 : : int number_unterminated;
1045 : : /* Number of leaves of the format argument that were not counted above. */
1046 : : int number_other;
1047 : : /* Location of the format string. */
1048 : : location_t format_string_loc;
1049 : : };
1050 : :
1051 : : struct format_check_context
1052 : : {
1053 : : format_check_results *res;
1054 : : function_format_info *info;
1055 : : tree params;
1056 : : vec<location_t> *arglocs;
1057 : : };
1058 : :
1059 : : /* Return the format name (as specified in the original table) for the format
1060 : : type indicated by format_num. */
1061 : : static const char *
1062 : 0 : format_name (int format_num)
1063 : : {
1064 : 0 : if (format_num >= 0 && format_num < n_format_types)
1065 : 0 : return format_types[format_num].name;
1066 : 0 : gcc_unreachable ();
1067 : : }
1068 : :
1069 : : /* Return the format flags (as specified in the original table) for the format
1070 : : type indicated by format_num. */
1071 : : static int
1072 : 10347743 : format_flags (int format_num)
1073 : : {
1074 : 10347743 : if (format_num >= 0 && format_num < n_format_types)
1075 : 10347743 : return format_types[format_num].flags;
1076 : 0 : gcc_unreachable ();
1077 : : }
1078 : :
1079 : : static void check_format_info (function_format_info *, tree,
1080 : : vec<location_t> *);
1081 : : static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT);
1082 : : static void check_format_info_main (format_check_results *,
1083 : : function_format_info *, const char *,
1084 : : location_t, tree,
1085 : : int, tree,
1086 : : unsigned HOST_WIDE_INT,
1087 : : object_allocator<format_wanted_type> &,
1088 : : vec<location_t> *);
1089 : :
1090 : : static void init_dollar_format_checking (int, tree);
1091 : : static int maybe_read_dollar_number (const char **, int,
1092 : : tree, tree *, const format_kind_info *);
1093 : : static bool avoid_dollar_number (const char *);
1094 : : static void finish_dollar_format_checking (format_check_results *, int);
1095 : :
1096 : : static const format_flag_spec *get_flag_spec (const format_flag_spec *,
1097 : : int, const char *);
1098 : :
1099 : : static void check_format_types (const substring_loc &fmt_loc,
1100 : : format_wanted_type *,
1101 : : const format_kind_info *fki,
1102 : : int offset_to_type_start,
1103 : : char conversion_char,
1104 : : vec<location_t> *arglocs);
1105 : : static void format_type_warning (const substring_loc &fmt_loc,
1106 : : location_t param_loc,
1107 : : format_wanted_type *, tree,
1108 : : tree,
1109 : : const format_kind_info *fki,
1110 : : int offset_to_type_start,
1111 : : char conversion_char);
1112 : :
1113 : : /* Decode a format type from a string, returning the type, or
1114 : : format_type_error if not valid, in which case the caller should
1115 : : print an error message. On success, when IS_RAW is non-null, set
1116 : : *IS_RAW when the format type corresponds to a GCC "raw" diagnostic
1117 : : formatting function and clear it otherwise. */
1118 : : static format_type
1119 : 10398766 : decode_format_type (const char *s, bool *is_raw /* = NULL */)
1120 : : {
1121 : 10398766 : bool is_raw_buf;
1122 : :
1123 : 10398766 : if (!is_raw)
1124 : 240 : is_raw = &is_raw_buf;
1125 : :
1126 : 10398766 : *is_raw = false;
1127 : :
1128 : 10398766 : s = convert_format_name_to_system_name (s);
1129 : :
1130 : 10398766 : size_t slen = strlen (s);
1131 : 41538954 : for (int i = 0; i < n_format_types; i++)
1132 : : {
1133 : : /* Check for a match with no underscores. */
1134 : 41538952 : if (!strcmp (s, format_types[i].name))
1135 : 10398734 : return static_cast<format_type> (i);
1136 : :
1137 : : /* Check for leading and trailing underscores. */
1138 : 31140218 : size_t alen = strlen (format_types[i].name);
1139 : 31140218 : if (slen == alen + 4 && s[0] == '_' && s[1] == '_'
1140 : 0 : && s[slen - 1] == '_' && s[slen - 2] == '_'
1141 : 0 : && !strncmp (s + 2, format_types[i].name, alen))
1142 : 0 : return static_cast<format_type>(i);
1143 : :
1144 : : /* Check for the "_raw" suffix and no leading underscores. */
1145 : 31140218 : if (slen == alen + 4
1146 : 1173940 : && !strncmp (s, format_types[i].name, alen)
1147 : 30 : && !strcmp (s + alen, "_raw"))
1148 : : {
1149 : 30 : *is_raw = true;
1150 : 30 : return static_cast<format_type>(i);
1151 : : }
1152 : :
1153 : : /* Check for the "_raw__" suffix and leading underscores. */
1154 : 31140188 : if (slen == alen + 8 && s[0] == '_' && s[1] == '_'
1155 : 0 : && !strncmp (s + 2, format_types[i].name, alen)
1156 : 0 : && !strcmp (s + 2 + alen, "_raw__"))
1157 : : {
1158 : 0 : *is_raw = true;
1159 : 0 : return static_cast<format_type>(i);
1160 : : }
1161 : : }
1162 : :
1163 : : return format_type_error;
1164 : : }
1165 : :
1166 : :
1167 : : /* Check the argument list of a call to printf, scanf, etc.
1168 : : ATTRS are the attributes on the function type. There are NARGS argument
1169 : : values in the array ARGARRAY. FN is either a function declaration or
1170 : : function type. Also, if -Wsuggest-attribute=format, warn for calls to
1171 : : vprintf or vscanf in functions with no such format attribute themselves. */
1172 : :
1173 : : void
1174 : 5806646 : check_function_format (const_tree fn, tree attrs, int nargs,
1175 : : tree *argarray, vec<location_t> *arglocs)
1176 : : {
1177 : 5806646 : tree a;
1178 : :
1179 : 5806646 : tree atname = get_identifier ("format");
1180 : 5806646 : bool skipped_default_format = false;
1181 : :
1182 : : /* See if this function has any format attributes. */
1183 : 6169923 : for (a = attrs; a; a = TREE_CHAIN (a))
1184 : : {
1185 : 363277 : if (is_attribute_p ("format", get_attribute_name (a)))
1186 : : {
1187 : : /* Yup; check it. */
1188 : 50705 : function_format_info info;
1189 : 50705 : decode_format_attr (fn, atname, TREE_VALUE (a), &info,
1190 : : /*validated=*/true);
1191 : :
1192 : : /* Mingw32 targets have traditionally used ms_printf format for the
1193 : : printf function, and this format is built in GCC. But nowadays,
1194 : : if mingw-w64 is configured to target UCRT, the printf function
1195 : : uses the gnu_printf format (specified in the stdio.h header). This
1196 : : causes GCC to check both formats, which means that GCC would
1197 : : warn twice about the same issue when both formats are violated,
1198 : : e.g. for %lu used to print long long unsigned.
1199 : :
1200 : : Hence, if there is a built-in attribute specifier and at least
1201 : : one another, we skip the built-in one. See PR 95130 (but note that
1202 : : GCC ms_printf already supports %llu) and PR 92292. */
1203 : :
1204 : 50705 : if (!skipped_default_format
1205 : 50705 : && fn
1206 : 50705 : && TREE_CODE (fn) == FUNCTION_DECL
1207 : 48672 : && fndecl_built_in_p (fn, BUILT_IN_NORMAL)
1208 : 82495 : && (tree_to_uhwi (TREE_PURPOSE (TREE_VALUE (a)))
1209 : 31790 : & (int) ATTR_FLAG_BUILT_IN))
1210 : : {
1211 : : tree aa;
1212 : 109577 : for (aa = attrs; aa; aa = TREE_CHAIN (aa))
1213 : 77787 : if (a != aa
1214 : 77787 : && is_attribute_p ("format", get_attribute_name (aa)))
1215 : : {
1216 : : skipped_default_format = true;
1217 : : break;
1218 : : }
1219 : 31790 : if (skipped_default_format)
1220 : 0 : continue;
1221 : : }
1222 : :
1223 : 50705 : if (warn_format)
1224 : : {
1225 : : /* FIXME: Rewrite all the internal functions in this file
1226 : : to use the ARGARRAY directly instead of constructing this
1227 : : temporary list. */
1228 : 50650 : tree params = NULL_TREE;
1229 : 50650 : int i;
1230 : 187889 : for (i = nargs - 1; i >= 0; i--)
1231 : 137239 : params = tree_cons (NULL_TREE, argarray[i], params);
1232 : 50650 : check_format_info (&info, params, arglocs);
1233 : : }
1234 : :
1235 : : /* Attempt to detect whether the current function might benefit
1236 : : from the format attribute if the called function is decorated
1237 : : with it. Avoid using calls with string literal formats for
1238 : : guidance since those are unlikely to be viable candidates. */
1239 : 50705 : if (warn_suggest_attribute_format
1240 : 1260 : && current_function_decl != NULL_TREE
1241 : 1258 : && info.first_arg_num == 0
1242 : 273 : && (format_types[info.format_type].flags
1243 : 273 : & (int) FMT_FLAG_ARG_CONVERT)
1244 : : /* c_strlen will fail for a function parameter but succeed
1245 : : for a literal or constant array. */
1246 : 50974 : && !c_strlen (argarray[info.format_num - 1], 1))
1247 : : {
1248 : 259 : tree c;
1249 : 259 : for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1250 : 635 : c;
1251 : 376 : c = TREE_CHAIN (c))
1252 : 610 : if (is_attribute_p ("format", get_attribute_name (c))
1253 : 844 : && (decode_format_type (IDENTIFIER_POINTER
1254 : : (TREE_VALUE (TREE_VALUE (c))))
1255 : 234 : == info.format_type))
1256 : : break;
1257 : 259 : if (c == NULL_TREE)
1258 : : {
1259 : : /* Check if the current function has a parameter to which
1260 : : the format attribute could be attached; if not, it
1261 : : can't be a candidate for a format attribute, despite
1262 : : the vprintf-like or vscanf-like call. */
1263 : 25 : tree args;
1264 : 25 : for (args = DECL_ARGUMENTS (current_function_decl);
1265 : 25 : args != 0;
1266 : 0 : args = DECL_CHAIN (args))
1267 : : {
1268 : 25 : if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE
1269 : 25 : && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args)))
1270 : 25 : == char_type_node))
1271 : : break;
1272 : : }
1273 : 25 : if (args != 0)
1274 : 25 : warning (OPT_Wsuggest_attribute_format, "function %qD "
1275 : : "might be a candidate for %qs format attribute",
1276 : : current_function_decl,
1277 : 25 : format_types[info.format_type].name);
1278 : : }
1279 : : }
1280 : : }
1281 : : }
1282 : 5806646 : }
1283 : :
1284 : :
1285 : : /* Variables used by the checking of $ operand number formats. */
1286 : : static char *dollar_arguments_used = NULL;
1287 : : static char *dollar_arguments_pointer_p = NULL;
1288 : : static int dollar_arguments_alloc = 0;
1289 : : static int dollar_arguments_count;
1290 : : static int dollar_first_arg_num;
1291 : : static int dollar_max_arg_used;
1292 : : static int dollar_format_warned;
1293 : :
1294 : : /* Initialize the checking for a format string that may contain $
1295 : : parameter number specifications; we will need to keep track of whether
1296 : : each parameter has been used. FIRST_ARG_NUM is the number of the first
1297 : : argument that is a parameter to the format, or 0 for a vprintf-style
1298 : : function; PARAMS is the list of arguments starting at this argument. */
1299 : :
1300 : : static void
1301 : 42893 : init_dollar_format_checking (int first_arg_num, tree params)
1302 : : {
1303 : 42893 : tree oparams = params;
1304 : :
1305 : 42893 : dollar_first_arg_num = first_arg_num;
1306 : 42893 : dollar_arguments_count = 0;
1307 : 42893 : dollar_max_arg_used = 0;
1308 : 42893 : dollar_format_warned = 0;
1309 : 42893 : if (first_arg_num > 0)
1310 : : {
1311 : 93807 : while (params)
1312 : : {
1313 : 51842 : dollar_arguments_count++;
1314 : 51842 : params = TREE_CHAIN (params);
1315 : : }
1316 : : }
1317 : 42893 : if (dollar_arguments_alloc < dollar_arguments_count)
1318 : : {
1319 : 4665 : free (dollar_arguments_used);
1320 : 4665 : free (dollar_arguments_pointer_p);
1321 : 4665 : dollar_arguments_alloc = dollar_arguments_count;
1322 : 4665 : dollar_arguments_used = XNEWVEC (char, dollar_arguments_alloc);
1323 : 4665 : dollar_arguments_pointer_p = XNEWVEC (char, dollar_arguments_alloc);
1324 : : }
1325 : 42893 : if (dollar_arguments_alloc)
1326 : : {
1327 : 40432 : memset (dollar_arguments_used, 0, dollar_arguments_alloc);
1328 : 40432 : if (first_arg_num > 0)
1329 : : {
1330 : : int i = 0;
1331 : : params = oparams;
1332 : 91866 : while (params)
1333 : : {
1334 : 51842 : dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params)))
1335 : 51842 : == POINTER_TYPE);
1336 : 51842 : params = TREE_CHAIN (params);
1337 : 51842 : i++;
1338 : : }
1339 : : }
1340 : : }
1341 : 42893 : }
1342 : :
1343 : :
1344 : : /* Look for a decimal number followed by a $ in *FORMAT. If DOLLAR_NEEDED
1345 : : is set, it is an error if one is not found; otherwise, it is OK. If
1346 : : such a number is found, check whether it is within range and mark that
1347 : : numbered operand as being used for later checking. Returns the operand
1348 : : number if found and within range, zero if no such number was found and
1349 : : this is OK, or -1 on error. PARAMS points to the first operand of the
1350 : : format; PARAM_PTR is made to point to the parameter referred to. If
1351 : : a $ format is found, *FORMAT is updated to point just after it. */
1352 : :
1353 : : static int
1354 : 35097 : maybe_read_dollar_number (const char **format,
1355 : : int dollar_needed, tree params, tree *param_ptr,
1356 : : const format_kind_info *fki)
1357 : : {
1358 : 35097 : int argnum;
1359 : 35097 : int overflow_flag;
1360 : 35097 : const char *fcp = *format;
1361 : 35097 : if (!ISDIGIT (*fcp))
1362 : : {
1363 : 34351 : if (dollar_needed)
1364 : : {
1365 : 2 : warning (OPT_Wformat_, "missing $ operand number in format");
1366 : 2 : return -1;
1367 : : }
1368 : : else
1369 : : return 0;
1370 : : }
1371 : : argnum = 0;
1372 : : overflow_flag = 0;
1373 : 2293 : while (ISDIGIT (*fcp))
1374 : : {
1375 : 1547 : HOST_WIDE_INT nargnum
1376 : 1547 : = HOST_WIDE_INT_UC (10) * argnum + (*fcp - '0');
1377 : 1547 : if ((int) nargnum != nargnum)
1378 : 30 : overflow_flag = 1;
1379 : 1547 : argnum = nargnum;
1380 : 1547 : fcp++;
1381 : : }
1382 : 746 : if (*fcp != '$')
1383 : : {
1384 : 549 : if (dollar_needed)
1385 : : {
1386 : 0 : warning (OPT_Wformat_, "missing $ operand number in format");
1387 : 0 : return -1;
1388 : : }
1389 : : else
1390 : : return 0;
1391 : : }
1392 : 197 : *format = fcp + 1;
1393 : 197 : if (pedantic && !dollar_format_warned)
1394 : : {
1395 : 4 : warning (OPT_Wformat_, "%s does not support %%n$ operand number formats",
1396 : 4 : C_STD_NAME (STD_EXT));
1397 : 4 : dollar_format_warned = 1;
1398 : : }
1399 : 197 : if (overflow_flag || argnum == 0
1400 : 195 : || (dollar_first_arg_num && argnum > dollar_arguments_count))
1401 : : {
1402 : 6 : warning (OPT_Wformat_, "operand number out of range in format");
1403 : 6 : return -1;
1404 : : }
1405 : 191 : if (argnum > dollar_max_arg_used)
1406 : 109 : dollar_max_arg_used = argnum;
1407 : : /* For vprintf-style functions we may need to allocate more memory to
1408 : : track which arguments are used. */
1409 : 191 : while (dollar_arguments_alloc < dollar_max_arg_used)
1410 : : {
1411 : 0 : int nalloc;
1412 : 0 : nalloc = 2 * dollar_arguments_alloc + 16;
1413 : 0 : dollar_arguments_used = XRESIZEVEC (char, dollar_arguments_used,
1414 : : nalloc);
1415 : 0 : dollar_arguments_pointer_p = XRESIZEVEC (char, dollar_arguments_pointer_p,
1416 : : nalloc);
1417 : 0 : memset (dollar_arguments_used + dollar_arguments_alloc, 0,
1418 : 0 : nalloc - dollar_arguments_alloc);
1419 : 0 : dollar_arguments_alloc = nalloc;
1420 : : }
1421 : 191 : if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE)
1422 : 64 : && dollar_arguments_used[argnum - 1] == 1)
1423 : : {
1424 : 2 : dollar_arguments_used[argnum - 1] = 2;
1425 : 2 : warning (OPT_Wformat_, "format argument %d used more than once in %s format",
1426 : 2 : argnum, fki->name);
1427 : : }
1428 : : else
1429 : 189 : dollar_arguments_used[argnum - 1] = 1;
1430 : 191 : if (dollar_first_arg_num)
1431 : : {
1432 : 175 : int i;
1433 : 175 : *param_ptr = params;
1434 : 344 : for (i = 1; i < argnum && *param_ptr != 0; i++)
1435 : 169 : *param_ptr = TREE_CHAIN (*param_ptr);
1436 : :
1437 : : /* This case shouldn't be caught here. */
1438 : 175 : gcc_assert (*param_ptr);
1439 : : }
1440 : : else
1441 : 16 : *param_ptr = 0;
1442 : : return argnum;
1443 : : }
1444 : :
1445 : : /* Ensure that FORMAT does not start with a decimal number followed by
1446 : : a $; give a diagnostic and return true if it does, false otherwise. */
1447 : :
1448 : : static bool
1449 : 16061 : avoid_dollar_number (const char *format)
1450 : : {
1451 : 16061 : if (!ISDIGIT (*format))
1452 : : return false;
1453 : 1247 : while (ISDIGIT (*format))
1454 : 834 : format++;
1455 : 413 : if (*format == '$')
1456 : : {
1457 : 8 : warning (OPT_Wformat_,
1458 : : "%<$%>operand number used after format without operand number");
1459 : 8 : return true;
1460 : : }
1461 : : return false;
1462 : : }
1463 : :
1464 : :
1465 : : /* Finish the checking for a format string that used $ operand number formats
1466 : : instead of non-$ formats. We check for unused operands before used ones
1467 : : (a serious error, since the implementation of the format function
1468 : : can't know what types to pass to va_arg to find the later arguments).
1469 : : and for unused operands at the end of the format (if we know how many
1470 : : arguments the format had, so not for vprintf). If there were operand
1471 : : numbers out of range on a non-vprintf-style format, we won't have reached
1472 : : here. If POINTER_GAP_OK, unused arguments are OK if all arguments are
1473 : : pointers. */
1474 : :
1475 : : static void
1476 : 80 : finish_dollar_format_checking (format_check_results *res, int pointer_gap_ok)
1477 : : {
1478 : 80 : int i;
1479 : 80 : bool found_pointer_gap = false;
1480 : 273 : for (i = 0; i < dollar_max_arg_used; i++)
1481 : : {
1482 : 193 : if (!dollar_arguments_used[i])
1483 : : {
1484 : 25 : if (pointer_gap_ok && (dollar_first_arg_num == 0
1485 : 12 : || dollar_arguments_pointer_p[i]))
1486 : : found_pointer_gap = true;
1487 : : else
1488 : 13 : warning_at (res->format_string_loc, OPT_Wformat_,
1489 : : "format argument %d unused before used argument %d "
1490 : : "in %<$%>-style format",
1491 : : i + 1, dollar_max_arg_used);
1492 : : }
1493 : : }
1494 : 80 : if (found_pointer_gap
1495 : 68 : || (dollar_first_arg_num
1496 : 64 : && dollar_max_arg_used < dollar_arguments_count))
1497 : : {
1498 : 18 : res->number_other--;
1499 : 18 : res->number_dollar_extra_args++;
1500 : : }
1501 : 80 : }
1502 : :
1503 : :
1504 : : /* Retrieve the specification for a format flag. SPEC contains the
1505 : : specifications for format flags for the applicable kind of format.
1506 : : FLAG is the flag in question. If PREDICATES is NULL, the basic
1507 : : spec for that flag must be retrieved and must exist. If
1508 : : PREDICATES is not NULL, it is a string listing possible predicates
1509 : : for the spec entry; if an entry predicated on any of these is
1510 : : found, it is returned, otherwise NULL is returned. */
1511 : :
1512 : : static const format_flag_spec *
1513 : 31111 : get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates)
1514 : : {
1515 : 31111 : int i;
1516 : 250698 : for (i = 0; spec[i].flag_char != 0; i++)
1517 : : {
1518 : 249482 : if (spec[i].flag_char != flag)
1519 : 218275 : continue;
1520 : 31207 : if (predicates != NULL)
1521 : : {
1522 : 1332 : if (spec[i].predicate != 0
1523 : 96 : && strchr (predicates, spec[i].predicate) != 0)
1524 : 20 : return &spec[i];
1525 : : }
1526 : 29875 : else if (spec[i].predicate == 0)
1527 : 29875 : return &spec[i];
1528 : : }
1529 : 1216 : gcc_assert (predicates);
1530 : : return NULL;
1531 : : }
1532 : :
1533 : :
1534 : : /* Check the argument list of a call to printf, scanf, etc.
1535 : : INFO points to the function_format_info structure.
1536 : : PARAMS is the list of argument values. */
1537 : :
1538 : : static void
1539 : 50650 : check_format_info (function_format_info *info, tree params,
1540 : : vec<location_t> *arglocs)
1541 : : {
1542 : 50650 : format_check_context format_ctx;
1543 : 50650 : unsigned HOST_WIDE_INT arg_num;
1544 : 50650 : tree format_tree;
1545 : 50650 : format_check_results res;
1546 : : /* Skip to format argument. If the argument isn't available, there's
1547 : : no work for us to do; prototype checking will catch the problem. */
1548 : 50650 : for (arg_num = 1; ; ++arg_num)
1549 : : {
1550 : 76644 : if (params == 0)
1551 : 0 : return;
1552 : 76644 : if (arg_num == info->format_num)
1553 : : break;
1554 : 25994 : params = TREE_CHAIN (params);
1555 : : }
1556 : 50650 : format_tree = TREE_VALUE (params);
1557 : 50650 : params = TREE_CHAIN (params);
1558 : 50650 : if (format_tree == 0)
1559 : : return;
1560 : :
1561 : 50650 : res.number_non_literal = 0;
1562 : 50650 : res.number_extra_args = 0;
1563 : 50650 : res.extra_arg_loc = UNKNOWN_LOCATION;
1564 : 50650 : res.number_dollar_extra_args = 0;
1565 : 50650 : res.number_wide = 0;
1566 : 50650 : res.number_non_char = 0;
1567 : 50650 : res.number_empty = 0;
1568 : 50650 : res.number_unterminated = 0;
1569 : 50650 : res.number_other = 0;
1570 : 50650 : res.format_string_loc = input_location;
1571 : :
1572 : 50650 : format_ctx.res = &res;
1573 : 50650 : format_ctx.info = info;
1574 : 50650 : format_ctx.params = params;
1575 : 50650 : format_ctx.arglocs = arglocs;
1576 : :
1577 : 50650 : check_function_arguments_recurse (check_format_arg, &format_ctx,
1578 : : format_tree, arg_num, OPT_Wformat_);
1579 : :
1580 : 50650 : location_t loc = format_ctx.res->format_string_loc;
1581 : :
1582 : 50650 : if (res.number_non_literal > 0)
1583 : : {
1584 : : /* Functions taking a va_list normally pass a non-literal format
1585 : : string. These functions typically are declared with
1586 : : first_arg_num == 0, so avoid warning in those cases. */
1587 : 7796 : if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT))
1588 : : {
1589 : : /* For strftime-like formats, warn for not checking the format
1590 : : string; but there are no arguments to check. */
1591 : 2 : warning_at (loc, OPT_Wformat_nonliteral,
1592 : : "format not a string literal, format string not checked");
1593 : : }
1594 : 7794 : else if (info->first_arg_num != 0)
1595 : : {
1596 : : /* If there are no arguments for the format at all, we may have
1597 : : printf (foo) which is likely to be a security hole. */
1598 : 140 : while (arg_num + 1 < info->first_arg_num)
1599 : : {
1600 : 0 : if (params == 0)
1601 : : break;
1602 : 0 : params = TREE_CHAIN (params);
1603 : 0 : ++arg_num;
1604 : : }
1605 : 140 : if (params == 0 && warn_format_security)
1606 : 9 : warning_at (loc, OPT_Wformat_security,
1607 : : "format not a string literal and no format arguments");
1608 : 14 : else if (params == 0 && warn_format_nonliteral)
1609 : 0 : warning_at (loc, OPT_Wformat_nonliteral,
1610 : : "format not a string literal and no format arguments");
1611 : : else
1612 : 131 : warning_at (loc, OPT_Wformat_nonliteral,
1613 : : "format not a string literal, argument types not checked");
1614 : : }
1615 : : }
1616 : :
1617 : : /* If there were extra arguments to the format, normally warn. However,
1618 : : the standard does say extra arguments are ignored, so in the specific
1619 : : case where we have multiple leaves (conditional expressions or
1620 : : ngettext) allow extra arguments if at least one leaf didn't have extra
1621 : : arguments, but was otherwise OK (either non-literal or checked OK).
1622 : : If the format is an empty string, this should be counted similarly to the
1623 : : case of extra format arguments. */
1624 : 50650 : if (res.number_extra_args > 0 && res.number_non_literal == 0
1625 : 235 : && res.number_other == 0)
1626 : : {
1627 : 221 : if (res.extra_arg_loc == UNKNOWN_LOCATION)
1628 : 211 : res.extra_arg_loc = loc;
1629 : 221 : warning_at (res.extra_arg_loc, OPT_Wformat_extra_args,
1630 : : "too many arguments for format");
1631 : : }
1632 : 50650 : if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0
1633 : 18 : && res.number_other == 0)
1634 : 18 : warning_at (loc, OPT_Wformat_extra_args,
1635 : : "unused arguments in %<$%>-style format");
1636 : 50650 : if (res.number_empty > 0 && res.number_non_literal == 0
1637 : 25 : && res.number_other == 0)
1638 : 21 : warning_at (loc, OPT_Wformat_zero_length, "zero-length %s format string",
1639 : 21 : format_types[info->format_type].name);
1640 : :
1641 : 50650 : if (res.number_wide > 0)
1642 : 11 : warning_at (loc, OPT_Wformat_, "format is a wide character string");
1643 : :
1644 : 50650 : if (res.number_non_char > 0)
1645 : 5 : warning_at (loc, OPT_Wformat_,
1646 : : "format string is not an array of type %qs", "char");
1647 : :
1648 : 50650 : if (res.number_unterminated > 0)
1649 : 6 : warning_at (loc, OPT_Wformat_, "unterminated format string");
1650 : : }
1651 : :
1652 : : /* Callback from check_function_arguments_recurse to check a
1653 : : format string. FORMAT_TREE is the format parameter. ARG_NUM
1654 : : is the number of the format argument. CTX points to a
1655 : : format_check_context. */
1656 : :
1657 : : static void
1658 : 50762 : check_format_arg (void *ctx, tree format_tree,
1659 : : unsigned HOST_WIDE_INT arg_num)
1660 : : {
1661 : 50762 : format_check_context *format_ctx = (format_check_context *) ctx;
1662 : 50762 : format_check_results *res = format_ctx->res;
1663 : 50762 : function_format_info *info = format_ctx->info;
1664 : 50762 : tree params = format_ctx->params;
1665 : 50762 : vec<location_t> *arglocs = format_ctx->arglocs;
1666 : :
1667 : 50762 : int format_length;
1668 : 50762 : HOST_WIDE_INT offset;
1669 : 50762 : const char *format_chars;
1670 : 50762 : tree array_size = 0;
1671 : 50762 : tree array_init;
1672 : :
1673 : 50762 : location_t fmt_param_loc = EXPR_LOC_OR_LOC (format_tree, input_location);
1674 : :
1675 : : /* Pull out a constant value if the front end didn't, and handle location
1676 : : wrappers. */
1677 : 50762 : format_tree = fold_for_warn (format_tree);
1678 : 50762 : STRIP_NOPS (format_tree);
1679 : :
1680 : 50762 : if (integer_zerop (format_tree))
1681 : : {
1682 : : /* Skip to first argument to check, so we can see if this format
1683 : : has any arguments (it shouldn't). */
1684 : 26 : while (arg_num + 1 < info->first_arg_num)
1685 : : {
1686 : 0 : if (params == 0)
1687 : 7869 : return;
1688 : 0 : params = TREE_CHAIN (params);
1689 : 0 : ++arg_num;
1690 : : }
1691 : :
1692 : 26 : if (params == 0)
1693 : 16 : res->number_other++;
1694 : : else
1695 : : {
1696 : 10 : if (res->number_extra_args == 0)
1697 : 12 : res->extra_arg_loc = EXPR_LOC_OR_LOC (TREE_VALUE (params),
1698 : : input_location);
1699 : 10 : res->number_extra_args++;
1700 : : }
1701 : 26 : return;
1702 : : }
1703 : :
1704 : 50736 : offset = 0;
1705 : 50736 : if (TREE_CODE (format_tree) == POINTER_PLUS_EXPR)
1706 : : {
1707 : 30 : tree arg0, arg1;
1708 : :
1709 : 30 : arg0 = TREE_OPERAND (format_tree, 0);
1710 : 30 : arg1 = TREE_OPERAND (format_tree, 1);
1711 : 30 : STRIP_NOPS (arg0);
1712 : 30 : STRIP_NOPS (arg1);
1713 : 30 : if (TREE_CODE (arg1) == INTEGER_CST)
1714 : 28 : format_tree = arg0;
1715 : : else
1716 : : {
1717 : 2 : res->number_non_literal++;
1718 : 2 : return;
1719 : : }
1720 : : /* POINTER_PLUS_EXPR offsets are to be interpreted signed. */
1721 : 28 : if (!cst_and_fits_in_hwi (arg1))
1722 : : {
1723 : 0 : res->number_non_literal++;
1724 : 0 : return;
1725 : : }
1726 : 28 : offset = int_cst_value (arg1);
1727 : : }
1728 : 50734 : if (TREE_CODE (format_tree) != ADDR_EXPR)
1729 : : {
1730 : 7766 : res->number_non_literal++;
1731 : 7766 : return;
1732 : : }
1733 : 42968 : res->format_string_loc = EXPR_LOC_OR_LOC (format_tree, input_location);
1734 : 42968 : format_tree = TREE_OPERAND (format_tree, 0);
1735 : 42968 : if (format_types[info->format_type].flags
1736 : 42968 : & (int) FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL)
1737 : : {
1738 : 0 : bool objc_str = (info->format_type == gcc_objc_string_format_type);
1739 : : /* We cannot examine this string here - but we can check that it is
1740 : : a valid type. */
1741 : 0 : if (TREE_CODE (format_tree) != CONST_DECL
1742 : 0 : || !((objc_str && objc_string_ref_type_p (TREE_TYPE (format_tree)))
1743 : 0 : || (*targetcm.string_object_ref_type_p)
1744 : 0 : ((const_tree) TREE_TYPE (format_tree))))
1745 : : {
1746 : 0 : res->number_non_literal++;
1747 : 0 : return;
1748 : : }
1749 : : /* Skip to first argument to check. */
1750 : 0 : while (arg_num + 1 < info->first_arg_num)
1751 : : {
1752 : 0 : if (params == 0)
1753 : : return;
1754 : 0 : params = TREE_CHAIN (params);
1755 : 0 : ++arg_num;
1756 : : }
1757 : : /* So, we have a valid literal string object and one or more params.
1758 : : We need to use an external helper to parse the string into format
1759 : : info. For Objective-C variants we provide the resource within the
1760 : : objc tree, for target variants, via a hook. */
1761 : 0 : if (objc_str)
1762 : 0 : objc_check_format_arg (format_tree, params);
1763 : 0 : else if (targetcm.check_string_object_format_arg)
1764 : 0 : (*targetcm.check_string_object_format_arg) (format_tree, params);
1765 : : /* Else we can't handle it and retire quietly. */
1766 : 0 : return;
1767 : : }
1768 : 42968 : if (TREE_CODE (format_tree) == ARRAY_REF
1769 : 16 : && tree_fits_shwi_p (TREE_OPERAND (format_tree, 1))
1770 : 42984 : && (offset += tree_to_shwi (TREE_OPERAND (format_tree, 1))) >= 0)
1771 : 16 : format_tree = TREE_OPERAND (format_tree, 0);
1772 : 42968 : if (offset < 0)
1773 : : {
1774 : 4 : res->number_non_literal++;
1775 : 4 : return;
1776 : : }
1777 : 42964 : if (VAR_P (format_tree)
1778 : 80 : && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE
1779 : 80 : && (array_init = decl_constant_value (format_tree)) != format_tree
1780 : 43022 : && TREE_CODE (array_init) == STRING_CST)
1781 : : {
1782 : : /* Extract the string constant initializer. Note that this may include
1783 : : a trailing NUL character that is not in the array (e.g.
1784 : : const char a[3] = "foo";). */
1785 : 58 : array_size = DECL_SIZE_UNIT (format_tree);
1786 : 58 : format_tree = array_init;
1787 : : }
1788 : 42964 : if (TREE_CODE (format_tree) != STRING_CST)
1789 : : {
1790 : 22 : res->number_non_literal++;
1791 : 22 : return;
1792 : : }
1793 : 42942 : tree underlying_type
1794 : 42942 : = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree)));
1795 : 42942 : if (underlying_type != char_type_node
1796 : 19 : && !(flag_char8_t && underlying_type == char8_type_node))
1797 : : {
1798 : 16 : if (underlying_type == char16_type_node
1799 : 16 : || underlying_type == char32_type_node
1800 : 16 : || underlying_type == wchar_type_node)
1801 : 11 : res->number_wide++;
1802 : : else
1803 : 5 : res->number_non_char++;
1804 : 16 : return;
1805 : : }
1806 : 42926 : format_chars = TREE_STRING_POINTER (format_tree);
1807 : 42926 : format_length = TREE_STRING_LENGTH (format_tree);
1808 : 42926 : if (array_size != 0)
1809 : : {
1810 : : /* Variable length arrays can't be initialized. */
1811 : 53 : gcc_assert (TREE_CODE (array_size) == INTEGER_CST);
1812 : :
1813 : 53 : if (tree_fits_shwi_p (array_size))
1814 : : {
1815 : 53 : HOST_WIDE_INT array_size_value = tree_to_shwi (array_size);
1816 : 53 : if (array_size_value > 0
1817 : 53 : && array_size_value == (int) array_size_value
1818 : 53 : && format_length > array_size_value)
1819 : 42926 : format_length = array_size_value;
1820 : : }
1821 : : }
1822 : 42926 : if (offset)
1823 : : {
1824 : 34 : if (offset >= format_length)
1825 : : {
1826 : 2 : res->number_non_literal++;
1827 : 2 : return;
1828 : : }
1829 : 32 : format_chars += offset;
1830 : 32 : format_length -= offset;
1831 : : }
1832 : 42924 : if (format_length < 1 || format_chars[--format_length] != 0)
1833 : : {
1834 : 6 : res->number_unterminated++;
1835 : 6 : return;
1836 : : }
1837 : 42918 : if (format_length == 0)
1838 : : {
1839 : 25 : res->number_empty++;
1840 : 25 : return;
1841 : : }
1842 : :
1843 : : /* Skip to first argument to check. */
1844 : 42895 : while (arg_num + 1 < info->first_arg_num)
1845 : : {
1846 : 2 : if (params == 0)
1847 : : return;
1848 : 2 : params = TREE_CHAIN (params);
1849 : 2 : ++arg_num;
1850 : : }
1851 : : /* Provisionally increment res->number_other; check_format_info_main
1852 : : will decrement it if it finds there are extra arguments, but this way
1853 : : need not adjust it for every return. */
1854 : 42893 : res->number_other++;
1855 : 42893 : object_allocator <format_wanted_type> fwt_pool ("format_wanted_type pool");
1856 : 42893 : check_format_info_main (res, info, format_chars, fmt_param_loc, format_tree,
1857 : : format_length, params, arg_num, fwt_pool, arglocs);
1858 : 42893 : }
1859 : :
1860 : : /* Support class for argument_parser and check_format_info_main.
1861 : : Tracks any flag characters that have been applied to the
1862 : : current argument. */
1863 : :
1864 : : class flag_chars_t
1865 : : {
1866 : : public:
1867 : : flag_chars_t ();
1868 : : bool has_char_p (char ch) const;
1869 : : void add_char (char ch);
1870 : : void validate (const format_kind_info *fki,
1871 : : const format_char_info *fci,
1872 : : const format_flag_spec *flag_specs,
1873 : : const char * const format_chars,
1874 : : tree format_string_cst,
1875 : : location_t format_string_loc,
1876 : : const char * const orig_format_chars,
1877 : : char format_char,
1878 : : bool quoted);
1879 : : int get_alloc_flag (const format_kind_info *fki);
1880 : : int assignment_suppression_p (const format_kind_info *fki);
1881 : :
1882 : : private:
1883 : : char m_flag_chars[256];
1884 : : };
1885 : :
1886 : : /* Support struct for argument_parser and check_format_info_main.
1887 : : Encapsulates any length modifier applied to the current argument. */
1888 : :
1889 : : class length_modifier
1890 : : {
1891 : : public:
1892 : 52277 : length_modifier ()
1893 : 52277 : : chars (NULL), val (FMT_LEN_none), std (STD_C89),
1894 : 52277 : scalar_identity_flag (0)
1895 : : {
1896 : : }
1897 : :
1898 : 19122 : length_modifier (const char *chars_,
1899 : : enum format_lengths val_,
1900 : : enum format_std_version std_,
1901 : : int scalar_identity_flag_)
1902 : : : chars (chars_), val (val_), std (std_),
1903 : : scalar_identity_flag (scalar_identity_flag_)
1904 : : {
1905 : : }
1906 : :
1907 : : const char *chars;
1908 : : enum format_lengths val;
1909 : : enum format_std_version std;
1910 : : int scalar_identity_flag;
1911 : : };
1912 : :
1913 : : /* Parsing one argument within a format string. */
1914 : :
1915 : : class argument_parser
1916 : : {
1917 : : public:
1918 : : argument_parser (function_format_info *info, const char *&format_chars,
1919 : : tree format_string_cst,
1920 : : const char * const orig_format_chars,
1921 : : location_t format_string_loc, flag_chars_t &flag_chars,
1922 : : int &has_operand_number, tree first_fillin_param,
1923 : : object_allocator <format_wanted_type> &fwt_pool_,
1924 : : vec<location_t> *arglocs);
1925 : :
1926 : : bool read_any_dollar ();
1927 : :
1928 : : bool read_format_flags ();
1929 : :
1930 : : bool
1931 : : read_any_format_width (tree ¶ms,
1932 : : unsigned HOST_WIDE_INT &arg_num);
1933 : :
1934 : : void
1935 : : read_any_format_left_precision ();
1936 : :
1937 : : bool
1938 : : read_any_format_precision (tree ¶ms,
1939 : : unsigned HOST_WIDE_INT &arg_num);
1940 : :
1941 : : void handle_alloc_chars ();
1942 : :
1943 : : length_modifier read_any_length_modifier ();
1944 : :
1945 : : void read_any_other_modifier ();
1946 : :
1947 : : const format_char_info *find_format_char_info (char format_char);
1948 : :
1949 : : void
1950 : : validate_flag_pairs (const format_char_info *fci,
1951 : : char format_char);
1952 : :
1953 : : void
1954 : : give_y2k_warnings (const format_char_info *fci,
1955 : : char format_char);
1956 : :
1957 : : void parse_any_scan_set (const format_char_info *fci);
1958 : :
1959 : : bool handle_conversions (const format_char_info *fci,
1960 : : const length_modifier &len_modifier,
1961 : : tree &wanted_type,
1962 : : const char *&wanted_type_name,
1963 : : unsigned HOST_WIDE_INT &arg_num,
1964 : : tree ¶ms,
1965 : : char format_char);
1966 : :
1967 : : bool
1968 : : check_argument_type (const format_char_info *fci,
1969 : : const length_modifier &len_modifier,
1970 : : tree &wanted_type,
1971 : : const char *&wanted_type_name,
1972 : : const bool suppressed,
1973 : : unsigned HOST_WIDE_INT &arg_num,
1974 : : tree ¶ms,
1975 : : const int alloc_flag,
1976 : : const char * const format_start,
1977 : : const char * const type_start,
1978 : : location_t fmt_param_loc,
1979 : : char conversion_char);
1980 : :
1981 : : private:
1982 : : const function_format_info *const info;
1983 : : const format_kind_info * const fki;
1984 : : const format_flag_spec * const flag_specs;
1985 : : const char *start_of_this_format;
1986 : : const char *&format_chars;
1987 : : const tree format_string_cst;
1988 : : const char * const orig_format_chars;
1989 : : const location_t format_string_loc;
1990 : : object_allocator <format_wanted_type> &fwt_pool;
1991 : : flag_chars_t &flag_chars;
1992 : : int main_arg_num;
1993 : : tree main_arg_params;
1994 : : int &has_operand_number;
1995 : : const tree first_fillin_param;
1996 : : format_wanted_type width_wanted_type;
1997 : : format_wanted_type precision_wanted_type;
1998 : : public:
1999 : : format_wanted_type main_wanted_type;
2000 : : private:
2001 : : format_wanted_type *first_wanted_type;
2002 : : format_wanted_type *last_wanted_type;
2003 : : vec<location_t> *arglocs;
2004 : : };
2005 : :
2006 : : /* flag_chars_t's constructor. */
2007 : :
2008 : 52295 : flag_chars_t::flag_chars_t ()
2009 : : {
2010 : 52295 : m_flag_chars[0] = 0;
2011 : 52295 : }
2012 : :
2013 : : /* Has CH been seen as a flag within the current argument? */
2014 : :
2015 : : bool
2016 : 162145 : flag_chars_t::has_char_p (char ch) const
2017 : : {
2018 : 162145 : return strchr (m_flag_chars, ch) != 0;
2019 : : }
2020 : :
2021 : : /* Add CH to the flags seen within the current argument. */
2022 : :
2023 : : void
2024 : 26516 : flag_chars_t::add_char (char ch)
2025 : : {
2026 : 26516 : int i = strlen (m_flag_chars);
2027 : 26516 : m_flag_chars[i++] = ch;
2028 : 26516 : m_flag_chars[i] = 0;
2029 : 26516 : }
2030 : :
2031 : : /* Validate the individual flags used, removing any that are invalid. */
2032 : :
2033 : : void
2034 : 52026 : flag_chars_t::validate (const format_kind_info *fki,
2035 : : const format_char_info *fci,
2036 : : const format_flag_spec *flag_specs,
2037 : : const char * const format_chars,
2038 : : tree format_string_cst,
2039 : : location_t format_string_loc,
2040 : : const char * const orig_format_chars,
2041 : : char format_char,
2042 : : bool quoted)
2043 : : {
2044 : 52026 : int i;
2045 : 52026 : int d = 0;
2046 : 52026 : bool quotflag = false;
2047 : :
2048 : 78449 : for (i = 0; m_flag_chars[i] != 0; i++)
2049 : : {
2050 : 26423 : const format_flag_spec *s = get_flag_spec (flag_specs,
2051 : : m_flag_chars[i], NULL);
2052 : 26423 : m_flag_chars[i - d] = m_flag_chars[i];
2053 : 26423 : if (m_flag_chars[i] == fki->length_code_char)
2054 : 19078 : continue;
2055 : :
2056 : : /* Remember if a quoting flag is seen. */
2057 : 7345 : quotflag |= s->quoting;
2058 : :
2059 : 7345 : if (strchr (fci->flag_chars, m_flag_chars[i]) == 0)
2060 : : {
2061 : 786 : format_warning_at_char (format_string_loc, format_string_cst,
2062 : 786 : format_chars - orig_format_chars,
2063 : : OPT_Wformat_,
2064 : : "%s used with %<%%%c%> %s format",
2065 : 786 : _(s->name), format_char, fki->name);
2066 : 786 : d++;
2067 : 786 : continue;
2068 : : }
2069 : 6559 : if (pedantic)
2070 : : {
2071 : 1236 : const format_flag_spec *t;
2072 : 1236 : if (ADJ_STD (s->std) > C_STD_VER)
2073 : 42 : warning_at (format_string_loc, OPT_Wformat_,
2074 : : "%s does not support %s",
2075 : 42 : C_STD_NAME (s->std), _(s->long_name));
2076 : 1236 : t = get_flag_spec (flag_specs, m_flag_chars[i], fci->flags2);
2077 : 1236 : if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std))
2078 : : {
2079 : 20 : const char *long_name = (t->long_name != NULL
2080 : : ? t->long_name
2081 : : : s->long_name);
2082 : 20 : if (ADJ_STD (t->std) > C_STD_VER)
2083 : 16 : warning_at (format_string_loc, OPT_Wformat_,
2084 : : "%s does not support %s with"
2085 : : " the %<%%%c%> %s format",
2086 : 16 : C_STD_NAME (t->std), _(long_name),
2087 : 16 : format_char, fki->name);
2088 : : }
2089 : : }
2090 : :
2091 : : /* Detect quoting directives used within a quoted sequence, such
2092 : : as GCC's "%<...%qE". */
2093 : 6559 : if (quoted && s->quoting)
2094 : : {
2095 : 12 : format_warning_at_char (format_string_loc, format_string_cst,
2096 : 12 : format_chars - orig_format_chars - 1,
2097 : : OPT_Wformat_,
2098 : : "%s used within a quoted sequence",
2099 : 12 : _(s->name));
2100 : : }
2101 : : }
2102 : 52026 : m_flag_chars[i - d] = 0;
2103 : :
2104 : 52026 : if (!quoted
2105 : : && !quotflag
2106 : 51506 : && strchr (fci->flags2, '\''))
2107 : : {
2108 : 54 : format_warning_at_char (format_string_loc, format_string_cst,
2109 : 54 : format_chars - orig_format_chars,
2110 : : OPT_Wformat_,
2111 : : "%qc conversion used unquoted",
2112 : : format_char);
2113 : : }
2114 : 52026 : }
2115 : :
2116 : : /* Determine if an assignment-allocation has been set, requiring
2117 : : an extra char ** for writing back a dynamically-allocated char *.
2118 : : This is for handling the optional 'm' character in scanf. */
2119 : :
2120 : : int
2121 : 52026 : flag_chars_t::get_alloc_flag (const format_kind_info *fki)
2122 : : {
2123 : 52026 : if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
2124 : 52026 : && has_char_p ('a'))
2125 : : return 1;
2126 : 51984 : if (fki->alloc_char && has_char_p (fki->alloc_char))
2127 : : return 1;
2128 : : return 0;
2129 : : }
2130 : :
2131 : : /* Determine if an assignment-suppression character was seen.
2132 : : ('*' in scanf, for discarding the converted input). */
2133 : :
2134 : : int
2135 : 52026 : flag_chars_t::assignment_suppression_p (const format_kind_info *fki)
2136 : : {
2137 : 52026 : if (fki->suppression_char
2138 : 52026 : && has_char_p (fki->suppression_char))
2139 : : return 1;
2140 : : return 0;
2141 : : }
2142 : :
2143 : : /* Constructor for argument_parser. Initialize for parsing one
2144 : : argument within a format string. */
2145 : :
2146 : 52295 : argument_parser::
2147 : : argument_parser (function_format_info *info_, const char *&format_chars_,
2148 : : tree format_string_cst_,
2149 : : const char * const orig_format_chars_,
2150 : : location_t format_string_loc_,
2151 : : flag_chars_t &flag_chars_,
2152 : : int &has_operand_number_,
2153 : : tree first_fillin_param_,
2154 : : object_allocator <format_wanted_type> &fwt_pool_,
2155 : 52295 : vec<location_t> *arglocs_)
2156 : 52295 : : info (info_),
2157 : 52295 : fki (&format_types[info->format_type]),
2158 : 52295 : flag_specs (fki->flag_specs),
2159 : 52295 : start_of_this_format (format_chars_),
2160 : 52295 : format_chars (format_chars_),
2161 : 52295 : format_string_cst (format_string_cst_),
2162 : 52295 : orig_format_chars (orig_format_chars_),
2163 : 52295 : format_string_loc (format_string_loc_),
2164 : 52295 : fwt_pool (fwt_pool_),
2165 : 52295 : flag_chars (flag_chars_),
2166 : 52295 : main_arg_num (0),
2167 : 52295 : main_arg_params (NULL),
2168 : 52295 : has_operand_number (has_operand_number_),
2169 : 52295 : first_fillin_param (first_fillin_param_),
2170 : 52295 : first_wanted_type (NULL),
2171 : 52295 : last_wanted_type (NULL),
2172 : 52295 : arglocs (arglocs_)
2173 : : {
2174 : 52295 : }
2175 : :
2176 : : /* Handle dollars at the start of format arguments, setting up main_arg_params
2177 : : and main_arg_num.
2178 : :
2179 : : Return true if format parsing is to continue, false otherwise. */
2180 : :
2181 : : bool
2182 : 52295 : argument_parser::read_any_dollar ()
2183 : : {
2184 : 52295 : if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0)
2185 : : {
2186 : : /* Possibly read a $ operand number at the start of the format.
2187 : : If one was previously used, one is required here. If one
2188 : : is not used here, we can't immediately conclude this is a
2189 : : format without them, since it could be printf %m or scanf %*. */
2190 : 33818 : int opnum;
2191 : 67636 : opnum = maybe_read_dollar_number (&format_chars, 0,
2192 : 33818 : first_fillin_param,
2193 : : &main_arg_params, fki);
2194 : 33818 : if (opnum == -1)
2195 : : return false;
2196 : 33812 : else if (opnum > 0)
2197 : : {
2198 : 167 : has_operand_number = 1;
2199 : 167 : main_arg_num = opnum + info->first_arg_num - 1;
2200 : : }
2201 : : }
2202 : 18477 : else if (fki->flags & FMT_FLAG_USE_DOLLAR)
2203 : : {
2204 : 15753 : if (avoid_dollar_number (format_chars))
2205 : : return false;
2206 : : }
2207 : : return true;
2208 : : }
2209 : :
2210 : : /* Read any format flags, but do not yet validate them beyond removing
2211 : : duplicates, since in general validation depends on the rest of
2212 : : the format.
2213 : :
2214 : : Return true if format parsing is to continue, false otherwise. */
2215 : :
2216 : : bool
2217 : 52285 : argument_parser::read_format_flags ()
2218 : : {
2219 : 52285 : while (*format_chars != 0
2220 : 55381 : && strchr (fki->flag_chars, *format_chars) != 0)
2221 : : {
2222 : 3098 : const format_flag_spec *s = get_flag_spec (flag_specs,
2223 : : *format_chars, NULL);
2224 : 3098 : if (flag_chars.has_char_p (*format_chars))
2225 : : {
2226 : 17 : format_warning_at_char (format_string_loc, format_string_cst,
2227 : 17 : format_chars + 1 - orig_format_chars,
2228 : : OPT_Wformat_,
2229 : 17 : "repeated %s in format", _(s->name));
2230 : : }
2231 : : else
2232 : 3081 : flag_chars.add_char (*format_chars);
2233 : :
2234 : 3098 : if (s->skip_next_char)
2235 : : {
2236 : 16 : ++format_chars;
2237 : 16 : if (*format_chars == 0)
2238 : : {
2239 : 2 : warning_at (format_string_loc, OPT_Wformat_,
2240 : : "missing fill character at end of strfmon format");
2241 : 2 : return false;
2242 : : }
2243 : : }
2244 : 3096 : ++format_chars;
2245 : : }
2246 : :
2247 : : return true;
2248 : : }
2249 : :
2250 : : /* Read any format width, possibly * or *m$.
2251 : :
2252 : : Return true if format parsing is to continue, false otherwise. */
2253 : :
2254 : : bool
2255 : 52283 : argument_parser::
2256 : : read_any_format_width (tree ¶ms,
2257 : : unsigned HOST_WIDE_INT &arg_num)
2258 : : {
2259 : 52283 : if (!fki->width_char)
2260 : : return true;
2261 : :
2262 : 50661 : if (fki->width_type != NULL && *format_chars == '*')
2263 : : {
2264 : 771 : flag_chars.add_char (fki->width_char);
2265 : : /* "...a field width...may be indicated by an asterisk.
2266 : : In this case, an int argument supplies the field width..." */
2267 : 771 : ++format_chars;
2268 : 771 : if (has_operand_number != 0)
2269 : : {
2270 : 720 : int opnum;
2271 : 1440 : opnum = maybe_read_dollar_number (&format_chars,
2272 : : has_operand_number == 1,
2273 : 720 : first_fillin_param,
2274 : 720 : ¶ms, fki);
2275 : 720 : if (opnum == -1)
2276 : : return false;
2277 : 718 : else if (opnum > 0)
2278 : : {
2279 : 16 : has_operand_number = 1;
2280 : 16 : arg_num = opnum + info->first_arg_num - 1;
2281 : : }
2282 : : else
2283 : 702 : has_operand_number = 0;
2284 : : }
2285 : : else
2286 : : {
2287 : 51 : if (avoid_dollar_number (format_chars))
2288 : : return false;
2289 : : }
2290 : 767 : if (info->first_arg_num != 0)
2291 : : {
2292 : 755 : tree cur_param;
2293 : 755 : if (params == 0)
2294 : : cur_param = NULL;
2295 : : else
2296 : : {
2297 : 753 : cur_param = TREE_VALUE (params);
2298 : 753 : if (has_operand_number <= 0)
2299 : : {
2300 : 737 : params = TREE_CHAIN (params);
2301 : 737 : ++arg_num;
2302 : : }
2303 : : }
2304 : 755 : width_wanted_type.wanted_type = *fki->width_type;
2305 : 755 : width_wanted_type.wanted_type_name = NULL;
2306 : 755 : width_wanted_type.pointer_count = 0;
2307 : 755 : width_wanted_type.char_lenient_flag = 0;
2308 : 755 : width_wanted_type.scalar_identity_flag = 0;
2309 : 755 : width_wanted_type.writing_in_flag = 0;
2310 : 755 : width_wanted_type.reading_from_flag = 0;
2311 : 755 : width_wanted_type.kind = CF_KIND_FIELD_WIDTH;
2312 : 755 : width_wanted_type.format_start = format_chars - 1;
2313 : 755 : width_wanted_type.format_length = 1;
2314 : 755 : width_wanted_type.param = cur_param;
2315 : 755 : width_wanted_type.arg_num = arg_num;
2316 : 755 : width_wanted_type.offset_loc =
2317 : 755 : format_chars - orig_format_chars;
2318 : 755 : width_wanted_type.next = NULL;
2319 : 755 : if (last_wanted_type != 0)
2320 : 0 : last_wanted_type->next = &width_wanted_type;
2321 : 755 : if (first_wanted_type == 0)
2322 : 755 : first_wanted_type = &width_wanted_type;
2323 : 755 : last_wanted_type = &width_wanted_type;
2324 : : }
2325 : : }
2326 : : else
2327 : : {
2328 : : /* Possibly read a numeric width. If the width is zero,
2329 : : we complain if appropriate. */
2330 : : int non_zero_width_char = false;
2331 : : int found_width = false;
2332 : 52223 : while (ISDIGIT (*format_chars))
2333 : : {
2334 : 2333 : found_width = true;
2335 : 2333 : if (*format_chars != '0')
2336 : 2276 : non_zero_width_char = true;
2337 : 2333 : ++format_chars;
2338 : : }
2339 : 49890 : if (found_width && !non_zero_width_char &&
2340 : 6 : (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD))
2341 : 4 : warning_at (format_string_loc, OPT_Wformat_,
2342 : 4 : "zero width in %s format", fki->name);
2343 : 49890 : if (found_width)
2344 : 1420 : flag_chars.add_char (fki->width_char);
2345 : : }
2346 : :
2347 : : return true;
2348 : : }
2349 : :
2350 : : /* Read any format left precision (must be a number, not *). */
2351 : : void
2352 : 52279 : argument_parser::read_any_format_left_precision ()
2353 : : {
2354 : 52279 : if (fki->left_precision_char == 0)
2355 : : return;
2356 : 118 : if (*format_chars != '#')
2357 : : return;
2358 : :
2359 : 60 : ++format_chars;
2360 : 60 : flag_chars.add_char (fki->left_precision_char);
2361 : 60 : if (!ISDIGIT (*format_chars))
2362 : 8 : format_warning_at_char (format_string_loc, format_string_cst,
2363 : 8 : format_chars - orig_format_chars,
2364 : : OPT_Wformat_,
2365 : 8 : "empty left precision in %s format", fki->name);
2366 : 112 : while (ISDIGIT (*format_chars))
2367 : 52 : ++format_chars;
2368 : : }
2369 : :
2370 : : /* Read any format precision, possibly * or *m$.
2371 : :
2372 : : Return true if format parsing is to continue, false otherwise. */
2373 : :
2374 : : bool
2375 : 52279 : argument_parser::
2376 : : read_any_format_precision (tree ¶ms,
2377 : : unsigned HOST_WIDE_INT &arg_num)
2378 : : {
2379 : 52279 : if (fki->precision_char == 0)
2380 : : return true;
2381 : 49237 : if (*format_chars != '.')
2382 : : return true;
2383 : :
2384 : 1636 : ++format_chars;
2385 : 1636 : flag_chars.add_char (fki->precision_char);
2386 : 1636 : if (fki->precision_type != NULL && *format_chars == '*')
2387 : : {
2388 : : /* "...a...precision...may be indicated by an asterisk.
2389 : : In this case, an int argument supplies the...precision." */
2390 : 816 : ++format_chars;
2391 : 816 : if (has_operand_number != 0)
2392 : : {
2393 : 559 : int opnum;
2394 : 1118 : opnum = maybe_read_dollar_number (&format_chars,
2395 : : has_operand_number == 1,
2396 : 559 : first_fillin_param,
2397 : : ¶ms, fki);
2398 : 559 : if (opnum == -1)
2399 : : return false;
2400 : 559 : else if (opnum > 0)
2401 : : {
2402 : 8 : has_operand_number = 1;
2403 : 8 : arg_num = opnum + info->first_arg_num - 1;
2404 : : }
2405 : : else
2406 : 551 : has_operand_number = 0;
2407 : : }
2408 : : else
2409 : : {
2410 : 257 : if (avoid_dollar_number (format_chars))
2411 : : return false;
2412 : : }
2413 : 814 : if (info->first_arg_num != 0)
2414 : : {
2415 : 793 : tree cur_param;
2416 : 793 : if (params == 0)
2417 : : cur_param = NULL;
2418 : : else
2419 : : {
2420 : 791 : cur_param = TREE_VALUE (params);
2421 : 791 : if (has_operand_number <= 0)
2422 : : {
2423 : 783 : params = TREE_CHAIN (params);
2424 : 783 : ++arg_num;
2425 : : }
2426 : : }
2427 : 793 : precision_wanted_type.wanted_type = *fki->precision_type;
2428 : 793 : precision_wanted_type.wanted_type_name = NULL;
2429 : 793 : precision_wanted_type.pointer_count = 0;
2430 : 793 : precision_wanted_type.char_lenient_flag = 0;
2431 : 793 : precision_wanted_type.scalar_identity_flag = 0;
2432 : 793 : precision_wanted_type.writing_in_flag = 0;
2433 : 793 : precision_wanted_type.reading_from_flag = 0;
2434 : 793 : precision_wanted_type.kind = CF_KIND_FIELD_PRECISION;
2435 : 793 : precision_wanted_type.param = cur_param;
2436 : 793 : precision_wanted_type.format_start = format_chars - 2;
2437 : 793 : precision_wanted_type.format_length = 2;
2438 : 793 : precision_wanted_type.arg_num = arg_num;
2439 : 793 : precision_wanted_type.offset_loc =
2440 : 793 : format_chars - orig_format_chars;
2441 : 793 : precision_wanted_type.next = NULL;
2442 : 793 : if (last_wanted_type != 0)
2443 : 176 : last_wanted_type->next = &precision_wanted_type;
2444 : 793 : if (first_wanted_type == 0)
2445 : 617 : first_wanted_type = &precision_wanted_type;
2446 : 793 : last_wanted_type = &precision_wanted_type;
2447 : : }
2448 : : }
2449 : : else
2450 : : {
2451 : 820 : if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK)
2452 : 52 : && !ISDIGIT (*format_chars))
2453 : 8 : format_warning_at_char (format_string_loc, format_string_cst,
2454 : 8 : format_chars - orig_format_chars,
2455 : : OPT_Wformat_,
2456 : 8 : "empty precision in %s format", fki->name);
2457 : 1678 : while (ISDIGIT (*format_chars))
2458 : 858 : ++format_chars;
2459 : : }
2460 : :
2461 : : return true;
2462 : : }
2463 : :
2464 : : /* Parse any assignment-allocation flags, which request an extra
2465 : : char ** for writing back a dynamically-allocated char *.
2466 : : This is for handling the optional 'm' character in scanf,
2467 : : and, before C99, 'a' (for compatibility with a non-standard
2468 : : GNU libc extension). */
2469 : :
2470 : : void
2471 : 52277 : argument_parser::handle_alloc_chars ()
2472 : : {
2473 : 52277 : if (fki->alloc_char && fki->alloc_char == *format_chars)
2474 : : {
2475 : 194 : flag_chars.add_char (fki->alloc_char);
2476 : 194 : format_chars++;
2477 : : }
2478 : :
2479 : : /* Handle the scanf allocation kludge. */
2480 : 52277 : if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
2481 : : {
2482 : 2178 : if (*format_chars == 'a' && !flag_isoc99)
2483 : : {
2484 : 44 : if (format_chars[1] == 's' || format_chars[1] == 'S'
2485 : : || format_chars[1] == '[')
2486 : : {
2487 : : /* 'a' is used as a flag. */
2488 : 42 : flag_chars.add_char ('a');
2489 : 42 : format_chars++;
2490 : : }
2491 : : }
2492 : : }
2493 : 52277 : }
2494 : :
2495 : : /* Look for length modifiers within the current format argument,
2496 : : returning a length_modifier instance describing it (or the
2497 : : default if one is not found).
2498 : :
2499 : : Issue warnings about non-standard modifiers. */
2500 : :
2501 : : length_modifier
2502 : 52277 : argument_parser::read_any_length_modifier ()
2503 : : {
2504 : 52277 : length_modifier result;
2505 : :
2506 : 52277 : const format_length_info *fli = fki->length_char_specs;
2507 : 52277 : if (!fli)
2508 : : return result;
2509 : :
2510 : 652202 : while (fli->name != 0
2511 : 652202 : && strncmp (fli->name, format_chars, strlen (fli->name)))
2512 : 600739 : fli++;
2513 : 51463 : if (fli->name != 0)
2514 : : {
2515 : 19122 : format_chars += strlen (fli->name);
2516 : 19122 : if (fli->double_name != 0 && fli->name[0] == *format_chars)
2517 : : {
2518 : 1378 : format_chars++;
2519 : 1378 : result = length_modifier (fli->double_name, fli->double_index,
2520 : 1378 : fli->double_std, 0);
2521 : : }
2522 : : else
2523 : : {
2524 : 17744 : result = length_modifier (fli->name, fli->index, fli->std,
2525 : 17744 : fli->scalar_identity_flag);
2526 : : }
2527 : 19122 : flag_chars.add_char (fki->length_code_char);
2528 : : }
2529 : 51463 : if (pedantic)
2530 : : {
2531 : : /* Warn if the length modifier is non-standard. */
2532 : 11064 : if (ADJ_STD (result.std) > C_STD_VER)
2533 : 240 : warning_at (format_string_loc, OPT_Wformat_,
2534 : : "%s does not support the %qs %s length modifier",
2535 : 240 : C_STD_NAME (result.std), result.chars,
2536 : 240 : fki->name);
2537 : : }
2538 : :
2539 : : return result;
2540 : : }
2541 : :
2542 : : /* Read any other modifier (strftime E/O). */
2543 : :
2544 : : void
2545 : 52277 : argument_parser::read_any_other_modifier ()
2546 : : {
2547 : 52277 : if (fki->modifier_chars == NULL)
2548 : : return;
2549 : :
2550 : 1008 : while (*format_chars != 0
2551 : 1008 : && strchr (fki->modifier_chars, *format_chars) != 0)
2552 : : {
2553 : 194 : if (flag_chars.has_char_p (*format_chars))
2554 : : {
2555 : 8 : const format_flag_spec *s = get_flag_spec (flag_specs,
2556 : 4 : *format_chars, NULL);
2557 : 4 : format_warning_at_char (format_string_loc, format_string_cst,
2558 : 4 : format_chars - orig_format_chars,
2559 : : OPT_Wformat_,
2560 : 4 : "repeated %s in format", _(s->name));
2561 : : }
2562 : : else
2563 : 190 : flag_chars.add_char (*format_chars);
2564 : 194 : ++format_chars;
2565 : : }
2566 : : }
2567 : :
2568 : : /* Return the format_char_info corresponding to FORMAT_CHAR,
2569 : : potentially issuing a warning if the format char is
2570 : : not supported in the C standard version we are checking
2571 : : against.
2572 : :
2573 : : Issue a warning and return NULL if it is not found.
2574 : :
2575 : : Issue warnings about non-standard modifiers. */
2576 : :
2577 : : const format_char_info *
2578 : 52235 : argument_parser::find_format_char_info (char format_char)
2579 : : {
2580 : 52235 : const format_char_info *fci = fki->conversion_specs;
2581 : :
2582 : 52235 : while (fci->format_chars != 0
2583 : 228192 : && strchr (fci->format_chars, format_char) == 0)
2584 : 175957 : ++fci;
2585 : 52235 : if (fci->format_chars == 0)
2586 : : {
2587 : 209 : format_warning_at_char (format_string_loc, format_string_cst,
2588 : 209 : format_chars - orig_format_chars,
2589 : : OPT_Wformat_,
2590 : : "unknown conversion type character"
2591 : : " %qc in format",
2592 : : format_char);
2593 : 209 : return NULL;
2594 : : }
2595 : :
2596 : 52026 : if (pedantic)
2597 : : {
2598 : 10978 : if (ADJ_STD (fci->std) > C_STD_VER)
2599 : 144 : format_warning_at_char (format_string_loc, format_string_cst,
2600 : 72 : format_chars - orig_format_chars,
2601 : : OPT_Wformat_,
2602 : : "%s does not support the %<%%%c%> %s format",
2603 : 72 : C_STD_NAME (fci->std), format_char, fki->name);
2604 : : }
2605 : :
2606 : : return fci;
2607 : : }
2608 : :
2609 : : /* Validate the pairs of flags used.
2610 : : Issue warnings about incompatible combinations of flags. */
2611 : :
2612 : : void
2613 : 52026 : argument_parser::validate_flag_pairs (const format_char_info *fci,
2614 : : char format_char)
2615 : : {
2616 : 52026 : const format_flag_pair * const bad_flag_pairs = fki->bad_flag_pairs;
2617 : :
2618 : 202882 : for (int i = 0; bad_flag_pairs[i].flag_char1 != 0; i++)
2619 : : {
2620 : 150856 : const format_flag_spec *s, *t;
2621 : 150856 : if (!flag_chars.has_char_p (bad_flag_pairs[i].flag_char1))
2622 : 149271 : continue;
2623 : 1585 : if (!flag_chars.has_char_p (bad_flag_pairs[i].flag_char2))
2624 : 1380 : continue;
2625 : 205 : if (bad_flag_pairs[i].predicate != 0
2626 : 74 : && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0)
2627 : 30 : continue;
2628 : 175 : s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL);
2629 : 175 : t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL);
2630 : 175 : if (bad_flag_pairs[i].ignored)
2631 : : {
2632 : 117 : if (bad_flag_pairs[i].predicate != 0)
2633 : 44 : warning_at (format_string_loc, OPT_Wformat_,
2634 : : "%s ignored with %s and %<%%%c%> %s format",
2635 : 44 : _(s->name), _(t->name), format_char,
2636 : 44 : fki->name);
2637 : : else
2638 : 73 : warning_at (format_string_loc, OPT_Wformat_,
2639 : : "%s ignored with %s in %s format",
2640 : 73 : _(s->name), _(t->name), fki->name);
2641 : : }
2642 : : else
2643 : : {
2644 : 58 : if (bad_flag_pairs[i].predicate != 0)
2645 : 0 : warning_at (format_string_loc, OPT_Wformat_,
2646 : : "use of %s and %s together with %<%%%c%> %s format",
2647 : 0 : _(s->name), _(t->name), format_char,
2648 : 0 : fki->name);
2649 : : else
2650 : 58 : warning_at (format_string_loc, OPT_Wformat_,
2651 : : "use of %s and %s together in %s format",
2652 : 58 : _(s->name), _(t->name), fki->name);
2653 : : }
2654 : : }
2655 : 52026 : }
2656 : :
2657 : : /* Give Y2K warnings. */
2658 : :
2659 : : void
2660 : 52026 : argument_parser::give_y2k_warnings (const format_char_info *fci,
2661 : : char format_char)
2662 : : {
2663 : 52026 : if (!warn_format_y2k)
2664 : : return;
2665 : :
2666 : 830 : int y2k_level = 0;
2667 : 830 : if (strchr (fci->flags2, '4') != 0)
2668 : 22 : if (flag_chars.has_char_p ('E'))
2669 : : y2k_level = 3;
2670 : : else
2671 : : y2k_level = 2;
2672 : 808 : else if (strchr (fci->flags2, '3') != 0)
2673 : : y2k_level = 3;
2674 : 768 : else if (strchr (fci->flags2, '2') != 0)
2675 : : y2k_level = 2;
2676 : : if (y2k_level == 3)
2677 : 46 : warning_at (format_string_loc, OPT_Wformat_y2k,
2678 : : "%<%%%c%> yields only last 2 digits of "
2679 : : "year in some locales", format_char);
2680 : 784 : else if (y2k_level == 2)
2681 : 56 : warning_at (format_string_loc, OPT_Wformat_y2k,
2682 : : "%<%%%c%> yields only last 2 digits of year",
2683 : : format_char);
2684 : : }
2685 : :
2686 : : /* Parse any "scan sets" enclosed in square brackets, e.g.
2687 : : for scanf-style calls. */
2688 : :
2689 : : void
2690 : 52026 : argument_parser::parse_any_scan_set (const format_char_info *fci)
2691 : : {
2692 : 52026 : if (strchr (fci->flags2, '[') == NULL)
2693 : : return;
2694 : :
2695 : : /* Skip over scan set, in case it happens to have '%' in it. */
2696 : 132 : if (*format_chars == '^')
2697 : 4 : ++format_chars;
2698 : : /* Find closing bracket; if one is hit immediately, then
2699 : : it's part of the scan set rather than a terminator. */
2700 : 132 : if (*format_chars == ']')
2701 : 6 : ++format_chars;
2702 : 498 : while (*format_chars && *format_chars != ']')
2703 : 366 : ++format_chars;
2704 : 132 : if (*format_chars != ']')
2705 : : /* The end of the format string was reached. */
2706 : 2 : format_warning_at_char (format_string_loc, format_string_cst,
2707 : 2 : format_chars - orig_format_chars,
2708 : : OPT_Wformat_,
2709 : : "no closing %<]%> for %<%%[%> format");
2710 : : }
2711 : :
2712 : : /* Return true if this argument is to be continued to be parsed,
2713 : : false to skip to next argument. */
2714 : :
2715 : : bool
2716 : 52026 : argument_parser::handle_conversions (const format_char_info *fci,
2717 : : const length_modifier &len_modifier,
2718 : : tree &wanted_type,
2719 : : const char *&wanted_type_name,
2720 : : unsigned HOST_WIDE_INT &arg_num,
2721 : : tree ¶ms,
2722 : : char format_char)
2723 : : {
2724 : 52026 : enum format_std_version wanted_type_std;
2725 : :
2726 : 52026 : if (!(fki->flags & (int) FMT_FLAG_ARG_CONVERT))
2727 : : return true;
2728 : :
2729 : 102424 : wanted_type = (fci->types[len_modifier.val].type
2730 : 51212 : ? *fci->types[len_modifier.val].type : 0);
2731 : 51212 : wanted_type_name = fci->types[len_modifier.val].name;
2732 : 51212 : wanted_type_std = fci->types[len_modifier.val].std;
2733 : 51212 : if (wanted_type == 0)
2734 : : {
2735 : 934 : format_warning_at_char (format_string_loc, format_string_cst,
2736 : 934 : format_chars - orig_format_chars,
2737 : : OPT_Wformat_,
2738 : : "use of %qs length modifier with %qc type"
2739 : : " character has either no effect"
2740 : : " or undefined behavior",
2741 : 934 : len_modifier.chars, format_char);
2742 : : /* Heuristic: skip one argument when an invalid length/type
2743 : : combination is encountered. */
2744 : 934 : arg_num++;
2745 : 934 : if (params != 0)
2746 : 934 : params = TREE_CHAIN (params);
2747 : 934 : return false;
2748 : : }
2749 : 50278 : else if (pedantic
2750 : : /* Warn if non-standard, provided it is more non-standard
2751 : : than the length and type characters that may already
2752 : : have been warned for. */
2753 : 10496 : && ADJ_STD (wanted_type_std) > ADJ_STD (len_modifier.std)
2754 : 372 : && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std))
2755 : : {
2756 : 195 : if (ADJ_STD (wanted_type_std) > C_STD_VER)
2757 : 215 : format_warning_at_char (format_string_loc, format_string_cst,
2758 : 107 : format_chars - orig_format_chars,
2759 : : OPT_Wformat_,
2760 : : "%s does not support the %<%%%s%c%> %s format",
2761 : 107 : C_STD_NAME (wanted_type_std),
2762 : 107 : len_modifier.chars,
2763 : 107 : format_char, fki->name);
2764 : : }
2765 : :
2766 : : return true;
2767 : : }
2768 : :
2769 : : /* Check type of argument against desired type.
2770 : :
2771 : : Return true if format parsing is to continue, false otherwise. */
2772 : :
2773 : : bool
2774 : 51092 : argument_parser::
2775 : : check_argument_type (const format_char_info *fci,
2776 : : const length_modifier &len_modifier,
2777 : : tree &wanted_type,
2778 : : const char *&wanted_type_name,
2779 : : const bool suppressed,
2780 : : unsigned HOST_WIDE_INT &arg_num,
2781 : : tree ¶ms,
2782 : : const int alloc_flag,
2783 : : const char * const format_start,
2784 : : const char * const type_start,
2785 : : location_t fmt_param_loc,
2786 : : char conversion_char)
2787 : : {
2788 : 51092 : if (info->first_arg_num == 0)
2789 : : return true;
2790 : :
2791 : 49916 : if ((fci->pointer_count == 0 && wanted_type == void_type_node)
2792 : 49314 : || suppressed)
2793 : : {
2794 : 782 : if (main_arg_num != 0)
2795 : : {
2796 : 4 : if (suppressed)
2797 : 2 : warning_at (format_string_loc, OPT_Wformat_,
2798 : : "operand number specified with "
2799 : : "suppressed assignment");
2800 : : else
2801 : 2 : warning_at (format_string_loc, OPT_Wformat_,
2802 : : "operand number specified for format "
2803 : : "taking no argument");
2804 : : }
2805 : : }
2806 : : else
2807 : : {
2808 : 49134 : format_wanted_type *wanted_type_ptr;
2809 : :
2810 : 49134 : if (main_arg_num != 0)
2811 : : {
2812 : 145 : arg_num = main_arg_num;
2813 : 145 : params = main_arg_params;
2814 : : }
2815 : : else
2816 : : {
2817 : 48989 : ++arg_num;
2818 : 48989 : if (has_operand_number > 0)
2819 : : {
2820 : 6 : warning_at (format_string_loc, OPT_Wformat_,
2821 : : "missing $ operand number in format");
2822 : 6 : return false;
2823 : : }
2824 : : else
2825 : 48983 : has_operand_number = 0;
2826 : : }
2827 : :
2828 : 49128 : wanted_type_ptr = &main_wanted_type;
2829 : 49128 : while (fci)
2830 : : {
2831 : 49140 : tree cur_param;
2832 : 49140 : if (params == 0)
2833 : : cur_param = NULL;
2834 : : else
2835 : : {
2836 : 49079 : cur_param = TREE_VALUE (params);
2837 : 49079 : params = TREE_CHAIN (params);
2838 : : }
2839 : :
2840 : 49140 : wanted_type_ptr->wanted_type = wanted_type;
2841 : 49140 : wanted_type_ptr->wanted_type_name = wanted_type_name;
2842 : 49140 : wanted_type_ptr->pointer_count = fci->pointer_count + alloc_flag;
2843 : 49140 : wanted_type_ptr->char_lenient_flag = 0;
2844 : 49140 : if (strchr (fci->flags2, 'c') != 0)
2845 : 19853 : wanted_type_ptr->char_lenient_flag = 1;
2846 : 49140 : wanted_type_ptr->scalar_identity_flag = 0;
2847 : 49140 : if (len_modifier.scalar_identity_flag)
2848 : 0 : wanted_type_ptr->scalar_identity_flag = 1;
2849 : 49140 : wanted_type_ptr->writing_in_flag = 0;
2850 : 49140 : wanted_type_ptr->reading_from_flag = 0;
2851 : 49140 : if (alloc_flag)
2852 : 114 : wanted_type_ptr->writing_in_flag = 1;
2853 : : else
2854 : : {
2855 : 49026 : if (strchr (fci->flags2, 'W') != 0)
2856 : 1471 : wanted_type_ptr->writing_in_flag = 1;
2857 : 49026 : if (strchr (fci->flags2, 'R') != 0)
2858 : 18459 : wanted_type_ptr->reading_from_flag = 1;
2859 : : }
2860 : 49140 : wanted_type_ptr->kind = CF_KIND_FORMAT;
2861 : 49140 : wanted_type_ptr->param = cur_param;
2862 : 49140 : wanted_type_ptr->arg_num = arg_num;
2863 : 49140 : wanted_type_ptr->format_start = format_start;
2864 : 49140 : wanted_type_ptr->format_length = format_chars - format_start;
2865 : 49140 : wanted_type_ptr->offset_loc = format_chars - orig_format_chars;
2866 : 49140 : wanted_type_ptr->next = NULL;
2867 : 49140 : if (last_wanted_type != 0)
2868 : 1367 : last_wanted_type->next = wanted_type_ptr;
2869 : 49140 : if (first_wanted_type == 0)
2870 : 47773 : first_wanted_type = wanted_type_ptr;
2871 : 49140 : last_wanted_type = wanted_type_ptr;
2872 : :
2873 : 49140 : fci = fci->chain;
2874 : 49140 : if (fci)
2875 : : {
2876 : 12 : wanted_type_ptr = fwt_pool.allocate ();
2877 : 12 : arg_num++;
2878 : 12 : wanted_type = *fci->types[len_modifier.val].type;
2879 : 12 : wanted_type_name = fci->types[len_modifier.val].name;
2880 : : }
2881 : : }
2882 : : }
2883 : :
2884 : 49910 : if (first_wanted_type != 0)
2885 : : {
2886 : 49142 : ptrdiff_t offset_to_format_start = (start_of_this_format - 1) - orig_format_chars;
2887 : 49142 : ptrdiff_t offset_to_format_end = (format_chars - 1) - orig_format_chars;
2888 : : /* By default, use the end of the range for the caret location. */
2889 : 49142 : substring_loc fmt_loc (fmt_param_loc, TREE_TYPE (format_string_cst),
2890 : : offset_to_format_end,
2891 : 49142 : offset_to_format_start, offset_to_format_end);
2892 : 49142 : ptrdiff_t offset_to_type_start = type_start - orig_format_chars;
2893 : 49142 : check_format_types (fmt_loc, first_wanted_type, fki,
2894 : : offset_to_type_start,
2895 : : conversion_char, arglocs);
2896 : : }
2897 : :
2898 : : return true;
2899 : : }
2900 : :
2901 : : /* Describes "paired tokens" within the format string that are
2902 : : expected to be balanced. */
2903 : :
2904 : : class baltoks_t
2905 : : {
2906 : : public:
2907 : 42893 : baltoks_t (): singlequote (), doublequote () { }
2908 : :
2909 : : typedef auto_vec<const char *> balanced_tokens_t;
2910 : : /* Vectors of pointers to opening brackets ('['), curly brackets ('{'),
2911 : : quoting directives (like GCC "%<"), parentheses, and angle brackets
2912 : : ('<'). Used to detect unbalanced tokens. */
2913 : : balanced_tokens_t brackets;
2914 : : balanced_tokens_t curly;
2915 : : balanced_tokens_t quotdirs;
2916 : : balanced_tokens_t parens;
2917 : : balanced_tokens_t pointy;
2918 : : /* Pointer to the last opening quote. */
2919 : : const char *singlequote;
2920 : : const char *doublequote;
2921 : : };
2922 : :
2923 : : /* Describes a keyword, operator, or other name. */
2924 : :
2925 : : struct token_t
2926 : : {
2927 : : const char *name; /* Keyword/operator name. */
2928 : : unsigned char len; /* Its length. */
2929 : : const char *alt; /* Alternate spelling. */
2930 : : };
2931 : :
2932 : : /* Helper for initializing global token_t arrays below. */
2933 : : #define NAME(name) { name, sizeof name - 1, NULL }
2934 : :
2935 : : /* C/C++ operators that are expected to be quoted within the format
2936 : : string. */
2937 : :
2938 : : static const token_t c_opers[] =
2939 : : {
2940 : : NAME ("!="), NAME ("%="), NAME ("&&"), NAME ("&="), NAME ("*="),
2941 : : NAME ("++"), NAME ("+="), NAME ("--"), NAME ("-="), NAME ("->"),
2942 : : NAME ("/="), NAME ("<<"), NAME ("<<="), NAME ("<="), NAME ("=="),
2943 : : NAME (">="), NAME (">>="), NAME (">>"), NAME ("?:"), NAME ("^="),
2944 : : NAME ("|="), NAME ("||")
2945 : : };
2946 : :
2947 : : static const token_t cxx_opers[] =
2948 : : {
2949 : : NAME ("->*"), NAME (".*"), NAME ("::"), NAME ("<=>")
2950 : : };
2951 : :
2952 : : /* Common C/C++ keywords that are expected to be quoted within the format
2953 : : string. Keywords like auto, inline, or volatile are excluded because
2954 : : they are sometimes used in common terms like /auto variables/, /inline
2955 : : function/, or /volatile access/ where they should not be quoted. */
2956 : :
2957 : : static const token_t c_keywords[] =
2958 : : {
2959 : : #undef NAME
2960 : : #define NAME(name, alt) { name, sizeof name - 1, alt }
2961 : :
2962 : : NAME ("alignas", NULL),
2963 : : NAME ("alignof", NULL),
2964 : : NAME ("asm", NULL),
2965 : : NAME ("bool", NULL),
2966 : : NAME ("char", NULL),
2967 : : NAME ("const %", NULL),
2968 : : NAME ("const-qualified", "%<const%>-qualified"),
2969 : : NAME ("float", NULL),
2970 : : NAME ("ifunc", NULL),
2971 : : NAME ("int", NULL),
2972 : : NAME ("long double", NULL),
2973 : : NAME ("long int", NULL),
2974 : : NAME ("long long", NULL),
2975 : : NAME ("malloc", NULL),
2976 : : NAME ("noclone", NULL),
2977 : : NAME ("noinline", NULL),
2978 : : NAME ("nonnull", NULL),
2979 : : NAME ("noreturn", NULL),
2980 : : NAME ("offsetof", NULL),
2981 : : NAME ("readonly", "read-only"),
2982 : : NAME ("readwrite", "read-write"),
2983 : : NAME ("restrict %", NULL),
2984 : : NAME ("restrict-qualified", "%<restrict%>-qualified"),
2985 : : NAME ("short int", NULL),
2986 : : NAME ("signed char", NULL),
2987 : : NAME ("signed int", NULL),
2988 : : NAME ("signed long", NULL),
2989 : : NAME ("signed short", NULL),
2990 : : NAME ("sizeof", NULL),
2991 : : NAME ("typeof", NULL),
2992 : : NAME ("unsigned char", NULL),
2993 : : NAME ("unsigned int", NULL),
2994 : : NAME ("unsigned long", NULL),
2995 : : NAME ("unsigned short", NULL),
2996 : : NAME ("volatile %", NULL),
2997 : : NAME ("volatile-qualified", "%<volatile%>-qualified"),
2998 : : NAME ("weakref", NULL),
2999 : : };
3000 : :
3001 : : static const token_t cxx_keywords[] =
3002 : : {
3003 : : /* C++ only keywords and operators. */
3004 : : NAME ("catch", NULL),
3005 : : NAME ("constexpr if", NULL),
3006 : : NAME ("constexpr", NULL),
3007 : : NAME ("constinit", NULL),
3008 : : NAME ("consteval", NULL),
3009 : : NAME ("decltype", NULL),
3010 : : NAME ("nullptr", NULL),
3011 : : NAME ("operator delete", NULL),
3012 : : NAME ("operator new", NULL),
3013 : : NAME ("typeid", NULL),
3014 : : NAME ("typeinfo", NULL)
3015 : : };
3016 : :
3017 : : /* Blacklisted words such as misspellings that should be avoided in favor
3018 : : of the specified alternatives. */
3019 : : static const struct
3020 : : {
3021 : : const char *name; /* Bad word. */
3022 : : unsigned char len; /* Its length. */
3023 : : const char *alt; /* Preferred alternative. */
3024 : : } badwords[] =
3025 : : {
3026 : : NAME ("arg", "argument"),
3027 : : NAME ("bitfield", "bit-field"),
3028 : : NAME ("builtin function", "built-in function"),
3029 : : NAME ("can not", "cannot"),
3030 : : NAME ("commandline option", "command-line option"),
3031 : : NAME ("commandline", "command line"),
3032 : : NAME ("command line option", "command-line option"),
3033 : : NAME ("decl", "declaration"),
3034 : : NAME ("enumeral", "enumerated"),
3035 : : NAME ("floating point", "floating-point"),
3036 : : NAME ("nonstatic", "non-static"),
3037 : : NAME ("non-zero", "nonzero"),
3038 : : NAME ("reg", "register"),
3039 : : NAME ("stmt", "statement"),
3040 : : };
3041 : :
3042 : : /* Common contractions that should be avoided in favor of the specified
3043 : : alternatives. */
3044 : :
3045 : : static const struct
3046 : : {
3047 : : const char *name; /* Contraction. */
3048 : : unsigned char len; /* Its length. */
3049 : : const char *alt; /* Preferred alternative. */
3050 : : } contrs[] =
3051 : : {
3052 : : NAME ("can't", "cannot"),
3053 : : NAME ("didn't", "did not"),
3054 : : /* These are commonly abused. Avoid diagnosing them for now.
3055 : : NAME ("isn't", "is not"),
3056 : : NAME ("don't", "is not"),
3057 : : */
3058 : : NAME ("mustn't", "must not"),
3059 : : NAME ("needn't", "need not"),
3060 : : NAME ("should't", "should not"),
3061 : : NAME ("that's", "that is"),
3062 : : NAME ("there's", "there is"),
3063 : : NAME ("they're", "they are"),
3064 : : NAME ("what's", "what is"),
3065 : : NAME ("won't", "will not")
3066 : : };
3067 : :
3068 : : /* Check for unquoted TOKENS. FORMAT_STRING_LOC is the location of
3069 : : the format string, FORMAT_STRING_CST the format string itself (as
3070 : : a tree), ORIG_FORMAT_CHARS and FORMAT_CHARS are pointers to
3071 : : the beginning of the format string and the character currently
3072 : : being processed, and BALTOKS describes paired "tokens" within
3073 : : the format string that are expected to be balanced.
3074 : : Returns a pointer to the last processed character or null when
3075 : : nothing was done. */
3076 : :
3077 : : static const char*
3078 : 1656 : check_tokens (const token_t *tokens, unsigned ntoks,
3079 : : location_t format_string_loc, tree format_string_cst,
3080 : : const char *orig_format_chars, const char *format_chars,
3081 : : baltoks_t &baltoks)
3082 : : {
3083 : : /* For brevity. */
3084 : 1656 : const int opt = OPT_Wformat_diag;
3085 : : /* Zero-based starting position of a problem sequence. */
3086 : 1656 : int fmtchrpos = format_chars - orig_format_chars;
3087 : :
3088 : : /* For identifier-like "words," set to the word length. */
3089 : 1656 : unsigned wlen = 0;
3090 : : /* Set for an operator, clear for an identifier/word. */
3091 : 1656 : bool is_oper = false;
3092 : 1656 : bool underscore = false;
3093 : :
3094 : 1656 : if (format_chars[0] == '_' || ISALPHA (format_chars[0]))
3095 : : {
3096 : 5574 : while (format_chars[wlen] == '_' || ISALNUM (format_chars[wlen]))
3097 : : {
3098 : 4464 : underscore |= format_chars[wlen] == '_';
3099 : 4464 : ++wlen;
3100 : : }
3101 : : }
3102 : : else
3103 : : is_oper = true;
3104 : :
3105 : 47420 : for (unsigned i = 0; i != ntoks; ++i)
3106 : : {
3107 : 45822 : unsigned toklen = tokens[i].len;
3108 : :
3109 : 45822 : if (toklen < wlen
3110 : 41536 : || strncmp (format_chars, tokens[i].name, toklen))
3111 : 45764 : continue;
3112 : :
3113 : 58 : if (toklen == 2
3114 : 20 : && format_chars - orig_format_chars > 0
3115 : 14 : && (TOUPPER (format_chars[-1]) == 'C'
3116 : 14 : || TOUPPER (format_chars[-1]) == 'G'))
3117 : 0 : return format_chars + toklen - 1; /* Reference to C++ or G++. */
3118 : :
3119 : 58 : if (ISPUNCT (format_chars[toklen - 1]))
3120 : : {
3121 : 32 : if (format_chars[toklen - 1] == format_chars[toklen])
3122 : : return NULL; /* Operator followed by another punctuator. */
3123 : : }
3124 : 26 : else if (ISALNUM (format_chars[toklen]))
3125 : : return NULL; /* Keyword prefix for a longer word. */
3126 : :
3127 : 56 : if (toklen == 2
3128 : 20 : && format_chars[0] == '-'
3129 : 4 : && format_chars[1] == '-'
3130 : 4 : && ISALNUM (format_chars[2]))
3131 : : return NULL; /* Probably option like --help. */
3132 : :
3133 : : /* Allow this ugly warning for the time being. */
3134 : 18 : if (toklen == 2
3135 : 18 : && format_chars - orig_format_chars > 6
3136 : 4 : && startswith (format_chars - 7, " count >= width of "))
3137 : 0 : return format_chars + 10;
3138 : :
3139 : : /* The token is a type if it ends in an alphabetic character. */
3140 : 108 : bool is_type = (ISALPHA (tokens[i].name[toklen - 1])
3141 : 54 : && strchr (tokens[i].name, ' '));
3142 : :
3143 : : /* Backtrack to the last alphabetic character (for tokens whose
3144 : : names end in '%'). */
3145 : 54 : if (!is_oper)
3146 : 60 : while (!ISALPHA (tokens[i].name[toklen - 1]))
3147 : : --toklen;
3148 : :
3149 : 54 : if (format_warning_substr (format_string_loc, format_string_cst,
3150 : 54 : fmtchrpos, fmtchrpos + toklen, opt,
3151 : : (is_type
3152 : : ? G_("unquoted type name %<%.*s%> in format")
3153 : : : (is_oper
3154 : 46 : ? G_("unquoted operator %<%.*s%> in format")
3155 : : : G_("unquoted keyword %<%.*s%> in format"))),
3156 : : toklen, format_chars)
3157 : 54 : && tokens[i].alt)
3158 : 2 : inform (format_string_loc, "use %qs instead", tokens[i].alt);
3159 : :
3160 : 54 : return format_chars + toklen - 1;
3161 : : }
3162 : :
3163 : : /* Diagnose unquoted __attribute__. Consider any parenthesized
3164 : : argument to the attribute to avoid redundant warnings for
3165 : : the double parentheses that might follow. */
3166 : 1598 : if (startswith (format_chars, "__attribute"))
3167 : : {
3168 : : unsigned nchars = sizeof "__attribute" - 1;
3169 : 38 : while ('_' == format_chars[nchars])
3170 : 24 : ++nchars;
3171 : :
3172 : 28 : for (int i = nchars; format_chars[i]; ++i)
3173 : 28 : if (' ' != format_chars[i])
3174 : : {
3175 : 14 : nchars = i;
3176 : 14 : break;
3177 : : }
3178 : :
3179 : 14 : if (format_chars[nchars] == '(')
3180 : : {
3181 : 12 : baltoks.parens.safe_push (format_chars + nchars);
3182 : :
3183 : 12 : ++nchars;
3184 : 12 : bool close = false;
3185 : 12 : if (format_chars[nchars] == '(')
3186 : : {
3187 : 8 : baltoks.parens.safe_push (format_chars + nchars);
3188 : 8 : close = true;
3189 : 8 : ++nchars;
3190 : : }
3191 : 56 : for (int i = nchars; format_chars[i]; ++i)
3192 : 54 : if (')' == format_chars[i])
3193 : : {
3194 : 10 : if (baltoks.parens.length () > 0)
3195 : 10 : baltoks.parens.pop ();
3196 : 10 : nchars = i + 1;
3197 : 10 : break;
3198 : : }
3199 : :
3200 : 12 : if (close && format_chars[nchars] == ')')
3201 : : {
3202 : 4 : if (baltoks.parens.length () > 0)
3203 : 4 : baltoks.parens.pop ();
3204 : 4 : ++nchars;
3205 : : }
3206 : : }
3207 : :
3208 : 14 : format_warning_substr (format_string_loc, format_string_cst,
3209 : 14 : fmtchrpos, fmtchrpos + nchars, opt,
3210 : : "unquoted attribute in format");
3211 : 14 : return format_chars + nchars - 1;
3212 : : }
3213 : :
3214 : : /* Diagnose unquoted built-ins. */
3215 : 1584 : if (format_chars[0] == '_'
3216 : 16 : && format_chars[1] == '_'
3217 : 1594 : && (startswith (format_chars + 2, "atomic")
3218 : 10 : || startswith (format_chars + 2, "builtin")
3219 : 2 : || startswith (format_chars + 2, "sync")))
3220 : : {
3221 : 8 : format_warning_substr (format_string_loc, format_string_cst,
3222 : 8 : fmtchrpos, fmtchrpos + wlen, opt,
3223 : : "unquoted name of built-in function %<%.*s%> "
3224 : : "in format",
3225 : : wlen, format_chars);
3226 : 8 : return format_chars + wlen - 1;
3227 : : }
3228 : :
3229 : : /* Diagnose unquoted substrings of alphanumeric characters containing
3230 : : underscores. They most likely refer to identifiers and should be
3231 : : quoted. */
3232 : 1576 : if (underscore)
3233 : 22 : format_warning_substr (format_string_loc, format_string_cst,
3234 : : format_chars - orig_format_chars,
3235 : 22 : format_chars + wlen - orig_format_chars,
3236 : : opt,
3237 : : "unquoted identifier or keyword %<%.*s%> in format",
3238 : : wlen, format_chars);
3239 : : else
3240 : : {
3241 : : /* Diagnose some common misspellings. */
3242 : 22852 : for (unsigned i = 0; i != ARRAY_SIZE (badwords); ++i)
3243 : : {
3244 : 21340 : unsigned badwlen = strspn (badwords[i].name, " -");
3245 : 21340 : if (wlen >= badwlen
3246 : 21340 : && (wlen <= badwords[i].len
3247 : 1674 : || (wlen == badwords[i].len + 1U
3248 : 608 : && TOUPPER (format_chars[wlen - 1]) == 'S'))
3249 : 19786 : && !strncasecmp (format_chars, badwords[i].name, badwords[i].len))
3250 : : {
3251 : : /* Handle singular as well as plural forms of all bad words
3252 : : even though the latter don't necessarily make sense for
3253 : : all of the former (like "can nots"). */
3254 : 42 : badwlen = badwords[i].len;
3255 : 42 : const char *plural = "";
3256 : 42 : if (TOUPPER (format_chars[badwlen]) == 'S')
3257 : : {
3258 : 18 : ++badwlen;
3259 : 18 : plural = "s";
3260 : : }
3261 : :
3262 : : /* As an exception, don't warn about "decl-specifier*" since
3263 : : it's a C++ grammar production. */
3264 : 42 : if (badwords[i].name[0] == 'd'
3265 : 42 : && startswith (format_chars, "decl-specifier"))
3266 : 0 : continue;
3267 : :
3268 : 42 : format_warning_substr (format_string_loc, format_string_cst,
3269 : 42 : fmtchrpos, fmtchrpos + badwords[i].len,
3270 : : opt,
3271 : : "misspelled term %<%.*s%> in format; "
3272 : : "use %<%s%s%> instead",
3273 : : badwlen, format_chars,
3274 : 42 : badwords[i].alt, plural);
3275 : :
3276 : 42 : return format_chars + badwords[i].len - 1;
3277 : : }
3278 : : }
3279 : :
3280 : : /* Skip C++/G++. */
3281 : 1512 : if (!strncasecmp (format_chars, "c++", 3)
3282 : 1506 : || !strncasecmp (format_chars, "g++", 3))
3283 : 14 : return format_chars + 2;
3284 : : }
3285 : :
3286 : 1520 : return wlen ? format_chars + wlen - 1 : NULL;
3287 : : }
3288 : :
3289 : : /* Check plain text in a format string of a GCC diagnostic function
3290 : : for common quoting, punctuation, and spelling mistakes, and issue
3291 : : -Wformat-diag warnings if they are found. FORMAT_STRING_LOC is
3292 : : the location of the format string, FORMAT_STRING_CST the format
3293 : : string itself (as a tree), ORIG_FORMAT_CHARS and FORMAT_CHARS are
3294 : : pointers to the beginning of the format string and the character
3295 : : currently being processed, and BALTOKS describes paired "tokens"
3296 : : within the format string that are expected to be balanced.
3297 : : Returns a pointer to the last processed character. */
3298 : :
3299 : : static const char*
3300 : 2958 : check_plain (location_t format_string_loc, tree format_string_cst,
3301 : : const char *orig_format_chars, const char *format_chars,
3302 : : baltoks_t &baltoks)
3303 : : {
3304 : : /* For brevity. */
3305 : 2958 : const int opt = OPT_Wformat_diag;
3306 : : /* Zero-based starting position of a problem sequence. */
3307 : 2958 : int fmtchrpos = format_chars - orig_format_chars;
3308 : :
3309 : 2958 : if (*format_chars == '%')
3310 : : {
3311 : : /* Diagnose %<%s%> and suggest using %qs instead. */
3312 : 1300 : if (startswith (format_chars, "%<%s%>"))
3313 : 2 : format_warning_substr (format_string_loc, format_string_cst,
3314 : : fmtchrpos, fmtchrpos + 6, opt,
3315 : : "quoted %qs directive in format; "
3316 : : "use %qs instead", "%s", "%qs");
3317 : 1298 : else if (format_chars - orig_format_chars > 2
3318 : 558 : && !strncasecmp (format_chars - 3, "can%'t", 6))
3319 : 4 : format_warning_substr (format_string_loc,
3320 : : format_string_cst,
3321 : : fmtchrpos - 3, fmtchrpos + 3, opt,
3322 : : "contraction %<%.*s%> in format; "
3323 : : "use %qs instead",
3324 : : 6, format_chars - 3, "cannot");
3325 : :
3326 : 1300 : return format_chars;
3327 : : }
3328 : :
3329 : 1770 : if (baltoks.quotdirs.length ())
3330 : : {
3331 : : /* Skip over all plain text within a quoting directive until
3332 : : the next directive. */
3333 : 212 : while (*format_chars && '%' != *format_chars)
3334 : 136 : ++format_chars;
3335 : :
3336 : 76 : return format_chars;
3337 : : }
3338 : :
3339 : : /* The length of the problem sequence. */
3340 : : int nchars = 0;
3341 : :
3342 : : /* Diagnose any whitespace characters other than <space> but only
3343 : : leading, trailing, and two or more consecutive <space>s. Do
3344 : : this before diagnosing control characters because whitespace
3345 : : is a subset of controls. */
3346 : : const char *other_than_space = NULL;
3347 : 2456 : while (ISSPACE (format_chars[nchars]))
3348 : : {
3349 : 874 : if (format_chars[nchars] != ' ' && !other_than_space)
3350 : 874 : other_than_space = format_chars + nchars;
3351 : 874 : ++nchars;
3352 : : }
3353 : :
3354 : 1582 : if (nchars)
3355 : : {
3356 : : /* This is the most common problem: go the extra mile to describe
3357 : : the problem in as much helpful detail as possible. */
3358 : 852 : if (other_than_space)
3359 : : {
3360 : 86 : format_warning_substr (format_string_loc, format_string_cst,
3361 : : fmtchrpos, fmtchrpos + nchars, opt,
3362 : : "unquoted whitespace character %qc in format",
3363 : 86 : *other_than_space);
3364 : 86 : return format_chars + nchars - 1;
3365 : : }
3366 : :
3367 : 766 : if (fmtchrpos == 0)
3368 : : /* Accept strings of leading spaces with no warning. */
3369 : 6 : return format_chars + nchars - 1;
3370 : :
3371 : 760 : if (!format_chars[nchars])
3372 : : {
3373 : 6 : format_warning_substr (format_string_loc, format_string_cst,
3374 : : fmtchrpos, fmtchrpos + nchars, opt,
3375 : : "spurious trailing space in format");
3376 : 6 : return format_chars + nchars - 1;
3377 : : }
3378 : :
3379 : 754 : if (nchars > 1)
3380 : : {
3381 : 10 : if (nchars == 2
3382 : 10 : && orig_format_chars < format_chars
3383 : 8 : && format_chars[-1] == '.'
3384 : 4 : && format_chars[0] == ' '
3385 : 4 : && format_chars[1] == ' ')
3386 : : {
3387 : : /* A period followed by two spaces. */
3388 : 4 : if (ISUPPER (*orig_format_chars))
3389 : : {
3390 : : /* If the part before the period is a capitalized
3391 : : sentence check to make sure that what follows
3392 : : is also capitalized. */
3393 : 4 : if (ISLOWER (format_chars[2]))
3394 : 2 : format_warning_substr (format_string_loc, format_string_cst,
3395 : : fmtchrpos, fmtchrpos + nchars, opt,
3396 : : "inconsistent capitalization in "
3397 : : "format");
3398 : : }
3399 : : }
3400 : : else
3401 : 6 : format_warning_substr (format_string_loc, format_string_cst,
3402 : : fmtchrpos, fmtchrpos + nchars, opt,
3403 : : "unquoted sequence of %i consecutive "
3404 : : "space characters in format", nchars);
3405 : 10 : return format_chars + nchars - 1;
3406 : : }
3407 : :
3408 : : format_chars += nchars;
3409 : : nchars = 0;
3410 : : }
3411 : :
3412 : 1474 : fmtchrpos = format_chars - orig_format_chars;
3413 : :
3414 : : /* Diagnose any unquoted control characters other than the terminating
3415 : : NUL. */
3416 : 1482 : while (format_chars[nchars] && ISCNTRL (format_chars[nchars]))
3417 : 8 : ++nchars;
3418 : :
3419 : 1474 : if (nchars > 1)
3420 : : {
3421 : 0 : format_warning_substr (format_string_loc, format_string_cst,
3422 : : fmtchrpos, fmtchrpos + nchars, opt,
3423 : : "unquoted control characters in format");
3424 : 0 : return format_chars + nchars - 1;
3425 : : }
3426 : 1474 : if (nchars)
3427 : : {
3428 : 8 : format_warning_substr (format_string_loc, format_string_cst,
3429 : : fmtchrpos, fmtchrpos + nchars, opt,
3430 : : "unquoted control character %qc in format",
3431 : 8 : *format_chars);
3432 : 8 : return format_chars + nchars - 1;
3433 : : }
3434 : :
3435 : 1466 : if (ISPUNCT (format_chars[0]))
3436 : : {
3437 : 312 : size_t nelts = ARRAY_SIZE (c_opers);
3438 : 312 : if (const char *ret = check_tokens (c_opers, nelts,
3439 : : format_string_loc, format_string_cst,
3440 : : orig_format_chars, format_chars,
3441 : : baltoks))
3442 : : return ret;
3443 : :
3444 : 264 : nelts = c_dialect_cxx () ? ARRAY_SIZE (cxx_opers) : 0;
3445 : 264 : if (const char *ret = check_tokens (cxx_opers, nelts,
3446 : : format_string_loc, format_string_cst,
3447 : : orig_format_chars, format_chars,
3448 : : baltoks))
3449 : : return ret;
3450 : : }
3451 : :
3452 : 1418 : if (ISALPHA (format_chars[0]))
3453 : : {
3454 : 1078 : size_t nelts = ARRAY_SIZE (c_keywords);
3455 : 1078 : if (const char *ret = check_tokens (c_keywords, nelts,
3456 : : format_string_loc, format_string_cst,
3457 : : orig_format_chars, format_chars,
3458 : : baltoks))
3459 : : return ret;
3460 : :
3461 : 2 : nelts = c_dialect_cxx () ? ARRAY_SIZE (cxx_keywords) : 0;
3462 : 2 : if (const char *ret = check_tokens (cxx_keywords, nelts,
3463 : : format_string_loc, format_string_cst,
3464 : : orig_format_chars, format_chars,
3465 : : baltoks))
3466 : : return ret;
3467 : : }
3468 : :
3469 : 340 : nchars = 0;
3470 : :
3471 : : /* Diagnose unquoted options. */
3472 : 340 : if ((format_chars == orig_format_chars
3473 : 300 : || format_chars[-1] == ' ')
3474 : 174 : && format_chars[0] == '-'
3475 : 12 : && ((format_chars[1] == '-'
3476 : 2 : && ISALPHA (format_chars[2]))
3477 : 10 : || ISALPHA (format_chars[1])))
3478 : : {
3479 : : nchars = 1;
3480 : 32 : while (ISALNUM (format_chars[nchars])
3481 : : || '_' == format_chars[nchars]
3482 : : || '-' == format_chars[nchars]
3483 : 32 : || '+' == format_chars[nchars])
3484 : 24 : ++nchars;
3485 : :
3486 : 8 : format_warning_substr (format_string_loc, format_string_cst,
3487 : : fmtchrpos, fmtchrpos + nchars, opt,
3488 : : "unquoted option name %<%.*s%> in format",
3489 : : nchars, format_chars);
3490 : 8 : return format_chars + nchars - 1;
3491 : : }
3492 : :
3493 : : /* Diagnose leading, trailing, and two or more consecutive punctuation
3494 : : characters. */
3495 : : const char *unbalanced = NULL;
3496 : 590 : while ('%' != format_chars[nchars]
3497 : 542 : && ISPUNCT (format_chars[nchars])
3498 : 850 : && !unbalanced)
3499 : : {
3500 : 258 : switch (format_chars[nchars])
3501 : : {
3502 : 0 : case '[':
3503 : 0 : baltoks.brackets.safe_push (format_chars + nchars);
3504 : 0 : break;
3505 : 0 : case '{':
3506 : 0 : baltoks.curly.safe_push (format_chars + nchars);
3507 : 0 : break;
3508 : 42 : case '(':
3509 : 42 : baltoks.parens.safe_push (format_chars + nchars);
3510 : 42 : break;
3511 : 2 : case '<':
3512 : 2 : baltoks.pointy.safe_push (format_chars + nchars);
3513 : 2 : break;
3514 : :
3515 : 0 : case ']':
3516 : 0 : if (baltoks.brackets.length () > 0)
3517 : 0 : baltoks.brackets.pop ();
3518 : : else
3519 : : unbalanced = format_chars + nchars;
3520 : : break;
3521 : 0 : case '}':
3522 : 0 : if (baltoks.curly.length () > 0)
3523 : 0 : baltoks.curly.pop ();
3524 : : else
3525 : : unbalanced = format_chars + nchars;
3526 : : break;
3527 : 46 : case ')':
3528 : 46 : if (baltoks.parens.length () > 0)
3529 : 38 : baltoks.parens.pop ();
3530 : : else
3531 : : unbalanced = format_chars + nchars;
3532 : : break;
3533 : 2 : case '>':
3534 : 2 : if (baltoks.pointy.length () > 0)
3535 : 0 : baltoks.pointy.pop ();
3536 : : else
3537 : : unbalanced = format_chars + nchars;
3538 : : break;
3539 : : }
3540 : :
3541 : 258 : ++nchars;
3542 : : }
3543 : :
3544 : 332 : if (unbalanced)
3545 : : {
3546 : 10 : format_warning_substr (format_string_loc, format_string_cst,
3547 : : fmtchrpos, fmtchrpos + nchars, opt,
3548 : : "unbalanced punctuation character %qc in format",
3549 : 10 : *unbalanced);
3550 : 10 : return format_chars + nchars - 1;
3551 : : }
3552 : :
3553 : 322 : if (nchars)
3554 : : {
3555 : : /* Consider any identifier that follows the pound ('#') sign
3556 : : a preprocessing directive. */
3557 : 200 : if (nchars == 1
3558 : 158 : && format_chars[0] == '#'
3559 : 12 : && ISALPHA (format_chars[1]))
3560 : : {
3561 : 42 : while (ISALNUM (format_chars[nchars])
3562 : 42 : || format_chars[nchars] == '_')
3563 : 36 : ++nchars;
3564 : :
3565 : 6 : format_warning_substr (format_string_loc, format_string_cst,
3566 : : fmtchrpos, fmtchrpos + nchars, opt,
3567 : : "unquoted preprocessing directive %<%.*s%> "
3568 : : "in format", nchars, format_chars);
3569 : 6 : return format_chars + nchars - 1;
3570 : : }
3571 : :
3572 : : /* Diagnose a bare single quote. */
3573 : 152 : if (nchars == 1
3574 : 152 : && format_chars[0] == '\''
3575 : 8 : && format_chars - orig_format_chars
3576 : 8 : && ISALPHA (format_chars[-1])
3577 : 8 : && ISALPHA (format_chars[1]))
3578 : : {
3579 : : /* Diagnose a subset of contractions that are best avoided. */
3580 : 52 : for (unsigned i = 0; i != ARRAY_SIZE (contrs); ++i)
3581 : : {
3582 : 48 : const char *apos = strchr (contrs[i].name, '\'');
3583 : 48 : gcc_assert (apos != NULL);
3584 : 48 : int off = apos - contrs[i].name;
3585 : :
3586 : 48 : if (format_chars - orig_format_chars >= off
3587 : 24 : && !strncmp (format_chars - off,
3588 : 24 : contrs[i].name, contrs[i].len))
3589 : : {
3590 : 4 : format_warning_substr (format_string_loc,
3591 : : format_string_cst,
3592 : : fmtchrpos, fmtchrpos + nchars, opt,
3593 : : "contraction %<%.*s%> in format; "
3594 : : "use %qs instead",
3595 : : contrs[i].len, contrs[i].name,
3596 : 4 : contrs[i].alt);
3597 : 4 : return format_chars + nchars - 1;
3598 : : }
3599 : : }
3600 : :
3601 : 4 : if (format_warning_substr (format_string_loc, format_string_cst,
3602 : : fmtchrpos, fmtchrpos + nchars, opt,
3603 : : "bare apostrophe %<'%> in format"))
3604 : 4 : inform (format_string_loc,
3605 : : "if avoiding the apostrophe is not feasible, enclose "
3606 : : "it in a pair of %qs and %qs directives instead",
3607 : : "%<", "%>");
3608 : 4 : return format_chars + nchars - 1;
3609 : : }
3610 : :
3611 : : /* Diagnose a backtick (grave accent). */
3612 : 144 : if (nchars == 1
3613 : 144 : && format_chars[0] == '`')
3614 : : {
3615 : 0 : if (format_warning_substr (format_string_loc, format_string_cst,
3616 : : fmtchrpos, fmtchrpos + nchars, opt,
3617 : : "grave accent %<`%> in format"))
3618 : 0 : inform (format_string_loc,
3619 : : "use the apostrophe directive %qs instead", "%'");
3620 : 0 : return format_chars + nchars - 1;
3621 : : }
3622 : :
3623 : : /* Diagnose a punctuation character after a space. */
3624 : 186 : if (nchars == 1
3625 : 186 : && format_chars - orig_format_chars
3626 : 128 : && format_chars[-1] == ' '
3627 : 54 : && strspn (format_chars, "!?:;.,") == 1)
3628 : : {
3629 : 10 : format_warning_substr (format_string_loc, format_string_cst,
3630 : : fmtchrpos - 1, fmtchrpos, opt,
3631 : : "space followed by punctuation character "
3632 : 10 : "%<%c%>", format_chars[0]);
3633 : 10 : return format_chars;
3634 : : }
3635 : :
3636 : 176 : if (nchars == 1)
3637 : : {
3638 : 134 : if (startswith (format_chars, "\"%s\""))
3639 : : {
3640 : 2 : if (format_warning_substr (format_string_loc, format_string_cst,
3641 : : fmtchrpos, fmtchrpos + 4, opt,
3642 : : "quoted %qs directive in format",
3643 : : "%s"))
3644 : 2 : inform (format_string_loc, "if using %qs is not feasible, "
3645 : : "use %qs instead", "%qs", "\"%-s\"");
3646 : : }
3647 : :
3648 : 134 : if (format_chars[0] == '"')
3649 : : {
3650 : 18 : baltoks.doublequote = baltoks.doublequote ? NULL : format_chars;
3651 : 18 : return format_chars + nchars - 1;
3652 : : }
3653 : 116 : if (format_chars[0] == '\'')
3654 : : {
3655 : 0 : baltoks.singlequote = baltoks.singlequote ? NULL : format_chars;
3656 : 0 : return format_chars + nchars - 1;
3657 : : }
3658 : : }
3659 : :
3660 : 158 : if (fmtchrpos == 0)
3661 : : {
3662 : 16 : if (nchars == 1
3663 : 8 : && format_chars[0] == '(')
3664 : : ; /* Text beginning in an open parenthesis. */
3665 : 12 : else if (nchars == 3
3666 : 2 : && startswith (format_chars, "...")
3667 : 14 : && format_chars[3])
3668 : : ; /* Text beginning in an ellipsis. */
3669 : : else
3670 : : {
3671 : 10 : format_warning_substr (format_string_loc, format_string_cst,
3672 : : fmtchrpos, fmtchrpos + nchars, opt,
3673 : : "spurious leading punctuation sequence "
3674 : : "%<%.*s%> in format",
3675 : : nchars, format_chars);
3676 : 10 : return format_chars + nchars - 1;
3677 : : }
3678 : : }
3679 : 142 : else if (!format_chars[nchars])
3680 : : {
3681 : 56 : if (nchars == 1
3682 : 38 : && (format_chars[nchars - 1] == ':'
3683 : 36 : || format_chars[nchars - 1] == ')'))
3684 : : ; /* Text ending in a colon or a closing parenthesis. */
3685 : 26 : else if (nchars == 1
3686 : 26 : && ((ISUPPER (*orig_format_chars)
3687 : 16 : && format_chars[nchars - 1] == '.')
3688 : 14 : || strspn (format_chars + nchars - 1, "?])") == 1))
3689 : : ; /* Capitalized sentence terminated by a single period,
3690 : : or text ending in a question mark, closing bracket,
3691 : : or parenthesis. */
3692 : 26 : else if (nchars == 2
3693 : 16 : && format_chars[0] == '?'
3694 : 4 : && format_chars[1] == ')')
3695 : : ; /* A question mark after a closing parenthetical note. */
3696 : 12 : else if (nchars == 2
3697 : 12 : && format_chars[0] == ')'
3698 : 6 : && (format_chars[1] == '?'
3699 : : || format_chars[1] == ';'
3700 : : || format_chars[1] == ':'
3701 : 2 : || (ISUPPER (*orig_format_chars)
3702 : 2 : && format_chars[1] == '.')))
3703 : : ; /* Closing parenthetical note followed by a question mark,
3704 : : semicolon, or colon at the end of the string, or by
3705 : : a period at the end of a capitalized sentence. */
3706 : 16 : else if (nchars == 3
3707 : 2 : && format_chars - orig_format_chars > 0
3708 : 18 : && startswith (format_chars, "..."))
3709 : : ; /* Text ending in the ellipsis. */
3710 : : else
3711 : 14 : format_warning_substr (format_string_loc, format_string_cst,
3712 : : fmtchrpos, fmtchrpos + nchars, opt,
3713 : : "spurious trailing punctuation sequence "
3714 : : "%<%.*s%> in format",
3715 : : nchars, format_chars);
3716 : :
3717 : 56 : return format_chars + nchars - 1;
3718 : : }
3719 : 86 : else if (nchars == 2
3720 : 14 : && format_chars[0] == ')'
3721 : 8 : && (format_chars[1] == ':'
3722 : 8 : || format_chars[1] == ';'
3723 : 2 : || format_chars[1] == ',')
3724 : 8 : && format_chars[2] == ' ')
3725 : : ; /* Closing parenthetical note followed by a colon, semicolon
3726 : : or a comma followed by a space in the middle of the string. */
3727 : 78 : else if (nchars > 1)
3728 : 8 : format_warning_substr (format_string_loc, format_string_cst,
3729 : : fmtchrpos, fmtchrpos + nchars, opt,
3730 : : "unquoted sequence of %i consecutive "
3731 : : "punctuation characters %q.*s in format",
3732 : : nchars, nchars, format_chars);
3733 : 92 : return format_chars + nchars - 1;
3734 : : }
3735 : :
3736 : : nchars = 0;
3737 : :
3738 : : /* Finally, diagnose any unquoted non-graph, non-punctuation characters
3739 : : other than the terminating NUL. */
3740 : 126 : while (format_chars[nchars]
3741 : 126 : && '%' != format_chars[nchars]
3742 : 80 : && !ISPUNCT (format_chars[nchars])
3743 : 206 : && !ISGRAPH (format_chars[nchars]))
3744 : 4 : ++nchars;
3745 : :
3746 : 122 : if (nchars > 1)
3747 : : {
3748 : 0 : format_warning_substr (format_string_loc, format_string_cst,
3749 : : fmtchrpos, fmtchrpos + nchars, opt,
3750 : : "unquoted non-graph characters in format");
3751 : 0 : return format_chars + nchars - 1;
3752 : : }
3753 : 122 : if (nchars)
3754 : : {
3755 : 4 : format_warning_substr (format_string_loc, format_string_cst,
3756 : : fmtchrpos, fmtchrpos + nchars, opt,
3757 : : "unquoted non-graph character %qc in format",
3758 : 4 : *format_chars);
3759 : 4 : return format_chars + nchars - 1;
3760 : : }
3761 : :
3762 : : return format_chars;
3763 : : }
3764 : :
3765 : : /* Diagnose unbalanced tokens described by BALTOKS in format string
3766 : : ORIG_FORMAT_CHARS and the corresponding FORMAT_STRING_CST. */
3767 : :
3768 : : static void
3769 : 42869 : maybe_diag_unbalanced_tokens (location_t format_string_loc,
3770 : : const char *orig_format_chars,
3771 : : tree format_string_cst,
3772 : : baltoks_t &baltoks)
3773 : : {
3774 : 42869 : const char *unbalanced = NULL;
3775 : :
3776 : 42869 : if (baltoks.brackets.length ())
3777 : 0 : unbalanced = baltoks.brackets.pop ();
3778 : 42869 : else if (baltoks.curly.length ())
3779 : 0 : unbalanced = baltoks.curly.pop ();
3780 : 42869 : else if (baltoks.parens.length ())
3781 : 6 : unbalanced = baltoks.parens.pop ();
3782 : 42863 : else if (baltoks.pointy.length ())
3783 : 2 : unbalanced = baltoks.pointy.pop ();
3784 : :
3785 : 8 : if (unbalanced)
3786 : 8 : format_warning_at_char (format_string_loc, format_string_cst,
3787 : 8 : unbalanced - orig_format_chars + 1,
3788 : : OPT_Wformat_diag,
3789 : : "unbalanced punctuation character %<%c%> in format",
3790 : 8 : *unbalanced);
3791 : :
3792 : 42869 : if (baltoks.quotdirs.length ())
3793 : 16 : format_warning_at_char (format_string_loc, format_string_cst,
3794 : 8 : baltoks.quotdirs.pop () - orig_format_chars,
3795 : : OPT_Wformat_,
3796 : : "unterminated quoting directive");
3797 : :
3798 : 85738 : const char *quote
3799 : 42869 : = baltoks.singlequote ? baltoks.singlequote : baltoks.doublequote;
3800 : :
3801 : 42869 : if (quote)
3802 : 2 : format_warning_at_char (format_string_loc, format_string_cst,
3803 : 2 : quote - orig_format_chars + 1,
3804 : : OPT_Wformat_diag,
3805 : : "unterminated quote character %<%c%> in format",
3806 : 2 : *quote);
3807 : 42869 : }
3808 : :
3809 : : /* Do the main part of checking a call to a format function. FORMAT_CHARS
3810 : : is the NUL-terminated format string (which at this point may contain
3811 : : internal NUL characters); FORMAT_LENGTH is its length (excluding the
3812 : : terminating NUL character). ARG_NUM is one less than the number of
3813 : : the first format argument to check; PARAMS points to that format
3814 : : argument in the list of arguments. */
3815 : :
3816 : : static void
3817 : 42893 : check_format_info_main (format_check_results *res,
3818 : : function_format_info *info, const char *format_chars,
3819 : : location_t fmt_param_loc, tree format_string_cst,
3820 : : int format_length, tree params,
3821 : : unsigned HOST_WIDE_INT arg_num,
3822 : : object_allocator <format_wanted_type> &fwt_pool,
3823 : : vec<location_t> *arglocs)
3824 : : {
3825 : 42893 : const char * const orig_format_chars = format_chars;
3826 : 42893 : const tree first_fillin_param = params;
3827 : :
3828 : 42893 : const format_kind_info * const fki = &format_types[info->format_type];
3829 : 42893 : const format_flag_spec * const flag_specs = fki->flag_specs;
3830 : 42893 : const location_t format_string_loc = res->format_string_loc;
3831 : :
3832 : : /* -1 if no conversions taking an operand have been found; 0 if one has
3833 : : and it didn't use $; 1 if $ formats are in use. */
3834 : 42893 : int has_operand_number = -1;
3835 : :
3836 : : /* Vectors of pointers to opening quoting directives (like GCC "%<"),
3837 : : opening braces, brackets, and parentheses. Used to detect unbalanced
3838 : : tokens. */
3839 : 42893 : baltoks_t baltoks;
3840 : :
3841 : : /* Pointers to the most recent color directives (like GCC's "%r or %R").
3842 : : A starting color directive much be terminated before the end of
3843 : : the format string. A terminating directive makes no sense without
3844 : : a prior starting directive. */
3845 : 42893 : const char *color_begin = NULL;
3846 : 42893 : const char *color_end = NULL;
3847 : :
3848 : 42893 : init_dollar_format_checking (info->first_arg_num, first_fillin_param);
3849 : :
3850 : : /* In GCC diagnostic functions check plain directives (substrings within
3851 : : the format string that don't start with %) for quoting and punctuations
3852 : : problems. */
3853 : 85786 : bool ck_plain = (!info->is_raw
3854 : 42893 : && (info->format_type == gcc_diag_format_type
3855 : : || info->format_type == gcc_tdiag_format_type
3856 : : || info->format_type == gcc_cdiag_format_type
3857 : 42871 : || info->format_type == gcc_cxxdiag_format_type));
3858 : :
3859 : 1017585 : while (*format_chars != 0)
3860 : : {
3861 : 974716 : if (ck_plain)
3862 : 2958 : format_chars = check_plain (format_string_loc,
3863 : : format_string_cst,
3864 : : orig_format_chars, format_chars,
3865 : : baltoks);
3866 : :
3867 : 974716 : if (*format_chars == 0 || *format_chars++ != '%')
3868 : 1845758 : continue;
3869 : :
3870 : 52564 : if (*format_chars == 0)
3871 : : {
3872 : 136 : format_warning_at_char (format_string_loc, format_string_cst,
3873 : 136 : format_chars - orig_format_chars,
3874 : : OPT_Wformat_,
3875 : : "spurious trailing %<%%%> in format");
3876 : 136 : continue;
3877 : : }
3878 : 52428 : if (*format_chars == '%')
3879 : : {
3880 : 133 : ++format_chars;
3881 : 133 : continue;
3882 : : }
3883 : :
3884 : : /* ARGUMENT_PARSER ctor takes FORMAT_CHARS by reference and calls
3885 : : to ARG_PARSER members may modify the variable. */
3886 : 52295 : flag_chars_t flag_chars;
3887 : 52295 : argument_parser arg_parser (info, format_chars, format_string_cst,
3888 : : orig_format_chars, format_string_loc,
3889 : : flag_chars, has_operand_number,
3890 : 52295 : first_fillin_param, fwt_pool, arglocs);
3891 : :
3892 : 52295 : if (!arg_parser.read_any_dollar ())
3893 : 24 : return;
3894 : :
3895 : 52285 : if (!arg_parser.read_format_flags ())
3896 : : return;
3897 : :
3898 : : /* Read any format width, possibly * or *m$. */
3899 : 52283 : if (!arg_parser.read_any_format_width (params, arg_num))
3900 : : return;
3901 : :
3902 : : /* Read any format left precision (must be a number, not *). */
3903 : 52279 : arg_parser.read_any_format_left_precision ();
3904 : :
3905 : : /* Read any format precision, possibly * or *m$. */
3906 : 52279 : if (!arg_parser.read_any_format_precision (params, arg_num))
3907 : : return;
3908 : :
3909 : 52277 : const char *format_start = format_chars;
3910 : :
3911 : 52277 : arg_parser.handle_alloc_chars ();
3912 : :
3913 : : /* The rest of the conversion specification is the length modifier
3914 : : (if any), and the conversion specifier, so this is where the
3915 : : type information starts. If we need to issue a suggestion
3916 : : about a type mismatch, then we should preserve everything up
3917 : : to here. */
3918 : 52277 : const char *type_start = format_chars;
3919 : :
3920 : : /* Read any length modifier, if this kind of format has them. */
3921 : 52277 : const length_modifier len_modifier
3922 : 52277 : = arg_parser.read_any_length_modifier ();
3923 : :
3924 : : /* Read any modifier (strftime E/O). */
3925 : 52277 : arg_parser.read_any_other_modifier ();
3926 : :
3927 : 52277 : char format_char = *format_chars;
3928 : 52277 : if (format_char == 0
3929 : 52267 : || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
3930 : 51453 : && format_char == '%'))
3931 : : {
3932 : 42 : format_warning_at_char (format_string_loc, format_string_cst,
3933 : 42 : format_chars - orig_format_chars,
3934 : : OPT_Wformat_,
3935 : : "conversion lacks type at end of format");
3936 : 42 : continue;
3937 : : }
3938 : 52235 : format_chars++;
3939 : :
3940 : 52235 : const format_char_info * const fci
3941 : 52235 : = arg_parser.find_format_char_info (format_char);
3942 : 52235 : if (!fci)
3943 : 209 : continue;
3944 : :
3945 : 52026 : flag_chars.validate (fki, fci, flag_specs, format_chars,
3946 : : format_string_cst,
3947 : : format_string_loc, orig_format_chars, format_char,
3948 : 52026 : baltoks.quotdirs.length () > 0);
3949 : :
3950 : 52026 : const int alloc_flag = flag_chars.get_alloc_flag (fki);
3951 : 52026 : const bool suppressed = flag_chars.assignment_suppression_p (fki);
3952 : :
3953 : : /* Diagnose nested or unmatched quoting directives such as GCC's
3954 : : "%<...%<" and "%>...%>". */
3955 : 52026 : bool quot_begin_p = strchr (fci->flags2, '<');
3956 : 52026 : bool quot_end_p = strchr (fci->flags2, '>');
3957 : :
3958 : 52026 : if (quot_begin_p && !quot_end_p)
3959 : : {
3960 : 206 : if (baltoks.quotdirs.length ())
3961 : 8 : format_warning_at_char (format_string_loc, format_string_cst,
3962 : 8 : format_chars - orig_format_chars,
3963 : : OPT_Wformat_,
3964 : : "nested quoting directive");
3965 : 206 : baltoks.quotdirs.safe_push (format_chars);
3966 : : }
3967 : 51820 : else if (!quot_begin_p && quot_end_p)
3968 : : {
3969 : 206 : if (baltoks.quotdirs.length ())
3970 : 198 : baltoks.quotdirs.pop ();
3971 : : else
3972 : 8 : format_warning_at_char (format_string_loc, format_string_cst,
3973 : 8 : format_chars - orig_format_chars,
3974 : : OPT_Wformat_,
3975 : : "unmatched quoting directive");
3976 : : }
3977 : :
3978 : 52026 : bool color_begin_p = strchr (fci->flags2, '/');
3979 : 52026 : if (color_begin_p)
3980 : : {
3981 : 102 : color_begin = format_chars;
3982 : 102 : color_end = NULL;
3983 : : }
3984 : 51924 : else if (strchr (fci->flags2, '\\'))
3985 : : {
3986 : 74 : if (color_end)
3987 : 0 : format_warning_at_char (format_string_loc, format_string_cst,
3988 : 0 : format_chars - orig_format_chars,
3989 : : OPT_Wformat_,
3990 : : "%qc directive redundant after prior "
3991 : : "occurence of the same", format_char);
3992 : 74 : else if (!color_begin)
3993 : 20 : format_warning_at_char (format_string_loc, format_string_cst,
3994 : 20 : format_chars - orig_format_chars,
3995 : : OPT_Wformat_,
3996 : : "unmatched color reset directive");
3997 : 74 : color_end = format_chars;
3998 : : }
3999 : :
4000 : : /* Diagnose directives that shouldn't appear in a quoted sequence.
4001 : : (They are denoted by a double quote in FLAGS2.) */
4002 : 52026 : if (baltoks.quotdirs.length ())
4003 : : {
4004 : 416 : if (strchr (fci->flags2, '"'))
4005 : 0 : format_warning_at_char (format_string_loc, format_string_cst,
4006 : 0 : format_chars - orig_format_chars,
4007 : : OPT_Wformat_,
4008 : : "%qc conversion used within a quoted "
4009 : : "sequence",
4010 : : format_char);
4011 : : }
4012 : :
4013 : : /* Validate the pairs of flags used. */
4014 : 52026 : arg_parser.validate_flag_pairs (fci, format_char);
4015 : :
4016 : 52026 : arg_parser.give_y2k_warnings (fci, format_char);
4017 : :
4018 : 52026 : arg_parser.parse_any_scan_set (fci);
4019 : :
4020 : 52026 : tree wanted_type = NULL;
4021 : 52026 : const char *wanted_type_name = NULL;
4022 : :
4023 : 52026 : if (!arg_parser.handle_conversions (fci, len_modifier,
4024 : : wanted_type, wanted_type_name,
4025 : : arg_num,
4026 : : params,
4027 : : format_char))
4028 : 934 : continue;
4029 : :
4030 : 51092 : arg_parser.main_wanted_type.next = NULL;
4031 : :
4032 : : /* Finally. . .check type of argument against desired type! */
4033 : 51092 : if (!arg_parser.check_argument_type (fci, len_modifier,
4034 : : wanted_type, wanted_type_name,
4035 : : suppressed,
4036 : : arg_num, params,
4037 : : alloc_flag,
4038 : : format_start, type_start,
4039 : : fmt_param_loc,
4040 : : format_char))
4041 : : return;
4042 : : }
4043 : :
4044 : 42869 : if (format_chars - orig_format_chars != format_length)
4045 : 36 : format_warning_at_char (format_string_loc, format_string_cst,
4046 : 36 : format_chars + 1 - orig_format_chars,
4047 : : OPT_Wformat_contains_nul,
4048 : : "embedded %<\\0%> in format");
4049 : 42869 : if (info->first_arg_num != 0 && params != 0
4050 : 270 : && has_operand_number <= 0)
4051 : : {
4052 : 233 : res->number_other--;
4053 : 233 : res->number_extra_args++;
4054 : : }
4055 : 42869 : if (has_operand_number > 0)
4056 : 80 : finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK);
4057 : :
4058 : 42869 : maybe_diag_unbalanced_tokens (format_string_loc, orig_format_chars,
4059 : : format_string_cst, baltoks);
4060 : :
4061 : 42869 : if (color_begin && !color_end)
4062 : 28 : format_warning_at_char (format_string_loc, format_string_cst,
4063 : 28 : color_begin - orig_format_chars,
4064 : : OPT_Wformat_, "unterminated color directive");
4065 : 42893 : }
4066 : :
4067 : : /* Check the argument types from a single format conversion (possibly
4068 : : including width and precision arguments).
4069 : :
4070 : : FMT_LOC is the location of the format conversion.
4071 : :
4072 : : TYPES is a singly-linked list expressing the parts of the format
4073 : : conversion that expect argument types, and the arguments they
4074 : : correspond to.
4075 : :
4076 : : OFFSET_TO_TYPE_START is the offset within the execution-charset encoded
4077 : : format string to where type information begins for the conversion
4078 : : (the length modifier and conversion specifier).
4079 : :
4080 : : CONVERSION_CHAR is the user-provided conversion specifier.
4081 : :
4082 : : For example, given:
4083 : :
4084 : : sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
4085 : :
4086 : : then FMT_LOC covers this range:
4087 : :
4088 : : sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
4089 : : ^^^^^^^^^
4090 : :
4091 : : and TYPES in this case is a three-entry singly-linked list consisting of:
4092 : : (1) the check for the field width here:
4093 : : sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
4094 : : ^ ^^^^
4095 : : against arg3, and
4096 : : (2) the check for the field precision here:
4097 : : sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
4098 : : ^^ ^^^^
4099 : : against arg4, and
4100 : : (3) the check for the length modifier and conversion char here:
4101 : : sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
4102 : : ^^^ ^^^^
4103 : : against arg5.
4104 : :
4105 : : OFFSET_TO_TYPE_START is 13, the offset to the "lld" within the
4106 : : STRING_CST:
4107 : :
4108 : : 0000000000111111111122
4109 : : 0123456789012345678901
4110 : : sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
4111 : : ^ ^
4112 : : | ` CONVERSION_CHAR: 'd'
4113 : : type starts here. */
4114 : :
4115 : : static void
4116 : 49142 : check_format_types (const substring_loc &fmt_loc,
4117 : : format_wanted_type *types, const format_kind_info *fki,
4118 : : int offset_to_type_start,
4119 : : char conversion_char,
4120 : : vec<location_t> *arglocs)
4121 : : {
4122 : 99827 : for (; types != 0; types = types->next)
4123 : : {
4124 : 50685 : tree cur_param;
4125 : 50685 : tree cur_type;
4126 : 50685 : tree orig_cur_type;
4127 : 50685 : tree wanted_type;
4128 : 50685 : int arg_num;
4129 : 50685 : int i;
4130 : 50685 : int char_type_flag;
4131 : :
4132 : 50685 : wanted_type = types->wanted_type;
4133 : 50685 : arg_num = types->arg_num;
4134 : :
4135 : : /* The following should not occur here. */
4136 : 50685 : gcc_assert (wanted_type);
4137 : 50685 : gcc_assert (wanted_type != void_type_node || types->pointer_count);
4138 : :
4139 : 50685 : if (types->pointer_count == 0)
4140 : 29133 : wanted_type = lang_hooks.types.type_promotes_to (wanted_type);
4141 : :
4142 : 50685 : wanted_type = TYPE_MAIN_VARIANT (wanted_type);
4143 : :
4144 : 50685 : cur_param = types->param;
4145 : 50685 : if (!cur_param)
4146 : : {
4147 : 65 : format_type_warning (fmt_loc, UNKNOWN_LOCATION, types, wanted_type,
4148 : : NULL, fki, offset_to_type_start,
4149 : : conversion_char);
4150 : 65 : continue;
4151 : : }
4152 : :
4153 : 50620 : cur_type = TREE_TYPE (cur_param);
4154 : 50620 : if (cur_type == error_mark_node)
4155 : 0 : continue;
4156 : 50620 : orig_cur_type = cur_type;
4157 : 50620 : char_type_flag = 0;
4158 : :
4159 : 50620 : location_t param_loc = UNKNOWN_LOCATION;
4160 : 50620 : if (EXPR_HAS_LOCATION (cur_param))
4161 : 32905 : param_loc = EXPR_LOCATION (cur_param);
4162 : 17715 : else if (arglocs)
4163 : : {
4164 : : /* arg_num is 1-based. */
4165 : 17683 : gcc_assert (types->arg_num > 0);
4166 : 17683 : param_loc = (*arglocs)[types->arg_num - 1];
4167 : : }
4168 : :
4169 : 50620 : STRIP_NOPS (cur_param);
4170 : :
4171 : : /* Check the types of any additional pointer arguments
4172 : : that precede the "real" argument. */
4173 : 122739 : for (i = 0; i < types->pointer_count; ++i)
4174 : : {
4175 : 21674 : if (TREE_CODE (cur_type) == POINTER_TYPE)
4176 : : {
4177 : 21499 : cur_type = TREE_TYPE (cur_type);
4178 : 21499 : if (cur_type == error_mark_node)
4179 : : break;
4180 : :
4181 : : /* Check for writing through a NULL pointer. */
4182 : 21499 : if (types->writing_in_flag
4183 : 1715 : && i == 0
4184 : 1715 : && cur_param != 0
4185 : 23078 : && integer_zerop (cur_param))
4186 : 4 : warning (OPT_Wformat_, "writing through null pointer "
4187 : : "(argument %d)", arg_num);
4188 : :
4189 : : /* Check for reading through a NULL pointer. Ignore
4190 : : printf-family of functions as they are checked for
4191 : : null arguments by the middle-end. */
4192 : 21499 : if (fki->conversion_specs != print_char_table
4193 : 2042 : && types->reading_from_flag
4194 : 158 : && i == 0
4195 : 158 : && cur_param != 0
4196 : 21657 : && integer_zerop (cur_param))
4197 : 4 : warning (OPT_Wformat_, "reading through null pointer "
4198 : : "(argument %d)", arg_num);
4199 : :
4200 : 21499 : if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
4201 : 7797 : cur_param = TREE_OPERAND (cur_param, 0);
4202 : : else
4203 : : cur_param = 0;
4204 : :
4205 : : /* See if this is an attempt to write into a const type with
4206 : : scanf or with printf "%n". Note: the writing in happens
4207 : : at the first indirection only, if for example
4208 : : void * const * is passed to scanf %p; passing
4209 : : const void ** is simply passing an incompatible type. */
4210 : 21499 : if (types->writing_in_flag
4211 : 1715 : && i == 0
4212 : 23078 : && (TYPE_READONLY (cur_type)
4213 : 1569 : || (cur_param != 0
4214 : 40 : && (CONSTANT_CLASS_P (cur_param)
4215 : 40 : || (DECL_P (cur_param)
4216 : 40 : && TREE_READONLY (cur_param))))))
4217 : 10 : warning (OPT_Wformat_, "writing into constant object "
4218 : : "(argument %d)", arg_num);
4219 : :
4220 : : /* If there are extra type qualifiers beyond the first
4221 : : indirection, then this makes the types technically
4222 : : incompatible. */
4223 : 21499 : if (i > 0
4224 : 136 : && pedantic
4225 : 21539 : && (TYPE_READONLY (cur_type)
4226 : 38 : || TYPE_VOLATILE (cur_type)
4227 : 38 : || TYPE_ATOMIC (cur_type)
4228 : 38 : || TYPE_RESTRICT (cur_type)))
4229 : 2 : warning (OPT_Wformat_, "extra type qualifiers in format "
4230 : : "argument (argument %d)",
4231 : : arg_num);
4232 : :
4233 : : }
4234 : : else
4235 : : {
4236 : 175 : format_type_warning (fmt_loc, param_loc,
4237 : : types, wanted_type, orig_cur_type, fki,
4238 : : offset_to_type_start, conversion_char);
4239 : 175 : break;
4240 : : }
4241 : : }
4242 : :
4243 : 50620 : if (i < types->pointer_count)
4244 : 175 : continue;
4245 : :
4246 : 50445 : cur_type = TYPE_MAIN_VARIANT (cur_type);
4247 : :
4248 : : /* Check whether the argument type is a character type. This leniency
4249 : : only applies to certain formats, flagged with 'c'. */
4250 : 50445 : if (types->char_lenient_flag)
4251 : 19686 : char_type_flag = (cur_type == char_type_node
4252 : 1530 : || cur_type == signed_char_type_node
4253 : 21202 : || cur_type == unsigned_char_type_node);
4254 : :
4255 : : /* Check the type of the "real" argument, if there's a type we want. */
4256 : 50445 : if (lang_hooks.types_compatible_p (wanted_type, cur_type))
4257 : 47848 : continue;
4258 : : /* If we want 'void *', allow any pointer type.
4259 : : (Anything else would already have got a warning.)
4260 : : With -Wpedantic, only allow pointers to void and to character
4261 : : types. */
4262 : 2597 : if (wanted_type == void_type_node
4263 : 112 : && (!pedantic || (i == 1 && char_type_flag)))
4264 : 106 : continue;
4265 : : /* Don't warn about differences merely in signedness, unless
4266 : : -Wpedantic. With -Wpedantic, warn if the type is a pointer
4267 : : target and not a character type, and for character types at
4268 : : a second level of indirection. */
4269 : 3974 : if (TREE_CODE (wanted_type) == INTEGER_TYPE
4270 : 2239 : && TREE_CODE (cur_type) == INTEGER_TYPE
4271 : 2075 : && ((!pedantic && !warn_format_signedness)
4272 : 2075 : || (i == 0 && !warn_format_signedness)
4273 : 92 : || (i == 1 && char_type_flag))
4274 : 5215 : && (TYPE_UNSIGNED (wanted_type)
4275 : 2001 : ? wanted_type == c_common_unsigned_type (cur_type)
4276 : 1278 : : wanted_type == c_common_signed_type (cur_type)))
4277 : 1483 : continue;
4278 : : /* Don't warn about differences merely in signedness if we know
4279 : : that the current type is integer-promoted and its original type
4280 : : was unsigned such as that it is in the range of WANTED_TYPE. */
4281 : 1008 : if (TREE_CODE (wanted_type) == INTEGER_TYPE
4282 : 756 : && TREE_CODE (cur_type) == INTEGER_TYPE
4283 : 592 : && warn_format_signedness
4284 : 40 : && TYPE_UNSIGNED (wanted_type)
4285 : 32 : && cur_param != NULL_TREE
4286 : 1039 : && TREE_CODE (cur_param) == NOP_EXPR)
4287 : : {
4288 : 20 : tree t = TREE_TYPE (TREE_OPERAND (cur_param, 0));
4289 : 20 : if (TYPE_UNSIGNED (t)
4290 : 20 : && cur_type == lang_hooks.types.type_promotes_to (t))
4291 : 10 : continue;
4292 : : }
4293 : : /* Likewise, "signed char", "unsigned char" and "char" are
4294 : : equivalent but the above test won't consider them equivalent. */
4295 : 998 : if (wanted_type == char_type_node
4296 : 44 : && (!pedantic || i < 2)
4297 : 44 : && char_type_flag)
4298 : 18 : continue;
4299 : 980 : if (types->scalar_identity_flag
4300 : 0 : && (TREE_CODE (cur_type) == TREE_CODE (wanted_type)
4301 : 0 : || (INTEGRAL_TYPE_P (cur_type)
4302 : 0 : && INTEGRAL_TYPE_P (wanted_type)))
4303 : 980 : && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type))
4304 : 0 : continue;
4305 : : /* Now we have a type mismatch. */
4306 : 980 : format_type_warning (fmt_loc, param_loc, types,
4307 : : wanted_type, orig_cur_type, fki,
4308 : : offset_to_type_start, conversion_char);
4309 : : }
4310 : 49142 : }
4311 : :
4312 : : /* Given type TYPE, attempt to dereference the type N times
4313 : : (e.g. from ("int ***", 2) to "int *")
4314 : :
4315 : : Return the derefenced type, with any qualifiers
4316 : : such as "const" stripped from the result, or
4317 : : NULL if unsuccessful (e.g. TYPE is not a pointer type). */
4318 : :
4319 : : static tree
4320 : 3113 : deref_n_times (tree type, int n)
4321 : : {
4322 : 3113 : gcc_assert (type);
4323 : :
4324 : 3777 : for (int i = n; i > 0; i--)
4325 : : {
4326 : 929 : if (TREE_CODE (type) != POINTER_TYPE)
4327 : : return NULL_TREE;
4328 : 664 : type = TREE_TYPE (type);
4329 : : }
4330 : : /* Strip off any "const" etc. */
4331 : 2848 : return build_qualified_type (type, 0);
4332 : : }
4333 : :
4334 : : /* Lookup the format code for FORMAT_LEN within FLI,
4335 : : returning the string code for expressing it, or NULL
4336 : : if it is not found. */
4337 : :
4338 : : static const char *
4339 : 1089 : get_modifier_for_format_len (const format_length_info *fli,
4340 : : enum format_lengths format_len)
4341 : : {
4342 : 4086 : for (; fli->name; fli++)
4343 : : {
4344 : 4086 : if (fli->index == format_len)
4345 : 400 : return fli->name;
4346 : 3686 : if (fli->double_index == format_len)
4347 : 689 : return fli->double_name;
4348 : : }
4349 : : return NULL;
4350 : : }
4351 : :
4352 : : #if CHECKING_P
4353 : :
4354 : : namespace selftest {
4355 : :
4356 : : static void
4357 : 3 : test_get_modifier_for_format_len ()
4358 : : {
4359 : 3 : ASSERT_STREQ ("h",
4360 : : get_modifier_for_format_len (printf_length_specs, FMT_LEN_h));
4361 : 3 : ASSERT_STREQ ("hh",
4362 : : get_modifier_for_format_len (printf_length_specs, FMT_LEN_hh));
4363 : 3 : ASSERT_STREQ ("L",
4364 : : get_modifier_for_format_len (printf_length_specs, FMT_LEN_L));
4365 : 3 : ASSERT_EQ (NULL,
4366 : : get_modifier_for_format_len (printf_length_specs, FMT_LEN_none));
4367 : 3 : }
4368 : :
4369 : : } // namespace selftest
4370 : :
4371 : : #endif /* CHECKING_P */
4372 : :
4373 : : /* Determine if SPEC_TYPE and ARG_TYPE are sufficiently similar for a
4374 : : format_type_detail using SPEC_TYPE to be offered as a suggestion for
4375 : : Wformat type errors where the argument has type ARG_TYPE. */
4376 : :
4377 : : static bool
4378 : 19877 : matching_type_p (tree spec_type, tree arg_type)
4379 : : {
4380 : 19877 : gcc_assert (spec_type);
4381 : 19877 : gcc_assert (arg_type);
4382 : :
4383 : : /* If any of the types requires structural equality, we can't compare
4384 : : their canonical types. */
4385 : 19877 : if (TYPE_STRUCTURAL_EQUALITY_P (spec_type)
4386 : 19877 : || TYPE_STRUCTURAL_EQUALITY_P (arg_type))
4387 : : return false;
4388 : :
4389 : 18281 : spec_type = TYPE_CANONICAL (spec_type);
4390 : 18281 : arg_type = TYPE_CANONICAL (arg_type);
4391 : :
4392 : 18281 : if (TREE_CODE (spec_type) == INTEGER_TYPE
4393 : 14901 : && TREE_CODE (arg_type) == INTEGER_TYPE
4394 : 21614 : && (TYPE_UNSIGNED (spec_type)
4395 : 2353 : ? spec_type == c_common_unsigned_type (arg_type)
4396 : 1373 : : spec_type == c_common_signed_type (arg_type)))
4397 : 723 : return true;
4398 : :
4399 : 17558 : return spec_type == arg_type;
4400 : : }
4401 : :
4402 : : /* Subroutine of get_format_for_type.
4403 : :
4404 : : Generate a string containing the length modifier and conversion specifier
4405 : : that should be used to format arguments of type ARG_TYPE within FKI
4406 : : (effectively the inverse of the checking code).
4407 : :
4408 : : If CONVERSION_CHAR is not zero (the first pass), the resulting suggestion
4409 : : is required to use it, for correcting bogus length modifiers.
4410 : : If CONVERSION_CHAR is zero (the second pass), then allow any suggestion
4411 : : that matches ARG_TYPE.
4412 : :
4413 : : If successful, returns a non-NULL string which should be freed
4414 : : by the caller.
4415 : : Otherwise, returns NULL. */
4416 : :
4417 : : static char *
4418 : 1522 : get_format_for_type_1 (const format_kind_info *fki, tree arg_type,
4419 : : char conversion_char)
4420 : : {
4421 : 1522 : gcc_assert (arg_type);
4422 : :
4423 : 1522 : const format_char_info *spec;
4424 : 10426 : for (spec = &fki->conversion_specs[0];
4425 : 10426 : spec->format_chars;
4426 : : spec++)
4427 : : {
4428 : 9981 : if (conversion_char)
4429 : 8009 : if (!strchr (spec->format_chars, conversion_char))
4430 : 6868 : continue;
4431 : :
4432 : 6226 : tree effective_arg_type = deref_n_times (arg_type,
4433 : 3113 : spec->pointer_count);
4434 : 3113 : if (!effective_arg_type)
4435 : 265 : continue;
4436 : 43003 : for (int i = 0; i < FMT_LEN_MAX; i++)
4437 : : {
4438 : 41232 : const format_type_detail *ftd = &spec->types[i];
4439 : 41232 : if (!ftd->type || *ftd->type == NULL_TREE)
4440 : 21355 : continue;
4441 : 19877 : if (matching_type_p (*ftd->type, effective_arg_type))
4442 : : {
4443 : 1077 : const char *len_modifier
4444 : 1077 : = get_modifier_for_format_len (fki->length_char_specs,
4445 : : (enum format_lengths)i);
4446 : 1077 : if (!len_modifier)
4447 : 561 : len_modifier = "";
4448 : :
4449 : 1077 : if (conversion_char)
4450 : : /* We found a match, using the given conversion char - the
4451 : : length modifier was incorrect (or absent).
4452 : : Provide a suggestion using the conversion char with the
4453 : : correct length modifier for the type. */
4454 : 760 : return xasprintf ("%s%c", len_modifier, conversion_char);
4455 : : else
4456 : : /* 2nd pass: no match was possible using the user-provided
4457 : : conversion char, but we do have a match without using it.
4458 : : Provide a suggestion using the first conversion char
4459 : : listed for the given type. */
4460 : 317 : return xasprintf ("%s%c", len_modifier, spec->format_chars[0]);
4461 : : }
4462 : : }
4463 : : }
4464 : :
4465 : : return NULL;
4466 : : }
4467 : :
4468 : : /* Generate a string containing the length modifier and conversion specifier
4469 : : that should be used to format arguments of type ARG_TYPE within FKI
4470 : : (effectively the inverse of the checking code).
4471 : :
4472 : : If successful, returns a non-NULL string which should be freed
4473 : : by the caller.
4474 : : Otherwise, returns NULL. */
4475 : :
4476 : : static char *
4477 : 1141 : get_format_for_type (const format_kind_info *fki, tree arg_type,
4478 : : char conversion_char)
4479 : : {
4480 : 1141 : gcc_assert (arg_type);
4481 : 1141 : gcc_assert (conversion_char);
4482 : :
4483 : : /* First pass: look for a format_char_info containing CONVERSION_CHAR
4484 : : If we find one, then presumably the length modifier was incorrect
4485 : : (or absent). */
4486 : 1141 : char *result = get_format_for_type_1 (fki, arg_type, conversion_char);
4487 : 1141 : if (result)
4488 : : return result;
4489 : :
4490 : : /* Second pass: we didn't find a match for CONVERSION_CHAR, so try
4491 : : matching just on the type. */
4492 : 381 : return get_format_for_type_1 (fki, arg_type, '\0');
4493 : : }
4494 : :
4495 : : /* Attempt to get a string for use as a replacement fix-it hint for the
4496 : : source range in FMT_LOC.
4497 : :
4498 : : Preserve all of the text within the range of FMT_LOC up to
4499 : : OFFSET_TO_TYPE_START, replacing the rest with an appropriate
4500 : : length modifier and conversion specifier for ARG_TYPE, attempting
4501 : : to keep the user-provided CONVERSION_CHAR if possible.
4502 : :
4503 : : For example, given a long vs long long mismatch for arg5 here:
4504 : :
4505 : : 000000000111111111122222222223333333333|
4506 : : 123456789012345678901234567890123456789` column numbers
4507 : : 0000000000111111111122|
4508 : : 0123456789012345678901` string offsets
4509 : : V~~~~~~~~ : range of FMT_LOC, from cols 23-31
4510 : : sprintf (d, "before %-+*.*lld after", arg3, arg4, arg5);
4511 : : ^ ^
4512 : : | ` CONVERSION_CHAR: 'd'
4513 : : type starts here
4514 : :
4515 : : where OFFSET_TO_TYPE_START is 13 (the offset to the "lld" within the
4516 : : STRING_CST), where the user provided:
4517 : : %-+*.*lld
4518 : : the result (assuming "long" argument 5) should be:
4519 : : %-+*.*ld
4520 : :
4521 : : If successful, returns a non-NULL string which should be freed
4522 : : by the caller.
4523 : : Otherwise, returns NULL. */
4524 : :
4525 : : static char *
4526 : 1220 : get_corrected_substring (const substring_loc &fmt_loc,
4527 : : format_wanted_type *type, tree arg_type,
4528 : : const format_kind_info *fki,
4529 : : int offset_to_type_start, char conversion_char)
4530 : : {
4531 : : /* Attempt to provide hints for argument types, but not for field widths
4532 : : and precisions. */
4533 : 1220 : if (!arg_type)
4534 : : return NULL;
4535 : 1155 : if (type->kind != CF_KIND_FORMAT)
4536 : : return NULL;
4537 : :
4538 : : /* Locate the current code within the source range, rejecting
4539 : : any awkward cases where the format string occupies more than
4540 : : one line.
4541 : : Lookup the place where the type starts (including any length
4542 : : modifiers), getting it as the caret location. */
4543 : 1073 : substring_loc type_loc (fmt_loc);
4544 : 1073 : type_loc.set_caret_index (offset_to_type_start);
4545 : :
4546 : 1073 : location_t fmt_substring_loc;
4547 : 1073 : const char *err = type_loc.get_location (&fmt_substring_loc);
4548 : 1073 : if (err)
4549 : : return NULL;
4550 : :
4551 : 1044 : source_range fmt_substring_range
4552 : 1044 : = get_range_from_loc (line_table, fmt_substring_loc);
4553 : :
4554 : 1044 : expanded_location caret
4555 : 1044 : = expand_location_to_spelling_point (fmt_substring_loc);
4556 : 1044 : expanded_location start
4557 : 1044 : = expand_location_to_spelling_point (fmt_substring_range.m_start);
4558 : 1044 : expanded_location finish
4559 : 1044 : = expand_location_to_spelling_point (fmt_substring_range.m_finish);
4560 : 1044 : if (caret.file != start.file)
4561 : : return NULL;
4562 : 1041 : if (start.file != finish.file)
4563 : : return NULL;
4564 : 1041 : if (caret.line != start.line)
4565 : : return NULL;
4566 : 1033 : if (start.line != finish.line)
4567 : : return NULL;
4568 : 1033 : if (start.column > caret.column)
4569 : : return NULL;
4570 : 1033 : if (start.column > finish.column)
4571 : : return NULL;
4572 : 1033 : if (caret.column > finish.column)
4573 : : return NULL;
4574 : :
4575 : 1033 : char_span line
4576 : 1033 : = global_dc->get_file_cache ().get_source_line (start.file, start.line);
4577 : 1033 : if (!line)
4578 : : return NULL;
4579 : :
4580 : : /* If we got this far, then we have the line containing the
4581 : : existing conversion specification.
4582 : :
4583 : : Generate a trimmed copy, containing the prefix part of the conversion
4584 : : specification, up to the (but not including) the length modifier.
4585 : : In the above example, this would be "%-+*.*". */
4586 : 1033 : int length_up_to_type = caret.column - start.column;
4587 : 1033 : char_span prefix_span = line.subspan (start.column - 1, length_up_to_type);
4588 : 1033 : char *prefix = prefix_span.xstrdup ();
4589 : :
4590 : : /* Now attempt to generate a suggestion for the rest of the specification
4591 : : (length modifier and conversion char), based on ARG_TYPE and
4592 : : CONVERSION_CHAR.
4593 : : In the above example, this would be "ld". */
4594 : 1033 : char *format_for_type = get_format_for_type (fki, arg_type, conversion_char);
4595 : 1033 : if (!format_for_type)
4596 : : {
4597 : 64 : free (prefix);
4598 : 64 : return NULL;
4599 : : }
4600 : :
4601 : : /* Success. Generate the resulting suggestion for the whole range of
4602 : : FMT_LOC by concatenating the two strings.
4603 : : In the above example, this would be "%-+*.*ld". */
4604 : 969 : char *result = concat (prefix, format_for_type, NULL);
4605 : 969 : free (format_for_type);
4606 : 969 : free (prefix);
4607 : 969 : return result;
4608 : : }
4609 : :
4610 : : /* Helper class for adding zero or more trailing '*' to types.
4611 : :
4612 : : The format type and name exclude any '*' for pointers, so those
4613 : : must be formatted manually. For all the types we currently have,
4614 : : this is adequate, but formats taking pointers to functions or
4615 : : arrays would require the full type to be built up in order to
4616 : : print it with %T. */
4617 : :
4618 : : class indirection_suffix
4619 : : {
4620 : : public:
4621 : 1602 : indirection_suffix (int pointer_count) : m_pointer_count (pointer_count) {}
4622 : :
4623 : : /* Determine the size of the buffer (including NUL-terminator). */
4624 : :
4625 : 1602 : size_t get_buffer_size () const
4626 : : {
4627 : 1602 : return m_pointer_count + 2;
4628 : : }
4629 : :
4630 : : /* Write the '*' to DST and add a NUL-terminator. */
4631 : :
4632 : 1602 : void fill_buffer (char *dst) const
4633 : : {
4634 : 1602 : if (m_pointer_count == 0)
4635 : 1097 : dst[0] = 0;
4636 : 505 : else if (c_dialect_cxx ())
4637 : : {
4638 : 221 : memset (dst, '*', m_pointer_count);
4639 : 221 : dst[m_pointer_count] = 0;
4640 : : }
4641 : : else
4642 : : {
4643 : 284 : dst[0] = ' ';
4644 : 284 : memset (dst + 1, '*', m_pointer_count);
4645 : 284 : dst[m_pointer_count + 1] = 0;
4646 : : }
4647 : 1602 : }
4648 : :
4649 : : private:
4650 : : int m_pointer_count;
4651 : : };
4652 : :
4653 : : /* Subclass of range_label for labelling the range in the format string
4654 : : with the type in question, adding trailing '*' for pointer_count. */
4655 : :
4656 : 3 : class range_label_for_format_type_mismatch
4657 : : : public range_label_for_type_mismatch
4658 : : {
4659 : : public:
4660 : 1223 : range_label_for_format_type_mismatch (tree labelled_type, tree other_type,
4661 : : int pointer_count)
4662 : 1223 : : range_label_for_type_mismatch (labelled_type, other_type),
4663 : 1223 : m_pointer_count (pointer_count)
4664 : : {
4665 : : }
4666 : :
4667 : 382 : label_text get_text (unsigned range_idx) const final override
4668 : : {
4669 : 382 : label_text text = range_label_for_type_mismatch::get_text (range_idx);
4670 : 382 : if (text.get () == NULL)
4671 : 0 : return text;
4672 : :
4673 : 382 : indirection_suffix suffix (m_pointer_count);
4674 : 382 : char *p = (char *) alloca (suffix.get_buffer_size ());
4675 : 382 : suffix.fill_buffer (p);
4676 : :
4677 : 382 : char *result = concat (text.get (), p, NULL);
4678 : 382 : return label_text::take (result);
4679 : 382 : }
4680 : :
4681 : : private:
4682 : : int m_pointer_count;
4683 : : };
4684 : :
4685 : : /* Give a warning about a format argument of different type from that expected.
4686 : : The range of the diagnostic is taken from WHOLE_FMT_LOC; the caret location
4687 : : is based on the location of the char at TYPE->offset_loc.
4688 : : PARAM_LOC is the location of the relevant argument, or UNKNOWN_LOCATION
4689 : : if this is unavailable.
4690 : : WANTED_TYPE is the type the argument should have,
4691 : : possibly stripped of pointer dereferences. The description (such as "field
4692 : : precision"), the placement in the format string, a possibly more
4693 : : friendly name of WANTED_TYPE, and the number of pointer dereferences
4694 : : are taken from TYPE. ARG_TYPE is the type of the actual argument,
4695 : : or NULL if it is missing.
4696 : :
4697 : : OFFSET_TO_TYPE_START is the offset within the execution-charset encoded
4698 : : format string to where type information begins for the conversion
4699 : : (the length modifier and conversion specifier).
4700 : : CONVERSION_CHAR is the user-provided conversion specifier.
4701 : :
4702 : : For example, given a type mismatch for argument 5 here:
4703 : :
4704 : : 00000000011111111112222222222333333333344444444445555555555|
4705 : : 12345678901234567890123456789012345678901234567890123456789` column numbers
4706 : : 0000000000111111111122|
4707 : : 0123456789012345678901` offsets within STRING_CST
4708 : : V~~~~~~~~ : range of WHOLE_FMT_LOC, from cols 23-31
4709 : : sprintf (d, "before %-+*.*lld after", int_expr, int_expr, long_expr);
4710 : : ^ ^ ^~~~~~~~~
4711 : : | ` CONVERSION_CHAR: 'd' PARAM_LOC
4712 : : type starts here
4713 : :
4714 : : OFFSET_TO_TYPE_START is 13, the offset to the "lld" within the
4715 : : STRING_CST. */
4716 : :
4717 : : static void
4718 : 1220 : format_type_warning (const substring_loc &whole_fmt_loc,
4719 : : location_t param_loc,
4720 : : format_wanted_type *type,
4721 : : tree wanted_type, tree arg_type,
4722 : : const format_kind_info *fki,
4723 : : int offset_to_type_start,
4724 : : char conversion_char)
4725 : : {
4726 : 1220 : enum format_specifier_kind kind = type->kind;
4727 : 1220 : const char *wanted_type_name = type->wanted_type_name;
4728 : 1220 : const char *format_start = type->format_start;
4729 : 1220 : int format_length = type->format_length;
4730 : 1220 : int pointer_count = type->pointer_count;
4731 : 1220 : int arg_num = type->arg_num;
4732 : :
4733 : : /* If ARG_TYPE is a typedef with a misleading name (for example,
4734 : : size_t but not the standard size_t expected by printf %zu), avoid
4735 : : printing the typedef name. */
4736 : 1220 : if (wanted_type_name
4737 : 1220 : && arg_type
4738 : 226 : && TYPE_NAME (arg_type)
4739 : 120 : && TREE_CODE (TYPE_NAME (arg_type)) == TYPE_DECL
4740 : 120 : && DECL_NAME (TYPE_NAME (arg_type))
4741 : 1340 : && !strcmp (wanted_type_name,
4742 : 120 : lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2)))
4743 : 0 : arg_type = TYPE_MAIN_VARIANT (arg_type);
4744 : :
4745 : 1220 : indirection_suffix suffix (pointer_count);
4746 : 1220 : char *p = (char *) alloca (suffix.get_buffer_size ());
4747 : 1220 : suffix.fill_buffer (p);
4748 : :
4749 : : /* WHOLE_FMT_LOC has the caret at the end of the range.
4750 : : Set the caret to be at the offset from TYPE. Subtract one
4751 : : from the offset for the same reason as in format_warning_at_char. */
4752 : 1220 : substring_loc fmt_loc (whole_fmt_loc);
4753 : 1220 : fmt_loc.set_caret_index (type->offset_loc - 1);
4754 : :
4755 : 1220 : range_label_for_format_type_mismatch fmt_label (wanted_type, arg_type,
4756 : 1220 : pointer_count);
4757 : 1220 : range_label_for_type_mismatch param_label (arg_type, wanted_type);
4758 : :
4759 : : /* Get a string for use as a replacement fix-it hint for the range in
4760 : : fmt_loc, or NULL. */
4761 : 1220 : char *corrected_substring
4762 : 1220 : = get_corrected_substring (fmt_loc, type, arg_type, fki,
4763 : : offset_to_type_start, conversion_char);
4764 : 1220 : format_string_diagnostic_t diag (fmt_loc, &fmt_label, param_loc, ¶m_label,
4765 : 1220 : corrected_substring);
4766 : 1220 : if (wanted_type_name)
4767 : : {
4768 : 232 : if (arg_type)
4769 : 226 : diag.emit_warning
4770 : 226 : (OPT_Wformat_,
4771 : : "%s %<%s%.*s%> expects argument of type %<%s%s%>, "
4772 : : "but argument %d has type %qT",
4773 : 226 : gettext (kind_descriptions[kind]),
4774 : : (kind == CF_KIND_FORMAT ? "%" : ""),
4775 : : format_length, format_start,
4776 : : wanted_type_name, p, arg_num, arg_type);
4777 : : else
4778 : 6 : diag.emit_warning
4779 : 6 : (OPT_Wformat_,
4780 : : "%s %<%s%.*s%> expects a matching %<%s%s%> argument",
4781 : 6 : gettext (kind_descriptions[kind]),
4782 : : (kind == CF_KIND_FORMAT ? "%" : ""),
4783 : : format_length, format_start, wanted_type_name, p);
4784 : : }
4785 : : else
4786 : : {
4787 : 988 : if (arg_type)
4788 : 929 : diag.emit_warning
4789 : 929 : (OPT_Wformat_,
4790 : : "%s %<%s%.*s%> expects argument of type %<%T%s%>, "
4791 : : "but argument %d has type %qT",
4792 : 929 : gettext (kind_descriptions[kind]),
4793 : : (kind == CF_KIND_FORMAT ? "%" : ""),
4794 : : format_length, format_start,
4795 : : wanted_type, p, arg_num, arg_type);
4796 : : else
4797 : 59 : diag.emit_warning
4798 : 59 : (OPT_Wformat_,
4799 : : "%s %<%s%.*s%> expects a matching %<%T%s%> argument",
4800 : 59 : gettext (kind_descriptions[kind]),
4801 : : (kind == CF_KIND_FORMAT ? "%" : ""),
4802 : : format_length, format_start, wanted_type, p);
4803 : : }
4804 : :
4805 : 1220 : free (corrected_substring);
4806 : 1220 : }
4807 : :
4808 : :
4809 : : /* Given a format_char_info array FCI, and a character C, this function
4810 : : returns the index into the conversion_specs where that specifier's
4811 : : data is located. The character must exist. */
4812 : : static unsigned int
4813 : 2 : find_char_info_specifier_index (const format_char_info *fci, int c)
4814 : : {
4815 : 2 : unsigned i;
4816 : :
4817 : 12 : for (i = 0; fci->format_chars; i++, fci++)
4818 : 12 : if (strchr (fci->format_chars, c))
4819 : 2 : return i;
4820 : :
4821 : : /* We shouldn't be looking for a non-existent specifier. */
4822 : 0 : gcc_unreachable ();
4823 : : }
4824 : :
4825 : : /* Given a format_length_info array FLI, and a character C, this
4826 : : function returns the index into the conversion_specs where that
4827 : : modifier's data is located. The character must exist. */
4828 : : static unsigned int
4829 : 8 : find_length_info_modifier_index (const format_length_info *fli, int c)
4830 : : {
4831 : 8 : unsigned i;
4832 : :
4833 : 16 : for (i = 0; fli->name; i++, fli++)
4834 : 16 : if (strchr (fli->name, c))
4835 : 8 : return i;
4836 : :
4837 : : /* We shouldn't be looking for a non-existent modifier. */
4838 : 0 : gcc_unreachable ();
4839 : : }
4840 : :
4841 : : /* Determine the type of HOST_WIDE_INT in the code being compiled for
4842 : : use in GCC's __asm_fprintf__ custom format attribute. You must
4843 : : have set dynamic_format_types before calling this function. */
4844 : : static void
4845 : 10 : init_dynamic_asm_fprintf_info (void)
4846 : : {
4847 : 10 : static tree hwi;
4848 : :
4849 : 10 : if (!hwi)
4850 : : {
4851 : 10 : format_length_info *new_asm_fprintf_length_specs;
4852 : 10 : unsigned int i;
4853 : :
4854 : : /* Find the underlying type for HOST_WIDE_INT. For the %w
4855 : : length modifier to work, one must have issued: "typedef
4856 : : HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code
4857 : : prior to using that modifier. */
4858 : 10 : hwi = maybe_get_identifier ("__gcc_host_wide_int__");
4859 : 10 : if (!hwi)
4860 : : {
4861 : 2 : error ("%<__gcc_host_wide_int__%> is not defined as a type");
4862 : 2 : return;
4863 : : }
4864 : 8 : hwi = identifier_global_value (hwi);
4865 : 8 : if (!hwi || TREE_CODE (hwi) != TYPE_DECL)
4866 : : {
4867 : 4 : error ("%<__gcc_host_wide_int__%> is not defined as a type");
4868 : 4 : return;
4869 : : }
4870 : 4 : hwi = DECL_ORIGINAL_TYPE (hwi);
4871 : 4 : gcc_assert (hwi);
4872 : 4 : if (hwi != long_integer_type_node && hwi != long_long_integer_type_node)
4873 : : {
4874 : 2 : error ("%<__gcc_host_wide_int__%> is not defined as %<long%>"
4875 : : " or %<long long%>");
4876 : 2 : return;
4877 : : }
4878 : :
4879 : : /* Create a new (writable) copy of asm_fprintf_length_specs. */
4880 : 2 : new_asm_fprintf_length_specs = (format_length_info *)
4881 : 2 : xmemdup (asm_fprintf_length_specs,
4882 : : sizeof (asm_fprintf_length_specs),
4883 : : sizeof (asm_fprintf_length_specs));
4884 : :
4885 : : /* HOST_WIDE_INT must be one of 'long' or 'long long'. */
4886 : 2 : i = find_length_info_modifier_index (new_asm_fprintf_length_specs, 'w');
4887 : 2 : if (hwi == long_integer_type_node)
4888 : 0 : new_asm_fprintf_length_specs[i].index = FMT_LEN_l;
4889 : 2 : else if (hwi == long_long_integer_type_node)
4890 : 2 : new_asm_fprintf_length_specs[i].index = FMT_LEN_ll;
4891 : : else
4892 : 0 : gcc_unreachable ();
4893 : :
4894 : : /* Assign the new data for use. */
4895 : 2 : dynamic_format_types[asm_fprintf_format_type].length_char_specs =
4896 : : new_asm_fprintf_length_specs;
4897 : : }
4898 : : }
4899 : :
4900 : : static const format_length_info*
4901 : 76 : get_init_dynamic_hwi (void)
4902 : : {
4903 : 76 : static tree hwi;
4904 : 76 : static format_length_info *diag_ls;
4905 : :
4906 : 76 : if (!hwi)
4907 : : {
4908 : 46 : unsigned int i;
4909 : :
4910 : : /* Find the underlying type for HOST_WIDE_INT. For the 'w'
4911 : : length modifier to work, one must have issued: "typedef
4912 : : HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code
4913 : : prior to using that modifier. */
4914 : 46 : if ((hwi = maybe_get_identifier ("__gcc_host_wide_int__")))
4915 : : {
4916 : 12 : hwi = identifier_global_value (hwi);
4917 : 12 : if (hwi)
4918 : : {
4919 : 10 : if (TREE_CODE (hwi) != TYPE_DECL)
4920 : : {
4921 : 2 : error ("%<__gcc_host_wide_int__%> is not defined as a type");
4922 : 2 : hwi = 0;
4923 : : }
4924 : : else
4925 : : {
4926 : 8 : hwi = DECL_ORIGINAL_TYPE (hwi);
4927 : 8 : gcc_assert (hwi);
4928 : 8 : if (hwi != long_integer_type_node
4929 : 8 : && hwi != long_long_integer_type_node)
4930 : : {
4931 : 2 : error ("%<__gcc_host_wide_int__%> is not defined"
4932 : : " as %<long%> or %<long long%>");
4933 : 2 : hwi = 0;
4934 : : }
4935 : : }
4936 : : }
4937 : : }
4938 : 46 : if (!diag_ls)
4939 : 46 : diag_ls = (format_length_info *)
4940 : 46 : xmemdup (gcc_diag_length_specs,
4941 : : sizeof (gcc_diag_length_specs),
4942 : : sizeof (gcc_diag_length_specs));
4943 : 46 : if (hwi)
4944 : : {
4945 : : /* HOST_WIDE_INT must be one of 'long' or 'long long'. */
4946 : 6 : i = find_length_info_modifier_index (diag_ls, 'w');
4947 : 6 : if (hwi == long_integer_type_node)
4948 : 0 : diag_ls[i].index = FMT_LEN_l;
4949 : 6 : else if (hwi == long_long_integer_type_node)
4950 : 6 : diag_ls[i].index = FMT_LEN_ll;
4951 : : else
4952 : 0 : gcc_unreachable ();
4953 : : }
4954 : : }
4955 : 76 : return diag_ls;
4956 : : }
4957 : :
4958 : : /* Determine the type of a "locus" in the code being compiled for use
4959 : : in GCC's __gcc_gfc__ custom format attribute. You must have set
4960 : : dynamic_format_types before calling this function. */
4961 : : static void
4962 : 4 : init_dynamic_gfc_info (void)
4963 : : {
4964 : 4 : dynamic_format_types[gcc_gfc_format_type].length_char_specs
4965 : 4 : = get_init_dynamic_hwi ();
4966 : :
4967 : 4 : if (!locus)
4968 : : {
4969 : 4 : static format_char_info *gfc_fci;
4970 : :
4971 : : /* For the GCC __gcc_gfc__ custom format specifier to work, one
4972 : : must have declared 'locus' prior to using this attribute. If
4973 : : we haven't seen this declarations then you shouldn't use the
4974 : : specifier requiring that type. */
4975 : 4 : if ((locus = maybe_get_identifier ("locus")))
4976 : : {
4977 : 4 : locus = identifier_global_value (locus);
4978 : 4 : if (locus)
4979 : : {
4980 : 4 : if (TREE_CODE (locus) != TYPE_DECL
4981 : 4 : || TREE_TYPE (locus) == error_mark_node)
4982 : : {
4983 : 2 : error ("%<locus%> is not defined as a type");
4984 : 2 : locus = 0;
4985 : : }
4986 : : else
4987 : 2 : locus = TREE_TYPE (locus);
4988 : : }
4989 : : }
4990 : :
4991 : : /* Assign the new data for use. */
4992 : :
4993 : : /* Handle the __gcc_gfc__ format specifics. */
4994 : 4 : if (!gfc_fci)
4995 : 8 : dynamic_format_types[gcc_gfc_format_type].conversion_specs =
4996 : 4 : gfc_fci = (format_char_info *)
4997 : 4 : xmemdup (gcc_gfc_char_table,
4998 : : sizeof (gcc_gfc_char_table),
4999 : : sizeof (gcc_gfc_char_table));
5000 : 4 : if (locus)
5001 : : {
5002 : 2 : const unsigned i = find_char_info_specifier_index (gfc_fci, 'L');
5003 : 2 : gfc_fci[i].types[0].type = &locus;
5004 : 2 : gfc_fci[i].pointer_count = 1;
5005 : : }
5006 : : }
5007 : 4 : }
5008 : :
5009 : : /* Lookup the type named NAME and return a NAME type if found.
5010 : : Otherwise, return void_type_node if NAME has not been used yet,
5011 : : or NULL_TREE if NAME is not a type (issuing an error). */
5012 : :
5013 : : static tree
5014 : 164 : get_named_type (const char *name)
5015 : : {
5016 : 164 : if (tree result = maybe_get_identifier (name))
5017 : : {
5018 : 24 : result = identifier_global_tag (result);
5019 : 24 : if (result)
5020 : : {
5021 : 19 : if (TYPE_P (result))
5022 : : ;
5023 : 8 : else if (TREE_CODE (result) == TYPE_DECL)
5024 : 8 : result = TREE_TYPE (result);
5025 : : else
5026 : : {
5027 : 0 : error ("%qs is not defined as a type", name);
5028 : 0 : result = NULL_TREE;
5029 : : }
5030 : : }
5031 : 24 : return result;
5032 : : }
5033 : : else
5034 : 140 : return void_type_node;
5035 : : }
5036 : :
5037 : : /* Determine the types of "tree" and "location_t" in the code being
5038 : : compiled for use in GCC's diagnostic custom format attributes. You
5039 : : must have set dynamic_format_types before calling this function. */
5040 : : static void
5041 : 72 : init_dynamic_diag_info (void)
5042 : : {
5043 : : /* For the GCC-diagnostics custom format specifiers to work, one
5044 : : must have declared 'tree' and 'location_t' prior to using those
5045 : : attributes. If we haven't seen these declarations then
5046 : : the specifiers requiring these types shouldn't be used.
5047 : : However we don't force a hard ICE because we may see only one
5048 : : or the other type. */
5049 : 72 : if (tree loc = maybe_get_identifier ("location_t"))
5050 : : {
5051 : 48 : loc = identifier_global_value (loc);
5052 : 48 : if (loc && TREE_CODE (loc) != TYPE_DECL)
5053 : 2 : error ("%<location_t%> is not defined as a type");
5054 : : }
5055 : :
5056 : : /* Initialize the global tree node type local to this file. */
5057 : 72 : if (!local_tree_type_node
5058 : 30 : || local_tree_type_node == void_type_node)
5059 : : {
5060 : : /* We need to grab the underlying 'union tree_node' so peek into
5061 : : an extra type level. */
5062 : 42 : if ((local_tree_type_node = maybe_get_identifier ("tree")))
5063 : : {
5064 : 17 : local_tree_type_node
5065 : 17 : = identifier_global_value (local_tree_type_node);
5066 : 17 : if (local_tree_type_node)
5067 : : {
5068 : 15 : if (TREE_CODE (local_tree_type_node) != TYPE_DECL)
5069 : : {
5070 : 2 : error ("%<tree%> is not defined as a type");
5071 : 2 : local_tree_type_node = NULL_TREE;
5072 : : }
5073 : 13 : else if (TREE_CODE (TREE_TYPE (local_tree_type_node))
5074 : : != POINTER_TYPE)
5075 : : {
5076 : 2 : error ("%<tree%> is not defined as a pointer type");
5077 : 2 : local_tree_type_node = NULL_TREE;
5078 : : }
5079 : : else
5080 : 11 : local_tree_type_node
5081 : 11 : = TREE_TYPE (TREE_TYPE (local_tree_type_node));
5082 : : }
5083 : : }
5084 : : else
5085 : 25 : local_tree_type_node = void_type_node;
5086 : : }
5087 : :
5088 : : /* Similar to the above but for gimple*. */
5089 : 72 : if (!local_gimple_ptr_node
5090 : 30 : || local_gimple_ptr_node == void_type_node)
5091 : 50 : local_gimple_ptr_node = get_named_type ("gimple");
5092 : :
5093 : : /* Similar to the above but for cgraph_node*. */
5094 : 72 : if (!local_cgraph_node_ptr_node
5095 : 30 : || local_cgraph_node_ptr_node == void_type_node)
5096 : 50 : local_cgraph_node_ptr_node = get_named_type ("cgraph_node");
5097 : :
5098 : : /* Similar to the above but for diagnostic_event_id_t*. */
5099 : 72 : if (!local_event_ptr_node
5100 : 30 : || local_event_ptr_node == void_type_node)
5101 : 64 : local_event_ptr_node = get_named_type ("diagnostic_event_id_t");
5102 : :
5103 : : /* All the GCC diag formats use the same length specs. */
5104 : 144 : dynamic_format_types[gcc_diag_format_type].length_char_specs =
5105 : 72 : dynamic_format_types[gcc_tdiag_format_type].length_char_specs =
5106 : 72 : dynamic_format_types[gcc_cdiag_format_type].length_char_specs =
5107 : 72 : dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs =
5108 : 72 : dynamic_format_types[gcc_dump_printf_format_type].length_char_specs
5109 : 72 : = get_init_dynamic_hwi ();
5110 : :
5111 : : /* It's safe to "re-initialize these to the same values. */
5112 : 72 : dynamic_format_types[gcc_diag_format_type].conversion_specs =
5113 : : gcc_diag_char_table;
5114 : 72 : dynamic_format_types[gcc_tdiag_format_type].conversion_specs =
5115 : : gcc_tdiag_char_table;
5116 : 72 : dynamic_format_types[gcc_cdiag_format_type].conversion_specs =
5117 : : gcc_cdiag_char_table;
5118 : 72 : dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs =
5119 : : gcc_cxxdiag_char_table;
5120 : 72 : dynamic_format_types[gcc_dump_printf_format_type].conversion_specs =
5121 : : gcc_dump_printf_char_table;
5122 : 72 : }
5123 : :
5124 : : #ifdef TARGET_FORMAT_TYPES
5125 : : extern const format_kind_info TARGET_FORMAT_TYPES[];
5126 : : #endif
5127 : :
5128 : : #ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
5129 : : extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
5130 : : #endif
5131 : : #ifdef TARGET_OVERRIDES_FORMAT_INIT
5132 : : extern void TARGET_OVERRIDES_FORMAT_INIT (void);
5133 : : #endif
5134 : :
5135 : : /* Attributes such as "printf" are equivalent to those such as
5136 : : "gnu_printf" unless this is overridden by a target. */
5137 : : static const target_ovr_attr gnu_target_overrides_format_attributes[] =
5138 : : {
5139 : : { "gnu_printf", "printf" },
5140 : : { "gnu_scanf", "scanf" },
5141 : : { "gnu_strftime", "strftime" },
5142 : : { "gnu_strfmon", "strfmon" },
5143 : : { NULL, NULL }
5144 : : };
5145 : :
5146 : : /* Translate to unified attribute name. This is used in decode_format_type and
5147 : : decode_format_attr. In attr_name the user specified argument is passed. It
5148 : : returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
5149 : : or the attr_name passed to this function, if there is no matching entry. */
5150 : : static const char *
5151 : 10398766 : convert_format_name_to_system_name (const char *attr_name)
5152 : : {
5153 : 10398766 : int i;
5154 : :
5155 : 10398766 : if (attr_name == NULL || *attr_name == 0
5156 : 20797532 : || startswith (attr_name, "gcc_"))
5157 : : return attr_name;
5158 : : #ifdef TARGET_OVERRIDES_FORMAT_INIT
5159 : : TARGET_OVERRIDES_FORMAT_INIT ();
5160 : : #endif
5161 : :
5162 : : #ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
5163 : : /* Check if format attribute is overridden by target. */
5164 : : if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
5165 : : {
5166 : : for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
5167 : : {
5168 : : if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
5169 : : attr_name))
5170 : : return attr_name;
5171 : : if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
5172 : : attr_name))
5173 : : return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
5174 : : }
5175 : : }
5176 : : #endif
5177 : : /* Otherwise default to gnu format. */
5178 : 4451833 : for (i = 0;
5179 : 14849447 : gnu_target_overrides_format_attributes[i].named_attr_src != NULL;
5180 : : ++i)
5181 : : {
5182 : 14849341 : if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
5183 : : attr_name))
5184 : : return attr_name;
5185 : 14836108 : if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
5186 : : attr_name))
5187 : 10384275 : return gnu_target_overrides_format_attributes[i].named_attr_src;
5188 : : }
5189 : :
5190 : : return attr_name;
5191 : : }
5192 : :
5193 : : /* Handle a "format" attribute; arguments as in
5194 : : struct attribute_spec.handler. */
5195 : : tree
5196 : 10347823 : handle_format_attribute (tree node[3], tree atname, tree args,
5197 : : int flags, bool *no_add_attrs)
5198 : : {
5199 : 10347823 : const_tree type = *node;
5200 : : /* NODE[2] may be NULL, and it also may be a PARM_DECL for function
5201 : : pointers. */
5202 : 10347802 : const_tree fndecl = ((node[2] && TREE_CODE (node[2]) == FUNCTION_DECL)
5203 : 10347823 : ? node[2] : NULL_TREE);
5204 : 10347823 : function_format_info info;
5205 : :
5206 : : #ifdef TARGET_FORMAT_TYPES
5207 : : /* If the target provides additional format types, we need to
5208 : : add them to FORMAT_TYPES at first use. */
5209 : : if (!dynamic_format_types)
5210 : : {
5211 : : dynamic_format_types = XNEWVEC (format_kind_info,
5212 : : n_format_types + TARGET_N_FORMAT_TYPES);
5213 : : memcpy (dynamic_format_types, format_types_orig,
5214 : : sizeof (format_types_orig));
5215 : : memcpy (&dynamic_format_types[n_format_types], TARGET_FORMAT_TYPES,
5216 : : TARGET_N_FORMAT_TYPES * sizeof (dynamic_format_types[0]));
5217 : :
5218 : : format_types = dynamic_format_types;
5219 : : /* Provide a reference for the first potential external type. */
5220 : : first_target_format_type = n_format_types;
5221 : : n_format_types += TARGET_N_FORMAT_TYPES;
5222 : : }
5223 : : #endif
5224 : :
5225 : : /* Canonicalize name of format function. */
5226 : 10347823 : if (TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
5227 : 10347821 : TREE_VALUE (args) = canonicalize_attr_name (TREE_VALUE (args));
5228 : :
5229 : : /* record the flags for check_function_format */
5230 : 10347823 : TREE_PURPOSE (args) = build_int_cst (unsigned_type_node, flags);
5231 : :
5232 : 10347932 : if (!decode_format_attr (fndecl ? fndecl : type, atname, args, &info,
5233 : : /* validated_p = */false))
5234 : : {
5235 : 48 : *no_add_attrs = true;
5236 : 48 : return NULL_TREE;
5237 : : }
5238 : :
5239 : 10347775 : if (prototype_p (type))
5240 : : {
5241 : 10347743 : if (!check_format_string (type, info.format_num, flags,
5242 : 10347743 : no_add_attrs, info.format_type))
5243 : : return NULL_TREE;
5244 : :
5245 : 10347743 : if (info.first_arg_num != 0)
5246 : : {
5247 : 5468757 : unsigned HOST_WIDE_INT arg_num = 1;
5248 : 5468757 : function_args_iterator iter;
5249 : 5468757 : tree arg_type;
5250 : :
5251 : : /* Verify that first_arg_num points to the last arg,
5252 : : the ... */
5253 : 18104923 : FOREACH_FUNCTION_ARGS (type, arg_type, iter)
5254 : 12636166 : arg_num++;
5255 : :
5256 : 5468757 : if (arg_num != info.first_arg_num)
5257 : : {
5258 : 2 : if (!(flags & (int) ATTR_FLAG_BUILT_IN))
5259 : 2 : error ("argument to be formatted is not %<...%>");
5260 : 2 : *no_add_attrs = true;
5261 : 2 : return NULL_TREE;
5262 : : }
5263 : : }
5264 : : }
5265 : :
5266 : : /* Check if this is a strftime variant. Just for this variant
5267 : : FMT_FLAG_ARG_CONVERT is not set. */
5268 : 10347773 : if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0
5269 : 410004 : && info.first_arg_num != 0)
5270 : : {
5271 : 2 : error ("strftime formats cannot format arguments");
5272 : 2 : *no_add_attrs = true;
5273 : 2 : return NULL_TREE;
5274 : : }
5275 : :
5276 : : /* If this is a custom GCC-internal format type, we have to
5277 : : initialize certain bits at runtime. */
5278 : 10347771 : if (info.format_type == asm_fprintf_format_type
5279 : 10347761 : || info.format_type == gcc_gfc_format_type
5280 : 10347757 : || info.format_type == gcc_diag_format_type
5281 : 10347726 : || info.format_type == gcc_tdiag_format_type
5282 : 10347705 : || info.format_type == gcc_cdiag_format_type
5283 : 10347697 : || info.format_type == gcc_cxxdiag_format_type
5284 : 10347689 : || info.format_type == gcc_dump_printf_format_type)
5285 : : {
5286 : : /* Our first time through, we have to make sure that our
5287 : : format_type data is allocated dynamically and is modifiable. */
5288 : 86 : if (!dynamic_format_types)
5289 : 56 : format_types = dynamic_format_types = (format_kind_info *)
5290 : 56 : xmemdup (format_types_orig, sizeof (format_types_orig),
5291 : : sizeof (format_types_orig));
5292 : :
5293 : : /* If this is format __asm_fprintf__, we have to initialize
5294 : : GCC's notion of HOST_WIDE_INT for checking %wd. */
5295 : 86 : if (info.format_type == asm_fprintf_format_type)
5296 : 10 : init_dynamic_asm_fprintf_info ();
5297 : : /* If this is format __gcc_gfc__, we have to initialize GCC's
5298 : : notion of 'locus' at runtime for %L. */
5299 : 76 : else if (info.format_type == gcc_gfc_format_type)
5300 : 4 : init_dynamic_gfc_info ();
5301 : : /* If this is one of the diagnostic attributes, then we have to
5302 : : initialize 'location_t' and 'tree' at runtime. */
5303 : 72 : else if (info.format_type == gcc_diag_format_type
5304 : : || info.format_type == gcc_tdiag_format_type
5305 : : || info.format_type == gcc_cdiag_format_type
5306 : : || info.format_type == gcc_cxxdiag_format_type
5307 : : || info.format_type == gcc_dump_printf_format_type)
5308 : 72 : init_dynamic_diag_info ();
5309 : : else
5310 : : gcc_unreachable ();
5311 : : }
5312 : :
5313 : : return NULL_TREE;
5314 : : }
5315 : :
5316 : : #if CHECKING_P
5317 : :
5318 : : namespace selftest {
5319 : :
5320 : : /* Selftests of location handling. */
5321 : :
5322 : : /* Get the format_kind_info with the given name. */
5323 : :
5324 : : static const format_kind_info *
5325 : 6 : get_info (const char *name)
5326 : : {
5327 : 6 : int idx = decode_format_type (name);
5328 : 6 : const format_kind_info *fki = &format_types[idx];
5329 : 6 : ASSERT_STREQ (fki->name, name);
5330 : 6 : return fki;
5331 : : }
5332 : :
5333 : : /* Verify that get_format_for_type (FKI, TYPE, CONVERSION_CHAR)
5334 : : is EXPECTED_FORMAT. */
5335 : :
5336 : : static void
5337 : 108 : assert_format_for_type_streq (const location &loc, const format_kind_info *fki,
5338 : : const char *expected_format, tree type,
5339 : : char conversion_char)
5340 : : {
5341 : 108 : gcc_assert (fki);
5342 : 108 : gcc_assert (expected_format);
5343 : 108 : gcc_assert (type);
5344 : :
5345 : 108 : char *actual_format = get_format_for_type (fki, type, conversion_char);
5346 : 108 : ASSERT_STREQ_AT (loc, expected_format, actual_format);
5347 : 108 : free (actual_format);
5348 : 108 : }
5349 : :
5350 : : /* Selftests for get_format_for_type. */
5351 : :
5352 : : #define ASSERT_FORMAT_FOR_TYPE_STREQ(EXPECTED_FORMAT, TYPE, CONVERSION_CHAR) \
5353 : : assert_format_for_type_streq (SELFTEST_LOCATION, (fki), (EXPECTED_FORMAT), \
5354 : : (TYPE), (CONVERSION_CHAR))
5355 : :
5356 : : /* Selftest for get_format_for_type for "printf"-style functions. */
5357 : :
5358 : : static void
5359 : 3 : test_get_format_for_type_printf ()
5360 : : {
5361 : 3 : const format_kind_info *fki = get_info ("gnu_printf");
5362 : 3 : ASSERT_NE (fki, NULL);
5363 : :
5364 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'i');
5365 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'i');
5366 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'o');
5367 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'o');
5368 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'x');
5369 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'x');
5370 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("f", double_type_node, 'X');
5371 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("Lf", long_double_type_node, 'X');
5372 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("d", integer_type_node, 'd');
5373 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("i", integer_type_node, 'i');
5374 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("o", integer_type_node, 'o');
5375 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("x", integer_type_node, 'x');
5376 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("X", integer_type_node, 'X');
5377 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("d", unsigned_type_node, 'd');
5378 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("i", unsigned_type_node, 'i');
5379 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("o", unsigned_type_node, 'o');
5380 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("x", unsigned_type_node, 'x');
5381 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("X", unsigned_type_node, 'X');
5382 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("ld", long_integer_type_node, 'd');
5383 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("li", long_integer_type_node, 'i');
5384 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("lx", long_integer_type_node, 'x');
5385 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("lo", long_unsigned_type_node, 'o');
5386 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("lx", long_unsigned_type_node, 'x');
5387 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("lld", long_long_integer_type_node, 'd');
5388 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("lli", long_long_integer_type_node, 'i');
5389 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("llo", long_long_unsigned_type_node, 'o');
5390 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("llx", long_long_unsigned_type_node, 'x');
5391 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("s", build_pointer_type (char_type_node), 'i');
5392 : 3 : }
5393 : :
5394 : : /* Selftest for get_format_for_type for "scanf"-style functions. */
5395 : :
5396 : : static void
5397 : 3 : test_get_format_for_type_scanf ()
5398 : : {
5399 : 3 : const format_kind_info *fki = get_info ("gnu_scanf");
5400 : 3 : ASSERT_NE (fki, NULL);
5401 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("d", build_pointer_type (integer_type_node), 'd');
5402 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("u", build_pointer_type (unsigned_type_node), 'u');
5403 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("ld",
5404 : : build_pointer_type (long_integer_type_node), 'd');
5405 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("lu",
5406 : : build_pointer_type (long_unsigned_type_node), 'u');
5407 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ
5408 : : ("lld", build_pointer_type (long_long_integer_type_node), 'd');
5409 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ
5410 : : ("llu", build_pointer_type (long_long_unsigned_type_node), 'u');
5411 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("e", build_pointer_type (float_type_node), 'e');
5412 : 3 : ASSERT_FORMAT_FOR_TYPE_STREQ ("le", build_pointer_type (double_type_node), 'e');
5413 : 3 : }
5414 : :
5415 : : #undef ASSERT_FORMAT_FOR_TYPE_STREQ
5416 : :
5417 : : /* Exercise the type-printing label code, to give some coverage
5418 : : under "make selftest-valgrind" (in particular, to ensure that
5419 : : the label-printing machinery doesn't leak). */
5420 : :
5421 : : static void
5422 : 3 : test_type_mismatch_range_labels ()
5423 : : {
5424 : : /* Create a tempfile and write some text to it.
5425 : : ....................0000000001 11111111 12 22222222
5426 : : ....................1234567890 12345678 90 12345678. */
5427 : 3 : const char *content = " printf (\"msg: %i\\n\", msg);\n";
5428 : 3 : temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
5429 : 3 : line_table_test ltt;
5430 : :
5431 : 3 : linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
5432 : :
5433 : 3 : location_t c17 = linemap_position_for_column (line_table, 17);
5434 : 3 : ASSERT_EQ (LOCATION_COLUMN (c17), 17);
5435 : 3 : location_t c18 = linemap_position_for_column (line_table, 18);
5436 : 3 : location_t c24 = linemap_position_for_column (line_table, 24);
5437 : 3 : location_t c26 = linemap_position_for_column (line_table, 26);
5438 : :
5439 : : /* Don't attempt to run the tests if column data might be unavailable. */
5440 : 3 : if (c26 > LINE_MAP_MAX_LOCATION_WITH_COLS)
5441 : 0 : return;
5442 : :
5443 : 3 : location_t fmt = make_location (c18, c17, c18);
5444 : 3 : ASSERT_EQ (LOCATION_COLUMN (fmt), 18);
5445 : :
5446 : 3 : location_t param = make_location (c24, c24, c26);
5447 : 3 : ASSERT_EQ (LOCATION_COLUMN (param), 24);
5448 : :
5449 : 3 : range_label_for_format_type_mismatch fmt_label (char_type_node,
5450 : 3 : integer_type_node, 1);
5451 : 3 : range_label_for_type_mismatch param_label (integer_type_node,
5452 : 3 : char_type_node);
5453 : 3 : gcc_rich_location richloc (fmt, &fmt_label);
5454 : 3 : richloc.add_range (param, SHOW_RANGE_WITHOUT_CARET, ¶m_label);
5455 : :
5456 : 3 : test_diagnostic_context dc;
5457 : 3 : diagnostic_show_locus (&dc, &richloc, DK_ERROR);
5458 : 3 : if (c_dialect_cxx ())
5459 : : /* "char*", without a space. */
5460 : 1 : ASSERT_STREQ (" printf (\"msg: %i\\n\", msg);\n"
5461 : : " ~^ ~~~\n"
5462 : : " | |\n"
5463 : : " char* int\n",
5464 : : pp_formatted_text (dc.printer));
5465 : : else
5466 : : /* "char *", with a space. */
5467 : 2 : ASSERT_STREQ (" printf (\"msg: %i\\n\", msg);\n"
5468 : : " ~^ ~~~\n"
5469 : : " | |\n"
5470 : : " | int\n"
5471 : : " char *\n",
5472 : : pp_formatted_text (dc.printer));
5473 : 3 : }
5474 : :
5475 : : /* Run all of the selftests within this file. */
5476 : :
5477 : : void
5478 : 3 : c_format_cc_tests ()
5479 : : {
5480 : 3 : test_get_modifier_for_format_len ();
5481 : 3 : test_get_format_for_type_printf ();
5482 : 3 : test_get_format_for_type_scanf ();
5483 : 3 : test_type_mismatch_range_labels ();
5484 : 3 : }
5485 : :
5486 : : } // namespace selftest
5487 : :
5488 : : #endif /* CHECKING_P */
5489 : :
5490 : : #include "gt-c-family-c-format.h"
|