📄 c-typeck.c
字号:
{ "S", 1, T_W, NULL, NULL, NULL, "-wp" }, { "p", 1, T_V, NULL, NULL, NULL, "-" }, { "n", 1, T_I, T_S, T_L, NULL, "" }, { NULL } };static format_char_info scan_table[] = { { "di", 1, T_I, T_S, T_L, NULL, "*" }, { "ouxX", 1, T_UI, T_US, T_UL, NULL, "*" }, { "efgEG", 1, T_F, NULL, T_D, T_LD, "*" }, { "sc", 1, T_C, NULL, T_W, NULL, "*" }, { "[", 1, T_C, NULL, NULL, NULL, "*" }, { "C", 1, T_W, NULL, NULL, NULL, "*" }, { "S", 1, T_W, NULL, NULL, NULL, "*" }, { "p", 2, T_V, NULL, NULL, NULL, "*" }, { "n", 1, T_I, T_S, T_L, NULL, "" }, { NULL } };typedef struct{ tree function_ident; /* identifier such as "printf" */ int is_scan; /* TRUE if *scanf */ int format_num; /* number of format argument */ int first_arg_num; /* number of first arg (zero for varargs) */} function_info;static unsigned int function_info_entries = 0;static function_info *function_info_table = NULL;/* Record information for argument format checking. FUNCTION_IDENT is the identifier node for the name of the function to check (its decl need not exist yet). IS_SCAN is true for scanf-type format checking; false indicates printf-style format checking. FORMAT_NUM is the number of the argument which is the format control string (starting from 1). FIRST_ARG_NUM is the number of the first actual argument to check against teh format string, or zero if no checking is not be done (e.g. for varargs such as vfprintf). */voidrecord_format_info (function_ident, is_scan, format_num, first_arg_num) tree function_ident; int is_scan; int format_num; int first_arg_num;{ function_info *info; function_info_entries++; if (function_info_table) function_info_table = (function_info *) xrealloc (function_info_table, function_info_entries * sizeof (function_info)); else function_info_table = (function_info *) xmalloc (sizeof (function_info)); info = &function_info_table[function_info_entries - 1]; info->function_ident = function_ident; info->is_scan = is_scan; info->format_num = format_num; info->first_arg_num = first_arg_num;}/* Initialize the table of functions to perform format checking on. The ANSI functions are always checked (whether <stdio.h> is included or not), since it is common to call printf without including <stdio.h>. There shouldn't be a problem with this, since ANSI reserves these function names whether you include the header file or not. In any case, the checking is harmless. */voidinit_format_info_table (){ record_format_info (get_identifier ("printf"), 0, 1, 2); record_format_info (get_identifier ("fprintf"), 0, 2, 3); record_format_info (get_identifier ("sprintf"), 0, 2, 3); record_format_info (get_identifier ("scanf"), 1, 1, 2); record_format_info (get_identifier ("fscanf"), 1, 2, 3); record_format_info (get_identifier ("sscanf"), 1, 2, 3); record_format_info (get_identifier ("vprintf"), 0, 1, 0); record_format_info (get_identifier ("vfprintf"), 0, 2, 0); record_format_info (get_identifier ("vsprintf"), 0, 2, 0);}static char tfaff[] = "too few arguments for format";/* Check the argument list of a call to printf, scanf, etc. INFO points to the element of function_info_table. PARAMS is the list of argument values. */static voidcheck_format (info, params) function_info *info; tree params;{ int i; int arg_num; int suppressed, wide, precise; int length_char; int format_char; int format_length; tree format_tree; tree cur_param; tree cur_type; tree wanted_type; char *format_chars; format_char_info *fci; static char message[132]; char flag_chars[8]; /* Skip to format argument. If the argument isn't available, there's no work for us to do; prototype checking will catch the problem. */ for (arg_num = 1; ; ++arg_num) { if (params == 0) return; if (arg_num == info->format_num) break; params = TREE_CHAIN (params); } format_tree = TREE_VALUE (params); params = TREE_CHAIN (params); if (format_tree == 0) return; /* We can only check the format if it's a string constant. */ while (TREE_CODE (format_tree) == NOP_EXPR) format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */ if (format_tree == null_pointer_node) { warning ("null format string"); return; } if (TREE_CODE (format_tree) != ADDR_EXPR) return; format_tree = TREE_OPERAND (format_tree, 0); if (TREE_CODE (format_tree) != STRING_CST) return; format_chars = TREE_STRING_POINTER (format_tree); format_length = TREE_STRING_LENGTH (format_tree); if (format_length <= 1) warning ("zero-length format string"); if (format_chars[--format_length] != 0) { warning ("unterminated format string"); return; } /* Skip to first argument to check. */ while (arg_num + 1 < info->first_arg_num) { if (params == 0) return; params = TREE_CHAIN (params); ++arg_num; } while (1) { if (*format_chars == 0) { if (format_chars - TREE_STRING_POINTER (format_tree) != format_length) warning ("embedded `\\0' in format"); if (info->first_arg_num != 0 && params != 0) warning ("too many arguments for format"); return; } if (*format_chars++ != '%') continue; if (*format_chars == 0) { warning ("spurious trailing `%%' in format"); continue; } if (*format_chars == '%') { ++format_chars; continue; } flag_chars[0] = 0; suppressed = wide = precise = FALSE; if (info->is_scan) { suppressed = *format_chars == '*'; if (suppressed) ++format_chars; while (ISDIGIT (*format_chars)) ++format_chars; } else { while (*format_chars != 0 && index (" +#0-", *format_chars) != 0) { if (index (flag_chars, *format_chars) != 0) { sprintf (message, "repeated `%c' flag in format", *format_chars); warning (message); } i = strlen (flag_chars); flag_chars[i++] = *format_chars++; flag_chars[i] = 0; } /* "If the space and + flags both appear, the space flag will be ignored." */ if (index (flag_chars, ' ') != 0 && index (flag_chars, '+') != 0) warning ("use of both ` ' and `+' flags in format"); /* "If the 0 and - flags both appear, the 0 flag will be ignored." */ if (index (flag_chars, '0') != 0 && index (flag_chars, '-') != 0) warning ("use of both `0' and `-' flags in format"); if (*format_chars == '*') { wide = TRUE; /* "...a field width...may be indicated by an asterisk. In this case, an int argument supplies the field width..." */ ++format_chars; if (params == 0) { warning (tfaff); return; } if (info->first_arg_num != 0) { cur_param = TREE_VALUE (params); params = TREE_CHAIN (params); ++arg_num; /* size_t is generally not valid here. It will work on most machines, because size_t and int have the same mode. But might as well warn anyway, since it will fail on other machines. */ if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) != integer_type_node) { sprintf (message, "field width is not type int (arg %d)", arg_num); warning (message); } } } else { while (ISDIGIT (*format_chars)) { wide = TRUE; ++format_chars; } } if (*format_chars == '.') { precise = TRUE; /* "For d, i, o, u, x, and X conversions, if a precision is specified, the 0 flag will be ignored. For other conversions, the behavior is undefined." */ if (index (flag_chars, '0') != 0) warning ("precision and `0' flag both used in one %%-sequence"); ++format_chars; if (*format_chars != '*' && !ISDIGIT (*format_chars)) warning ("`.' not followed by `*' or digit in format"); /* "...a...precision...may be indicated by an asterisk. In this case, an int argument supplies the...precision." */ if (*format_chars == '*') { if (info->first_arg_num != 0) { ++format_chars; if (params == 0) { warning (tfaff); return; } cur_param = TREE_VALUE (params); params = TREE_CHAIN (params); ++arg_num; if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) != integer_type_node) { sprintf (message, "field width is not type int (arg %d)", arg_num); warning (message); } } } else { while (ISDIGIT (*format_chars)) ++format_chars; } } } if (*format_chars == 'h' || *format_chars == 'l' || *format_chars == 'L') length_char = *format_chars++; else length_char = 0; if (suppressed && length_char != 0) { sprintf (message, "use of `*' and `%c' together in format", length_char); warning (message); } format_char = *format_chars; if (format_char == 0) { warning ("conversion lacks type at end of format"); continue; } format_chars++; fci = info->is_scan ? scan_table : print_table; while (1) { if (fci->format_chars == 0 || index (fci->format_chars, format_char) != 0) break; ++fci; } if (fci->format_chars == 0) { if (format_char >= 040 && format_char < 0177) sprintf (message, "unknown conversion type character `%c' in format", format_char); else sprintf (message, "unknown conversion type character 0x%x in format", format_char); warning (message); continue; } if (wide && index (fci->flag_chars, 'w') == 0) { sprintf (message, "width used with `%c' format", format_char); warning (message); } if (precise && index (fci->flag_chars, 'p') == 0) { sprintf (message, "precision used with `%c' format", format_char); warning (message); } if (suppressed) { if (index (fci->flag_chars, '*') == 0) { sprintf (message, "suppression of `%c' conversion in format", format_char); warning (message); } continue; } for (i = 0; flag_chars[i] != 0; ++i) { if (index (fci->flag_chars, flag_chars[i]) == 0) { sprintf (message, "flag `%c' used with type `%c'", flag_chars[i], format_char); warning (message); } } switch (length_char) { default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break; case 'h': wanted_type = fci->hlen ? *(fci->hlen) : 0; break; case 'l': wanted_type = fci->llen ? *(fci->llen) : 0; break; case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break; } if (wanted_type == 0) { sprintf (message, "use of `%c' length character with `%c' type character", length_char, format_char); warning (message); } /* ** XXX -- should kvetch about stuff such as ** { ** const int i; ** ** scanf ("%d", &i); ** } */ /* Finally. . .check type of argument against desired type! */ if (info->first_arg_num == 0) continue; if (params == 0) { warning (tfaff); return; } cur_param = TREE_VALUE (params); params = TREE_CHAIN (params); ++arg_num; cur_type = TREE_TYPE (cur_param); /* Check the types of any additional pointer arguments that precede the "real" argument. */ for (i = 0; i < fci->pointer_count; ++i) { if (TREE_CODE (cur_type) == POINTER_TYPE) { cur_type = TREE_TYPE (cur_type); continue; } sprintf (message, "format argument is not a %s (arg %d)", ((fci->pointer_count == 1) ? "pointer" : "pointer to a pointer"), arg_num); warning (message); break; } /* Check the type of the "real" argument, if there's a type we want. */ if (i == fci->pointer_count && wanted_type != 0 && wanted_type != TYPE_MAIN_VARIANT (cur_type) /* If we want `void *', allow any pointer type. (Anything else would already have got a warning.) */ && ! (wanted_type == void_type_node && fci->pointer_count > 0) /* Don't warn about differences merely in signedness. */ && !(TREE_CODE (wanted_type) == INTEGER_TYPE && TREE_CODE (cur_type) == INTEGER_TYPE && TYPE_PRECISION (wanted_type) == TYPE_PRECISION (cur_type))) { register char *this; register char *that; this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type))); that = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -