X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fc-common.c;h=1e2f6c5c0bb7c4cf814b89e7a18abea0234c8622;hb=faaf6e4c6d466e9f63f0f4b92a037d34d437106d;hp=8b3b887f8fdd896466493028bbd643ee73125240;hpb=aa5ec236cf31ff5a76ef0440a181a8036a849017;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/c-common.c b/gcc/c-common.c index 8b3b887f8fd..1e2f6c5c0bb 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -1,5 +1,5 @@ /* Subroutines shared by all languages that are variants of C. - Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. + Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. This file is part of GNU CC. @@ -15,7 +15,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ #include "config.h" #include "tree.h" @@ -26,9 +27,29 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include +#ifndef WCHAR_TYPE_SIZE +#ifdef INT_TYPE_SIZE +#define WCHAR_TYPE_SIZE INT_TYPE_SIZE +#else +#define WCHAR_TYPE_SIZE BITS_PER_WORD +#endif +#endif + extern struct obstack permanent_obstack; -static void declare_hidden_char_array PROTO((char *, char *)); +/* Nonzero means the expression being parsed will never be evaluated. + This is a count, since unevaluated expressions can nest. */ +int skip_evaluation; + +enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION, + A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED, + A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS}; + +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)); +static void record_international_format PROTO((tree, tree, int)); /* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */ @@ -80,6 +101,7 @@ declare_hidden_char_array (name, value) TREE_READONLY (decl) = 1; TREE_ASM_WRITTEN (decl) = 1; DECL_SOURCE_LINE (decl) = 0; + DECL_ARTIFICIAL (decl) = 1; DECL_IN_SYSTEM_HEADER (decl) = 1; DECL_IGNORED_P (decl) = 1; init = build_string (vlen, value); @@ -148,7 +170,12 @@ combine_strings (strings) { int i; for (i = 0; i < len; i++) - ((int *) q)[i] = TREE_STRING_POINTER (t)[i]; + { + if (WCHAR_TYPE_SIZE == HOST_BITS_PER_SHORT) + ((short *) q)[i] = TREE_STRING_POINTER (t)[i]; + else + ((int *) q)[i] = TREE_STRING_POINTER (t)[i]; + } q += len * wchar_bytes; } } @@ -199,329 +226,605 @@ combine_strings (strings) return value; } -/* Process the attributes listed in ATTRIBUTES - and install them in DECL. */ +/* 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, 0); + add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1); + add_attribute (A_COMMON, "common", 0, 0, 1); + add_attribute (A_NORETURN, "noreturn", 0, 0, 1); + add_attribute (A_NORETURN, "volatile", 0, 0, 1); + add_attribute (A_UNUSED, "unused", 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, 1); + add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1); + add_attribute (A_WEAK, "weak", 0, 0, 1); + add_attribute (A_ALIAS, "alias", 1, 1, 1); +} + +/* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES + 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) - tree decl, attributes; +decl_attributes (node, attributes, prefix_attributes) + tree node, attributes, prefix_attributes; { - tree a, name, args, type, new_attr; + tree decl = 0, type; + int is_type; + tree a; + + if (attrtab_idx == 0) + init_attributes (); - type = TREE_TYPE (decl); + 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; - new_attr = TYPE_ATTRIBUTES (type); + 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 ignore"); - - } - else if (TREE_VALUE (a) == get_identifier ("noreturn") - || TREE_VALUE (a) == get_identifier ("__noreturn__") - || TREE_VALUE (a) == get_identifier ("volatile") - || TREE_VALUE (a) == 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, "`%s' attribute ignored", - IDENTIFIER_POINTER (TREE_VALUE (a))); - } - else if (TREE_VALUE (a) == get_identifier ("const") - || TREE_VALUE (a) == 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 (TREE_VALUE (a) == get_identifier ("transparent_union") - || TREE_VALUE (a) == 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 (TREE_VALUE (a) == get_identifier ("constructor") - || TREE_VALUE (a) == 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 (TREE_VALUE (a) == get_identifier ("destructor") - || TREE_VALUE (a) == 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 (TREE_CODE (name) != TREE_LIST) - { -#ifdef VALID_MACHINE_ATTRIBUTE - if (VALID_MACHINE_ATTRIBUTE (type, new_attr, name)) - { - register tree atlist; - - for (atlist = new_attr; atlist; atlist = TREE_CHAIN (atlist)) - if (TREE_VALUE (atlist) == name) - goto found_attr; - - new_attr = tree_cons (NULL_TREE, name, new_attr); -found_attr:; - } - else -#endif - warning ("`%s' attribute directive ignored", + { + 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) + { + if (! valid_machine_attribute (name, args, decl, type)) + warning ("`%s' attribute directive ignored", + IDENTIFIER_POINTER (name)); + else if (decl != 0) + type = TREE_TYPE (decl); + continue; + } + else if (attrtab[i].decl_req && decl == 0) + { + warning ("`%s' attribute does not apply to types", IDENTIFIER_POINTER (name)); - } - else if ( args = TREE_CHAIN(name), - (!strcmp (IDENTIFIER_POINTER (name = TREE_PURPOSE (name)), "mode") - || !strcmp (IDENTIFIER_POINTER (name), "__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_with_decl (decl, "unknown machine mode `%s'", specified_name); - else if ((typefm = type_for_mode (mode, TREE_UNSIGNED (type))) == 0) - error_with_decl (decl, "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) - { + 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 (is_type) + TYPE_PACKED (type) = 1; + else 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_NOCOMMON: + if (TREE_CODE (decl) == VAR_DECL) + DECL_COMMON (decl) = 0; + else + warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name)); + break; + + case A_COMMON: + if (TREE_CODE (decl) == VAR_DECL) + DECL_COMMON (decl) = 1; + 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_UNUSED: + if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL) + TREE_USED (decl) = 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 (is_type + && TREE_CODE (type) == UNION_TYPE + && (decl == 0 + || (TYPE_FIELDS (type) != 0 + && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))))) + TYPE_TRANSPARENT_UNION (type) = 1; + else 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 + 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; + TREE_USED (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; + TREE_USED (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 - 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) - { - 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 + && ! TREE_STATIC (decl)) + 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 / BITS_PER_UNIT)); + 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; - 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) != VAR_DECL - && TREE_CODE (decl) != FIELD_DECL) - error_with_decl (decl, - "alignment 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 if (TREE_CODE (format_type) == IDENTIFIER_NODE) + { + error ("`%s' is an unrecognized format function type", + IDENTIFIER_POINTER (format_type)); + continue; + } + else + { + error ("unrecognized format specifier"); + 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); + + 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; } - /* 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) + case A_FORMAT_ARG: { - for (arg_num = 1; ; ++arg_num) + tree format_num_expr = TREE_VALUE (args); + int format_num, arg_num; + tree argument; + + if (TREE_CODE (decl) != FUNCTION_DECL) { - if (argument == 0 || arg_num == format_num) - break; - argument = TREE_CHAIN (argument); + error_with_decl (decl, + "argument format specified for non-function `%s'"); + continue; } - if (! argument - || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE - || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument))) - != char_type_node)) + + /* Strip any conversions from the first arg number and verify it + is a constant. */ + 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 (TREE_CODE (format_num_expr) != INTEGER_CST) { - error_with_decl (decl, - "format string arg not a string type, for `%s'"); + error ("format string has non-constant operand number"); continue; } - if (first_arg_num != 0) + + format_num = TREE_INT_CST_LOW (format_num_expr); + + /* 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 (TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) != POINTER_TYPE + || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_TYPE (decl)))) + != char_type_node)) + { + error ("function does not return string type"); + continue; + } + + record_international_format (DECL_NAME (decl), + DECL_ASSEMBLER_NAME (decl), + format_num); + break; } - record_function_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl), - is_scan, format_num, first_arg_num); - } - else - warning ("`%s' attribute directive ignored", - IDENTIFIER_POINTER (name)); + case A_WEAK: + declare_weak (decl); + break; - TREE_TYPE (decl) = build_type_attribute_variant (type, new_attr); + 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; + } + } +} + +/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two + lists. SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE). + + The head of the declspec list is stored in DECLSPECS. + The head of the attribute list is stored in PREFIX_ATTRIBUTES. + + Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of + the list elements. We drop the containing TREE_LIST nodes and link the + resulting attributes together the way decl_attributes expects them. */ + +void +split_specs_attrs (specs_attrs, declspecs, prefix_attributes) + tree specs_attrs; + tree *declspecs, *prefix_attributes; +{ + tree t, s, a, next, specs, attrs; + + /* This can happen in c++ (eg: decl: typespec initdecls ';'). */ + if (specs_attrs != NULL_TREE + && TREE_CODE (specs_attrs) != TREE_LIST) + { + *declspecs = specs_attrs; + *prefix_attributes = NULL_TREE; + return; + } + + /* Remember to keep the lists in the same order, element-wise. */ + + specs = s = NULL_TREE; + attrs = a = NULL_TREE; + for (t = specs_attrs; t; t = next) + { + next = TREE_CHAIN (t); + /* Declspecs have a non-NULL TREE_VALUE. */ + if (TREE_VALUE (t) != NULL_TREE) + { + if (specs == NULL_TREE) + specs = s = t; + else + { + TREE_CHAIN (s) = t; + s = t; + } + } + else + { + if (attrs == NULL_TREE) + attrs = a = TREE_PURPOSE (t); + else + { + TREE_CHAIN (a) = TREE_PURPOSE (t); + a = TREE_PURPOSE (t); + } + /* More attrs can be linked here, move A to the end. */ + while (TREE_CHAIN (a) != NULL_TREE) + a = TREE_CHAIN (a); + } + } + + /* Terminate the lists. */ + if (s != NULL_TREE) + TREE_CHAIN (s) = NULL_TREE; + if (a != NULL_TREE) + TREE_CHAIN (a) = NULL_TREE; + + /* All done. */ + *declspecs = specs; + *prefix_attributes = attrs; } /* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against @@ -570,7 +873,7 @@ static format_char_info print_char_table[] = { { "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_UI, T_UI, T_UL, NULL, NULL, "-wp" }, + { "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" }, @@ -594,7 +897,8 @@ static format_char_info scan_char_table[] = { { NULL } }; -typedef struct function_format_info { +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++) */ @@ -605,14 +909,27 @@ typedef struct function_format_info { static function_format_info *function_format_list = NULL; -static void check_format_info PROTO((function_format_info *, tree)); +typedef struct international_format_info +{ + struct international_format_info *next; /* next structure on the list */ + tree name; /* identifier such as "gettext" */ + tree assembler_name; /* optional mangled identifier (for C++) */ + int format_num; /* number of format argument */ +} international_format_info; + +static international_format_info *international_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 is included or not), since it is common to call printf without including . 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. */ + header file or not. In any case, the checking is harmless. + + Also initialize the name of function that modify the format string for + internationalization purposes. */ void init_function_format_info () @@ -626,6 +943,10 @@ init_function_format_info () 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_international_format (get_identifier ("gettext"), NULL_TREE, 1); + record_international_format (get_identifier ("dgettext"), NULL_TREE, 2); + record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2); } /* Record information for argument format checking. FUNCTION_IDENT is @@ -634,7 +955,7 @@ init_function_format_info () 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 + against the format string, or zero if no checking is not be done (e.g. for varargs such as vfprintf). */ void @@ -670,6 +991,43 @@ record_function_format (name, assembler_name, is_scan, info->first_arg_num = first_arg_num; } +/* Record information for the names of function that modify the format + argument to format functions. FUNCTION_IDENT is the identifier node for + the name of the function (its decl need not exist yet) and FORMAT_NUM is + the number of the argument which is the format control string (starting + from 1). */ + +static void +record_international_format (name, assembler_name, format_num) + tree name; + tree assembler_name; + int format_num; +{ + international_format_info *info; + + /* Re-use existing structure if it's there. */ + + for (info = international_format_list; info; info = info->next) + { + if (info->name == name && info->assembler_name == assembler_name) + break; + } + + if (! info) + { + info + = (international_format_info *) + xmalloc (sizeof (international_format_info)); + info->next = international_format_list; + international_format_list = info; + + info->name = name; + info->assembler_name = assembler_name; + } + + info->format_num = format_num; +} + static char tfaff[] = "too few arguments for format"; /* Check the argument list of a call to printf, scanf, etc. @@ -740,10 +1098,44 @@ check_format_info (info, 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) + + if (TREE_CODE (format_tree) == CALL_EXPR + && TREE_CODE (TREE_OPERAND (format_tree, 0)) == ADDR_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0)) + == FUNCTION_DECL)) + { + tree function = TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0); + + /* See if this is a call to a known internationalization function + that modifies the format arg. */ + international_format_info *info; + + for (info = international_format_list; info; info = info->next) + if (info->assembler_name + ? (info->assembler_name == DECL_ASSEMBLER_NAME (function)) + : (info->name == DECL_NAME (function))) + { + tree inner_args; + int i; + + for (inner_args = TREE_OPERAND (format_tree, 1), i = 1; + inner_args != 0; + inner_args = TREE_CHAIN (inner_args), i++) + if (i == info->format_num) + { + format_tree = TREE_VALUE (inner_args); + + while (TREE_CODE (format_tree) == NOP_EXPR) + format_tree = TREE_OPERAND (format_tree, 0); + } + } + } + + if (integer_zerop (format_tree)) { warning ("null format string"); return; @@ -936,13 +1328,23 @@ check_format_info (info, params) } } } - if (*format_chars == 'h' || *format_chars == 'l' || *format_chars == 'q' || - *format_chars == 'L') + if (*format_chars == 'h' || *format_chars == 'l') length_char = *format_chars++; + else if (*format_chars == 'q' || *format_chars == 'L') + { + length_char = *format_chars++; + if (pedantic) + pedwarn ("ANSI C does not support the `%c' length modifier", + length_char); + } else length_char = 0; if (length_char == 'l' && *format_chars == 'l') - length_char = 'q', format_chars++; + { + length_char = 'q', format_chars++; + if (pedantic) + pedwarn ("ANSI C does not support the `ll' length modifier"); + } aflag = 0; if (*format_chars == 'a') { @@ -957,7 +1359,7 @@ check_format_info (info, params) warning (message); } format_char = *format_chars; - if (format_char == 0) + if (format_char == 0 || format_char == '%') { warning ("conversion lacks type at end of format"); continue; @@ -1039,7 +1441,7 @@ check_format_info (info, params) || format_char == 'x' || format_char == 'x')) { sprintf (message, - "precision and `0' flag not both allowed with `%c' format", + "`0' flag ignored with precision specifier and `%c' format", format_char); warning (message); } @@ -1071,6 +1473,9 @@ check_format_info (info, params) /* 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); @@ -1090,16 +1495,20 @@ check_format_info (info, params) 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); + 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.) */ @@ -1197,7 +1606,8 @@ overflow_warning (value) && TREE_OVERFLOW (value)) { TREE_OVERFLOW (value) = 0; - warning ("integer overflow in expression"); + if (skip_evaluation == 0) + warning ("integer overflow in expression"); } else if ((TREE_CODE (value) == REAL_CST || (TREE_CODE (value) == COMPLEX_CST @@ -1205,7 +1615,8 @@ overflow_warning (value) && TREE_OVERFLOW (value)) { TREE_OVERFLOW (value) = 0; - warning ("floating-pointer overflow in expression"); + if (skip_evaluation == 0) + warning ("floating point overflow in expression"); } } @@ -1221,6 +1632,7 @@ unsigned_conversion_warning (result, operand) if (TREE_CODE (operand) == INTEGER_CST && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE && TREE_UNSIGNED (TREE_TYPE (result)) + && skip_evaluation == 0 && !int_fits_type_p (operand, TREE_TYPE (result))) { if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result)))) @@ -1246,16 +1658,21 @@ convert_and_check (type, expr) { TREE_OVERFLOW (t) = 0; + /* Do not diagnose overflow in a constant expression merely + because a conversion overflowed. */ + TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (expr); + /* No warning for converting 0x80000000 to int. */ if (!(TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (expr)) && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr)))) /* If EXPR fits in the unsigned version of TYPE, don't warn unless pedantic. */ - if (pedantic - || TREE_UNSIGNED (type) - || ! int_fits_type_p (expr, unsigned_type (type))) - warning ("overflow in implicit constant conversion"); + if ((pedantic + || TREE_UNSIGNED (type) + || ! int_fits_type_p (expr, unsigned_type (type))) + && skip_evaluation == 0) + warning ("overflow in implicit constant conversion"); } else unsigned_conversion_warning (t, expr); @@ -1316,15 +1733,15 @@ type_for_size (bits, unsignedp) unsigned bits; int unsignedp; { + if (bits == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + if (bits == TYPE_PRECISION (signed_char_type_node)) return unsignedp ? unsigned_char_type_node : signed_char_type_node; if (bits == TYPE_PRECISION (short_integer_type_node)) return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (bits == TYPE_PRECISION (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - if (bits == TYPE_PRECISION (long_integer_type_node)) return unsignedp ? long_unsigned_type_node : long_integer_type_node; @@ -1356,15 +1773,15 @@ type_for_mode (mode, unsignedp) enum machine_mode mode; int unsignedp; { + if (mode == TYPE_MODE (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + if (mode == TYPE_MODE (signed_char_type_node)) return unsignedp ? unsigned_char_type_node : signed_char_type_node; if (mode == TYPE_MODE (short_integer_type_node)) return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (mode == TYPE_MODE (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - if (mode == TYPE_MODE (long_integer_type_node)) return unsignedp ? long_unsigned_type_node : long_integer_type_node; @@ -1645,40 +2062,40 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) if (code == NE_EXPR) { if (max_lt || min_gt) - val = integer_one_node; + val = boolean_true_node; } else if (code == EQ_EXPR) { if (max_lt || min_gt) - val = integer_zero_node; + val = boolean_false_node; } else if (code == LT_EXPR) { if (max_lt) - val = integer_one_node; + val = boolean_true_node; if (!min_lt) - val = integer_zero_node; + val = boolean_false_node; } else if (code == GT_EXPR) { if (min_gt) - val = integer_one_node; + val = boolean_true_node; if (!max_gt) - val = integer_zero_node; + val = boolean_false_node; } else if (code == LE_EXPR) { if (!max_gt) - val = integer_one_node; + val = boolean_true_node; if (min_gt) - val = integer_zero_node; + val = boolean_false_node; } else if (code == GE_EXPR) { if (!min_lt) - val = integer_one_node; + val = boolean_true_node; if (max_lt) - val = integer_zero_node; + val = boolean_false_node; } /* If primop0 was sign-extended and unsigned comparison specd, @@ -1716,18 +2133,18 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) { /* This is the case of (char)x >?< 0x80, which people used to use expecting old C compilers to change the 0x80 into -0x80. */ - if (val == integer_zero_node) + if (val == boolean_false_node) warning ("comparison is always 0 due to limited range of data type"); - if (val == integer_one_node) + if (val == boolean_true_node) warning ("comparison is always 1 due to limited range of data type"); } if (!min_lt && unsignedp0 && TREE_CODE (primop0) != INTEGER_CST) { /* This is the case of (unsigned char)x >?< -1 or < 0. */ - if (val == integer_zero_node) + if (val == boolean_false_node) warning ("comparison is always 0 due to limited range of data type"); - if (val == integer_one_node) + if (val == boolean_true_node) warning ("comparison is always 1 due to limited range of data type"); } @@ -1795,7 +2212,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) && ! TREE_OVERFLOW (convert (signed_type (type), primop0)))) warning ("unsigned value >= 0 is always 1"); - value = integer_one_node; + value = boolean_true_node; break; case LT_EXPR: @@ -1804,7 +2221,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) && ! TREE_OVERFLOW (convert (signed_type (type), primop0)))) warning ("unsigned value < 0 is always 0"); - value = integer_zero_node; + value = boolean_false_node; } if (value != 0) @@ -1821,7 +2238,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) *op0_ptr = convert (type, primop0); *op1_ptr = convert (type, primop1); - *restype_ptr = integer_type_node; + *restype_ptr = boolean_type_node; return 0; } @@ -1832,10 +2249,10 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) This preparation consists of taking the ordinary representation of an expression expr and producing a valid tree boolean expression describing whether expr is nonzero. We could - simply always do build_binary_op (NE_EXPR, expr, integer_zero_node, 1), + simply always do build_binary_op (NE_EXPR, expr, boolean_false_node, 1), but we optimize comparisons, &&, ||, and !. - The resulting type should always be `integer_type_node'. */ + The resulting type should always be `boolean_type_node'. */ tree truthvalue_conversion (expr) @@ -1851,15 +2268,15 @@ truthvalue_conversion (expr) { case RECORD_TYPE: error ("struct type value used where scalar is required"); - return integer_zero_node; + return boolean_false_node; case UNION_TYPE: error ("union type value used where scalar is required"); - return integer_zero_node; + return boolean_false_node; case ARRAY_TYPE: error ("array type value used where scalar is required"); - return integer_zero_node; + return boolean_false_node; default: break; @@ -1892,23 +2309,31 @@ truthvalue_conversion (expr) case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case TRUTH_XOR_EXPR: - return convert (integer_type_node, expr); + case TRUTH_NOT_EXPR: + TREE_TYPE (expr) = boolean_type_node; + return expr; case ERROR_MARK: return expr; case INTEGER_CST: - return integer_zerop (expr) ? integer_zero_node : integer_one_node; + return integer_zerop (expr) ? boolean_false_node : boolean_true_node; case REAL_CST: - return real_zerop (expr) ? integer_zero_node : integer_one_node; + return real_zerop (expr) ? boolean_false_node : boolean_true_node; case ADDR_EXPR: + /* If we are taking the address of a external decl, it might be zero + if it is weak, so we cannot optimize. */ + if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (expr, 0))) == 'd' + && DECL_EXTERNAL (TREE_OPERAND (expr, 0))) + break; + if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0))) - return build (COMPOUND_EXPR, integer_type_node, - TREE_OPERAND (expr, 0), integer_one_node); + return build (COMPOUND_EXPR, boolean_type_node, + TREE_OPERAND (expr, 0), boolean_true_node); else - return integer_one_node; + return boolean_true_node; case COMPLEX_EXPR: return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)) @@ -1929,14 +2354,14 @@ truthvalue_conversion (expr) /* These don't change whether an object is zero or non-zero, but we can't ignore them if their second arg has side-effects. */ if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))) - return build (COMPOUND_EXPR, integer_type_node, TREE_OPERAND (expr, 1), + return build (COMPOUND_EXPR, boolean_type_node, TREE_OPERAND (expr, 1), truthvalue_conversion (TREE_OPERAND (expr, 0))); else return truthvalue_conversion (TREE_OPERAND (expr, 0)); case COND_EXPR: /* Distribute the conversion into the arms of a COND_EXPR. */ - return fold (build (COND_EXPR, integer_type_node, TREE_OPERAND (expr, 0), + return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0), truthvalue_conversion (TREE_OPERAND (expr, 1)), truthvalue_conversion (TREE_OPERAND (expr, 2)))); @@ -1946,7 +2371,7 @@ truthvalue_conversion (expr) if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE) break; - /* fall through... */ + /* fall through... */ case NOP_EXPR: /* If this is widening the argument, we can ignore it. */ if (TYPE_PRECISION (TREE_TYPE (expr)) @@ -1960,7 +2385,7 @@ truthvalue_conversion (expr) if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE) break; - /* fall through... */ + /* fall through... */ case BIT_XOR_EXPR: /* This and MINUS_EXPR can be changed into a comparison of the two objects. */ @@ -1974,8 +2399,11 @@ truthvalue_conversion (expr) TREE_OPERAND (expr, 1))), 1); case BIT_AND_EXPR: - if (integer_onep (TREE_OPERAND (expr, 1))) - return expr; + if (integer_onep (TREE_OPERAND (expr, 1)) + && TREE_TYPE (expr) != boolean_type_node) + /* Using convert here would cause infinite recursion. */ + return build1 (NOP_EXPR, boolean_type_node, expr); + break; case MODIFY_EXPR: if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR) @@ -2002,7 +2430,10 @@ truthvalue_conversion (expr) a part of the directive. The value is a string in a reusable buffer. It remains valid - only until the next time this function is called. */ + only until the next time this function is called. + + The terminating character ('\n' or EOF) is left in FINPUT for the + caller to re-read. */ char * get_directive_line (finput) @@ -2046,7 +2477,8 @@ get_directive_line (finput) continue; /* Detect the end of the directive. */ - if (c == '\n' && looking_for == 0) + if (looking_for == 0 + && (c == '\n' || c == EOF)) { ungetc (c, finput); c = '\0';