📄 c-common.c
字号:
if (len > 4 && p[0] == '_' && p[1] == '_' && p[len - 1] == '_' && p[len - 2] == '_') { char *newp = (char *) alloca (len - 1); strcpy (newp, &p[2]); newp[len - 4] = '\0'; p = newp; } /* Give this decl a type with the specified mode. First check for the special modes. */ if (! strcmp (p, "byte")) mode = byte_mode; else if (!strcmp (p, "word")) mode = word_mode; else if (! strcmp (p, "pointer")) mode = ptr_mode; else for (j = 0; j < NUM_MACHINE_MODES; j++) if (!strcmp (p, GET_MODE_NAME (j))) mode = (enum machine_mode) j; if (mode == VOIDmode) error ("unknown machine mode `%s'", p); else if (0 == (typefm = type_for_mode (mode, TREE_UNSIGNED (type)))) error ("no data type for mode `%s'", p); else { TREE_TYPE (decl) = type = typefm; DECL_SIZE (decl) = 0; layout_decl (decl, 0); } } break; case A_SECTION:#ifdef ASM_OUTPUT_SECTION_NAME if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) && TREE_CODE (TREE_VALUE (args)) == STRING_CST) { if (TREE_CODE (decl) == VAR_DECL && current_function_decl != NULL_TREE) error_with_decl (decl, "section attribute cannot be specified for local variables"); /* The decl may have already been given a section attribute from a previous declaration. Ensure they match. */ else if (DECL_SECTION_NAME (decl) != NULL_TREE && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), TREE_STRING_POINTER (TREE_VALUE (args))) != 0) error_with_decl (node, "section of `%s' conflicts with previous declaration"); else DECL_SECTION_NAME (decl) = TREE_VALUE (args); } else error_with_decl (node, "section attribute not allowed for `%s'");#else error_with_decl (node, "section attributes are not supported for this target");#endif break; case A_ALIGNED: { tree align_expr = args ? TREE_VALUE (args) : size_int (BIGGEST_ALIGNMENT); int align; /* Strip any NOPs of any kind. */ while (TREE_CODE (align_expr) == NOP_EXPR || TREE_CODE (align_expr) == CONVERT_EXPR || TREE_CODE (align_expr) == NON_LVALUE_EXPR) align_expr = TREE_OPERAND (align_expr, 0); if (TREE_CODE (align_expr) != INTEGER_CST) { error ("requested alignment is not a constant"); continue; } align = TREE_INT_CST_LOW (align_expr) * BITS_PER_UNIT; if (exact_log2 (align) == -1) error ("requested alignment is not a power of 2"); else if (is_type) TYPE_ALIGN (type) = align; else if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FIELD_DECL) error_with_decl (decl, "alignment may not be specified for `%s'"); else DECL_ALIGN (decl) = align; } break; case A_FORMAT: { tree format_type = TREE_VALUE (args); tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); tree first_arg_num_expr = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); int format_num; int first_arg_num; int is_scan; tree argument; int arg_num; if (TREE_CODE (decl) != FUNCTION_DECL) { error_with_decl (decl, "argument format specified for non-function `%s'"); continue; } if (TREE_CODE (format_type) == IDENTIFIER_NODE && (!strcmp (IDENTIFIER_POINTER (format_type), "printf") || !strcmp (IDENTIFIER_POINTER (format_type), "__printf__"))) is_scan = 0; else if (TREE_CODE (format_type) == IDENTIFIER_NODE && (!strcmp (IDENTIFIER_POINTER (format_type), "scanf") || !strcmp (IDENTIFIER_POINTER (format_type), "__scanf__"))) is_scan = 1; else { error ("unrecognized format specifier for `%s'"); continue; } /* Strip any conversions from the string index and first arg number and verify they are constants. */ while (TREE_CODE (format_num_expr) == NOP_EXPR || TREE_CODE (format_num_expr) == CONVERT_EXPR || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR) format_num_expr = TREE_OPERAND (format_num_expr, 0); while (TREE_CODE (first_arg_num_expr) == NOP_EXPR || TREE_CODE (first_arg_num_expr) == CONVERT_EXPR || TREE_CODE (first_arg_num_expr) == NON_LVALUE_EXPR) first_arg_num_expr = TREE_OPERAND (first_arg_num_expr, 0); if (TREE_CODE (format_num_expr) != INTEGER_CST || TREE_CODE (first_arg_num_expr) != INTEGER_CST) { error ("format string has non-constant operand number"); continue; } format_num = TREE_INT_CST_LOW (format_num_expr); first_arg_num = TREE_INT_CST_LOW (first_arg_num_expr); if (first_arg_num != 0 && first_arg_num <= format_num) { error ("format string arg follows the args to be formatted"); continue; } /* If a parameter list is specified, verify that the format_num argument is actually a string, in case the format attribute is in error. */ argument = TYPE_ARG_TYPES (type); if (argument) { for (arg_num = 1; ; ++arg_num) { if (argument == 0 || arg_num == format_num) break; argument = TREE_CHAIN (argument); } if (! argument || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) != char_type_node)) { error ("format string arg not a string type"); continue; } if (first_arg_num != 0) { /* Verify that first_arg_num points to the last arg, the ... */ while (argument) arg_num++, argument = TREE_CHAIN (argument); if (arg_num != first_arg_num) { error ("args to be formatted is not ..."); continue; } } } record_function_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl), is_scan, format_num, first_arg_num); break; } case A_WEAK: declare_weak (decl); break; case A_ALIAS: if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl)) || TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)) error_with_decl (decl, "`%s' defined both normally and as an alias"); else if (decl_function_context (decl) == 0) { tree id = get_identifier (TREE_STRING_POINTER (TREE_VALUE (args))); if (TREE_CODE (decl) == FUNCTION_DECL) DECL_INITIAL (decl) = error_mark_node; else DECL_EXTERNAL (decl) = 0; assemble_alias (decl, id); } else warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); break; } }}/* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against a parameter list. */#define T_I &integer_type_node#define T_L &long_integer_type_node#define T_LL &long_long_integer_type_node#define T_S &short_integer_type_node#define T_UI &unsigned_type_node#define T_UL &long_unsigned_type_node#define T_ULL &long_long_unsigned_type_node#define T_US &short_unsigned_type_node#define T_F &float_type_node#define T_D &double_type_node#define T_LD &long_double_type_node#define T_C &char_type_node#define T_V &void_type_node#define T_W &wchar_type_node#define T_ST &sizetypetypedef struct { char *format_chars; int pointer_count; /* Type of argument if no length modifier is used. */ tree *nolen; /* Type of argument if length modifier for shortening is used. If NULL, then this modifier is not allowed. */ tree *hlen; /* Type of argument if length modifier `l' is used. If NULL, then this modifier is not allowed. */ tree *llen; /* Type of argument if length modifier `q' or `ll' is used. If NULL, then this modifier is not allowed. */ tree *qlen; /* Type of argument if length modifier `L' is used. If NULL, then this modifier is not allowed. */ tree *bigllen; /* List of other modifier characters allowed with these options. */ char *flag_chars;} format_char_info;static format_char_info print_char_table[] = { { "di", 0, T_I, T_I, T_L, T_LL, T_LL, "-wp0 +" }, { "oxX", 0, T_UI, T_UI, T_UL, T_ULL, T_ULL, "-wp0#" }, { "u", 0, T_UI, T_UI, T_UL, T_ULL, T_ULL, "-wp0" },/* Two GNU extensions. */ { "Z", 0, T_ST, NULL, NULL, NULL, NULL, "-wp0" }, { "m", 0, T_V, NULL, NULL, NULL, NULL, "-wp" }, { "feEgG", 0, T_D, NULL, NULL, NULL, T_LD, "-wp0 +#" }, { "c", 0, T_I, NULL, T_W, NULL, NULL, "-w" }, { "C", 0, T_W, NULL, NULL, NULL, NULL, "-w" }, { "s", 1, T_C, NULL, T_W, NULL, NULL, "-wp" }, { "S", 1, T_W, NULL, NULL, NULL, NULL, "-wp" }, { "p", 1, T_V, NULL, NULL, NULL, NULL, "-w" }, { "n", 1, T_I, T_S, T_L, T_LL, NULL, "" }, { NULL }};static format_char_info scan_char_table[] = { { "di", 1, T_I, T_S, T_L, T_LL, T_LL, "*" }, { "ouxX", 1, T_UI, T_US, T_UL, T_ULL, T_ULL, "*" }, { "efgEG", 1, T_F, NULL, T_D, NULL, T_LD, "*" }, { "sc", 1, T_C, NULL, T_W, NULL, NULL, "*a" }, { "[", 1, T_C, NULL, NULL, NULL, NULL, "*a" }, { "C", 1, T_W, NULL, NULL, NULL, NULL, "*" }, { "S", 1, T_W, NULL, NULL, NULL, NULL, "*" }, { "p", 2, T_V, NULL, NULL, NULL, NULL, "*" }, { "n", 1, T_I, T_S, T_L, T_LL, NULL, "" }, { NULL }};typedef struct function_format_info { struct function_format_info *next; /* next structure on the list */ tree name; /* identifier such as "printf" */ tree assembler_name; /* optional mangled identifier (for C++) */ 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_format_info;static function_format_info *function_format_list = NULL;static void check_format_info PROTO((function_format_info *, tree));/* 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_function_format_info (){ record_function_format (get_identifier ("printf"), NULL_TREE, 0, 1, 2); record_function_format (get_identifier ("fprintf"), NULL_TREE, 0, 2, 3); record_function_format (get_identifier ("sprintf"), NULL_TREE, 0, 2, 3); record_function_format (get_identifier ("scanf"), NULL_TREE, 1, 1, 2); record_function_format (get_identifier ("fscanf"), NULL_TREE, 1, 2, 3); record_function_format (get_identifier ("sscanf"), NULL_TREE, 1, 2, 3); record_function_format (get_identifier ("vprintf"), NULL_TREE, 0, 1, 0); record_function_format (get_identifier ("vfprintf"), NULL_TREE, 0, 2, 0); record_function_format (get_identifier ("vsprintf"), NULL_TREE, 0, 2, 0);}/* 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_function_format (name, assembler_name, is_scan, format_num, first_arg_num) tree name; tree assembler_name; int is_scan; int format_num; int first_arg_num;{ function_format_info *info; /* Re-use existing structure if it's there. */ for (info = function_format_list; info; info = info->next) { if (info->name == name && info->assembler_name == assembler_name) break; } if (! info) { info = (function_format_info *) xmalloc (sizeof (function_format_info)); info->next = function_format_list; function_format_list = info; info->name = name; info->assembler_name = assembler_name; } info->is_scan = is_scan; info->format_num = format_num; info->first_arg_num = first_arg_num;}static char tfaff[] = "too few arguments for format";/* Check the argument list of a call to printf, scanf, etc. NAME is the function identifier. ASSEMBLER_NAME is the function's assembler identifier. (Either NAME or ASSEMBLER_NAME, but not both, may be NULL_TREE.) PARAMS is the list of argument values. */voidcheck_function_format (name, assembler_name, params) tree name; tree assembler_name; tree params;{ function_format_info *info; /* See if this function is a format function. */ for (info = function_format_list; info; info = info->next) { if (info->assembler_name ? (info->assembler_name == assembler_name) : (info->name == name)) { /* Yup; check it. */ check_format_info (info, params); break; } }}/* Check the argument list of a call to printf, scanf, etc. INFO points to the function_format_info structure. PARAMS is the list of argument values. */static voidcheck_format_info (info, params) function_format_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; tree first_fillin_param; char *format_chars; format_char_info *fci; static char message[132]; char flag_chars[8]; int has_operand_number = 0; /* Skip to format argument. If the argument isn't available, there's
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -