190075Sobrien/* Check calls to formatted I/O functions (-Wformat). 296263Sobrien Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 3169701Skan 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 490075Sobrien 590075SobrienThis file is part of GCC. 690075Sobrien 790075SobrienGCC is free software; you can redistribute it and/or modify it under 890075Sobrienthe terms of the GNU General Public License as published by the Free 990075SobrienSoftware Foundation; either version 2, or (at your option) any later 1090075Sobrienversion. 1190075Sobrien 1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1490075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1590075Sobrienfor more details. 1690075Sobrien 1790075SobrienYou should have received a copy of the GNU General Public License 1890075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 19169701SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 20169701Skan02110-1301, USA. */ 2190075Sobrien 2296558Sobrien/* $FreeBSD$ */ 2396558Sobrien 2490075Sobrien#include "config.h" 2590075Sobrien#include "system.h" 26132731Skan#include "coretypes.h" 27132731Skan#include "tm.h" 2890075Sobrien#include "tree.h" 2990075Sobrien#include "flags.h" 30169701Skan#include "c-common.h" 3190075Sobrien#include "toplev.h" 3290075Sobrien#include "intl.h" 3390075Sobrien#include "diagnostic.h" 34117422Skan#include "langhooks.h" 35169701Skan#include "c-format.h" 3690075Sobrien 3790075Sobrien/* Set format warning options according to a -Wformat=n option. */ 3890075Sobrien 3990075Sobrienvoid 40132731Skanset_Wformat (int setting) 4190075Sobrien{ 4290075Sobrien warn_format = setting; 4390075Sobrien warn_format_extra_args = setting; 44117422Skan warn_format_zero_length = setting; 4590075Sobrien if (setting != 1) 4690075Sobrien { 4790075Sobrien warn_format_nonliteral = setting; 4890075Sobrien warn_format_security = setting; 49132731Skan warn_format_y2k = setting; 5090075Sobrien } 51117422Skan /* Make sure not to disable -Wnonnull if -Wformat=0 is specified. */ 52117422Skan if (setting) 53117422Skan warn_nonnull = setting; 5490075Sobrien} 5590075Sobrien 5690075Sobrien 5790075Sobrien/* Handle attributes associated with format checking. */ 5890075Sobrien 59169701Skan/* This must be in the same order as format_types, except for 60169701Skan format_type_error. Target-specific format types do not have 61169701Skan matching enum values. */ 62132731Skanenum format_type { printf_format_type, asm_fprintf_format_type, 63169701Skan gcc_diag_format_type, gcc_tdiag_format_type, 64169701Skan gcc_cdiag_format_type, 65169701Skan gcc_cxxdiag_format_type, gcc_gfc_format_type, 66132731Skan scanf_format_type, strftime_format_type, 67169701Skan strfmon_format_type, format_type_error = -1}; 6890075Sobrien 6990075Sobrientypedef struct function_format_info 7090075Sobrien{ 71169701Skan int format_type; /* type of format (printf, scanf, etc.) */ 7290075Sobrien unsigned HOST_WIDE_INT format_num; /* number of format argument */ 7390075Sobrien unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */ 7490075Sobrien} function_format_info; 7590075Sobrien 76132731Skanstatic bool decode_format_attr (tree, function_format_info *, int); 77169701Skanstatic int decode_format_type (const char *); 7890075Sobrien 79132731Skanstatic bool check_format_string (tree argument, 80132731Skan unsigned HOST_WIDE_INT format_num, 81132731Skan int flags, bool *no_add_attrs); 82132731Skanstatic bool get_constant (tree expr, unsigned HOST_WIDE_INT *value, 83132731Skan int validated_p); 84132731Skan 85132731Skan 86132731Skan/* Handle a "format_arg" attribute; arguments as in 8790075Sobrien struct attribute_spec.handler. */ 8890075Sobrientree 89169701Skanhandle_format_arg_attribute (tree *node, tree ARG_UNUSED (name), 90132731Skan tree args, int flags, bool *no_add_attrs) 9190075Sobrien{ 9290075Sobrien tree type = *node; 93132731Skan tree format_num_expr = TREE_VALUE (args); 94169701Skan unsigned HOST_WIDE_INT format_num = 0; 9590075Sobrien tree argument; 9690075Sobrien 97132731Skan if (!get_constant (format_num_expr, &format_num, 0)) 9890075Sobrien { 99132731Skan error ("format string has invalid operand number"); 10090075Sobrien *no_add_attrs = true; 10190075Sobrien return NULL_TREE; 10290075Sobrien } 10390075Sobrien 10490075Sobrien argument = TYPE_ARG_TYPES (type); 10590075Sobrien if (argument) 10690075Sobrien { 107132731Skan if (!check_format_string (argument, format_num, flags, no_add_attrs)) 108132731Skan return NULL_TREE; 10990075Sobrien } 11090075Sobrien 111132731Skan if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE 112132731Skan || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))) 113132731Skan != char_type_node)) 11490075Sobrien { 115132731Skan if (!(flags & (int) ATTR_FLAG_BUILT_IN)) 116132731Skan error ("function does not return string type"); 11790075Sobrien *no_add_attrs = true; 11890075Sobrien return NULL_TREE; 11990075Sobrien } 12090075Sobrien 12190075Sobrien return NULL_TREE; 12290075Sobrien} 12390075Sobrien 124132731Skan/* Verify that the format_num argument is actually a string, in case 125132731Skan the format attribute is in error. */ 126132731Skanstatic bool 127132731Skancheck_format_string (tree argument, unsigned HOST_WIDE_INT format_num, 128132731Skan int flags, bool *no_add_attrs) 12990075Sobrien{ 130132731Skan unsigned HOST_WIDE_INT i; 13190075Sobrien 132132731Skan for (i = 1; i != format_num; i++) 133132731Skan { 134132731Skan if (argument == 0) 135132731Skan break; 136132731Skan argument = TREE_CHAIN (argument); 137132731Skan } 13890075Sobrien 139132731Skan if (!argument 140132731Skan || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE 141132731Skan || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) 142132731Skan != char_type_node)) 14390075Sobrien { 144132731Skan if (!(flags & (int) ATTR_FLAG_BUILT_IN)) 145169701Skan error ("format string argument not a string type"); 14690075Sobrien *no_add_attrs = true; 147132731Skan return false; 14890075Sobrien } 14990075Sobrien 150132731Skan return true; 151132731Skan} 15290075Sobrien 153169701Skan/* Verify EXPR is a constant, and store its value. 154169701Skan If validated_p is true there should be no errors. 155132731Skan Returns true on success, false otherwise. */ 156132731Skanstatic bool 157169701Skanget_constant (tree expr, unsigned HOST_WIDE_INT *value, int validated_p) 158132731Skan{ 159132731Skan if (TREE_CODE (expr) != INTEGER_CST || TREE_INT_CST_HIGH (expr) != 0) 16090075Sobrien { 161169701Skan gcc_assert (!validated_p); 162132731Skan return false; 16390075Sobrien } 16490075Sobrien 165132731Skan *value = TREE_INT_CST_LOW (expr); 166132731Skan 167132731Skan return true; 16890075Sobrien} 16990075Sobrien 170169701Skan/* Decode the arguments to a "format" attribute into a 171169701Skan function_format_info structure. It is already known that the list 172169701Skan is of the right length. If VALIDATED_P is true, then these 173169701Skan attributes have already been validated and must not be erroneous; 174169701Skan if false, it will give an error message. Returns true if the 175169701Skan attributes are successfully decoded, false otherwise. */ 17690075Sobrien 17790075Sobrienstatic bool 178132731Skandecode_format_attr (tree args, function_format_info *info, int validated_p) 17990075Sobrien{ 18090075Sobrien tree format_type_id = TREE_VALUE (args); 18190075Sobrien tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); 18290075Sobrien tree first_arg_num_expr 18390075Sobrien = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); 18490075Sobrien 18590075Sobrien if (TREE_CODE (format_type_id) != IDENTIFIER_NODE) 18690075Sobrien { 187169701Skan gcc_assert (!validated_p); 188169701Skan error ("%Junrecognized format specifier", lang_hooks.decls.getdecls ()); 18990075Sobrien return false; 19090075Sobrien } 19190075Sobrien else 19290075Sobrien { 19390075Sobrien const char *p = IDENTIFIER_POINTER (format_type_id); 19490075Sobrien 19590075Sobrien info->format_type = decode_format_type (p); 19690075Sobrien 19790075Sobrien if (info->format_type == format_type_error) 19890075Sobrien { 199169701Skan gcc_assert (!validated_p); 200169701Skan warning (OPT_Wformat, "%qE is an unrecognized format function type", 201169701Skan format_type_id); 20290075Sobrien return false; 20390075Sobrien } 20490075Sobrien } 20590075Sobrien 206132731Skan if (!get_constant (format_num_expr, &info->format_num, validated_p)) 20790075Sobrien { 20890075Sobrien error ("format string has invalid operand number"); 20990075Sobrien return false; 21090075Sobrien } 21190075Sobrien 212132731Skan if (!get_constant (first_arg_num_expr, &info->first_arg_num, validated_p)) 213132731Skan { 214169701Skan error ("%<...%> has invalid operand number"); 215132731Skan return false; 216132731Skan } 217132731Skan 21890075Sobrien if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num) 21990075Sobrien { 220169701Skan gcc_assert (!validated_p); 221169701Skan error ("format string argument follows the args to be formatted"); 22290075Sobrien return false; 22390075Sobrien } 22490075Sobrien 22590075Sobrien return true; 22690075Sobrien} 22790075Sobrien 22890075Sobrien/* Check a call to a format function against a parameter list. */ 22990075Sobrien 23090075Sobrien/* The C standard version C++ is treated as equivalent to 23190075Sobrien or inheriting from, for the purpose of format features supported. */ 23290075Sobrien#define CPLUSPLUS_STD_VER STD_C94 23390075Sobrien/* The C standard version we are checking formats against when pedantic. */ 234169701Skan#define C_STD_VER ((int) (c_dialect_cxx () \ 235169701Skan ? CPLUSPLUS_STD_VER \ 236169701Skan : (flag_isoc99 \ 237169701Skan ? STD_C99 \ 23890075Sobrien : (flag_isoc94 ? STD_C94 : STD_C89)))) 23990075Sobrien/* The name to give to the standard version we are warning about when 24090075Sobrien pedantic. FEATURE_VER is the version in which the feature warned out 24190075Sobrien appeared, which is higher than C_STD_VER. */ 242132731Skan#define C_STD_NAME(FEATURE_VER) (c_dialect_cxx () \ 24390075Sobrien ? "ISO C++" \ 24490075Sobrien : ((FEATURE_VER) == STD_EXT \ 24590075Sobrien ? "ISO C" \ 246117422Skan : "ISO C90")) 24790075Sobrien/* Adjust a C standard version, which may be STD_C9L, to account for 24890075Sobrien -Wno-long-long. Returns other standard versions unchanged. */ 249169701Skan#define ADJ_STD(VER) ((int) ((VER) == STD_C9L \ 25090075Sobrien ? (warn_long_long ? STD_C99 : STD_C89) \ 25190075Sobrien : (VER))) 25290075Sobrien 25390075Sobrien/* Structure describing details of a type expected in format checking, 25490075Sobrien and the type to check against it. */ 25590075Sobrientypedef struct format_wanted_type 25690075Sobrien{ 25790075Sobrien /* The type wanted. */ 25890075Sobrien tree wanted_type; 25990075Sobrien /* The name of this type to use in diagnostics. */ 26090075Sobrien const char *wanted_type_name; 26190075Sobrien /* The level of indirection through pointers at which this type occurs. */ 26290075Sobrien int pointer_count; 26390075Sobrien /* Whether, when pointer_count is 1, to allow any character type when 26490075Sobrien pedantic, rather than just the character or void type specified. */ 26590075Sobrien int char_lenient_flag; 26690075Sobrien /* Whether the argument, dereferenced once, is written into and so the 26790075Sobrien argument must not be a pointer to a const-qualified type. */ 26890075Sobrien int writing_in_flag; 26990075Sobrien /* Whether the argument, dereferenced once, is read from and so 27090075Sobrien must not be a NULL pointer. */ 27190075Sobrien int reading_from_flag; 272169701Skan /* If warnings should be of the form "field precision should have 273169701Skan type 'int'", the name to use (in this case "field precision"), 274169701Skan otherwise NULL, for "format expects type 'long'" type 275169701Skan messages. */ 27690075Sobrien const char *name; 27790075Sobrien /* The actual parameter to check against the wanted type. */ 27890075Sobrien tree param; 27990075Sobrien /* The argument number of that parameter. */ 28090075Sobrien int arg_num; 28190075Sobrien /* The next type to check for this format conversion, or NULL if none. */ 28290075Sobrien struct format_wanted_type *next; 28390075Sobrien} format_wanted_type; 28490075Sobrien 28590075Sobrien 28690075Sobrienstatic const format_length_info printf_length_specs[] = 28790075Sobrien{ 28890075Sobrien { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 }, 28990075Sobrien { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L }, 29090075Sobrien { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 }, 29190075Sobrien { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 }, 29290075Sobrien { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 }, 29390075Sobrien { "Z", FMT_LEN_z, STD_EXT, NULL, 0, 0 }, 29490075Sobrien { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 }, 29590075Sobrien { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 }, 296169701Skan { "H", FMT_LEN_H, STD_EXT, NULL, 0, 0 }, 297169701Skan { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT }, 29890075Sobrien { NULL, 0, 0, NULL, 0, 0 } 29990075Sobrien}; 30090075Sobrien 301132731Skan/* Length specifiers valid for asm_fprintf. */ 302132731Skanstatic const format_length_info asm_fprintf_length_specs[] = 303132731Skan{ 304132731Skan { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 }, 305132731Skan { "w", FMT_LEN_none, STD_C89, NULL, 0, 0 }, 306132731Skan { NULL, 0, 0, NULL, 0, 0 } 307132731Skan}; 30890075Sobrien 309132731Skan/* Length specifiers valid for GCC diagnostics. */ 310132731Skanstatic const format_length_info gcc_diag_length_specs[] = 311132731Skan{ 312132731Skan { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 }, 313132731Skan { "w", FMT_LEN_none, STD_C89, NULL, 0, 0 }, 314132731Skan { NULL, 0, 0, NULL, 0, 0 } 315132731Skan}; 316132731Skan 317132731Skan/* The custom diagnostics all accept the same length specifiers. */ 318169701Skan#define gcc_tdiag_length_specs gcc_diag_length_specs 319132731Skan#define gcc_cdiag_length_specs gcc_diag_length_specs 320132731Skan#define gcc_cxxdiag_length_specs gcc_diag_length_specs 321132731Skan 32290075Sobrien/* This differs from printf_length_specs only in that "Z" is not accepted. */ 32390075Sobrienstatic const format_length_info scanf_length_specs[] = 32490075Sobrien{ 32590075Sobrien { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 }, 32690075Sobrien { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L }, 32790075Sobrien { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 }, 32890075Sobrien { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 }, 32990075Sobrien { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 }, 33090075Sobrien { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 }, 33190075Sobrien { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 }, 332169701Skan { "H", FMT_LEN_H, STD_EXT, NULL, 0, 0 }, 333169701Skan { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT }, 33490075Sobrien { NULL, 0, 0, NULL, 0, 0 } 33590075Sobrien}; 33690075Sobrien 33790075Sobrien 33890075Sobrien/* All tables for strfmon use STD_C89 everywhere, since -pedantic warnings 33990075Sobrien make no sense for a format type not part of any C standard version. */ 34090075Sobrienstatic const format_length_info strfmon_length_specs[] = 34190075Sobrien{ 34290075Sobrien /* A GNU extension. */ 34390075Sobrien { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 }, 34490075Sobrien { NULL, 0, 0, NULL, 0, 0 } 34590075Sobrien}; 34690075Sobrien 34790075Sobrienstatic const format_flag_spec printf_flag_specs[] = 34890075Sobrien{ 349169701Skan { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 }, 350169701Skan { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, 351169701Skan { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, 352169701Skan { '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 }, 353169701Skan { '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 }, 354169701Skan { '\'', 0, 0, N_("''' flag"), N_("the ''' printf flag"), STD_EXT }, 355169701Skan { 'I', 0, 0, N_("'I' flag"), N_("the 'I' printf flag"), STD_EXT }, 35690075Sobrien { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, 35790075Sobrien { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, 35890075Sobrien { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, 35990075Sobrien { 0, 0, 0, NULL, NULL, 0 } 36090075Sobrien}; 36190075Sobrien 36290075Sobrien 36390075Sobrienstatic const format_flag_pair printf_flag_pairs[] = 36490075Sobrien{ 36590075Sobrien { ' ', '+', 1, 0 }, 36690075Sobrien { '0', '-', 1, 0 }, 36790075Sobrien { '0', 'p', 1, 'i' }, 36890075Sobrien { 0, 0, 0, 0 } 36990075Sobrien}; 37090075Sobrien 371132731Skanstatic const format_flag_spec asm_fprintf_flag_specs[] = 372132731Skan{ 373169701Skan { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 }, 374169701Skan { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, 375169701Skan { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, 376169701Skan { '0', 0, 0, N_("'0' flag"), N_("the '0' printf flag"), STD_C89 }, 377169701Skan { '-', 0, 0, N_("'-' flag"), N_("the '-' printf flag"), STD_C89 }, 378132731Skan { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 }, 379132731Skan { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, 380132731Skan { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, 381132731Skan { 0, 0, 0, NULL, NULL, 0 } 382132731Skan}; 38390075Sobrien 384132731Skanstatic const format_flag_pair asm_fprintf_flag_pairs[] = 385132731Skan{ 386132731Skan { ' ', '+', 1, 0 }, 387132731Skan { '0', '-', 1, 0 }, 388132731Skan { '0', 'p', 1, 'i' }, 389132731Skan { 0, 0, 0, 0 } 390132731Skan}; 391132731Skan 392132731Skanstatic const format_flag_pair gcc_diag_flag_pairs[] = 393132731Skan{ 394132731Skan { 0, 0, 0, 0 } 395132731Skan}; 396132731Skan 397169701Skan#define gcc_tdiag_flag_pairs gcc_diag_flag_pairs 398132731Skan#define gcc_cdiag_flag_pairs gcc_diag_flag_pairs 399132731Skan#define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs 400132731Skan 401169701Skanstatic const format_flag_pair gcc_gfc_flag_pairs[] = 402169701Skan{ 403169701Skan { 0, 0, 0, 0 } 404169701Skan}; 405169701Skan 406132731Skanstatic const format_flag_spec gcc_diag_flag_specs[] = 407132731Skan{ 408169701Skan { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, 409169701Skan { 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 }, 410132731Skan { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, 411132731Skan { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, 412132731Skan { 0, 0, 0, NULL, NULL, 0 } 413132731Skan}; 414132731Skan 415169701Skan#define gcc_tdiag_flag_specs gcc_diag_flag_specs 416132731Skan#define gcc_cdiag_flag_specs gcc_diag_flag_specs 417132731Skan 418132731Skanstatic const format_flag_spec gcc_cxxdiag_flag_specs[] = 419132731Skan{ 420169701Skan { '+', 0, 0, N_("'+' flag"), N_("the '+' printf flag"), STD_C89 }, 421169701Skan { '#', 0, 0, N_("'#' flag"), N_("the '#' printf flag"), STD_C89 }, 422169701Skan { 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), STD_C89 }, 423132731Skan { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 }, 424132731Skan { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 }, 425132731Skan { 0, 0, 0, NULL, NULL, 0 } 426132731Skan}; 427132731Skan 42890075Sobrienstatic const format_flag_spec scanf_flag_specs[] = 42990075Sobrien{ 43090075Sobrien { '*', 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 }, 431169701Skan { 'a', 0, 0, N_("'a' flag"), N_("the 'a' scanf flag"), STD_EXT }, 43290075Sobrien { 'w', 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 }, 43390075Sobrien { 'L', 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 }, 434169701Skan { '\'', 0, 0, N_("''' flag"), N_("the ''' scanf flag"), STD_EXT }, 435169701Skan { 'I', 0, 0, N_("'I' flag"), N_("the 'I' scanf flag"), STD_EXT }, 43690075Sobrien { 0, 0, 0, NULL, NULL, 0 } 43790075Sobrien}; 43890075Sobrien 43990075Sobrien 44090075Sobrienstatic const format_flag_pair scanf_flag_pairs[] = 44190075Sobrien{ 44290075Sobrien { '*', 'L', 0, 0 }, 44390075Sobrien { 0, 0, 0, 0 } 44490075Sobrien}; 44590075Sobrien 44690075Sobrien 44790075Sobrienstatic const format_flag_spec strftime_flag_specs[] = 44890075Sobrien{ 449169701Skan { '_', 0, 0, N_("'_' flag"), N_("the '_' strftime flag"), STD_EXT }, 450169701Skan { '-', 0, 0, N_("'-' flag"), N_("the '-' strftime flag"), STD_EXT }, 451169701Skan { '0', 0, 0, N_("'0' flag"), N_("the '0' strftime flag"), STD_EXT }, 452169701Skan { '^', 0, 0, N_("'^' flag"), N_("the '^' strftime flag"), STD_EXT }, 453169701Skan { '#', 0, 0, N_("'#' flag"), N_("the '#' strftime flag"), STD_EXT }, 45490075Sobrien { 'w', 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT }, 455169701Skan { 'E', 0, 0, N_("'E' modifier"), N_("the 'E' strftime modifier"), STD_C99 }, 456169701Skan { 'O', 0, 0, N_("'O' modifier"), N_("the 'O' strftime modifier"), STD_C99 }, 457169701Skan { 'O', 'o', 0, NULL, N_("the 'O' modifier"), STD_EXT }, 45890075Sobrien { 0, 0, 0, NULL, NULL, 0 } 45990075Sobrien}; 46090075Sobrien 46190075Sobrien 46290075Sobrienstatic const format_flag_pair strftime_flag_pairs[] = 46390075Sobrien{ 46490075Sobrien { 'E', 'O', 0, 0 }, 46590075Sobrien { '_', '-', 0, 0 }, 46690075Sobrien { '_', '0', 0, 0 }, 46790075Sobrien { '-', '0', 0, 0 }, 46890075Sobrien { '^', '#', 0, 0 }, 46990075Sobrien { 0, 0, 0, 0 } 47090075Sobrien}; 47190075Sobrien 47290075Sobrien 47390075Sobrienstatic const format_flag_spec strfmon_flag_specs[] = 47490075Sobrien{ 47590075Sobrien { '=', 0, 1, N_("fill character"), N_("fill character in strfmon format"), STD_C89 }, 476169701Skan { '^', 0, 0, N_("'^' flag"), N_("the '^' strfmon flag"), STD_C89 }, 477169701Skan { '+', 0, 0, N_("'+' flag"), N_("the '+' strfmon flag"), STD_C89 }, 478169701Skan { '(', 0, 0, N_("'(' flag"), N_("the '(' strfmon flag"), STD_C89 }, 479169701Skan { '!', 0, 0, N_("'!' flag"), N_("the '!' strfmon flag"), STD_C89 }, 480169701Skan { '-', 0, 0, N_("'-' flag"), N_("the '-' strfmon flag"), STD_C89 }, 48190075Sobrien { 'w', 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 }, 48290075Sobrien { '#', 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 }, 48390075Sobrien { 'p', 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 }, 48490075Sobrien { 'L', 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 }, 48590075Sobrien { 0, 0, 0, NULL, NULL, 0 } 48690075Sobrien}; 48790075Sobrien 48890075Sobrienstatic const format_flag_pair strfmon_flag_pairs[] = 48990075Sobrien{ 49090075Sobrien { '+', '(', 0, 0 }, 49190075Sobrien { 0, 0, 0, 0 } 49290075Sobrien}; 49390075Sobrien 49490075Sobrien 49590075Sobrienstatic const format_char_info print_char_table[] = 49690075Sobrien{ 49790075Sobrien /* C89 conversion specifiers. */ 498169701Skan { "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 }, 499169701Skan { "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 }, 500169701Skan { "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 }, 501169701Skan { "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 }, 502169701Skan { "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 }, 503169701Skan { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, 504169701Skan { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, 505169701Skan { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c", NULL }, 506169701Skan { "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 }, 50790075Sobrien /* C99 conversion specifiers. */ 508169701Skan { "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 }, 509169701Skan { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL }, 51090075Sobrien /* X/Open conversion specifiers. */ 511169701Skan { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, 512169701Skan { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL }, 51390075Sobrien /* GNU conversion specifiers. */ 514169701Skan { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL }, 515169701Skan { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } 516169701Skan}; 517169701Skan 518169701Skanstatic const format_char_info fbsd_ext_char_info = 519169701Skan{ NULL, 1, STD_EXT, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL }; 520169701Skan 521169701Skanstatic const format_char_info fbsd_print_char_table[] = 522169701Skan{ 52397130Sobrien /* BSD conversion specifiers. */ 52497130Sobrien /* FreeBSD kernel extensions (src/sys/kern/subr_prf.c). 52597130Sobrien The format %b is supported to decode error registers. 52697130Sobrien Its usage is: printf("reg=%b\n", regval, "<base><arg>*"); 52797130Sobrien which produces: reg=3<BITTWO,BITONE> 52897130Sobrien The format %D provides a hexdump given a pointer and separator string: 52997130Sobrien ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 53097130Sobrien ("%*D", len, ptr, " ") -> XX XX XX XX ... 53197130Sobrien */ 532169701Skan { "D", 1, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", &fbsd_ext_char_info }, 533169701Skan { "b", 0, STD_EXT, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", &fbsd_ext_char_info }, 534169701Skan { "ry", 0, STD_EXT, { T89_I, BADLEN, BADLEN, T89_L, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "i", NULL }, 53590075Sobrien { NULL, 0, 0, NOLENGTHS, NULL, NULL } 53690075Sobrien}; 53790075Sobrien 538132731Skanstatic const format_char_info asm_fprintf_char_table[] = 539132731Skan{ 540132731Skan /* C89 conversion specifiers. */ 541169701Skan { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +", "i", NULL }, 542169701Skan { "oxX", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL }, 543169701Skan { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0", "i", NULL }, 544169701Skan { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, 545169701Skan { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, 546132731Skan 547132731Skan /* asm_fprintf conversion specifiers. */ 548169701Skan { "O", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 549169701Skan { "R", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 550169701Skan { "I", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 551169701Skan { "L", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 552169701Skan { "U", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 553169701Skan { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, 554169701Skan { "@", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 555169701Skan { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } 556132731Skan}; 557132731Skan 558132731Skanstatic const format_char_info gcc_diag_char_table[] = 559132731Skan{ 560132731Skan /* C89 conversion specifiers. */ 561169701Skan { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 562169701Skan { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 563169701Skan { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 564169701Skan { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 565169701Skan { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, 566169701Skan { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, 567132731Skan 568132731Skan /* Custom conversion specifiers. */ 569132731Skan 570132731Skan /* %H will require "location_t" at runtime. */ 571169701Skan { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 572132731Skan 573132731Skan /* These will require a "tree" at runtime. */ 574169701Skan { "J", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 575132731Skan 576169701Skan { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 577169701Skan { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, 578169701Skan { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } 579132731Skan}; 580132731Skan 581169701Skanstatic const format_char_info gcc_tdiag_char_table[] = 582169701Skan{ 583169701Skan /* C89 conversion specifiers. */ 584169701Skan { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 585169701Skan { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 586169701Skan { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 587169701Skan { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 588169701Skan { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, 589169701Skan { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, 590169701Skan 591169701Skan /* Custom conversion specifiers. */ 592169701Skan 593169701Skan /* %H will require "location_t" at runtime. */ 594169701Skan { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 595169701Skan 596169701Skan /* These will require a "tree" at runtime. */ 597169701Skan { "DFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, 598169701Skan 599169701Skan { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 600169701Skan { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, 601169701Skan { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } 602169701Skan}; 603169701Skan 604132731Skanstatic const format_char_info gcc_cdiag_char_table[] = 605132731Skan{ 606132731Skan /* C89 conversion specifiers. */ 607169701Skan { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 608169701Skan { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 609169701Skan { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 610169701Skan { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 611169701Skan { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, 612169701Skan { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, 613132731Skan 614132731Skan /* Custom conversion specifiers. */ 615132731Skan 616132731Skan /* %H will require "location_t" at runtime. */ 617169701Skan { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 618132731Skan 619132731Skan /* These will require a "tree" at runtime. */ 620169701Skan { "DEFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, 621132731Skan 622169701Skan { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 623169701Skan { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, 624169701Skan { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } 625132731Skan}; 626132731Skan 627132731Skanstatic const format_char_info gcc_cxxdiag_char_table[] = 628132731Skan{ 629132731Skan /* C89 conversion specifiers. */ 630169701Skan { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 631169701Skan { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 632169701Skan { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 633169701Skan { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 634169701Skan { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, 635169701Skan { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, 636132731Skan 637132731Skan /* Custom conversion specifiers. */ 638132731Skan 639132731Skan /* %H will require "location_t" at runtime. */ 640169701Skan { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 641132731Skan 642132731Skan /* These will require a "tree" at runtime. */ 643169701Skan { "ADEFJTV",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL }, 644132731Skan 645169701Skan /* These accept either an 'int' or an 'enum tree_code' (which is handled as an 'int'.) */ 646169701Skan { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, 647132731Skan 648169701Skan { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 649169701Skan { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, 650169701Skan { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } 651132731Skan}; 652132731Skan 653169701Skanstatic const format_char_info gcc_gfc_char_table[] = 654169701Skan{ 655169701Skan /* C89 conversion specifiers. */ 656169701Skan { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, 657169701Skan { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, 658169701Skan { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL }, 659169701Skan 660169701Skan /* gfc conversion specifiers. */ 661169701Skan 662169701Skan { "C", 0, STD_C89, NOARGUMENTS, "", "", NULL }, 663169701Skan 664169701Skan /* This will require a "locus" at runtime. */ 665169701Skan { "L", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "R", NULL }, 666169701Skan 667169701Skan { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } 668169701Skan}; 669169701Skan 67090075Sobrienstatic const format_char_info scan_char_table[] = 67190075Sobrien{ 67290075Sobrien /* C89 conversion specifiers. */ 673169701Skan { "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 }, 674169701Skan { "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 }, 675169701Skan { "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 }, 676169701Skan { "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 }, 677169701Skan { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "cW", NULL }, 678169701Skan { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW", NULL }, 679169701Skan { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW[", NULL }, 680169701Skan { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, 681169701Skan { "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 }, 68290075Sobrien /* C99 conversion specifiers. */ 683169701Skan { "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 }, 684169701Skan { "aA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, 68590075Sobrien /* X/Open conversion specifiers. */ 686169701Skan { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W", NULL }, 687169701Skan { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "W", NULL }, 688169701Skan { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } 68990075Sobrien}; 69090075Sobrien 69190075Sobrienstatic const format_char_info time_char_table[] = 69290075Sobrien{ 69390075Sobrien /* C89 conversion specifiers. */ 694169701Skan { "ABZab", 0, STD_C89, NOLENGTHS, "^#", "", NULL }, 695169701Skan { "cx", 0, STD_C89, NOLENGTHS, "E", "3", NULL }, 696169701Skan { "HIMSUWdmw", 0, STD_C89, NOLENGTHS, "-_0Ow", "", NULL }, 697169701Skan { "j", 0, STD_C89, NOLENGTHS, "-_0Ow", "o", NULL }, 698169701Skan { "p", 0, STD_C89, NOLENGTHS, "#", "", NULL }, 699169701Skan { "X", 0, STD_C89, NOLENGTHS, "E", "", NULL }, 700169701Skan { "y", 0, STD_C89, NOLENGTHS, "EO-_0w", "4", NULL }, 701169701Skan { "Y", 0, STD_C89, NOLENGTHS, "-_0EOw", "o", NULL }, 702169701Skan { "%", 0, STD_C89, NOLENGTHS, "", "", NULL }, 70390075Sobrien /* C99 conversion specifiers. */ 704169701Skan { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o", NULL }, 705169701Skan { "D", 0, STD_C99, NOLENGTHS, "", "2", NULL }, 706169701Skan { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "", NULL }, 707169701Skan { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "", NULL }, 708169701Skan { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o", NULL }, 709169701Skan { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o", NULL }, 710169701Skan { "h", 0, STD_C99, NOLENGTHS, "^#", "", NULL }, 711169701Skan { "z", 0, STD_C99, NOLENGTHS, "O", "o", NULL }, 71290075Sobrien /* GNU conversion specifiers. */ 713169701Skan { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "", NULL }, 714169701Skan { "P", 0, STD_EXT, NOLENGTHS, "", "", NULL }, 715169701Skan { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } 71690075Sobrien}; 71790075Sobrien 71890075Sobrienstatic const format_char_info monetary_char_table[] = 71990075Sobrien{ 720169701Skan { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "", NULL }, 721169701Skan { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } 72290075Sobrien}; 72390075Sobrien 72490075Sobrien/* This must be in the same order as enum format_type. */ 725132731Skanstatic const format_kind_info format_types_orig[] = 72690075Sobrien{ 727169701Skan { "printf", printf_length_specs, print_char_table, " +#0-'I", NULL, 72890075Sobrien printf_flag_specs, printf_flag_pairs, 72990075Sobrien FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK, 73090075Sobrien 'w', 0, 'p', 0, 'L', 731169701Skan &integer_type_node, &integer_type_node 73290075Sobrien }, 733169701Skan { "asm_fprintf", asm_fprintf_length_specs, asm_fprintf_char_table, " +#0-", NULL, 734132731Skan asm_fprintf_flag_specs, asm_fprintf_flag_pairs, 735132731Skan FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK, 736132731Skan 'w', 0, 'p', 0, 'L', 737132731Skan NULL, NULL 738132731Skan }, 739169701Skan { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "q+", NULL, 740132731Skan gcc_diag_flag_specs, gcc_diag_flag_pairs, 741132731Skan FMT_FLAG_ARG_CONVERT, 742132731Skan 0, 0, 'p', 0, 'L', 743132731Skan NULL, &integer_type_node 744132731Skan }, 745169701Skan { "gcc_tdiag", gcc_tdiag_length_specs, gcc_tdiag_char_table, "q+", NULL, 746169701Skan gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs, 747169701Skan FMT_FLAG_ARG_CONVERT, 748169701Skan 0, 0, 'p', 0, 'L', 749169701Skan NULL, &integer_type_node 750169701Skan }, 751169701Skan { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "q+", NULL, 752132731Skan gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs, 753132731Skan FMT_FLAG_ARG_CONVERT, 754132731Skan 0, 0, 'p', 0, 'L', 755132731Skan NULL, &integer_type_node 756132731Skan }, 757169701Skan { "gcc_cxxdiag", gcc_cxxdiag_length_specs, gcc_cxxdiag_char_table, "q+#", NULL, 758132731Skan gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs, 759132731Skan FMT_FLAG_ARG_CONVERT, 760132731Skan 0, 0, 'p', 0, 'L', 761132731Skan NULL, &integer_type_node 762132731Skan }, 763169701Skan { "gcc_gfc", NULL, gcc_gfc_char_table, "", NULL, 764169701Skan NULL, gcc_gfc_flag_pairs, 765169701Skan FMT_FLAG_ARG_CONVERT, 766169701Skan 0, 0, 0, 0, 0, 767169701Skan NULL, NULL 768169701Skan }, 769169701Skan { "scanf", scanf_length_specs, scan_char_table, "*'I", NULL, 77090075Sobrien scanf_flag_specs, scanf_flag_pairs, 77190075Sobrien FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK, 77290075Sobrien 'w', 0, 0, '*', 'L', 773169701Skan NULL, NULL 77490075Sobrien }, 77590075Sobrien { "strftime", NULL, time_char_table, "_-0^#", "EO", 77690075Sobrien strftime_flag_specs, strftime_flag_pairs, 77790075Sobrien FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 778169701Skan NULL, NULL 77990075Sobrien }, 780169701Skan { "strfmon", strfmon_length_specs, monetary_char_table, "=^+(!-", NULL, 78190075Sobrien strfmon_flag_specs, strfmon_flag_pairs, 78290075Sobrien FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 783169701Skan NULL, NULL 78497130Sobrien }, 785169701Skan { "printf0", printf_length_specs, print_char_table, " +#0-'I", NULL, 78697130Sobrien printf_flag_specs, printf_flag_pairs, 787169701Skan FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK|FMT_FLAG_NULL_FORMAT_OK, 788169701Skan 'w', 0, 'p', 0, 'L', 789169701Skan &integer_type_node, &integer_type_node 79090075Sobrien } 79190075Sobrien}; 79290075Sobrien 793132731Skan/* This layer of indirection allows GCC to reassign format_types with 794132731Skan new data if necessary, while still allowing the original data to be 795132731Skan const. */ 796132731Skanstatic const format_kind_info *format_types = format_types_orig; 797169701Skan/* We can modify this one. We also add target-specific format types 798169701Skan to the end of the array. */ 799132731Skanstatic format_kind_info *dynamic_format_types; 80090075Sobrien 801169701Skanstatic int n_format_types = ARRAY_SIZE (format_types_orig); 802169701Skan 80390075Sobrien/* Structure detailing the results of checking a format function call 80490075Sobrien where the format expression may be a conditional expression with 80590075Sobrien many leaves resulting from nested conditional expressions. */ 80690075Sobrientypedef struct 80790075Sobrien{ 80890075Sobrien /* Number of leaves of the format argument that could not be checked 80990075Sobrien as they were not string literals. */ 81090075Sobrien int number_non_literal; 81190075Sobrien /* Number of leaves of the format argument that were null pointers or 81290075Sobrien string literals, but had extra format arguments. */ 81390075Sobrien int number_extra_args; 81490075Sobrien /* Number of leaves of the format argument that were null pointers or 81590075Sobrien string literals, but had extra format arguments and used $ operand 81690075Sobrien numbers. */ 81790075Sobrien int number_dollar_extra_args; 81890075Sobrien /* Number of leaves of the format argument that were wide string 81990075Sobrien literals. */ 82090075Sobrien int number_wide; 82190075Sobrien /* Number of leaves of the format argument that were empty strings. */ 82290075Sobrien int number_empty; 82390075Sobrien /* Number of leaves of the format argument that were unterminated 82490075Sobrien strings. */ 82590075Sobrien int number_unterminated; 82690075Sobrien /* Number of leaves of the format argument that were not counted above. */ 82790075Sobrien int number_other; 82890075Sobrien} format_check_results; 82990075Sobrien 830117422Skantypedef struct 831117422Skan{ 832117422Skan format_check_results *res; 833117422Skan function_format_info *info; 834117422Skan tree params; 835117422Skan} format_check_context; 836117422Skan 837169701Skanstatic void check_format_info (function_format_info *, tree); 838132731Skanstatic void check_format_arg (void *, tree, unsigned HOST_WIDE_INT); 839169701Skanstatic void check_format_info_main (format_check_results *, 840132731Skan function_format_info *, 841132731Skan const char *, int, tree, 842132731Skan unsigned HOST_WIDE_INT); 84390075Sobrien 844132731Skanstatic void init_dollar_format_checking (int, tree); 845169701Skanstatic int maybe_read_dollar_number (const char **, int, 846132731Skan tree, tree *, const format_kind_info *); 847169701Skanstatic bool avoid_dollar_number (const char *); 848169701Skanstatic void finish_dollar_format_checking (format_check_results *, int); 84990075Sobrien 850132731Skanstatic const format_flag_spec *get_flag_spec (const format_flag_spec *, 851132731Skan int, const char *); 85290075Sobrien 853169701Skanstatic void check_format_types (format_wanted_type *, const char *, int); 854169701Skanstatic void format_type_warning (const char *, const char *, int, tree, 855169701Skan int, const char *, tree, int); 85690075Sobrien 85790075Sobrien/* Decode a format type from a string, returning the type, or 85890075Sobrien format_type_error if not valid, in which case the caller should print an 85990075Sobrien error message. */ 860169701Skanstatic int 861132731Skandecode_format_type (const char *s) 86290075Sobrien{ 86390075Sobrien int i; 86490075Sobrien int slen; 86590075Sobrien slen = strlen (s); 866169701Skan for (i = 0; i < n_format_types; i++) 86790075Sobrien { 86890075Sobrien int alen; 86990075Sobrien if (!strcmp (s, format_types[i].name)) 870169701Skan return i; 87190075Sobrien alen = strlen (format_types[i].name); 87290075Sobrien if (slen == alen + 4 && s[0] == '_' && s[1] == '_' 87390075Sobrien && s[slen - 1] == '_' && s[slen - 2] == '_' 87490075Sobrien && !strncmp (s + 2, format_types[i].name, alen)) 875169701Skan return i; 87690075Sobrien } 877169701Skan return format_type_error; 87890075Sobrien} 87990075Sobrien 88090075Sobrien 88190075Sobrien/* Check the argument list of a call to printf, scanf, etc. 88290075Sobrien ATTRS are the attributes on the function type. 88390075Sobrien PARAMS is the list of argument values. Also, if -Wmissing-format-attribute, 88490075Sobrien warn for calls to vprintf or vscanf in functions with no such format 88590075Sobrien attribute themselves. */ 88690075Sobrien 88790075Sobrienvoid 888169701Skancheck_function_format (tree attrs, tree params) 88990075Sobrien{ 89090075Sobrien tree a; 89190075Sobrien 89290075Sobrien /* See if this function has any format attributes. */ 89390075Sobrien for (a = attrs; a; a = TREE_CHAIN (a)) 89490075Sobrien { 89590075Sobrien if (is_attribute_p ("format", TREE_PURPOSE (a))) 89690075Sobrien { 89790075Sobrien /* Yup; check it. */ 89890075Sobrien function_format_info info; 89990075Sobrien decode_format_attr (TREE_VALUE (a), &info, 1); 900169701Skan if (warn_format) 901169701Skan check_format_info (&info, params); 90290075Sobrien if (warn_missing_format_attribute && info.first_arg_num == 0 90390075Sobrien && (format_types[info.format_type].flags 90490075Sobrien & (int) FMT_FLAG_ARG_CONVERT)) 90590075Sobrien { 90690075Sobrien tree c; 90790075Sobrien for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); 90890075Sobrien c; 90990075Sobrien c = TREE_CHAIN (c)) 91090075Sobrien if (is_attribute_p ("format", TREE_PURPOSE (c)) 91190075Sobrien && (decode_format_type (IDENTIFIER_POINTER 91290075Sobrien (TREE_VALUE (TREE_VALUE (c)))) 91390075Sobrien == info.format_type)) 91490075Sobrien break; 91590075Sobrien if (c == NULL_TREE) 91690075Sobrien { 91790075Sobrien /* Check if the current function has a parameter to which 91890075Sobrien the format attribute could be attached; if not, it 91990075Sobrien can't be a candidate for a format attribute, despite 92090075Sobrien the vprintf-like or vscanf-like call. */ 92190075Sobrien tree args; 92290075Sobrien for (args = DECL_ARGUMENTS (current_function_decl); 92390075Sobrien args != 0; 92490075Sobrien args = TREE_CHAIN (args)) 92590075Sobrien { 92690075Sobrien if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE 92790075Sobrien && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args))) 92890075Sobrien == char_type_node)) 92990075Sobrien break; 93090075Sobrien } 93190075Sobrien if (args != 0) 932169701Skan warning (OPT_Wmissing_format_attribute, "function might " 933169701Skan "be possible candidate for %qs format attribute", 93490075Sobrien format_types[info.format_type].name); 93590075Sobrien } 93690075Sobrien } 93790075Sobrien } 93890075Sobrien } 93990075Sobrien} 94090075Sobrien 94190075Sobrien 94290075Sobrien/* Variables used by the checking of $ operand number formats. */ 94390075Sobrienstatic char *dollar_arguments_used = NULL; 94490075Sobrienstatic char *dollar_arguments_pointer_p = NULL; 94590075Sobrienstatic int dollar_arguments_alloc = 0; 94690075Sobrienstatic int dollar_arguments_count; 94790075Sobrienstatic int dollar_first_arg_num; 94890075Sobrienstatic int dollar_max_arg_used; 94990075Sobrienstatic int dollar_format_warned; 95090075Sobrien 95190075Sobrien/* Initialize the checking for a format string that may contain $ 95290075Sobrien parameter number specifications; we will need to keep track of whether 95390075Sobrien each parameter has been used. FIRST_ARG_NUM is the number of the first 95490075Sobrien argument that is a parameter to the format, or 0 for a vprintf-style 95590075Sobrien function; PARAMS is the list of arguments starting at this argument. */ 95690075Sobrien 95790075Sobrienstatic void 958132731Skaninit_dollar_format_checking (int first_arg_num, tree params) 95990075Sobrien{ 96090075Sobrien tree oparams = params; 96190075Sobrien 96290075Sobrien dollar_first_arg_num = first_arg_num; 96390075Sobrien dollar_arguments_count = 0; 96490075Sobrien dollar_max_arg_used = 0; 96590075Sobrien dollar_format_warned = 0; 96690075Sobrien if (first_arg_num > 0) 96790075Sobrien { 96890075Sobrien while (params) 96990075Sobrien { 97090075Sobrien dollar_arguments_count++; 97190075Sobrien params = TREE_CHAIN (params); 97290075Sobrien } 97390075Sobrien } 97490075Sobrien if (dollar_arguments_alloc < dollar_arguments_count) 97590075Sobrien { 97690075Sobrien if (dollar_arguments_used) 97790075Sobrien free (dollar_arguments_used); 97890075Sobrien if (dollar_arguments_pointer_p) 97990075Sobrien free (dollar_arguments_pointer_p); 98090075Sobrien dollar_arguments_alloc = dollar_arguments_count; 981169701Skan dollar_arguments_used = XNEWVEC (char, dollar_arguments_alloc); 982169701Skan dollar_arguments_pointer_p = XNEWVEC (char, dollar_arguments_alloc); 98390075Sobrien } 98490075Sobrien if (dollar_arguments_alloc) 98590075Sobrien { 98690075Sobrien memset (dollar_arguments_used, 0, dollar_arguments_alloc); 98790075Sobrien if (first_arg_num > 0) 98890075Sobrien { 98990075Sobrien int i = 0; 99090075Sobrien params = oparams; 99190075Sobrien while (params) 99290075Sobrien { 99390075Sobrien dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params))) 99490075Sobrien == POINTER_TYPE); 99590075Sobrien params = TREE_CHAIN (params); 99690075Sobrien i++; 99790075Sobrien } 99890075Sobrien } 99990075Sobrien } 100090075Sobrien} 100190075Sobrien 100290075Sobrien 100390075Sobrien/* Look for a decimal number followed by a $ in *FORMAT. If DOLLAR_NEEDED 100490075Sobrien is set, it is an error if one is not found; otherwise, it is OK. If 100590075Sobrien such a number is found, check whether it is within range and mark that 100690075Sobrien numbered operand as being used for later checking. Returns the operand 100790075Sobrien number if found and within range, zero if no such number was found and 100890075Sobrien this is OK, or -1 on error. PARAMS points to the first operand of the 100990075Sobrien format; PARAM_PTR is made to point to the parameter referred to. If 101090075Sobrien a $ format is found, *FORMAT is updated to point just after it. */ 101190075Sobrien 101290075Sobrienstatic int 1013169701Skanmaybe_read_dollar_number (const char **format, 1014132731Skan int dollar_needed, tree params, tree *param_ptr, 1015132731Skan const format_kind_info *fki) 101690075Sobrien{ 101790075Sobrien int argnum; 101890075Sobrien int overflow_flag; 101990075Sobrien const char *fcp = *format; 1020169701Skan if (!ISDIGIT (*fcp)) 102190075Sobrien { 102290075Sobrien if (dollar_needed) 102390075Sobrien { 1024169701Skan warning (OPT_Wformat, "missing $ operand number in format"); 102590075Sobrien return -1; 102690075Sobrien } 102790075Sobrien else 102890075Sobrien return 0; 102990075Sobrien } 103090075Sobrien argnum = 0; 103190075Sobrien overflow_flag = 0; 103290075Sobrien while (ISDIGIT (*fcp)) 103390075Sobrien { 103490075Sobrien int nargnum; 103590075Sobrien nargnum = 10 * argnum + (*fcp - '0'); 103690075Sobrien if (nargnum < 0 || nargnum / 10 != argnum) 103790075Sobrien overflow_flag = 1; 103890075Sobrien argnum = nargnum; 103990075Sobrien fcp++; 104090075Sobrien } 104190075Sobrien if (*fcp != '$') 104290075Sobrien { 104390075Sobrien if (dollar_needed) 104490075Sobrien { 1045169701Skan warning (OPT_Wformat, "missing $ operand number in format"); 104690075Sobrien return -1; 104790075Sobrien } 104890075Sobrien else 104990075Sobrien return 0; 105090075Sobrien } 105190075Sobrien *format = fcp + 1; 105290075Sobrien if (pedantic && !dollar_format_warned) 105390075Sobrien { 1054169701Skan warning (OPT_Wformat, "%s does not support %%n$ operand number formats", 1055169701Skan C_STD_NAME (STD_EXT)); 105690075Sobrien dollar_format_warned = 1; 105790075Sobrien } 105890075Sobrien if (overflow_flag || argnum == 0 105990075Sobrien || (dollar_first_arg_num && argnum > dollar_arguments_count)) 106090075Sobrien { 1061169701Skan warning (OPT_Wformat, "operand number out of range in format"); 106290075Sobrien return -1; 106390075Sobrien } 106490075Sobrien if (argnum > dollar_max_arg_used) 106590075Sobrien dollar_max_arg_used = argnum; 106690075Sobrien /* For vprintf-style functions we may need to allocate more memory to 106790075Sobrien track which arguments are used. */ 106890075Sobrien while (dollar_arguments_alloc < dollar_max_arg_used) 106990075Sobrien { 107090075Sobrien int nalloc; 107190075Sobrien nalloc = 2 * dollar_arguments_alloc + 16; 1072169701Skan dollar_arguments_used = XRESIZEVEC (char, dollar_arguments_used, 1073169701Skan nalloc); 1074169701Skan dollar_arguments_pointer_p = XRESIZEVEC (char, dollar_arguments_pointer_p, 1075169701Skan nalloc); 107690075Sobrien memset (dollar_arguments_used + dollar_arguments_alloc, 0, 107790075Sobrien nalloc - dollar_arguments_alloc); 107890075Sobrien dollar_arguments_alloc = nalloc; 107990075Sobrien } 108090075Sobrien if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE) 108190075Sobrien && dollar_arguments_used[argnum - 1] == 1) 108290075Sobrien { 108390075Sobrien dollar_arguments_used[argnum - 1] = 2; 1084169701Skan warning (OPT_Wformat, "format argument %d used more than once in %s format", 1085169701Skan argnum, fki->name); 108690075Sobrien } 108790075Sobrien else 108890075Sobrien dollar_arguments_used[argnum - 1] = 1; 108990075Sobrien if (dollar_first_arg_num) 109090075Sobrien { 109190075Sobrien int i; 109290075Sobrien *param_ptr = params; 109390075Sobrien for (i = 1; i < argnum && *param_ptr != 0; i++) 109490075Sobrien *param_ptr = TREE_CHAIN (*param_ptr); 109590075Sobrien 1096169701Skan /* This case shouldn't be caught here. */ 1097169701Skan gcc_assert (*param_ptr); 109890075Sobrien } 109990075Sobrien else 110090075Sobrien *param_ptr = 0; 110190075Sobrien return argnum; 110290075Sobrien} 110390075Sobrien 1104169701Skan/* Ensure that FORMAT does not start with a decimal number followed by 1105169701Skan a $; give a diagnostic and return true if it does, false otherwise. */ 110690075Sobrien 1107169701Skanstatic bool 1108169701Skanavoid_dollar_number (const char *format) 1109169701Skan{ 1110169701Skan if (!ISDIGIT (*format)) 1111169701Skan return false; 1112169701Skan while (ISDIGIT (*format)) 1113169701Skan format++; 1114169701Skan if (*format == '$') 1115169701Skan { 1116169701Skan warning (OPT_Wformat, "$ operand number used after format without operand number"); 1117169701Skan return true; 1118169701Skan } 1119169701Skan return false; 1120169701Skan} 1121169701Skan 1122169701Skan 112390075Sobrien/* Finish the checking for a format string that used $ operand number formats 112490075Sobrien instead of non-$ formats. We check for unused operands before used ones 112590075Sobrien (a serious error, since the implementation of the format function 112690075Sobrien can't know what types to pass to va_arg to find the later arguments). 112790075Sobrien and for unused operands at the end of the format (if we know how many 112890075Sobrien arguments the format had, so not for vprintf). If there were operand 112990075Sobrien numbers out of range on a non-vprintf-style format, we won't have reached 113090075Sobrien here. If POINTER_GAP_OK, unused arguments are OK if all arguments are 113190075Sobrien pointers. */ 113290075Sobrien 113390075Sobrienstatic void 1134169701Skanfinish_dollar_format_checking (format_check_results *res, int pointer_gap_ok) 113590075Sobrien{ 113690075Sobrien int i; 113790075Sobrien bool found_pointer_gap = false; 113890075Sobrien for (i = 0; i < dollar_max_arg_used; i++) 113990075Sobrien { 114090075Sobrien if (!dollar_arguments_used[i]) 114190075Sobrien { 114290075Sobrien if (pointer_gap_ok && (dollar_first_arg_num == 0 114390075Sobrien || dollar_arguments_pointer_p[i])) 114490075Sobrien found_pointer_gap = true; 114590075Sobrien else 1146169701Skan warning (OPT_Wformat, 1147169701Skan "format argument %d unused before used argument %d in $-style format", 1148169701Skan i + 1, dollar_max_arg_used); 114990075Sobrien } 115090075Sobrien } 115190075Sobrien if (found_pointer_gap 115290075Sobrien || (dollar_first_arg_num 115390075Sobrien && dollar_max_arg_used < dollar_arguments_count)) 115490075Sobrien { 115590075Sobrien res->number_other--; 115690075Sobrien res->number_dollar_extra_args++; 115790075Sobrien } 115890075Sobrien} 115990075Sobrien 116090075Sobrien 116190075Sobrien/* Retrieve the specification for a format flag. SPEC contains the 116290075Sobrien specifications for format flags for the applicable kind of format. 116390075Sobrien FLAG is the flag in question. If PREDICATES is NULL, the basic 1164169701Skan spec for that flag must be retrieved and must exist. If 1165169701Skan PREDICATES is not NULL, it is a string listing possible predicates 1166169701Skan for the spec entry; if an entry predicated on any of these is 1167169701Skan found, it is returned, otherwise NULL is returned. */ 116890075Sobrien 116990075Sobrienstatic const format_flag_spec * 1170132731Skanget_flag_spec (const format_flag_spec *spec, int flag, const char *predicates) 117190075Sobrien{ 117290075Sobrien int i; 117390075Sobrien for (i = 0; spec[i].flag_char != 0; i++) 117490075Sobrien { 117590075Sobrien if (spec[i].flag_char != flag) 117690075Sobrien continue; 117790075Sobrien if (predicates != NULL) 117890075Sobrien { 117990075Sobrien if (spec[i].predicate != 0 118090075Sobrien && strchr (predicates, spec[i].predicate) != 0) 118190075Sobrien return &spec[i]; 118290075Sobrien } 118390075Sobrien else if (spec[i].predicate == 0) 118490075Sobrien return &spec[i]; 118590075Sobrien } 1186169701Skan gcc_assert (predicates); 1187169701Skan return NULL; 118890075Sobrien} 118990075Sobrien 119090075Sobrien 119190075Sobrien/* Check the argument list of a call to printf, scanf, etc. 119290075Sobrien INFO points to the function_format_info structure. 119390075Sobrien PARAMS is the list of argument values. */ 119490075Sobrien 119590075Sobrienstatic void 1196169701Skancheck_format_info (function_format_info *info, tree params) 119790075Sobrien{ 1198117422Skan format_check_context format_ctx; 119990075Sobrien unsigned HOST_WIDE_INT arg_num; 120090075Sobrien tree format_tree; 120190075Sobrien format_check_results res; 120290075Sobrien /* Skip to format argument. If the argument isn't available, there's 120390075Sobrien no work for us to do; prototype checking will catch the problem. */ 120490075Sobrien for (arg_num = 1; ; ++arg_num) 120590075Sobrien { 120690075Sobrien if (params == 0) 120790075Sobrien return; 120890075Sobrien if (arg_num == info->format_num) 120990075Sobrien break; 121090075Sobrien params = TREE_CHAIN (params); 121190075Sobrien } 121290075Sobrien format_tree = TREE_VALUE (params); 121390075Sobrien params = TREE_CHAIN (params); 121490075Sobrien if (format_tree == 0) 121590075Sobrien return; 121690075Sobrien 121790075Sobrien res.number_non_literal = 0; 121890075Sobrien res.number_extra_args = 0; 121990075Sobrien res.number_dollar_extra_args = 0; 122090075Sobrien res.number_wide = 0; 122190075Sobrien res.number_empty = 0; 122290075Sobrien res.number_unterminated = 0; 122390075Sobrien res.number_other = 0; 122490075Sobrien 1225117422Skan format_ctx.res = &res; 1226117422Skan format_ctx.info = info; 1227117422Skan format_ctx.params = params; 122890075Sobrien 1229117422Skan check_function_arguments_recurse (check_format_arg, &format_ctx, 1230117422Skan format_tree, arg_num); 1231117422Skan 123290075Sobrien if (res.number_non_literal > 0) 123390075Sobrien { 123490075Sobrien /* Functions taking a va_list normally pass a non-literal format 123590075Sobrien string. These functions typically are declared with 123690075Sobrien first_arg_num == 0, so avoid warning in those cases. */ 123790075Sobrien if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT)) 123890075Sobrien { 123990075Sobrien /* For strftime-like formats, warn for not checking the format 124090075Sobrien string; but there are no arguments to check. */ 1241169701Skan warning (OPT_Wformat_nonliteral, 1242169701Skan "format not a string literal, format string not checked"); 124390075Sobrien } 124490075Sobrien else if (info->first_arg_num != 0) 124590075Sobrien { 124690075Sobrien /* If there are no arguments for the format at all, we may have 124790075Sobrien printf (foo) which is likely to be a security hole. */ 124890075Sobrien while (arg_num + 1 < info->first_arg_num) 124990075Sobrien { 125090075Sobrien if (params == 0) 125190075Sobrien break; 125290075Sobrien params = TREE_CHAIN (params); 125390075Sobrien ++arg_num; 125490075Sobrien } 1255169701Skan if (params == 0 && warn_format_security) 1256169701Skan warning (OPT_Wformat_security, 1257169701Skan "format not a string literal and no format arguments"); 1258169701Skan else if (params == 0 && warn_format_nonliteral) 1259169701Skan warning (OPT_Wformat_nonliteral, 1260169701Skan "format not a string literal and no format arguments"); 1261169701Skan else 1262169701Skan warning (OPT_Wformat_nonliteral, 1263169701Skan "format not a string literal, argument types not checked"); 126490075Sobrien } 126590075Sobrien } 126690075Sobrien 126790075Sobrien /* If there were extra arguments to the format, normally warn. However, 126890075Sobrien the standard does say extra arguments are ignored, so in the specific 126990075Sobrien case where we have multiple leaves (conditional expressions or 127090075Sobrien ngettext) allow extra arguments if at least one leaf didn't have extra 127190075Sobrien arguments, but was otherwise OK (either non-literal or checked OK). 127290075Sobrien If the format is an empty string, this should be counted similarly to the 127390075Sobrien case of extra format arguments. */ 127490075Sobrien if (res.number_extra_args > 0 && res.number_non_literal == 0 1275169701Skan && res.number_other == 0) 1276169701Skan warning (OPT_Wformat_extra_args, "too many arguments for format"); 127790075Sobrien if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0 1278169701Skan && res.number_other == 0) 1279169701Skan warning (OPT_Wformat_extra_args, "unused arguments in $-style format"); 128090075Sobrien if (res.number_empty > 0 && res.number_non_literal == 0 1281169701Skan && res.number_other == 0) 1282169701Skan warning (OPT_Wformat_zero_length, "zero-length %s format string", 1283169701Skan format_types[info->format_type].name); 128490075Sobrien 128590075Sobrien if (res.number_wide > 0) 1286169701Skan warning (OPT_Wformat, "format is a wide character string"); 128790075Sobrien 128890075Sobrien if (res.number_unterminated > 0) 1289169701Skan warning (OPT_Wformat, "unterminated format string"); 129090075Sobrien} 129190075Sobrien 1292117422Skan/* Callback from check_function_arguments_recurse to check a 1293117422Skan format string. FORMAT_TREE is the format parameter. ARG_NUM 1294117422Skan is the number of the format argument. CTX points to a 1295117422Skan format_check_context. */ 129690075Sobrien 129790075Sobrienstatic void 1298132731Skancheck_format_arg (void *ctx, tree format_tree, 1299132731Skan unsigned HOST_WIDE_INT arg_num) 130090075Sobrien{ 1301169701Skan format_check_context *format_ctx = (format_check_context *) ctx; 1302117422Skan format_check_results *res = format_ctx->res; 1303117422Skan function_format_info *info = format_ctx->info; 1304117422Skan tree params = format_ctx->params; 1305117422Skan 130690075Sobrien int format_length; 130790075Sobrien HOST_WIDE_INT offset; 130890075Sobrien const char *format_chars; 130990075Sobrien tree array_size = 0; 131090075Sobrien tree array_init; 131190075Sobrien 131290075Sobrien if (integer_zerop (format_tree)) 131390075Sobrien { 131490075Sobrien /* FIXME: this warning should go away once Marc Espie's 131590075Sobrien __attribute__((nonnull)) patch is in. Instead, checking for 131690075Sobrien nonnull attributes should probably change this function to act 131790075Sobrien specially if info == NULL and add a res->number_null entry for 131890075Sobrien that case, or maybe add a function pointer to be called at 131990075Sobrien the end instead of hardcoding check_format_info_main. */ 1320169701Skan if (!(format_types[info->format_type].flags & FMT_FLAG_NULL_FORMAT_OK)) 1321169701Skan warning (OPT_Wformat, "null format string"); 132290075Sobrien 132390075Sobrien /* Skip to first argument to check, so we can see if this format 132490075Sobrien has any arguments (it shouldn't). */ 132590075Sobrien while (arg_num + 1 < info->first_arg_num) 132690075Sobrien { 132790075Sobrien if (params == 0) 132890075Sobrien return; 132990075Sobrien params = TREE_CHAIN (params); 133090075Sobrien ++arg_num; 133190075Sobrien } 133290075Sobrien 133390075Sobrien if (params == 0) 133490075Sobrien res->number_other++; 133590075Sobrien else 133690075Sobrien res->number_extra_args++; 133790075Sobrien 133890075Sobrien return; 133990075Sobrien } 134090075Sobrien 134190075Sobrien offset = 0; 134290075Sobrien if (TREE_CODE (format_tree) == PLUS_EXPR) 134390075Sobrien { 134490075Sobrien tree arg0, arg1; 134590075Sobrien 134690075Sobrien arg0 = TREE_OPERAND (format_tree, 0); 134790075Sobrien arg1 = TREE_OPERAND (format_tree, 1); 134890075Sobrien STRIP_NOPS (arg0); 134990075Sobrien STRIP_NOPS (arg1); 135090075Sobrien if (TREE_CODE (arg1) == INTEGER_CST) 135190075Sobrien format_tree = arg0; 135290075Sobrien else if (TREE_CODE (arg0) == INTEGER_CST) 135390075Sobrien { 135490075Sobrien format_tree = arg1; 135590075Sobrien arg1 = arg0; 135690075Sobrien } 135790075Sobrien else 135890075Sobrien { 135990075Sobrien res->number_non_literal++; 136090075Sobrien return; 136190075Sobrien } 136296263Sobrien if (!host_integerp (arg1, 0) 136396263Sobrien || (offset = tree_low_cst (arg1, 0)) < 0) 136490075Sobrien { 136590075Sobrien res->number_non_literal++; 136690075Sobrien return; 136790075Sobrien } 136890075Sobrien } 136990075Sobrien if (TREE_CODE (format_tree) != ADDR_EXPR) 137090075Sobrien { 137190075Sobrien res->number_non_literal++; 137290075Sobrien return; 137390075Sobrien } 137490075Sobrien format_tree = TREE_OPERAND (format_tree, 0); 1375169701Skan if (TREE_CODE (format_tree) == ARRAY_REF 1376169701Skan && host_integerp (TREE_OPERAND (format_tree, 1), 0) 1377169701Skan && (offset += tree_low_cst (TREE_OPERAND (format_tree, 1), 0)) >= 0) 1378169701Skan format_tree = TREE_OPERAND (format_tree, 0); 137990075Sobrien if (TREE_CODE (format_tree) == VAR_DECL 138090075Sobrien && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE 138190075Sobrien && (array_init = decl_constant_value (format_tree)) != format_tree 138290075Sobrien && TREE_CODE (array_init) == STRING_CST) 138390075Sobrien { 138490075Sobrien /* Extract the string constant initializer. Note that this may include 138590075Sobrien a trailing NUL character that is not in the array (e.g. 138690075Sobrien const char a[3] = "foo";). */ 138790075Sobrien array_size = DECL_SIZE_UNIT (format_tree); 138890075Sobrien format_tree = array_init; 138990075Sobrien } 139090075Sobrien if (TREE_CODE (format_tree) != STRING_CST) 139190075Sobrien { 139290075Sobrien res->number_non_literal++; 139390075Sobrien return; 139490075Sobrien } 139590075Sobrien if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree))) != char_type_node) 139690075Sobrien { 139790075Sobrien res->number_wide++; 139890075Sobrien return; 139990075Sobrien } 140090075Sobrien format_chars = TREE_STRING_POINTER (format_tree); 140190075Sobrien format_length = TREE_STRING_LENGTH (format_tree); 140290075Sobrien if (array_size != 0) 140390075Sobrien { 140490075Sobrien /* Variable length arrays can't be initialized. */ 1405169701Skan gcc_assert (TREE_CODE (array_size) == INTEGER_CST); 1406169701Skan 140790075Sobrien if (host_integerp (array_size, 0)) 140890075Sobrien { 140990075Sobrien HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size); 141090075Sobrien if (array_size_value > 0 141190075Sobrien && array_size_value == (int) array_size_value 141290075Sobrien && format_length > array_size_value) 141390075Sobrien format_length = array_size_value; 141490075Sobrien } 141590075Sobrien } 141690075Sobrien if (offset) 141790075Sobrien { 141890075Sobrien if (offset >= format_length) 141990075Sobrien { 142090075Sobrien res->number_non_literal++; 142190075Sobrien return; 142290075Sobrien } 142390075Sobrien format_chars += offset; 142490075Sobrien format_length -= offset; 142590075Sobrien } 142690075Sobrien if (format_length < 1) 142790075Sobrien { 142890075Sobrien res->number_unterminated++; 142990075Sobrien return; 143090075Sobrien } 143190075Sobrien if (format_length == 1) 143290075Sobrien { 143390075Sobrien res->number_empty++; 143490075Sobrien return; 143590075Sobrien } 143690075Sobrien if (format_chars[--format_length] != 0) 143790075Sobrien { 143890075Sobrien res->number_unterminated++; 143990075Sobrien return; 144090075Sobrien } 144190075Sobrien 144290075Sobrien /* Skip to first argument to check. */ 144390075Sobrien while (arg_num + 1 < info->first_arg_num) 144490075Sobrien { 144590075Sobrien if (params == 0) 144690075Sobrien return; 144790075Sobrien params = TREE_CHAIN (params); 144890075Sobrien ++arg_num; 144990075Sobrien } 145090075Sobrien /* Provisionally increment res->number_other; check_format_info_main 145190075Sobrien will decrement it if it finds there are extra arguments, but this way 145290075Sobrien need not adjust it for every return. */ 145390075Sobrien res->number_other++; 1454169701Skan check_format_info_main (res, info, format_chars, format_length, 145590075Sobrien params, arg_num); 145690075Sobrien} 145790075Sobrien 145890075Sobrien 145990075Sobrien/* Do the main part of checking a call to a format function. FORMAT_CHARS 146090075Sobrien is the NUL-terminated format string (which at this point may contain 146190075Sobrien internal NUL characters); FORMAT_LENGTH is its length (excluding the 146290075Sobrien terminating NUL character). ARG_NUM is one less than the number of 146390075Sobrien the first format argument to check; PARAMS points to that format 146490075Sobrien argument in the list of arguments. */ 146590075Sobrien 146690075Sobrienstatic void 1467169701Skancheck_format_info_main (format_check_results *res, 1468132731Skan function_format_info *info, const char *format_chars, 1469132731Skan int format_length, tree params, 1470132731Skan unsigned HOST_WIDE_INT arg_num) 147190075Sobrien{ 147290075Sobrien const char *orig_format_chars = format_chars; 147390075Sobrien tree first_fillin_param = params; 147490075Sobrien 147590075Sobrien const format_kind_info *fki = &format_types[info->format_type]; 147690075Sobrien const format_flag_spec *flag_specs = fki->flag_specs; 147790075Sobrien const format_flag_pair *bad_flag_pairs = fki->bad_flag_pairs; 147890075Sobrien 147990075Sobrien /* -1 if no conversions taking an operand have been found; 0 if one has 148090075Sobrien and it didn't use $; 1 if $ formats are in use. */ 148190075Sobrien int has_operand_number = -1; 148290075Sobrien 148390075Sobrien init_dollar_format_checking (info->first_arg_num, first_fillin_param); 148490075Sobrien 148590075Sobrien while (1) 148690075Sobrien { 148790075Sobrien int i; 148890075Sobrien int suppressed = FALSE; 148990075Sobrien const char *length_chars = NULL; 149090075Sobrien enum format_lengths length_chars_val = FMT_LEN_none; 149190075Sobrien enum format_std_version length_chars_std = STD_C89; 149290075Sobrien int format_char; 149390075Sobrien tree cur_param; 149490075Sobrien tree wanted_type; 149590075Sobrien int main_arg_num = 0; 149690075Sobrien tree main_arg_params = 0; 149790075Sobrien enum format_std_version wanted_type_std; 149890075Sobrien const char *wanted_type_name; 149990075Sobrien format_wanted_type width_wanted_type; 150090075Sobrien format_wanted_type precision_wanted_type; 150190075Sobrien format_wanted_type main_wanted_type; 150290075Sobrien format_wanted_type *first_wanted_type = NULL; 150390075Sobrien format_wanted_type *last_wanted_type = NULL; 150490075Sobrien const format_length_info *fli = NULL; 150590075Sobrien const format_char_info *fci = NULL; 150690075Sobrien char flag_chars[256]; 150790075Sobrien int aflag = 0; 1508169701Skan const char *format_start = format_chars; 150990075Sobrien if (*format_chars == 0) 151090075Sobrien { 151190075Sobrien if (format_chars - orig_format_chars != format_length) 1512169701Skan warning (OPT_Wformat, "embedded %<\\0%> in format"); 151390075Sobrien if (info->first_arg_num != 0 && params != 0 151490075Sobrien && has_operand_number <= 0) 151590075Sobrien { 151690075Sobrien res->number_other--; 151790075Sobrien res->number_extra_args++; 151890075Sobrien } 151990075Sobrien if (has_operand_number > 0) 1520169701Skan finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK); 152190075Sobrien return; 152290075Sobrien } 152390075Sobrien if (*format_chars++ != '%') 152490075Sobrien continue; 152590075Sobrien if (*format_chars == 0) 152690075Sobrien { 1527169701Skan warning (OPT_Wformat, "spurious trailing %<%%%> in format"); 152890075Sobrien continue; 152990075Sobrien } 153090075Sobrien if (*format_chars == '%') 153190075Sobrien { 153290075Sobrien ++format_chars; 153390075Sobrien continue; 153490075Sobrien } 153590075Sobrien flag_chars[0] = 0; 153690075Sobrien 153790075Sobrien if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0) 153890075Sobrien { 153990075Sobrien /* Possibly read a $ operand number at the start of the format. 154090075Sobrien If one was previously used, one is required here. If one 154190075Sobrien is not used here, we can't immediately conclude this is a 154290075Sobrien format without them, since it could be printf %m or scanf %*. */ 154390075Sobrien int opnum; 1544169701Skan opnum = maybe_read_dollar_number (&format_chars, 0, 154590075Sobrien first_fillin_param, 154690075Sobrien &main_arg_params, fki); 154790075Sobrien if (opnum == -1) 154890075Sobrien return; 154990075Sobrien else if (opnum > 0) 155090075Sobrien { 155190075Sobrien has_operand_number = 1; 155290075Sobrien main_arg_num = opnum + info->first_arg_num - 1; 155390075Sobrien } 155490075Sobrien } 1555169701Skan else if (fki->flags & FMT_FLAG_USE_DOLLAR) 1556169701Skan { 1557169701Skan if (avoid_dollar_number (format_chars)) 1558169701Skan return; 1559169701Skan } 156090075Sobrien 156190075Sobrien /* Read any format flags, but do not yet validate them beyond removing 156290075Sobrien duplicates, since in general validation depends on the rest of 156390075Sobrien the format. */ 156490075Sobrien while (*format_chars != 0 156590075Sobrien && strchr (fki->flag_chars, *format_chars) != 0) 156690075Sobrien { 156790075Sobrien const format_flag_spec *s = get_flag_spec (flag_specs, 156890075Sobrien *format_chars, NULL); 156990075Sobrien if (strchr (flag_chars, *format_chars) != 0) 157090075Sobrien { 1571169701Skan warning (OPT_Wformat, "repeated %s in format", _(s->name)); 157290075Sobrien } 157390075Sobrien else 157490075Sobrien { 157590075Sobrien i = strlen (flag_chars); 157690075Sobrien flag_chars[i++] = *format_chars; 157790075Sobrien flag_chars[i] = 0; 157890075Sobrien } 157990075Sobrien if (s->skip_next_char) 158090075Sobrien { 158190075Sobrien ++format_chars; 158290075Sobrien if (*format_chars == 0) 158390075Sobrien { 1584169701Skan warning (OPT_Wformat, "missing fill character at end of strfmon format"); 158590075Sobrien return; 158690075Sobrien } 158790075Sobrien } 158890075Sobrien ++format_chars; 158990075Sobrien } 159090075Sobrien 159190075Sobrien /* Read any format width, possibly * or *m$. */ 159290075Sobrien if (fki->width_char != 0) 159390075Sobrien { 159490075Sobrien if (fki->width_type != NULL && *format_chars == '*') 159590075Sobrien { 159690075Sobrien i = strlen (flag_chars); 159790075Sobrien flag_chars[i++] = fki->width_char; 159890075Sobrien flag_chars[i] = 0; 159990075Sobrien /* "...a field width...may be indicated by an asterisk. 160090075Sobrien In this case, an int argument supplies the field width..." */ 160190075Sobrien ++format_chars; 160290075Sobrien if (has_operand_number != 0) 160390075Sobrien { 160490075Sobrien int opnum; 1605169701Skan opnum = maybe_read_dollar_number (&format_chars, 160690075Sobrien has_operand_number == 1, 160790075Sobrien first_fillin_param, 160890075Sobrien ¶ms, fki); 160990075Sobrien if (opnum == -1) 161090075Sobrien return; 161190075Sobrien else if (opnum > 0) 161290075Sobrien { 161390075Sobrien has_operand_number = 1; 161490075Sobrien arg_num = opnum + info->first_arg_num - 1; 161590075Sobrien } 161690075Sobrien else 161790075Sobrien has_operand_number = 0; 161890075Sobrien } 1619169701Skan else 1620169701Skan { 1621169701Skan if (avoid_dollar_number (format_chars)) 1622169701Skan return; 1623169701Skan } 162490075Sobrien if (info->first_arg_num != 0) 162590075Sobrien { 1626117422Skan if (params == 0) 1627117422Skan { 1628169701Skan warning (OPT_Wformat, "too few arguments for format"); 1629117422Skan return; 1630117422Skan } 163190075Sobrien cur_param = TREE_VALUE (params); 163290075Sobrien if (has_operand_number <= 0) 163390075Sobrien { 163490075Sobrien params = TREE_CHAIN (params); 163590075Sobrien ++arg_num; 163690075Sobrien } 163790075Sobrien width_wanted_type.wanted_type = *fki->width_type; 163890075Sobrien width_wanted_type.wanted_type_name = NULL; 163990075Sobrien width_wanted_type.pointer_count = 0; 164090075Sobrien width_wanted_type.char_lenient_flag = 0; 164190075Sobrien width_wanted_type.writing_in_flag = 0; 164290075Sobrien width_wanted_type.reading_from_flag = 0; 164390075Sobrien width_wanted_type.name = _("field width"); 164490075Sobrien width_wanted_type.param = cur_param; 164590075Sobrien width_wanted_type.arg_num = arg_num; 164690075Sobrien width_wanted_type.next = NULL; 164790075Sobrien if (last_wanted_type != 0) 164890075Sobrien last_wanted_type->next = &width_wanted_type; 164990075Sobrien if (first_wanted_type == 0) 165090075Sobrien first_wanted_type = &width_wanted_type; 165190075Sobrien last_wanted_type = &width_wanted_type; 165290075Sobrien } 165390075Sobrien } 165490075Sobrien else 165590075Sobrien { 165690075Sobrien /* Possibly read a numeric width. If the width is zero, 165790075Sobrien we complain if appropriate. */ 165890075Sobrien int non_zero_width_char = FALSE; 165990075Sobrien int found_width = FALSE; 166090075Sobrien while (ISDIGIT (*format_chars)) 166190075Sobrien { 166290075Sobrien found_width = TRUE; 166390075Sobrien if (*format_chars != '0') 166490075Sobrien non_zero_width_char = TRUE; 166590075Sobrien ++format_chars; 166690075Sobrien } 166790075Sobrien if (found_width && !non_zero_width_char && 166890075Sobrien (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD)) 1669169701Skan warning (OPT_Wformat, "zero width in %s format", fki->name); 167090075Sobrien if (found_width) 167190075Sobrien { 167290075Sobrien i = strlen (flag_chars); 167390075Sobrien flag_chars[i++] = fki->width_char; 167490075Sobrien flag_chars[i] = 0; 167590075Sobrien } 167690075Sobrien } 167790075Sobrien } 167890075Sobrien 167990075Sobrien /* Read any format left precision (must be a number, not *). */ 168090075Sobrien if (fki->left_precision_char != 0 && *format_chars == '#') 168190075Sobrien { 168290075Sobrien ++format_chars; 168390075Sobrien i = strlen (flag_chars); 168490075Sobrien flag_chars[i++] = fki->left_precision_char; 168590075Sobrien flag_chars[i] = 0; 168690075Sobrien if (!ISDIGIT (*format_chars)) 1687169701Skan warning (OPT_Wformat, "empty left precision in %s format", fki->name); 168890075Sobrien while (ISDIGIT (*format_chars)) 168990075Sobrien ++format_chars; 169090075Sobrien } 169190075Sobrien 169290075Sobrien /* Read any format precision, possibly * or *m$. */ 169390075Sobrien if (fki->precision_char != 0 && *format_chars == '.') 169490075Sobrien { 169590075Sobrien ++format_chars; 169690075Sobrien i = strlen (flag_chars); 169790075Sobrien flag_chars[i++] = fki->precision_char; 169890075Sobrien flag_chars[i] = 0; 169990075Sobrien if (fki->precision_type != NULL && *format_chars == '*') 170090075Sobrien { 170190075Sobrien /* "...a...precision...may be indicated by an asterisk. 170290075Sobrien In this case, an int argument supplies the...precision." */ 170390075Sobrien ++format_chars; 170490075Sobrien if (has_operand_number != 0) 170590075Sobrien { 170690075Sobrien int opnum; 1707169701Skan opnum = maybe_read_dollar_number (&format_chars, 170890075Sobrien has_operand_number == 1, 170990075Sobrien first_fillin_param, 171090075Sobrien ¶ms, fki); 171190075Sobrien if (opnum == -1) 171290075Sobrien return; 171390075Sobrien else if (opnum > 0) 171490075Sobrien { 171590075Sobrien has_operand_number = 1; 171690075Sobrien arg_num = opnum + info->first_arg_num - 1; 171790075Sobrien } 171890075Sobrien else 171990075Sobrien has_operand_number = 0; 172090075Sobrien } 1721169701Skan else 1722169701Skan { 1723169701Skan if (avoid_dollar_number (format_chars)) 1724169701Skan return; 1725169701Skan } 172690075Sobrien if (info->first_arg_num != 0) 172790075Sobrien { 172890075Sobrien if (params == 0) 172990075Sobrien { 1730169701Skan warning (OPT_Wformat, "too few arguments for format"); 173190075Sobrien return; 173290075Sobrien } 173390075Sobrien cur_param = TREE_VALUE (params); 173490075Sobrien if (has_operand_number <= 0) 173590075Sobrien { 173690075Sobrien params = TREE_CHAIN (params); 173790075Sobrien ++arg_num; 173890075Sobrien } 173990075Sobrien precision_wanted_type.wanted_type = *fki->precision_type; 174090075Sobrien precision_wanted_type.wanted_type_name = NULL; 174190075Sobrien precision_wanted_type.pointer_count = 0; 174290075Sobrien precision_wanted_type.char_lenient_flag = 0; 174390075Sobrien precision_wanted_type.writing_in_flag = 0; 174490075Sobrien precision_wanted_type.reading_from_flag = 0; 174590075Sobrien precision_wanted_type.name = _("field precision"); 174690075Sobrien precision_wanted_type.param = cur_param; 174790075Sobrien precision_wanted_type.arg_num = arg_num; 174890075Sobrien precision_wanted_type.next = NULL; 174990075Sobrien if (last_wanted_type != 0) 175090075Sobrien last_wanted_type->next = &precision_wanted_type; 175190075Sobrien if (first_wanted_type == 0) 175290075Sobrien first_wanted_type = &precision_wanted_type; 175390075Sobrien last_wanted_type = &precision_wanted_type; 175490075Sobrien } 175590075Sobrien } 175690075Sobrien else 175790075Sobrien { 175890075Sobrien if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK) 175990075Sobrien && !ISDIGIT (*format_chars)) 1760169701Skan warning (OPT_Wformat, "empty precision in %s format", fki->name); 176190075Sobrien while (ISDIGIT (*format_chars)) 176290075Sobrien ++format_chars; 176390075Sobrien } 176490075Sobrien } 176590075Sobrien 176690075Sobrien /* Read any length modifier, if this kind of format has them. */ 176790075Sobrien fli = fki->length_char_specs; 176890075Sobrien length_chars = NULL; 176990075Sobrien length_chars_val = FMT_LEN_none; 177090075Sobrien length_chars_std = STD_C89; 177190075Sobrien if (fli) 177290075Sobrien { 177390075Sobrien while (fli->name != 0 && fli->name[0] != *format_chars) 177490075Sobrien fli++; 1775169701Skan /* 1776169701Skan * Make sure FreeBSD's D format char takes preference 1777169701Skan * over new DD length specifier if FreeBSD format 1778169701Skan * extensions are requested. 1779169701Skan */ 1780169701Skan if (fli->index == FMT_LEN_D && flag_format_extensions 1781169701Skan && fki->conversion_specs == print_char_table) 1782169701Skan while (fli->name != 0) fli++; 178390075Sobrien if (fli->name != 0) 178490075Sobrien { 178590075Sobrien format_chars++; 178690075Sobrien if (fli->double_name != 0 && fli->name[0] == *format_chars) 178790075Sobrien { 178890075Sobrien format_chars++; 178990075Sobrien length_chars = fli->double_name; 179090075Sobrien length_chars_val = fli->double_index; 179190075Sobrien length_chars_std = fli->double_std; 179290075Sobrien } 179390075Sobrien else 179490075Sobrien { 179590075Sobrien length_chars = fli->name; 179690075Sobrien length_chars_val = fli->index; 179790075Sobrien length_chars_std = fli->std; 179890075Sobrien } 179990075Sobrien i = strlen (flag_chars); 180090075Sobrien flag_chars[i++] = fki->length_code_char; 180190075Sobrien flag_chars[i] = 0; 180290075Sobrien } 180390075Sobrien if (pedantic) 180490075Sobrien { 180590075Sobrien /* Warn if the length modifier is non-standard. */ 180690075Sobrien if (ADJ_STD (length_chars_std) > C_STD_VER) 1807169701Skan warning (OPT_Wformat, 1808169701Skan "%s does not support the %qs %s length modifier", 1809169701Skan C_STD_NAME (length_chars_std), length_chars, 1810169701Skan fki->name); 181190075Sobrien } 181290075Sobrien } 181390075Sobrien 181490075Sobrien /* Read any modifier (strftime E/O). */ 181590075Sobrien if (fki->modifier_chars != NULL) 181690075Sobrien { 181790075Sobrien while (*format_chars != 0 181890075Sobrien && strchr (fki->modifier_chars, *format_chars) != 0) 181990075Sobrien { 182090075Sobrien if (strchr (flag_chars, *format_chars) != 0) 182190075Sobrien { 182290075Sobrien const format_flag_spec *s = get_flag_spec (flag_specs, 182390075Sobrien *format_chars, NULL); 1824169701Skan warning (OPT_Wformat, "repeated %s in format", _(s->name)); 182590075Sobrien } 182690075Sobrien else 182790075Sobrien { 182890075Sobrien i = strlen (flag_chars); 182990075Sobrien flag_chars[i++] = *format_chars; 183090075Sobrien flag_chars[i] = 0; 183190075Sobrien } 183290075Sobrien ++format_chars; 183390075Sobrien } 183490075Sobrien } 183590075Sobrien 183690075Sobrien /* Handle the scanf allocation kludge. */ 183790075Sobrien if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) 183890075Sobrien { 183990075Sobrien if (*format_chars == 'a' && !flag_isoc99) 184090075Sobrien { 184190075Sobrien if (format_chars[1] == 's' || format_chars[1] == 'S' 184290075Sobrien || format_chars[1] == '[') 184390075Sobrien { 1844169701Skan /* 'a' is used as a flag. */ 184590075Sobrien i = strlen (flag_chars); 184690075Sobrien flag_chars[i++] = 'a'; 184790075Sobrien flag_chars[i] = 0; 184890075Sobrien format_chars++; 184990075Sobrien } 185090075Sobrien } 185190075Sobrien } 185290075Sobrien 185390075Sobrien format_char = *format_chars; 185490075Sobrien if (format_char == 0 185590075Sobrien || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK) 185690075Sobrien && format_char == '%')) 185790075Sobrien { 1858169701Skan warning (OPT_Wformat, "conversion lacks type at end of format"); 185990075Sobrien continue; 186090075Sobrien } 186190075Sobrien format_chars++; 186290075Sobrien fci = fki->conversion_specs; 186390075Sobrien while (fci->format_chars != 0 186490075Sobrien && strchr (fci->format_chars, format_char) == 0) 186590075Sobrien ++fci; 1866169701Skan if (fci->format_chars == 0 && flag_format_extensions 1867169701Skan && fki->conversion_specs == print_char_table) 1868169701Skan { 1869169701Skan fci = fbsd_print_char_table; 1870169701Skan while (fci->format_chars != 0 1871169701Skan && strchr (fci->format_chars, format_char) == 0) 1872169701Skan ++fci; 1873169701Skan } 187490075Sobrien if (fci->format_chars == 0) 187590075Sobrien { 1876169701Skan if (ISGRAPH (format_char)) 1877169701Skan warning (OPT_Wformat, "unknown conversion type character %qc in format", 187890075Sobrien format_char); 187990075Sobrien else 1880169701Skan warning (OPT_Wformat, "unknown conversion type character 0x%x in format", 188190075Sobrien format_char); 188290075Sobrien continue; 188390075Sobrien } 188490075Sobrien if (pedantic) 188590075Sobrien { 188690075Sobrien if (ADJ_STD (fci->std) > C_STD_VER) 1887169701Skan warning (OPT_Wformat, "%s does not support the %<%%%c%> %s format", 1888169701Skan C_STD_NAME (fci->std), format_char, fki->name); 188990075Sobrien } 189090075Sobrien 189190075Sobrien /* Validate the individual flags used, removing any that are invalid. */ 189290075Sobrien { 189390075Sobrien int d = 0; 189490075Sobrien for (i = 0; flag_chars[i] != 0; i++) 189590075Sobrien { 189690075Sobrien const format_flag_spec *s = get_flag_spec (flag_specs, 189790075Sobrien flag_chars[i], NULL); 189890075Sobrien flag_chars[i - d] = flag_chars[i]; 189990075Sobrien if (flag_chars[i] == fki->length_code_char) 190090075Sobrien continue; 190190075Sobrien if (strchr (fci->flag_chars, flag_chars[i]) == 0) 190290075Sobrien { 1903169701Skan warning (OPT_Wformat, "%s used with %<%%%c%> %s format", 1904169701Skan _(s->name), format_char, fki->name); 190590075Sobrien d++; 190690075Sobrien continue; 190790075Sobrien } 190890075Sobrien if (pedantic) 190990075Sobrien { 191090075Sobrien const format_flag_spec *t; 191190075Sobrien if (ADJ_STD (s->std) > C_STD_VER) 1912169701Skan warning (OPT_Wformat, "%s does not support %s", 1913169701Skan C_STD_NAME (s->std), _(s->long_name)); 191490075Sobrien t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2); 191590075Sobrien if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std)) 191690075Sobrien { 191790075Sobrien const char *long_name = (t->long_name != NULL 191890075Sobrien ? t->long_name 191990075Sobrien : s->long_name); 192090075Sobrien if (ADJ_STD (t->std) > C_STD_VER) 1921169701Skan warning (OPT_Wformat, 1922169701Skan "%s does not support %s with the %<%%%c%> %s format", 1923169701Skan C_STD_NAME (t->std), _(long_name), 1924169701Skan format_char, fki->name); 192590075Sobrien } 192690075Sobrien } 192790075Sobrien } 192890075Sobrien flag_chars[i - d] = 0; 192990075Sobrien } 193090075Sobrien 193190075Sobrien if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) 193290075Sobrien && strchr (flag_chars, 'a') != 0) 193390075Sobrien aflag = 1; 193490075Sobrien 193590075Sobrien if (fki->suppression_char 193690075Sobrien && strchr (flag_chars, fki->suppression_char) != 0) 193790075Sobrien suppressed = 1; 193890075Sobrien 193990075Sobrien /* Validate the pairs of flags used. */ 194090075Sobrien for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++) 194190075Sobrien { 194290075Sobrien const format_flag_spec *s, *t; 194390075Sobrien if (strchr (flag_chars, bad_flag_pairs[i].flag_char1) == 0) 194490075Sobrien continue; 194590075Sobrien if (strchr (flag_chars, bad_flag_pairs[i].flag_char2) == 0) 194690075Sobrien continue; 194790075Sobrien if (bad_flag_pairs[i].predicate != 0 194890075Sobrien && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0) 194990075Sobrien continue; 195090075Sobrien s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL); 195190075Sobrien t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL); 195290075Sobrien if (bad_flag_pairs[i].ignored) 195390075Sobrien { 195490075Sobrien if (bad_flag_pairs[i].predicate != 0) 1955169701Skan warning (OPT_Wformat, 1956169701Skan "%s ignored with %s and %<%%%c%> %s format", 1957169701Skan _(s->name), _(t->name), format_char, 1958169701Skan fki->name); 195990075Sobrien else 1960169701Skan warning (OPT_Wformat, "%s ignored with %s in %s format", 1961169701Skan _(s->name), _(t->name), fki->name); 196290075Sobrien } 196390075Sobrien else 196490075Sobrien { 196590075Sobrien if (bad_flag_pairs[i].predicate != 0) 1966169701Skan warning (OPT_Wformat, 1967169701Skan "use of %s and %s together with %<%%%c%> %s format", 1968169701Skan _(s->name), _(t->name), format_char, 1969169701Skan fki->name); 197090075Sobrien else 1971169701Skan warning (OPT_Wformat, "use of %s and %s together in %s format", 1972169701Skan _(s->name), _(t->name), fki->name); 197390075Sobrien } 197490075Sobrien } 197590075Sobrien 197690075Sobrien /* Give Y2K warnings. */ 197790075Sobrien if (warn_format_y2k) 197890075Sobrien { 197990075Sobrien int y2k_level = 0; 198090075Sobrien if (strchr (fci->flags2, '4') != 0) 198190075Sobrien if (strchr (flag_chars, 'E') != 0) 198290075Sobrien y2k_level = 3; 198390075Sobrien else 198490075Sobrien y2k_level = 2; 198590075Sobrien else if (strchr (fci->flags2, '3') != 0) 198690075Sobrien y2k_level = 3; 198790075Sobrien else if (strchr (fci->flags2, '2') != 0) 198890075Sobrien y2k_level = 2; 198990075Sobrien if (y2k_level == 3) 1990169701Skan warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of " 1991169701Skan "year in some locales on non-BSD systems", format_char); 199290075Sobrien else if (y2k_level == 2) 1993169701Skan warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of " 1994169701Skan "year", format_char); 199590075Sobrien } 199690075Sobrien 199790075Sobrien if (strchr (fci->flags2, '[') != 0) 199890075Sobrien { 199990075Sobrien /* Skip over scan set, in case it happens to have '%' in it. */ 200090075Sobrien if (*format_chars == '^') 200190075Sobrien ++format_chars; 200290075Sobrien /* Find closing bracket; if one is hit immediately, then 200390075Sobrien it's part of the scan set rather than a terminator. */ 200490075Sobrien if (*format_chars == ']') 200590075Sobrien ++format_chars; 200690075Sobrien while (*format_chars && *format_chars != ']') 200790075Sobrien ++format_chars; 200890075Sobrien if (*format_chars != ']') 200990075Sobrien /* The end of the format string was reached. */ 2010169701Skan warning (OPT_Wformat, "no closing %<]%> for %<%%[%> format"); 201190075Sobrien } 201290075Sobrien 201390075Sobrien wanted_type = 0; 201490075Sobrien wanted_type_name = 0; 201590075Sobrien if (fki->flags & (int) FMT_FLAG_ARG_CONVERT) 201690075Sobrien { 201790075Sobrien wanted_type = (fci->types[length_chars_val].type 201890075Sobrien ? *fci->types[length_chars_val].type : 0); 201990075Sobrien wanted_type_name = fci->types[length_chars_val].name; 202090075Sobrien wanted_type_std = fci->types[length_chars_val].std; 202190075Sobrien if (wanted_type == 0) 202290075Sobrien { 2023169701Skan warning (OPT_Wformat, 2024169701Skan "use of %qs length modifier with %qc type character", 2025169701Skan length_chars, format_char); 202690075Sobrien /* Heuristic: skip one argument when an invalid length/type 202790075Sobrien combination is encountered. */ 202890075Sobrien arg_num++; 202990075Sobrien if (params == 0) 203090075Sobrien { 2031169701Skan warning (OPT_Wformat, "too few arguments for format"); 203290075Sobrien return; 203390075Sobrien } 203490075Sobrien params = TREE_CHAIN (params); 203590075Sobrien continue; 203690075Sobrien } 203790075Sobrien else if (pedantic 203890075Sobrien /* Warn if non-standard, provided it is more non-standard 203990075Sobrien than the length and type characters that may already 204090075Sobrien have been warned for. */ 204190075Sobrien && ADJ_STD (wanted_type_std) > ADJ_STD (length_chars_std) 204290075Sobrien && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std)) 204390075Sobrien { 204490075Sobrien if (ADJ_STD (wanted_type_std) > C_STD_VER) 2045169701Skan warning (OPT_Wformat, 2046169701Skan "%s does not support the %<%%%s%c%> %s format", 2047169701Skan C_STD_NAME (wanted_type_std), length_chars, 2048169701Skan format_char, fki->name); 204990075Sobrien } 205090075Sobrien } 205190075Sobrien 2052169701Skan main_wanted_type.next = NULL; 2053169701Skan 205490075Sobrien /* Finally. . .check type of argument against desired type! */ 205590075Sobrien if (info->first_arg_num == 0) 205690075Sobrien continue; 205790075Sobrien if ((fci->pointer_count == 0 && wanted_type == void_type_node) 205890075Sobrien || suppressed) 205990075Sobrien { 206090075Sobrien if (main_arg_num != 0) 206190075Sobrien { 206290075Sobrien if (suppressed) 2063169701Skan warning (OPT_Wformat, "operand number specified with " 2064169701Skan "suppressed assignment"); 206590075Sobrien else 2066169701Skan warning (OPT_Wformat, "operand number specified for format " 2067169701Skan "taking no argument"); 206890075Sobrien } 206990075Sobrien } 207090075Sobrien else 207190075Sobrien { 2072169701Skan format_wanted_type *wanted_type_ptr; 2073169701Skan 207490075Sobrien if (main_arg_num != 0) 207590075Sobrien { 207690075Sobrien arg_num = main_arg_num; 207790075Sobrien params = main_arg_params; 207890075Sobrien } 207990075Sobrien else 208090075Sobrien { 208190075Sobrien ++arg_num; 208290075Sobrien if (has_operand_number > 0) 208390075Sobrien { 2084169701Skan warning (OPT_Wformat, "missing $ operand number in format"); 208590075Sobrien return; 208690075Sobrien } 208790075Sobrien else 208890075Sobrien has_operand_number = 0; 2089169701Skan } 2090169701Skan 2091169701Skan wanted_type_ptr = &main_wanted_type; 2092169701Skan while (fci) 2093169701Skan { 209490075Sobrien if (params == 0) 209590075Sobrien { 2096169701Skan warning (OPT_Wformat, "too few arguments for format"); 209790075Sobrien return; 209890075Sobrien } 2099169701Skan 2100169701Skan cur_param = TREE_VALUE (params); 2101169701Skan params = TREE_CHAIN (params); 2102169701Skan 2103169701Skan wanted_type_ptr->wanted_type = wanted_type; 2104169701Skan wanted_type_ptr->wanted_type_name = wanted_type_name; 2105169701Skan wanted_type_ptr->pointer_count = fci->pointer_count + aflag; 2106169701Skan wanted_type_ptr->char_lenient_flag = 0; 2107169701Skan if (strchr (fci->flags2, 'c') != 0) 2108169701Skan wanted_type_ptr->char_lenient_flag = 1; 2109169701Skan wanted_type_ptr->writing_in_flag = 0; 2110169701Skan wanted_type_ptr->reading_from_flag = 0; 2111169701Skan if (aflag) 2112169701Skan wanted_type_ptr->writing_in_flag = 1; 2113169701Skan else 2114169701Skan { 2115169701Skan if (strchr (fci->flags2, 'W') != 0) 2116169701Skan wanted_type_ptr->writing_in_flag = 1; 2117169701Skan if (strchr (fci->flags2, 'R') != 0) 2118169701Skan wanted_type_ptr->reading_from_flag = 1; 2119169701Skan } 2120169701Skan wanted_type_ptr->name = NULL; 2121169701Skan wanted_type_ptr->param = cur_param; 2122169701Skan wanted_type_ptr->arg_num = arg_num; 2123169701Skan wanted_type_ptr->next = NULL; 2124169701Skan if (last_wanted_type != 0) 2125169701Skan last_wanted_type->next = wanted_type_ptr; 2126169701Skan if (first_wanted_type == 0) 2127169701Skan first_wanted_type = wanted_type_ptr; 2128169701Skan last_wanted_type = wanted_type_ptr; 2129169701Skan 2130169701Skan fci = fci->chain; 2131169701Skan if (fci) 2132169701Skan { 2133169701Skan wanted_type_ptr = GGC_NEW (format_wanted_type); 2134169701Skan arg_num++; 2135169701Skan wanted_type = *fci->types[length_chars_val].type; 2136169701Skan wanted_type_name = fci->types[length_chars_val].name; 2137169701Skan } 213890075Sobrien } 213990075Sobrien } 214090075Sobrien 214190075Sobrien if (first_wanted_type != 0) 2142169701Skan check_format_types (first_wanted_type, format_start, 2143169701Skan format_chars - format_start); 214490075Sobrien 2145169701Skan if (main_wanted_type.next != NULL) 2146169701Skan { 2147169701Skan format_wanted_type *wanted_type_ptr = main_wanted_type.next; 2148169701Skan while (wanted_type_ptr) 2149169701Skan { 2150169701Skan format_wanted_type *next = wanted_type_ptr->next; 2151169701Skan ggc_free (wanted_type_ptr); 2152169701Skan wanted_type_ptr = next; 2153169701Skan } 2154169701Skan } 215590075Sobrien } 215690075Sobrien} 215790075Sobrien 215890075Sobrien 215990075Sobrien/* Check the argument types from a single format conversion (possibly 216090075Sobrien including width and precision arguments). */ 216190075Sobrienstatic void 2162169701Skancheck_format_types (format_wanted_type *types, const char *format_start, 2163169701Skan int format_length) 216490075Sobrien{ 216590075Sobrien for (; types != 0; types = types->next) 216690075Sobrien { 216790075Sobrien tree cur_param; 216890075Sobrien tree cur_type; 216990075Sobrien tree orig_cur_type; 217090075Sobrien tree wanted_type; 217190075Sobrien int arg_num; 217290075Sobrien int i; 217390075Sobrien int char_type_flag; 217490075Sobrien cur_param = types->param; 217590075Sobrien cur_type = TREE_TYPE (cur_param); 217690075Sobrien if (cur_type == error_mark_node) 217790075Sobrien continue; 2178169701Skan orig_cur_type = cur_type; 217990075Sobrien char_type_flag = 0; 218090075Sobrien wanted_type = types->wanted_type; 218190075Sobrien arg_num = types->arg_num; 218290075Sobrien 218390075Sobrien /* The following should not occur here. */ 2184169701Skan gcc_assert (wanted_type); 2185169701Skan gcc_assert (wanted_type != void_type_node || types->pointer_count); 218690075Sobrien 218790075Sobrien if (types->pointer_count == 0) 2188169701Skan wanted_type = lang_hooks.types.type_promotes_to (wanted_type); 218990075Sobrien 2190169701Skan wanted_type = TYPE_MAIN_VARIANT (wanted_type); 2191169701Skan 219290075Sobrien STRIP_NOPS (cur_param); 219390075Sobrien 219490075Sobrien /* Check the types of any additional pointer arguments 219590075Sobrien that precede the "real" argument. */ 219690075Sobrien for (i = 0; i < types->pointer_count; ++i) 219790075Sobrien { 219890075Sobrien if (TREE_CODE (cur_type) == POINTER_TYPE) 219990075Sobrien { 220090075Sobrien cur_type = TREE_TYPE (cur_type); 220190075Sobrien if (cur_type == error_mark_node) 220290075Sobrien break; 220390075Sobrien 220490075Sobrien /* Check for writing through a NULL pointer. */ 220590075Sobrien if (types->writing_in_flag 220690075Sobrien && i == 0 220790075Sobrien && cur_param != 0 220890075Sobrien && integer_zerop (cur_param)) 2209169701Skan warning (OPT_Wformat, "writing through null pointer " 2210169701Skan "(argument %d)", arg_num); 221190075Sobrien 221290075Sobrien /* Check for reading through a NULL pointer. */ 221390075Sobrien if (types->reading_from_flag 221490075Sobrien && i == 0 221590075Sobrien && cur_param != 0 221690075Sobrien && integer_zerop (cur_param)) 2217169701Skan warning (OPT_Wformat, "reading through null pointer " 2218169701Skan "(argument %d)", arg_num); 221990075Sobrien 222090075Sobrien if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR) 222190075Sobrien cur_param = TREE_OPERAND (cur_param, 0); 222290075Sobrien else 222390075Sobrien cur_param = 0; 222490075Sobrien 222590075Sobrien /* See if this is an attempt to write into a const type with 222690075Sobrien scanf or with printf "%n". Note: the writing in happens 222790075Sobrien at the first indirection only, if for example 222890075Sobrien void * const * is passed to scanf %p; passing 222990075Sobrien const void ** is simply passing an incompatible type. */ 223090075Sobrien if (types->writing_in_flag 223190075Sobrien && i == 0 223290075Sobrien && (TYPE_READONLY (cur_type) 223390075Sobrien || (cur_param != 0 2234169701Skan && (CONSTANT_CLASS_P (cur_param) 223590075Sobrien || (DECL_P (cur_param) 223690075Sobrien && TREE_READONLY (cur_param)))))) 2237169701Skan warning (OPT_Wformat, "writing into constant object " 2238169701Skan "(argument %d)", arg_num); 223990075Sobrien 224090075Sobrien /* If there are extra type qualifiers beyond the first 224190075Sobrien indirection, then this makes the types technically 224290075Sobrien incompatible. */ 224390075Sobrien if (i > 0 224490075Sobrien && pedantic 224590075Sobrien && (TYPE_READONLY (cur_type) 224690075Sobrien || TYPE_VOLATILE (cur_type) 224790075Sobrien || TYPE_RESTRICT (cur_type))) 2248169701Skan warning (OPT_Wformat, "extra type qualifiers in format " 2249169701Skan "argument (argument %d)", 225090075Sobrien arg_num); 225190075Sobrien 225290075Sobrien } 225390075Sobrien else 225490075Sobrien { 2255169701Skan format_type_warning (types->name, format_start, format_length, 2256169701Skan wanted_type, types->pointer_count, 2257169701Skan types->wanted_type_name, orig_cur_type, 2258169701Skan arg_num); 225990075Sobrien break; 226090075Sobrien } 226190075Sobrien } 226290075Sobrien 226390075Sobrien if (i < types->pointer_count) 226490075Sobrien continue; 226590075Sobrien 226690075Sobrien cur_type = TYPE_MAIN_VARIANT (cur_type); 226790075Sobrien 226890075Sobrien /* Check whether the argument type is a character type. This leniency 226990075Sobrien only applies to certain formats, flagged with 'c'. 227090075Sobrien */ 227190075Sobrien if (types->char_lenient_flag) 227290075Sobrien char_type_flag = (cur_type == char_type_node 227390075Sobrien || cur_type == signed_char_type_node 227490075Sobrien || cur_type == unsigned_char_type_node); 227590075Sobrien 227690075Sobrien /* Check the type of the "real" argument, if there's a type we want. */ 2277169701Skan if (lang_hooks.types_compatible_p (wanted_type, cur_type)) 227890075Sobrien continue; 2279169701Skan /* If we want 'void *', allow any pointer type. 228090075Sobrien (Anything else would already have got a warning.) 228190075Sobrien With -pedantic, only allow pointers to void and to character 228290075Sobrien types. */ 228390075Sobrien if (wanted_type == void_type_node 228490075Sobrien && (!pedantic || (i == 1 && char_type_flag))) 228590075Sobrien continue; 228690075Sobrien /* Don't warn about differences merely in signedness, unless 228790075Sobrien -pedantic. With -pedantic, warn if the type is a pointer 228890075Sobrien target and not a character type, and for character types at 228990075Sobrien a second level of indirection. */ 229090075Sobrien if (TREE_CODE (wanted_type) == INTEGER_TYPE 229190075Sobrien && TREE_CODE (cur_type) == INTEGER_TYPE 2292169701Skan && (!pedantic || i == 0 || (i == 1 && char_type_flag)) 2293169701Skan && (TYPE_UNSIGNED (wanted_type) 2294117422Skan ? wanted_type == c_common_unsigned_type (cur_type) 2295117422Skan : wanted_type == c_common_signed_type (cur_type))) 229690075Sobrien continue; 229790075Sobrien /* Likewise, "signed char", "unsigned char" and "char" are 229890075Sobrien equivalent but the above test won't consider them equivalent. */ 229990075Sobrien if (wanted_type == char_type_node 2300169701Skan && (!pedantic || i < 2) 230190075Sobrien && char_type_flag) 230290075Sobrien continue; 230390075Sobrien /* Now we have a type mismatch. */ 2304169701Skan format_type_warning (types->name, format_start, format_length, 2305169701Skan wanted_type, types->pointer_count, 2306169701Skan types->wanted_type_name, orig_cur_type, arg_num); 2307169701Skan } 2308169701Skan} 230990075Sobrien 2310132731Skan 2311169701Skan/* Give a warning about a format argument of different type from that 2312169701Skan expected. DESCR is a description such as "field precision", or 2313169701Skan NULL for an ordinary format. For an ordinary format, FORMAT_START 2314169701Skan points to where the format starts in the format string and 2315169701Skan FORMAT_LENGTH is its length. WANTED_TYPE is the type the argument 2316169701Skan should have after POINTER_COUNT pointer dereferences. 2317169701Skan WANTED_NAME_NAME is a possibly more friendly name of WANTED_TYPE, 2318169701Skan or NULL if the ordinary name of the type should be used. ARG_TYPE 2319169701Skan is the type of the actual argument. ARG_NUM is the number of that 2320169701Skan argument. */ 2321169701Skanstatic void 2322169701Skanformat_type_warning (const char *descr, const char *format_start, 2323169701Skan int format_length, tree wanted_type, int pointer_count, 2324169701Skan const char *wanted_type_name, tree arg_type, int arg_num) 2325169701Skan{ 2326169701Skan char *p; 2327169701Skan /* If ARG_TYPE is a typedef with a misleading name (for example, 2328169701Skan size_t but not the standard size_t expected by printf %zu), avoid 2329169701Skan printing the typedef name. */ 2330169701Skan if (wanted_type_name 2331169701Skan && TYPE_NAME (arg_type) 2332169701Skan && TREE_CODE (TYPE_NAME (arg_type)) == TYPE_DECL 2333169701Skan && DECL_NAME (TYPE_NAME (arg_type)) 2334169701Skan && !strcmp (wanted_type_name, 2335169701Skan lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2))) 2336169701Skan arg_type = TYPE_MAIN_VARIANT (arg_type); 2337169701Skan /* The format type and name exclude any '*' for pointers, so those 2338169701Skan must be formatted manually. For all the types we currently have, 2339169701Skan this is adequate, but formats taking pointers to functions or 2340169701Skan arrays would require the full type to be built up in order to 2341169701Skan print it with %T. */ 2342169701Skan p = (char *) alloca (pointer_count + 2); 2343169701Skan if (pointer_count == 0) 2344169701Skan p[0] = 0; 2345169701Skan else if (c_dialect_cxx ()) 2346169701Skan { 2347169701Skan memset (p, '*', pointer_count); 2348169701Skan p[pointer_count] = 0; 234990075Sobrien } 2350169701Skan else 2351169701Skan { 2352169701Skan p[0] = ' '; 2353169701Skan memset (p + 1, '*', pointer_count); 2354169701Skan p[pointer_count + 1] = 0; 2355169701Skan } 2356169701Skan if (wanted_type_name) 2357169701Skan { 2358169701Skan if (descr) 2359169701Skan warning (OPT_Wformat, "%s should have type %<%s%s%>, " 2360169701Skan "but argument %d has type %qT", 2361169701Skan descr, wanted_type_name, p, arg_num, arg_type); 2362169701Skan else 2363169701Skan warning (OPT_Wformat, "format %q.*s expects type %<%s%s%>, " 2364169701Skan "but argument %d has type %qT", 2365169701Skan format_length, format_start, wanted_type_name, p, 2366169701Skan arg_num, arg_type); 2367169701Skan } 2368169701Skan else 2369169701Skan { 2370169701Skan if (descr) 2371169701Skan warning (OPT_Wformat, "%s should have type %<%T%s%>, " 2372169701Skan "but argument %d has type %qT", 2373169701Skan descr, wanted_type, p, arg_num, arg_type); 2374169701Skan else 2375169701Skan warning (OPT_Wformat, "format %q.*s expects type %<%T%s%>, " 2376169701Skan "but argument %d has type %qT", 2377169701Skan format_length, format_start, wanted_type, p, arg_num, arg_type); 2378169701Skan } 237990075Sobrien} 2380132731Skan 2381169701Skan 2382132731Skan/* Given a format_char_info array FCI, and a character C, this function 2383132731Skan returns the index into the conversion_specs where that specifier's 2384169701Skan data is located. The character must exist. */ 2385132731Skanstatic unsigned int 2386132731Skanfind_char_info_specifier_index (const format_char_info *fci, int c) 2387132731Skan{ 2388169701Skan unsigned i; 2389169701Skan 2390169701Skan for (i = 0; fci->format_chars; i++, fci++) 2391169701Skan if (strchr (fci->format_chars, c)) 2392169701Skan return i; 2393169701Skan 2394132731Skan /* We shouldn't be looking for a non-existent specifier. */ 2395169701Skan gcc_unreachable (); 2396132731Skan} 2397132731Skan 2398132731Skan/* Given a format_length_info array FLI, and a character C, this 2399132731Skan function returns the index into the conversion_specs where that 2400169701Skan modifier's data is located. The character must exist. */ 2401132731Skanstatic unsigned int 2402132731Skanfind_length_info_modifier_index (const format_length_info *fli, int c) 2403132731Skan{ 2404169701Skan unsigned i; 2405169701Skan 2406169701Skan for (i = 0; fli->name; i++, fli++) 2407169701Skan if (strchr (fli->name, c)) 2408169701Skan return i; 2409169701Skan 2410132731Skan /* We shouldn't be looking for a non-existent modifier. */ 2411169701Skan gcc_unreachable (); 2412132731Skan} 2413132731Skan 2414132731Skan/* Determine the type of HOST_WIDE_INT in the code being compiled for 2415132731Skan use in GCC's __asm_fprintf__ custom format attribute. You must 2416132731Skan have set dynamic_format_types before calling this function. */ 2417132731Skanstatic void 2418132731Skaninit_dynamic_asm_fprintf_info (void) 2419132731Skan{ 2420132731Skan static tree hwi; 2421169701Skan 2422132731Skan if (!hwi) 2423132731Skan { 2424132731Skan format_length_info *new_asm_fprintf_length_specs; 2425132731Skan unsigned int i; 2426169701Skan 2427132731Skan /* Find the underlying type for HOST_WIDE_INT. For the %w 2428132731Skan length modifier to work, one must have issued: "typedef 2429132731Skan HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code 2430132731Skan prior to using that modifier. */ 2431146908Skan hwi = maybe_get_identifier ("__gcc_host_wide_int__"); 2432146908Skan if (!hwi) 2433146908Skan { 2434169701Skan error ("%<__gcc_host_wide_int__%> is not defined as a type"); 2435146908Skan return; 2436146908Skan } 2437146908Skan hwi = identifier_global_value (hwi); 2438146908Skan if (!hwi || TREE_CODE (hwi) != TYPE_DECL) 2439146908Skan { 2440169701Skan error ("%<__gcc_host_wide_int__%> is not defined as a type"); 2441146908Skan return; 2442146908Skan } 2443146908Skan hwi = DECL_ORIGINAL_TYPE (hwi); 2444169701Skan gcc_assert (hwi); 2445146908Skan if (hwi != long_integer_type_node && hwi != long_long_integer_type_node) 2446146908Skan { 2447169701Skan error ("%<__gcc_host_wide_int__%> is not defined as %<long%>" 2448169701Skan " or %<long long%>"); 2449146908Skan return; 2450146908Skan } 2451132731Skan 2452132731Skan /* Create a new (writable) copy of asm_fprintf_length_specs. */ 2453169701Skan new_asm_fprintf_length_specs = (format_length_info *) 2454169701Skan xmemdup (asm_fprintf_length_specs, 2455132731Skan sizeof (asm_fprintf_length_specs), 2456132731Skan sizeof (asm_fprintf_length_specs)); 2457132731Skan 2458132731Skan /* HOST_WIDE_INT must be one of 'long' or 'long long'. */ 2459132731Skan i = find_length_info_modifier_index (new_asm_fprintf_length_specs, 'w'); 2460132731Skan if (hwi == long_integer_type_node) 2461132731Skan new_asm_fprintf_length_specs[i].index = FMT_LEN_l; 2462132731Skan else if (hwi == long_long_integer_type_node) 2463132731Skan new_asm_fprintf_length_specs[i].index = FMT_LEN_ll; 2464132731Skan else 2465169701Skan gcc_unreachable (); 2466132731Skan 2467132731Skan /* Assign the new data for use. */ 2468132731Skan dynamic_format_types[asm_fprintf_format_type].length_char_specs = 2469132731Skan new_asm_fprintf_length_specs; 2470132731Skan } 2471132731Skan} 2472132731Skan 2473169701Skan/* Determine the type of a "locus" in the code being compiled for use 2474169701Skan in GCC's __gcc_gfc__ custom format attribute. You must have set 2475169701Skan dynamic_format_types before calling this function. */ 2476169701Skanstatic void 2477169701Skaninit_dynamic_gfc_info (void) 2478169701Skan{ 2479169701Skan static tree locus; 2480169701Skan 2481169701Skan if (!locus) 2482169701Skan { 2483169701Skan static format_char_info *gfc_fci; 2484169701Skan 2485169701Skan /* For the GCC __gcc_gfc__ custom format specifier to work, one 2486169701Skan must have declared 'locus' prior to using this attribute. If 2487169701Skan we haven't seen this declarations then you shouldn't use the 2488169701Skan specifier requiring that type. */ 2489169701Skan if ((locus = maybe_get_identifier ("locus"))) 2490169701Skan { 2491169701Skan locus = identifier_global_value (locus); 2492169701Skan if (locus) 2493169701Skan { 2494169701Skan if (TREE_CODE (locus) != TYPE_DECL) 2495169701Skan { 2496169701Skan error ("%<locus%> is not defined as a type"); 2497169701Skan locus = 0; 2498169701Skan } 2499169701Skan else 2500169701Skan locus = TREE_TYPE (locus); 2501169701Skan } 2502169701Skan } 2503169701Skan 2504169701Skan /* Assign the new data for use. */ 2505169701Skan 2506169701Skan /* Handle the __gcc_gfc__ format specifics. */ 2507169701Skan if (!gfc_fci) 2508169701Skan dynamic_format_types[gcc_gfc_format_type].conversion_specs = 2509169701Skan gfc_fci = (format_char_info *) 2510169701Skan xmemdup (gcc_gfc_char_table, 2511169701Skan sizeof (gcc_gfc_char_table), 2512169701Skan sizeof (gcc_gfc_char_table)); 2513169701Skan if (locus) 2514169701Skan { 2515169701Skan const unsigned i = find_char_info_specifier_index (gfc_fci, 'L'); 2516169701Skan gfc_fci[i].types[0].type = &locus; 2517169701Skan gfc_fci[i].pointer_count = 1; 2518169701Skan } 2519169701Skan } 2520169701Skan} 2521169701Skan 2522132731Skan/* Determine the types of "tree" and "location_t" in the code being 2523132731Skan compiled for use in GCC's diagnostic custom format attributes. You 2524132731Skan must have set dynamic_format_types before calling this function. */ 2525132731Skanstatic void 2526132731Skaninit_dynamic_diag_info (void) 2527132731Skan{ 2528132731Skan static tree t, loc, hwi; 2529169701Skan 2530132731Skan if (!loc || !t || !hwi) 2531132731Skan { 2532169701Skan static format_char_info *diag_fci, *tdiag_fci, *cdiag_fci, *cxxdiag_fci; 2533132731Skan static format_length_info *diag_ls; 2534132731Skan unsigned int i; 2535132731Skan 2536132731Skan /* For the GCC-diagnostics custom format specifiers to work, one 2537169701Skan must have declared 'tree' and/or 'location_t' prior to using 2538132731Skan those attributes. If we haven't seen these declarations then 2539132731Skan you shouldn't use the specifiers requiring these types. 2540132731Skan However we don't force a hard ICE because we may see only one 2541132731Skan or the other type. */ 2542132731Skan if ((loc = maybe_get_identifier ("location_t"))) 2543146908Skan { 2544146908Skan loc = identifier_global_value (loc); 2545146908Skan if (loc) 2546146908Skan { 2547146908Skan if (TREE_CODE (loc) != TYPE_DECL) 2548146908Skan { 2549169701Skan error ("%<location_t%> is not defined as a type"); 2550146908Skan loc = 0; 2551146908Skan } 2552146908Skan else 2553146908Skan loc = TREE_TYPE (loc); 2554146908Skan } 2555146908Skan } 2556132731Skan 2557169701Skan /* We need to grab the underlying 'union tree_node' so peek into 2558132731Skan an extra type level. */ 2559132731Skan if ((t = maybe_get_identifier ("tree"))) 2560146908Skan { 2561146908Skan t = identifier_global_value (t); 2562146908Skan if (t) 2563146908Skan { 2564146908Skan if (TREE_CODE (t) != TYPE_DECL) 2565146908Skan { 2566169701Skan error ("%<tree%> is not defined as a type"); 2567146908Skan t = 0; 2568146908Skan } 2569146908Skan else if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) 2570146908Skan { 2571169701Skan error ("%<tree%> is not defined as a pointer type"); 2572146908Skan t = 0; 2573146908Skan } 2574146908Skan else 2575146908Skan t = TREE_TYPE (TREE_TYPE (t)); 2576146908Skan } 2577146908Skan } 2578169701Skan 2579132731Skan /* Find the underlying type for HOST_WIDE_INT. For the %w 2580132731Skan length modifier to work, one must have issued: "typedef 2581132731Skan HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code 2582132731Skan prior to using that modifier. */ 2583132731Skan if ((hwi = maybe_get_identifier ("__gcc_host_wide_int__"))) 2584146908Skan { 2585146908Skan hwi = identifier_global_value (hwi); 2586146908Skan if (hwi) 2587146908Skan { 2588146908Skan if (TREE_CODE (hwi) != TYPE_DECL) 2589146908Skan { 2590169701Skan error ("%<__gcc_host_wide_int__%> is not defined as a type"); 2591146908Skan hwi = 0; 2592146908Skan } 2593146908Skan else 2594146908Skan { 2595146908Skan hwi = DECL_ORIGINAL_TYPE (hwi); 2596169701Skan gcc_assert (hwi); 2597146908Skan if (hwi != long_integer_type_node 2598146908Skan && hwi != long_long_integer_type_node) 2599146908Skan { 2600169701Skan error ("%<__gcc_host_wide_int__%> is not defined" 2601169701Skan " as %<long%> or %<long long%>"); 2602146908Skan hwi = 0; 2603146908Skan } 2604146908Skan } 2605146908Skan } 2606146908Skan } 2607169701Skan 2608132731Skan /* Assign the new data for use. */ 2609132731Skan 2610132731Skan /* All the GCC diag formats use the same length specs. */ 2611169701Skan if (!diag_ls) 2612132731Skan dynamic_format_types[gcc_diag_format_type].length_char_specs = 2613169701Skan dynamic_format_types[gcc_tdiag_format_type].length_char_specs = 2614132731Skan dynamic_format_types[gcc_cdiag_format_type].length_char_specs = 2615132731Skan dynamic_format_types[gcc_cxxdiag_format_type].length_char_specs = 2616169701Skan diag_ls = (format_length_info *) 2617169701Skan xmemdup (gcc_diag_length_specs, 2618132731Skan sizeof (gcc_diag_length_specs), 2619169701Skan sizeof (gcc_diag_length_specs)); 2620132731Skan if (hwi) 2621169701Skan { 2622132731Skan /* HOST_WIDE_INT must be one of 'long' or 'long long'. */ 2623132731Skan i = find_length_info_modifier_index (diag_ls, 'w'); 2624132731Skan if (hwi == long_integer_type_node) 2625132731Skan diag_ls[i].index = FMT_LEN_l; 2626132731Skan else if (hwi == long_long_integer_type_node) 2627132731Skan diag_ls[i].index = FMT_LEN_ll; 2628132731Skan else 2629169701Skan gcc_unreachable (); 2630132731Skan } 2631132731Skan 2632132731Skan /* Handle the __gcc_diag__ format specifics. */ 2633169701Skan if (!diag_fci) 2634132731Skan dynamic_format_types[gcc_diag_format_type].conversion_specs = 2635169701Skan diag_fci = (format_char_info *) 2636169701Skan xmemdup (gcc_diag_char_table, 2637169701Skan sizeof (gcc_diag_char_table), 2638169701Skan sizeof (gcc_diag_char_table)); 2639132731Skan if (loc) 2640169701Skan { 2641132731Skan i = find_char_info_specifier_index (diag_fci, 'H'); 2642132731Skan diag_fci[i].types[0].type = &loc; 2643132731Skan diag_fci[i].pointer_count = 1; 2644132731Skan } 2645132731Skan if (t) 2646169701Skan { 2647132731Skan i = find_char_info_specifier_index (diag_fci, 'J'); 2648132731Skan diag_fci[i].types[0].type = &t; 2649132731Skan diag_fci[i].pointer_count = 1; 2650132731Skan } 2651132731Skan 2652169701Skan /* Handle the __gcc_tdiag__ format specifics. */ 2653169701Skan if (!tdiag_fci) 2654169701Skan dynamic_format_types[gcc_tdiag_format_type].conversion_specs = 2655169701Skan tdiag_fci = (format_char_info *) 2656169701Skan xmemdup (gcc_tdiag_char_table, 2657169701Skan sizeof (gcc_tdiag_char_table), 2658169701Skan sizeof (gcc_tdiag_char_table)); 2659169701Skan if (loc) 2660169701Skan { 2661169701Skan i = find_char_info_specifier_index (tdiag_fci, 'H'); 2662169701Skan tdiag_fci[i].types[0].type = &loc; 2663169701Skan tdiag_fci[i].pointer_count = 1; 2664169701Skan } 2665169701Skan if (t) 2666169701Skan { 2667169701Skan /* All specifiers taking a tree share the same struct. */ 2668169701Skan i = find_char_info_specifier_index (tdiag_fci, 'D'); 2669169701Skan tdiag_fci[i].types[0].type = &t; 2670169701Skan tdiag_fci[i].pointer_count = 1; 2671169701Skan i = find_char_info_specifier_index (tdiag_fci, 'J'); 2672169701Skan tdiag_fci[i].types[0].type = &t; 2673169701Skan tdiag_fci[i].pointer_count = 1; 2674169701Skan } 2675169701Skan 2676132731Skan /* Handle the __gcc_cdiag__ format specifics. */ 2677169701Skan if (!cdiag_fci) 2678132731Skan dynamic_format_types[gcc_cdiag_format_type].conversion_specs = 2679169701Skan cdiag_fci = (format_char_info *) 2680169701Skan xmemdup (gcc_cdiag_char_table, 2681169701Skan sizeof (gcc_cdiag_char_table), 2682169701Skan sizeof (gcc_cdiag_char_table)); 2683132731Skan if (loc) 2684169701Skan { 2685132731Skan i = find_char_info_specifier_index (cdiag_fci, 'H'); 2686132731Skan cdiag_fci[i].types[0].type = &loc; 2687132731Skan cdiag_fci[i].pointer_count = 1; 2688132731Skan } 2689132731Skan if (t) 2690169701Skan { 2691132731Skan /* All specifiers taking a tree share the same struct. */ 2692132731Skan i = find_char_info_specifier_index (cdiag_fci, 'D'); 2693132731Skan cdiag_fci[i].types[0].type = &t; 2694132731Skan cdiag_fci[i].pointer_count = 1; 2695132731Skan i = find_char_info_specifier_index (cdiag_fci, 'J'); 2696132731Skan cdiag_fci[i].types[0].type = &t; 2697132731Skan cdiag_fci[i].pointer_count = 1; 2698132731Skan } 2699132731Skan 2700132731Skan /* Handle the __gcc_cxxdiag__ format specifics. */ 2701169701Skan if (!cxxdiag_fci) 2702132731Skan dynamic_format_types[gcc_cxxdiag_format_type].conversion_specs = 2703169701Skan cxxdiag_fci = (format_char_info *) 2704169701Skan xmemdup (gcc_cxxdiag_char_table, 2705169701Skan sizeof (gcc_cxxdiag_char_table), 2706169701Skan sizeof (gcc_cxxdiag_char_table)); 2707132731Skan if (loc) 2708169701Skan { 2709132731Skan i = find_char_info_specifier_index (cxxdiag_fci, 'H'); 2710132731Skan cxxdiag_fci[i].types[0].type = &loc; 2711132731Skan cxxdiag_fci[i].pointer_count = 1; 2712132731Skan } 2713132731Skan if (t) 2714169701Skan { 2715132731Skan /* All specifiers taking a tree share the same struct. */ 2716132731Skan i = find_char_info_specifier_index (cxxdiag_fci, 'D'); 2717132731Skan cxxdiag_fci[i].types[0].type = &t; 2718132731Skan cxxdiag_fci[i].pointer_count = 1; 2719132731Skan i = find_char_info_specifier_index (cxxdiag_fci, 'J'); 2720132731Skan cxxdiag_fci[i].types[0].type = &t; 2721132731Skan cxxdiag_fci[i].pointer_count = 1; 2722132731Skan } 2723132731Skan } 2724132731Skan} 2725132731Skan 2726169701Skan#ifdef TARGET_FORMAT_TYPES 2727169701Skanextern const format_kind_info TARGET_FORMAT_TYPES[]; 2728169701Skan#endif 2729169701Skan 2730132731Skan/* Handle a "format" attribute; arguments as in 2731132731Skan struct attribute_spec.handler. */ 2732132731Skantree 2733169701Skanhandle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args, 2734132731Skan int flags, bool *no_add_attrs) 2735132731Skan{ 2736132731Skan tree type = *node; 2737132731Skan function_format_info info; 2738132731Skan tree argument; 2739132731Skan 2740169701Skan#ifdef TARGET_FORMAT_TYPES 2741169701Skan /* If the target provides additional format types, we need to 2742169701Skan add them to FORMAT_TYPES at first use. */ 2743169701Skan if (TARGET_FORMAT_TYPES != NULL && !dynamic_format_types) 2744169701Skan { 2745169701Skan dynamic_format_types = xmalloc ((n_format_types + TARGET_N_FORMAT_TYPES) 2746169701Skan * sizeof (dynamic_format_types[0])); 2747169701Skan memcpy (dynamic_format_types, format_types_orig, 2748169701Skan sizeof (format_types_orig)); 2749169701Skan memcpy (&dynamic_format_types[n_format_types], TARGET_FORMAT_TYPES, 2750169701Skan TARGET_N_FORMAT_TYPES * sizeof (dynamic_format_types[0])); 2751169701Skan 2752169701Skan format_types = dynamic_format_types; 2753169701Skan n_format_types += TARGET_N_FORMAT_TYPES; 2754169701Skan } 2755169701Skan#endif 2756169701Skan 2757132731Skan if (!decode_format_attr (args, &info, 0)) 2758132731Skan { 2759132731Skan *no_add_attrs = true; 2760132731Skan return NULL_TREE; 2761132731Skan } 2762132731Skan 2763132731Skan argument = TYPE_ARG_TYPES (type); 2764132731Skan if (argument) 2765132731Skan { 2766132731Skan if (!check_format_string (argument, info.format_num, flags, 2767132731Skan no_add_attrs)) 2768132731Skan return NULL_TREE; 2769132731Skan 2770132731Skan if (info.first_arg_num != 0) 2771132731Skan { 2772132731Skan unsigned HOST_WIDE_INT arg_num = 1; 2773132731Skan 2774132731Skan /* Verify that first_arg_num points to the last arg, 2775132731Skan the ... */ 2776132731Skan while (argument) 2777132731Skan arg_num++, argument = TREE_CHAIN (argument); 2778132731Skan 2779132731Skan if (arg_num != info.first_arg_num) 2780132731Skan { 2781132731Skan if (!(flags & (int) ATTR_FLAG_BUILT_IN)) 2782169701Skan error ("args to be formatted is not %<...%>"); 2783132731Skan *no_add_attrs = true; 2784132731Skan return NULL_TREE; 2785132731Skan } 2786132731Skan } 2787132731Skan } 2788132731Skan 2789132731Skan if (info.format_type == strftime_format_type && info.first_arg_num != 0) 2790132731Skan { 2791132731Skan error ("strftime formats cannot format arguments"); 2792132731Skan *no_add_attrs = true; 2793132731Skan return NULL_TREE; 2794132731Skan } 2795132731Skan 2796132731Skan /* If this is a custom GCC-internal format type, we have to 2797132731Skan initialize certain bits a runtime. */ 2798132731Skan if (info.format_type == asm_fprintf_format_type 2799169701Skan || info.format_type == gcc_gfc_format_type 2800132731Skan || info.format_type == gcc_diag_format_type 2801169701Skan || info.format_type == gcc_tdiag_format_type 2802132731Skan || info.format_type == gcc_cdiag_format_type 2803132731Skan || info.format_type == gcc_cxxdiag_format_type) 2804132731Skan { 2805132731Skan /* Our first time through, we have to make sure that our 2806169701Skan format_type data is allocated dynamically and is modifiable. */ 2807132731Skan if (!dynamic_format_types) 2808169701Skan format_types = dynamic_format_types = (format_kind_info *) 2809132731Skan xmemdup (format_types_orig, sizeof (format_types_orig), 2810132731Skan sizeof (format_types_orig)); 2811132731Skan 2812132731Skan /* If this is format __asm_fprintf__, we have to initialize 2813169701Skan GCC's notion of HOST_WIDE_INT for checking %wd. */ 2814132731Skan if (info.format_type == asm_fprintf_format_type) 2815169701Skan init_dynamic_asm_fprintf_info (); 2816169701Skan /* If this is format __gcc_gfc__, we have to initialize GCC's 2817169701Skan notion of 'locus' at runtime for %L. */ 2818169701Skan else if (info.format_type == gcc_gfc_format_type) 2819169701Skan init_dynamic_gfc_info (); 2820132731Skan /* If this is one of the diagnostic attributes, then we have to 2821169701Skan initialize 'location_t' and 'tree' at runtime. */ 2822132731Skan else if (info.format_type == gcc_diag_format_type 2823169701Skan || info.format_type == gcc_tdiag_format_type 2824132731Skan || info.format_type == gcc_cdiag_format_type 2825132731Skan || info.format_type == gcc_cxxdiag_format_type) 2826169701Skan init_dynamic_diag_info (); 2827132731Skan else 2828169701Skan gcc_unreachable (); 2829132731Skan } 2830132731Skan 2831132731Skan return NULL_TREE; 2832132731Skan} 2833