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