00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "config.h"
00027 #include "system.h"
00028 #ifdef SGI_MONGOOSE
00029
00030 #include "rtl.h"
00031 #endif
00032 #include "tree.h"
00033 #include "flags.h"
00034 #include "toplev.h"
00035 #include "c-common.h"
00036 #include "intl.h"
00037 #include "diagnostic.h"
00038 #include "langhooks.h"
00039
00040
00041
00042 void
00043 set_Wformat (setting)
00044 int setting;
00045 {
00046 warn_format = setting;
00047 warn_format_y2k = setting;
00048 warn_format_extra_args = setting;
00049 warn_format_zero_length = setting;
00050 if (setting != 1)
00051 {
00052 warn_format_nonliteral = setting;
00053 warn_format_security = setting;
00054 }
00055
00056 if (setting)
00057 warn_nonnull = setting;
00058 }
00059
00060
00061
00062
00063
00064
00065 enum format_type { printf_format_type, scanf_format_type,
00066 strftime_format_type, strfmon_format_type,
00067 format_type_error };
00068
00069 typedef struct function_format_info
00070 {
00071 enum format_type format_type;
00072 unsigned HOST_WIDE_INT format_num;
00073 unsigned HOST_WIDE_INT first_arg_num;
00074 } function_format_info;
00075
00076 static bool decode_format_attr PARAMS ((tree,
00077 function_format_info *, int));
00078 static enum format_type decode_format_type PARAMS ((const char *));
00079
00080
00081
00082 tree
00083 handle_format_attribute (node, name, args, flags, no_add_attrs)
00084 tree *node;
00085 tree name ATTRIBUTE_UNUSED;
00086 tree args;
00087 int flags;
00088 bool *no_add_attrs;
00089 {
00090 tree type = *node;
00091 function_format_info info;
00092 tree argument;
00093 unsigned HOST_WIDE_INT arg_num;
00094
00095 if (!decode_format_attr (args, &info, 0))
00096 {
00097 *no_add_attrs = true;
00098 return NULL_TREE;
00099 }
00100
00101
00102
00103
00104 argument = TYPE_ARG_TYPES (type);
00105 if (argument)
00106 {
00107 for (arg_num = 1; argument != 0 && arg_num != info.format_num;
00108 ++arg_num, argument = TREE_CHAIN (argument))
00109 ;
00110
00111 if (! argument
00112 || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
00113 || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
00114 != char_type_node))
00115 {
00116 if (!(flags & (int) ATTR_FLAG_BUILT_IN))
00117 error ("format string arg not a string type");
00118 *no_add_attrs = true;
00119 return NULL_TREE;
00120 }
00121
00122 else if (info.first_arg_num != 0)
00123 {
00124
00125
00126 while (argument)
00127 arg_num++, argument = TREE_CHAIN (argument);
00128
00129 if (arg_num != info.first_arg_num)
00130 {
00131 if (!(flags & (int) ATTR_FLAG_BUILT_IN))
00132 error ("args to be formatted is not '...'");
00133 *no_add_attrs = true;
00134 return NULL_TREE;
00135 }
00136 }
00137 }
00138
00139 if (info.format_type == strftime_format_type && info.first_arg_num != 0)
00140 {
00141 error ("strftime formats cannot format arguments");
00142 *no_add_attrs = true;
00143 return NULL_TREE;
00144 }
00145
00146 return NULL_TREE;
00147 }
00148
00149
00150
00151
00152 tree
00153 handle_format_arg_attribute (node, name, args, flags, no_add_attrs)
00154 tree *node;
00155 tree name ATTRIBUTE_UNUSED;
00156 tree args;
00157 int flags;
00158 bool *no_add_attrs;
00159 {
00160 tree type = *node;
00161 tree format_num_expr = TREE_VALUE (args);
00162 unsigned HOST_WIDE_INT format_num;
00163 unsigned HOST_WIDE_INT arg_num;
00164 tree argument;
00165
00166
00167
00168 while (TREE_CODE (format_num_expr) == NOP_EXPR
00169 || TREE_CODE (format_num_expr) == CONVERT_EXPR
00170 || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
00171 format_num_expr = TREE_OPERAND (format_num_expr, 0);
00172
00173 if (TREE_CODE (format_num_expr) != INTEGER_CST
00174 || TREE_INT_CST_HIGH (format_num_expr) != 0)
00175 {
00176 error ("format string has invalid operand number");
00177 *no_add_attrs = true;
00178 return NULL_TREE;
00179 }
00180
00181 format_num = TREE_INT_CST_LOW (format_num_expr);
00182
00183
00184
00185
00186 argument = TYPE_ARG_TYPES (type);
00187 if (argument)
00188 {
00189 for (arg_num = 1; argument != 0 && arg_num != format_num;
00190 ++arg_num, argument = TREE_CHAIN (argument))
00191 ;
00192
00193 if (! argument
00194 || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
00195 || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
00196 != char_type_node))
00197 {
00198 if (!(flags & (int) ATTR_FLAG_BUILT_IN))
00199 error ("format string arg not a string type");
00200 *no_add_attrs = true;
00201 return NULL_TREE;
00202 }
00203 }
00204
00205 if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
00206 || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
00207 != char_type_node))
00208 {
00209 if (!(flags & (int) ATTR_FLAG_BUILT_IN))
00210 error ("function does not return string type");
00211 *no_add_attrs = true;
00212 return NULL_TREE;
00213 }
00214
00215 return NULL_TREE;
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 static bool
00227 decode_format_attr (args, info, validated_p)
00228 tree args;
00229 function_format_info *info;
00230 int validated_p;
00231 {
00232 tree format_type_id = TREE_VALUE (args);
00233 tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
00234 tree first_arg_num_expr
00235 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
00236
00237 if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
00238 {
00239 if (validated_p)
00240 abort ();
00241 error ("unrecognized format specifier");
00242 return false;
00243 }
00244 else
00245 {
00246 const char *p = IDENTIFIER_POINTER (format_type_id);
00247
00248 info->format_type = decode_format_type (p);
00249
00250 if (info->format_type == format_type_error)
00251 {
00252 if (validated_p)
00253 abort ();
00254 warning ("`%s' is an unrecognized format function type", p);
00255 return false;
00256 }
00257 }
00258
00259
00260
00261 while (TREE_CODE (format_num_expr) == NOP_EXPR
00262 || TREE_CODE (format_num_expr) == CONVERT_EXPR
00263 || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
00264 format_num_expr = TREE_OPERAND (format_num_expr, 0);
00265
00266 while (TREE_CODE (first_arg_num_expr) == NOP_EXPR
00267 || TREE_CODE (first_arg_num_expr) == CONVERT_EXPR
00268 || TREE_CODE (first_arg_num_expr) == NON_LVALUE_EXPR)
00269 first_arg_num_expr = TREE_OPERAND (first_arg_num_expr, 0);
00270
00271 if (TREE_CODE (format_num_expr) != INTEGER_CST
00272 || TREE_INT_CST_HIGH (format_num_expr) != 0
00273 || TREE_CODE (first_arg_num_expr) != INTEGER_CST
00274 || TREE_INT_CST_HIGH (first_arg_num_expr) != 0)
00275 {
00276 if (validated_p)
00277 abort ();
00278 error ("format string has invalid operand number");
00279 return false;
00280 }
00281
00282 info->format_num = TREE_INT_CST_LOW (format_num_expr);
00283 info->first_arg_num = TREE_INT_CST_LOW (first_arg_num_expr);
00284 if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num)
00285 {
00286 if (validated_p)
00287 abort ();
00288 error ("format string arg follows the args to be formatted");
00289 return false;
00290 }
00291
00292 return true;
00293 }
00294
00295
00296
00297
00298
00299 enum format_lengths
00300 {
00301 FMT_LEN_none,
00302 FMT_LEN_hh,
00303 FMT_LEN_h,
00304 FMT_LEN_l,
00305 FMT_LEN_ll,
00306 FMT_LEN_L,
00307 FMT_LEN_z,
00308 FMT_LEN_t,
00309 FMT_LEN_j,
00310 FMT_LEN_MAX
00311 };
00312
00313
00314
00315 enum format_std_version
00316 {
00317 STD_C89,
00318 STD_C94,
00319 STD_C9L,
00320 STD_C99,
00321 STD_EXT
00322 };
00323
00324
00325
00326 #define CPLUSPLUS_STD_VER STD_C94
00327
00328 #define C_STD_VER ((int)(c_language == clk_cplusplus \
00329 ? CPLUSPLUS_STD_VER \
00330 : (flag_isoc99 \
00331 ? STD_C99 \
00332 : (flag_isoc94 ? STD_C94 : STD_C89))))
00333
00334
00335
00336 #define C_STD_NAME(FEATURE_VER) (c_language == clk_cplusplus \
00337 ? "ISO C++" \
00338 : ((FEATURE_VER) == STD_EXT \
00339 ? "ISO C" \
00340 : "ISO C90"))
00341
00342
00343 #define ADJ_STD(VER) ((int)((VER) == STD_C9L \
00344 ? (warn_long_long ? STD_C99 : STD_C89) \
00345 : (VER)))
00346
00347
00348 enum
00349 {
00350
00351
00352 FMT_FLAG_ARG_CONVERT = 1,
00353
00354 FMT_FLAG_SCANF_A_KLUDGE = 2,
00355
00356
00357 FMT_FLAG_FANCY_PERCENT_OK = 4,
00358
00359
00360 FMT_FLAG_DOLLAR_MULTIPLE = 8,
00361
00362 FMT_FLAG_USE_DOLLAR = 16,
00363
00364 FMT_FLAG_ZERO_WIDTH_BAD = 32,
00365
00366 FMT_FLAG_EMPTY_PREC_OK = 64,
00367
00368
00369 FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128
00370
00371
00372
00373
00374 };
00375
00376
00377
00378
00379 typedef struct
00380 {
00381
00382 const char *const name;
00383
00384 const enum format_lengths index;
00385
00386 const enum format_std_version std;
00387
00388 const char *const double_name;
00389 const enum format_lengths double_index;
00390 const enum format_std_version double_std;
00391 } format_length_info;
00392
00393
00394
00395
00396 typedef struct
00397 {
00398
00399
00400
00401 enum format_std_version std;
00402
00403
00404 const char *name;
00405
00406 tree *type;
00407 } format_type_detail;
00408
00409
00410
00411 #define BADLEN { 0, NULL, NULL }
00412 #define NOLENGTHS { BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }
00413
00414
00415
00416
00417 typedef struct
00418 {
00419 const char *const format_chars;
00420 const int pointer_count;
00421 const enum format_std_version std;
00422
00423 const format_type_detail types[FMT_LEN_MAX];
00424
00425
00426
00427
00428
00429
00430 const char *const flag_chars;
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 const char *const flags2;
00441 } format_char_info;
00442
00443
00444
00445 typedef struct
00446 {
00447
00448 const int flag_char;
00449
00450
00451
00452
00453
00454
00455
00456
00457 const int predicate;
00458
00459
00460 const int skip_next_char;
00461
00462
00463 const char *const name;
00464
00465
00466 const char *const long_name;
00467
00468 const enum format_std_version std;
00469 } format_flag_spec;
00470
00471
00472
00473
00474 typedef struct
00475 {
00476
00477 const int flag_char1;
00478
00479 const int flag_char2;
00480
00481
00482 const int ignored;
00483
00484
00485
00486 const int predicate;
00487 } format_flag_pair;
00488
00489
00490
00491 typedef struct
00492 {
00493
00494
00495 const char *const name;
00496
00497 const format_length_info *const length_char_specs;
00498
00499 const format_char_info *const conversion_specs;
00500
00501 const char *const flag_chars;
00502
00503 const char *const modifier_chars;
00504
00505 const format_flag_spec *const flag_specs;
00506
00507 const format_flag_pair *const bad_flag_pairs;
00508
00509 const int flags;
00510
00511 const int width_char;
00512
00513
00514 const int left_precision_char;
00515
00516
00517 const int precision_char;
00518
00519
00520 const int suppression_char;
00521
00522
00523
00524
00525 const int length_code_char;
00526
00527
00528 tree *const width_type;
00529
00530
00531 tree *const precision_type;
00532 } format_kind_info;
00533
00534
00535
00536
00537 typedef struct format_wanted_type
00538 {
00539
00540 tree wanted_type;
00541
00542 const char *wanted_type_name;
00543
00544 int pointer_count;
00545
00546
00547 int char_lenient_flag;
00548
00549
00550 int writing_in_flag;
00551
00552
00553 int reading_from_flag;
00554
00555
00556
00557
00558
00559
00560 const char *name;
00561
00562 tree param;
00563
00564 int arg_num;
00565
00566 struct format_wanted_type *next;
00567 } format_wanted_type;
00568
00569
00570 static const format_length_info printf_length_specs[] =
00571 {
00572 { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
00573 { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L },
00574 { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
00575 { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
00576 { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 },
00577 { "Z", FMT_LEN_z, STD_EXT, NULL, 0, 0 },
00578 { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 },
00579 { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 },
00580 { NULL, 0, 0, NULL, 0, 0 }
00581 };
00582
00583
00584
00585 static const format_length_info scanf_length_specs[] =
00586 {
00587 { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
00588 { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L },
00589 { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
00590 { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
00591 { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 },
00592 { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 },
00593 { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 },
00594 { NULL, 0, 0, NULL, 0, 0 }
00595 };
00596
00597
00598
00599
00600 static const format_length_info strfmon_length_specs[] =
00601 {
00602
00603 { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
00604 { NULL, 0, 0, NULL, 0, 0 }
00605 };
00606
00607 static const format_flag_spec printf_flag_specs[] =
00608 {
00609 { ' ', 0, 0, N_("` ' flag"), N_("the ` ' printf flag"), STD_C89 },
00610 { '+', 0, 0, N_("`+' flag"), N_("the `+' printf flag"), STD_C89 },
00611 { '#', 0, 0, N_("`#' flag"), N_("the `#' printf flag"), STD_C89 },
00612 { '0', 0, 0, N_("`0' flag"), N_("the `0' printf flag"), STD_C89 },
00613 { '-', 0, 0, N_("`-' flag"), N_("the `-' printf flag"), STD_C89 },
00614 { '\'', 0, 0, N_("`'' flag"), N_("the `'' printf flag"), STD_EXT },
00615 { 'I', 0, 0, N_("`I' flag"), N_("the `I' printf flag"), STD_EXT },
00616 { 'w', 0, 0, N_("field width"), N_("field width in printf format"), STD_C89 },
00617 { 'p', 0, 0, N_("precision"), N_("precision in printf format"), STD_C89 },
00618 { 'L', 0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
00619 { 0, 0, 0, NULL, NULL, 0 }
00620 };
00621
00622
00623 static const format_flag_pair printf_flag_pairs[] =
00624 {
00625 { ' ', '+', 1, 0 },
00626 { '0', '-', 1, 0 },
00627 { '0', 'p', 1, 'i' },
00628 { 0, 0, 0, 0 }
00629 };
00630
00631
00632 static const format_flag_spec scanf_flag_specs[] =
00633 {
00634 { '*', 0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
00635 { 'a', 0, 0, N_("`a' flag"), N_("the `a' scanf flag"), STD_EXT },
00636 { 'w', 0, 0, N_("field width"), N_("field width in scanf format"), STD_C89 },
00637 { 'L', 0, 0, N_("length modifier"), N_("length modifier in scanf format"), STD_C89 },
00638 { '\'', 0, 0, N_("`'' flag"), N_("the `'' scanf flag"), STD_EXT },
00639 { 'I', 0, 0, N_("`I' flag"), N_("the `I' scanf flag"), STD_EXT },
00640 { 0, 0, 0, NULL, NULL, 0 }
00641 };
00642
00643
00644 static const format_flag_pair scanf_flag_pairs[] =
00645 {
00646 { '*', 'L', 0, 0 },
00647 { 0, 0, 0, 0 }
00648 };
00649
00650
00651 static const format_flag_spec strftime_flag_specs[] =
00652 {
00653 { '_', 0, 0, N_("`_' flag"), N_("the `_' strftime flag"), STD_EXT },
00654 { '-', 0, 0, N_("`-' flag"), N_("the `-' strftime flag"), STD_EXT },
00655 { '0', 0, 0, N_("`0' flag"), N_("the `0' strftime flag"), STD_EXT },
00656 { '^', 0, 0, N_("`^' flag"), N_("the `^' strftime flag"), STD_EXT },
00657 { '#', 0, 0, N_("`#' flag"), N_("the `#' strftime flag"), STD_EXT },
00658 { 'w', 0, 0, N_("field width"), N_("field width in strftime format"), STD_EXT },
00659 { 'E', 0, 0, N_("`E' modifier"), N_("the `E' strftime modifier"), STD_C99 },
00660 { 'O', 0, 0, N_("`O' modifier"), N_("the `O' strftime modifier"), STD_C99 },
00661 { 'O', 'o', 0, NULL, N_("the `O' modifier"), STD_EXT },
00662 { 0, 0, 0, NULL, NULL, 0 }
00663 };
00664
00665
00666 static const format_flag_pair strftime_flag_pairs[] =
00667 {
00668 { 'E', 'O', 0, 0 },
00669 { '_', '-', 0, 0 },
00670 { '_', '0', 0, 0 },
00671 { '-', '0', 0, 0 },
00672 { '^', '#', 0, 0 },
00673 { 0, 0, 0, 0 }
00674 };
00675
00676
00677 static const format_flag_spec strfmon_flag_specs[] =
00678 {
00679 { '=', 0, 1, N_("fill character"), N_("fill character in strfmon format"), STD_C89 },
00680 { '^', 0, 0, N_("`^' flag"), N_("the `^' strfmon flag"), STD_C89 },
00681 { '+', 0, 0, N_("`+' flag"), N_("the `+' strfmon flag"), STD_C89 },
00682 { '(', 0, 0, N_("`(' flag"), N_("the `(' strfmon flag"), STD_C89 },
00683 { '!', 0, 0, N_("`!' flag"), N_("the `!' strfmon flag"), STD_C89 },
00684 { '-', 0, 0, N_("`-' flag"), N_("the `-' strfmon flag"), STD_C89 },
00685 { 'w', 0, 0, N_("field width"), N_("field width in strfmon format"), STD_C89 },
00686 { '#', 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 },
00687 { 'p', 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 },
00688 { 'L', 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 },
00689 { 0, 0, 0, NULL, NULL, 0 }
00690 };
00691
00692 static const format_flag_pair strfmon_flag_pairs[] =
00693 {
00694 { '+', '(', 0, 0 },
00695 { 0, 0, 0, 0 }
00696 };
00697
00698
00699 #define T_I &integer_type_node
00700 #define T89_I { STD_C89, NULL, T_I }
00701 #define T_L &long_integer_type_node
00702 #define T89_L { STD_C89, NULL, T_L }
00703 #define T_LL &long_long_integer_type_node
00704 #define T9L_LL { STD_C9L, NULL, T_LL }
00705 #define TEX_LL { STD_EXT, NULL, T_LL }
00706 #define T_S &short_integer_type_node
00707 #define T89_S { STD_C89, NULL, T_S }
00708 #define T_UI &unsigned_type_node
00709 #define T89_UI { STD_C89, NULL, T_UI }
00710 #define T_UL &long_unsigned_type_node
00711 #define T89_UL { STD_C89, NULL, T_UL }
00712 #define T_ULL &long_long_unsigned_type_node
00713 #define T9L_ULL { STD_C9L, NULL, T_ULL }
00714 #define TEX_ULL { STD_EXT, NULL, T_ULL }
00715 #define T_US &short_unsigned_type_node
00716 #define T89_US { STD_C89, NULL, T_US }
00717 #define T_F &float_type_node
00718 #define T89_F { STD_C89, NULL, T_F }
00719 #define T99_F { STD_C99, NULL, T_F }
00720 #define T_D &double_type_node
00721 #define T89_D { STD_C89, NULL, T_D }
00722 #define T99_D { STD_C99, NULL, T_D }
00723 #define T_LD &long_double_type_node
00724 #define T89_LD { STD_C89, NULL, T_LD }
00725 #define T99_LD { STD_C99, NULL, T_LD }
00726 #define T_C &char_type_node
00727 #define T89_C { STD_C89, NULL, T_C }
00728 #define T_SC &signed_char_type_node
00729 #define T99_SC { STD_C99, NULL, T_SC }
00730 #define T_UC &unsigned_char_type_node
00731 #define T99_UC { STD_C99, NULL, T_UC }
00732 #define T_V &void_type_node
00733 #define T89_V { STD_C89, NULL, T_V }
00734 #define T_W &wchar_type_node
00735 #define T94_W { STD_C94, "wchar_t", T_W }
00736 #define TEX_W { STD_EXT, "wchar_t", T_W }
00737 #define T_WI &wint_type_node
00738 #define T94_WI { STD_C94, "wint_t", T_WI }
00739 #define TEX_WI { STD_EXT, "wint_t", T_WI }
00740 #define T_ST &size_type_node
00741 #define T99_ST { STD_C99, "size_t", T_ST }
00742 #define T_SST &signed_size_type_node
00743 #define T99_SST { STD_C99, "signed size_t", T_SST }
00744 #define T_PD &ptrdiff_type_node
00745 #define T99_PD { STD_C99, "ptrdiff_t", T_PD }
00746 #define T_UPD &unsigned_ptrdiff_type_node
00747 #define T99_UPD { STD_C99, "unsigned ptrdiff_t", T_UPD }
00748 #define T_IM &intmax_type_node
00749 #define T99_IM { STD_C99, "intmax_t", T_IM }
00750 #define T_UIM &uintmax_type_node
00751 #define T99_UIM { STD_C99, "uintmax_t", T_UIM }
00752
00753 static const format_char_info print_char_table[] =
00754 {
00755
00756 { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "-wp0 +'I", "i" },
00757 { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0#", "i" },
00758 { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0'I", "i" },
00759 { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "" },
00760 { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "" },
00761 { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" },
00762 { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR" },
00763 { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c" },
00764 { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W" },
00765
00766 { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "" },
00767 { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "" },
00768
00769 { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" },
00770 { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R" },
00771
00772 { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "" },
00773 { NULL, 0, 0, NOLENGTHS, NULL, NULL }
00774 };
00775
00776 static const format_char_info scan_char_table[] =
00777 {
00778
00779 { "di", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "*w'I", "W" },
00780 { "u", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "*w'I", "W" },
00781 { "oxX", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "*w", "W" },
00782 { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W" },
00783 { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "cW" },
00784 { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW" },
00785 { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW[" },
00786 { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W" },
00787 { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W" },
00788
00789 { "FaA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W" },
00790
00791 { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W" },
00792 { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "W" },
00793 { NULL, 0, 0, NOLENGTHS, NULL, NULL }
00794 };
00795
00796 static const format_char_info time_char_table[] =
00797 {
00798
00799 { "ABZab", 0, STD_C89, NOLENGTHS, "^#", "" },
00800 { "cx", 0, STD_C89, NOLENGTHS, "E", "3" },
00801 { "HIMSUWdmw", 0, STD_C89, NOLENGTHS, "-_0Ow", "" },
00802 { "j", 0, STD_C89, NOLENGTHS, "-_0Ow", "o" },
00803 { "p", 0, STD_C89, NOLENGTHS, "#", "" },
00804 { "X", 0, STD_C89, NOLENGTHS, "E", "" },
00805 { "y", 0, STD_C89, NOLENGTHS, "EO-_0w", "4" },
00806 { "Y", 0, STD_C89, NOLENGTHS, "-_0EOw", "o" },
00807 { "%", 0, STD_C89, NOLENGTHS, "", "" },
00808
00809 { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o" },
00810 { "D", 0, STD_C99, NOLENGTHS, "", "2" },
00811 { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "" },
00812 { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "" },
00813 { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o" },
00814 { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o" },
00815 { "h", 0, STD_C99, NOLENGTHS, "^#", "" },
00816 { "z", 0, STD_C99, NOLENGTHS, "O", "o" },
00817
00818 { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "" },
00819 { "P", 0, STD_EXT, NOLENGTHS, "", "" },
00820 { NULL, 0, 0, NOLENGTHS, NULL, NULL }
00821 };
00822
00823 static const format_char_info monetary_char_table[] =
00824 {
00825 { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "" },
00826 { NULL, 0, 0, NOLENGTHS, NULL, NULL }
00827 };
00828
00829
00830
00831 static const format_kind_info format_types[] =
00832 {
00833 { "printf", printf_length_specs, print_char_table, " +#0-'I", NULL,
00834 printf_flag_specs, printf_flag_pairs,
00835 FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
00836 'w', 0, 'p', 0, 'L',
00837 &integer_type_node, &integer_type_node
00838 },
00839 { "scanf", scanf_length_specs, scan_char_table, "*'I", NULL,
00840 scanf_flag_specs, scanf_flag_pairs,
00841 FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
00842 'w', 0, 0, '*', 'L',
00843 NULL, NULL
00844 },
00845 { "strftime", NULL, time_char_table, "_-0^#", "EO",
00846 strftime_flag_specs, strftime_flag_pairs,
00847 FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0,
00848 NULL, NULL
00849 },
00850 { "strfmon", strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
00851 strfmon_flag_specs, strfmon_flag_pairs,
00852 FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L',
00853 NULL, NULL
00854 }
00855 };
00856
00857
00858
00859
00860
00861 typedef struct
00862 {
00863
00864
00865 int number_non_literal;
00866
00867
00868 int number_extra_args;
00869
00870
00871
00872 int number_dollar_extra_args;
00873
00874
00875 int number_wide;
00876
00877 int number_empty;
00878
00879
00880 int number_unterminated;
00881
00882 int number_other;
00883 } format_check_results;
00884
00885 typedef struct
00886 {
00887 format_check_results *res;
00888 function_format_info *info;
00889 tree params;
00890 int *status;
00891 } format_check_context;
00892
00893 static void check_format_info PARAMS ((int *, function_format_info *, tree));
00894 static void check_format_arg PARAMS ((void *, tree, unsigned HOST_WIDE_INT));
00895 static void check_format_info_main PARAMS ((int *, format_check_results *,
00896 function_format_info *,
00897 const char *, int, tree,
00898 unsigned HOST_WIDE_INT));
00899 static void status_warning PARAMS ((int *, const char *, ...))
00900 ATTRIBUTE_PRINTF_2;
00901
00902 static void init_dollar_format_checking PARAMS ((int, tree));
00903 static int maybe_read_dollar_number PARAMS ((int *, const char **, int,
00904 tree, tree *,
00905 const format_kind_info *));
00906 static void finish_dollar_format_checking PARAMS ((int *, format_check_results *, int));
00907
00908 static const format_flag_spec *get_flag_spec PARAMS ((const format_flag_spec *,
00909 int, const char *));
00910
00911 static void check_format_types PARAMS ((int *, format_wanted_type *));
00912
00913
00914
00915
00916 static enum format_type
00917 decode_format_type (s)
00918 const char *s;
00919 {
00920 int i;
00921 int slen;
00922 slen = strlen (s);
00923 for (i = 0; i < (int) format_type_error; i++)
00924 {
00925 int alen;
00926 if (!strcmp (s, format_types[i].name))
00927 break;
00928 alen = strlen (format_types[i].name);
00929 if (slen == alen + 4 && s[0] == '_' && s[1] == '_'
00930 && s[slen - 1] == '_' && s[slen - 2] == '_'
00931 && !strncmp (s + 2, format_types[i].name, alen))
00932 break;
00933 }
00934 return ((enum format_type) i);
00935 }
00936
00937
00938
00939
00940
00941
00942
00943
00944 void
00945 check_function_format (status, attrs, params)
00946 int *status;
00947 tree attrs;
00948 tree params;
00949 {
00950 tree a;
00951
00952
00953 for (a = attrs; a; a = TREE_CHAIN (a))
00954 {
00955 if (is_attribute_p ("format", TREE_PURPOSE (a)))
00956 {
00957
00958 function_format_info info;
00959 decode_format_attr (TREE_VALUE (a), &info, 1);
00960 check_format_info (status, &info, params);
00961 if (warn_missing_format_attribute && info.first_arg_num == 0
00962 && (format_types[info.format_type].flags
00963 & (int) FMT_FLAG_ARG_CONVERT))
00964 {
00965 tree c;
00966 for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
00967 c;
00968 c = TREE_CHAIN (c))
00969 if (is_attribute_p ("format", TREE_PURPOSE (c))
00970 && (decode_format_type (IDENTIFIER_POINTER
00971 (TREE_VALUE (TREE_VALUE (c))))
00972 == info.format_type))
00973 break;
00974 if (c == NULL_TREE)
00975 {
00976
00977
00978
00979
00980 tree args;
00981 for (args = DECL_ARGUMENTS (current_function_decl);
00982 args != 0;
00983 args = TREE_CHAIN (args))
00984 {
00985 if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE
00986 && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args)))
00987 == char_type_node))
00988 break;
00989 }
00990 if (args != 0)
00991 warning ("function might be possible candidate for `%s' format attribute",
00992 format_types[info.format_type].name);
00993 }
00994 }
00995 }
00996 }
00997 }
00998
00999
01000
01001
01002
01003
01004 static void
01005 status_warning VPARAMS ((int *status, const char *msgid, ...))
01006 {
01007 diagnostic_info diagnostic ;
01008
01009 #ifndef SGI_MONGOOSE
01010 VA_OPEN (ap, msgid);
01011 VA_FIXEDARG (ap, int *, status);
01012 VA_FIXEDARG (ap, const char *, msgid);
01013 #else
01014 va_list ap;
01015
01016 VA_START (ap, msgid);
01017 #endif
01018
01019 if (status)
01020 *status = 1;
01021 else
01022 {
01023
01024 diagnostic_set_info (&diagnostic, _(msgid), &ap, input_filename, lineno,
01025 DK_WARNING);
01026 report_diagnostic (&diagnostic);
01027 }
01028
01029 #ifndef SGI_MONGOOSE
01030 VA_CLOSE (ap);
01031 #else
01032 va_end (ap);
01033 #endif
01034 }
01035
01036
01037 static char *dollar_arguments_used = NULL;
01038 static char *dollar_arguments_pointer_p = NULL;
01039 static int dollar_arguments_alloc = 0;
01040 static int dollar_arguments_count;
01041 static int dollar_first_arg_num;
01042 static int dollar_max_arg_used;
01043 static int dollar_format_warned;
01044
01045
01046
01047
01048
01049
01050
01051 static void
01052 init_dollar_format_checking (first_arg_num, params)
01053 int first_arg_num;
01054 tree params;
01055 {
01056 tree oparams = params;
01057
01058 dollar_first_arg_num = first_arg_num;
01059 dollar_arguments_count = 0;
01060 dollar_max_arg_used = 0;
01061 dollar_format_warned = 0;
01062 if (first_arg_num > 0)
01063 {
01064 while (params)
01065 {
01066 dollar_arguments_count++;
01067 params = TREE_CHAIN (params);
01068 }
01069 }
01070 if (dollar_arguments_alloc < dollar_arguments_count)
01071 {
01072 if (dollar_arguments_used)
01073 free (dollar_arguments_used);
01074 if (dollar_arguments_pointer_p)
01075 free (dollar_arguments_pointer_p);
01076 dollar_arguments_alloc = dollar_arguments_count;
01077 dollar_arguments_used = xmalloc (dollar_arguments_alloc);
01078 dollar_arguments_pointer_p = xmalloc (dollar_arguments_alloc);
01079 }
01080 if (dollar_arguments_alloc)
01081 {
01082 memset (dollar_arguments_used, 0, dollar_arguments_alloc);
01083 if (first_arg_num > 0)
01084 {
01085 int i = 0;
01086 params = oparams;
01087 while (params)
01088 {
01089 dollar_arguments_pointer_p[i] = (TREE_CODE (TREE_TYPE (TREE_VALUE (params)))
01090 == POINTER_TYPE);
01091 params = TREE_CHAIN (params);
01092 i++;
01093 }
01094 }
01095 }
01096 }
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108 static int
01109 maybe_read_dollar_number (status, format, dollar_needed, params, param_ptr,
01110 fki)
01111 int *status;
01112 const char **format;
01113 int dollar_needed;
01114 tree params;
01115 tree *param_ptr;
01116 const format_kind_info *fki;
01117 {
01118 int argnum;
01119 int overflow_flag;
01120 const char *fcp = *format;
01121 if (! ISDIGIT (*fcp))
01122 {
01123 if (dollar_needed)
01124 {
01125 status_warning (status, "missing $ operand number in format");
01126 return -1;
01127 }
01128 else
01129 return 0;
01130 }
01131 argnum = 0;
01132 overflow_flag = 0;
01133 while (ISDIGIT (*fcp))
01134 {
01135 int nargnum;
01136 nargnum = 10 * argnum + (*fcp - '0');
01137 if (nargnum < 0 || nargnum / 10 != argnum)
01138 overflow_flag = 1;
01139 argnum = nargnum;
01140 fcp++;
01141 }
01142 if (*fcp != '$')
01143 {
01144 if (dollar_needed)
01145 {
01146 status_warning (status, "missing $ operand number in format");
01147 return -1;
01148 }
01149 else
01150 return 0;
01151 }
01152 *format = fcp + 1;
01153 if (pedantic && !dollar_format_warned)
01154 {
01155 status_warning (status,
01156 "%s does not support %%n$ operand number formats",
01157 C_STD_NAME (STD_EXT));
01158 dollar_format_warned = 1;
01159 }
01160 if (overflow_flag || argnum == 0
01161 || (dollar_first_arg_num && argnum > dollar_arguments_count))
01162 {
01163 status_warning (status, "operand number out of range in format");
01164 return -1;
01165 }
01166 if (argnum > dollar_max_arg_used)
01167 dollar_max_arg_used = argnum;
01168
01169
01170 while (dollar_arguments_alloc < dollar_max_arg_used)
01171 {
01172 int nalloc;
01173 nalloc = 2 * dollar_arguments_alloc + 16;
01174 dollar_arguments_used = xrealloc (dollar_arguments_used, nalloc);
01175 dollar_arguments_pointer_p = xrealloc (dollar_arguments_pointer_p,
01176 nalloc);
01177 memset (dollar_arguments_used + dollar_arguments_alloc, 0,
01178 nalloc - dollar_arguments_alloc);
01179 dollar_arguments_alloc = nalloc;
01180 }
01181 if (!(fki->flags & (int) FMT_FLAG_DOLLAR_MULTIPLE)
01182 && dollar_arguments_used[argnum - 1] == 1)
01183 {
01184 dollar_arguments_used[argnum - 1] = 2;
01185 status_warning (status,
01186 "format argument %d used more than once in %s format",
01187 argnum, fki->name);
01188 }
01189 else
01190 dollar_arguments_used[argnum - 1] = 1;
01191 if (dollar_first_arg_num)
01192 {
01193 int i;
01194 *param_ptr = params;
01195 for (i = 1; i < argnum && *param_ptr != 0; i++)
01196 *param_ptr = TREE_CHAIN (*param_ptr);
01197
01198 if (*param_ptr == 0)
01199 {
01200
01201 abort ();
01202 }
01203 }
01204 else
01205 *param_ptr = 0;
01206 return argnum;
01207 }
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220 static void
01221 finish_dollar_format_checking (status, res, pointer_gap_ok)
01222 int *status;
01223 format_check_results *res;
01224 int pointer_gap_ok;
01225 {
01226 int i;
01227 bool found_pointer_gap = false;
01228 for (i = 0; i < dollar_max_arg_used; i++)
01229 {
01230 if (!dollar_arguments_used[i])
01231 {
01232 if (pointer_gap_ok && (dollar_first_arg_num == 0
01233 || dollar_arguments_pointer_p[i]))
01234 found_pointer_gap = true;
01235 else
01236 status_warning (status, "format argument %d unused before used argument %d in $-style format",
01237 i + 1, dollar_max_arg_used);
01238 }
01239 }
01240 if (found_pointer_gap
01241 || (dollar_first_arg_num
01242 && dollar_max_arg_used < dollar_arguments_count))
01243 {
01244 res->number_other--;
01245 res->number_dollar_extra_args++;
01246 }
01247 }
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258 static const format_flag_spec *
01259 get_flag_spec (spec, flag, predicates)
01260 const format_flag_spec *spec;
01261 int flag;
01262 const char *predicates;
01263 {
01264 int i;
01265 for (i = 0; spec[i].flag_char != 0; i++)
01266 {
01267 if (spec[i].flag_char != flag)
01268 continue;
01269 if (predicates != NULL)
01270 {
01271 if (spec[i].predicate != 0
01272 && strchr (predicates, spec[i].predicate) != 0)
01273 return &spec[i];
01274 }
01275 else if (spec[i].predicate == 0)
01276 return &spec[i];
01277 }
01278 if (predicates == NULL)
01279 abort ();
01280 else
01281 return NULL;
01282 }
01283
01284
01285
01286
01287
01288
01289 static void
01290 check_format_info (status, info, params)
01291 int *status;
01292 function_format_info *info;
01293 tree params;
01294 {
01295 format_check_context format_ctx;
01296 unsigned HOST_WIDE_INT arg_num;
01297 tree format_tree;
01298 format_check_results res;
01299
01300
01301 for (arg_num = 1; ; ++arg_num)
01302 {
01303 if (params == 0)
01304 return;
01305 if (arg_num == info->format_num)
01306 break;
01307 params = TREE_CHAIN (params);
01308 }
01309 format_tree = TREE_VALUE (params);
01310 params = TREE_CHAIN (params);
01311 if (format_tree == 0)
01312 return;
01313
01314 res.number_non_literal = 0;
01315 res.number_extra_args = 0;
01316 res.number_dollar_extra_args = 0;
01317 res.number_wide = 0;
01318 res.number_empty = 0;
01319 res.number_unterminated = 0;
01320 res.number_other = 0;
01321
01322 format_ctx.res = &res;
01323 format_ctx.info = info;
01324 format_ctx.params = params;
01325 format_ctx.status = status;
01326
01327 check_function_arguments_recurse (check_format_arg, &format_ctx,
01328 format_tree, arg_num);
01329
01330 if (res.number_non_literal > 0)
01331 {
01332
01333
01334
01335 if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT))
01336 {
01337
01338
01339 if (warn_format_nonliteral)
01340 status_warning (status, "format not a string literal, format string not checked");
01341 }
01342 else if (info->first_arg_num != 0)
01343 {
01344
01345
01346 while (arg_num + 1 < info->first_arg_num)
01347 {
01348 if (params == 0)
01349 break;
01350 params = TREE_CHAIN (params);
01351 ++arg_num;
01352 }
01353 if (params == 0 && (warn_format_nonliteral || warn_format_security))
01354 status_warning (status, "format not a string literal and no format arguments");
01355 else if (warn_format_nonliteral)
01356 status_warning (status, "format not a string literal, argument types not checked");
01357 }
01358 }
01359
01360
01361
01362
01363
01364
01365
01366
01367 if (res.number_extra_args > 0 && res.number_non_literal == 0
01368 && res.number_other == 0 && warn_format_extra_args)
01369 status_warning (status, "too many arguments for format");
01370 if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0
01371 && res.number_other == 0 && warn_format_extra_args)
01372 status_warning (status, "unused arguments in $-style format");
01373 if (res.number_empty > 0 && res.number_non_literal == 0
01374 && res.number_other == 0 && warn_format_zero_length)
01375 status_warning (status, "zero-length %s format string",
01376 format_types[info->format_type].name);
01377
01378 if (res.number_wide > 0)
01379 status_warning (status, "format is a wide character string");
01380
01381 if (res.number_unterminated > 0)
01382 status_warning (status, "unterminated format string");
01383 }
01384
01385
01386
01387
01388
01389
01390 static void
01391 check_format_arg (ctx, format_tree, arg_num)
01392 void *ctx;
01393 tree format_tree;
01394 unsigned HOST_WIDE_INT arg_num;
01395 {
01396 format_check_context *format_ctx = ctx;
01397 format_check_results *res = format_ctx->res;
01398 function_format_info *info = format_ctx->info;
01399 tree params = format_ctx->params;
01400 int *status = format_ctx->status;
01401
01402 int format_length;
01403 HOST_WIDE_INT offset;
01404 const char *format_chars;
01405 tree array_size = 0;
01406 tree array_init;
01407
01408 if (integer_zerop (format_tree))
01409 {
01410
01411
01412 while (arg_num + 1 < info->first_arg_num)
01413 {
01414 if (params == 0)
01415 return;
01416 params = TREE_CHAIN (params);
01417 ++arg_num;
01418 }
01419
01420 if (params == 0)
01421 res->number_other++;
01422 else
01423 res->number_extra_args++;
01424
01425 return;
01426 }
01427
01428 offset = 0;
01429 if (TREE_CODE (format_tree) == PLUS_EXPR)
01430 {
01431 tree arg0, arg1;
01432
01433 arg0 = TREE_OPERAND (format_tree, 0);
01434 arg1 = TREE_OPERAND (format_tree, 1);
01435 STRIP_NOPS (arg0);
01436 STRIP_NOPS (arg1);
01437 if (TREE_CODE (arg1) == INTEGER_CST)
01438 format_tree = arg0;
01439 else if (TREE_CODE (arg0) == INTEGER_CST)
01440 {
01441 format_tree = arg1;
01442 arg1 = arg0;
01443 }
01444 else
01445 {
01446 res->number_non_literal++;
01447 return;
01448 }
01449 if (!host_integerp (arg1, 0)
01450 || (offset = tree_low_cst (arg1, 0)) < 0)
01451 {
01452 res->number_non_literal++;
01453 return;
01454 }
01455 }
01456 if (TREE_CODE (format_tree) != ADDR_EXPR)
01457 {
01458 res->number_non_literal++;
01459 return;
01460 }
01461 format_tree = TREE_OPERAND (format_tree, 0);
01462 if (TREE_CODE (format_tree) == VAR_DECL
01463 && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE
01464 && (array_init = decl_constant_value (format_tree)) != format_tree
01465 && TREE_CODE (array_init) == STRING_CST)
01466 {
01467
01468
01469
01470 array_size = DECL_SIZE_UNIT (format_tree);
01471 format_tree = array_init;
01472 }
01473 if (TREE_CODE (format_tree) != STRING_CST)
01474 {
01475 res->number_non_literal++;
01476 return;
01477 }
01478 if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree))) != char_type_node)
01479 {
01480 res->number_wide++;
01481 return;
01482 }
01483 format_chars = TREE_STRING_POINTER (format_tree);
01484 format_length = TREE_STRING_LENGTH (format_tree);
01485 if (array_size != 0)
01486 {
01487
01488 if (TREE_CODE (array_size) != INTEGER_CST)
01489 abort ();
01490 if (host_integerp (array_size, 0))
01491 {
01492 HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size);
01493 if (array_size_value > 0
01494 && array_size_value == (int) array_size_value
01495 && format_length > array_size_value)
01496 format_length = array_size_value;
01497 }
01498 }
01499 if (offset)
01500 {
01501 if (offset >= format_length)
01502 {
01503 res->number_non_literal++;
01504 return;
01505 }
01506 format_chars += offset;
01507 format_length -= offset;
01508 }
01509 if (format_length < 1)
01510 {
01511 res->number_unterminated++;
01512 return;
01513 }
01514 if (format_length == 1)
01515 {
01516 res->number_empty++;
01517 return;
01518 }
01519 if (format_chars[--format_length] != 0)
01520 {
01521 res->number_unterminated++;
01522 return;
01523 }
01524
01525
01526 while (arg_num + 1 < info->first_arg_num)
01527 {
01528 if (params == 0)
01529 return;
01530 params = TREE_CHAIN (params);
01531 ++arg_num;
01532 }
01533
01534
01535
01536 res->number_other++;
01537 check_format_info_main (status, res, info, format_chars, format_length,
01538 params, arg_num);
01539 }
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549 static void
01550 check_format_info_main (status, res, info, format_chars, format_length,
01551 params, arg_num)
01552 int *status;
01553 format_check_results *res;
01554 function_format_info *info;
01555 const char *format_chars;
01556 int format_length;
01557 tree params;
01558 unsigned HOST_WIDE_INT arg_num;
01559 {
01560 const char *orig_format_chars = format_chars;
01561 tree first_fillin_param = params;
01562
01563 const format_kind_info *fki = &format_types[info->format_type];
01564 const format_flag_spec *flag_specs = fki->flag_specs;
01565 const format_flag_pair *bad_flag_pairs = fki->bad_flag_pairs;
01566
01567
01568
01569 int has_operand_number = -1;
01570
01571 init_dollar_format_checking (info->first_arg_num, first_fillin_param);
01572
01573 while (1)
01574 {
01575 int i;
01576 int suppressed = FALSE;
01577 const char *length_chars = NULL;
01578 enum format_lengths length_chars_val = FMT_LEN_none;
01579 enum format_std_version length_chars_std = STD_C89;
01580 int format_char;
01581 tree cur_param;
01582 tree wanted_type;
01583 int main_arg_num = 0;
01584 tree main_arg_params = 0;
01585 enum format_std_version wanted_type_std;
01586 const char *wanted_type_name;
01587 format_wanted_type width_wanted_type;
01588 format_wanted_type precision_wanted_type;
01589 format_wanted_type main_wanted_type;
01590 format_wanted_type *first_wanted_type = NULL;
01591 format_wanted_type *last_wanted_type = NULL;
01592 const format_length_info *fli = NULL;
01593 const format_char_info *fci = NULL;
01594 char flag_chars[256];
01595 int aflag = 0;
01596 if (*format_chars == 0)
01597 {
01598 if (format_chars - orig_format_chars != format_length)
01599 status_warning (status, "embedded `\\0' in format");
01600 if (info->first_arg_num != 0 && params != 0
01601 && has_operand_number <= 0)
01602 {
01603 res->number_other--;
01604 res->number_extra_args++;
01605 }
01606 if (has_operand_number > 0)
01607 finish_dollar_format_checking (status, res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK);
01608 return;
01609 }
01610 if (*format_chars++ != '%')
01611 continue;
01612 if (*format_chars == 0)
01613 {
01614 status_warning (status, "spurious trailing `%%' in format");
01615 continue;
01616 }
01617 if (*format_chars == '%')
01618 {
01619 ++format_chars;
01620 continue;
01621 }
01622 flag_chars[0] = 0;
01623
01624 if ((fki->flags & (int) FMT_FLAG_USE_DOLLAR) && has_operand_number != 0)
01625 {
01626
01627
01628
01629
01630 int opnum;
01631 opnum = maybe_read_dollar_number (status, &format_chars, 0,
01632 first_fillin_param,
01633 &main_arg_params, fki);
01634 if (opnum == -1)
01635 return;
01636 else if (opnum > 0)
01637 {
01638 has_operand_number = 1;
01639 main_arg_num = opnum + info->first_arg_num - 1;
01640 }
01641 }
01642
01643
01644
01645
01646 while (*format_chars != 0
01647 && strchr (fki->flag_chars, *format_chars) != 0)
01648 {
01649 const format_flag_spec *s = get_flag_spec (flag_specs,
01650 *format_chars, NULL);
01651 if (strchr (flag_chars, *format_chars) != 0)
01652 {
01653 status_warning (status, "repeated %s in format", _(s->name));
01654 }
01655 else
01656 {
01657 i = strlen (flag_chars);
01658 flag_chars[i++] = *format_chars;
01659 flag_chars[i] = 0;
01660 }
01661 if (s->skip_next_char)
01662 {
01663 ++format_chars;
01664 if (*format_chars == 0)
01665 {
01666 status_warning (status, "missing fill character at end of strfmon format");
01667 return;
01668 }
01669 }
01670 ++format_chars;
01671 }
01672
01673
01674 if (fki->width_char != 0)
01675 {
01676 if (fki->width_type != NULL && *format_chars == '*')
01677 {
01678 i = strlen (flag_chars);
01679 flag_chars[i++] = fki->width_char;
01680 flag_chars[i] = 0;
01681
01682
01683 ++format_chars;
01684 if (has_operand_number != 0)
01685 {
01686 int opnum;
01687 opnum = maybe_read_dollar_number (status, &format_chars,
01688 has_operand_number == 1,
01689 first_fillin_param,
01690 ¶ms, fki);
01691 if (opnum == -1)
01692 return;
01693 else if (opnum > 0)
01694 {
01695 has_operand_number = 1;
01696 arg_num = opnum + info->first_arg_num - 1;
01697 }
01698 else
01699 has_operand_number = 0;
01700 }
01701 if (info->first_arg_num != 0)
01702 {
01703 if (params == 0)
01704 {
01705 status_warning (status, "too few arguments for format");
01706 return;
01707 }
01708 cur_param = TREE_VALUE (params);
01709 if (has_operand_number <= 0)
01710 {
01711 params = TREE_CHAIN (params);
01712 ++arg_num;
01713 }
01714 width_wanted_type.wanted_type = *fki->width_type;
01715 width_wanted_type.wanted_type_name = NULL;
01716 width_wanted_type.pointer_count = 0;
01717 width_wanted_type.char_lenient_flag = 0;
01718 width_wanted_type.writing_in_flag = 0;
01719 width_wanted_type.reading_from_flag = 0;
01720 width_wanted_type.name = _("field width");
01721 width_wanted_type.param = cur_param;
01722 width_wanted_type.arg_num = arg_num;
01723 width_wanted_type.next = NULL;
01724 if (last_wanted_type != 0)
01725 last_wanted_type->next = &width_wanted_type;
01726 if (first_wanted_type == 0)
01727 first_wanted_type = &width_wanted_type;
01728 last_wanted_type = &width_wanted_type;
01729 }
01730 }
01731 else
01732 {
01733
01734
01735 int non_zero_width_char = FALSE;
01736 int found_width = FALSE;
01737 while (ISDIGIT (*format_chars))
01738 {
01739 found_width = TRUE;
01740 if (*format_chars != '0')
01741 non_zero_width_char = TRUE;
01742 ++format_chars;
01743 }
01744 if (found_width && !non_zero_width_char &&
01745 (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD))
01746 status_warning (status, "zero width in %s format",
01747 fki->name);
01748 if (found_width)
01749 {
01750 i = strlen (flag_chars);
01751 flag_chars[i++] = fki->width_char;
01752 flag_chars[i] = 0;
01753 }
01754 }
01755 }
01756
01757
01758 if (fki->left_precision_char != 0 && *format_chars == '#')
01759 {
01760 ++format_chars;
01761 i = strlen (flag_chars);
01762 flag_chars[i++] = fki->left_precision_char;
01763 flag_chars[i] = 0;
01764 if (!ISDIGIT (*format_chars))
01765 status_warning (status, "empty left precision in %s format",
01766 fki->name);
01767 while (ISDIGIT (*format_chars))
01768 ++format_chars;
01769 }
01770
01771
01772 if (fki->precision_char != 0 && *format_chars == '.')
01773 {
01774 ++format_chars;
01775 i = strlen (flag_chars);
01776 flag_chars[i++] = fki->precision_char;
01777 flag_chars[i] = 0;
01778 if (fki->precision_type != NULL && *format_chars == '*')
01779 {
01780
01781
01782 ++format_chars;
01783 if (has_operand_number != 0)
01784 {
01785 int opnum;
01786 opnum = maybe_read_dollar_number (status, &format_chars,
01787 has_operand_number == 1,
01788 first_fillin_param,
01789 ¶ms, fki);
01790 if (opnum == -1)
01791 return;
01792 else if (opnum > 0)
01793 {
01794 has_operand_number = 1;
01795 arg_num = opnum + info->first_arg_num - 1;
01796 }
01797 else
01798 has_operand_number = 0;
01799 }
01800 if (info->first_arg_num != 0)
01801 {
01802 if (params == 0)
01803 {
01804 status_warning (status, "too few arguments for format");
01805 return;
01806 }
01807 cur_param = TREE_VALUE (params);
01808 if (has_operand_number <= 0)
01809 {
01810 params = TREE_CHAIN (params);
01811 ++arg_num;
01812 }
01813 precision_wanted_type.wanted_type = *fki->precision_type;
01814 precision_wanted_type.wanted_type_name = NULL;
01815 precision_wanted_type.pointer_count = 0;
01816 precision_wanted_type.char_lenient_flag = 0;
01817 precision_wanted_type.writing_in_flag = 0;
01818 precision_wanted_type.reading_from_flag = 0;
01819 precision_wanted_type.name = _("field precision");
01820 precision_wanted_type.param = cur_param;
01821 precision_wanted_type.arg_num = arg_num;
01822 precision_wanted_type.next = NULL;
01823 if (last_wanted_type != 0)
01824 last_wanted_type->next = &precision_wanted_type;
01825 if (first_wanted_type == 0)
01826 first_wanted_type = &precision_wanted_type;
01827 last_wanted_type = &precision_wanted_type;
01828 }
01829 }
01830 else
01831 {
01832 if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK)
01833 && !ISDIGIT (*format_chars))
01834 status_warning (status, "empty precision in %s format",
01835 fki->name);
01836 while (ISDIGIT (*format_chars))
01837 ++format_chars;
01838 }
01839 }
01840
01841
01842 fli = fki->length_char_specs;
01843 length_chars = NULL;
01844 length_chars_val = FMT_LEN_none;
01845 length_chars_std = STD_C89;
01846 if (fli)
01847 {
01848 while (fli->name != 0 && fli->name[0] != *format_chars)
01849 fli++;
01850 if (fli->name != 0)
01851 {
01852 format_chars++;
01853 if (fli->double_name != 0 && fli->name[0] == *format_chars)
01854 {
01855 format_chars++;
01856 length_chars = fli->double_name;
01857 length_chars_val = fli->double_index;
01858 length_chars_std = fli->double_std;
01859 }
01860 else
01861 {
01862 length_chars = fli->name;
01863 length_chars_val = fli->index;
01864 length_chars_std = fli->std;
01865 }
01866 i = strlen (flag_chars);
01867 flag_chars[i++] = fki->length_code_char;
01868 flag_chars[i] = 0;
01869 }
01870 if (pedantic)
01871 {
01872
01873 if (ADJ_STD (length_chars_std) > C_STD_VER)
01874 status_warning (status, "%s does not support the `%s' %s length modifier",
01875 C_STD_NAME (length_chars_std), length_chars,
01876 fki->name);
01877 }
01878 }
01879
01880
01881 if (fki->modifier_chars != NULL)
01882 {
01883 while (*format_chars != 0
01884 && strchr (fki->modifier_chars, *format_chars) != 0)
01885 {
01886 if (strchr (flag_chars, *format_chars) != 0)
01887 {
01888 const format_flag_spec *s = get_flag_spec (flag_specs,
01889 *format_chars, NULL);
01890 status_warning (status, "repeated %s in format", _(s->name));
01891 }
01892 else
01893 {
01894 i = strlen (flag_chars);
01895 flag_chars[i++] = *format_chars;
01896 flag_chars[i] = 0;
01897 }
01898 ++format_chars;
01899 }
01900 }
01901
01902
01903 if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
01904 {
01905 if (*format_chars == 'a' && !flag_isoc99)
01906 {
01907 if (format_chars[1] == 's' || format_chars[1] == 'S'
01908 || format_chars[1] == '[')
01909 {
01910
01911 i = strlen (flag_chars);
01912 flag_chars[i++] = 'a';
01913 flag_chars[i] = 0;
01914 format_chars++;
01915 }
01916 }
01917 }
01918
01919 format_char = *format_chars;
01920 if (format_char == 0
01921 || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
01922 && format_char == '%'))
01923 {
01924 status_warning (status, "conversion lacks type at end of format");
01925 continue;
01926 }
01927 format_chars++;
01928 fci = fki->conversion_specs;
01929 while (fci->format_chars != 0
01930 && strchr (fci->format_chars, format_char) == 0)
01931 ++fci;
01932 if (fci->format_chars == 0)
01933 {
01934 if (ISGRAPH(format_char))
01935 status_warning (status, "unknown conversion type character `%c' in format",
01936 format_char);
01937 else
01938 status_warning (status, "unknown conversion type character 0x%x in format",
01939 format_char);
01940 continue;
01941 }
01942 if (pedantic)
01943 {
01944 if (ADJ_STD (fci->std) > C_STD_VER)
01945 status_warning (status, "%s does not support the `%%%c' %s format",
01946 C_STD_NAME (fci->std), format_char, fki->name);
01947 }
01948
01949
01950 {
01951 int d = 0;
01952 for (i = 0; flag_chars[i] != 0; i++)
01953 {
01954 const format_flag_spec *s = get_flag_spec (flag_specs,
01955 flag_chars[i], NULL);
01956 flag_chars[i - d] = flag_chars[i];
01957 if (flag_chars[i] == fki->length_code_char)
01958 continue;
01959 if (strchr (fci->flag_chars, flag_chars[i]) == 0)
01960 {
01961 status_warning (status, "%s used with `%%%c' %s format",
01962 _(s->name), format_char, fki->name);
01963 d++;
01964 continue;
01965 }
01966 if (pedantic)
01967 {
01968 const format_flag_spec *t;
01969 if (ADJ_STD (s->std) > C_STD_VER)
01970 status_warning (status, "%s does not support %s",
01971 C_STD_NAME (s->std), _(s->long_name));
01972 t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2);
01973 if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std))
01974 {
01975 const char *long_name = (t->long_name != NULL
01976 ? t->long_name
01977 : s->long_name);
01978 if (ADJ_STD (t->std) > C_STD_VER)
01979 status_warning (status, "%s does not support %s with the `%%%c' %s format",
01980 C_STD_NAME (t->std), _(long_name),
01981 format_char, fki->name);
01982 }
01983 }
01984 }
01985 flag_chars[i - d] = 0;
01986 }
01987
01988 if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
01989 && strchr (flag_chars, 'a') != 0)
01990 aflag = 1;
01991
01992 if (fki->suppression_char
01993 && strchr (flag_chars, fki->suppression_char) != 0)
01994 suppressed = 1;
01995
01996
01997 for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++)
01998 {
01999 const format_flag_spec *s, *t;
02000 if (strchr (flag_chars, bad_flag_pairs[i].flag_char1) == 0)
02001 continue;
02002 if (strchr (flag_chars, bad_flag_pairs[i].flag_char2) == 0)
02003 continue;
02004 if (bad_flag_pairs[i].predicate != 0
02005 && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0)
02006 continue;
02007 s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL);
02008 t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL);
02009 if (bad_flag_pairs[i].ignored)
02010 {
02011 if (bad_flag_pairs[i].predicate != 0)
02012 status_warning (status, "%s ignored with %s and `%%%c' %s format",
02013 _(s->name), _(t->name), format_char,
02014 fki->name);
02015 else
02016 status_warning (status, "%s ignored with %s in %s format",
02017 _(s->name), _(t->name), fki->name);
02018 }
02019 else
02020 {
02021 if (bad_flag_pairs[i].predicate != 0)
02022 status_warning (status, "use of %s and %s together with `%%%c' %s format",
02023 _(s->name), _(t->name), format_char,
02024 fki->name);
02025 else
02026 status_warning (status, "use of %s and %s together in %s format",
02027 _(s->name), _(t->name), fki->name);
02028 }
02029 }
02030
02031
02032 if (warn_format_y2k)
02033 {
02034 int y2k_level = 0;
02035 if (strchr (fci->flags2, '4') != 0)
02036 if (strchr (flag_chars, 'E') != 0)
02037 y2k_level = 3;
02038 else
02039 y2k_level = 2;
02040 else if (strchr (fci->flags2, '3') != 0)
02041 y2k_level = 3;
02042 else if (strchr (fci->flags2, '2') != 0)
02043 y2k_level = 2;
02044 if (y2k_level == 3)
02045 status_warning (status, "`%%%c' yields only last 2 digits of year in some locales",
02046 format_char);
02047 else if (y2k_level == 2)
02048 status_warning (status, "`%%%c' yields only last 2 digits of year", format_char);
02049 }
02050
02051 if (strchr (fci->flags2, '[') != 0)
02052 {
02053
02054 if (*format_chars == '^')
02055 ++format_chars;
02056
02057
02058 if (*format_chars == ']')
02059 ++format_chars;
02060 while (*format_chars && *format_chars != ']')
02061 ++format_chars;
02062 if (*format_chars != ']')
02063
02064 status_warning (status, "no closing `]' for `%%[' format");
02065 }
02066
02067 wanted_type = 0;
02068 wanted_type_name = 0;
02069 if (fki->flags & (int) FMT_FLAG_ARG_CONVERT)
02070 {
02071 wanted_type = (fci->types[length_chars_val].type
02072 ? *fci->types[length_chars_val].type : 0);
02073 wanted_type_name = fci->types[length_chars_val].name;
02074 wanted_type_std = fci->types[length_chars_val].std;
02075 if (wanted_type == 0)
02076 {
02077 status_warning (status, "use of `%s' length modifier with `%c' type character",
02078 length_chars, format_char);
02079
02080
02081 arg_num++;
02082 if (params == 0)
02083 {
02084 status_warning (status, "too few arguments for format");
02085 return;
02086 }
02087 params = TREE_CHAIN (params);
02088 continue;
02089 }
02090 else if (pedantic
02091
02092
02093
02094 && ADJ_STD (wanted_type_std) > ADJ_STD (length_chars_std)
02095 && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std))
02096 {
02097 if (ADJ_STD (wanted_type_std) > C_STD_VER)
02098 status_warning (status, "%s does not support the `%%%s%c' %s format",
02099 C_STD_NAME (wanted_type_std), length_chars,
02100 format_char, fki->name);
02101 }
02102 }
02103
02104
02105 if (info->first_arg_num == 0)
02106 continue;
02107 if ((fci->pointer_count == 0 && wanted_type == void_type_node)
02108 || suppressed)
02109 {
02110 if (main_arg_num != 0)
02111 {
02112 if (suppressed)
02113 status_warning (status, "operand number specified with suppressed assignment");
02114 else
02115 status_warning (status, "operand number specified for format taking no argument");
02116 }
02117 }
02118 else
02119 {
02120 if (main_arg_num != 0)
02121 {
02122 arg_num = main_arg_num;
02123 params = main_arg_params;
02124 }
02125 else
02126 {
02127 ++arg_num;
02128 if (has_operand_number > 0)
02129 {
02130 status_warning (status, "missing $ operand number in format");
02131 return;
02132 }
02133 else
02134 has_operand_number = 0;
02135 if (params == 0)
02136 {
02137 status_warning (status, "too few arguments for format");
02138 return;
02139 }
02140 }
02141 cur_param = TREE_VALUE (params);
02142 params = TREE_CHAIN (params);
02143 main_wanted_type.wanted_type = wanted_type;
02144 main_wanted_type.wanted_type_name = wanted_type_name;
02145 main_wanted_type.pointer_count = fci->pointer_count + aflag;
02146 main_wanted_type.char_lenient_flag = 0;
02147 if (strchr (fci->flags2, 'c') != 0)
02148 main_wanted_type.char_lenient_flag = 1;
02149 main_wanted_type.writing_in_flag = 0;
02150 main_wanted_type.reading_from_flag = 0;
02151 if (aflag)
02152 main_wanted_type.writing_in_flag = 1;
02153 else
02154 {
02155 if (strchr (fci->flags2, 'W') != 0)
02156 main_wanted_type.writing_in_flag = 1;
02157 if (strchr (fci->flags2, 'R') != 0)
02158 main_wanted_type.reading_from_flag = 1;
02159 }
02160 main_wanted_type.name = NULL;
02161 main_wanted_type.param = cur_param;
02162 main_wanted_type.arg_num = arg_num;
02163 main_wanted_type.next = NULL;
02164 if (last_wanted_type != 0)
02165 last_wanted_type->next = &main_wanted_type;
02166 if (first_wanted_type == 0)
02167 first_wanted_type = &main_wanted_type;
02168 last_wanted_type = &main_wanted_type;
02169 }
02170
02171 if (first_wanted_type != 0)
02172 check_format_types (status, first_wanted_type);
02173
02174 }
02175 }
02176
02177
02178
02179
02180 static void
02181 check_format_types (status, types)
02182 int *status;
02183 format_wanted_type *types;
02184 {
02185 for (; types != 0; types = types->next)
02186 {
02187 tree cur_param;
02188 tree cur_type;
02189 tree orig_cur_type;
02190 tree wanted_type;
02191 int arg_num;
02192 int i;
02193 int char_type_flag;
02194 cur_param = types->param;
02195 cur_type = TREE_TYPE (cur_param);
02196 if (cur_type == error_mark_node)
02197 continue;
02198 char_type_flag = 0;
02199 wanted_type = types->wanted_type;
02200 arg_num = types->arg_num;
02201
02202
02203 if (wanted_type == 0)
02204 abort ();
02205 if (wanted_type == void_type_node && types->pointer_count == 0)
02206 abort ();
02207
02208 if (types->pointer_count == 0)
02209 wanted_type = (*lang_hooks.types.type_promotes_to) (wanted_type);
02210
02211 STRIP_NOPS (cur_param);
02212
02213
02214
02215 for (i = 0; i < types->pointer_count; ++i)
02216 {
02217 if (TREE_CODE (cur_type) == POINTER_TYPE)
02218 {
02219 cur_type = TREE_TYPE (cur_type);
02220 if (cur_type == error_mark_node)
02221 break;
02222
02223
02224 if (types->writing_in_flag
02225 && i == 0
02226 && cur_param != 0
02227 && integer_zerop (cur_param))
02228 status_warning (status,
02229 "writing through null pointer (arg %d)",
02230 arg_num);
02231
02232
02233 if (types->reading_from_flag
02234 && i == 0
02235 && cur_param != 0
02236 && integer_zerop (cur_param))
02237 status_warning (status,
02238 "reading through null pointer (arg %d)",
02239 arg_num);
02240
02241 if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
02242 cur_param = TREE_OPERAND (cur_param, 0);
02243 else
02244 cur_param = 0;
02245
02246
02247
02248
02249
02250
02251 if (types->writing_in_flag
02252 && i == 0
02253 && (TYPE_READONLY (cur_type)
02254 || (cur_param != 0
02255 && (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c'
02256 || (DECL_P (cur_param)
02257 && TREE_READONLY (cur_param))))))
02258 status_warning (status, "writing into constant object (arg %d)", arg_num);
02259
02260
02261
02262
02263 if (i > 0
02264 && pedantic
02265 && (TYPE_READONLY (cur_type)
02266 || TYPE_VOLATILE (cur_type)
02267 || TYPE_RESTRICT (cur_type)))
02268 status_warning (status, "extra type qualifiers in format argument (arg %d)",
02269 arg_num);
02270
02271 }
02272 else
02273 {
02274 if (types->pointer_count == 1)
02275 status_warning (status, "format argument is not a pointer (arg %d)", arg_num);
02276 else
02277 status_warning (status, "format argument is not a pointer to a pointer (arg %d)", arg_num);
02278 break;
02279 }
02280 }
02281
02282 if (i < types->pointer_count)
02283 continue;
02284
02285 orig_cur_type = cur_type;
02286 cur_type = TYPE_MAIN_VARIANT (cur_type);
02287
02288
02289
02290
02291 if (types->char_lenient_flag)
02292 char_type_flag = (cur_type == char_type_node
02293 || cur_type == signed_char_type_node
02294 || cur_type == unsigned_char_type_node);
02295
02296
02297 if (wanted_type == cur_type)
02298 continue;
02299
02300
02301
02302
02303 if (wanted_type == void_type_node
02304 && (!pedantic || (i == 1 && char_type_flag)))
02305 continue;
02306
02307
02308
02309
02310 if (TREE_CODE (wanted_type) == INTEGER_TYPE
02311 && TREE_CODE (cur_type) == INTEGER_TYPE
02312 && (! pedantic || i == 0 || (i == 1 && char_type_flag))
02313 && (TREE_UNSIGNED (wanted_type)
02314 ? wanted_type == c_common_unsigned_type (cur_type)
02315 : wanted_type == c_common_signed_type (cur_type)))
02316 continue;
02317
02318
02319 if (wanted_type == char_type_node
02320 && (! pedantic || i < 2)
02321 && char_type_flag)
02322 continue;
02323
02324 {
02325 const char *this;
02326 const char *that;
02327
02328 this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
02329 that = 0;
02330 if (TYPE_NAME (orig_cur_type) != 0
02331 && TREE_CODE (orig_cur_type) != INTEGER_TYPE
02332 && !(TREE_CODE (orig_cur_type) == POINTER_TYPE
02333 && TREE_CODE (TREE_TYPE (orig_cur_type)) == INTEGER_TYPE))
02334 {
02335 if (TREE_CODE (TYPE_NAME (orig_cur_type)) == TYPE_DECL
02336 && DECL_NAME (TYPE_NAME (orig_cur_type)) != 0)
02337 that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (orig_cur_type)));
02338 else
02339 that = IDENTIFIER_POINTER (TYPE_NAME (orig_cur_type));
02340 }
02341
02342
02343
02344
02345 if (that == 0)
02346 {
02347 if (TREE_CODE (orig_cur_type) == POINTER_TYPE)
02348 that = _("pointer");
02349 else
02350 that = _("different type");
02351 }
02352
02353
02354 if (TREE_CODE (orig_cur_type) == INTEGER_TYPE
02355 && TREE_CODE (wanted_type) == INTEGER_TYPE
02356 && TYPE_PRECISION (orig_cur_type) == TYPE_PRECISION (wanted_type)
02357 && TYPE_NAME (orig_cur_type) != 0
02358 && TREE_CODE (TYPE_NAME (orig_cur_type)) == TYPE_DECL)
02359 that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (orig_cur_type)));
02360
02361 if (strcmp (this, that) != 0)
02362 {
02363
02364
02365
02366
02367 if (types->wanted_type_name != 0
02368 && strcmp (types->wanted_type_name, that) != 0)
02369 this = types->wanted_type_name;
02370 if (types->name != 0)
02371 status_warning (status, "%s is not type %s (arg %d)", types->name, this,
02372 arg_num);
02373 else
02374 status_warning (status, "%s format, %s arg (arg %d)", this, that, arg_num);
02375 }
02376 }
02377 }
02378 }