diff options
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 2537 |
1 files changed, 0 insertions, 2537 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c deleted file mode 100644 index d921661578e..00000000000 --- a/gcc/c-common.c +++ /dev/null @@ -1,2537 +0,0 @@ -/* Subroutines shared by all languages that are variants of C. - Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -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, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include "config.h" -#include "tree.h" -#include "c-lex.h" -#include "c-tree.h" -#include "flags.h" -#include "obstack.h" -#include <stdio.h> -#include <ctype.h> - -#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; - -/* 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__. */ - -void -declare_function_name () -{ - char *name, *printable_name; - - if (current_function_decl == NULL) - { - name = ""; - printable_name = "top level"; - } - else - { - /* Allow functions to be nameless (such as artificial ones). */ - if (DECL_NAME (current_function_decl)) - name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl)); - else - name = ""; - printable_name = (*decl_printable_name) (current_function_decl, 2); - } - - declare_hidden_char_array ("__FUNCTION__", name); - declare_hidden_char_array ("__PRETTY_FUNCTION__", printable_name); -} - -static void -declare_hidden_char_array (name, value) - char *name, *value; -{ - tree decl, type, init; - int vlen; - - /* If the default size of char arrays isn't big enough for the name, - or if we want to give warnings for large objects, make a bigger one. */ - vlen = strlen (value) + 1; - type = char_array_type_node; - if (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TREE_TYPE (type))) < vlen - || warn_larger_than) - type = build_array_type (char_type_node, - build_index_type (build_int_2 (vlen, 0))); - push_obstacks_nochange (); - decl = build_decl (VAR_DECL, get_identifier (name), type); - TREE_STATIC (decl) = 1; - 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); - TREE_TYPE (init) = type; - DECL_INITIAL (decl) = init; - finish_decl (pushdecl (decl), init, NULL_TREE); -} - -/* Given a chain of STRING_CST nodes, - concatenate them into one STRING_CST - and give it a suitable array-of-chars data type. */ - -tree -combine_strings (strings) - tree strings; -{ - register tree value, t; - register int length = 1; - int wide_length = 0; - int wide_flag = 0; - int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT; - int nchars; - - if (TREE_CHAIN (strings)) - { - /* More than one in the chain, so concatenate. */ - register char *p, *q; - - /* Don't include the \0 at the end of each substring, - except for the last one. - Count wide strings and ordinary strings separately. */ - for (t = strings; t; t = TREE_CHAIN (t)) - { - if (TREE_TYPE (t) == wchar_array_type_node) - { - wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes); - wide_flag = 1; - } - else - length += (TREE_STRING_LENGTH (t) - 1); - } - - /* If anything is wide, the non-wides will be converted, - which makes them take more space. */ - if (wide_flag) - length = length * wchar_bytes + wide_length; - - p = savealloc (length); - - /* Copy the individual strings into the new combined string. - If the combined string is wide, convert the chars to ints - for any individual strings that are not wide. */ - - q = p; - for (t = strings; t; t = TREE_CHAIN (t)) - { - int len = (TREE_STRING_LENGTH (t) - - ((TREE_TYPE (t) == wchar_array_type_node) - ? wchar_bytes : 1)); - if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag) - { - bcopy (TREE_STRING_POINTER (t), q, len); - q += len; - } - else - { - int i; - for (i = 0; i < len; 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; - } - } - if (wide_flag) - { - int i; - for (i = 0; i < wchar_bytes; i++) - *q++ = 0; - } - else - *q = 0; - - value = make_node (STRING_CST); - TREE_STRING_POINTER (value) = p; - TREE_STRING_LENGTH (value) = length; - TREE_CONSTANT (value) = 1; - } - else - { - value = strings; - length = TREE_STRING_LENGTH (value); - if (TREE_TYPE (value) == wchar_array_type_node) - wide_flag = 1; - } - - /* Compute the number of elements, for the array type. */ - nchars = wide_flag ? length / wchar_bytes : length; - - /* Create the array type for the string constant. - -Wwrite-strings says make the string constant an array of const char - so that copying it to a non-const pointer will get a warning. */ - if (warn_write_strings - && (! flag_traditional && ! flag_writable_strings)) - { - tree elements - = build_type_variant (wide_flag ? wchar_type_node : char_type_node, - 1, 0); - TREE_TYPE (value) - = build_array_type (elements, - build_index_type (build_int_2 (nchars - 1, 0))); - } - else - TREE_TYPE (value) - = build_array_type (wide_flag ? wchar_type_node : char_type_node, - build_index_type (build_int_2 (nchars - 1, 0))); - TREE_CONSTANT (value) = 1; - TREE_STATIC (value) = 1; - 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, 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 (node, attributes, prefix_attributes) - tree node, attributes, prefix_attributes; -{ - 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; - - attributes = chainon (prefix_attributes, attributes); - - for (a = attributes; a; a = TREE_CHAIN (a)) - { - 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)); - 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) - && 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 (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 / 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; - - 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 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; - } - - /* 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_FORMAT_ARG: - { - tree format_num_expr = TREE_VALUE (args); - int format_num, arg_num; - tree argument; - - if (TREE_CODE (decl) != FUNCTION_DECL) - { - error_with_decl (decl, - "argument format specified for non-function `%s'"); - continue; - } - - /* 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 ("format string has non-constant operand number"); - continue; - } - - 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) - { - 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 (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; - } - - 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; - } - } -} - -/* 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 - 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 &sizetype - -typedef 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; - -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 <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. - - Also initialize the name of function that modify the format string for - internationalization purposes. */ - -void -init_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_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 - 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 the format string, or zero if no checking is not be done - (e.g. for varargs such as vfprintf). */ - -void -record_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; -} - -/* 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. - 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. */ - -void -check_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 void -check_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 - 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 (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; - } - 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') - 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++; - if (pedantic) - pedwarn ("ANSI C does not support the `ll' length modifier"); - } - 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 || format_char == '%') - { - 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, - "`0' flag ignored with precision specifier and `%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) - && TYPE_NAME (cur_type) != 0 - && TREE_CODE (TYPE_NAME (cur_type)) == TYPE_DECL) - that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type))); - - if (strcmp (this, that) != 0) - { - sprintf (message, "%s format, %s arg (arg %d)", - this, that, arg_num); - warning (message); - } - } - } -} - -/* Print a warning if a constant expression had overflow in folding. - Invoke this function on every expression that the language - requires to be a constant expression. - Note the ANSI C standard says it is erroneous for a - constant expression to overflow. */ - -void -constant_expression_warning (value) - tree value; -{ - if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST - || TREE_CODE (value) == COMPLEX_CST) - && TREE_CONSTANT_OVERFLOW (value) && pedantic) - pedwarn ("overflow in constant expression"); -} - -/* Print a warning if an expression had overflow in folding. - Invoke this function on every expression that - (1) appears in the source code, and - (2) might be a constant expression that overflowed, and - (3) is not already checked by convert_and_check; - however, do not invoke this function on operands of explicit casts. */ - -void -overflow_warning (value) - tree value; -{ - if ((TREE_CODE (value) == INTEGER_CST - || (TREE_CODE (value) == COMPLEX_CST - && TREE_CODE (TREE_REALPART (value)) == INTEGER_CST)) - && TREE_OVERFLOW (value)) - { - TREE_OVERFLOW (value) = 0; - if (skip_evaluation == 0) - warning ("integer overflow in expression"); - } - else if ((TREE_CODE (value) == REAL_CST - || (TREE_CODE (value) == COMPLEX_CST - && TREE_CODE (TREE_REALPART (value)) == REAL_CST)) - && TREE_OVERFLOW (value)) - { - TREE_OVERFLOW (value) = 0; - if (skip_evaluation == 0) - warning ("floating point overflow in expression"); - } -} - -/* Print a warning if a large constant is truncated to unsigned, - or if -Wconversion is used and a constant < 0 is converted to unsigned. - Invoke this function on every expression that might be implicitly - converted to an unsigned type. */ - -void -unsigned_conversion_warning (result, operand) - tree 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)))) - /* This detects cases like converting -129 or 256 to unsigned char. */ - warning ("large integer implicitly truncated to unsigned type"); - else if (warn_conversion) - warning ("negative integer implicitly converted to unsigned type"); - } -} - -/* Convert EXPR to TYPE, warning about conversion problems with constants. - Invoke this function on every expression that is converted implicitly, - i.e. because of language rules and not because of an explicit cast. */ - -tree -convert_and_check (type, expr) - tree type, expr; -{ - tree t = convert (type, expr); - if (TREE_CODE (t) == INTEGER_CST) - { - if (TREE_OVERFLOW (t)) - { - 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))) - && skip_evaluation == 0) - warning ("overflow in implicit constant conversion"); - } - else - unsigned_conversion_warning (t, expr); - } - return t; -} - -void -c_expand_expr_stmt (expr) - tree expr; -{ - /* Do default conversion if safe and possibly important, - in case within ({...}). */ - if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr)) - || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE) - expr = default_conversion (expr); - - if (TREE_TYPE (expr) != error_mark_node - && TYPE_SIZE (TREE_TYPE (expr)) == 0 - && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE) - error ("expression statement has incomplete type"); - - expand_expr_stmt (expr); -} - -/* Validate the expression after `case' and apply default promotions. */ - -tree -check_case_value (value) - tree value; -{ - if (value == NULL_TREE) - return value; - - /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ - STRIP_TYPE_NOPS (value); - - if (TREE_CODE (value) != INTEGER_CST - && value != error_mark_node) - { - error ("case label does not reduce to an integer constant"); - value = error_mark_node; - } - else - /* Promote char or short to int. */ - value = default_conversion (value); - - constant_expression_warning (value); - - return value; -} - -/* Return an integer type with BITS bits of precision, - that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ - -tree -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 (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - - if (bits == TYPE_PRECISION (long_long_integer_type_node)) - return (unsignedp ? long_long_unsigned_type_node - : long_long_integer_type_node); - - if (bits <= TYPE_PRECISION (intQI_type_node)) - return unsignedp ? unsigned_intQI_type_node : intQI_type_node; - - if (bits <= TYPE_PRECISION (intHI_type_node)) - return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - - if (bits <= TYPE_PRECISION (intSI_type_node)) - return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - - if (bits <= TYPE_PRECISION (intDI_type_node)) - return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - - return 0; -} - -/* Return a data type that has machine mode MODE. - If the mode is an integer, - then UNSIGNEDP selects between signed and unsigned types. */ - -tree -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 (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - - if (mode == TYPE_MODE (long_long_integer_type_node)) - return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node; - - if (mode == TYPE_MODE (intQI_type_node)) - return unsignedp ? unsigned_intQI_type_node : intQI_type_node; - - if (mode == TYPE_MODE (intHI_type_node)) - return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - - if (mode == TYPE_MODE (intSI_type_node)) - return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - - if (mode == TYPE_MODE (intDI_type_node)) - return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - - if (mode == TYPE_MODE (float_type_node)) - return float_type_node; - - if (mode == TYPE_MODE (double_type_node)) - return double_type_node; - - if (mode == TYPE_MODE (long_double_type_node)) - return long_double_type_node; - - if (mode == TYPE_MODE (build_pointer_type (char_type_node))) - return build_pointer_type (char_type_node); - - if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) - return build_pointer_type (integer_type_node); - - return 0; -} - -/* Return the minimum number of bits needed to represent VALUE in a - signed or unsigned type, UNSIGNEDP says which. */ - -int -min_precision (value, unsignedp) - tree value; - int unsignedp; -{ - int log; - - /* If the value is negative, compute its negative minus 1. The latter - adjustment is because the absolute value of the largest negative value - is one larger than the largest positive value. This is equivalent to - a bit-wise negation, so use that operation instead. */ - - if (tree_int_cst_sgn (value) < 0) - value = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (value), value)); - - /* Return the number of bits needed, taking into account the fact - that we need one more bit for a signed than unsigned type. */ - - if (integer_zerop (value)) - log = 0; - else if (TREE_INT_CST_HIGH (value) != 0) - log = HOST_BITS_PER_WIDE_INT + floor_log2 (TREE_INT_CST_HIGH (value)); - else - log = floor_log2 (TREE_INT_CST_LOW (value)); - - return log + 1 + ! unsignedp; -} - -/* Print an error message for invalid operands to arith operation CODE. - NOP_EXPR is used as a special case (see truthvalue_conversion). */ - -void -binary_op_error (code) - enum tree_code code; -{ - register char *opname = "unknown"; - - switch (code) - { - case NOP_EXPR: - error ("invalid truth-value expression"); - return; - - case PLUS_EXPR: - opname = "+"; break; - case MINUS_EXPR: - opname = "-"; break; - case MULT_EXPR: - opname = "*"; break; - case MAX_EXPR: - opname = "max"; break; - case MIN_EXPR: - opname = "min"; break; - case EQ_EXPR: - opname = "=="; break; - case NE_EXPR: - opname = "!="; break; - case LE_EXPR: - opname = "<="; break; - case GE_EXPR: - opname = ">="; break; - case LT_EXPR: - opname = "<"; break; - case GT_EXPR: - opname = ">"; break; - case LSHIFT_EXPR: - opname = "<<"; break; - case RSHIFT_EXPR: - opname = ">>"; break; - case TRUNC_MOD_EXPR: - case FLOOR_MOD_EXPR: - opname = "%"; break; - case TRUNC_DIV_EXPR: - case FLOOR_DIV_EXPR: - opname = "/"; break; - case BIT_AND_EXPR: - opname = "&"; break; - case BIT_IOR_EXPR: - opname = "|"; break; - case TRUTH_ANDIF_EXPR: - opname = "&&"; break; - case TRUTH_ORIF_EXPR: - opname = "||"; break; - case BIT_XOR_EXPR: - opname = "^"; break; - case LROTATE_EXPR: - case RROTATE_EXPR: - opname = "rotate"; break; - } - error ("invalid operands to binary %s", opname); -} - -/* Subroutine of build_binary_op, used for comparison operations. - See if the operands have both been converted from subword integer types - and, if so, perhaps change them both back to their original type. - This function is also responsible for converting the two operands - to the proper common type for comparison. - - The arguments of this function are all pointers to local variables - of build_binary_op: OP0_PTR is &OP0, OP1_PTR is &OP1, - RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE. - - If this function returns nonzero, it means that the comparison has - a constant value. What this function returns is an expression for - that value. */ - -tree -shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) - tree *op0_ptr, *op1_ptr; - tree *restype_ptr; - enum tree_code *rescode_ptr; -{ - register tree type; - tree op0 = *op0_ptr; - tree op1 = *op1_ptr; - int unsignedp0, unsignedp1; - int real1, real2; - tree primop0, primop1; - enum tree_code code = *rescode_ptr; - - /* Throw away any conversions to wider types - already present in the operands. */ - - primop0 = get_narrower (op0, &unsignedp0); - primop1 = get_narrower (op1, &unsignedp1); - - /* Handle the case that OP0 does not *contain* a conversion - but it *requires* conversion to FINAL_TYPE. */ - - if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr) - unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0)); - if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr) - unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1)); - - /* If one of the operands must be floated, we cannot optimize. */ - real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE; - real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE; - - /* If first arg is constant, swap the args (changing operation - so value is preserved), for canonicalization. Don't do this if - the second arg is 0. */ - - if (TREE_CONSTANT (primop0) - && ! integer_zerop (primop1) && ! real_zerop (primop1)) - { - register tree tem = primop0; - register int temi = unsignedp0; - primop0 = primop1; - primop1 = tem; - tem = op0; - op0 = op1; - op1 = tem; - *op0_ptr = op0; - *op1_ptr = op1; - unsignedp0 = unsignedp1; - unsignedp1 = temi; - temi = real1; - real1 = real2; - real2 = temi; - - switch (code) - { - case LT_EXPR: - code = GT_EXPR; - break; - case GT_EXPR: - code = LT_EXPR; - break; - case LE_EXPR: - code = GE_EXPR; - break; - case GE_EXPR: - code = LE_EXPR; - break; - } - *rescode_ptr = code; - } - - /* If comparing an integer against a constant more bits wide, - maybe we can deduce a value of 1 or 0 independent of the data. - Or else truncate the constant now - rather than extend the variable at run time. - - This is only interesting if the constant is the wider arg. - Also, it is not safe if the constant is unsigned and the - variable arg is signed, since in this case the variable - would be sign-extended and then regarded as unsigned. - Our technique fails in this case because the lowest/highest - possible unsigned results don't follow naturally from the - lowest/highest possible values of the variable operand. - For just EQ_EXPR and NE_EXPR there is another technique that - could be used: see if the constant can be faithfully represented - in the other operand's type, by truncating it and reextending it - and see if that preserves the constant's value. */ - - if (!real1 && !real2 - && TREE_CODE (primop1) == INTEGER_CST - && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)) - { - int min_gt, max_gt, min_lt, max_lt; - tree maxval, minval; - /* 1 if comparison is nominally unsigned. */ - int unsignedp = TREE_UNSIGNED (*restype_ptr); - tree val; - - type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)); - - maxval = TYPE_MAX_VALUE (type); - minval = TYPE_MIN_VALUE (type); - - if (unsignedp && !unsignedp0) - *restype_ptr = signed_type (*restype_ptr); - - if (TREE_TYPE (primop1) != *restype_ptr) - primop1 = convert (*restype_ptr, primop1); - if (type != *restype_ptr) - { - minval = convert (*restype_ptr, minval); - maxval = convert (*restype_ptr, maxval); - } - - if (unsignedp && unsignedp0) - { - min_gt = INT_CST_LT_UNSIGNED (primop1, minval); - max_gt = INT_CST_LT_UNSIGNED (primop1, maxval); - min_lt = INT_CST_LT_UNSIGNED (minval, primop1); - max_lt = INT_CST_LT_UNSIGNED (maxval, primop1); - } - else - { - min_gt = INT_CST_LT (primop1, minval); - max_gt = INT_CST_LT (primop1, maxval); - min_lt = INT_CST_LT (minval, primop1); - max_lt = INT_CST_LT (maxval, primop1); - } - - val = 0; - /* This used to be a switch, but Genix compiler can't handle that. */ - if (code == NE_EXPR) - { - if (max_lt || min_gt) - val = boolean_true_node; - } - else if (code == EQ_EXPR) - { - if (max_lt || min_gt) - val = boolean_false_node; - } - else if (code == LT_EXPR) - { - if (max_lt) - val = boolean_true_node; - if (!min_lt) - val = boolean_false_node; - } - else if (code == GT_EXPR) - { - if (min_gt) - val = boolean_true_node; - if (!max_gt) - val = boolean_false_node; - } - else if (code == LE_EXPR) - { - if (!max_gt) - val = boolean_true_node; - if (min_gt) - val = boolean_false_node; - } - else if (code == GE_EXPR) - { - if (!min_lt) - val = boolean_true_node; - if (max_lt) - val = boolean_false_node; - } - - /* If primop0 was sign-extended and unsigned comparison specd, - we did a signed comparison above using the signed type bounds. - But the comparison we output must be unsigned. - - Also, for inequalities, VAL is no good; but if the signed - comparison had *any* fixed result, it follows that the - unsigned comparison just tests the sign in reverse - (positive values are LE, negative ones GE). - So we can generate an unsigned comparison - against an extreme value of the signed type. */ - - if (unsignedp && !unsignedp0) - { - if (val != 0) - switch (code) - { - case LT_EXPR: - case GE_EXPR: - primop1 = TYPE_MIN_VALUE (type); - val = 0; - break; - - case LE_EXPR: - case GT_EXPR: - primop1 = TYPE_MAX_VALUE (type); - val = 0; - break; - } - type = unsigned_type (type); - } - - if (!max_gt && !unsignedp0 && TREE_CODE (primop0) != INTEGER_CST) - { - /* 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 == boolean_false_node) - warning ("comparison is always 0 due to limited range of data type"); - 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 == boolean_false_node) - warning ("comparison is always 0 due to limited range of data type"); - if (val == boolean_true_node) - warning ("comparison is always 1 due to limited range of data type"); - } - - if (val != 0) - { - /* Don't forget to evaluate PRIMOP0 if it has side effects. */ - if (TREE_SIDE_EFFECTS (primop0)) - return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val); - return val; - } - - /* Value is not predetermined, but do the comparison - in the type of the operand that is not constant. - TYPE is already properly set. */ - } - else if (real1 && real2 - && (TYPE_PRECISION (TREE_TYPE (primop0)) - == TYPE_PRECISION (TREE_TYPE (primop1)))) - type = TREE_TYPE (primop0); - - /* If args' natural types are both narrower than nominal type - and both extend in the same manner, compare them - in the type of the wider arg. - Otherwise must actually extend both to the nominal - common type lest different ways of extending - alter the result. - (eg, (short)-1 == (unsigned short)-1 should be 0.) */ - - else if (unsignedp0 == unsignedp1 && real1 == real2 - && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr) - && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)) - { - type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)); - type = signed_or_unsigned_type (unsignedp0 - || TREE_UNSIGNED (*restype_ptr), - type); - /* Make sure shorter operand is extended the right way - to match the longer operand. */ - primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)), - primop0); - primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)), - primop1); - } - else - { - /* Here we must do the comparison on the nominal type - using the args exactly as we received them. */ - type = *restype_ptr; - primop0 = op0; - primop1 = op1; - - if (!real1 && !real2 && integer_zerop (primop1) - && TREE_UNSIGNED (*restype_ptr)) - { - tree value = 0; - switch (code) - { - case GE_EXPR: - /* All unsigned values are >= 0, so we warn if extra warnings - are requested. However, if OP0 is a constant that is - >= 0, the signedness of the comparison isn't an issue, - so suppress the warning. */ - if (extra_warnings - && ! (TREE_CODE (primop0) == INTEGER_CST - && ! TREE_OVERFLOW (convert (signed_type (type), - primop0)))) - warning ("unsigned value >= 0 is always 1"); - value = boolean_true_node; - break; - - case LT_EXPR: - if (extra_warnings - && ! (TREE_CODE (primop0) == INTEGER_CST - && ! TREE_OVERFLOW (convert (signed_type (type), - primop0)))) - warning ("unsigned value < 0 is always 0"); - value = boolean_false_node; - } - - if (value != 0) - { - /* Don't forget to evaluate PRIMOP0 if it has side effects. */ - if (TREE_SIDE_EFFECTS (primop0)) - return build (COMPOUND_EXPR, TREE_TYPE (value), - primop0, value); - return value; - } - } - } - - *op0_ptr = convert (type, primop0); - *op1_ptr = convert (type, primop1); - - *restype_ptr = boolean_type_node; - - return 0; -} - -/* Prepare expr to be an argument of a TRUTH_NOT_EXPR, - or validate its data type for an `if' or `while' statement or ?..: exp. - - 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, boolean_false_node, 1), - but we optimize comparisons, &&, ||, and !. - - The resulting type should always be `boolean_type_node'. */ - -tree -truthvalue_conversion (expr) - tree expr; -{ - if (TREE_CODE (expr) == ERROR_MARK) - return expr; - -#if 0 /* This appears to be wrong for C++. */ - /* These really should return error_mark_node after 2.4 is stable. - But not all callers handle ERROR_MARK properly. */ - switch (TREE_CODE (TREE_TYPE (expr))) - { - case RECORD_TYPE: - error ("struct type value used where scalar is required"); - return boolean_false_node; - - case UNION_TYPE: - error ("union type value used where scalar is required"); - return boolean_false_node; - - case ARRAY_TYPE: - error ("array type value used where scalar is required"); - return boolean_false_node; - - default: - break; - } -#endif /* 0 */ - - switch (TREE_CODE (expr)) - { - /* It is simpler and generates better code to have only TRUTH_*_EXPR - or comparison expressions as truth values at this level. */ -#if 0 - case COMPONENT_REF: - /* A one-bit unsigned bit-field is already acceptable. */ - if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1))) - && TREE_UNSIGNED (TREE_OPERAND (expr, 1))) - return expr; - break; -#endif - - case EQ_EXPR: - /* It is simpler and generates better code to have only TRUTH_*_EXPR - or comparison expressions as truth values at this level. */ -#if 0 - if (integer_zerop (TREE_OPERAND (expr, 1))) - return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0); -#endif - case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_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) ? boolean_false_node : boolean_true_node; - - case REAL_CST: - 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, boolean_type_node, - TREE_OPERAND (expr, 0), boolean_true_node); - else - return boolean_true_node; - - case COMPLEX_EXPR: - return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)) - ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), - truthvalue_conversion (TREE_OPERAND (expr, 0)), - truthvalue_conversion (TREE_OPERAND (expr, 1)), - 0); - - case NEGATE_EXPR: - case ABS_EXPR: - case FLOAT_EXPR: - case FFS_EXPR: - /* These don't change whether an object is non-zero or zero. */ - return truthvalue_conversion (TREE_OPERAND (expr, 0)); - - case LROTATE_EXPR: - case RROTATE_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, 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, boolean_type_node, TREE_OPERAND (expr, 0), - truthvalue_conversion (TREE_OPERAND (expr, 1)), - truthvalue_conversion (TREE_OPERAND (expr, 2)))); - - case CONVERT_EXPR: - /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE, - since that affects how `default_conversion' will behave. */ - if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE - || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE) - break; - /* fall through... */ - case NOP_EXPR: - /* If this is widening the argument, we can ignore it. */ - if (TYPE_PRECISION (TREE_TYPE (expr)) - >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) - return truthvalue_conversion (TREE_OPERAND (expr, 0)); - break; - - case MINUS_EXPR: - /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize - this case. */ - if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT - && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE) - break; - /* fall through... */ - case BIT_XOR_EXPR: - /* This and MINUS_EXPR can be changed into a comparison of the - two objects. */ - if (TREE_TYPE (TREE_OPERAND (expr, 0)) - == TREE_TYPE (TREE_OPERAND (expr, 1))) - return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0), - TREE_OPERAND (expr, 1), 1); - return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0), - fold (build1 (NOP_EXPR, - TREE_TYPE (TREE_OPERAND (expr, 0)), - TREE_OPERAND (expr, 1))), 1); - - case BIT_AND_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) - warning ("suggest parentheses around assignment used as truth value"); - break; - } - - if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE) - return (build_binary_op - ((TREE_SIDE_EFFECTS (expr) - ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR), - truthvalue_conversion (build_unary_op (REALPART_EXPR, expr, 0)), - truthvalue_conversion (build_unary_op (IMAGPART_EXPR, expr, 0)), - 0)); - - return build_binary_op (NE_EXPR, expr, integer_zero_node, 1); -} - -/* Read the rest of a #-directive from input stream FINPUT. - In normal use, the directive name and the white space after it - have already been read, so they won't be included in the result. - We allow for the fact that the directive line may contain - a newline embedded within a character or string literal which forms - 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. - - The terminating character ('\n' or EOF) is left in FINPUT for the - caller to re-read. */ - -char * -get_directive_line (finput) - register FILE *finput; -{ - static char *directive_buffer = NULL; - static unsigned buffer_length = 0; - register char *p; - register char *buffer_limit; - register int looking_for = 0; - register int char_escaped = 0; - - if (buffer_length == 0) - { - directive_buffer = (char *)xmalloc (128); - buffer_length = 128; - } - - buffer_limit = &directive_buffer[buffer_length]; - - for (p = directive_buffer; ; ) - { - int c; - - /* Make buffer bigger if it is full. */ - if (p >= buffer_limit) - { - register unsigned bytes_used = (p - directive_buffer); - - buffer_length *= 2; - directive_buffer - = (char *)xrealloc (directive_buffer, buffer_length); - p = &directive_buffer[bytes_used]; - buffer_limit = &directive_buffer[buffer_length]; - } - - c = getc (finput); - - /* Discard initial whitespace. */ - if ((c == ' ' || c == '\t') && p == directive_buffer) - continue; - - /* Detect the end of the directive. */ - if (looking_for == 0 - && (c == '\n' || c == EOF)) - { - ungetc (c, finput); - c = '\0'; - } - - *p++ = c; - - if (c == 0) - return directive_buffer; - - /* Handle string and character constant syntax. */ - if (looking_for) - { - if (looking_for == c && !char_escaped) - looking_for = 0; /* Found terminator... stop looking. */ - } - else - if (c == '\'' || c == '"') - looking_for = c; /* Don't stop buffering until we see another - another one of these (or an EOF). */ - - /* Handle backslash. */ - char_escaped = (c == '\\' && ! char_escaped); - } -} - -/* Make a variant type in the proper way for C/C++, propagating qualifiers - down to the element type of an array. */ - -tree -c_build_type_variant (type, constp, volatilep) - tree type; - int constp, volatilep; -{ - if (TREE_CODE (type) == ARRAY_TYPE) - { - tree real_main_variant = TYPE_MAIN_VARIANT (type); - - push_obstacks (TYPE_OBSTACK (real_main_variant), - TYPE_OBSTACK (real_main_variant)); - type = build_array_type (c_build_type_variant (TREE_TYPE (type), - constp, volatilep), - TYPE_DOMAIN (type)); - - /* TYPE must be on same obstack as REAL_MAIN_VARIANT. If not, - make a copy. (TYPE might have come from the hash table and - REAL_MAIN_VARIANT might be in some function's obstack.) */ - - if (TYPE_OBSTACK (type) != TYPE_OBSTACK (real_main_variant)) - { - type = copy_node (type); - TYPE_POINTER_TO (type) = TYPE_REFERENCE_TO (type) = 0; - } - - TYPE_MAIN_VARIANT (type) = real_main_variant; - pop_obstacks (); - } - return build_type_variant (type, constp, volatilep); -} |