From 5306559682044f799760e0d8cbcdd622c3a5ca0b Mon Sep 17 00:00:00 2001 From: Richard Kenner Date: Thu, 30 Mar 1995 08:59:11 -0500 Subject: [PATCH] (enum attrs): New enum class. (attrtab, attrtab_idx): New variables. (add_attribute, init_attributes): New functions. (decl_attributes): Major rewrite. From-SVN: r9261 --- gcc/c-common.c | 652 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 370 insertions(+), 282 deletions(-) diff --git a/gcc/c-common.c b/gcc/c-common.c index d952868..b625447 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -28,7 +28,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ extern struct obstack permanent_obstack; -static void declare_hidden_char_array PROTO((char *, char *)); +enum attrs {A_PACKED, A_NORETURN, A_CONST, A_T_UNION, A_CONSTRUCTOR, + A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED, A_FORMAT}; + +static void declare_hidden_char_array PROTO((char *, char *)); +static void add_attribute PROTO((enum attrs, char *, + int, int, int)); +static void init_attributes PROTO((void)); /* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */ @@ -199,318 +205,400 @@ combine_strings (strings) return value; } +/* To speed up processing of attributes, we maintain an array of + IDENTIFIER_NODES and the corresponding attribute types. */ + +/* Array to hold attribute information. */ + +static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50]; + +static int attrtab_idx = 0; + +/* Add an entry to the attribute table above. */ + +static void +add_attribute (id, string, min_len, max_len, decl_req) + enum attrs id; + char *string; + int min_len, max_len; + int decl_req; +{ + char buf[100]; + + attrtab[attrtab_idx].id = id; + attrtab[attrtab_idx].name = get_identifier (string); + attrtab[attrtab_idx].min = min_len; + attrtab[attrtab_idx].max = max_len; + attrtab[attrtab_idx++].decl_req = decl_req; + + sprintf (buf, "__%s__", string); + + attrtab[attrtab_idx].id = id; + attrtab[attrtab_idx].name = get_identifier (buf); + attrtab[attrtab_idx].min = min_len; + attrtab[attrtab_idx].max = max_len; + attrtab[attrtab_idx++].decl_req = decl_req; +} + +/* Initialize attribute table. */ + +static void +init_attributes () +{ + add_attribute (A_PACKED, "packed", 0, 0, 1); + add_attribute (A_NORETURN, "noreturn", 0, 0, 1); + add_attribute (A_NORETURN, "volatile", 0, 0, 1); + add_attribute (A_CONST, "const", 0, 0, 1); + add_attribute (A_T_UNION, "transparent_union", 0, 0, 0); + add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1); + add_attribute (A_DESTRUCTOR, "destructor", 0, 0, 1); + add_attribute (A_MODE, "mode", 1, 1, 1); + add_attribute (A_SECTION, "section", 1, 1, 1); + add_attribute (A_ALIGNED, "aligned", 0, 1, 0); + add_attribute (A_FORMAT, "format", 3, 3, 0); +} + /* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES - and install them in DECL. PREFIX_ATTRIBUTES can appear after the - declaration specifiers and declaration modifiers but before the - declaration proper. */ + and install them in NODE, which is either a DECL (including a TYPE_DECL) + or a TYPE. PREFIX_ATTRIBUTES can appear after the declaration specifiers + and declaration modifiers but before the declaration proper. */ void -decl_attributes (decl, attributes, prefix_attributes) - tree decl, attributes, prefix_attributes; +decl_attributes (node, attributes, prefix_attributes) + tree node, attributes, prefix_attributes; { - tree a, name, args, type; + tree decl = 0, type; + int is_type; + tree a; + + if (attrtab_idx == 0) + init_attributes (); + + if (TREE_CODE_CLASS (TREE_CODE (node)) == 'd') + { + decl = node; + type = TREE_TYPE (decl); + is_type = TREE_CODE (node) == TYPE_DECL; + } + else if (TREE_CODE_CLASS (TREE_CODE (node)) == 't') + type = node, is_type = 1; - type = TREE_TYPE (decl); attributes = chainon (prefix_attributes, attributes); for (a = attributes; a; a = TREE_CHAIN (a)) - if (!(name = TREE_VALUE (a))) - continue; - else if (name == get_identifier ("packed") - || name == get_identifier ("__packed__")) - { - if (TREE_CODE (decl) == FIELD_DECL) - DECL_PACKED (decl) = 1; - /* We can't set DECL_PACKED for a VAR_DECL, because the bit is - used for DECL_REGISTER. It wouldn't mean anything anyway. */ - else - warning_with_decl (decl, "`packed' attribute ignored"); - } - else if (name == get_identifier ("noreturn") - || name == get_identifier ("__noreturn__") - || name == get_identifier ("volatile") - || name == get_identifier ("__volatile__")) - { - if (TREE_CODE (decl) == FUNCTION_DECL) - TREE_THIS_VOLATILE (decl) = 1; - else if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) - TREE_TYPE (decl) = type - = build_pointer_type - (build_type_variant (TREE_TYPE (type), - TREE_READONLY (TREE_TYPE (type)), 1)); - else - warning_with_decl (decl, - (IDENTIFIER_POINTER (name)[0] == 'n' - || IDENTIFIER_POINTER (name)[2] == 'n') - ? "`noreturn' attribute ignored" - : "`volatile' attribute ignored"); - } - else if (name == get_identifier ("const") - || name == get_identifier ("__const__")) - { - if (TREE_CODE (decl) == FUNCTION_DECL) - TREE_READONLY (decl) = 1; - else if (TREE_CODE (type) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) - TREE_TYPE (decl) = type - = build_pointer_type - (build_type_variant (TREE_TYPE (type), 1, - TREE_THIS_VOLATILE (TREE_TYPE (type)))); - else - warning_with_decl (decl, "`const' attribute ignored"); - } - else if (name == get_identifier ("transparent_union") - || name == get_identifier ("__transparent_union__")) - { - if (TREE_CODE (decl) == PARM_DECL - && TREE_CODE (type) == UNION_TYPE - && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))) - DECL_TRANSPARENT_UNION (decl) = 1; - else if (TREE_CODE (decl) == TYPE_DECL - && TREE_CODE (type) == UNION_TYPE - && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))) - TYPE_TRANSPARENT_UNION (type) = 1; - else - warning_with_decl (decl, "`transparent_union' attribute ignored"); - } - else if (name == get_identifier ("constructor") - || name == get_identifier ("__constructor__")) - { - if (TREE_CODE (decl) != FUNCTION_DECL - || TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE - || decl_function_context (decl)) - { - error_with_decl (decl, - "`constructor' attribute meaningless for non-function %s"); - continue; - } - DECL_STATIC_CONSTRUCTOR (decl) = 1; - } - else if (name == get_identifier ("destructor") - || name == get_identifier ("__destructor__")) - { - if (TREE_CODE (decl) != FUNCTION_DECL - || TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE - || decl_function_context (decl)) - { - error_with_decl (decl, - "`destructor' attribute meaningless for non-function %s"); - continue; - } - DECL_STATIC_DESTRUCTOR (decl) = 1; - } - else if ((args = TREE_CHAIN (name)) != 0 - && (name == get_identifier ("mode") - || name == get_identifier ("__mode__")) - && list_length (args) == 1 - && TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE) - { - int i; - char *specified_name = IDENTIFIER_POINTER (TREE_VALUE (args)); - enum machine_mode mode = VOIDmode; - tree typefm; - - /* Give this decl a type with the specified mode. - First check for the special modes. */ - if (! strcmp (specified_name, "byte") - || ! strcmp (specified_name, "__byte__")) - mode = byte_mode; - else if (!strcmp (specified_name, "word") - || ! strcmp (specified_name, "__word__")) - mode = word_mode; - else if (! strcmp (specified_name, "pointer") - || !strcmp (specified_name, "__pointer__")) - mode = ptr_mode; - else - for (i = 0; i < NUM_MACHINE_MODES; i++) - if (!strcmp (specified_name, GET_MODE_NAME (i))) - mode = (enum machine_mode) i; - - if (mode == VOIDmode) - error ("unknown machine mode `%s'", specified_name); - else if ((typefm = type_for_mode (mode, TREE_UNSIGNED (type))) == 0) - error ("no data type for mode `%s'", specified_name); - else - { - TREE_TYPE (decl) = type = typefm; - DECL_SIZE (decl) = 0; - layout_decl (decl, 0); - } - } - else if ((!strcmp (IDENTIFIER_POINTER (name), "section") - || !strcmp (IDENTIFIER_POINTER (name), "__section__")) - && list_length (args) == 1 - && TREE_CODE (TREE_VALUE (args)) == STRING_CST) - { + { + tree name = TREE_PURPOSE (a); + tree args = TREE_VALUE (a); + int i; + enum attrs id; + + for (i = 0; i < attrtab_idx; i++) + if (attrtab[i].name == name) + break; + + if (i == attrtab_idx + && ! valid_machine_attribute (name, args, decl, type)) + { + warning ("`%s' attribute directive ignored", + IDENTIFIER_POINTER (name)); + continue; + } + else if (attrtab[i].decl_req && decl == 0) + { + warning ("`%s' attribute does not apply to types", + IDENTIFIER_POINTER (name)); + continue; + } + else if (list_length (args) < attrtab[i].min + || list_length (args) > attrtab[i].max) + { + error ("wrong number of arguments specified for `%s' attribute", + IDENTIFIER_POINTER (name)); + continue; + } + + id = attrtab[i].id; + switch (id) + { + case A_PACKED: + if (TREE_CODE (decl) == FIELD_DECL) + DECL_PACKED (decl) = 1; + /* We can't set DECL_PACKED for a VAR_DECL, because the bit is + used for DECL_REGISTER. It wouldn't mean anything anyway. */ + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_NORETURN: + if (TREE_CODE (decl) == FUNCTION_DECL) + TREE_THIS_VOLATILE (decl) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (decl) = type + = build_pointer_type + (build_type_variant (TREE_TYPE (type), + TREE_READONLY (TREE_TYPE (type)), 1)); + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_CONST: + if (TREE_CODE (decl) == FUNCTION_DECL) + TREE_READONLY (decl) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (decl) = type + = build_pointer_type + (build_type_variant (TREE_TYPE (type), 1, + TREE_THIS_VOLATILE (TREE_TYPE (type)))); + else + warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_T_UNION: + if (decl != 0 && TREE_CODE (decl) == PARM_DECL + && TREE_CODE (type) == UNION_TYPE + && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))) + DECL_TRANSPARENT_UNION (decl) = 1; + else if (is_type + && TREE_CODE (type) == UNION_TYPE + && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))) + TYPE_TRANSPARENT_UNION (type) = 1; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_CONSTRUCTOR: + if (TREE_CODE (decl) == FUNCTION_DECL + && TREE_CODE (type) == FUNCTION_TYPE + && decl_function_context (decl) == 0) + DECL_STATIC_CONSTRUCTOR (decl) = 1; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_DESTRUCTOR: + if (TREE_CODE (decl) == FUNCTION_DECL + && TREE_CODE (type) == FUNCTION_TYPE + && decl_function_context (decl) == 0) + DECL_STATIC_DESTRUCTOR (decl) = 1; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_MODE: + if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE) + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + else + { + int j; + char *p = IDENTIFIER_POINTER (TREE_VALUE (args)); + int len = strlen (p); + enum machine_mode mode = VOIDmode; + tree typefm; + + if (len > 4 && p[0] == '_' && p[1] == '_' + && p[len - 1] == '_' && p[len - 2] == '_') + { + char *newp = (char *) alloca (len - 2); + + 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) - { - 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 (decl, - "section of `%s' conflicts with previous declaration"); - else - DECL_SECTION_NAME (decl) = TREE_VALUE (args); - } - else - error_with_decl (decl, + 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 (decl, "section attributes are not supported for this target"); + error_with_decl (node, + "section attributes are not supported for this target"); #endif - } - else if ((!strcmp (IDENTIFIER_POINTER (name), "aligned") - || !strcmp (IDENTIFIER_POINTER (name), "__aligned__")) - && list_length (args) == 1 - && TREE_CODE (TREE_VALUE (args)) == INTEGER_CST) - { - tree align_expr = TREE_VALUE (args); - 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) + break; + + case A_ALIGNED: { - error_with_decl (decl, - "requested alignment of `%s' is not a constant"); - continue; + 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 (TREE_TYPE (decl)) = 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; - align = TREE_INT_CST_LOW (align_expr) * BITS_PER_UNIT; - - if (exact_log2 (align) == -1) - error_with_decl (decl, - "requested alignment of `%s' is not a power of 2"); - else if (TREE_CODE (decl) == TYPE_DECL) - TYPE_ALIGN (TREE_TYPE (decl)) = 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; - } - else if ((!strcmp (IDENTIFIER_POINTER (name), "format") - || !strcmp (IDENTIFIER_POINTER (name), "__format__")) - && list_length (args) == 3 - && TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE - && TREE_CODE (TREE_VALUE (TREE_CHAIN (args))) == INTEGER_CST - && TREE_CODE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)))) - == INTEGER_CST ) - { - 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) + case A_FORMAT: { - error_with_decl (decl, - "argument format specified for non-function `%s'"); - continue; - } + 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 (!strcmp (IDENTIFIER_POINTER (format_type), "printf") - || !strcmp (IDENTIFIER_POINTER (format_type), "__printf__")) - is_scan = 0; - else if (!strcmp (IDENTIFIER_POINTER (format_type), "scanf") - || !strcmp (IDENTIFIER_POINTER (format_type), "__scanf__")) - is_scan = 1; - else - { - error_with_decl (decl, "unrecognized format specifier for `%s'"); - continue; - } + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_with_decl (decl, + "argument format specified for non-function `%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_with_decl (decl, - "format string for `%s' has non-constant operand number"); - 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; + } - 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_with_decl (decl, - "format string arg follows the args to be formatted, 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); - /* 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) + 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) { - if (argument == 0 || arg_num == format_num) - break; - argument = TREE_CHAIN (argument); + error ("format string has non-constant operand number"); + continue; } - if (! argument - || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE - || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) - != char_type_node)) + + 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_with_decl (decl, - "format string arg not a string type, for `%s'"); + error ("format string arg follows the args to be formatted"); continue; } - if (first_arg_num != 0) + + /* 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) { - /* 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) + 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_with_decl (decl, - "args to be formatted is not ..., for `%s'"); + 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); - } - else if (valid_machine_attribute (name, decl, type)) - ; - else - warning ("`%s' attribute directive ignored", - IDENTIFIER_POINTER (name)); + record_function_format (DECL_NAME (decl), + DECL_ASSEMBLER_NAME (decl), + is_scan, format_num, first_arg_num); + break; + } + } + } } /* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against -- 2.7.4