1e4b17023SJohn Marino /* Check calls to formatted I/O functions (-Wformat).
2e4b17023SJohn Marino    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3e4b17023SJohn Marino    2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
4e4b17023SJohn Marino    Free Software Foundation, Inc.
5e4b17023SJohn Marino 
6e4b17023SJohn Marino This file is part of GCC.
7e4b17023SJohn Marino 
8e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
9e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
10e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
11e4b17023SJohn Marino version.
12e4b17023SJohn Marino 
13e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
15e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16e4b17023SJohn Marino for more details.
17e4b17023SJohn Marino 
18e4b17023SJohn Marino You should have received a copy of the GNU General Public License
19e4b17023SJohn Marino along with GCC; see the file COPYING3.  If not see
20e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
21e4b17023SJohn Marino 
22e4b17023SJohn Marino #include "config.h"
23e4b17023SJohn Marino #include "system.h"
24e4b17023SJohn Marino #include "coretypes.h"
25e4b17023SJohn Marino #include "tm.h"
26e4b17023SJohn Marino #include "tree.h"
27e4b17023SJohn Marino #include "flags.h"
28e4b17023SJohn Marino #include "c-common.h"
29e4b17023SJohn Marino #include "c-objc.h"
30e4b17023SJohn Marino #include "intl.h"
31e4b17023SJohn Marino #include "diagnostic-core.h"
32e4b17023SJohn Marino #include "langhooks.h"
33e4b17023SJohn Marino #include "c-format.h"
34e4b17023SJohn Marino #include "alloc-pool.h"
35e4b17023SJohn Marino #include "c-target.h"
36e4b17023SJohn Marino 
37e4b17023SJohn Marino /* Set format warning options according to a -Wformat=n option.  */
38e4b17023SJohn Marino 
39e4b17023SJohn Marino void
set_Wformat(int setting)40e4b17023SJohn Marino set_Wformat (int setting)
41e4b17023SJohn Marino {
42e4b17023SJohn Marino   warn_format = setting;
43e4b17023SJohn Marino   warn_format_extra_args = setting;
44e4b17023SJohn Marino   warn_format_zero_length = setting;
45e4b17023SJohn Marino   warn_format_contains_nul = setting;
46e4b17023SJohn Marino   if (setting != 1)
47e4b17023SJohn Marino     {
48e4b17023SJohn Marino       warn_format_nonliteral = setting;
49e4b17023SJohn Marino       warn_format_security = setting;
50e4b17023SJohn Marino       warn_format_y2k = setting;
51e4b17023SJohn Marino     }
52e4b17023SJohn Marino   /* Make sure not to disable -Wnonnull if -Wformat=0 is specified.  */
53e4b17023SJohn Marino   if (setting)
54e4b17023SJohn Marino     warn_nonnull = setting;
55e4b17023SJohn Marino }
56e4b17023SJohn Marino 
57e4b17023SJohn Marino 
58e4b17023SJohn Marino /* Handle attributes associated with format checking.  */
59e4b17023SJohn Marino 
60e4b17023SJohn Marino /* This must be in the same order as format_types, except for
61e4b17023SJohn Marino    format_type_error.  Target-specific format types do not have
62e4b17023SJohn Marino    matching enum values.  */
63e4b17023SJohn Marino enum format_type { printf_format_type, asm_fprintf_format_type,
64e4b17023SJohn Marino 		   gcc_diag_format_type, gcc_tdiag_format_type,
65e4b17023SJohn Marino 		   gcc_cdiag_format_type,
66e4b17023SJohn Marino 		   gcc_cxxdiag_format_type, gcc_gfc_format_type,
67e4b17023SJohn Marino 		   gcc_objc_string_format_type,
68e4b17023SJohn Marino 		   format_type_error = -1};
69e4b17023SJohn Marino 
70e4b17023SJohn Marino typedef struct function_format_info
71e4b17023SJohn Marino {
72e4b17023SJohn Marino   int format_type;			/* type of format (printf, scanf, etc.) */
73e4b17023SJohn Marino   unsigned HOST_WIDE_INT format_num;	/* number of format argument */
74e4b17023SJohn Marino   unsigned HOST_WIDE_INT first_arg_num;	/* number of first arg (zero for varargs) */
75e4b17023SJohn Marino } function_format_info;
76e4b17023SJohn Marino 
77e4b17023SJohn Marino static bool decode_format_attr (tree, function_format_info *, int);
78e4b17023SJohn Marino static int decode_format_type (const char *);
79e4b17023SJohn Marino 
80e4b17023SJohn Marino static bool check_format_string (tree argument,
81e4b17023SJohn Marino 				 unsigned HOST_WIDE_INT format_num,
82e4b17023SJohn Marino 				 int flags, bool *no_add_attrs,
83e4b17023SJohn Marino 				 int expected_format_type);
84e4b17023SJohn Marino static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
85e4b17023SJohn Marino 			  int validated_p);
86e4b17023SJohn Marino static const char *convert_format_name_to_system_name (const char *attr_name);
87e4b17023SJohn Marino static bool cmp_attribs (const char *tattr_name, const char *attr_name);
88e4b17023SJohn Marino 
89e4b17023SJohn Marino static int first_target_format_type;
90e4b17023SJohn Marino static const char *format_name (int format_num);
91e4b17023SJohn Marino static int format_flags (int format_num);
92e4b17023SJohn Marino 
93e4b17023SJohn Marino /* Check that we have a pointer to a string suitable for use as a format.
94e4b17023SJohn Marino    The default is to check for a char type.
95e4b17023SJohn Marino    For objective-c dialects, this is extended to include references to string
96e4b17023SJohn Marino    objects validated by objc_string_ref_type_p ().
97e4b17023SJohn Marino    Targets may also provide a string object type that can be used within c and
98e4b17023SJohn Marino    c++ and shared with their respective objective-c dialects. In this case the
99e4b17023SJohn Marino    reference to a format string is checked for validity via a hook.
100e4b17023SJohn Marino 
101e4b17023SJohn Marino    The function returns true if strref points to any string type valid for the
102e4b17023SJohn Marino    language dialect and target.  */
103e4b17023SJohn Marino 
104e4b17023SJohn Marino static bool
valid_stringptr_type_p(tree strref)105e4b17023SJohn Marino valid_stringptr_type_p (tree strref)
106e4b17023SJohn Marino {
107e4b17023SJohn Marino   return (strref != NULL
108e4b17023SJohn Marino 	  && TREE_CODE (strref) == POINTER_TYPE
109e4b17023SJohn Marino 	  && (TYPE_MAIN_VARIANT (TREE_TYPE (strref)) == char_type_node
110e4b17023SJohn Marino 	      || objc_string_ref_type_p (strref)
111e4b17023SJohn Marino 	      || (*targetcm.string_object_ref_type_p) ((const_tree) strref)));
112e4b17023SJohn Marino }
113e4b17023SJohn Marino 
114e4b17023SJohn Marino /* Handle a "format_arg" attribute; arguments as in
115e4b17023SJohn Marino    struct attribute_spec.handler.  */
116e4b17023SJohn Marino tree
handle_format_arg_attribute(tree * node,tree ARG_UNUSED (name),tree args,int flags,bool * no_add_attrs)117e4b17023SJohn Marino handle_format_arg_attribute (tree *node, tree ARG_UNUSED (name),
118e4b17023SJohn Marino 			     tree args, int flags, bool *no_add_attrs)
119e4b17023SJohn Marino {
120e4b17023SJohn Marino   tree type = *node;
121e4b17023SJohn Marino   tree format_num_expr = TREE_VALUE (args);
122e4b17023SJohn Marino   unsigned HOST_WIDE_INT format_num = 0;
123e4b17023SJohn Marino 
124e4b17023SJohn Marino   if (!get_constant (format_num_expr, &format_num, 0))
125e4b17023SJohn Marino     {
126e4b17023SJohn Marino       error ("format string has invalid operand number");
127e4b17023SJohn Marino       *no_add_attrs = true;
128e4b17023SJohn Marino       return NULL_TREE;
129e4b17023SJohn Marino     }
130e4b17023SJohn Marino 
131e4b17023SJohn Marino   if (prototype_p (type))
132e4b17023SJohn Marino     {
133e4b17023SJohn Marino       /* The format arg can be any string reference valid for the language and
134e4b17023SJohn Marino          target.  We cannot be more specific in this case.  */
135e4b17023SJohn Marino       if (!check_format_string (type, format_num, flags, no_add_attrs, -1))
136e4b17023SJohn Marino 	return NULL_TREE;
137e4b17023SJohn Marino     }
138e4b17023SJohn Marino 
139e4b17023SJohn Marino   if (!valid_stringptr_type_p (TREE_TYPE (type)))
140e4b17023SJohn Marino     {
141e4b17023SJohn Marino       if (!(flags & (int) ATTR_FLAG_BUILT_IN))
142e4b17023SJohn Marino 	error ("function does not return string type");
143e4b17023SJohn Marino       *no_add_attrs = true;
144e4b17023SJohn Marino       return NULL_TREE;
145e4b17023SJohn Marino     }
146e4b17023SJohn Marino 
147e4b17023SJohn Marino   return NULL_TREE;
148e4b17023SJohn Marino }
149e4b17023SJohn Marino 
150e4b17023SJohn Marino /* Verify that the format_num argument is actually a string reference suitable,
151e4b17023SJohn Marino    for the language dialect and target (in case the format attribute is in
152e4b17023SJohn Marino    error).  When we know the specific reference type expected, this is also
153e4b17023SJohn Marino    checked.  */
154e4b17023SJohn Marino static bool
check_format_string(tree fntype,unsigned HOST_WIDE_INT format_num,int flags,bool * no_add_attrs,int expected_format_type)155e4b17023SJohn Marino check_format_string (tree fntype, unsigned HOST_WIDE_INT format_num,
156e4b17023SJohn Marino 		     int flags, bool *no_add_attrs, int expected_format_type)
157e4b17023SJohn Marino {
158e4b17023SJohn Marino   unsigned HOST_WIDE_INT i;
159e4b17023SJohn Marino   bool is_objc_sref, is_target_sref, is_char_ref;
160e4b17023SJohn Marino   tree ref;
161e4b17023SJohn Marino   int fmt_flags;
162e4b17023SJohn Marino   function_args_iterator iter;
163e4b17023SJohn Marino 
164e4b17023SJohn Marino   i = 1;
165e4b17023SJohn Marino   FOREACH_FUNCTION_ARGS (fntype, ref, iter)
166e4b17023SJohn Marino     {
167e4b17023SJohn Marino       if (i == format_num)
168e4b17023SJohn Marino 	break;
169e4b17023SJohn Marino       i++;
170e4b17023SJohn Marino     }
171e4b17023SJohn Marino 
172e4b17023SJohn Marino   if (!ref
173e4b17023SJohn Marino       || !valid_stringptr_type_p (ref))
174e4b17023SJohn Marino     {
175e4b17023SJohn Marino       if (!(flags & (int) ATTR_FLAG_BUILT_IN))
176e4b17023SJohn Marino 	error ("format string argument is not a string type");
177e4b17023SJohn Marino       *no_add_attrs = true;
178e4b17023SJohn Marino       return false;
179e4b17023SJohn Marino     }
180e4b17023SJohn Marino 
181e4b17023SJohn Marino   /* We only know that we want a suitable string reference.  */
182e4b17023SJohn Marino   if (expected_format_type < 0)
183e4b17023SJohn Marino     return true;
184e4b17023SJohn Marino 
185e4b17023SJohn Marino   /* Now check that the arg matches the expected type.  */
186e4b17023SJohn Marino   is_char_ref =
187e4b17023SJohn Marino     (TYPE_MAIN_VARIANT (TREE_TYPE (ref)) == char_type_node);
188e4b17023SJohn Marino 
189e4b17023SJohn Marino   fmt_flags = format_flags (expected_format_type);
190e4b17023SJohn Marino   is_objc_sref = is_target_sref = false;
191e4b17023SJohn Marino   if (!is_char_ref)
192e4b17023SJohn Marino     is_objc_sref = objc_string_ref_type_p (ref);
193e4b17023SJohn Marino 
194e4b17023SJohn Marino   if (!(fmt_flags & FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL))
195e4b17023SJohn Marino     {
196e4b17023SJohn Marino       if (is_char_ref)
197e4b17023SJohn Marino 	return true; /* OK, we expected a char and found one.  */
198e4b17023SJohn Marino       else
199e4b17023SJohn Marino 	{
200e4b17023SJohn Marino 	  /* We expected a char but found an extended string type.  */
201e4b17023SJohn Marino 	  if (is_objc_sref)
202e4b17023SJohn Marino 	    error ("found a %<%s%> reference but the format argument should"
203e4b17023SJohn Marino 		   " be a string", format_name (gcc_objc_string_format_type));
204e4b17023SJohn Marino 	  else
205e4b17023SJohn Marino 	    error ("found a %qT but the format argument should be a string",
206e4b17023SJohn Marino 		   ref);
207e4b17023SJohn Marino 	  *no_add_attrs = true;
208e4b17023SJohn Marino 	  return false;
209e4b17023SJohn Marino 	}
210e4b17023SJohn Marino     }
211e4b17023SJohn Marino 
212e4b17023SJohn Marino   /* We expect a string object type as the format arg.  */
213e4b17023SJohn Marino   if (is_char_ref)
214e4b17023SJohn Marino     {
215e4b17023SJohn Marino       error ("format argument should be a %<%s%> reference but"
216e4b17023SJohn Marino 	     " a string was found", format_name (expected_format_type));
217e4b17023SJohn Marino       *no_add_attrs = true;
218e4b17023SJohn Marino       return false;
219e4b17023SJohn Marino     }
220e4b17023SJohn Marino 
221e4b17023SJohn Marino   /* We will assert that objective-c will support either its own string type
222e4b17023SJohn Marino      or the target-supplied variant.  */
223e4b17023SJohn Marino   if (!is_objc_sref)
224e4b17023SJohn Marino     is_target_sref = (*targetcm.string_object_ref_type_p) ((const_tree) ref);
225e4b17023SJohn Marino 
226e4b17023SJohn Marino   if (expected_format_type == (int) gcc_objc_string_format_type
227e4b17023SJohn Marino       && (is_objc_sref || is_target_sref))
228e4b17023SJohn Marino     return true;
229e4b17023SJohn Marino 
230e4b17023SJohn Marino   /* We will allow a target string ref to match only itself.  */
231e4b17023SJohn Marino   if (first_target_format_type
232e4b17023SJohn Marino       && expected_format_type >= first_target_format_type
233e4b17023SJohn Marino       && is_target_sref)
234e4b17023SJohn Marino     return true;
235e4b17023SJohn Marino   else
236e4b17023SJohn Marino     {
237e4b17023SJohn Marino       error ("format argument should be a %<%s%> reference",
238e4b17023SJohn Marino 	      format_name (expected_format_type));
239e4b17023SJohn Marino       *no_add_attrs = true;
240e4b17023SJohn Marino       return false;
241e4b17023SJohn Marino     }
242e4b17023SJohn Marino 
243e4b17023SJohn Marino   gcc_unreachable ();
244e4b17023SJohn Marino }
245e4b17023SJohn Marino 
246e4b17023SJohn Marino /* Verify EXPR is a constant, and store its value.
247e4b17023SJohn Marino    If validated_p is true there should be no errors.
248e4b17023SJohn Marino    Returns true on success, false otherwise.  */
249e4b17023SJohn Marino static bool
get_constant(tree expr,unsigned HOST_WIDE_INT * value,int validated_p)250e4b17023SJohn Marino get_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p)
251e4b17023SJohn Marino {
252e4b17023SJohn Marino   if (TREE_CODE (expr) != INTEGER_CST || TREE_INT_CST_HIGH (expr) != 0)
253e4b17023SJohn Marino     {
254e4b17023SJohn Marino       gcc_assert (!validated_p);
255e4b17023SJohn Marino       return false;
256e4b17023SJohn Marino     }
257e4b17023SJohn Marino 
258e4b17023SJohn Marino   *value = TREE_INT_CST_LOW (expr);
259e4b17023SJohn Marino 
260e4b17023SJohn Marino   return true;
261e4b17023SJohn Marino }
262e4b17023SJohn Marino 
263e4b17023SJohn Marino /* Decode the arguments to a "format" attribute into a
264e4b17023SJohn Marino    function_format_info structure.  It is already known that the list
265e4b17023SJohn Marino    is of the right length.  If VALIDATED_P is true, then these
266e4b17023SJohn Marino    attributes have already been validated and must not be erroneous;
267e4b17023SJohn Marino    if false, it will give an error message.  Returns true if the
268e4b17023SJohn Marino    attributes are successfully decoded, false otherwise.  */
269e4b17023SJohn Marino 
270e4b17023SJohn Marino static bool
decode_format_attr(tree args,function_format_info * info,int validated_p)271e4b17023SJohn Marino decode_format_attr (tree args, function_format_info *info, int validated_p)
272e4b17023SJohn Marino {
273e4b17023SJohn Marino   tree format_type_id = TREE_VALUE (args);
274e4b17023SJohn Marino   tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
275e4b17023SJohn Marino   tree first_arg_num_expr
276e4b17023SJohn Marino     = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
277e4b17023SJohn Marino 
278e4b17023SJohn Marino   if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
279e4b17023SJohn Marino     {
280e4b17023SJohn Marino       gcc_assert (!validated_p);
281e4b17023SJohn Marino       error ("unrecognized format specifier");
282e4b17023SJohn Marino       return false;
283e4b17023SJohn Marino     }
284e4b17023SJohn Marino   else
285e4b17023SJohn Marino     {
286e4b17023SJohn Marino       const char *p = IDENTIFIER_POINTER (format_type_id);
287e4b17023SJohn Marino 
288e4b17023SJohn Marino       p = convert_format_name_to_system_name (p);
289e4b17023SJohn Marino 
290e4b17023SJohn Marino       info->format_type = decode_format_type (p);
291e4b17023SJohn Marino 
292e4b17023SJohn Marino       if (!c_dialect_objc ()
293e4b17023SJohn Marino 	   && info->format_type == gcc_objc_string_format_type)
294e4b17023SJohn Marino 	{
295e4b17023SJohn Marino 	  gcc_assert (!validated_p);
296e4b17023SJohn Marino 	  warning (OPT_Wformat, "%qE is only allowed in Objective-C dialects",
297e4b17023SJohn Marino 		   format_type_id);
298e4b17023SJohn Marino 	  info->format_type = format_type_error;
299e4b17023SJohn Marino 	  return false;
300e4b17023SJohn Marino 	}
301e4b17023SJohn Marino 
302e4b17023SJohn Marino       if (info->format_type == format_type_error)
303e4b17023SJohn Marino 	{
304e4b17023SJohn Marino 	  gcc_assert (!validated_p);
305e4b17023SJohn Marino 	  warning (OPT_Wformat, "%qE is an unrecognized format function type",
306e4b17023SJohn Marino 		   format_type_id);
307e4b17023SJohn Marino 	  return false;
308e4b17023SJohn Marino 	}
309e4b17023SJohn Marino     }
310e4b17023SJohn Marino 
311e4b17023SJohn Marino   if (!get_constant (format_num_expr, &info->format_num, validated_p))
312e4b17023SJohn Marino     {
313e4b17023SJohn Marino       error ("format string has invalid operand number");
314e4b17023SJohn Marino       return false;
315e4b17023SJohn Marino     }
316e4b17023SJohn Marino 
317e4b17023SJohn Marino   if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p))
318e4b17023SJohn Marino     {
319e4b17023SJohn Marino       error ("%<...%> has invalid operand number");
320e4b17023SJohn Marino       return false;
321e4b17023SJohn Marino     }
322e4b17023SJohn Marino 
323e4b17023SJohn Marino   if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num)
324e4b17023SJohn Marino     {
325e4b17023SJohn Marino       gcc_assert (!validated_p);
326e4b17023SJohn Marino       error ("format string argument follows the args to be formatted");
327e4b17023SJohn Marino       return false;
328e4b17023SJohn Marino     }
329e4b17023SJohn Marino 
330e4b17023SJohn Marino   return true;
331e4b17023SJohn Marino }
332e4b17023SJohn Marino 
333e4b17023SJohn Marino /* Check a call to a format function against a parameter list.  */
334e4b17023SJohn Marino 
335e4b17023SJohn Marino /* The C standard version C++ is treated as equivalent to
336e4b17023SJohn Marino    or inheriting from, for the purpose of format features supported.  */
337e4b17023SJohn Marino #define CPLUSPLUS_STD_VER	STD_C94
338e4b17023SJohn Marino /* The C standard version we are checking formats against when pedantic.  */
339e4b17023SJohn Marino #define C_STD_VER		((int) (c_dialect_cxx ()		   \
340e4b17023SJohn Marino 				 ? CPLUSPLUS_STD_VER			   \
341e4b17023SJohn Marino 				 : (flag_isoc99				   \
342e4b17023SJohn Marino 				    ? STD_C99				   \
343e4b17023SJohn Marino 				    : (flag_isoc94 ? STD_C94 : STD_C89))))
344e4b17023SJohn Marino /* The name to give to the standard version we are warning about when
345e4b17023SJohn Marino    pedantic.  FEATURE_VER is the version in which the feature warned out
346e4b17023SJohn Marino    appeared, which is higher than C_STD_VER.  */
347e4b17023SJohn Marino #define C_STD_NAME(FEATURE_VER) (c_dialect_cxx ()		\
348e4b17023SJohn Marino 				 ? "ISO C++"			\
349e4b17023SJohn Marino 				 : ((FEATURE_VER) == STD_EXT	\
350e4b17023SJohn Marino 				    ? "ISO C"			\
351e4b17023SJohn Marino 				    : "ISO C90"))
352e4b17023SJohn Marino /* Adjust a C standard version, which may be STD_C9L, to account for
353e4b17023SJohn Marino    -Wno-long-long.  Returns other standard versions unchanged.  */
354e4b17023SJohn Marino #define ADJ_STD(VER)		((int) ((VER) == STD_C9L		      \
355e4b17023SJohn Marino 				       ? (warn_long_long ? STD_C99 : STD_C89) \
356e4b17023SJohn Marino 				       : (VER)))
357e4b17023SJohn Marino 
358e4b17023SJohn Marino /* Enum describing the kind of specifiers present in the format and
359e4b17023SJohn Marino    requiring an argument.  */
360e4b17023SJohn Marino enum format_specifier_kind {
361e4b17023SJohn Marino   CF_KIND_FORMAT,
362e4b17023SJohn Marino   CF_KIND_FIELD_WIDTH,
363e4b17023SJohn Marino   CF_KIND_FIELD_PRECISION
364e4b17023SJohn Marino };
365e4b17023SJohn Marino 
366e4b17023SJohn Marino static const char *kind_descriptions[] = {
367e4b17023SJohn Marino   N_("format"),
368e4b17023SJohn Marino   N_("field width specifier"),
369e4b17023SJohn Marino   N_("field precision specifier")
370e4b17023SJohn Marino };
371e4b17023SJohn Marino 
372e4b17023SJohn Marino /* Structure describing details of a type expected in format checking,
373e4b17023SJohn Marino    and the type to check against it.  */
374e4b17023SJohn Marino typedef struct format_wanted_type
375e4b17023SJohn Marino {
376e4b17023SJohn Marino   /* The type wanted.  */
377e4b17023SJohn Marino   tree wanted_type;
378e4b17023SJohn Marino   /* The name of this type to use in diagnostics.  */
379e4b17023SJohn Marino   const char *wanted_type_name;
380e4b17023SJohn Marino   /* Should be type checked just for scalar width identity.  */
381e4b17023SJohn Marino   int scalar_identity_flag;
382e4b17023SJohn Marino   /* The level of indirection through pointers at which this type occurs.  */
383e4b17023SJohn Marino   int pointer_count;
384e4b17023SJohn Marino   /* Whether, when pointer_count is 1, to allow any character type when
385e4b17023SJohn Marino      pedantic, rather than just the character or void type specified.  */
386e4b17023SJohn Marino   int char_lenient_flag;
387e4b17023SJohn Marino   /* Whether the argument, dereferenced once, is written into and so the
388e4b17023SJohn Marino      argument must not be a pointer to a const-qualified type.  */
389e4b17023SJohn Marino   int writing_in_flag;
390e4b17023SJohn Marino   /* Whether the argument, dereferenced once, is read from and so
391e4b17023SJohn Marino      must not be a NULL pointer.  */
392e4b17023SJohn Marino   int reading_from_flag;
393e4b17023SJohn Marino   /* The kind of specifier that this type is used for.  */
394e4b17023SJohn Marino   enum format_specifier_kind kind;
395e4b17023SJohn Marino   /* The starting character of the specifier.  This never includes the
396e4b17023SJohn Marino      initial percent sign.  */
397e4b17023SJohn Marino   const char *format_start;
398e4b17023SJohn Marino   /* The length of the specifier.  */
399e4b17023SJohn Marino   int format_length;
400e4b17023SJohn Marino   /* The actual parameter to check against the wanted type.  */
401e4b17023SJohn Marino   tree param;
402e4b17023SJohn Marino   /* The argument number of that parameter.  */
403e4b17023SJohn Marino   int arg_num;
404e4b17023SJohn Marino   /* The next type to check for this format conversion, or NULL if none.  */
405e4b17023SJohn Marino   struct format_wanted_type *next;
406e4b17023SJohn Marino } format_wanted_type;
407e4b17023SJohn Marino 
408e4b17023SJohn Marino /* Convenience macro for format_length_info meaning unused.  */
409e4b17023SJohn Marino #define NO_FMT NULL, FMT_LEN_none, STD_C89
410e4b17023SJohn Marino 
411e4b17023SJohn Marino static const format_length_info printf_length_specs[] =
412e4b17023SJohn Marino {
413e4b17023SJohn Marino   { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 },
414e4b17023SJohn Marino   { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 },
415e4b17023SJohn Marino   { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 },
416e4b17023SJohn Marino   { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 },
417e4b17023SJohn Marino   { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 },
418e4b17023SJohn Marino   { "Z", FMT_LEN_z, STD_EXT, NO_FMT, 0 },
419e4b17023SJohn Marino   { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 },
420e4b17023SJohn Marino   { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 },
421e4b17023SJohn Marino   { "H", FMT_LEN_H, STD_EXT, NO_FMT, 0 },
422e4b17023SJohn Marino   { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT, 0 },
423e4b17023SJohn Marino   { NO_FMT, NO_FMT, 0 }
424e4b17023SJohn Marino };
425e4b17023SJohn Marino 
426e4b17023SJohn Marino /* Length specifiers valid for asm_fprintf.  */
427e4b17023SJohn Marino static const format_length_info asm_fprintf_length_specs[] =
428e4b17023SJohn Marino {
429e4b17023SJohn Marino   { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 },
430e4b17023SJohn Marino   { "w", FMT_LEN_none, STD_C89, NO_FMT, 0 },
431e4b17023SJohn Marino   { NO_FMT, NO_FMT, 0 }
432e4b17023SJohn Marino };
433e4b17023SJohn Marino 
434e4b17023SJohn Marino /* Length specifiers valid for GCC diagnostics.  */
435e4b17023SJohn Marino static const format_length_info gcc_diag_length_specs[] =
436e4b17023SJohn Marino {
437e4b17023SJohn Marino   { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 },
438e4b17023SJohn Marino   { "w", FMT_LEN_none, STD_C89, NO_FMT, 0 },
439e4b17023SJohn Marino   { NO_FMT, NO_FMT, 0 }
440e4b17023SJohn Marino };
441e4b17023SJohn Marino 
442e4b17023SJohn Marino /* The custom diagnostics all accept the same length specifiers.  */
443e4b17023SJohn Marino #define gcc_tdiag_length_specs gcc_diag_length_specs
444e4b17023SJohn Marino #define gcc_cdiag_length_specs gcc_diag_length_specs
445e4b17023SJohn Marino #define gcc_cxxdiag_length_specs gcc_diag_length_specs
446e4b17023SJohn Marino 
447e4b17023SJohn Marino /* This differs from printf_length_specs only in that "Z" is not accepted.  */
448e4b17023SJohn Marino static const format_length_info scanf_length_specs[] =
449e4b17023SJohn Marino {
450e4b17023SJohn Marino   { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 },
451e4b17023SJohn Marino   { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 },
452e4b17023SJohn Marino   { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 },
453e4b17023SJohn Marino   { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 },
454e4b17023SJohn Marino   { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 },
455e4b17023SJohn Marino   { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 },
456e4b17023SJohn Marino   { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 },
457e4b17023SJohn Marino   { "H", FMT_LEN_H, STD_EXT, NO_FMT, 0 },
458e4b17023SJohn Marino   { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT, 0 },
459e4b17023SJohn Marino   { NO_FMT, NO_FMT, 0 }
460e4b17023SJohn Marino };
461e4b17023SJohn Marino 
462e4b17023SJohn Marino 
463e4b17023SJohn Marino /* All tables for strfmon use STD_C89 everywhere, since -pedantic warnings
464e4b17023SJohn Marino    make no sense for a format type not part of any C standard version.  */
465e4b17023SJohn Marino static const format_length_info strfmon_length_specs[] =
466e4b17023SJohn Marino {
467e4b17023SJohn Marino   /* A GNU extension.  */
468e4b17023SJohn Marino   { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 },
469e4b17023SJohn Marino   { NO_FMT, NO_FMT, 0 }
470e4b17023SJohn Marino };
471e4b17023SJohn Marino 
472e4b17023SJohn Marino 
473e4b17023SJohn Marino /* For now, the Fortran front-end routines only use l as length modifier.  */
474e4b17023SJohn Marino static const format_length_info gcc_gfc_length_specs[] =
475e4b17023SJohn Marino {
476e4b17023SJohn Marino   { "l", FMT_LEN_l, STD_C89, NO_FMT, 0 },
477e4b17023SJohn Marino   { NO_FMT, NO_FMT, 0 }
478e4b17023SJohn Marino };
479e4b17023SJohn Marino 
480e4b17023SJohn Marino 
481e4b17023SJohn Marino static const format_flag_spec printf_flag_specs[] =
482e4b17023SJohn Marino {
483e4b17023SJohn Marino   { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
484e4b17023SJohn Marino   { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
485e4b17023SJohn Marino   { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
486e4b17023SJohn Marino   { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
487e4b17023SJohn Marino   { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
488e4b17023SJohn Marino   { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
489e4b17023SJohn Marino   { 'I',  0, 0, N_("'I' flag"),        N_("the 'I' printf flag"),              STD_EXT },
490e4b17023SJohn Marino   { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
491e4b17023SJohn Marino   { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
492e4b17023SJohn Marino   { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
493e4b17023SJohn Marino   { 0, 0, 0, NULL, NULL, STD_C89 }
494e4b17023SJohn Marino };
495e4b17023SJohn Marino 
496e4b17023SJohn Marino 
497e4b17023SJohn Marino static const format_flag_pair printf_flag_pairs[] =
498e4b17023SJohn Marino {
499e4b17023SJohn Marino   { ' ', '+', 1, 0   },
500e4b17023SJohn Marino   { '0', '-', 1, 0   },
501e4b17023SJohn Marino   { '0', 'p', 1, 'i' },
502e4b17023SJohn Marino   { 0, 0, 0, 0 }
503e4b17023SJohn Marino };
504e4b17023SJohn Marino 
505e4b17023SJohn Marino static const format_flag_spec asm_fprintf_flag_specs[] =
506e4b17023SJohn Marino {
507e4b17023SJohn Marino   { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
508e4b17023SJohn Marino   { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
509e4b17023SJohn Marino   { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
510e4b17023SJohn Marino   { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
511e4b17023SJohn Marino   { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
512e4b17023SJohn Marino   { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
513e4b17023SJohn Marino   { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
514e4b17023SJohn Marino   { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
515e4b17023SJohn Marino   { 0, 0, 0, NULL, NULL, STD_C89 }
516e4b17023SJohn Marino };
517e4b17023SJohn Marino 
518e4b17023SJohn Marino static const format_flag_pair asm_fprintf_flag_pairs[] =
519e4b17023SJohn Marino {
520e4b17023SJohn Marino   { ' ', '+', 1, 0   },
521e4b17023SJohn Marino   { '0', '-', 1, 0   },
522e4b17023SJohn Marino   { '0', 'p', 1, 'i' },
523e4b17023SJohn Marino   { 0, 0, 0, 0 }
524e4b17023SJohn Marino };
525e4b17023SJohn Marino 
526e4b17023SJohn Marino static const format_flag_pair gcc_diag_flag_pairs[] =
527e4b17023SJohn Marino {
528e4b17023SJohn Marino   { 0, 0, 0, 0 }
529e4b17023SJohn Marino };
530e4b17023SJohn Marino 
531e4b17023SJohn Marino #define gcc_tdiag_flag_pairs gcc_diag_flag_pairs
532e4b17023SJohn Marino #define gcc_cdiag_flag_pairs gcc_diag_flag_pairs
533e4b17023SJohn Marino #define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs
534e4b17023SJohn Marino 
535e4b17023SJohn Marino static const format_flag_pair gcc_gfc_flag_pairs[] =
536e4b17023SJohn Marino {
537e4b17023SJohn Marino   { 0, 0, 0, 0 }
538e4b17023SJohn Marino };
539e4b17023SJohn Marino 
540e4b17023SJohn Marino static const format_flag_spec gcc_diag_flag_specs[] =
541e4b17023SJohn Marino {
542e4b17023SJohn Marino   { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
543e4b17023SJohn Marino   { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
544e4b17023SJohn Marino   { 'q',  0, 0, N_("'q' flag"),        N_("the 'q' diagnostic flag"),          STD_C89 },
545e4b17023SJohn Marino   { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
546e4b17023SJohn Marino   { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
547e4b17023SJohn Marino   { 0, 0, 0, NULL, NULL, STD_C89 }
548e4b17023SJohn Marino };
549e4b17023SJohn Marino 
550e4b17023SJohn Marino #define gcc_tdiag_flag_specs gcc_diag_flag_specs
551e4b17023SJohn Marino #define gcc_cdiag_flag_specs gcc_diag_flag_specs
552e4b17023SJohn Marino #define gcc_cxxdiag_flag_specs gcc_diag_flag_specs
553e4b17023SJohn Marino 
554e4b17023SJohn Marino static const format_flag_spec scanf_flag_specs[] =
555e4b17023SJohn Marino {
556e4b17023SJohn Marino   { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
557e4b17023SJohn Marino   { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
558e4b17023SJohn Marino   { 'm',  0, 0, N_("'m' flag"),               N_("the 'm' scanf flag"),                       STD_EXT },
559e4b17023SJohn Marino   { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
560e4b17023SJohn Marino   { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
561e4b17023SJohn Marino   { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
562e4b17023SJohn Marino   { 'I',  0, 0, N_("'I' flag"),               N_("the 'I' scanf flag"),                       STD_EXT },
563e4b17023SJohn Marino   { 0, 0, 0, NULL, NULL, STD_C89 }
564e4b17023SJohn Marino };
565e4b17023SJohn Marino 
566e4b17023SJohn Marino 
567e4b17023SJohn Marino static const format_flag_pair scanf_flag_pairs[] =
568e4b17023SJohn Marino {
569e4b17023SJohn Marino   { '*', 'L', 0, 0 },
570e4b17023SJohn Marino   { 'a', 'm', 0, 0 },
571e4b17023SJohn Marino   { 0, 0, 0, 0 }
572e4b17023SJohn Marino };
573e4b17023SJohn Marino 
574e4b17023SJohn Marino 
575e4b17023SJohn Marino static const format_flag_spec strftime_flag_specs[] =
576e4b17023SJohn Marino {
577e4b17023SJohn Marino   { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
578e4b17023SJohn Marino   { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
579e4b17023SJohn Marino   { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
580e4b17023SJohn Marino   { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
581e4b17023SJohn Marino   { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
582e4b17023SJohn Marino   { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
583e4b17023SJohn Marino   { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
584e4b17023SJohn Marino   { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
585e4b17023SJohn Marino   { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
586e4b17023SJohn Marino   { 0, 0, 0, NULL, NULL, STD_C89 }
587e4b17023SJohn Marino };
588e4b17023SJohn Marino 
589e4b17023SJohn Marino 
590e4b17023SJohn Marino static const format_flag_pair strftime_flag_pairs[] =
591e4b17023SJohn Marino {
592e4b17023SJohn Marino   { 'E', 'O', 0, 0 },
593e4b17023SJohn Marino   { '_', '-', 0, 0 },
594e4b17023SJohn Marino   { '_', '0', 0, 0 },
595e4b17023SJohn Marino   { '-', '0', 0, 0 },
596e4b17023SJohn Marino   { '^', '#', 0, 0 },
597e4b17023SJohn Marino   { 0, 0, 0, 0 }
598e4b17023SJohn Marino };
599e4b17023SJohn Marino 
600e4b17023SJohn Marino 
601e4b17023SJohn Marino static const format_flag_spec strfmon_flag_specs[] =
602e4b17023SJohn Marino {
603e4b17023SJohn Marino   { '=',  0, 1, N_("fill character"),  N_("fill character in strfmon format"),  STD_C89 },
604e4b17023SJohn Marino   { '^',  0, 0, N_("'^' flag"),        N_("the '^' strfmon flag"),              STD_C89 },
605e4b17023SJohn Marino   { '+',  0, 0, N_("'+' flag"),        N_("the '+' strfmon flag"),              STD_C89 },
606e4b17023SJohn Marino   { '(',  0, 0, N_("'(' flag"),        N_("the '(' strfmon flag"),              STD_C89 },
607e4b17023SJohn Marino   { '!',  0, 0, N_("'!' flag"),        N_("the '!' strfmon flag"),              STD_C89 },
608e4b17023SJohn Marino   { '-',  0, 0, N_("'-' flag"),        N_("the '-' strfmon flag"),              STD_C89 },
609e4b17023SJohn Marino   { 'w',  0, 0, N_("field width"),     N_("field width in strfmon format"),     STD_C89 },
610e4b17023SJohn Marino   { '#',  0, 0, N_("left precision"),  N_("left precision in strfmon format"),  STD_C89 },
611e4b17023SJohn Marino   { 'p',  0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 },
612e4b17023SJohn Marino   { 'L',  0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 },
613e4b17023SJohn Marino   { 0, 0, 0, NULL, NULL, STD_C89 }
614e4b17023SJohn Marino };
615e4b17023SJohn Marino 
616e4b17023SJohn Marino static const format_flag_pair strfmon_flag_pairs[] =
617e4b17023SJohn Marino {
618e4b17023SJohn Marino   { '+', '(', 0, 0 },
619e4b17023SJohn Marino   { 0, 0, 0, 0 }
620e4b17023SJohn Marino };
621e4b17023SJohn Marino 
622e4b17023SJohn Marino 
623e4b17023SJohn Marino static const format_char_info print_char_table[] =
624e4b17023SJohn Marino {
625e4b17023SJohn Marino   /* C89 conversion specifiers.  */
626e4b17023SJohn Marino   { "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  }, "-wp0 +'I",  "i",  NULL },
627e4b17023SJohn Marino   { "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 }, "-wp0#",     "i",  NULL },
628e4b17023SJohn Marino   { "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 }, "-wp0'I",    "i",  NULL },
629e4b17023SJohn Marino   { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "",   NULL },
630e4b17023SJohn Marino   { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#I",  "",   NULL },
631e4b17023SJohn Marino   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
632e4b17023SJohn Marino   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
633e4b17023SJohn Marino   { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
634e4b17023SJohn Marino   { "n",   1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
635e4b17023SJohn Marino   /* C99 conversion specifiers.  */
636e4b17023SJohn Marino   { "F",   0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "",   NULL },
637e4b17023SJohn Marino   { "aA",  0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp0 +#",   "",   NULL },
638e4b17023SJohn Marino   /* X/Open conversion specifiers.  */
639e4b17023SJohn Marino   { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
640e4b17023SJohn Marino   { "S",   1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
641e4b17023SJohn Marino   /* GNU conversion specifiers.  */
642e4b17023SJohn Marino   { "m",   0, STD_EXT, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "",   NULL },
643e4b17023SJohn Marino   { NULL,  0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
644e4b17023SJohn Marino };
645e4b17023SJohn Marino 
646e4b17023SJohn Marino static const format_char_info asm_fprintf_char_table[] =
647e4b17023SJohn Marino {
648e4b17023SJohn Marino   /* C89 conversion specifiers.  */
649e4b17023SJohn Marino   { "di",  0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T89_L,   T9L_LL,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +",  "i", NULL },
650e4b17023SJohn Marino   { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  T9L_ULL, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0#",   "i", NULL },
651e4b17023SJohn Marino   { "u",   0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  T9L_ULL, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0",    "i", NULL },
652e4b17023SJohn Marino   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       "", NULL },
653e4b17023SJohn Marino   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",    "cR", NULL },
654e4b17023SJohn Marino 
655e4b17023SJohn Marino   /* asm_fprintf conversion specifiers.  */
656e4b17023SJohn Marino   { "O",   0, STD_C89, NOARGUMENTS, "",      "",   NULL },
657e4b17023SJohn Marino   { "R",   0, STD_C89, NOARGUMENTS, "",      "",   NULL },
658e4b17023SJohn Marino   { "I",   0, STD_C89, NOARGUMENTS, "",      "",   NULL },
659e4b17023SJohn Marino   { "L",   0, STD_C89, NOARGUMENTS, "",      "",   NULL },
660e4b17023SJohn Marino   { "U",   0, STD_C89, NOARGUMENTS, "",      "",   NULL },
661e4b17023SJohn Marino   { "r",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",  "", NULL },
662e4b17023SJohn Marino   { "@",   0, STD_C89, NOARGUMENTS, "",      "",   NULL },
663e4b17023SJohn Marino   { NULL,  0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
664e4b17023SJohn Marino };
665e4b17023SJohn Marino 
666e4b17023SJohn Marino static const format_char_info gcc_diag_char_table[] =
667e4b17023SJohn Marino {
668e4b17023SJohn Marino   /* C89 conversion specifiers.  */
669e4b17023SJohn Marino   { "di",  0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T89_L,   T9L_LL,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
670e4b17023SJohn Marino   { "ox",  0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  T9L_ULL, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
671e4b17023SJohn Marino   { "u",   0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  T9L_ULL, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
672e4b17023SJohn Marino   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
673e4b17023SJohn Marino   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "pq", "cR", NULL },
674e4b17023SJohn Marino   { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "c",  NULL },
675e4b17023SJohn Marino 
676e4b17023SJohn Marino   /* Custom conversion specifiers.  */
677e4b17023SJohn Marino 
678e4b17023SJohn Marino   /* These will require a "tree" at runtime.  */
679e4b17023SJohn Marino   { "K", 0, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",    "",   NULL },
680e4b17023SJohn Marino 
681e4b17023SJohn Marino   { "<>'", 0, STD_C89, NOARGUMENTS, "",      "",   NULL },
682e4b17023SJohn Marino   { "m",   0, STD_C89, NOARGUMENTS, "q",     "",   NULL },
683e4b17023SJohn Marino   { NULL,  0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
684e4b17023SJohn Marino };
685e4b17023SJohn Marino 
686e4b17023SJohn Marino static const format_char_info gcc_tdiag_char_table[] =
687e4b17023SJohn Marino {
688e4b17023SJohn Marino   /* C89 conversion specifiers.  */
689e4b17023SJohn Marino   { "di",  0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T89_L,   T9L_LL,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
690e4b17023SJohn Marino   { "ox",  0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  T9L_ULL, BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
691e4b17023SJohn Marino   { "u",   0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  T9L_ULL, BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
692e4b17023SJohn Marino   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
693e4b17023SJohn Marino   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "pq", "cR", NULL },
694e4b17023SJohn Marino   { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "c",  NULL },
695e4b17023SJohn Marino 
696e4b17023SJohn Marino   /* Custom conversion specifiers.  */
697e4b17023SJohn Marino 
698e4b17023SJohn Marino   /* These will require a "tree" at runtime.  */
699e4b17023SJohn Marino   { "DFKTEV", 0, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+", "",   NULL },
700e4b17023SJohn Marino 
701e4b17023SJohn Marino   { "v", 0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q#",  "",   NULL },
702e4b17023SJohn Marino 
703e4b17023SJohn Marino   { "<>'", 0, STD_C89, NOARGUMENTS, "",      "",   NULL },
704e4b17023SJohn Marino   { "m",   0, STD_C89, NOARGUMENTS, "q",     "",   NULL },
705e4b17023SJohn Marino   { NULL,  0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
706e4b17023SJohn Marino };
707e4b17023SJohn Marino 
708e4b17023SJohn Marino static const format_char_info gcc_cdiag_char_table[] =
709e4b17023SJohn Marino {
710e4b17023SJohn Marino   /* C89 conversion specifiers.  */
711e4b17023SJohn Marino   { "di",  0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T89_L,   T9L_LL,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
712e4b17023SJohn Marino   { "ox",  0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  T9L_ULL, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
713e4b17023SJohn Marino   { "u",   0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  T9L_ULL, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
714e4b17023SJohn Marino   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
715e4b17023SJohn Marino   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "pq", "cR", NULL },
716e4b17023SJohn Marino   { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "c",  NULL },
717e4b17023SJohn Marino 
718e4b17023SJohn Marino   /* Custom conversion specifiers.  */
719e4b17023SJohn Marino 
720e4b17023SJohn Marino   /* These will require a "tree" at runtime.  */
721e4b17023SJohn Marino   { "DEFKTV", 0, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+", "",   NULL },
722e4b17023SJohn Marino 
723e4b17023SJohn Marino   { "v", 0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q#",  "",   NULL },
724e4b17023SJohn Marino 
725e4b17023SJohn Marino   { "<>'", 0, STD_C89, NOARGUMENTS, "",      "",   NULL },
726e4b17023SJohn Marino   { "m",   0, STD_C89, NOARGUMENTS, "q",     "",   NULL },
727e4b17023SJohn Marino   { NULL,  0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
728e4b17023SJohn Marino };
729e4b17023SJohn Marino 
730e4b17023SJohn Marino static const format_char_info gcc_cxxdiag_char_table[] =
731e4b17023SJohn Marino {
732e4b17023SJohn Marino   /* C89 conversion specifiers.  */
733e4b17023SJohn Marino   { "di",  0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T89_L,   T9L_LL,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
734e4b17023SJohn Marino   { "ox",  0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  T9L_ULL, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
735e4b17023SJohn Marino   { "u",   0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  T9L_ULL, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
736e4b17023SJohn Marino   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
737e4b17023SJohn Marino   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "pq", "cR", NULL },
738e4b17023SJohn Marino   { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "c",  NULL },
739e4b17023SJohn Marino 
740e4b17023SJohn Marino   /* Custom conversion specifiers.  */
741e4b17023SJohn Marino 
742e4b17023SJohn Marino   /* These will require a "tree" at runtime.  */
743e4b17023SJohn Marino   { "ADEFKSTV",0,STD_C89,{ T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+#",   "",   NULL },
744e4b17023SJohn Marino 
745e4b17023SJohn Marino   { "v", 0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q#",  "",   NULL },
746e4b17023SJohn Marino 
747e4b17023SJohn Marino   /* These accept either an 'int' or an 'enum tree_code' (which is handled as an 'int'.)  */
748e4b17023SJohn Marino   { "CLOPQ",0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
749e4b17023SJohn Marino 
750e4b17023SJohn Marino   { "<>'", 0, STD_C89, NOARGUMENTS, "",      "",   NULL },
751e4b17023SJohn Marino   { "m",   0, STD_C89, NOARGUMENTS, "q",     "",   NULL },
752e4b17023SJohn Marino   { NULL,  0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
753e4b17023SJohn Marino };
754e4b17023SJohn Marino 
755e4b17023SJohn Marino static const format_char_info gcc_gfc_char_table[] =
756e4b17023SJohn Marino {
757e4b17023SJohn Marino   /* C89 conversion specifiers.  */
758e4b17023SJohn Marino   { "di",  0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T89_L,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "", NULL },
759e4b17023SJohn Marino   { "u",   0, STD_C89, { T89_UI,  BADLEN,  BADLEN,  T89_UL,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "", NULL },
760e4b17023SJohn Marino   { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "", NULL },
761e4b17023SJohn Marino   { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "cR", NULL },
762e4b17023SJohn Marino 
763e4b17023SJohn Marino   /* gfc conversion specifiers.  */
764e4b17023SJohn Marino 
765e4b17023SJohn Marino   { "C",   0, STD_C89, NOARGUMENTS, "",      "",   NULL },
766e4b17023SJohn Marino 
767e4b17023SJohn Marino   /* This will require a "locus" at runtime.  */
768e4b17023SJohn Marino   { "L",   0, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "R", NULL },
769e4b17023SJohn Marino 
770e4b17023SJohn Marino   { NULL,  0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
771e4b17023SJohn Marino };
772e4b17023SJohn Marino 
773e4b17023SJohn Marino static const format_char_info scan_char_table[] =
774e4b17023SJohn Marino {
775e4b17023SJohn Marino   /* C89 conversion specifiers.  */
776e4b17023SJohn Marino   { "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 }, "*w'I", "W",   NULL },
777e4b17023SJohn Marino   { "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 }, "*w'I", "W",   NULL },
778e4b17023SJohn Marino   { "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 }, "*w",   "W",   NULL },
779e4b17023SJohn Marino   { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "*w'",  "W",   NULL },
780e4b17023SJohn Marino   { "c",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*mw",   "cW",  NULL },
781e4b17023SJohn Marino   { "s",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*amw",  "cW",  NULL },
782e4b17023SJohn Marino   { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*amw",  "cW[", NULL },
783e4b17023SJohn Marino   { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
784e4b17023SJohn Marino   { "n",     1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
785e4b17023SJohn Marino   /* C99 conversion specifiers.  */
786e4b17023SJohn Marino   { "F",   1, STD_C99, { T99_F,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "*w'",  "W",   NULL },
787e4b17023SJohn Marino   { "aA",   1, STD_C99, { T99_F,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'",  "W",   NULL },
788e4b17023SJohn Marino   /* X/Open conversion specifiers.  */
789e4b17023SJohn Marino   { "C",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*mw",   "W",   NULL },
790e4b17023SJohn Marino   { "S",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*amw",  "W",   NULL },
791e4b17023SJohn Marino   { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
792e4b17023SJohn Marino };
793e4b17023SJohn Marino 
794e4b17023SJohn Marino static const format_char_info time_char_table[] =
795e4b17023SJohn Marino {
796e4b17023SJohn Marino   /* C89 conversion specifiers.  */
797e4b17023SJohn Marino   { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
798e4b17023SJohn Marino   { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
799e4b17023SJohn Marino   { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
800e4b17023SJohn Marino   { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
801e4b17023SJohn Marino   { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
802e4b17023SJohn Marino   { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
803e4b17023SJohn Marino   { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
804e4b17023SJohn Marino   { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
805e4b17023SJohn Marino   { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
806e4b17023SJohn Marino   /* C99 conversion specifiers.  */
807e4b17023SJohn Marino   { "C",		0, STD_C99, NOLENGTHS, "-_0EOw", "o",  NULL },
808e4b17023SJohn Marino   { "D",		0, STD_C99, NOLENGTHS, "",       "2",  NULL },
809e4b17023SJohn Marino   { "eVu",		0, STD_C99, NOLENGTHS, "-_0Ow",  "",   NULL },
810e4b17023SJohn Marino   { "FRTnrt",		0, STD_C99, NOLENGTHS, "",       "",   NULL },
811e4b17023SJohn Marino   { "g",		0, STD_C99, NOLENGTHS, "O-_0w",  "2o", NULL },
812e4b17023SJohn Marino   { "G",		0, STD_C99, NOLENGTHS, "-_0Ow",  "o",  NULL },
813e4b17023SJohn Marino   { "h",		0, STD_C99, NOLENGTHS, "^#",     "",   NULL },
814e4b17023SJohn Marino   { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
815e4b17023SJohn Marino   /* GNU conversion specifiers.  */
816e4b17023SJohn Marino   { "kls",		0, STD_EXT, NOLENGTHS, "-_0Ow",  "",   NULL },
817e4b17023SJohn Marino   { "P",		0, STD_EXT, NOLENGTHS, "",       "",   NULL },
818*9a4014feSSascha Wildner   /* DragonFly/FreeBSD conversion specifiers. */
819*9a4014feSSascha Wildner   { "+",		0, STD_EXT, NOLENGTHS, "E",      "3",  NULL },
820e4b17023SJohn Marino   { NULL,		0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
821e4b17023SJohn Marino };
822e4b17023SJohn Marino 
823e4b17023SJohn Marino static const format_char_info monetary_char_table[] =
824e4b17023SJohn Marino {
825e4b17023SJohn Marino   { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "", NULL },
826e4b17023SJohn Marino   { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
827e4b17023SJohn Marino };
828e4b17023SJohn Marino 
829e4b17023SJohn Marino /* This must be in the same order as enum format_type.  */
830e4b17023SJohn Marino static const format_kind_info format_types_orig[] =
831e4b17023SJohn Marino {
832e4b17023SJohn Marino   { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
833e4b17023SJohn Marino     printf_flag_specs, printf_flag_pairs,
834e4b17023SJohn Marino     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
835e4b17023SJohn Marino     'w', 0, 'p', 0, 'L', 0,
836e4b17023SJohn Marino     &integer_type_node, &integer_type_node
837e4b17023SJohn Marino   },
838e4b17023SJohn Marino   { "asm_fprintf",   asm_fprintf_length_specs,  asm_fprintf_char_table, " +#0-", NULL,
839e4b17023SJohn Marino     asm_fprintf_flag_specs, asm_fprintf_flag_pairs,
840e4b17023SJohn Marino     FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK,
841e4b17023SJohn Marino     'w', 0, 'p', 0, 'L', 0,
842e4b17023SJohn Marino     NULL, NULL
843e4b17023SJohn Marino   },
844e4b17023SJohn Marino   { "gcc_diag",   gcc_diag_length_specs,  gcc_diag_char_table, "q+#", NULL,
845e4b17023SJohn Marino     gcc_diag_flag_specs, gcc_diag_flag_pairs,
846e4b17023SJohn Marino     FMT_FLAG_ARG_CONVERT,
847e4b17023SJohn Marino     0, 0, 'p', 0, 'L', 0,
848e4b17023SJohn Marino     NULL, &integer_type_node
849e4b17023SJohn Marino   },
850e4b17023SJohn Marino   { "gcc_tdiag",   gcc_tdiag_length_specs,  gcc_tdiag_char_table, "q+#", NULL,
851e4b17023SJohn Marino     gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs,
852e4b17023SJohn Marino     FMT_FLAG_ARG_CONVERT,
853e4b17023SJohn Marino     0, 0, 'p', 0, 'L', 0,
854e4b17023SJohn Marino     NULL, &integer_type_node
855e4b17023SJohn Marino   },
856e4b17023SJohn Marino   { "gcc_cdiag",   gcc_cdiag_length_specs,  gcc_cdiag_char_table, "q+#", NULL,
857e4b17023SJohn Marino     gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs,
858e4b17023SJohn Marino     FMT_FLAG_ARG_CONVERT,
859e4b17023SJohn Marino     0, 0, 'p', 0, 'L', 0,
860e4b17023SJohn Marino     NULL, &integer_type_node
861e4b17023SJohn Marino   },
862e4b17023SJohn Marino   { "gcc_cxxdiag",   gcc_cxxdiag_length_specs,  gcc_cxxdiag_char_table, "q+#", NULL,
863e4b17023SJohn Marino     gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs,
864e4b17023SJohn Marino     FMT_FLAG_ARG_CONVERT,
865e4b17023SJohn Marino     0, 0, 'p', 0, 'L', 0,
866e4b17023SJohn Marino     NULL, &integer_type_node
867e4b17023SJohn Marino   },
868e4b17023SJohn Marino   { "gcc_gfc", gcc_gfc_length_specs, gcc_gfc_char_table, "", NULL,
869e4b17023SJohn Marino     NULL, gcc_gfc_flag_pairs,
870e4b17023SJohn Marino     FMT_FLAG_ARG_CONVERT,
871e4b17023SJohn Marino     0, 0, 0, 0, 0, 0,
872e4b17023SJohn Marino     NULL, NULL
873e4b17023SJohn Marino   },
874e4b17023SJohn Marino   { "NSString",   NULL,  NULL, NULL, NULL,
875e4b17023SJohn Marino     NULL, NULL,
876e4b17023SJohn Marino     FMT_FLAG_ARG_CONVERT|FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL, 0, 0, 0, 0, 0, 0,
877e4b17023SJohn Marino     NULL, NULL
878e4b17023SJohn Marino   },
879e4b17023SJohn Marino   { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
880e4b17023SJohn Marino     scanf_flag_specs, scanf_flag_pairs,
881e4b17023SJohn Marino     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
882e4b17023SJohn Marino     'w', 0, 0, '*', 'L', 'm',
883e4b17023SJohn Marino     NULL, NULL
884e4b17023SJohn Marino   },
885e4b17023SJohn Marino   { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
886e4b17023SJohn Marino     strftime_flag_specs, strftime_flag_pairs,
887e4b17023SJohn Marino     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
888e4b17023SJohn Marino     NULL, NULL
889e4b17023SJohn Marino   },
890e4b17023SJohn Marino   { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
891e4b17023SJohn Marino     strfmon_flag_specs, strfmon_flag_pairs,
892e4b17023SJohn Marino     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
893e4b17023SJohn Marino     NULL, NULL
894e4b17023SJohn Marino   }
895e4b17023SJohn Marino };
896e4b17023SJohn Marino 
897e4b17023SJohn Marino /* This layer of indirection allows GCC to reassign format_types with
898e4b17023SJohn Marino    new data if necessary, while still allowing the original data to be
899e4b17023SJohn Marino    const.  */
900e4b17023SJohn Marino static const format_kind_info *format_types = format_types_orig;
901e4b17023SJohn Marino /* We can modify this one.  We also add target-specific format types
902e4b17023SJohn Marino    to the end of the array.  */
903e4b17023SJohn Marino static format_kind_info *dynamic_format_types;
904e4b17023SJohn Marino 
905e4b17023SJohn Marino static int n_format_types = ARRAY_SIZE (format_types_orig);
906e4b17023SJohn Marino 
907e4b17023SJohn Marino /* Structure detailing the results of checking a format function call
908e4b17023SJohn Marino    where the format expression may be a conditional expression with
909e4b17023SJohn Marino    many leaves resulting from nested conditional expressions.  */
910e4b17023SJohn Marino typedef struct
911e4b17023SJohn Marino {
912e4b17023SJohn Marino   /* Number of leaves of the format argument that could not be checked
913e4b17023SJohn Marino      as they were not string literals.  */
914e4b17023SJohn Marino   int number_non_literal;
915e4b17023SJohn Marino   /* Number of leaves of the format argument that were null pointers or
916e4b17023SJohn Marino      string literals, but had extra format arguments.  */
917e4b17023SJohn Marino   int number_extra_args;
918e4b17023SJohn Marino   /* Number of leaves of the format argument that were null pointers or
919e4b17023SJohn Marino      string literals, but had extra format arguments and used $ operand
920e4b17023SJohn Marino      numbers.  */
921e4b17023SJohn Marino   int number_dollar_extra_args;
922e4b17023SJohn Marino   /* Number of leaves of the format argument that were wide string
923e4b17023SJohn Marino      literals.  */
924e4b17023SJohn Marino   int number_wide;
925e4b17023SJohn Marino   /* Number of leaves of the format argument that were empty strings.  */
926e4b17023SJohn Marino   int number_empty;
927e4b17023SJohn Marino   /* Number of leaves of the format argument that were unterminated
928e4b17023SJohn Marino      strings.  */
929e4b17023SJohn Marino   int number_unterminated;
930e4b17023SJohn Marino   /* Number of leaves of the format argument that were not counted above.  */
931e4b17023SJohn Marino   int number_other;
932e4b17023SJohn Marino } format_check_results;
933e4b17023SJohn Marino 
934e4b17023SJohn Marino typedef struct
935e4b17023SJohn Marino {
936e4b17023SJohn Marino   format_check_results *res;
937e4b17023SJohn Marino   function_format_info *info;
938e4b17023SJohn Marino   tree params;
939e4b17023SJohn Marino } format_check_context;
940e4b17023SJohn Marino 
941e4b17023SJohn Marino /* Return the format name (as specified in the original table) for the format
942e4b17023SJohn Marino    type indicated by format_num.  */
943e4b17023SJohn Marino static const char *
format_name(int format_num)944e4b17023SJohn Marino format_name (int format_num)
945e4b17023SJohn Marino {
946e4b17023SJohn Marino   if (format_num >= 0 && format_num < n_format_types)
947e4b17023SJohn Marino     return format_types[format_num].name;
948e4b17023SJohn Marino   gcc_unreachable ();
949e4b17023SJohn Marino }
950e4b17023SJohn Marino 
951e4b17023SJohn Marino /* Return the format flags (as specified in the original table) for the format
952e4b17023SJohn Marino    type indicated by format_num.  */
953e4b17023SJohn Marino static int
format_flags(int format_num)954e4b17023SJohn Marino format_flags (int format_num)
955e4b17023SJohn Marino {
956e4b17023SJohn Marino   if (format_num >= 0 && format_num < n_format_types)
957e4b17023SJohn Marino     return format_types[format_num].flags;
958e4b17023SJohn Marino   gcc_unreachable ();
959e4b17023SJohn Marino }
960e4b17023SJohn Marino 
961e4b17023SJohn Marino static void check_format_info (function_format_info *, tree);
962e4b17023SJohn Marino static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT);
963e4b17023SJohn Marino static void check_format_info_main (format_check_results *,
964e4b17023SJohn Marino 				    function_format_info *,
965e4b17023SJohn Marino 				    const char *, int, tree,
966e4b17023SJohn Marino                                     unsigned HOST_WIDE_INT, alloc_pool);
967e4b17023SJohn Marino 
968e4b17023SJohn Marino static void init_dollar_format_checking (int, tree);
969e4b17023SJohn Marino static int maybe_read_dollar_number (const char **, int,
970e4b17023SJohn Marino 				     tree, tree *, const format_kind_info *);
971e4b17023SJohn Marino static bool avoid_dollar_number (const char *);
972e4b17023SJohn Marino static void finish_dollar_format_checking (format_check_results *, int);
973e4b17023SJohn Marino 
974e4b17023SJohn Marino static const format_flag_spec *get_flag_spec (const format_flag_spec *,
975e4b17023SJohn Marino 					      int, const char *);
976e4b17023SJohn Marino 
977e4b17023SJohn Marino static void check_format_types (format_wanted_type *);
978e4b17023SJohn Marino static void format_type_warning (format_wanted_type *, tree, tree);
979e4b17023SJohn Marino 
980e4b17023SJohn Marino /* Decode a format type from a string, returning the type, or
981e4b17023SJohn Marino    format_type_error if not valid, in which case the caller should print an
982e4b17023SJohn Marino    error message.  */
983e4b17023SJohn Marino static int
decode_format_type(const char * s)984e4b17023SJohn Marino decode_format_type (const char *s)
985e4b17023SJohn Marino {
986e4b17023SJohn Marino   int i;
987e4b17023SJohn Marino   int slen;
988e4b17023SJohn Marino 
989e4b17023SJohn Marino   s = convert_format_name_to_system_name (s);
990e4b17023SJohn Marino   slen = strlen (s);
991e4b17023SJohn Marino   for (i = 0; i < n_format_types; i++)
992e4b17023SJohn Marino     {
993e4b17023SJohn Marino       int alen;
994e4b17023SJohn Marino       if (!strcmp (s, format_types[i].name))
995e4b17023SJohn Marino 	return i;
996e4b17023SJohn Marino       alen = strlen (format_types[i].name);
997e4b17023SJohn Marino       if (slen == alen + 4 && s[0] == '_' && s[1] == '_'
998e4b17023SJohn Marino 	  && s[slen - 1] == '_' && s[slen - 2] == '_'
999e4b17023SJohn Marino 	  && !strncmp (s + 2, format_types[i].name, alen))
1000e4b17023SJohn Marino 	return i;
1001e4b17023SJohn Marino     }
1002e4b17023SJohn Marino   return format_type_error;
1003e4b17023SJohn Marino }
1004e4b17023SJohn Marino 
1005e4b17023SJohn Marino 
1006e4b17023SJohn Marino /* Check the argument list of a call to printf, scanf, etc.
1007e4b17023SJohn Marino    ATTRS are the attributes on the function type.  There are NARGS argument
1008e4b17023SJohn Marino    values in the array ARGARRAY.
1009e4b17023SJohn Marino    Also, if -Wmissing-format-attribute,
1010e4b17023SJohn Marino    warn for calls to vprintf or vscanf in functions with no such format
1011e4b17023SJohn Marino    attribute themselves.  */
1012e4b17023SJohn Marino 
1013e4b17023SJohn Marino void
check_function_format(tree attrs,int nargs,tree * argarray)1014e4b17023SJohn Marino check_function_format (tree attrs, int nargs, tree *argarray)
1015e4b17023SJohn Marino {
1016e4b17023SJohn Marino   tree a;
1017e4b17023SJohn Marino 
1018e4b17023SJohn Marino   /* See if this function has any format attributes.  */
1019e4b17023SJohn Marino   for (a = attrs; a; a = TREE_CHAIN (a))
1020e4b17023SJohn Marino     {
1021e4b17023SJohn Marino       if (is_attribute_p ("format", TREE_PURPOSE (a)))
1022e4b17023SJohn Marino 	{
1023e4b17023SJohn Marino 	  /* Yup; check it.  */
1024e4b17023SJohn Marino 	  function_format_info info;
1025e4b17023SJohn Marino 	  decode_format_attr (TREE_VALUE (a), &info, 1);
1026e4b17023SJohn Marino 	  if (warn_format)
1027e4b17023SJohn Marino 	    {
1028e4b17023SJohn Marino 	      /* FIXME: Rewrite all the internal functions in this file
1029e4b17023SJohn Marino 		 to use the ARGARRAY directly instead of constructing this
1030e4b17023SJohn Marino 		 temporary list.  */
1031e4b17023SJohn Marino 	      tree params = NULL_TREE;
1032e4b17023SJohn Marino 	      int i;
1033e4b17023SJohn Marino 	      for (i = nargs - 1; i >= 0; i--)
1034e4b17023SJohn Marino 		params = tree_cons (NULL_TREE, argarray[i], params);
1035e4b17023SJohn Marino 	      check_format_info (&info, params);
1036e4b17023SJohn Marino 	    }
1037e4b17023SJohn Marino 	  if (warn_missing_format_attribute && info.first_arg_num == 0
1038e4b17023SJohn Marino 	      && (format_types[info.format_type].flags
1039e4b17023SJohn Marino 		  & (int) FMT_FLAG_ARG_CONVERT))
1040e4b17023SJohn Marino 	    {
1041e4b17023SJohn Marino 	      tree c;
1042e4b17023SJohn Marino 	      for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1043e4b17023SJohn Marino 		   c;
1044e4b17023SJohn Marino 		   c = TREE_CHAIN (c))
1045e4b17023SJohn Marino 		if (is_attribute_p ("format", TREE_PURPOSE (c))
1046e4b17023SJohn Marino 		    && (decode_format_type (IDENTIFIER_POINTER
1047e4b17023SJohn Marino 					    (TREE_VALUE (TREE_VALUE (c))))
1048e4b17023SJohn Marino 			== info.format_type))
1049e4b17023SJohn Marino 		  break;
1050e4b17023SJohn Marino 	      if (c == NULL_TREE)
1051e4b17023SJohn Marino 		{
1052e4b17023SJohn Marino 		  /* Check if the current function has a parameter to which
1053e4b17023SJohn Marino 		     the format attribute could be attached; if not, it
1054e4b17023SJohn Marino 		     can't be a candidate for a format attribute, despite
1055e4b17023SJohn Marino 		     the vprintf-like or vscanf-like call.  */
1056e4b17023SJohn Marino 		  tree args;
1057e4b17023SJohn Marino 		  for (args = DECL_ARGUMENTS (current_function_decl);
1058e4b17023SJohn Marino 		       args != 0;
1059e4b17023SJohn Marino 		       args = DECL_CHAIN (args))
1060e4b17023SJohn Marino 		    {
1061e4b17023SJohn Marino 		      if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE
1062e4b17023SJohn Marino 			  && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args)))
1063e4b17023SJohn Marino 			      == char_type_node))
1064e4b17023SJohn Marino 			break;
1065e4b17023SJohn Marino 		    }
1066e4b17023SJohn Marino 		  if (args != 0)
1067e4b17023SJohn Marino 		    warning (OPT_Wmissing_format_attribute, "function might "
1068e4b17023SJohn Marino 			     "be possible candidate for %qs format attribute",
1069e4b17023SJohn Marino 			     format_types[info.format_type].name);
1070e4b17023SJohn Marino 		}
1071e4b17023SJohn Marino 	    }
1072e4b17023SJohn Marino 	}
1073e4b17023SJohn Marino     }
1074e4b17023SJohn Marino }
1075e4b17023SJohn Marino 
1076e4b17023SJohn Marino 
1077e4b17023SJohn Marino /* Variables used by the checking of $ operand number formats.  */
1078e4b17023SJohn Marino static char *dollar_arguments_used = NULL;
1079e4b17023SJohn Marino static char *dollar_arguments_pointer_p = NULL;
1080e4b17023SJohn Marino static int dollar_arguments_alloc = 0;
1081e4b17023SJohn Marino static int dollar_arguments_count;
1082e4b17023SJohn Marino static int dollar_first_arg_num;
1083e4b17023SJohn Marino static int dollar_max_arg_used;
1084e4b17023SJohn Marino static int dollar_format_warned;
1085e4b17023SJohn Marino 
1086e4b17023SJohn Marino /* Initialize the checking for a format string that may contain $
1087e4b17023SJohn Marino    parameter number specifications; we will need to keep track of whether
1088e4b17023SJohn Marino    each parameter has been used.  FIRST_ARG_NUM is the number of the first
1089e4b17023SJohn Marino    argument that is a parameter to the format, or 0 for a vprintf-style
1090e4b17023SJohn Marino    function; PARAMS is the list of arguments starting at this argument.  */
1091e4b17023SJohn Marino 
1092e4b17023SJohn Marino static void
init_dollar_format_checking(int first_arg_num,tree params)1093e4b17023SJohn Marino init_dollar_format_checking (int first_arg_num, tree params)
1094e4b17023SJohn Marino {
1095e4b17023SJohn Marino   tree oparams = params;
1096e4b17023SJohn Marino 
1097e4b17023SJohn Marino   dollar_first_arg_num = first_arg_num;
1098e4b17023SJohn Marino   dollar_arguments_count = 0;
1099e4b17023SJohn Marino   dollar_max_arg_used = 0;
1100e4b17023SJohn Marino   dollar_format_warned = 0;
1101e4b17023SJohn Marino   if (first_arg_num > 0)
1102e4b17023SJohn Marino     {
1103e4b17023SJohn Marino       while (params)
1104e4b17023SJohn Marino 	{
1105e4b17023SJohn Marino 	  dollar_arguments_count++;
1106e4b17023SJohn Marino 	  params = TREE_CHAIN (params);
1107e4b17023SJohn Marino 	}
1108e4b17023SJohn Marino     }
1109e4b17023SJohn Marino   if (dollar_arguments_alloc < dollar_arguments_count)
1110e4b17023SJohn Marino     {
1111e4b17023SJohn Marino       free (dollar_arguments_used);
1112e4b17023SJohn Marino       free (dollar_arguments_pointer_p);
1113e4b17023SJohn Marino       dollar_arguments_alloc = dollar_arguments_count;
1114e4b17023SJohn Marino       dollar_arguments_used = XNEWVEC (char, dollar_arguments_alloc);
1115e4b17023SJohn Marino       dollar_arguments_pointer_p = XNEWVEC (char, dollar_arguments_alloc);
1116e4b17023SJohn Marino     }
1117e4b17023SJohn Marino   if (dollar_arguments_alloc)
1118e4b17023SJohn Marino     {
1119e4b17023SJohn Marino       memset (dollar_arguments_used, 0, dollar_arguments_alloc);
1120e4b17023SJohn Marino       if (first_arg_num > 0)
1121e4b17023SJohn Marino 	{
1122e4b17023SJohn Marino 	  int i = 0;
1123e4b17023SJohn Marino 	  params = oparams;
1124e4b17023SJohn Marino 	  while (params)
1125e4b17023SJohn Marino 	    {
1126e4b17023SJohn Marino 	      dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params)))
1127e4b17023SJohn Marino 					       == POINTER_TYPE);
1128e4b17023SJohn Marino 	      params = TREE_CHAIN (params);
1129e4b17023SJohn Marino 	      i++;
1130e4b17023SJohn Marino 	    }
1131e4b17023SJohn Marino 	}
1132e4b17023SJohn Marino     }
1133e4b17023SJohn Marino }
1134e4b17023SJohn Marino 
1135e4b17023SJohn Marino 
1136e4b17023SJohn Marino /* Look for a decimal number followed by a $ in *FORMAT.  If DOLLAR_NEEDED
1137e4b17023SJohn Marino    is set, it is an error if one is not found; otherwise, it is OK.  If
1138e4b17023SJohn Marino    such a number is found, check whether it is within range and mark that
1139e4b17023SJohn Marino    numbered operand as being used for later checking.  Returns the operand
1140e4b17023SJohn Marino    number if found and within range, zero if no such number was found and
1141e4b17023SJohn Marino    this is OK, or -1 on error.  PARAMS points to the first operand of the
1142e4b17023SJohn Marino    format; PARAM_PTR is made to point to the parameter referred to.  If
1143e4b17023SJohn Marino    a $ format is found, *FORMAT is updated to point just after it.  */
1144e4b17023SJohn Marino 
1145e4b17023SJohn Marino static int
maybe_read_dollar_number(const char ** format,int dollar_needed,tree params,tree * param_ptr,const format_kind_info * fki)1146e4b17023SJohn Marino maybe_read_dollar_number (const char **format,
1147e4b17023SJohn Marino 			  int dollar_needed, tree params, tree *param_ptr,
1148e4b17023SJohn Marino 			  const format_kind_info *fki)
1149e4b17023SJohn Marino {
1150e4b17023SJohn Marino   int argnum;
1151e4b17023SJohn Marino   int overflow_flag;
1152e4b17023SJohn Marino   const char *fcp = *format;
1153e4b17023SJohn Marino   if (!ISDIGIT (*fcp))
1154e4b17023SJohn Marino     {
1155e4b17023SJohn Marino       if (dollar_needed)
1156e4b17023SJohn Marino 	{
1157e4b17023SJohn Marino 	  warning (OPT_Wformat, "missing $ operand number in format");
1158e4b17023SJohn Marino 	  return -1;
1159e4b17023SJohn Marino 	}
1160e4b17023SJohn Marino       else
1161e4b17023SJohn Marino 	return 0;
1162e4b17023SJohn Marino     }
1163e4b17023SJohn Marino   argnum = 0;
1164e4b17023SJohn Marino   overflow_flag = 0;
1165e4b17023SJohn Marino   while (ISDIGIT (*fcp))
1166e4b17023SJohn Marino     {
1167e4b17023SJohn Marino       int nargnum;
1168e4b17023SJohn Marino       nargnum = 10 * argnum + (*fcp - '0');
1169e4b17023SJohn Marino       if (nargnum < 0 || nargnum / 10 != argnum)
1170e4b17023SJohn Marino 	overflow_flag = 1;
1171e4b17023SJohn Marino       argnum = nargnum;
1172e4b17023SJohn Marino       fcp++;
1173e4b17023SJohn Marino     }
1174e4b17023SJohn Marino   if (*fcp != '$')
1175e4b17023SJohn Marino     {
1176e4b17023SJohn Marino       if (dollar_needed)
1177e4b17023SJohn Marino 	{
1178e4b17023SJohn Marino 	  warning (OPT_Wformat, "missing $ operand number in format");
1179e4b17023SJohn Marino 	  return -1;
1180e4b17023SJohn Marino 	}
1181e4b17023SJohn Marino       else
1182e4b17023SJohn Marino 	return 0;
1183e4b17023SJohn Marino     }
1184e4b17023SJohn Marino   *format = fcp + 1;
1185e4b17023SJohn Marino   if (pedantic && !dollar_format_warned)
1186e4b17023SJohn Marino     {
1187e4b17023SJohn Marino       warning (OPT_Wformat, "%s does not support %%n$ operand number formats",
1188e4b17023SJohn Marino 	       C_STD_NAME (STD_EXT));
1189e4b17023SJohn Marino       dollar_format_warned = 1;
1190e4b17023SJohn Marino     }
1191e4b17023SJohn Marino   if (overflow_flag || argnum == 0
1192e4b17023SJohn Marino       || (dollar_first_arg_num && argnum > dollar_arguments_count))
1193e4b17023SJohn Marino     {
1194e4b17023SJohn Marino       warning (OPT_Wformat, "operand number out of range in format");
1195e4b17023SJohn Marino       return -1;
1196e4b17023SJohn Marino     }
1197e4b17023SJohn Marino   if (argnum > dollar_max_arg_used)
1198e4b17023SJohn Marino     dollar_max_arg_used = argnum;
1199e4b17023SJohn Marino   /* For vprintf-style functions we may need to allocate more memory to
1200e4b17023SJohn Marino      track which arguments are used.  */
1201e4b17023SJohn Marino   while (dollar_arguments_alloc < dollar_max_arg_used)
1202e4b17023SJohn Marino     {
1203e4b17023SJohn Marino       int nalloc;
1204e4b17023SJohn Marino       nalloc = 2 * dollar_arguments_alloc + 16;
1205e4b17023SJohn Marino       dollar_arguments_used = XRESIZEVEC (char, dollar_arguments_used,
1206e4b17023SJohn Marino 					  nalloc);
1207e4b17023SJohn Marino       dollar_arguments_pointer_p = XRESIZEVEC (char, dollar_arguments_pointer_p,
1208e4b17023SJohn Marino 					       nalloc);
1209e4b17023SJohn Marino       memset (dollar_arguments_used + dollar_arguments_alloc, 0,
1210e4b17023SJohn Marino 	      nalloc - dollar_arguments_alloc);
1211e4b17023SJohn Marino       dollar_arguments_alloc = nalloc;
1212e4b17023SJohn Marino     }
1213e4b17023SJohn Marino   if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE)
1214e4b17023SJohn Marino       && dollar_arguments_used[argnum - 1] == 1)
1215e4b17023SJohn Marino     {
1216e4b17023SJohn Marino       dollar_arguments_used[argnum - 1] = 2;
1217e4b17023SJohn Marino       warning (OPT_Wformat, "format argument %d used more than once in %s format",
1218e4b17023SJohn Marino 	       argnum, fki->name);
1219e4b17023SJohn Marino     }
1220e4b17023SJohn Marino   else
1221e4b17023SJohn Marino     dollar_arguments_used[argnum - 1] = 1;
1222e4b17023SJohn Marino   if (dollar_first_arg_num)
1223e4b17023SJohn Marino     {
1224e4b17023SJohn Marino       int i;
1225e4b17023SJohn Marino       *param_ptr = params;
1226e4b17023SJohn Marino       for (i = 1; i < argnum && *param_ptr != 0; i++)
1227e4b17023SJohn Marino 	*param_ptr = TREE_CHAIN (*param_ptr);
1228e4b17023SJohn Marino 
1229e4b17023SJohn Marino       /* This case shouldn't be caught here.  */
1230e4b17023SJohn Marino       gcc_assert (*param_ptr);
1231e4b17023SJohn Marino     }
1232e4b17023SJohn Marino   else
1233e4b17023SJohn Marino     *param_ptr = 0;
1234e4b17023SJohn Marino   return argnum;
1235e4b17023SJohn Marino }
1236e4b17023SJohn Marino 
1237e4b17023SJohn Marino /* Ensure that FORMAT does not start with a decimal number followed by
1238e4b17023SJohn Marino    a $; give a diagnostic and return true if it does, false otherwise.  */
1239e4b17023SJohn Marino 
1240e4b17023SJohn Marino static bool
avoid_dollar_number(const char * format)1241e4b17023SJohn Marino avoid_dollar_number (const char *format)
1242e4b17023SJohn Marino {
1243e4b17023SJohn Marino   if (!ISDIGIT (*format))
1244e4b17023SJohn Marino     return false;
1245e4b17023SJohn Marino   while (ISDIGIT (*format))
1246e4b17023SJohn Marino     format++;
1247e4b17023SJohn Marino   if (*format == '$')
1248e4b17023SJohn Marino     {
1249e4b17023SJohn Marino       warning (OPT_Wformat, "$ operand number used after format without operand number");
1250e4b17023SJohn Marino       return true;
1251e4b17023SJohn Marino     }
1252e4b17023SJohn Marino   return false;
1253e4b17023SJohn Marino }
1254e4b17023SJohn Marino 
1255e4b17023SJohn Marino 
1256e4b17023SJohn Marino /* Finish the checking for a format string that used $ operand number formats
1257e4b17023SJohn Marino    instead of non-$ formats.  We check for unused operands before used ones
1258e4b17023SJohn Marino    (a serious error, since the implementation of the format function
1259e4b17023SJohn Marino    can't know what types to pass to va_arg to find the later arguments).
1260e4b17023SJohn Marino    and for unused operands at the end of the format (if we know how many
1261e4b17023SJohn Marino    arguments the format had, so not for vprintf).  If there were operand
1262e4b17023SJohn Marino    numbers out of range on a non-vprintf-style format, we won't have reached
1263e4b17023SJohn Marino    here.  If POINTER_GAP_OK, unused arguments are OK if all arguments are
1264e4b17023SJohn Marino    pointers.  */
1265e4b17023SJohn Marino 
1266e4b17023SJohn Marino static void
finish_dollar_format_checking(format_check_results * res,int pointer_gap_ok)1267e4b17023SJohn Marino finish_dollar_format_checking (format_check_results *res, int pointer_gap_ok)
1268e4b17023SJohn Marino {
1269e4b17023SJohn Marino   int i;
1270e4b17023SJohn Marino   bool found_pointer_gap = false;
1271e4b17023SJohn Marino   for (i = 0; i < dollar_max_arg_used; i++)
1272e4b17023SJohn Marino     {
1273e4b17023SJohn Marino       if (!dollar_arguments_used[i])
1274e4b17023SJohn Marino 	{
1275e4b17023SJohn Marino 	  if (pointer_gap_ok && (dollar_first_arg_num == 0
1276e4b17023SJohn Marino 				 || dollar_arguments_pointer_p[i]))
1277e4b17023SJohn Marino 	    found_pointer_gap = true;
1278e4b17023SJohn Marino 	  else
1279e4b17023SJohn Marino 	    warning (OPT_Wformat,
1280e4b17023SJohn Marino 		     "format argument %d unused before used argument %d in $-style format",
1281e4b17023SJohn Marino 		     i + 1, dollar_max_arg_used);
1282e4b17023SJohn Marino 	}
1283e4b17023SJohn Marino     }
1284e4b17023SJohn Marino   if (found_pointer_gap
1285e4b17023SJohn Marino       || (dollar_first_arg_num
1286e4b17023SJohn Marino 	  && dollar_max_arg_used < dollar_arguments_count))
1287e4b17023SJohn Marino     {
1288e4b17023SJohn Marino       res->number_other--;
1289e4b17023SJohn Marino       res->number_dollar_extra_args++;
1290e4b17023SJohn Marino     }
1291e4b17023SJohn Marino }
1292e4b17023SJohn Marino 
1293e4b17023SJohn Marino 
1294e4b17023SJohn Marino /* Retrieve the specification for a format flag.  SPEC contains the
1295e4b17023SJohn Marino    specifications for format flags for the applicable kind of format.
1296e4b17023SJohn Marino    FLAG is the flag in question.  If PREDICATES is NULL, the basic
1297e4b17023SJohn Marino    spec for that flag must be retrieved and must exist.  If
1298e4b17023SJohn Marino    PREDICATES is not NULL, it is a string listing possible predicates
1299e4b17023SJohn Marino    for the spec entry; if an entry predicated on any of these is
1300e4b17023SJohn Marino    found, it is returned, otherwise NULL is returned.  */
1301e4b17023SJohn Marino 
1302e4b17023SJohn Marino static const format_flag_spec *
get_flag_spec(const format_flag_spec * spec,int flag,const char * predicates)1303e4b17023SJohn Marino get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates)
1304e4b17023SJohn Marino {
1305e4b17023SJohn Marino   int i;
1306e4b17023SJohn Marino   for (i = 0; spec[i].flag_char != 0; i++)
1307e4b17023SJohn Marino     {
1308e4b17023SJohn Marino       if (spec[i].flag_char != flag)
1309e4b17023SJohn Marino 	continue;
1310e4b17023SJohn Marino       if (predicates != NULL)
1311e4b17023SJohn Marino 	{
1312e4b17023SJohn Marino 	  if (spec[i].predicate != 0
1313e4b17023SJohn Marino 	      && strchr (predicates, spec[i].predicate) != 0)
1314e4b17023SJohn Marino 	    return &spec[i];
1315e4b17023SJohn Marino 	}
1316e4b17023SJohn Marino       else if (spec[i].predicate == 0)
1317e4b17023SJohn Marino 	return &spec[i];
1318e4b17023SJohn Marino     }
1319e4b17023SJohn Marino   gcc_assert (predicates);
1320e4b17023SJohn Marino   return NULL;
1321e4b17023SJohn Marino }
1322e4b17023SJohn Marino 
1323e4b17023SJohn Marino 
1324e4b17023SJohn Marino /* Check the argument list of a call to printf, scanf, etc.
1325e4b17023SJohn Marino    INFO points to the function_format_info structure.
1326e4b17023SJohn Marino    PARAMS is the list of argument values.  */
1327e4b17023SJohn Marino 
1328e4b17023SJohn Marino static void
check_format_info(function_format_info * info,tree params)1329e4b17023SJohn Marino check_format_info (function_format_info *info, tree params)
1330e4b17023SJohn Marino {
1331e4b17023SJohn Marino   format_check_context format_ctx;
1332e4b17023SJohn Marino   unsigned HOST_WIDE_INT arg_num;
1333e4b17023SJohn Marino   tree format_tree;
1334e4b17023SJohn Marino   format_check_results res;
1335e4b17023SJohn Marino   /* Skip to format argument.  If the argument isn't available, there's
1336e4b17023SJohn Marino      no work for us to do; prototype checking will catch the problem.  */
1337e4b17023SJohn Marino   for (arg_num = 1; ; ++arg_num)
1338e4b17023SJohn Marino     {
1339e4b17023SJohn Marino       if (params == 0)
1340e4b17023SJohn Marino 	return;
1341e4b17023SJohn Marino       if (arg_num == info->format_num)
1342e4b17023SJohn Marino 	break;
1343e4b17023SJohn Marino       params = TREE_CHAIN (params);
1344e4b17023SJohn Marino     }
1345e4b17023SJohn Marino   format_tree = TREE_VALUE (params);
1346e4b17023SJohn Marino   params = TREE_CHAIN (params);
1347e4b17023SJohn Marino   if (format_tree == 0)
1348e4b17023SJohn Marino     return;
1349e4b17023SJohn Marino 
1350e4b17023SJohn Marino   res.number_non_literal = 0;
1351e4b17023SJohn Marino   res.number_extra_args = 0;
1352e4b17023SJohn Marino   res.number_dollar_extra_args = 0;
1353e4b17023SJohn Marino   res.number_wide = 0;
1354e4b17023SJohn Marino   res.number_empty = 0;
1355e4b17023SJohn Marino   res.number_unterminated = 0;
1356e4b17023SJohn Marino   res.number_other = 0;
1357e4b17023SJohn Marino 
1358e4b17023SJohn Marino   format_ctx.res = &res;
1359e4b17023SJohn Marino   format_ctx.info = info;
1360e4b17023SJohn Marino   format_ctx.params = params;
1361e4b17023SJohn Marino 
1362e4b17023SJohn Marino   check_function_arguments_recurse (check_format_arg, &format_ctx,
1363e4b17023SJohn Marino 				    format_tree, arg_num);
1364e4b17023SJohn Marino 
1365e4b17023SJohn Marino   if (res.number_non_literal > 0)
1366e4b17023SJohn Marino     {
1367e4b17023SJohn Marino       /* Functions taking a va_list normally pass a non-literal format
1368e4b17023SJohn Marino 	 string.  These functions typically are declared with
1369e4b17023SJohn Marino 	 first_arg_num == 0, so avoid warning in those cases.  */
1370e4b17023SJohn Marino       if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT))
1371e4b17023SJohn Marino 	{
1372e4b17023SJohn Marino 	  /* For strftime-like formats, warn for not checking the format
1373e4b17023SJohn Marino 	     string; but there are no arguments to check.  */
1374e4b17023SJohn Marino 	  warning (OPT_Wformat_nonliteral,
1375e4b17023SJohn Marino 		   "format not a string literal, format string not checked");
1376e4b17023SJohn Marino 	}
1377e4b17023SJohn Marino       else if (info->first_arg_num != 0)
1378e4b17023SJohn Marino 	{
1379e4b17023SJohn Marino 	  /* If there are no arguments for the format at all, we may have
1380e4b17023SJohn Marino 	     printf (foo) which is likely to be a security hole.  */
1381e4b17023SJohn Marino 	  while (arg_num + 1 < info->first_arg_num)
1382e4b17023SJohn Marino 	    {
1383e4b17023SJohn Marino 	      if (params == 0)
1384e4b17023SJohn Marino 		break;
1385e4b17023SJohn Marino 	      params = TREE_CHAIN (params);
1386e4b17023SJohn Marino 	      ++arg_num;
1387e4b17023SJohn Marino 	    }
1388e4b17023SJohn Marino 	  if (params == 0 && warn_format_security)
1389e4b17023SJohn Marino 	    warning (OPT_Wformat_security,
1390e4b17023SJohn Marino 		     "format not a string literal and no format arguments");
1391e4b17023SJohn Marino 	  else if (params == 0 && warn_format_nonliteral)
1392e4b17023SJohn Marino 	    warning (OPT_Wformat_nonliteral,
1393e4b17023SJohn Marino 		     "format not a string literal and no format arguments");
1394e4b17023SJohn Marino 	  else
1395e4b17023SJohn Marino 	    warning (OPT_Wformat_nonliteral,
1396e4b17023SJohn Marino 		     "format not a string literal, argument types not checked");
1397e4b17023SJohn Marino 	}
1398e4b17023SJohn Marino     }
1399e4b17023SJohn Marino 
1400e4b17023SJohn Marino   /* If there were extra arguments to the format, normally warn.  However,
1401e4b17023SJohn Marino      the standard does say extra arguments are ignored, so in the specific
1402e4b17023SJohn Marino      case where we have multiple leaves (conditional expressions or
1403e4b17023SJohn Marino      ngettext) allow extra arguments if at least one leaf didn't have extra
1404e4b17023SJohn Marino      arguments, but was otherwise OK (either non-literal or checked OK).
1405e4b17023SJohn Marino      If the format is an empty string, this should be counted similarly to the
1406e4b17023SJohn Marino      case of extra format arguments.  */
1407e4b17023SJohn Marino   if (res.number_extra_args > 0 && res.number_non_literal == 0
1408e4b17023SJohn Marino       && res.number_other == 0)
1409e4b17023SJohn Marino     warning (OPT_Wformat_extra_args, "too many arguments for format");
1410e4b17023SJohn Marino   if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0
1411e4b17023SJohn Marino       && res.number_other == 0)
1412e4b17023SJohn Marino     warning (OPT_Wformat_extra_args, "unused arguments in $-style format");
1413e4b17023SJohn Marino   if (res.number_empty > 0 && res.number_non_literal == 0
1414e4b17023SJohn Marino       && res.number_other == 0)
1415e4b17023SJohn Marino     warning (OPT_Wformat_zero_length, "zero-length %s format string",
1416e4b17023SJohn Marino 	     format_types[info->format_type].name);
1417e4b17023SJohn Marino 
1418e4b17023SJohn Marino   if (res.number_wide > 0)
1419e4b17023SJohn Marino     warning (OPT_Wformat, "format is a wide character string");
1420e4b17023SJohn Marino 
1421e4b17023SJohn Marino   if (res.number_unterminated > 0)
1422e4b17023SJohn Marino     warning (OPT_Wformat, "unterminated format string");
1423e4b17023SJohn Marino }
1424e4b17023SJohn Marino 
1425e4b17023SJohn Marino /* Callback from check_function_arguments_recurse to check a
1426e4b17023SJohn Marino    format string.  FORMAT_TREE is the format parameter.  ARG_NUM
1427e4b17023SJohn Marino    is the number of the format argument.  CTX points to a
1428e4b17023SJohn Marino    format_check_context.  */
1429e4b17023SJohn Marino 
1430e4b17023SJohn Marino static void
check_format_arg(void * ctx,tree format_tree,unsigned HOST_WIDE_INT arg_num)1431e4b17023SJohn Marino check_format_arg (void *ctx, tree format_tree,
1432e4b17023SJohn Marino 		  unsigned HOST_WIDE_INT arg_num)
1433e4b17023SJohn Marino {
1434e4b17023SJohn Marino   format_check_context *format_ctx = (format_check_context *) ctx;
1435e4b17023SJohn Marino   format_check_results *res = format_ctx->res;
1436e4b17023SJohn Marino   function_format_info *info = format_ctx->info;
1437e4b17023SJohn Marino   tree params = format_ctx->params;
1438e4b17023SJohn Marino 
1439e4b17023SJohn Marino   int format_length;
1440e4b17023SJohn Marino   HOST_WIDE_INT offset;
1441e4b17023SJohn Marino   const char *format_chars;
1442e4b17023SJohn Marino   tree array_size = 0;
1443e4b17023SJohn Marino   tree array_init;
1444e4b17023SJohn Marino   alloc_pool fwt_pool;
1445e4b17023SJohn Marino 
1446e4b17023SJohn Marino   if (integer_zerop (format_tree))
1447e4b17023SJohn Marino     {
1448e4b17023SJohn Marino       /* Skip to first argument to check, so we can see if this format
1449e4b17023SJohn Marino 	 has any arguments (it shouldn't).  */
1450e4b17023SJohn Marino       while (arg_num + 1 < info->first_arg_num)
1451e4b17023SJohn Marino 	{
1452e4b17023SJohn Marino 	  if (params == 0)
1453e4b17023SJohn Marino 	    return;
1454e4b17023SJohn Marino 	  params = TREE_CHAIN (params);
1455e4b17023SJohn Marino 	  ++arg_num;
1456e4b17023SJohn Marino 	}
1457e4b17023SJohn Marino 
1458e4b17023SJohn Marino       if (params == 0)
1459e4b17023SJohn Marino 	res->number_other++;
1460e4b17023SJohn Marino       else
1461e4b17023SJohn Marino 	res->number_extra_args++;
1462e4b17023SJohn Marino 
1463e4b17023SJohn Marino       return;
1464e4b17023SJohn Marino     }
1465e4b17023SJohn Marino 
1466e4b17023SJohn Marino   offset = 0;
1467e4b17023SJohn Marino   if (TREE_CODE (format_tree) == POINTER_PLUS_EXPR)
1468e4b17023SJohn Marino     {
1469e4b17023SJohn Marino       tree arg0, arg1;
1470e4b17023SJohn Marino 
1471e4b17023SJohn Marino       arg0 = TREE_OPERAND (format_tree, 0);
1472e4b17023SJohn Marino       arg1 = TREE_OPERAND (format_tree, 1);
1473e4b17023SJohn Marino       STRIP_NOPS (arg0);
1474e4b17023SJohn Marino       STRIP_NOPS (arg1);
1475e4b17023SJohn Marino       if (TREE_CODE (arg1) == INTEGER_CST)
1476e4b17023SJohn Marino 	format_tree = arg0;
1477e4b17023SJohn Marino       else
1478e4b17023SJohn Marino 	{
1479e4b17023SJohn Marino 	  res->number_non_literal++;
1480e4b17023SJohn Marino 	  return;
1481e4b17023SJohn Marino 	}
1482e4b17023SJohn Marino       if (!host_integerp (arg1, 0)
1483e4b17023SJohn Marino 	  || (offset = tree_low_cst (arg1, 0)) < 0)
1484e4b17023SJohn Marino 	{
1485e4b17023SJohn Marino 	  res->number_non_literal++;
1486e4b17023SJohn Marino 	  return;
1487e4b17023SJohn Marino 	}
1488e4b17023SJohn Marino     }
1489e4b17023SJohn Marino   if (TREE_CODE (format_tree) != ADDR_EXPR)
1490e4b17023SJohn Marino     {
1491e4b17023SJohn Marino       res->number_non_literal++;
1492e4b17023SJohn Marino       return;
1493e4b17023SJohn Marino     }
1494e4b17023SJohn Marino   format_tree = TREE_OPERAND (format_tree, 0);
1495e4b17023SJohn Marino   if (format_types[info->format_type].flags
1496e4b17023SJohn Marino       & (int) FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL)
1497e4b17023SJohn Marino     {
1498e4b17023SJohn Marino       bool objc_str = (info->format_type == gcc_objc_string_format_type);
1499e4b17023SJohn Marino       /* We cannot examine this string here - but we can check that it is
1500e4b17023SJohn Marino          a valid type.  */
1501e4b17023SJohn Marino       if (TREE_CODE (format_tree) != CONST_DECL
1502e4b17023SJohn Marino 	  || !((objc_str && objc_string_ref_type_p (TREE_TYPE (format_tree)))
1503e4b17023SJohn Marino 		|| (*targetcm.string_object_ref_type_p)
1504e4b17023SJohn Marino 				     ((const_tree) TREE_TYPE (format_tree))))
1505e4b17023SJohn Marino 	{
1506e4b17023SJohn Marino 	  res->number_non_literal++;
1507e4b17023SJohn Marino 	  return;
1508e4b17023SJohn Marino 	}
1509e4b17023SJohn Marino       /* Skip to first argument to check.  */
1510e4b17023SJohn Marino       while (arg_num + 1 < info->first_arg_num)
1511e4b17023SJohn Marino 	{
1512e4b17023SJohn Marino 	  if (params == 0)
1513e4b17023SJohn Marino 	    return;
1514e4b17023SJohn Marino 	  params = TREE_CHAIN (params);
1515e4b17023SJohn Marino 	  ++arg_num;
1516e4b17023SJohn Marino 	}
1517e4b17023SJohn Marino       /* So, we have a valid literal string object and one or more params.
1518e4b17023SJohn Marino          We need to use an external helper to parse the string into format
1519e4b17023SJohn Marino          info.  For Objective-C variants we provide the resource within the
1520e4b17023SJohn Marino          objc tree, for target variants, via a hook.  */
1521e4b17023SJohn Marino       if (objc_str)
1522e4b17023SJohn Marino 	objc_check_format_arg (format_tree, params);
1523e4b17023SJohn Marino       else if (targetcm.check_string_object_format_arg)
1524e4b17023SJohn Marino 	(*targetcm.check_string_object_format_arg) (format_tree, params);
1525e4b17023SJohn Marino       /* Else we can't handle it and retire quietly.  */
1526e4b17023SJohn Marino       return;
1527e4b17023SJohn Marino     }
1528e4b17023SJohn Marino   if (TREE_CODE (format_tree) == ARRAY_REF
1529e4b17023SJohn Marino       && host_integerp (TREE_OPERAND (format_tree, 1), 0)
1530e4b17023SJohn Marino       && (offset += tree_low_cst (TREE_OPERAND (format_tree, 1), 0)) >= 0)
1531e4b17023SJohn Marino     format_tree = TREE_OPERAND (format_tree, 0);
1532e4b17023SJohn Marino   if (TREE_CODE (format_tree) == VAR_DECL
1533e4b17023SJohn Marino       && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE
1534e4b17023SJohn Marino       && (array_init = decl_constant_value (format_tree)) != format_tree
1535e4b17023SJohn Marino       && TREE_CODE (array_init) == STRING_CST)
1536e4b17023SJohn Marino     {
1537e4b17023SJohn Marino       /* Extract the string constant initializer.  Note that this may include
1538e4b17023SJohn Marino 	 a trailing NUL character that is not in the array (e.g.
1539e4b17023SJohn Marino 	 const char a[3] = "foo";).  */
1540e4b17023SJohn Marino       array_size = DECL_SIZE_UNIT (format_tree);
1541e4b17023SJohn Marino       format_tree = array_init;
1542e4b17023SJohn Marino     }
1543e4b17023SJohn Marino   if (TREE_CODE (format_tree) != STRING_CST)
1544e4b17023SJohn Marino     {
1545e4b17023SJohn Marino       res->number_non_literal++;
1546e4b17023SJohn Marino       return;
1547e4b17023SJohn Marino     }
1548e4b17023SJohn Marino   if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree))) != char_type_node)
1549e4b17023SJohn Marino     {
1550e4b17023SJohn Marino       res->number_wide++;
1551e4b17023SJohn Marino       return;
1552e4b17023SJohn Marino     }
1553e4b17023SJohn Marino   format_chars = TREE_STRING_POINTER (format_tree);
1554e4b17023SJohn Marino   format_length = TREE_STRING_LENGTH (format_tree);
1555e4b17023SJohn Marino   if (array_size != 0)
1556e4b17023SJohn Marino     {
1557e4b17023SJohn Marino       /* Variable length arrays can't be initialized.  */
1558e4b17023SJohn Marino       gcc_assert (TREE_CODE (array_size) == INTEGER_CST);
1559e4b17023SJohn Marino 
1560e4b17023SJohn Marino       if (host_integerp (array_size, 0))
1561e4b17023SJohn Marino 	{
1562e4b17023SJohn Marino 	  HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size);
1563e4b17023SJohn Marino 	  if (array_size_value > 0
1564e4b17023SJohn Marino 	      && array_size_value == (int) array_size_value
1565e4b17023SJohn Marino 	      && format_length > array_size_value)
1566e4b17023SJohn Marino 	    format_length = array_size_value;
1567e4b17023SJohn Marino 	}
1568e4b17023SJohn Marino     }
1569e4b17023SJohn Marino   if (offset)
1570e4b17023SJohn Marino     {
1571e4b17023SJohn Marino       if (offset >= format_length)
1572e4b17023SJohn Marino 	{
1573e4b17023SJohn Marino 	  res->number_non_literal++;
1574e4b17023SJohn Marino 	  return;
1575e4b17023SJohn Marino 	}
1576e4b17023SJohn Marino       format_chars += offset;
1577e4b17023SJohn Marino       format_length -= offset;
1578e4b17023SJohn Marino     }
1579e4b17023SJohn Marino   if (format_length < 1 || format_chars[--format_length] != 0)
1580e4b17023SJohn Marino     {
1581e4b17023SJohn Marino       res->number_unterminated++;
1582e4b17023SJohn Marino       return;
1583e4b17023SJohn Marino     }
1584e4b17023SJohn Marino   if (format_length == 0)
1585e4b17023SJohn Marino     {
1586e4b17023SJohn Marino       res->number_empty++;
1587e4b17023SJohn Marino       return;
1588e4b17023SJohn Marino     }
1589e4b17023SJohn Marino 
1590e4b17023SJohn Marino   /* Skip to first argument to check.  */
1591e4b17023SJohn Marino   while (arg_num + 1 < info->first_arg_num)
1592e4b17023SJohn Marino     {
1593e4b17023SJohn Marino       if (params == 0)
1594e4b17023SJohn Marino 	return;
1595e4b17023SJohn Marino       params = TREE_CHAIN (params);
1596e4b17023SJohn Marino       ++arg_num;
1597e4b17023SJohn Marino     }
1598e4b17023SJohn Marino   /* Provisionally increment res->number_other; check_format_info_main
1599e4b17023SJohn Marino      will decrement it if it finds there are extra arguments, but this way
1600e4b17023SJohn Marino      need not adjust it for every return.  */
1601e4b17023SJohn Marino   res->number_other++;
1602e4b17023SJohn Marino   fwt_pool = create_alloc_pool ("format_wanted_type pool",
1603e4b17023SJohn Marino                                 sizeof (format_wanted_type), 10);
1604e4b17023SJohn Marino   check_format_info_main (res, info, format_chars, format_length,
1605e4b17023SJohn Marino                           params, arg_num, fwt_pool);
1606e4b17023SJohn Marino   free_alloc_pool (fwt_pool);
1607e4b17023SJohn Marino }
1608e4b17023SJohn Marino 
1609e4b17023SJohn Marino 
1610e4b17023SJohn Marino /* Do the main part of checking a call to a format function.  FORMAT_CHARS
1611e4b17023SJohn Marino    is the NUL-terminated format string (which at this point may contain
1612e4b17023SJohn Marino    internal NUL characters); FORMAT_LENGTH is its length (excluding the
1613e4b17023SJohn Marino    terminating NUL character).  ARG_NUM is one less than the number of
1614e4b17023SJohn Marino    the first format argument to check; PARAMS points to that format
1615e4b17023SJohn Marino    argument in the list of arguments.  */
1616e4b17023SJohn Marino 
1617e4b17023SJohn Marino static void
check_format_info_main(format_check_results * res,function_format_info * info,const char * format_chars,int format_length,tree params,unsigned HOST_WIDE_INT arg_num,alloc_pool fwt_pool)1618e4b17023SJohn Marino check_format_info_main (format_check_results *res,
1619e4b17023SJohn Marino 			function_format_info *info, const char *format_chars,
1620e4b17023SJohn Marino 			int format_length, tree params,
1621e4b17023SJohn Marino                         unsigned HOST_WIDE_INT arg_num, alloc_pool fwt_pool)
1622e4b17023SJohn Marino {
1623e4b17023SJohn Marino   const char *orig_format_chars = format_chars;
1624e4b17023SJohn Marino   tree first_fillin_param = params;
1625e4b17023SJohn Marino 
1626e4b17023SJohn Marino   const format_kind_info *fki = &format_types[info->format_type];
1627e4b17023SJohn Marino   const format_flag_spec *flag_specs = fki->flag_specs;
1628e4b17023SJohn Marino   const format_flag_pair *bad_flag_pairs = fki->bad_flag_pairs;
1629e4b17023SJohn Marino 
1630e4b17023SJohn Marino   /* -1 if no conversions taking an operand have been found; 0 if one has
1631e4b17023SJohn Marino      and it didn't use $; 1 if $ formats are in use.  */
1632e4b17023SJohn Marino   int has_operand_number = -1;
1633e4b17023SJohn Marino 
1634e4b17023SJohn Marino   init_dollar_format_checking (info->first_arg_num, first_fillin_param);
1635e4b17023SJohn Marino 
1636e4b17023SJohn Marino   while (*format_chars != 0)
1637e4b17023SJohn Marino     {
1638e4b17023SJohn Marino       int i;
1639e4b17023SJohn Marino       int suppressed = FALSE;
1640e4b17023SJohn Marino       const char *length_chars = NULL;
1641e4b17023SJohn Marino       enum format_lengths length_chars_val = FMT_LEN_none;
1642e4b17023SJohn Marino       enum format_std_version length_chars_std = STD_C89;
1643e4b17023SJohn Marino       int format_char;
1644e4b17023SJohn Marino       tree cur_param;
1645e4b17023SJohn Marino       tree wanted_type;
1646e4b17023SJohn Marino       int main_arg_num = 0;
1647e4b17023SJohn Marino       tree main_arg_params = 0;
1648e4b17023SJohn Marino       enum format_std_version wanted_type_std;
1649e4b17023SJohn Marino       const char *wanted_type_name;
1650e4b17023SJohn Marino       format_wanted_type width_wanted_type;
1651e4b17023SJohn Marino       format_wanted_type precision_wanted_type;
1652e4b17023SJohn Marino       format_wanted_type main_wanted_type;
1653e4b17023SJohn Marino       format_wanted_type *first_wanted_type = NULL;
1654e4b17023SJohn Marino       format_wanted_type *last_wanted_type = NULL;
1655e4b17023SJohn Marino       const format_length_info *fli = NULL;
1656e4b17023SJohn Marino       const format_char_info *fci = NULL;
1657e4b17023SJohn Marino       char flag_chars[256];
1658e4b17023SJohn Marino       int alloc_flag = 0;
1659e4b17023SJohn Marino       int scalar_identity_flag = 0;
1660e4b17023SJohn Marino       const char *format_start;
1661e4b17023SJohn Marino 
1662e4b17023SJohn Marino       if (*format_chars++ != '%')
1663e4b17023SJohn Marino 	continue;
1664e4b17023SJohn Marino       if (*format_chars == 0)
1665e4b17023SJohn Marino 	{
1666e4b17023SJohn Marino 	  warning (OPT_Wformat, "spurious trailing %<%%%> in format");
1667e4b17023SJohn Marino 	  continue;
1668e4b17023SJohn Marino 	}
1669e4b17023SJohn Marino       if (*format_chars == '%')
1670e4b17023SJohn Marino 	{
1671e4b17023SJohn Marino 	  ++format_chars;
1672e4b17023SJohn Marino 	  continue;
1673e4b17023SJohn Marino 	}
1674e4b17023SJohn Marino       flag_chars[0] = 0;
1675e4b17023SJohn Marino 
1676e4b17023SJohn Marino       if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0)
1677e4b17023SJohn Marino 	{
1678e4b17023SJohn Marino 	  /* Possibly read a $ operand number at the start of the format.
1679e4b17023SJohn Marino 	     If one was previously used, one is required here.  If one
1680e4b17023SJohn Marino 	     is not used here, we can't immediately conclude this is a
1681e4b17023SJohn Marino 	     format without them, since it could be printf %m or scanf %*.  */
1682e4b17023SJohn Marino 	  int opnum;
1683e4b17023SJohn Marino 	  opnum = maybe_read_dollar_number (&format_chars, 0,
1684e4b17023SJohn Marino 					    first_fillin_param,
1685e4b17023SJohn Marino 					    &main_arg_params, fki);
1686e4b17023SJohn Marino 	  if (opnum == -1)
1687e4b17023SJohn Marino 	    return;
1688e4b17023SJohn Marino 	  else if (opnum > 0)
1689e4b17023SJohn Marino 	    {
1690e4b17023SJohn Marino 	      has_operand_number = 1;
1691e4b17023SJohn Marino 	      main_arg_num = opnum + info->first_arg_num - 1;
1692e4b17023SJohn Marino 	    }
1693e4b17023SJohn Marino 	}
1694e4b17023SJohn Marino       else if (fki->flags & FMT_FLAG_USE_DOLLAR)
1695e4b17023SJohn Marino 	{
1696e4b17023SJohn Marino 	  if (avoid_dollar_number (format_chars))
1697e4b17023SJohn Marino 	    return;
1698e4b17023SJohn Marino 	}
1699e4b17023SJohn Marino 
1700e4b17023SJohn Marino       /* Read any format flags, but do not yet validate them beyond removing
1701e4b17023SJohn Marino 	 duplicates, since in general validation depends on the rest of
1702e4b17023SJohn Marino 	 the format.  */
1703e4b17023SJohn Marino       while (*format_chars != 0
1704e4b17023SJohn Marino 	     && strchr (fki->flag_chars, *format_chars) != 0)
1705e4b17023SJohn Marino 	{
1706e4b17023SJohn Marino 	  const format_flag_spec *s = get_flag_spec (flag_specs,
1707e4b17023SJohn Marino 						     *format_chars, NULL);
1708e4b17023SJohn Marino 	  if (strchr (flag_chars, *format_chars) != 0)
1709e4b17023SJohn Marino 	    {
1710e4b17023SJohn Marino 	      warning (OPT_Wformat, "repeated %s in format", _(s->name));
1711e4b17023SJohn Marino 	    }
1712e4b17023SJohn Marino 	  else
1713e4b17023SJohn Marino 	    {
1714e4b17023SJohn Marino 	      i = strlen (flag_chars);
1715e4b17023SJohn Marino 	      flag_chars[i++] = *format_chars;
1716e4b17023SJohn Marino 	      flag_chars[i] = 0;
1717e4b17023SJohn Marino 	    }
1718e4b17023SJohn Marino 	  if (s->skip_next_char)
1719e4b17023SJohn Marino 	    {
1720e4b17023SJohn Marino 	      ++format_chars;
1721e4b17023SJohn Marino 	      if (*format_chars == 0)
1722e4b17023SJohn Marino 		{
1723e4b17023SJohn Marino 		  warning (OPT_Wformat, "missing fill character at end of strfmon format");
1724e4b17023SJohn Marino 		  return;
1725e4b17023SJohn Marino 		}
1726e4b17023SJohn Marino 	    }
1727e4b17023SJohn Marino 	  ++format_chars;
1728e4b17023SJohn Marino 	}
1729e4b17023SJohn Marino 
1730e4b17023SJohn Marino       /* Read any format width, possibly * or *m$.  */
1731e4b17023SJohn Marino       if (fki->width_char != 0)
1732e4b17023SJohn Marino 	{
1733e4b17023SJohn Marino 	  if (fki->width_type != NULL && *format_chars == '*')
1734e4b17023SJohn Marino 	    {
1735e4b17023SJohn Marino 	      i = strlen (flag_chars);
1736e4b17023SJohn Marino 	      flag_chars[i++] = fki->width_char;
1737e4b17023SJohn Marino 	      flag_chars[i] = 0;
1738e4b17023SJohn Marino 	      /* "...a field width...may be indicated by an asterisk.
1739e4b17023SJohn Marino 		 In this case, an int argument supplies the field width..."  */
1740e4b17023SJohn Marino 	      ++format_chars;
1741e4b17023SJohn Marino 	      if (has_operand_number != 0)
1742e4b17023SJohn Marino 		{
1743e4b17023SJohn Marino 		  int opnum;
1744e4b17023SJohn Marino 		  opnum = maybe_read_dollar_number (&format_chars,
1745e4b17023SJohn Marino 						    has_operand_number == 1,
1746e4b17023SJohn Marino 						    first_fillin_param,
1747e4b17023SJohn Marino 						    &params, fki);
1748e4b17023SJohn Marino 		  if (opnum == -1)
1749e4b17023SJohn Marino 		    return;
1750e4b17023SJohn Marino 		  else if (opnum > 0)
1751e4b17023SJohn Marino 		    {
1752e4b17023SJohn Marino 		      has_operand_number = 1;
1753e4b17023SJohn Marino 		      arg_num = opnum + info->first_arg_num - 1;
1754e4b17023SJohn Marino 		    }
1755e4b17023SJohn Marino 		  else
1756e4b17023SJohn Marino 		    has_operand_number = 0;
1757e4b17023SJohn Marino 		}
1758e4b17023SJohn Marino 	      else
1759e4b17023SJohn Marino 		{
1760e4b17023SJohn Marino 		  if (avoid_dollar_number (format_chars))
1761e4b17023SJohn Marino 		    return;
1762e4b17023SJohn Marino 		}
1763e4b17023SJohn Marino 	      if (info->first_arg_num != 0)
1764e4b17023SJohn Marino 		{
1765e4b17023SJohn Marino 		  if (params == 0)
1766e4b17023SJohn Marino                     cur_param = NULL;
1767e4b17023SJohn Marino                   else
1768e4b17023SJohn Marino                     {
1769e4b17023SJohn Marino                       cur_param = TREE_VALUE (params);
1770e4b17023SJohn Marino                       if (has_operand_number <= 0)
1771e4b17023SJohn Marino                         {
1772e4b17023SJohn Marino                           params = TREE_CHAIN (params);
1773e4b17023SJohn Marino                           ++arg_num;
1774e4b17023SJohn Marino                         }
1775e4b17023SJohn Marino                     }
1776e4b17023SJohn Marino 		  width_wanted_type.wanted_type = *fki->width_type;
1777e4b17023SJohn Marino 		  width_wanted_type.wanted_type_name = NULL;
1778e4b17023SJohn Marino 		  width_wanted_type.pointer_count = 0;
1779e4b17023SJohn Marino 		  width_wanted_type.char_lenient_flag = 0;
1780e4b17023SJohn Marino 		  width_wanted_type.scalar_identity_flag = 0;
1781e4b17023SJohn Marino 		  width_wanted_type.writing_in_flag = 0;
1782e4b17023SJohn Marino 		  width_wanted_type.reading_from_flag = 0;
1783e4b17023SJohn Marino                   width_wanted_type.kind = CF_KIND_FIELD_WIDTH;
1784e4b17023SJohn Marino 		  width_wanted_type.format_start = format_chars - 1;
1785e4b17023SJohn Marino 		  width_wanted_type.format_length = 1;
1786e4b17023SJohn Marino 		  width_wanted_type.param = cur_param;
1787e4b17023SJohn Marino 		  width_wanted_type.arg_num = arg_num;
1788e4b17023SJohn Marino 		  width_wanted_type.next = NULL;
1789e4b17023SJohn Marino 		  if (last_wanted_type != 0)
1790e4b17023SJohn Marino 		    last_wanted_type->next = &width_wanted_type;
1791e4b17023SJohn Marino 		  if (first_wanted_type == 0)
1792e4b17023SJohn Marino 		    first_wanted_type = &width_wanted_type;
1793e4b17023SJohn Marino 		  last_wanted_type = &width_wanted_type;
1794e4b17023SJohn Marino 		}
1795e4b17023SJohn Marino 	    }
1796e4b17023SJohn Marino 	  else
1797e4b17023SJohn Marino 	    {
1798e4b17023SJohn Marino 	      /* Possibly read a numeric width.  If the width is zero,
1799e4b17023SJohn Marino 		 we complain if appropriate.  */
1800e4b17023SJohn Marino 	      int non_zero_width_char = FALSE;
1801e4b17023SJohn Marino 	      int found_width = FALSE;
1802e4b17023SJohn Marino 	      while (ISDIGIT (*format_chars))
1803e4b17023SJohn Marino 		{
1804e4b17023SJohn Marino 		  found_width = TRUE;
1805e4b17023SJohn Marino 		  if (*format_chars != '0')
1806e4b17023SJohn Marino 		    non_zero_width_char = TRUE;
1807e4b17023SJohn Marino 		  ++format_chars;
1808e4b17023SJohn Marino 		}
1809e4b17023SJohn Marino 	      if (found_width && !non_zero_width_char &&
1810e4b17023SJohn Marino 		  (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD))
1811e4b17023SJohn Marino 		warning (OPT_Wformat, "zero width in %s format", fki->name);
1812e4b17023SJohn Marino 	      if (found_width)
1813e4b17023SJohn Marino 		{
1814e4b17023SJohn Marino 		  i = strlen (flag_chars);
1815e4b17023SJohn Marino 		  flag_chars[i++] = fki->width_char;
1816e4b17023SJohn Marino 		  flag_chars[i] = 0;
1817e4b17023SJohn Marino 		}
1818e4b17023SJohn Marino 	    }
1819e4b17023SJohn Marino 	}
1820e4b17023SJohn Marino 
1821e4b17023SJohn Marino       /* Read any format left precision (must be a number, not *).  */
1822e4b17023SJohn Marino       if (fki->left_precision_char != 0 && *format_chars == '#')
1823e4b17023SJohn Marino 	{
1824e4b17023SJohn Marino 	  ++format_chars;
1825e4b17023SJohn Marino 	  i = strlen (flag_chars);
1826e4b17023SJohn Marino 	  flag_chars[i++] = fki->left_precision_char;
1827e4b17023SJohn Marino 	  flag_chars[i] = 0;
1828e4b17023SJohn Marino 	  if (!ISDIGIT (*format_chars))
1829e4b17023SJohn Marino 	    warning (OPT_Wformat, "empty left precision in %s format", fki->name);
1830e4b17023SJohn Marino 	  while (ISDIGIT (*format_chars))
1831e4b17023SJohn Marino 	    ++format_chars;
1832e4b17023SJohn Marino 	}
1833e4b17023SJohn Marino 
1834e4b17023SJohn Marino       /* Read any format precision, possibly * or *m$.  */
1835e4b17023SJohn Marino       if (fki->precision_char != 0 && *format_chars == '.')
1836e4b17023SJohn Marino 	{
1837e4b17023SJohn Marino 	  ++format_chars;
1838e4b17023SJohn Marino 	  i = strlen (flag_chars);
1839e4b17023SJohn Marino 	  flag_chars[i++] = fki->precision_char;
1840e4b17023SJohn Marino 	  flag_chars[i] = 0;
1841e4b17023SJohn Marino 	  if (fki->precision_type != NULL && *format_chars == '*')
1842e4b17023SJohn Marino 	    {
1843e4b17023SJohn Marino 	      /* "...a...precision...may be indicated by an asterisk.
1844e4b17023SJohn Marino 		 In this case, an int argument supplies the...precision."  */
1845e4b17023SJohn Marino 	      ++format_chars;
1846e4b17023SJohn Marino 	      if (has_operand_number != 0)
1847e4b17023SJohn Marino 		{
1848e4b17023SJohn Marino 		  int opnum;
1849e4b17023SJohn Marino 		  opnum = maybe_read_dollar_number (&format_chars,
1850e4b17023SJohn Marino 						    has_operand_number == 1,
1851e4b17023SJohn Marino 						    first_fillin_param,
1852e4b17023SJohn Marino 						    &params, fki);
1853e4b17023SJohn Marino 		  if (opnum == -1)
1854e4b17023SJohn Marino 		    return;
1855e4b17023SJohn Marino 		  else if (opnum > 0)
1856e4b17023SJohn Marino 		    {
1857e4b17023SJohn Marino 		      has_operand_number = 1;
1858e4b17023SJohn Marino 		      arg_num = opnum + info->first_arg_num - 1;
1859e4b17023SJohn Marino 		    }
1860e4b17023SJohn Marino 		  else
1861e4b17023SJohn Marino 		    has_operand_number = 0;
1862e4b17023SJohn Marino 		}
1863e4b17023SJohn Marino 	      else
1864e4b17023SJohn Marino 		{
1865e4b17023SJohn Marino 		  if (avoid_dollar_number (format_chars))
1866e4b17023SJohn Marino 		    return;
1867e4b17023SJohn Marino 		}
1868e4b17023SJohn Marino 	      if (info->first_arg_num != 0)
1869e4b17023SJohn Marino 		{
1870e4b17023SJohn Marino 		  if (params == 0)
1871e4b17023SJohn Marino                     cur_param = NULL;
1872e4b17023SJohn Marino                   else
1873e4b17023SJohn Marino                     {
1874e4b17023SJohn Marino                       cur_param = TREE_VALUE (params);
1875e4b17023SJohn Marino                       if (has_operand_number <= 0)
1876e4b17023SJohn Marino                         {
1877e4b17023SJohn Marino                           params = TREE_CHAIN (params);
1878e4b17023SJohn Marino                           ++arg_num;
1879e4b17023SJohn Marino                         }
1880e4b17023SJohn Marino                     }
1881e4b17023SJohn Marino 		  precision_wanted_type.wanted_type = *fki->precision_type;
1882e4b17023SJohn Marino 		  precision_wanted_type.wanted_type_name = NULL;
1883e4b17023SJohn Marino 		  precision_wanted_type.pointer_count = 0;
1884e4b17023SJohn Marino 		  precision_wanted_type.char_lenient_flag = 0;
1885e4b17023SJohn Marino 		  precision_wanted_type.scalar_identity_flag = 0;
1886e4b17023SJohn Marino 		  precision_wanted_type.writing_in_flag = 0;
1887e4b17023SJohn Marino 		  precision_wanted_type.reading_from_flag = 0;
1888e4b17023SJohn Marino                   precision_wanted_type.kind = CF_KIND_FIELD_PRECISION;
1889e4b17023SJohn Marino 		  precision_wanted_type.param = cur_param;
1890e4b17023SJohn Marino 		  precision_wanted_type.format_start = format_chars - 2;
1891e4b17023SJohn Marino 		  precision_wanted_type.format_length = 2;
1892e4b17023SJohn Marino 		  precision_wanted_type.arg_num = arg_num;
1893e4b17023SJohn Marino 		  precision_wanted_type.next = NULL;
1894e4b17023SJohn Marino 		  if (last_wanted_type != 0)
1895e4b17023SJohn Marino 		    last_wanted_type->next = &precision_wanted_type;
1896e4b17023SJohn Marino 		  if (first_wanted_type == 0)
1897e4b17023SJohn Marino 		    first_wanted_type = &precision_wanted_type;
1898e4b17023SJohn Marino 		  last_wanted_type = &precision_wanted_type;
1899e4b17023SJohn Marino 		}
1900e4b17023SJohn Marino 	    }
1901e4b17023SJohn Marino 	  else
1902e4b17023SJohn Marino 	    {
1903e4b17023SJohn Marino 	      if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK)
1904e4b17023SJohn Marino 		  && !ISDIGIT (*format_chars))
1905e4b17023SJohn Marino 		warning (OPT_Wformat, "empty precision in %s format", fki->name);
1906e4b17023SJohn Marino 	      while (ISDIGIT (*format_chars))
1907e4b17023SJohn Marino 		++format_chars;
1908e4b17023SJohn Marino 	    }
1909e4b17023SJohn Marino 	}
1910e4b17023SJohn Marino 
1911e4b17023SJohn Marino       format_start = format_chars;
1912e4b17023SJohn Marino       if (fki->alloc_char && fki->alloc_char == *format_chars)
1913e4b17023SJohn Marino 	{
1914e4b17023SJohn Marino 	  i = strlen (flag_chars);
1915e4b17023SJohn Marino 	  flag_chars[i++] = fki->alloc_char;
1916e4b17023SJohn Marino 	  flag_chars[i] = 0;
1917e4b17023SJohn Marino 	  format_chars++;
1918e4b17023SJohn Marino 	}
1919e4b17023SJohn Marino 
1920e4b17023SJohn Marino       /* Handle the scanf allocation kludge.  */
1921e4b17023SJohn Marino       if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
1922e4b17023SJohn Marino 	{
1923e4b17023SJohn Marino 	  if (*format_chars == 'a' && !flag_isoc99)
1924e4b17023SJohn Marino 	    {
1925e4b17023SJohn Marino 	      if (format_chars[1] == 's' || format_chars[1] == 'S'
1926e4b17023SJohn Marino 		  || format_chars[1] == '[')
1927e4b17023SJohn Marino 		{
1928e4b17023SJohn Marino 		  /* 'a' is used as a flag.  */
1929e4b17023SJohn Marino 		  i = strlen (flag_chars);
1930e4b17023SJohn Marino 		  flag_chars[i++] = 'a';
1931e4b17023SJohn Marino 		  flag_chars[i] = 0;
1932e4b17023SJohn Marino 		  format_chars++;
1933e4b17023SJohn Marino 		}
1934e4b17023SJohn Marino 	    }
1935e4b17023SJohn Marino 	}
1936e4b17023SJohn Marino 
1937e4b17023SJohn Marino       /* Read any length modifier, if this kind of format has them.  */
1938e4b17023SJohn Marino       fli = fki->length_char_specs;
1939e4b17023SJohn Marino       length_chars = NULL;
1940e4b17023SJohn Marino       length_chars_val = FMT_LEN_none;
1941e4b17023SJohn Marino       length_chars_std = STD_C89;
1942e4b17023SJohn Marino       scalar_identity_flag = 0;
1943e4b17023SJohn Marino       if (fli)
1944e4b17023SJohn Marino 	{
1945e4b17023SJohn Marino 	  while (fli->name != 0
1946e4b17023SJohn Marino  		 && strncmp (fli->name, format_chars, strlen (fli->name)))
1947e4b17023SJohn Marino 	      fli++;
1948e4b17023SJohn Marino 	  if (fli->name != 0)
1949e4b17023SJohn Marino 	    {
1950e4b17023SJohn Marino  	      format_chars += strlen (fli->name);
1951e4b17023SJohn Marino 	      if (fli->double_name != 0 && fli->name[0] == *format_chars)
1952e4b17023SJohn Marino 		{
1953e4b17023SJohn Marino 		  format_chars++;
1954e4b17023SJohn Marino 		  length_chars = fli->double_name;
1955e4b17023SJohn Marino 		  length_chars_val = fli->double_index;
1956e4b17023SJohn Marino 		  length_chars_std = fli->double_std;
1957e4b17023SJohn Marino 		}
1958e4b17023SJohn Marino 	      else
1959e4b17023SJohn Marino 		{
1960e4b17023SJohn Marino 		  length_chars = fli->name;
1961e4b17023SJohn Marino 		  length_chars_val = fli->index;
1962e4b17023SJohn Marino 		  length_chars_std = fli->std;
1963e4b17023SJohn Marino 		  scalar_identity_flag = fli->scalar_identity_flag;
1964e4b17023SJohn Marino 		}
1965e4b17023SJohn Marino 	      i = strlen (flag_chars);
1966e4b17023SJohn Marino 	      flag_chars[i++] = fki->length_code_char;
1967e4b17023SJohn Marino 	      flag_chars[i] = 0;
1968e4b17023SJohn Marino 	    }
1969e4b17023SJohn Marino 	  if (pedantic)
1970e4b17023SJohn Marino 	    {
1971e4b17023SJohn Marino 	      /* Warn if the length modifier is non-standard.  */
1972e4b17023SJohn Marino 	      if (ADJ_STD (length_chars_std) > C_STD_VER)
1973e4b17023SJohn Marino 		warning (OPT_Wformat,
1974e4b17023SJohn Marino 			 "%s does not support the %qs %s length modifier",
1975e4b17023SJohn Marino 			 C_STD_NAME (length_chars_std), length_chars,
1976e4b17023SJohn Marino 			 fki->name);
1977e4b17023SJohn Marino 	    }
1978e4b17023SJohn Marino 	}
1979e4b17023SJohn Marino 
1980e4b17023SJohn Marino       /* Read any modifier (strftime E/O).  */
1981e4b17023SJohn Marino       if (fki->modifier_chars != NULL)
1982e4b17023SJohn Marino 	{
1983e4b17023SJohn Marino 	  while (*format_chars != 0
1984e4b17023SJohn Marino 		 && strchr (fki->modifier_chars, *format_chars) != 0)
1985e4b17023SJohn Marino 	    {
1986e4b17023SJohn Marino 	      if (strchr (flag_chars, *format_chars) != 0)
1987e4b17023SJohn Marino 		{
1988e4b17023SJohn Marino 		  const format_flag_spec *s = get_flag_spec (flag_specs,
1989e4b17023SJohn Marino 							     *format_chars, NULL);
1990e4b17023SJohn Marino 		  warning (OPT_Wformat, "repeated %s in format", _(s->name));
1991e4b17023SJohn Marino 		}
1992e4b17023SJohn Marino 	      else
1993e4b17023SJohn Marino 		{
1994e4b17023SJohn Marino 		  i = strlen (flag_chars);
1995e4b17023SJohn Marino 		  flag_chars[i++] = *format_chars;
1996e4b17023SJohn Marino 		  flag_chars[i] = 0;
1997e4b17023SJohn Marino 		}
1998e4b17023SJohn Marino 	      ++format_chars;
1999e4b17023SJohn Marino 	    }
2000e4b17023SJohn Marino 	}
2001e4b17023SJohn Marino 
2002e4b17023SJohn Marino       format_char = *format_chars;
2003e4b17023SJohn Marino       if (format_char == 0
2004e4b17023SJohn Marino 	  || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
2005e4b17023SJohn Marino 	      && format_char == '%'))
2006e4b17023SJohn Marino 	{
2007e4b17023SJohn Marino 	  warning (OPT_Wformat, "conversion lacks type at end of format");
2008e4b17023SJohn Marino 	  continue;
2009e4b17023SJohn Marino 	}
2010e4b17023SJohn Marino       format_chars++;
2011e4b17023SJohn Marino       fci = fki->conversion_specs;
2012e4b17023SJohn Marino       while (fci->format_chars != 0
2013e4b17023SJohn Marino 	     && strchr (fci->format_chars, format_char) == 0)
2014e4b17023SJohn Marino 	  ++fci;
2015e4b17023SJohn Marino       if (fci->format_chars == 0)
2016e4b17023SJohn Marino 	{
2017e4b17023SJohn Marino 	  if (ISGRAPH (format_char))
2018e4b17023SJohn Marino 	    warning (OPT_Wformat, "unknown conversion type character %qc in format",
2019e4b17023SJohn Marino 		     format_char);
2020e4b17023SJohn Marino 	  else
2021e4b17023SJohn Marino 	    warning (OPT_Wformat, "unknown conversion type character 0x%x in format",
2022e4b17023SJohn Marino 		     format_char);
2023e4b17023SJohn Marino 	  continue;
2024e4b17023SJohn Marino 	}
2025e4b17023SJohn Marino       if (pedantic)
2026e4b17023SJohn Marino 	{
2027e4b17023SJohn Marino 	  if (ADJ_STD (fci->std) > C_STD_VER)
2028e4b17023SJohn Marino 	    warning (OPT_Wformat, "%s does not support the %<%%%c%> %s format",
2029e4b17023SJohn Marino 		     C_STD_NAME (fci->std), format_char, fki->name);
2030e4b17023SJohn Marino 	}
2031e4b17023SJohn Marino 
2032e4b17023SJohn Marino       /* Validate the individual flags used, removing any that are invalid.  */
2033e4b17023SJohn Marino       {
2034e4b17023SJohn Marino 	int d = 0;
2035e4b17023SJohn Marino 	for (i = 0; flag_chars[i] != 0; i++)
2036e4b17023SJohn Marino 	  {
2037e4b17023SJohn Marino 	    const format_flag_spec *s = get_flag_spec (flag_specs,
2038e4b17023SJohn Marino 						       flag_chars[i], NULL);
2039e4b17023SJohn Marino 	    flag_chars[i - d] = flag_chars[i];
2040e4b17023SJohn Marino 	    if (flag_chars[i] == fki->length_code_char)
2041e4b17023SJohn Marino 	      continue;
2042e4b17023SJohn Marino 	    if (strchr (fci->flag_chars, flag_chars[i]) == 0)
2043e4b17023SJohn Marino 	      {
2044e4b17023SJohn Marino 		warning (OPT_Wformat, "%s used with %<%%%c%> %s format",
2045e4b17023SJohn Marino 			 _(s->name), format_char, fki->name);
2046e4b17023SJohn Marino 		d++;
2047e4b17023SJohn Marino 		continue;
2048e4b17023SJohn Marino 	      }
2049e4b17023SJohn Marino 	    if (pedantic)
2050e4b17023SJohn Marino 	      {
2051e4b17023SJohn Marino 		const format_flag_spec *t;
2052e4b17023SJohn Marino 		if (ADJ_STD (s->std) > C_STD_VER)
2053e4b17023SJohn Marino 		  warning (OPT_Wformat, "%s does not support %s",
2054e4b17023SJohn Marino 			   C_STD_NAME (s->std), _(s->long_name));
2055e4b17023SJohn Marino 		t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2);
2056e4b17023SJohn Marino 		if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std))
2057e4b17023SJohn Marino 		  {
2058e4b17023SJohn Marino 		    const char *long_name = (t->long_name != NULL
2059e4b17023SJohn Marino 					     ? t->long_name
2060e4b17023SJohn Marino 					     : s->long_name);
2061e4b17023SJohn Marino 		    if (ADJ_STD (t->std) > C_STD_VER)
2062e4b17023SJohn Marino 		      warning (OPT_Wformat,
2063e4b17023SJohn Marino 			       "%s does not support %s with the %<%%%c%> %s format",
2064e4b17023SJohn Marino 			       C_STD_NAME (t->std), _(long_name),
2065e4b17023SJohn Marino 			       format_char, fki->name);
2066e4b17023SJohn Marino 		  }
2067e4b17023SJohn Marino 	      }
2068e4b17023SJohn Marino 	  }
2069e4b17023SJohn Marino 	flag_chars[i - d] = 0;
2070e4b17023SJohn Marino       }
2071e4b17023SJohn Marino 
2072e4b17023SJohn Marino       if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
2073e4b17023SJohn Marino 	  && strchr (flag_chars, 'a') != 0)
2074e4b17023SJohn Marino 	alloc_flag = 1;
2075e4b17023SJohn Marino       if (fki->alloc_char && strchr (flag_chars, fki->alloc_char) != 0)
2076e4b17023SJohn Marino 	alloc_flag = 1;
2077e4b17023SJohn Marino 
2078e4b17023SJohn Marino       if (fki->suppression_char
2079e4b17023SJohn Marino 	  && strchr (flag_chars, fki->suppression_char) != 0)
2080e4b17023SJohn Marino 	suppressed = 1;
2081e4b17023SJohn Marino 
2082e4b17023SJohn Marino       /* Validate the pairs of flags used.  */
2083e4b17023SJohn Marino       for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++)
2084e4b17023SJohn Marino 	{
2085e4b17023SJohn Marino 	  const format_flag_spec *s, *t;
2086e4b17023SJohn Marino 	  if (strchr (flag_chars, bad_flag_pairs[i].flag_char1) == 0)
2087e4b17023SJohn Marino 	    continue;
2088e4b17023SJohn Marino 	  if (strchr (flag_chars, bad_flag_pairs[i].flag_char2) == 0)
2089e4b17023SJohn Marino 	    continue;
2090e4b17023SJohn Marino 	  if (bad_flag_pairs[i].predicate != 0
2091e4b17023SJohn Marino 	      && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0)
2092e4b17023SJohn Marino 	    continue;
2093e4b17023SJohn Marino 	  s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL);
2094e4b17023SJohn Marino 	  t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL);
2095e4b17023SJohn Marino 	  if (bad_flag_pairs[i].ignored)
2096e4b17023SJohn Marino 	    {
2097e4b17023SJohn Marino 	      if (bad_flag_pairs[i].predicate != 0)
2098e4b17023SJohn Marino 		warning (OPT_Wformat,
2099e4b17023SJohn Marino 			 "%s ignored with %s and %<%%%c%> %s format",
2100e4b17023SJohn Marino 			 _(s->name), _(t->name), format_char,
2101e4b17023SJohn Marino 			 fki->name);
2102e4b17023SJohn Marino 	      else
2103e4b17023SJohn Marino 		warning (OPT_Wformat, "%s ignored with %s in %s format",
2104e4b17023SJohn Marino 			 _(s->name), _(t->name), fki->name);
2105e4b17023SJohn Marino 	    }
2106e4b17023SJohn Marino 	  else
2107e4b17023SJohn Marino 	    {
2108e4b17023SJohn Marino 	      if (bad_flag_pairs[i].predicate != 0)
2109e4b17023SJohn Marino 		warning (OPT_Wformat,
2110e4b17023SJohn Marino 			 "use of %s and %s together with %<%%%c%> %s format",
2111e4b17023SJohn Marino 			 _(s->name), _(t->name), format_char,
2112e4b17023SJohn Marino 			 fki->name);
2113e4b17023SJohn Marino 	      else
2114e4b17023SJohn Marino 		warning (OPT_Wformat, "use of %s and %s together in %s format",
2115e4b17023SJohn Marino 			 _(s->name), _(t->name), fki->name);
2116e4b17023SJohn Marino 	    }
2117e4b17023SJohn Marino 	}
2118e4b17023SJohn Marino 
2119e4b17023SJohn Marino       /* Give Y2K warnings.  */
2120e4b17023SJohn Marino       if (warn_format_y2k)
2121e4b17023SJohn Marino 	{
2122e4b17023SJohn Marino 	  int y2k_level = 0;
2123e4b17023SJohn Marino 	  if (strchr (fci->flags2, '4') != 0)
2124e4b17023SJohn Marino 	    if (strchr (flag_chars, 'E') != 0)
2125e4b17023SJohn Marino 	      y2k_level = 3;
2126e4b17023SJohn Marino 	    else
2127e4b17023SJohn Marino 	      y2k_level = 2;
2128e4b17023SJohn Marino 	  else if (strchr (fci->flags2, '3') != 0)
2129e4b17023SJohn Marino 	    y2k_level = 3;
2130e4b17023SJohn Marino 	  else if (strchr (fci->flags2, '2') != 0)
2131e4b17023SJohn Marino 	    y2k_level = 2;
2132e4b17023SJohn Marino 	  if (y2k_level == 3)
2133e4b17023SJohn Marino 	    warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of "
2134e4b17023SJohn Marino 		     "year in some locales", format_char);
2135e4b17023SJohn Marino 	  else if (y2k_level == 2)
2136e4b17023SJohn Marino 	    warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of "
2137e4b17023SJohn Marino 		     "year", format_char);
2138e4b17023SJohn Marino 	}
2139e4b17023SJohn Marino 
2140e4b17023SJohn Marino       if (strchr (fci->flags2, '[') != 0)
2141e4b17023SJohn Marino 	{
2142e4b17023SJohn Marino 	  /* Skip over scan set, in case it happens to have '%' in it.  */
2143e4b17023SJohn Marino 	  if (*format_chars == '^')
2144e4b17023SJohn Marino 	    ++format_chars;
2145e4b17023SJohn Marino 	  /* Find closing bracket; if one is hit immediately, then
2146e4b17023SJohn Marino 	     it's part of the scan set rather than a terminator.  */
2147e4b17023SJohn Marino 	  if (*format_chars == ']')
2148e4b17023SJohn Marino 	    ++format_chars;
2149e4b17023SJohn Marino 	  while (*format_chars && *format_chars != ']')
2150e4b17023SJohn Marino 	    ++format_chars;
2151e4b17023SJohn Marino 	  if (*format_chars != ']')
2152e4b17023SJohn Marino 	    /* The end of the format string was reached.  */
2153e4b17023SJohn Marino 	    warning (OPT_Wformat, "no closing %<]%> for %<%%[%> format");
2154e4b17023SJohn Marino 	}
2155e4b17023SJohn Marino 
2156e4b17023SJohn Marino       wanted_type = 0;
2157e4b17023SJohn Marino       wanted_type_name = 0;
2158e4b17023SJohn Marino       if (fki->flags & (int) FMT_FLAG_ARG_CONVERT)
2159e4b17023SJohn Marino 	{
2160e4b17023SJohn Marino 	  wanted_type = (fci->types[length_chars_val].type
2161e4b17023SJohn Marino 			 ? *fci->types[length_chars_val].type : 0);
2162e4b17023SJohn Marino 	  wanted_type_name = fci->types[length_chars_val].name;
2163e4b17023SJohn Marino 	  wanted_type_std = fci->types[length_chars_val].std;
2164e4b17023SJohn Marino 	  if (wanted_type == 0)
2165e4b17023SJohn Marino 	    {
2166e4b17023SJohn Marino 	      warning (OPT_Wformat,
2167e4b17023SJohn Marino 		       "use of %qs length modifier with %qc type character",
2168e4b17023SJohn Marino 		       length_chars, format_char);
2169e4b17023SJohn Marino 	      /* Heuristic: skip one argument when an invalid length/type
2170e4b17023SJohn Marino 		 combination is encountered.  */
2171e4b17023SJohn Marino 	      arg_num++;
2172e4b17023SJohn Marino 	      if (params != 0)
2173e4b17023SJohn Marino                 params = TREE_CHAIN (params);
2174e4b17023SJohn Marino 	      continue;
2175e4b17023SJohn Marino 	    }
2176e4b17023SJohn Marino 	  else if (pedantic
2177e4b17023SJohn Marino 		   /* Warn if non-standard, provided it is more non-standard
2178e4b17023SJohn Marino 		      than the length and type characters that may already
2179e4b17023SJohn Marino 		      have been warned for.  */
2180e4b17023SJohn Marino 		   && ADJ_STD (wanted_type_std) > ADJ_STD (length_chars_std)
2181e4b17023SJohn Marino 		   && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std))
2182e4b17023SJohn Marino 	    {
2183e4b17023SJohn Marino 	      if (ADJ_STD (wanted_type_std) > C_STD_VER)
2184e4b17023SJohn Marino 		warning (OPT_Wformat,
2185e4b17023SJohn Marino 			 "%s does not support the %<%%%s%c%> %s format",
2186e4b17023SJohn Marino 			 C_STD_NAME (wanted_type_std), length_chars,
2187e4b17023SJohn Marino 			 format_char, fki->name);
2188e4b17023SJohn Marino 	    }
2189e4b17023SJohn Marino 	}
2190e4b17023SJohn Marino 
2191e4b17023SJohn Marino       main_wanted_type.next = NULL;
2192e4b17023SJohn Marino 
2193e4b17023SJohn Marino       /* Finally. . .check type of argument against desired type!  */
2194e4b17023SJohn Marino       if (info->first_arg_num == 0)
2195e4b17023SJohn Marino 	continue;
2196e4b17023SJohn Marino       if ((fci->pointer_count == 0 && wanted_type == void_type_node)
2197e4b17023SJohn Marino 	  || suppressed)
2198e4b17023SJohn Marino 	{
2199e4b17023SJohn Marino 	  if (main_arg_num != 0)
2200e4b17023SJohn Marino 	    {
2201e4b17023SJohn Marino 	      if (suppressed)
2202e4b17023SJohn Marino 		warning (OPT_Wformat, "operand number specified with "
2203e4b17023SJohn Marino 			 "suppressed assignment");
2204e4b17023SJohn Marino 	      else
2205e4b17023SJohn Marino 		warning (OPT_Wformat, "operand number specified for format "
2206e4b17023SJohn Marino 			 "taking no argument");
2207e4b17023SJohn Marino 	    }
2208e4b17023SJohn Marino 	}
2209e4b17023SJohn Marino       else
2210e4b17023SJohn Marino 	{
2211e4b17023SJohn Marino 	  format_wanted_type *wanted_type_ptr;
2212e4b17023SJohn Marino 
2213e4b17023SJohn Marino 	  if (main_arg_num != 0)
2214e4b17023SJohn Marino 	    {
2215e4b17023SJohn Marino 	      arg_num = main_arg_num;
2216e4b17023SJohn Marino 	      params = main_arg_params;
2217e4b17023SJohn Marino 	    }
2218e4b17023SJohn Marino 	  else
2219e4b17023SJohn Marino 	    {
2220e4b17023SJohn Marino 	      ++arg_num;
2221e4b17023SJohn Marino 	      if (has_operand_number > 0)
2222e4b17023SJohn Marino 		{
2223e4b17023SJohn Marino 		  warning (OPT_Wformat, "missing $ operand number in format");
2224e4b17023SJohn Marino 		  return;
2225e4b17023SJohn Marino 		}
2226e4b17023SJohn Marino 	      else
2227e4b17023SJohn Marino 		has_operand_number = 0;
2228e4b17023SJohn Marino 	    }
2229e4b17023SJohn Marino 
2230e4b17023SJohn Marino 	  wanted_type_ptr = &main_wanted_type;
2231e4b17023SJohn Marino 	  while (fci)
2232e4b17023SJohn Marino 	    {
2233e4b17023SJohn Marino 	      if (params == 0)
2234e4b17023SJohn Marino                 cur_param = NULL;
2235e4b17023SJohn Marino               else
2236e4b17023SJohn Marino                 {
2237e4b17023SJohn Marino                   cur_param = TREE_VALUE (params);
2238e4b17023SJohn Marino                   params = TREE_CHAIN (params);
2239e4b17023SJohn Marino                 }
2240e4b17023SJohn Marino 
2241e4b17023SJohn Marino 	      wanted_type_ptr->wanted_type = wanted_type;
2242e4b17023SJohn Marino 	      wanted_type_ptr->wanted_type_name = wanted_type_name;
2243e4b17023SJohn Marino 	      wanted_type_ptr->pointer_count = fci->pointer_count + alloc_flag;
2244e4b17023SJohn Marino 	      wanted_type_ptr->char_lenient_flag = 0;
2245e4b17023SJohn Marino 	      if (strchr (fci->flags2, 'c') != 0)
2246e4b17023SJohn Marino 		wanted_type_ptr->char_lenient_flag = 1;
2247e4b17023SJohn Marino 	      wanted_type_ptr->scalar_identity_flag = 0;
2248e4b17023SJohn Marino 	      if (scalar_identity_flag)
2249e4b17023SJohn Marino 		wanted_type_ptr->scalar_identity_flag = 1;
2250e4b17023SJohn Marino 	      wanted_type_ptr->writing_in_flag = 0;
2251e4b17023SJohn Marino 	      wanted_type_ptr->reading_from_flag = 0;
2252e4b17023SJohn Marino 	      if (alloc_flag)
2253e4b17023SJohn Marino 		wanted_type_ptr->writing_in_flag = 1;
2254e4b17023SJohn Marino 	      else
2255e4b17023SJohn Marino 		{
2256e4b17023SJohn Marino 		  if (strchr (fci->flags2, 'W') != 0)
2257e4b17023SJohn Marino 		    wanted_type_ptr->writing_in_flag = 1;
2258e4b17023SJohn Marino 		  if (strchr (fci->flags2, 'R') != 0)
2259e4b17023SJohn Marino 		    wanted_type_ptr->reading_from_flag = 1;
2260e4b17023SJohn Marino 		}
2261e4b17023SJohn Marino               wanted_type_ptr->kind = CF_KIND_FORMAT;
2262e4b17023SJohn Marino 	      wanted_type_ptr->param = cur_param;
2263e4b17023SJohn Marino 	      wanted_type_ptr->arg_num = arg_num;
2264e4b17023SJohn Marino 	      wanted_type_ptr->format_start = format_start;
2265e4b17023SJohn Marino 	      wanted_type_ptr->format_length = format_chars - format_start;
2266e4b17023SJohn Marino 	      wanted_type_ptr->next = NULL;
2267e4b17023SJohn Marino 	      if (last_wanted_type != 0)
2268e4b17023SJohn Marino 		last_wanted_type->next = wanted_type_ptr;
2269e4b17023SJohn Marino 	      if (first_wanted_type == 0)
2270e4b17023SJohn Marino 		first_wanted_type = wanted_type_ptr;
2271e4b17023SJohn Marino 	      last_wanted_type = wanted_type_ptr;
2272e4b17023SJohn Marino 
2273e4b17023SJohn Marino 	      fci = fci->chain;
2274e4b17023SJohn Marino 	      if (fci)
2275e4b17023SJohn Marino 		{
2276e4b17023SJohn Marino                   wanted_type_ptr = (format_wanted_type *)
2277e4b17023SJohn Marino                       pool_alloc (fwt_pool);
2278e4b17023SJohn Marino 		  arg_num++;
2279e4b17023SJohn Marino 		  wanted_type = *fci->types[length_chars_val].type;
2280e4b17023SJohn Marino 		  wanted_type_name = fci->types[length_chars_val].name;
2281e4b17023SJohn Marino 		}
2282e4b17023SJohn Marino 	    }
2283e4b17023SJohn Marino 	}
2284e4b17023SJohn Marino 
2285e4b17023SJohn Marino       if (first_wanted_type != 0)
2286e4b17023SJohn Marino         check_format_types (first_wanted_type);
2287e4b17023SJohn Marino     }
2288e4b17023SJohn Marino 
2289e4b17023SJohn Marino   if (format_chars - orig_format_chars != format_length)
2290e4b17023SJohn Marino     warning (OPT_Wformat_contains_nul, "embedded %<\\0%> in format");
2291e4b17023SJohn Marino   if (info->first_arg_num != 0 && params != 0
2292e4b17023SJohn Marino       && has_operand_number <= 0)
2293e4b17023SJohn Marino     {
2294e4b17023SJohn Marino       res->number_other--;
2295e4b17023SJohn Marino       res->number_extra_args++;
2296e4b17023SJohn Marino     }
2297e4b17023SJohn Marino   if (has_operand_number > 0)
2298e4b17023SJohn Marino     finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK);
2299e4b17023SJohn Marino }
2300e4b17023SJohn Marino 
2301e4b17023SJohn Marino 
2302e4b17023SJohn Marino /* Check the argument types from a single format conversion (possibly
2303e4b17023SJohn Marino    including width and precision arguments).  */
2304e4b17023SJohn Marino static void
check_format_types(format_wanted_type * types)2305e4b17023SJohn Marino check_format_types (format_wanted_type *types)
2306e4b17023SJohn Marino {
2307e4b17023SJohn Marino   for (; types != 0; types = types->next)
2308e4b17023SJohn Marino     {
2309e4b17023SJohn Marino       tree cur_param;
2310e4b17023SJohn Marino       tree cur_type;
2311e4b17023SJohn Marino       tree orig_cur_type;
2312e4b17023SJohn Marino       tree wanted_type;
2313e4b17023SJohn Marino       int arg_num;
2314e4b17023SJohn Marino       int i;
2315e4b17023SJohn Marino       int char_type_flag;
2316e4b17023SJohn Marino 
2317e4b17023SJohn Marino       wanted_type = types->wanted_type;
2318e4b17023SJohn Marino       arg_num = types->arg_num;
2319e4b17023SJohn Marino 
2320e4b17023SJohn Marino       /* The following should not occur here.  */
2321e4b17023SJohn Marino       gcc_assert (wanted_type);
2322e4b17023SJohn Marino       gcc_assert (wanted_type != void_type_node || types->pointer_count);
2323e4b17023SJohn Marino 
2324e4b17023SJohn Marino       if (types->pointer_count == 0)
2325e4b17023SJohn Marino 	wanted_type = lang_hooks.types.type_promotes_to (wanted_type);
2326e4b17023SJohn Marino 
2327e4b17023SJohn Marino       wanted_type = TYPE_MAIN_VARIANT (wanted_type);
2328e4b17023SJohn Marino 
2329e4b17023SJohn Marino       cur_param = types->param;
2330e4b17023SJohn Marino       if (!cur_param)
2331e4b17023SJohn Marino         {
2332e4b17023SJohn Marino           format_type_warning (types, wanted_type, NULL);
2333e4b17023SJohn Marino           continue;
2334e4b17023SJohn Marino         }
2335e4b17023SJohn Marino 
2336e4b17023SJohn Marino       cur_type = TREE_TYPE (cur_param);
2337e4b17023SJohn Marino       if (cur_type == error_mark_node)
2338e4b17023SJohn Marino 	continue;
2339e4b17023SJohn Marino       orig_cur_type = cur_type;
2340e4b17023SJohn Marino       char_type_flag = 0;
2341e4b17023SJohn Marino 
2342e4b17023SJohn Marino       STRIP_NOPS (cur_param);
2343e4b17023SJohn Marino 
2344e4b17023SJohn Marino       /* Check the types of any additional pointer arguments
2345e4b17023SJohn Marino 	 that precede the "real" argument.  */
2346e4b17023SJohn Marino       for (i = 0; i < types->pointer_count; ++i)
2347e4b17023SJohn Marino 	{
2348e4b17023SJohn Marino 	  if (TREE_CODE (cur_type) == POINTER_TYPE)
2349e4b17023SJohn Marino 	    {
2350e4b17023SJohn Marino 	      cur_type = TREE_TYPE (cur_type);
2351e4b17023SJohn Marino 	      if (cur_type == error_mark_node)
2352e4b17023SJohn Marino 		break;
2353e4b17023SJohn Marino 
2354e4b17023SJohn Marino 	      /* Check for writing through a NULL pointer.  */
2355e4b17023SJohn Marino 	      if (types->writing_in_flag
2356e4b17023SJohn Marino 		  && i == 0
2357e4b17023SJohn Marino 		  && cur_param != 0
2358e4b17023SJohn Marino 		  && integer_zerop (cur_param))
2359e4b17023SJohn Marino 		warning (OPT_Wformat, "writing through null pointer "
2360e4b17023SJohn Marino 			 "(argument %d)", arg_num);
2361e4b17023SJohn Marino 
2362e4b17023SJohn Marino 	      /* Check for reading through a NULL pointer.  */
2363e4b17023SJohn Marino 	      if (types->reading_from_flag
2364e4b17023SJohn Marino 		  && i == 0
2365e4b17023SJohn Marino 		  && cur_param != 0
2366e4b17023SJohn Marino 		  && integer_zerop (cur_param))
2367e4b17023SJohn Marino 		warning (OPT_Wformat, "reading through null pointer "
2368e4b17023SJohn Marino 			 "(argument %d)", arg_num);
2369e4b17023SJohn Marino 
2370e4b17023SJohn Marino 	      if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
2371e4b17023SJohn Marino 		cur_param = TREE_OPERAND (cur_param, 0);
2372e4b17023SJohn Marino 	      else
2373e4b17023SJohn Marino 		cur_param = 0;
2374e4b17023SJohn Marino 
2375e4b17023SJohn Marino 	      /* See if this is an attempt to write into a const type with
2376e4b17023SJohn Marino 		 scanf or with printf "%n".  Note: the writing in happens
2377e4b17023SJohn Marino 		 at the first indirection only, if for example
2378e4b17023SJohn Marino 		 void * const * is passed to scanf %p; passing
2379e4b17023SJohn Marino 		 const void ** is simply passing an incompatible type.  */
2380e4b17023SJohn Marino 	      if (types->writing_in_flag
2381e4b17023SJohn Marino 		  && i == 0
2382e4b17023SJohn Marino 		  && (TYPE_READONLY (cur_type)
2383e4b17023SJohn Marino 		      || (cur_param != 0
2384e4b17023SJohn Marino 			  && (CONSTANT_CLASS_P (cur_param)
2385e4b17023SJohn Marino 			      || (DECL_P (cur_param)
2386e4b17023SJohn Marino 				  && TREE_READONLY (cur_param))))))
2387e4b17023SJohn Marino 		warning (OPT_Wformat, "writing into constant object "
2388e4b17023SJohn Marino 			 "(argument %d)", arg_num);
2389e4b17023SJohn Marino 
2390e4b17023SJohn Marino 	      /* If there are extra type qualifiers beyond the first
2391e4b17023SJohn Marino 		 indirection, then this makes the types technically
2392e4b17023SJohn Marino 		 incompatible.  */
2393e4b17023SJohn Marino 	      if (i > 0
2394e4b17023SJohn Marino 		  && pedantic
2395e4b17023SJohn Marino 		  && (TYPE_READONLY (cur_type)
2396e4b17023SJohn Marino 		      || TYPE_VOLATILE (cur_type)
2397e4b17023SJohn Marino 		      || TYPE_RESTRICT (cur_type)))
2398e4b17023SJohn Marino 		warning (OPT_Wformat, "extra type qualifiers in format "
2399e4b17023SJohn Marino 			 "argument (argument %d)",
2400e4b17023SJohn Marino 			 arg_num);
2401e4b17023SJohn Marino 
2402e4b17023SJohn Marino 	    }
2403e4b17023SJohn Marino 	  else
2404e4b17023SJohn Marino 	    {
2405e4b17023SJohn Marino               format_type_warning (types, wanted_type, orig_cur_type);
2406e4b17023SJohn Marino 	      break;
2407e4b17023SJohn Marino 	    }
2408e4b17023SJohn Marino 	}
2409e4b17023SJohn Marino 
2410e4b17023SJohn Marino       if (i < types->pointer_count)
2411e4b17023SJohn Marino 	continue;
2412e4b17023SJohn Marino 
2413e4b17023SJohn Marino       cur_type = TYPE_MAIN_VARIANT (cur_type);
2414e4b17023SJohn Marino 
2415e4b17023SJohn Marino       /* Check whether the argument type is a character type.  This leniency
2416e4b17023SJohn Marino 	 only applies to certain formats, flagged with 'c'.
2417e4b17023SJohn Marino       */
2418e4b17023SJohn Marino       if (types->char_lenient_flag)
2419e4b17023SJohn Marino 	char_type_flag = (cur_type == char_type_node
2420e4b17023SJohn Marino 			  || cur_type == signed_char_type_node
2421e4b17023SJohn Marino 			  || cur_type == unsigned_char_type_node);
2422e4b17023SJohn Marino 
2423e4b17023SJohn Marino       /* Check the type of the "real" argument, if there's a type we want.  */
2424e4b17023SJohn Marino       if (lang_hooks.types_compatible_p (wanted_type, cur_type))
2425e4b17023SJohn Marino 	continue;
2426e4b17023SJohn Marino       /* If we want 'void *', allow any pointer type.
2427e4b17023SJohn Marino 	 (Anything else would already have got a warning.)
2428e4b17023SJohn Marino 	 With -pedantic, only allow pointers to void and to character
2429e4b17023SJohn Marino 	 types.  */
2430e4b17023SJohn Marino       if (wanted_type == void_type_node
2431e4b17023SJohn Marino 	  && (!pedantic || (i == 1 && char_type_flag)))
2432e4b17023SJohn Marino 	continue;
2433e4b17023SJohn Marino       /* Don't warn about differences merely in signedness, unless
2434e4b17023SJohn Marino 	 -pedantic.  With -pedantic, warn if the type is a pointer
2435e4b17023SJohn Marino 	 target and not a character type, and for character types at
2436e4b17023SJohn Marino 	 a second level of indirection.  */
2437e4b17023SJohn Marino       if (TREE_CODE (wanted_type) == INTEGER_TYPE
2438e4b17023SJohn Marino 	  && TREE_CODE (cur_type) == INTEGER_TYPE
2439e4b17023SJohn Marino 	  && (!pedantic || i == 0 || (i == 1 && char_type_flag))
2440e4b17023SJohn Marino 	  && (TYPE_UNSIGNED (wanted_type)
2441e4b17023SJohn Marino 	      ? wanted_type == c_common_unsigned_type (cur_type)
2442e4b17023SJohn Marino 	      : wanted_type == c_common_signed_type (cur_type)))
2443e4b17023SJohn Marino 	continue;
2444e4b17023SJohn Marino       /* Likewise, "signed char", "unsigned char" and "char" are
2445e4b17023SJohn Marino 	 equivalent but the above test won't consider them equivalent.  */
2446e4b17023SJohn Marino       if (wanted_type == char_type_node
2447e4b17023SJohn Marino 	  && (!pedantic || i < 2)
2448e4b17023SJohn Marino 	  && char_type_flag)
2449e4b17023SJohn Marino 	continue;
2450e4b17023SJohn Marino       if (types->scalar_identity_flag
2451e4b17023SJohn Marino 	  && (TREE_CODE (cur_type) == TREE_CODE (wanted_type)
2452e4b17023SJohn Marino 	      || (INTEGRAL_TYPE_P (cur_type)
2453e4b17023SJohn Marino 		  && INTEGRAL_TYPE_P (wanted_type)))
2454e4b17023SJohn Marino 	  && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type))
2455e4b17023SJohn Marino 	continue;
2456e4b17023SJohn Marino       /* Now we have a type mismatch.  */
2457e4b17023SJohn Marino       format_type_warning (types, wanted_type, orig_cur_type);
2458e4b17023SJohn Marino     }
2459e4b17023SJohn Marino }
2460e4b17023SJohn Marino 
2461e4b17023SJohn Marino 
2462e4b17023SJohn Marino /* Give a warning about a format argument of different type from that
2463e4b17023SJohn Marino    expected.  WANTED_TYPE is the type the argument should have, possibly
2464e4b17023SJohn Marino    stripped of pointer dereferences.  The description (such as "field
2465e4b17023SJohn Marino    precision"), the placement in the format string, a possibly more
2466e4b17023SJohn Marino    friendly name of WANTED_TYPE, and the number of pointer dereferences
2467e4b17023SJohn Marino    are taken from TYPE.  ARG_TYPE is the type of the actual argument,
2468e4b17023SJohn Marino    or NULL if it is missing.  */
2469e4b17023SJohn Marino static void
format_type_warning(format_wanted_type * type,tree wanted_type,tree arg_type)2470e4b17023SJohn Marino format_type_warning (format_wanted_type *type, tree wanted_type, tree arg_type)
2471e4b17023SJohn Marino {
2472e4b17023SJohn Marino   int kind = type->kind;
2473e4b17023SJohn Marino   const char *wanted_type_name = type->wanted_type_name;
2474e4b17023SJohn Marino   const char *format_start = type->format_start;
2475e4b17023SJohn Marino   int format_length = type->format_length;
2476e4b17023SJohn Marino   int pointer_count = type->pointer_count;
2477e4b17023SJohn Marino   int arg_num = type->arg_num;
2478e4b17023SJohn Marino 
2479e4b17023SJohn Marino   char *p;
2480e4b17023SJohn Marino   /* If ARG_TYPE is a typedef with a misleading name (for example,
2481e4b17023SJohn Marino      size_t but not the standard size_t expected by printf %zu), avoid
2482e4b17023SJohn Marino      printing the typedef name.  */
2483e4b17023SJohn Marino   if (wanted_type_name
2484e4b17023SJohn Marino       && arg_type
2485e4b17023SJohn Marino       && TYPE_NAME (arg_type)
2486e4b17023SJohn Marino       && TREE_CODE (TYPE_NAME (arg_type)) == TYPE_DECL
2487e4b17023SJohn Marino       && DECL_NAME (TYPE_NAME (arg_type))
2488e4b17023SJohn Marino       && !strcmp (wanted_type_name,
2489e4b17023SJohn Marino 		  lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2)))
2490e4b17023SJohn Marino     arg_type = TYPE_MAIN_VARIANT (arg_type);
2491e4b17023SJohn Marino   /* The format type and name exclude any '*' for pointers, so those
2492e4b17023SJohn Marino      must be formatted manually.  For all the types we currently have,
2493e4b17023SJohn Marino      this is adequate, but formats taking pointers to functions or
2494e4b17023SJohn Marino      arrays would require the full type to be built up in order to
2495e4b17023SJohn Marino      print it with %T.  */
2496e4b17023SJohn Marino   p = (char *) alloca (pointer_count + 2);
2497e4b17023SJohn Marino   if (pointer_count == 0)
2498e4b17023SJohn Marino     p[0] = 0;
2499e4b17023SJohn Marino   else if (c_dialect_cxx ())
2500e4b17023SJohn Marino     {
2501e4b17023SJohn Marino       memset (p, '*', pointer_count);
2502e4b17023SJohn Marino       p[pointer_count] = 0;
2503e4b17023SJohn Marino     }
2504e4b17023SJohn Marino   else
2505e4b17023SJohn Marino     {
2506e4b17023SJohn Marino       p[0] = ' ';
2507e4b17023SJohn Marino       memset (p + 1, '*', pointer_count);
2508e4b17023SJohn Marino       p[pointer_count + 1] = 0;
2509e4b17023SJohn Marino     }
2510e4b17023SJohn Marino 
2511e4b17023SJohn Marino   if (wanted_type_name)
2512e4b17023SJohn Marino     {
2513e4b17023SJohn Marino       if (arg_type)
2514e4b17023SJohn Marino         warning (OPT_Wformat, "%s %<%s%.*s%> expects argument of type %<%s%s%>, "
2515e4b17023SJohn Marino                  "but argument %d has type %qT",
2516e4b17023SJohn Marino                  gettext (kind_descriptions[kind]),
2517e4b17023SJohn Marino                  (kind == CF_KIND_FORMAT ? "%" : ""),
2518e4b17023SJohn Marino                  format_length, format_start,
2519e4b17023SJohn Marino                  wanted_type_name, p, arg_num, arg_type);
2520e4b17023SJohn Marino       else
2521e4b17023SJohn Marino         warning (OPT_Wformat, "%s %<%s%.*s%> expects a matching %<%s%s%> argument",
2522e4b17023SJohn Marino                  gettext (kind_descriptions[kind]),
2523e4b17023SJohn Marino                  (kind == CF_KIND_FORMAT ? "%" : ""),
2524e4b17023SJohn Marino                  format_length, format_start, wanted_type_name, p);
2525e4b17023SJohn Marino     }
2526e4b17023SJohn Marino   else
2527e4b17023SJohn Marino     {
2528e4b17023SJohn Marino       if (arg_type)
2529e4b17023SJohn Marino         warning (OPT_Wformat, "%s %<%s%.*s%> expects argument of type %<%T%s%>, "
2530e4b17023SJohn Marino                  "but argument %d has type %qT",
2531e4b17023SJohn Marino                  gettext (kind_descriptions[kind]),
2532e4b17023SJohn Marino                  (kind == CF_KIND_FORMAT ? "%" : ""),
2533e4b17023SJohn Marino                  format_length, format_start,
2534e4b17023SJohn Marino                  wanted_type, p, arg_num, arg_type);
2535e4b17023SJohn Marino       else
2536e4b17023SJohn Marino         warning (OPT_Wformat, "%s %<%s%.*s%> expects a matching %<%T%s%> argument",
2537e4b17023SJohn Marino                  gettext (kind_descriptions[kind]),
2538e4b17023SJohn Marino                  (kind == CF_KIND_FORMAT ? "%" : ""),
2539e4b17023SJohn Marino                  format_length, format_start, wanted_type, p);
2540e4b17023SJohn Marino     }
2541e4b17023SJohn Marino }
2542e4b17023SJohn Marino 
2543e4b17023SJohn Marino 
2544e4b17023SJohn Marino /* Given a format_char_info array FCI, and a character C, this function
2545e4b17023SJohn Marino    returns the index into the conversion_specs where that specifier's
2546e4b17023SJohn Marino    data is located.  The character must exist.  */
2547e4b17023SJohn Marino static unsigned int
find_char_info_specifier_index(const format_char_info * fci,int c)2548e4b17023SJohn Marino find_char_info_specifier_index (const format_char_info *fci, int c)
2549e4b17023SJohn Marino {
2550e4b17023SJohn Marino   unsigned i;
2551e4b17023SJohn Marino 
2552e4b17023SJohn Marino   for (i = 0; fci->format_chars; i++, fci++)
2553e4b17023SJohn Marino     if (strchr (fci->format_chars, c))
2554e4b17023SJohn Marino       return i;
2555e4b17023SJohn Marino 
2556e4b17023SJohn Marino   /* We shouldn't be looking for a non-existent specifier.  */
2557e4b17023SJohn Marino   gcc_unreachable ();
2558e4b17023SJohn Marino }
2559e4b17023SJohn Marino 
2560e4b17023SJohn Marino /* Given a format_length_info array FLI, and a character C, this
2561e4b17023SJohn Marino    function returns the index into the conversion_specs where that
2562e4b17023SJohn Marino    modifier's data is located.  The character must exist.  */
2563e4b17023SJohn Marino static unsigned int
find_length_info_modifier_index(const format_length_info * fli,int c)2564e4b17023SJohn Marino find_length_info_modifier_index (const format_length_info *fli, int c)
2565e4b17023SJohn Marino {
2566e4b17023SJohn Marino   unsigned i;
2567e4b17023SJohn Marino 
2568e4b17023SJohn Marino   for (i = 0; fli->name; i++, fli++)
2569e4b17023SJohn Marino     if (strchr (fli->name, c))
2570e4b17023SJohn Marino       return i;
2571e4b17023SJohn Marino 
2572e4b17023SJohn Marino   /* We shouldn't be looking for a non-existent modifier.  */
2573e4b17023SJohn Marino   gcc_unreachable ();
2574e4b17023SJohn Marino }
2575e4b17023SJohn Marino 
2576e4b17023SJohn Marino /* Determine the type of HOST_WIDE_INT in the code being compiled for
2577e4b17023SJohn Marino    use in GCC's __asm_fprintf__ custom format attribute.  You must
2578e4b17023SJohn Marino    have set dynamic_format_types before calling this function.  */
2579e4b17023SJohn Marino static void
init_dynamic_asm_fprintf_info(void)2580e4b17023SJohn Marino init_dynamic_asm_fprintf_info (void)
2581e4b17023SJohn Marino {
2582e4b17023SJohn Marino   static tree hwi;
2583e4b17023SJohn Marino 
2584e4b17023SJohn Marino   if (!hwi)
2585e4b17023SJohn Marino     {
2586e4b17023SJohn Marino       format_length_info *new_asm_fprintf_length_specs;
2587e4b17023SJohn Marino       unsigned int i;
2588e4b17023SJohn Marino 
2589e4b17023SJohn Marino       /* Find the underlying type for HOST_WIDE_INT.  For the %w
2590e4b17023SJohn Marino 	 length modifier to work, one must have issued: "typedef
2591e4b17023SJohn Marino 	 HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code
2592e4b17023SJohn Marino 	 prior to using that modifier.  */
2593e4b17023SJohn Marino       hwi = maybe_get_identifier ("__gcc_host_wide_int__");
2594e4b17023SJohn Marino       if (!hwi)
2595e4b17023SJohn Marino 	{
2596e4b17023SJohn Marino 	  error ("%<__gcc_host_wide_int__%> is not defined as a type");
2597e4b17023SJohn Marino 	  return;
2598e4b17023SJohn Marino 	}
2599e4b17023SJohn Marino       hwi = identifier_global_value (hwi);
2600e4b17023SJohn Marino       if (!hwi || TREE_CODE (hwi) != TYPE_DECL)
2601e4b17023SJohn Marino 	{
2602e4b17023SJohn Marino 	  error ("%<__gcc_host_wide_int__%> is not defined as a type");
2603e4b17023SJohn Marino 	  return;
2604e4b17023SJohn Marino 	}
2605e4b17023SJohn Marino       hwi = DECL_ORIGINAL_TYPE (hwi);
2606e4b17023SJohn Marino       gcc_assert (hwi);
2607e4b17023SJohn Marino       if (hwi != long_integer_type_node && hwi != long_long_integer_type_node)
2608e4b17023SJohn Marino 	{
2609e4b17023SJohn Marino 	  error ("%<__gcc_host_wide_int__%> is not defined as %<long%>"
2610e4b17023SJohn Marino 		 " or %<long long%>");
2611e4b17023SJohn Marino 	  return;
2612e4b17023SJohn Marino 	}
2613e4b17023SJohn Marino 
2614e4b17023SJohn Marino       /* Create a new (writable) copy of asm_fprintf_length_specs.  */
2615e4b17023SJohn Marino       new_asm_fprintf_length_specs = (format_length_info *)
2616e4b17023SJohn Marino 				     xmemdup (asm_fprintf_length_specs,
2617e4b17023SJohn Marino 					      sizeof (asm_fprintf_length_specs),
2618e4b17023SJohn Marino 					      sizeof (asm_fprintf_length_specs));
2619e4b17023SJohn Marino 
2620e4b17023SJohn Marino       /* HOST_WIDE_INT must be one of 'long' or 'long long'.  */
2621e4b17023SJohn Marino       i = find_length_info_modifier_index (new_asm_fprintf_length_specs, 'w');
2622e4b17023SJohn Marino       if (hwi == long_integer_type_node)
2623e4b17023SJohn Marino 	new_asm_fprintf_length_specs[i].index = FMT_LEN_l;
2624e4b17023SJohn Marino       else if (hwi == long_long_integer_type_node)
2625e4b17023SJohn Marino 	new_asm_fprintf_length_specs[i].index = FMT_LEN_ll;
2626e4b17023SJohn Marino       else
2627e4b17023SJohn Marino 	gcc_unreachable ();
2628e4b17023SJohn Marino 
2629e4b17023SJohn Marino       /* Assign the new data for use.  */
2630e4b17023SJohn Marino       dynamic_format_types[asm_fprintf_format_type].length_char_specs =
2631e4b17023SJohn Marino 	new_asm_fprintf_length_specs;
2632e4b17023SJohn Marino     }
2633e4b17023SJohn Marino }
2634e4b17023SJohn Marino 
2635e4b17023SJohn Marino /* Determine the type of a "locus" in the code being compiled for use
2636e4b17023SJohn Marino    in GCC's __gcc_gfc__ custom format attribute.  You must have set
2637e4b17023SJohn Marino    dynamic_format_types before calling this function.  */
2638e4b17023SJohn Marino static void
init_dynamic_gfc_info(void)2639e4b17023SJohn Marino init_dynamic_gfc_info (void)
2640e4b17023SJohn Marino {
2641e4b17023SJohn Marino   static tree locus;
2642e4b17023SJohn Marino 
2643e4b17023SJohn Marino   if (!locus)
2644e4b17023SJohn Marino     {
2645e4b17023SJohn Marino       static format_char_info *gfc_fci;
2646e4b17023SJohn Marino 
2647e4b17023SJohn Marino       /* For the GCC __gcc_gfc__ custom format specifier to work, one
2648e4b17023SJohn Marino 	 must have declared 'locus' prior to using this attribute.  If
2649e4b17023SJohn Marino 	 we haven't seen this declarations then you shouldn't use the
2650e4b17023SJohn Marino 	 specifier requiring that type.  */
2651e4b17023SJohn Marino       if ((locus = maybe_get_identifier ("locus")))
2652e4b17023SJohn Marino 	{
2653e4b17023SJohn Marino 	  locus = identifier_global_value (locus);
2654e4b17023SJohn Marino 	  if (locus)
2655e4b17023SJohn Marino 	    {
2656e4b17023SJohn Marino 	      if (TREE_CODE (locus) != TYPE_DECL
2657e4b17023SJohn Marino 		  || TREE_TYPE (locus) == error_mark_node)
2658e4b17023SJohn Marino 		{
2659e4b17023SJohn Marino 		  error ("%<locus%> is not defined as a type");
2660e4b17023SJohn Marino 		  locus = 0;
2661e4b17023SJohn Marino 		}
2662e4b17023SJohn Marino 	      else
2663e4b17023SJohn Marino 		locus = TREE_TYPE (locus);
2664e4b17023SJohn Marino 	    }
2665e4b17023SJohn Marino 	}
2666e4b17023SJohn Marino 
2667e4b17023SJohn Marino       /* Assign the new data for use.  */
2668e4b17023SJohn Marino 
2669e4b17023SJohn Marino       /* Handle the __gcc_gfc__ format specifics.  */
2670e4b17023SJohn Marino       if (!gfc_fci)
2671e4b17023SJohn Marino 	dynamic_format_types[gcc_gfc_format_type].conversion_specs =
2672e4b17023SJohn Marino 	  gfc_fci = (format_char_info *)
2673e4b17023SJohn Marino 		     xmemdup (gcc_gfc_char_table,
2674e4b17023SJohn Marino 			      sizeof (gcc_gfc_char_table),
2675e4b17023SJohn Marino 			      sizeof (gcc_gfc_char_table));
2676e4b17023SJohn Marino       if (locus)
2677e4b17023SJohn Marino 	{
2678e4b17023SJohn Marino 	  const unsigned i = find_char_info_specifier_index (gfc_fci, 'L');
2679e4b17023SJohn Marino 	  gfc_fci[i].types[0].type = &locus;
2680e4b17023SJohn Marino 	  gfc_fci[i].pointer_count = 1;
2681e4b17023SJohn Marino 	}
2682e4b17023SJohn Marino     }
2683e4b17023SJohn Marino }
2684e4b17023SJohn Marino 
2685e4b17023SJohn Marino /* Determine the types of "tree" and "location_t" in the code being
2686e4b17023SJohn Marino    compiled for use in GCC's diagnostic custom format attributes.  You
2687e4b17023SJohn Marino    must have set dynamic_format_types before calling this function.  */
2688e4b17023SJohn Marino static void
init_dynamic_diag_info(void)2689e4b17023SJohn Marino init_dynamic_diag_info (void)
2690e4b17023SJohn Marino {
2691e4b17023SJohn Marino   static tree t, loc, hwi;
2692e4b17023SJohn Marino 
2693e4b17023SJohn Marino   if (!loc || !t || !hwi)
2694e4b17023SJohn Marino     {
2695e4b17023SJohn Marino       static format_char_info *diag_fci, *tdiag_fci, *cdiag_fci, *cxxdiag_fci;
2696e4b17023SJohn Marino       static format_length_info *diag_ls;
2697e4b17023SJohn Marino       unsigned int i;
2698e4b17023SJohn Marino 
2699e4b17023SJohn Marino       /* For the GCC-diagnostics custom format specifiers to work, one
2700e4b17023SJohn Marino 	 must have declared 'tree' and/or 'location_t' prior to using
2701e4b17023SJohn Marino 	 those attributes.  If we haven't seen these declarations then
2702e4b17023SJohn Marino 	 you shouldn't use the specifiers requiring these types.
2703e4b17023SJohn Marino 	 However we don't force a hard ICE because we may see only one
2704e4b17023SJohn Marino 	 or the other type.  */
2705e4b17023SJohn Marino       if ((loc = maybe_get_identifier ("location_t")))
2706e4b17023SJohn Marino 	{
2707e4b17023SJohn Marino 	  loc = identifier_global_value (loc);
2708e4b17023SJohn Marino 	  if (loc)
2709e4b17023SJohn Marino 	    {
2710e4b17023SJohn Marino 	      if (TREE_CODE (loc) != TYPE_DECL)
2711e4b17023SJohn Marino 		{
2712e4b17023SJohn Marino 		  error ("%<location_t%> is not defined as a type");
2713e4b17023SJohn Marino 		  loc = 0;
2714e4b17023SJohn Marino 		}
2715e4b17023SJohn Marino 	      else
2716e4b17023SJohn Marino 		loc = TREE_TYPE (loc);
2717e4b17023SJohn Marino 	    }
2718e4b17023SJohn Marino 	}
2719e4b17023SJohn Marino 
2720e4b17023SJohn Marino       /* We need to grab the underlying 'union tree_node' so peek into
2721e4b17023SJohn Marino 	 an extra type level.  */
2722e4b17023SJohn Marino       if ((t = maybe_get_identifier ("tree")))
2723e4b17023SJohn Marino 	{
2724e4b17023SJohn Marino 	  t = identifier_global_value (t);
2725e4b17023SJohn Marino 	  if (t)
2726e4b17023SJohn Marino 	    {
2727e4b17023SJohn Marino 	      if (TREE_CODE (t) != TYPE_DECL)
2728e4b17023SJohn Marino 		{
2729e4b17023SJohn Marino 		  error ("%<tree%> is not defined as a type");
2730e4b17023SJohn Marino 		  t = 0;
2731e4b17023SJohn Marino 		}
2732e4b17023SJohn Marino 	      else if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
2733e4b17023SJohn Marino 		{
2734e4b17023SJohn Marino 		  error ("%<tree%> is not defined as a pointer type");
2735e4b17023SJohn Marino 		  t = 0;
2736e4b17023SJohn Marino 		}
2737e4b17023SJohn Marino 	      else
2738e4b17023SJohn Marino 		t = TREE_TYPE (TREE_TYPE (t));
2739e4b17023SJohn Marino 	    }
2740e4b17023SJohn Marino 	}
2741e4b17023SJohn Marino 
2742e4b17023SJohn Marino       /* Find the underlying type for HOST_WIDE_INT.  For the %w
2743e4b17023SJohn Marino 	 length modifier to work, one must have issued: "typedef
2744e4b17023SJohn Marino 	 HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code
2745e4b17023SJohn Marino 	 prior to using that modifier.  */
2746e4b17023SJohn Marino       if ((hwi = maybe_get_identifier ("__gcc_host_wide_int__")))
2747e4b17023SJohn Marino 	{
2748e4b17023SJohn Marino 	  hwi = identifier_global_value (hwi);
2749e4b17023SJohn Marino 	  if (hwi)
2750e4b17023SJohn Marino 	    {
2751e4b17023SJohn Marino 	      if (TREE_CODE (hwi) != TYPE_DECL)
2752e4b17023SJohn Marino 		{
2753e4b17023SJohn Marino 		  error ("%<__gcc_host_wide_int__%> is not defined as a type");
2754e4b17023SJohn Marino 		  hwi = 0;
2755e4b17023SJohn Marino 		}
2756e4b17023SJohn Marino 	      else
2757e4b17023SJohn Marino 		{
2758e4b17023SJohn Marino 		  hwi = DECL_ORIGINAL_TYPE (hwi);
2759e4b17023SJohn Marino 		  gcc_assert (hwi);
2760e4b17023SJohn Marino 		  if (hwi != long_integer_type_node
2761e4b17023SJohn Marino 		      && hwi != long_long_integer_type_node)
2762e4b17023SJohn Marino 		    {
2763e4b17023SJohn Marino 		      error ("%<__gcc_host_wide_int__%> is not defined"
2764e4b17023SJohn Marino 			     " as %<long%> or %<long long%>");
2765e4b17023SJohn Marino 		      hwi = 0;
2766e4b17023SJohn Marino 		    }
2767e4b17023SJohn Marino 		}
2768e4b17023SJohn Marino 	    }
2769e4b17023SJohn Marino 	}
2770e4b17023SJohn Marino 
2771e4b17023SJohn Marino       /* Assign the new data for use.  */
2772e4b17023SJohn Marino 
2773e4b17023SJohn Marino       /* All the GCC diag formats use the same length specs.  */
2774e4b17023SJohn Marino       if (!diag_ls)
2775e4b17023SJohn Marino 	dynamic_format_types[gcc_diag_format_type].length_char_specs =
2776e4b17023SJohn Marino 	  dynamic_format_types[gcc_tdiag_format_type].length_char_specs =
2777e4b17023SJohn Marino 	  dynamic_format_types[gcc_cdiag_format_type].length_char_specs =
2778e4b17023SJohn Marino 	  dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs =
2779e4b17023SJohn Marino 	  diag_ls = (format_length_info *)
2780e4b17023SJohn Marino 		    xmemdup (gcc_diag_length_specs,
2781e4b17023SJohn Marino 			     sizeof (gcc_diag_length_specs),
2782e4b17023SJohn Marino 			     sizeof (gcc_diag_length_specs));
2783e4b17023SJohn Marino       if (hwi)
2784e4b17023SJohn Marino 	{
2785e4b17023SJohn Marino 	  /* HOST_WIDE_INT must be one of 'long' or 'long long'.  */
2786e4b17023SJohn Marino 	  i = find_length_info_modifier_index (diag_ls, 'w');
2787e4b17023SJohn Marino 	  if (hwi == long_integer_type_node)
2788e4b17023SJohn Marino 	    diag_ls[i].index = FMT_LEN_l;
2789e4b17023SJohn Marino 	  else if (hwi == long_long_integer_type_node)
2790e4b17023SJohn Marino 	    diag_ls[i].index = FMT_LEN_ll;
2791e4b17023SJohn Marino 	  else
2792e4b17023SJohn Marino 	    gcc_unreachable ();
2793e4b17023SJohn Marino 	}
2794e4b17023SJohn Marino 
2795e4b17023SJohn Marino       /* Handle the __gcc_diag__ format specifics.  */
2796e4b17023SJohn Marino       if (!diag_fci)
2797e4b17023SJohn Marino 	dynamic_format_types[gcc_diag_format_type].conversion_specs =
2798e4b17023SJohn Marino 	  diag_fci = (format_char_info *)
2799e4b17023SJohn Marino 		     xmemdup (gcc_diag_char_table,
2800e4b17023SJohn Marino 			      sizeof (gcc_diag_char_table),
2801e4b17023SJohn Marino 			      sizeof (gcc_diag_char_table));
2802e4b17023SJohn Marino       if (t)
2803e4b17023SJohn Marino 	{
2804e4b17023SJohn Marino 	  i = find_char_info_specifier_index (diag_fci, 'K');
2805e4b17023SJohn Marino 	  diag_fci[i].types[0].type = &t;
2806e4b17023SJohn Marino 	  diag_fci[i].pointer_count = 1;
2807e4b17023SJohn Marino 	}
2808e4b17023SJohn Marino 
2809e4b17023SJohn Marino       /* Handle the __gcc_tdiag__ format specifics.  */
2810e4b17023SJohn Marino       if (!tdiag_fci)
2811e4b17023SJohn Marino 	dynamic_format_types[gcc_tdiag_format_type].conversion_specs =
2812e4b17023SJohn Marino 	  tdiag_fci = (format_char_info *)
2813e4b17023SJohn Marino 		      xmemdup (gcc_tdiag_char_table,
2814e4b17023SJohn Marino 			       sizeof (gcc_tdiag_char_table),
2815e4b17023SJohn Marino 			       sizeof (gcc_tdiag_char_table));
2816e4b17023SJohn Marino       if (t)
2817e4b17023SJohn Marino 	{
2818e4b17023SJohn Marino 	  /* All specifiers taking a tree share the same struct.  */
2819e4b17023SJohn Marino 	  i = find_char_info_specifier_index (tdiag_fci, 'D');
2820e4b17023SJohn Marino 	  tdiag_fci[i].types[0].type = &t;
2821e4b17023SJohn Marino 	  tdiag_fci[i].pointer_count = 1;
2822e4b17023SJohn Marino 	  i = find_char_info_specifier_index (tdiag_fci, 'K');
2823e4b17023SJohn Marino 	  tdiag_fci[i].types[0].type = &t;
2824e4b17023SJohn Marino 	  tdiag_fci[i].pointer_count = 1;
2825e4b17023SJohn Marino 	}
2826e4b17023SJohn Marino 
2827e4b17023SJohn Marino       /* Handle the __gcc_cdiag__ format specifics.  */
2828e4b17023SJohn Marino       if (!cdiag_fci)
2829e4b17023SJohn Marino 	dynamic_format_types[gcc_cdiag_format_type].conversion_specs =
2830e4b17023SJohn Marino 	  cdiag_fci = (format_char_info *)
2831e4b17023SJohn Marino 		      xmemdup (gcc_cdiag_char_table,
2832e4b17023SJohn Marino 			       sizeof (gcc_cdiag_char_table),
2833e4b17023SJohn Marino 			       sizeof (gcc_cdiag_char_table));
2834e4b17023SJohn Marino       if (t)
2835e4b17023SJohn Marino 	{
2836e4b17023SJohn Marino 	  /* All specifiers taking a tree share the same struct.  */
2837e4b17023SJohn Marino 	  i = find_char_info_specifier_index (cdiag_fci, 'D');
2838e4b17023SJohn Marino 	  cdiag_fci[i].types[0].type = &t;
2839e4b17023SJohn Marino 	  cdiag_fci[i].pointer_count = 1;
2840e4b17023SJohn Marino 	  i = find_char_info_specifier_index (cdiag_fci, 'K');
2841e4b17023SJohn Marino 	  cdiag_fci[i].types[0].type = &t;
2842e4b17023SJohn Marino 	  cdiag_fci[i].pointer_count = 1;
2843e4b17023SJohn Marino 	}
2844e4b17023SJohn Marino 
2845e4b17023SJohn Marino       /* Handle the __gcc_cxxdiag__ format specifics.  */
2846e4b17023SJohn Marino       if (!cxxdiag_fci)
2847e4b17023SJohn Marino 	dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs =
2848e4b17023SJohn Marino 	  cxxdiag_fci = (format_char_info *)
2849e4b17023SJohn Marino 			xmemdup (gcc_cxxdiag_char_table,
2850e4b17023SJohn Marino 				 sizeof (gcc_cxxdiag_char_table),
2851e4b17023SJohn Marino 				 sizeof (gcc_cxxdiag_char_table));
2852e4b17023SJohn Marino       if (t)
2853e4b17023SJohn Marino 	{
2854e4b17023SJohn Marino 	  /* All specifiers taking a tree share the same struct.  */
2855e4b17023SJohn Marino 	  i = find_char_info_specifier_index (cxxdiag_fci, 'D');
2856e4b17023SJohn Marino 	  cxxdiag_fci[i].types[0].type = &t;
2857e4b17023SJohn Marino 	  cxxdiag_fci[i].pointer_count = 1;
2858e4b17023SJohn Marino 	  i = find_char_info_specifier_index (cxxdiag_fci, 'K');
2859e4b17023SJohn Marino 	  cxxdiag_fci[i].types[0].type = &t;
2860e4b17023SJohn Marino 	  cxxdiag_fci[i].pointer_count = 1;
2861e4b17023SJohn Marino 	}
2862e4b17023SJohn Marino     }
2863e4b17023SJohn Marino }
2864e4b17023SJohn Marino 
2865e4b17023SJohn Marino #ifdef TARGET_FORMAT_TYPES
2866e4b17023SJohn Marino extern const format_kind_info TARGET_FORMAT_TYPES[];
2867e4b17023SJohn Marino #endif
2868e4b17023SJohn Marino 
2869e4b17023SJohn Marino #ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
2870e4b17023SJohn Marino extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
2871e4b17023SJohn Marino #endif
2872e4b17023SJohn Marino #ifdef TARGET_OVERRIDES_FORMAT_INIT
2873e4b17023SJohn Marino   extern void TARGET_OVERRIDES_FORMAT_INIT (void);
2874e4b17023SJohn Marino #endif
2875e4b17023SJohn Marino 
2876e4b17023SJohn Marino /* Attributes such as "printf" are equivalent to those such as
2877e4b17023SJohn Marino    "gnu_printf" unless this is overridden by a target.  */
2878e4b17023SJohn Marino static const target_ovr_attr gnu_target_overrides_format_attributes[] =
2879e4b17023SJohn Marino {
2880e4b17023SJohn Marino   { "gnu_printf",   "printf" },
2881e4b17023SJohn Marino   { "gnu_scanf",    "scanf" },
2882e4b17023SJohn Marino   { "gnu_strftime", "strftime" },
2883e4b17023SJohn Marino   { "gnu_strfmon",  "strfmon" },
2884e4b17023SJohn Marino   { NULL,           NULL }
2885e4b17023SJohn Marino };
2886e4b17023SJohn Marino 
2887e4b17023SJohn Marino /* Translate to unified attribute name. This is used in decode_format_type and
2888e4b17023SJohn Marino    decode_format_attr. In attr_name the user specified argument is passed. It
2889e4b17023SJohn Marino    returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
2890e4b17023SJohn Marino    or the attr_name passed to this function, if there is no matching entry.  */
2891e4b17023SJohn Marino static const char *
convert_format_name_to_system_name(const char * attr_name)2892e4b17023SJohn Marino convert_format_name_to_system_name (const char *attr_name)
2893e4b17023SJohn Marino {
2894e4b17023SJohn Marino   int i;
2895e4b17023SJohn Marino 
2896e4b17023SJohn Marino   if (attr_name == NULL || *attr_name == 0
2897e4b17023SJohn Marino       || strncmp (attr_name, "gcc_", 4) == 0)
2898e4b17023SJohn Marino     return attr_name;
2899e4b17023SJohn Marino #ifdef TARGET_OVERRIDES_FORMAT_INIT
2900e4b17023SJohn Marino   TARGET_OVERRIDES_FORMAT_INIT ();
2901e4b17023SJohn Marino #endif
2902e4b17023SJohn Marino 
2903e4b17023SJohn Marino #ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
2904e4b17023SJohn Marino   /* Check if format attribute is overridden by target.  */
2905e4b17023SJohn Marino   if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
2906e4b17023SJohn Marino       && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
2907e4b17023SJohn Marino     {
2908e4b17023SJohn Marino       for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
2909e4b17023SJohn Marino         {
2910e4b17023SJohn Marino           if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
2911e4b17023SJohn Marino 			   attr_name))
2912e4b17023SJohn Marino             return attr_name;
2913e4b17023SJohn Marino           if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
2914e4b17023SJohn Marino 			   attr_name))
2915e4b17023SJohn Marino             return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
2916e4b17023SJohn Marino         }
2917e4b17023SJohn Marino     }
2918e4b17023SJohn Marino #endif
2919e4b17023SJohn Marino   /* Otherwise default to gnu format.  */
2920e4b17023SJohn Marino   for (i = 0;
2921e4b17023SJohn Marino        gnu_target_overrides_format_attributes[i].named_attr_src != NULL;
2922e4b17023SJohn Marino        ++i)
2923e4b17023SJohn Marino     {
2924e4b17023SJohn Marino       if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
2925e4b17023SJohn Marino 		       attr_name))
2926e4b17023SJohn Marino         return attr_name;
2927e4b17023SJohn Marino       if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
2928e4b17023SJohn Marino 		       attr_name))
2929e4b17023SJohn Marino         return gnu_target_overrides_format_attributes[i].named_attr_src;
2930e4b17023SJohn Marino     }
2931e4b17023SJohn Marino 
2932e4b17023SJohn Marino   return attr_name;
2933e4b17023SJohn Marino }
2934e4b17023SJohn Marino 
2935e4b17023SJohn Marino /* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
2936e4b17023SJohn Marino    counting "name" and "__name__" as the same, false otherwise.  */
2937e4b17023SJohn Marino static bool
cmp_attribs(const char * tattr_name,const char * attr_name)2938e4b17023SJohn Marino cmp_attribs (const char *tattr_name, const char *attr_name)
2939e4b17023SJohn Marino {
2940e4b17023SJohn Marino   int alen = strlen (attr_name);
2941e4b17023SJohn Marino   int slen = (tattr_name ? strlen (tattr_name) : 0);
2942e4b17023SJohn Marino   if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
2943e4b17023SJohn Marino       && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
2944e4b17023SJohn Marino     {
2945e4b17023SJohn Marino       attr_name += 2;
2946e4b17023SJohn Marino       alen -= 4;
2947e4b17023SJohn Marino     }
2948e4b17023SJohn Marino   if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
2949e4b17023SJohn Marino     return false;
2950e4b17023SJohn Marino   return true;
2951e4b17023SJohn Marino }
2952e4b17023SJohn Marino 
2953e4b17023SJohn Marino /* Handle a "format" attribute; arguments as in
2954e4b17023SJohn Marino    struct attribute_spec.handler.  */
2955e4b17023SJohn Marino tree
handle_format_attribute(tree * node,tree ARG_UNUSED (name),tree args,int flags,bool * no_add_attrs)2956e4b17023SJohn Marino handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
2957e4b17023SJohn Marino 			 int flags, bool *no_add_attrs)
2958e4b17023SJohn Marino {
2959e4b17023SJohn Marino   tree type = *node;
2960e4b17023SJohn Marino   function_format_info info;
2961e4b17023SJohn Marino 
2962e4b17023SJohn Marino #ifdef TARGET_FORMAT_TYPES
2963e4b17023SJohn Marino   /* If the target provides additional format types, we need to
2964e4b17023SJohn Marino      add them to FORMAT_TYPES at first use.  */
2965e4b17023SJohn Marino   if (TARGET_FORMAT_TYPES != NULL && !dynamic_format_types)
2966e4b17023SJohn Marino     {
2967e4b17023SJohn Marino       dynamic_format_types = XNEWVEC (format_kind_info,
2968e4b17023SJohn Marino 				      n_format_types + TARGET_N_FORMAT_TYPES);
2969e4b17023SJohn Marino       memcpy (dynamic_format_types, format_types_orig,
2970e4b17023SJohn Marino 	      sizeof (format_types_orig));
2971e4b17023SJohn Marino       memcpy (&dynamic_format_types[n_format_types], TARGET_FORMAT_TYPES,
2972e4b17023SJohn Marino 	      TARGET_N_FORMAT_TYPES * sizeof (dynamic_format_types[0]));
2973e4b17023SJohn Marino 
2974e4b17023SJohn Marino       format_types = dynamic_format_types;
2975e4b17023SJohn Marino       /* Provide a reference for the first potential external type.  */
2976e4b17023SJohn Marino       first_target_format_type = n_format_types;
2977e4b17023SJohn Marino       n_format_types += TARGET_N_FORMAT_TYPES;
2978e4b17023SJohn Marino     }
2979e4b17023SJohn Marino #endif
2980e4b17023SJohn Marino 
2981e4b17023SJohn Marino   if (!decode_format_attr (args, &info, 0))
2982e4b17023SJohn Marino     {
2983e4b17023SJohn Marino       *no_add_attrs = true;
2984e4b17023SJohn Marino       return NULL_TREE;
2985e4b17023SJohn Marino     }
2986e4b17023SJohn Marino 
2987e4b17023SJohn Marino   if (prototype_p (type))
2988e4b17023SJohn Marino     {
2989e4b17023SJohn Marino       if (!check_format_string (type, info.format_num, flags,
2990e4b17023SJohn Marino 				no_add_attrs, info.format_type))
2991e4b17023SJohn Marino 	return NULL_TREE;
2992e4b17023SJohn Marino 
2993e4b17023SJohn Marino       if (info.first_arg_num != 0)
2994e4b17023SJohn Marino 	{
2995e4b17023SJohn Marino 	  unsigned HOST_WIDE_INT arg_num = 1;
2996e4b17023SJohn Marino 	  function_args_iterator iter;
2997e4b17023SJohn Marino 	  tree arg_type;
2998e4b17023SJohn Marino 
2999e4b17023SJohn Marino 	  /* Verify that first_arg_num points to the last arg,
3000e4b17023SJohn Marino 	     the ...  */
3001e4b17023SJohn Marino 	  FOREACH_FUNCTION_ARGS (type, arg_type, iter)
3002e4b17023SJohn Marino 	    arg_num++;
3003e4b17023SJohn Marino 
3004e4b17023SJohn Marino 	  if (arg_num != info.first_arg_num)
3005e4b17023SJohn Marino 	    {
3006e4b17023SJohn Marino 	      if (!(flags & (int) ATTR_FLAG_BUILT_IN))
3007e4b17023SJohn Marino 		error ("args to be formatted is not %<...%>");
3008e4b17023SJohn Marino 	      *no_add_attrs = true;
3009e4b17023SJohn Marino 	      return NULL_TREE;
3010e4b17023SJohn Marino 	    }
3011e4b17023SJohn Marino 	}
3012e4b17023SJohn Marino     }
3013e4b17023SJohn Marino 
3014e4b17023SJohn Marino   /* Check if this is a strftime variant. Just for this variant
3015e4b17023SJohn Marino      FMT_FLAG_ARG_CONVERT is not set.  */
3016e4b17023SJohn Marino   if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0
3017e4b17023SJohn Marino       && info.first_arg_num != 0)
3018e4b17023SJohn Marino     {
3019e4b17023SJohn Marino       error ("strftime formats cannot format arguments");
3020e4b17023SJohn Marino       *no_add_attrs = true;
3021e4b17023SJohn Marino       return NULL_TREE;
3022e4b17023SJohn Marino     }
3023e4b17023SJohn Marino 
3024e4b17023SJohn Marino   /* If this is a custom GCC-internal format type, we have to
3025e4b17023SJohn Marino      initialize certain bits at runtime.  */
3026e4b17023SJohn Marino   if (info.format_type == asm_fprintf_format_type
3027e4b17023SJohn Marino       || info.format_type == gcc_gfc_format_type
3028e4b17023SJohn Marino       || info.format_type == gcc_diag_format_type
3029e4b17023SJohn Marino       || info.format_type == gcc_tdiag_format_type
3030e4b17023SJohn Marino       || info.format_type == gcc_cdiag_format_type
3031e4b17023SJohn Marino       || info.format_type == gcc_cxxdiag_format_type)
3032e4b17023SJohn Marino     {
3033e4b17023SJohn Marino       /* Our first time through, we have to make sure that our
3034e4b17023SJohn Marino 	 format_type data is allocated dynamically and is modifiable.  */
3035e4b17023SJohn Marino       if (!dynamic_format_types)
3036e4b17023SJohn Marino 	format_types = dynamic_format_types = (format_kind_info *)
3037e4b17023SJohn Marino 	  xmemdup (format_types_orig, sizeof (format_types_orig),
3038e4b17023SJohn Marino 		   sizeof (format_types_orig));
3039e4b17023SJohn Marino 
3040e4b17023SJohn Marino       /* If this is format __asm_fprintf__, we have to initialize
3041e4b17023SJohn Marino 	 GCC's notion of HOST_WIDE_INT for checking %wd.  */
3042e4b17023SJohn Marino       if (info.format_type == asm_fprintf_format_type)
3043e4b17023SJohn Marino 	init_dynamic_asm_fprintf_info ();
3044e4b17023SJohn Marino       /* If this is format __gcc_gfc__, we have to initialize GCC's
3045e4b17023SJohn Marino 	 notion of 'locus' at runtime for %L.  */
3046e4b17023SJohn Marino       else if (info.format_type == gcc_gfc_format_type)
3047e4b17023SJohn Marino 	init_dynamic_gfc_info ();
3048e4b17023SJohn Marino       /* If this is one of the diagnostic attributes, then we have to
3049e4b17023SJohn Marino 	 initialize 'location_t' and 'tree' at runtime.  */
3050e4b17023SJohn Marino       else if (info.format_type == gcc_diag_format_type
3051e4b17023SJohn Marino 	       || info.format_type == gcc_tdiag_format_type
3052e4b17023SJohn Marino 	       || info.format_type == gcc_cdiag_format_type
3053e4b17023SJohn Marino 	       || info.format_type == gcc_cxxdiag_format_type)
3054e4b17023SJohn Marino 	init_dynamic_diag_info ();
3055e4b17023SJohn Marino       else
3056e4b17023SJohn Marino 	gcc_unreachable ();
3057e4b17023SJohn Marino     }
3058e4b17023SJohn Marino 
3059e4b17023SJohn Marino   return NULL_TREE;
3060e4b17023SJohn Marino }
3061