📄 c-common.c
字号:
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 (integer_zerop (format_tree)) { 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; } first_fillin_param = params; while (1) { int aflag; 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 && ! has_operand_number) 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 { /* See if we have a number followed by a dollar sign. If we do, it is an operand number, so set PARAMS to that operand. */ if (*format_chars >= '0' && *format_chars <= '9') { char *p = format_chars; while (*p >= '0' && *p++ <= '9') ; if (*p == '$') { int opnum = atoi (format_chars); params = first_fillin_param; format_chars = p + 1; has_operand_number = 1; for (i = 1; i < opnum && params != 0; i++) params = TREE_CHAIN (params); if (opnum == 0 || params == 0) { warning ("operand number out of range in format"); return; } } } 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) && (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param)) != unsigned_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; ++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 == 'q' || *format_chars == 'L') length_char = *format_chars++; else length_char = 0; if (length_char == 'l' && *format_chars == 'l') length_char = 'q', format_chars++; aflag = 0; if (*format_chars == 'a') { aflag = 1; format_chars++; } 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_char_table : print_char_table; while (fci->format_chars != 0 && index (fci->format_chars, format_char) == 0) ++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 (aflag && index (fci->flag_chars, 'a') == 0) { sprintf (message, "`a' flag used with `%c' format", format_char); warning (message); } if (info->is_scan && format_char == '[') { /* Skip over scan set, in case it happens to have '%' in it. */ if (*format_chars == '^') ++format_chars; /* Find closing bracket; if one is hit immediately, then it's part of the scan set rather than a terminator. */ if (*format_chars == ']') ++format_chars; while (*format_chars && *format_chars != ']') ++format_chars; if (*format_chars != ']') /* The end of the format string was reached. */ warning ("no closing `]' for `%%[' format"); } 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); } } if (precise && index (flag_chars, '0') != 0 && (format_char == 'd' || format_char == 'i' || format_char == 'o' || format_char == 'u' || format_char == 'x' || format_char == 'x')) { sprintf (message, "precision and `0' flag not both allowed with `%c' format", 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 'q': wanted_type = fci->qlen ? *(fci->qlen) : 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 (fci->pointer_count == 0 && wanted_type == void_type_node) /* This specifier takes no argument. */ 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; } if (TREE_CODE (cur_type) != ERROR_MARK) { 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 && TREE_CODE (cur_type) != ERROR_MARK && 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 (TYPE_MAIN_VARIANT (cur_type)) == INTEGER_TYPE && (TREE_UNSIGNED (wanted_type) ? wanted_type == (cur_type = unsigned_type (cur_type)) : wanted_type == (cur_type = signed_type (cur_type)))) /* Likewise, "signed char", "unsigned char" and "char" are equivalent but the above test won't consider them equivalent. */ && ! (wanted_type == char_type_node && (TYPE_MAIN_VARIANT (cur_type) == signed_char_type_node || TYPE_MAIN_VARIANT (cur_type) == unsigned_char_type_node))) { register char *this; register char *that; this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type))); that = 0; if (TREE_CODE (cur_type) != ERROR_MARK && TYPE_NAME (cur_type) != 0 && TREE_CODE (cur_type) != INTEGER_TYPE && !(TREE_CODE (cur_type) == POINTER_TYPE && TREE_CODE (TREE_TYPE (cur_type)) == INTEGER_TYPE)) { if (TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL && DECL_NAME (TYPE_NAME (cur_type)) != 0) that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type))); else that = IDENTIFIER_POINTER (TYPE_NAME (cur_type)); } /* A nameless type can't possibly match what the format wants. So there will be a warning for it. Make up a string to describe vaguely what it is. */ if (that == 0) { if (TREE_CODE (cur_type) == POINTER_TYPE) that = "pointer"; else that = "different type"; } /* Make the warning better in case of mismatch of int vs long. */ if (TREE_CODE (cur_type) == INTEGER_TYPE && TREE_CODE (wanted_type) == INTEGER_TYPE && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -