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