diff --git a/gcc/c-common.c b/gcc/c-common.c new file mode 100644 index 00000000000..a65a49c81a4 --- /dev/null +++ b/gcc/c-common.c @@ -0,0 +1,894 @@ +/* Subroutines shared by all languages that are variants of C. + Copyright (C) 1992 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" +#include "tree.h" +#include "c-lex.h" +#include "c-tree.h" +#include "flags.h" +#include + +#undef NULL +#define NULL 0 + +/* 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++) + ((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; +} + +/* Process the attributes listed in ATTRIBUTES + and install them in DECL. */ + +void +decl_attributes (decl, attributes) + tree decl, attributes; +{ + tree a; + for (a = attributes; a; a = TREE_CHAIN (a)) + if (TREE_VALUE (a) != 0 + && TREE_CODE (TREE_VALUE (a)) == TREE_LIST + && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("aligned")) + { + int align = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (a))) + * BITS_PER_UNIT; + + if (exact_log2 (align) == -1) + warning_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) + warning_with_decl (decl, + "alignment specified for `%s' which is not a variable"); + + /* ??? The maximum alignment gcc can currently handle is 16 bytes! + We should change the representation to be the log of the + actual alignment since we only handle powers of 2 anyway. */ + else if (align > 255) + warning_with_decl (decl, + "requested alignment of `%s' exceeds compiler limits"); + else + DECL_ALIGN (decl) = align; + } + else if (TREE_VALUE (a) != 0 + && TREE_CODE (TREE_VALUE (a)) == TREE_LIST + && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("packed")) + { + if (TREE_CODE (decl) == FIELD_DECL) + DECL_PACKED (decl) = 1; + } + else if (TREE_VALUE (a) != 0 + && TREE_CODE (TREE_VALUE (a)) == TREE_LIST + && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("format")) + { + tree list = TREE_VALUE (TREE_VALUE (a)); + tree format_type = TREE_PURPOSE (list); + int format_num = TREE_INT_CST_LOW (TREE_PURPOSE (TREE_VALUE (list))); + int first_arg_num = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (list))); + int is_scan; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + warning_with_decl (decl, + "argument format specified for non-function `%s'"); + return; + } + + if (format_type == get_identifier ("printf")) + is_scan = 0; + else if (format_type == get_identifier ("scanf")) + is_scan = 1; + else + { + warning_with_decl (decl,"unrecognized format specifier for `%s'"); + return; + } + + if (first_arg_num != 0 && first_arg_num <= format_num) + { + warning_with_decl (decl, + "format string arg follows the args to be formatted, for `%s'"); + return; + } + + record_format_info (DECL_NAME (decl), is_scan, format_num, + first_arg_num); + } +} + +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. */ + if (TREE_CODE (value) == NON_LVALUE_EXPR) + value = TREE_OPERAND (value, 0); + + 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); + + 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 (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; + + if (bits <= TYPE_PRECISION (long_long_integer_type_node)) + return (unsignedp ? long_long_unsigned_type_node + : long_long_integer_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 (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; + + 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 (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; +} + +/* 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; + 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: + opname = "%"; break; + case TRUNC_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; + } + 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. + + 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. */ + + if (TREE_CONSTANT (primop0)) + { + 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 = integer_one_node; + } + else if (code == EQ_EXPR) + { + if (max_lt || min_gt) + val = integer_zero_node; + } + else if (code == LT_EXPR) + { + if (max_lt) + val = integer_one_node; + if (!min_lt) + val = integer_zero_node; + } + else if (code == GT_EXPR) + { + if (min_gt) + val = integer_one_node; + if (!max_gt) + val = integer_zero_node; + } + else if (code == LE_EXPR) + { + if (!max_gt) + val = integer_one_node; + if (min_gt) + val = integer_zero_node; + } + else if (code == GE_EXPR) + { + if (!min_lt) + val = integer_one_node; + if (max_lt) + val = integer_zero_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_lt && !unsignedp0) + { + /* 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) + warning ("comparison is always 0 due to limited range of data type"); + if (val == integer_one_node) + warning ("comparison is always 1 due to limited range of data type"); + } + + if (min_gt && unsignedp0) + { + /* This is the case of (unsigned char)x >?< -1. */ + if (val == integer_zero_node) + warning ("comparison is always 0 due to limited range of data type"); + if (val == integer_one_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 (TREE_TYPE (primop0))) + { + tree value = 0; + switch (code) + { + case GE_EXPR: + if (extra_warnings) + warning ("unsigned value >= 0 is always 1"); + value = integer_one_node; + break; + + case LT_EXPR: + if (extra_warnings) + warning ("unsigned value < 0 is always 0"); + value = integer_zero_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 = integer_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, integer_zero_node, 1), + but we optimize comparisons, &&, ||, and !. + + The resulting type should always be `integer_type_node'. */ + +tree +truthvalue_conversion (expr) + tree expr; +{ + register enum tree_code code; + + 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 ERROR_MARK: + return expr; + + case INTEGER_CST: + return integer_zerop (expr) ? integer_zero_node : integer_one_node; + + case REAL_CST: + return real_zerop (expr) ? integer_zero_node : integer_one_node; + + case ADDR_EXPR: + if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0))) + return build (COMPOUND_EXPR, integer_type_node, + TREE_OPERAND (expr, 0), integer_one_node); + else + return integer_one_node; + + 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, integer_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), + 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 BIT_XOR_EXPR: + case MINUS_EXPR: + /* These 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); + } + + 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. */ + +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 (c == '\n' && looking_for == 0) + { + 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); + } +}