/* Utility routines for data type conversion for GNU C.
- Copyright (C) 1987, 1988, 1991, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91, 92, 94, 1995 Free Software Foundation, Inc.
This file is part of GNU C.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* These routines are somewhat language-independent utility function
- intended to be called by the language-specific convert () functions. */
+ intended to be called by the language-specific convert () functions. */
#include "config.h"
#include "tree.h"
#include "flags.h"
#include "convert.h"
-/* Convert EXPR to some pointer type TYPE.
+/* Convert EXPR to some pointer or reference type TYPE.
- EXPR must be pointer, integer, enumeral, or literal zero;
- in other cases error is called. */
+ EXPR must be pointer, reference, integer, enumeral, or literal zero;
+ in other cases error is called. */
tree
convert_to_pointer (type, expr)
if (integer_zerop (expr))
{
- if (type == TREE_TYPE (null_pointer_node))
- return null_pointer_node;
expr = build_int_2 (0, 0);
TREE_TYPE (expr) = type;
return expr;
}
- if (form == POINTER_TYPE)
+ if (form == POINTER_TYPE || form == REFERENCE_TYPE)
return build1 (NOP_EXPR, type, expr);
error ("cannot convert to a pointer type");
- return null_pointer_node;
+ expr = build_int_2 (0, 0);
+ TREE_TYPE (expr) = type;
+ return expr;
}
/* Convert EXPR to some floating-point type TYPE.
EXPR must be float, integer, or enumeral;
- in other cases error is called. */
+ in other cases error is called. */
tree
convert_to_real (type, expr)
return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
type, expr);
- if (form == INTEGER_TYPE || form == ENUMERAL_TYPE)
+ if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
return build1 (FLOAT_EXPR, type, expr);
if (form == COMPLEX_TYPE)
return convert (type, fold (build1 (REALPART_EXPR,
TREE_TYPE (TREE_TYPE (expr)), expr)));
- if (form == POINTER_TYPE)
+ if (form == POINTER_TYPE || form == REFERENCE_TYPE)
error ("pointer value used where a floating point value was expected");
else
error ("aggregate value used where a float was expected");
{
register tree tem = make_node (REAL_CST);
TREE_TYPE (tem) = type;
- TREE_REAL_CST (tem) = REAL_VALUE_ATOF ("0.0");
+ TREE_REAL_CST (tem) = REAL_VALUE_ATOF ("0.0", TYPE_MODE (type));
return tem;
}
}
register tree intype = TREE_TYPE (expr);
register enum tree_code form = TREE_CODE (intype);
- if (form == POINTER_TYPE)
+ if (form == POINTER_TYPE || form == REFERENCE_TYPE)
{
if (integer_zerop (expr))
expr = integer_zero_node;
/* If we are widening the type, put in an explicit conversion.
Similarly if we are not changing the width. However, if this is
a logical operation that just returns 0 or 1, we can change the
- type of the expression (see below). */
+ type of the expression. For logical operations, we must
+ also change the types of the operands to maintain type
+ correctness. */
- if (TREE_CODE_CLASS (ex_form) == '<'
- || ex_form == TRUTH_AND_EXPR || ex_form == TRUTH_ANDIF_EXPR
- || ex_form == TRUTH_OR_EXPR || ex_form == TRUTH_ORIF_EXPR
- || ex_form == TRUTH_XOR_EXPR || ex_form == TRUTH_NOT_EXPR)
+ if (TREE_CODE_CLASS (ex_form) == '<')
+ {
+ TREE_TYPE (expr) = type;
+ return expr;
+ }
+ else if (ex_form == TRUTH_AND_EXPR || ex_form == TRUTH_ANDIF_EXPR
+ || ex_form == TRUTH_OR_EXPR || ex_form == TRUTH_ORIF_EXPR
+ || ex_form == TRUTH_XOR_EXPR)
{
+ TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0));
+ TREE_OPERAND (expr, 1) = convert (type, TREE_OPERAND (expr, 1));
+ TREE_TYPE (expr) = type;
+ return expr;
+ }
+ else if (ex_form == TRUTH_NOT_EXPR)
+ {
+ TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0));
TREE_TYPE (expr) = type;
return expr;
}
else if (outprec >= inprec)
return build1 (NOP_EXPR, type, expr);
-/* Here detect when we can distribute the truncation down past some arithmetic.
- For example, if adding two longs and converting to an int,
- we can equally well convert both to ints and then add.
- For the operations handled here, such truncation distribution
- is always safe.
- It is desirable in these cases:
- 1) when truncating down to full-word from a larger size
- 2) when truncating takes no work.
- 3) when at least one operand of the arithmetic has been extended
- (as by C's default conversions). In this case we need two conversions
- if we do the arithmetic as already requested, so we might as well
- truncate both and then combine. Perhaps that way we need only one.
-
- Note that in general we cannot do the arithmetic in a type
- shorter than the desired result of conversion, even if the operands
- are both extended from a shorter type, because they might overflow
- if combined in that type. The exceptions to this--the times when
- two narrow values can be combined in their narrow type even to
- make a wider result--are handled by "shorten" in build_binary_op. */
+ /* If TYPE is an enumeral type or a type with a precision less
+ than the number of bits in its mode, do the conversion to the
+ type corresponding to its mode, then do a nop conversion
+ to TYPE. */
+ else if (TREE_CODE (type) == ENUMERAL_TYPE
+ || outprec != GET_MODE_BITSIZE (TYPE_MODE (type)))
+ return build1 (NOP_EXPR, type,
+ convert (type_for_mode (TYPE_MODE (type),
+ TREE_UNSIGNED (type)),
+ expr));
+
+ /* Here detect when we can distribute the truncation down past some
+ arithmetic. For example, if adding two longs and converting to an
+ int, we can equally well convert both to ints and then add.
+ For the operations handled here, such truncation distribution
+ is always safe.
+ It is desirable in these cases:
+ 1) when truncating down to full-word from a larger size
+ 2) when truncating takes no work.
+ 3) when at least one operand of the arithmetic has been extended
+ (as by C's default conversions). In this case we need two conversions
+ if we do the arithmetic as already requested, so we might as well
+ truncate both and then combine. Perhaps that way we need only one.
+
+ Note that in general we cannot do the arithmetic in a type
+ shorter than the desired result of conversion, even if the operands
+ are both extended from a shorter type, because they might overflow
+ if combined in that type. The exceptions to this--the times when
+ two narrow values can be combined in their narrow type even to
+ make a wider result--are handled by "shorten" in build_binary_op. */
switch (ex_form)
{
/* We can pass truncation down through right shifting
when the shift count is a nonpositive constant. */
if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
- && tree_int_cst_lt (TREE_OPERAND (expr, 1), integer_one_node))
+ && tree_int_cst_lt (TREE_OPERAND (expr, 1),
+ convert (TREE_TYPE (TREE_OPERAND (expr, 1)),
+ integer_one_node)))
goto trunc1;
break;
/* We can pass truncation down through left shifting
when the shift count is a nonnegative constant. */
if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
- && ! tree_int_cst_lt (TREE_OPERAND (expr, 1), integer_zero_node)
+ && tree_int_cst_sgn (TREE_OPERAND (expr, 1)) >= 0
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
{
/* If shift count is less than the width of the truncated type,
/* In this case, shifting is like multiplication. */
goto trunc1;
else
- /* If it is >= that width, result is zero.
- Handling this with trunc1 would give the wrong result:
- (int) ((long long) a << 32) is well defined (as 0)
- but (int) a << 32 is undefined and would get a warning. */
- return convert_to_integer (type, integer_zero_node);
+ {
+ /* If it is >= that width, result is zero.
+ Handling this with trunc1 would give the wrong result:
+ (int) ((long long) a << 32) is well defined (as 0)
+ but (int) a << 32 is undefined and would get a
+ warning. */
+
+ tree t = convert_to_integer (type, integer_zero_node);
+
+ /* If the original expression had side-effects, we must
+ preserve it. */
+ if (TREE_SIDE_EFFECTS (expr))
+ return build (COMPOUND_EXPR, type, expr, t);
+ else
+ return t;
+ }
}
break;
|| TREE_UNSIGNED (TREE_TYPE (arg1)))
? unsigned_type (typex) : signed_type (typex));
return convert (type,
- build_binary_op (ex_form,
- convert (typex, arg0),
- convert (typex, arg1),
- 0));
+ fold (build (ex_form, typex,
+ convert (typex, arg0),
+ convert (typex, arg1),
+ 0)));
}
}
}
case NEGATE_EXPR:
case BIT_NOT_EXPR:
- case ABS_EXPR:
+ /* This is not correct for ABS_EXPR,
+ since we must test the sign before truncation. */
{
register tree typex = type;
typex = (TREE_UNSIGNED (TREE_TYPE (expr))
? unsigned_type (typex) : signed_type (typex));
return convert (type,
- build_unary_op (ex_form,
- convert (typex, TREE_OPERAND (expr, 0)),
- 1));
+ fold (build1 (ex_form, typex,
+ convert (typex,
+ TREE_OPERAND (expr, 0)))));
}
}
return fold (build (COMPLEX_EXPR,
type,
convert (subtype,
- build_unary_op (REALPART_EXPR, expr, 1)),
+ fold (build1 (REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr))),
convert (subtype,
- build_unary_op (IMAGPART_EXPR, expr, 1))));
+ fold (build1 (IMAGPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr)))));
}
}
- if (form == POINTER_TYPE)
+ if (form == POINTER_TYPE || form == REFERENCE_TYPE)
error ("pointer value used where a complex was expected");
else
error ("aggregate value used where a complex was expected");