896 lines
26 KiB
C++
896 lines
26 KiB
C++
/* d-convert.cc -- Data type conversion routines.
|
|
Copyright (C) 2006-2021 Free Software Foundation, Inc.
|
|
|
|
GCC 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 3, or (at your option)
|
|
any later version.
|
|
|
|
GCC 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 GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
|
|
#include "dmd/aggregate.h"
|
|
#include "dmd/declaration.h"
|
|
#include "dmd/expression.h"
|
|
#include "dmd/mtype.h"
|
|
|
|
#include "tree.h"
|
|
#include "fold-const.h"
|
|
#include "diagnostic.h"
|
|
#include "langhooks.h"
|
|
#include "target.h"
|
|
#include "convert.h"
|
|
#include "stor-layout.h"
|
|
|
|
#include "d-tree.h"
|
|
|
|
|
|
/* Build CODE expression with operands OP0 and OP1.
|
|
Helper function for d_truthvalue_conversion, so assumes bool result. */
|
|
|
|
static tree
|
|
d_build_truthvalue_op (tree_code code, tree op0, tree op1)
|
|
{
|
|
tree type0, type1;
|
|
|
|
tree result_type = NULL_TREE;
|
|
|
|
type0 = TREE_TYPE (op0);
|
|
type1 = TREE_TYPE (op1);
|
|
|
|
/* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
|
|
STRIP_TYPE_NOPS (op0);
|
|
STRIP_TYPE_NOPS (op1);
|
|
|
|
/* Also need to convert pointer/int comparison. */
|
|
if (POINTER_TYPE_P (type0) && TREE_CODE (op1) == INTEGER_CST
|
|
&& integer_zerop (op1))
|
|
{
|
|
result_type = type0;
|
|
}
|
|
else if (POINTER_TYPE_P (type1) && TREE_CODE (op0) == INTEGER_CST
|
|
&& integer_zerop (op0))
|
|
{
|
|
result_type = type1;
|
|
}
|
|
/* If integral, need to convert unsigned/signed comparison.
|
|
Will also need to convert if type precisions differ. */
|
|
else if (INTEGRAL_TYPE_P (type0) && INTEGRAL_TYPE_P (type1))
|
|
{
|
|
if (TYPE_PRECISION (type0) > TYPE_PRECISION (type1))
|
|
result_type = type0;
|
|
else if (TYPE_PRECISION (type0) < TYPE_PRECISION (type1))
|
|
result_type = type1;
|
|
else if (TYPE_UNSIGNED (type0) != TYPE_UNSIGNED (type1))
|
|
result_type = TYPE_UNSIGNED (type0) ? type0 : type1;
|
|
}
|
|
|
|
if (result_type)
|
|
{
|
|
if (TREE_TYPE (op0) != result_type)
|
|
op0 = convert (result_type, op0);
|
|
if (TREE_TYPE (op1) != result_type)
|
|
op1 = convert (result_type, op1);
|
|
}
|
|
|
|
return fold_build2 (code, d_bool_type, op0, op1);
|
|
}
|
|
|
|
/* Return whether EXPR is a declaration whose address can never be NULL. */
|
|
|
|
bool
|
|
decl_with_nonnull_addr_p (const_tree expr)
|
|
{
|
|
return (DECL_P (expr)
|
|
&& (TREE_CODE (expr) == PARM_DECL
|
|
|| TREE_CODE (expr) == LABEL_DECL
|
|
|| !DECL_WEAK (expr)));
|
|
}
|
|
|
|
/* Convert EXPR to be a truth-value, validating its type for this purpose. */
|
|
|
|
tree
|
|
d_truthvalue_conversion (tree expr)
|
|
{
|
|
switch (TREE_CODE (expr))
|
|
{
|
|
case EQ_EXPR: case NE_EXPR: case LE_EXPR:
|
|
case GE_EXPR: case LT_EXPR: case GT_EXPR:
|
|
if (TREE_TYPE (expr) == d_bool_type)
|
|
return expr;
|
|
return build2 (TREE_CODE (expr), d_bool_type,
|
|
TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
|
|
|
|
case TRUTH_ANDIF_EXPR:
|
|
case TRUTH_ORIF_EXPR:
|
|
case TRUTH_AND_EXPR:
|
|
case TRUTH_OR_EXPR:
|
|
case TRUTH_XOR_EXPR:
|
|
if (TREE_TYPE (expr) == d_bool_type)
|
|
return expr;
|
|
return build2 (TREE_CODE (expr), d_bool_type,
|
|
d_truthvalue_conversion (TREE_OPERAND (expr, 0)),
|
|
d_truthvalue_conversion (TREE_OPERAND (expr, 1)));
|
|
|
|
case TRUTH_NOT_EXPR:
|
|
if (TREE_TYPE (expr) == d_bool_type)
|
|
return expr;
|
|
return build1 (TREE_CODE (expr), d_bool_type,
|
|
d_truthvalue_conversion (TREE_OPERAND (expr, 0)));
|
|
|
|
case ERROR_MARK:
|
|
return expr;
|
|
|
|
case INTEGER_CST:
|
|
return integer_zerop (expr) ? boolean_false_node
|
|
: boolean_true_node;
|
|
|
|
case REAL_CST:
|
|
return real_compare (NE_EXPR, &TREE_REAL_CST (expr), &dconst0)
|
|
? boolean_true_node
|
|
: boolean_false_node;
|
|
|
|
case ADDR_EXPR:
|
|
/* If we are taking the address of a decl that can never be null,
|
|
then the return result is always true. */
|
|
if (decl_with_nonnull_addr_p (TREE_OPERAND (expr, 0)))
|
|
{
|
|
warning (OPT_Waddress,
|
|
"the address of %qD will always evaluate as %<true%>",
|
|
TREE_OPERAND (expr, 0));
|
|
return boolean_true_node;
|
|
}
|
|
break;
|
|
|
|
case COMPLEX_EXPR:
|
|
return d_build_truthvalue_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
|
|
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
|
|
d_truthvalue_conversion (TREE_OPERAND (expr, 0)),
|
|
d_truthvalue_conversion (TREE_OPERAND (expr, 1)));
|
|
|
|
case NEGATE_EXPR:
|
|
case ABS_EXPR:
|
|
case FLOAT_EXPR:
|
|
/* These don't change whether an object is nonzero or zero. */
|
|
return d_truthvalue_conversion (TREE_OPERAND (expr, 0));
|
|
|
|
case LROTATE_EXPR:
|
|
case RROTATE_EXPR:
|
|
/* These don't change whether an object is zero or nonzero, but
|
|
we can't ignore them if their second arg has side-effects. */
|
|
if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
|
|
{
|
|
return build2 (COMPOUND_EXPR, d_bool_type, TREE_OPERAND (expr, 1),
|
|
d_truthvalue_conversion (TREE_OPERAND (expr, 0)));
|
|
}
|
|
else
|
|
return d_truthvalue_conversion (TREE_OPERAND (expr, 0));
|
|
|
|
case COND_EXPR:
|
|
/* Distribute the conversion into the arms of a COND_EXPR. */
|
|
return fold_build3 (COND_EXPR, d_bool_type, TREE_OPERAND (expr, 0),
|
|
d_truthvalue_conversion (TREE_OPERAND (expr, 1)),
|
|
d_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 isn't narrowing the argument, we can ignore it. */
|
|
if (TYPE_PRECISION (TREE_TYPE (expr))
|
|
>= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
|
|
return d_truthvalue_conversion (TREE_OPERAND (expr, 0));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
|
|
{
|
|
tree t = save_expr (expr);
|
|
return d_build_truthvalue_op ((TREE_SIDE_EFFECTS (expr)
|
|
? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
|
|
d_truthvalue_conversion (real_part (t)),
|
|
d_truthvalue_conversion (imaginary_part (t)));
|
|
}
|
|
else
|
|
return d_build_truthvalue_op (NE_EXPR, expr,
|
|
build_zero_cst (TREE_TYPE (expr)));
|
|
}
|
|
|
|
|
|
/* Creates an expression whose value is that of EXPR, converted to type TYPE.
|
|
This function implements all reasonable scalar conversions. */
|
|
|
|
tree
|
|
convert (tree type, tree expr)
|
|
{
|
|
tree e = expr;
|
|
tree_code code = TREE_CODE (type);
|
|
|
|
if (type == error_mark_node
|
|
|| expr == error_mark_node
|
|
|| TREE_TYPE (expr) == error_mark_node)
|
|
return error_mark_node;
|
|
|
|
const char *invalid_conv_diag
|
|
= targetm.invalid_conversion (TREE_TYPE (expr), type);
|
|
|
|
if (invalid_conv_diag)
|
|
{
|
|
error ("%s", invalid_conv_diag);
|
|
return error_mark_node;
|
|
}
|
|
|
|
if (type == TREE_TYPE (expr))
|
|
return expr;
|
|
|
|
if (TREE_CODE (type) == ARRAY_TYPE
|
|
&& TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
|
|
&& TYPE_DOMAIN (type) == TYPE_DOMAIN (TREE_TYPE (expr)))
|
|
return expr;
|
|
|
|
tree ret = targetm.convert_to_type (type, expr);
|
|
if (ret)
|
|
return ret;
|
|
|
|
STRIP_TYPE_NOPS (e);
|
|
tree etype = TREE_TYPE (e);
|
|
|
|
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
|
|
return fold_convert (type, expr);
|
|
if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
|
|
return error_mark_node;
|
|
if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE)
|
|
{
|
|
error ("void value not ignored as it ought to be");
|
|
return error_mark_node;
|
|
}
|
|
|
|
switch (code)
|
|
{
|
|
case VOID_TYPE:
|
|
return fold_convert (type, e);
|
|
|
|
case INTEGER_TYPE:
|
|
case ENUMERAL_TYPE:
|
|
if (TREE_CODE (etype) == POINTER_TYPE
|
|
|| TREE_CODE (etype) == REFERENCE_TYPE)
|
|
{
|
|
if (integer_zerop (e))
|
|
return build_int_cst (type, 0);
|
|
|
|
/* Convert to an unsigned integer of the correct width first, and
|
|
from there widen/truncate to the required type. */
|
|
tree utype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype),
|
|
1);
|
|
ret = fold_build1 (CONVERT_EXPR, utype, e);
|
|
return fold_convert (type, ret);
|
|
}
|
|
|
|
return fold (convert_to_integer (type, e));
|
|
|
|
case BOOLEAN_TYPE:
|
|
return fold_convert (type, d_truthvalue_conversion (expr));
|
|
|
|
case POINTER_TYPE:
|
|
case REFERENCE_TYPE:
|
|
return fold (convert_to_pointer (type, e));
|
|
|
|
case REAL_TYPE:
|
|
if (TREE_CODE (etype) == COMPLEX_TYPE && TYPE_IMAGINARY_FLOAT (type))
|
|
e = build1 (IMAGPART_EXPR, TREE_TYPE (etype), e);
|
|
|
|
return fold (convert_to_real (type, e));
|
|
|
|
case COMPLEX_TYPE:
|
|
if (TREE_CODE (etype) == REAL_TYPE && TYPE_IMAGINARY_FLOAT (etype))
|
|
return fold_build2 (COMPLEX_EXPR, type,
|
|
build_zero_cst (TREE_TYPE (type)),
|
|
convert (TREE_TYPE (type), expr));
|
|
|
|
return fold (convert_to_complex (type, e));
|
|
|
|
case VECTOR_TYPE:
|
|
return fold (convert_to_vector (type, e));
|
|
|
|
case RECORD_TYPE:
|
|
case UNION_TYPE:
|
|
if (lang_hooks.types_compatible_p (type, TREE_TYPE (expr)))
|
|
return fold_build1 (VIEW_CONVERT_EXPR, type, expr);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
error ("conversion to non-scalar type requested");
|
|
return error_mark_node;
|
|
}
|
|
|
|
/* Return expression EXP, whose type has been converted to TYPE. */
|
|
|
|
tree
|
|
d_convert (tree type, tree exp)
|
|
{
|
|
/* Check this first before retrieving frontend type. */
|
|
if (error_operand_p (type) || error_operand_p (exp))
|
|
return error_mark_node;
|
|
|
|
Type *totype = TYPE_LANG_FRONTEND (type);
|
|
Type *etype = TYPE_LANG_FRONTEND (TREE_TYPE (exp));
|
|
|
|
if (totype && etype)
|
|
return convert_expr (exp, etype, totype);
|
|
|
|
return convert (type, exp);
|
|
}
|
|
|
|
/* Return expression EXP, whose type has been convert from ETYPE to TOTYPE. */
|
|
|
|
tree
|
|
convert_expr (tree exp, Type *etype, Type *totype)
|
|
{
|
|
tree result = NULL_TREE;
|
|
|
|
gcc_assert (etype && totype);
|
|
Type *ebtype = etype->toBasetype ();
|
|
Type *tbtype = totype->toBasetype ();
|
|
|
|
if (same_type_p (etype, totype))
|
|
return exp;
|
|
|
|
if (error_operand_p (exp))
|
|
return exp;
|
|
|
|
switch (ebtype->ty)
|
|
{
|
|
case Tdelegate:
|
|
if (tbtype->ty == Tdelegate)
|
|
{
|
|
exp = d_save_expr (exp);
|
|
return build_delegate_cst (delegate_method (exp),
|
|
delegate_object (exp), totype);
|
|
}
|
|
else if (tbtype->ty == Tpointer)
|
|
{
|
|
/* The front-end converts <delegate>.ptr to cast (void *)<delegate>.
|
|
Maybe should only allow void* ? */
|
|
exp = delegate_object (exp);
|
|
}
|
|
else
|
|
{
|
|
error ("cannot convert a delegate expression to %qs",
|
|
totype->toChars ());
|
|
return error_mark_node;
|
|
}
|
|
break;
|
|
|
|
case Tstruct:
|
|
if (tbtype->ty == Tstruct)
|
|
{
|
|
if (totype->size () == etype->size ())
|
|
{
|
|
/* Allowed to cast to structs with same type size. */
|
|
result = build_vconvert (build_ctype (totype), exp);
|
|
}
|
|
else
|
|
{
|
|
error ("cannot convert struct %qs to %qs",
|
|
etype->toChars (), totype->toChars ());
|
|
return error_mark_node;
|
|
}
|
|
}
|
|
/* else, default conversion, which should produce an error. */
|
|
break;
|
|
|
|
case Tclass:
|
|
if (tbtype->ty == Tclass)
|
|
{
|
|
ClassDeclaration *cdfrom = ebtype->isClassHandle ();
|
|
ClassDeclaration *cdto = tbtype->isClassHandle ();
|
|
int offset;
|
|
|
|
if (cdto->isBaseOf (cdfrom, &offset) && offset != OFFSET_RUNTIME)
|
|
{
|
|
/* Casting up the inheritance tree: Don't do anything special.
|
|
Cast to an implemented interface: Handle at compile-time. */
|
|
if (offset)
|
|
{
|
|
/* Forward references should not leak from the frontend. */
|
|
gcc_assert (offset != OFFSET_FWDREF);
|
|
|
|
tree type = build_ctype (totype);
|
|
exp = d_save_expr (exp);
|
|
|
|
tree cond = build_boolop (NE_EXPR, exp, null_pointer_node);
|
|
tree object = build_offset (exp, size_int (offset));
|
|
|
|
return build_condition (build_ctype (totype), cond,
|
|
build_nop (type, object),
|
|
build_nop (type, null_pointer_node));
|
|
}
|
|
|
|
/* d_convert will make a no-op cast. */
|
|
break;
|
|
}
|
|
else if (cdfrom->isCPPclass () || cdto->isCPPclass ())
|
|
{
|
|
/* Downcasting in C++ is a no-op. */
|
|
if (cdfrom->isCPPclass () && cdto->isCPPclass ())
|
|
break;
|
|
|
|
/* Casting from a C++ interface to a class/non-C++ interface
|
|
always results in null as there is no run-time information,
|
|
and no way one can derive from the other. */
|
|
warning (OPT_Wcast_result, "cast to %qs will produce null result",
|
|
totype->toChars ());
|
|
result = d_convert (build_ctype (totype), null_pointer_node);
|
|
|
|
/* Make sure the expression is still evaluated if necessary. */
|
|
if (TREE_SIDE_EFFECTS (exp))
|
|
result = compound_expr (exp, result);
|
|
|
|
break;
|
|
}
|
|
|
|
/* The offset can only be determined at run-time, do dynamic cast. */
|
|
libcall_fn libcall = cdfrom->isInterfaceDeclaration ()
|
|
? LIBCALL_INTERFACE_CAST : LIBCALL_DYNAMIC_CAST;
|
|
|
|
return build_libcall (libcall, totype, 2, exp,
|
|
build_address (get_classinfo_decl (cdto)));
|
|
}
|
|
/* else default conversion. */
|
|
break;
|
|
|
|
case Tsarray:
|
|
if (tbtype->ty == Tpointer)
|
|
{
|
|
result = build_nop (build_ctype (totype), build_address (exp));
|
|
}
|
|
else if (tbtype->ty == Tarray)
|
|
{
|
|
dinteger_t dim = ebtype->isTypeSArray ()->dim->toInteger ();
|
|
dinteger_t esize = ebtype->nextOf ()->size ();
|
|
dinteger_t tsize = tbtype->nextOf ()->size ();
|
|
|
|
tree ptrtype = build_ctype (tbtype->nextOf ()->pointerTo ());
|
|
|
|
if (esize != tsize)
|
|
{
|
|
/* Array element sizes do not match, so we must adjust the
|
|
dimensions. */
|
|
if (tsize == 0 || (dim * esize) % tsize != 0)
|
|
{
|
|
error ("cannot cast %qs to %qs since sizes do not line up",
|
|
etype->toChars (), totype->toChars ());
|
|
return error_mark_node;
|
|
}
|
|
dim = (dim * esize) / tsize;
|
|
}
|
|
|
|
/* Assumes casting to dynamic array of same type or void. */
|
|
return d_array_value (build_ctype (totype), size_int (dim),
|
|
build_nop (ptrtype, build_address (exp)));
|
|
}
|
|
else if (tbtype->ty == Tsarray)
|
|
{
|
|
/* D allows casting a static array to any static array type. */
|
|
return build_nop (build_ctype (totype), exp);
|
|
}
|
|
else if (tbtype->ty == Tstruct)
|
|
{
|
|
/* And allows casting a static array to any struct type too.
|
|
Type sizes should have already been checked by the frontend. */
|
|
gcc_assert (totype->size () == etype->size ());
|
|
result = build_vconvert (build_ctype (totype), exp);
|
|
}
|
|
else if (tbtype->ty == Tvector && tbtype->size () == ebtype->size ())
|
|
{
|
|
/* Allow casting from array to vector as if its an unaligned load. */
|
|
tree type = build_ctype (totype);
|
|
tree unaligned_type = build_variant_type_copy (type);
|
|
SET_TYPE_ALIGN (unaligned_type, 1 * BITS_PER_UNIT);
|
|
TYPE_USER_ALIGN (unaligned_type) = 1;
|
|
result = convert (type, build_vconvert (unaligned_type, exp));
|
|
}
|
|
else
|
|
{
|
|
error ("cannot cast expression of type %qs to type %qs",
|
|
etype->toChars (), totype->toChars ());
|
|
return error_mark_node;
|
|
}
|
|
break;
|
|
|
|
case Tarray:
|
|
if (tbtype->ty == Tpointer)
|
|
{
|
|
return d_convert (build_ctype (totype), d_array_ptr (exp));
|
|
}
|
|
else if (tbtype->ty == Tarray)
|
|
{
|
|
/* Assume tvoid->size() == 1. */
|
|
d_uns64 fsize = ebtype->nextOf ()->toBasetype ()->size ();
|
|
d_uns64 tsize = tbtype->nextOf ()->toBasetype ()->size ();
|
|
|
|
if (fsize != tsize)
|
|
{
|
|
/* Conversion requires a reinterpret cast of array. */
|
|
return build_libcall (LIBCALL_ARRAYCAST, totype, 3,
|
|
size_int (tsize), size_int (fsize), exp);
|
|
}
|
|
else
|
|
{
|
|
/* Convert from void[] or elements are the same size
|
|
-- don't change length. */
|
|
return build_vconvert (build_ctype (totype), exp);
|
|
}
|
|
}
|
|
else if (tbtype->ty == Tsarray)
|
|
{
|
|
/* Strings are treated as dynamic arrays in D2. */
|
|
if (ebtype->isString () && tbtype->isString ())
|
|
return indirect_ref (build_ctype (totype), d_array_ptr (exp));
|
|
}
|
|
else
|
|
{
|
|
error ("cannot cast expression of type %qs to %qs",
|
|
etype->toChars (), totype->toChars ());
|
|
return error_mark_node;
|
|
}
|
|
break;
|
|
|
|
case Taarray:
|
|
if (tbtype->ty == Taarray)
|
|
return build_vconvert (build_ctype (totype), exp);
|
|
/* Can convert associative arrays to void pointers. */
|
|
else if (tbtype->ty == Tpointer && tbtype->nextOf ()->ty == Tvoid)
|
|
return build_vconvert (build_ctype (totype), exp);
|
|
/* Else, default conversion, which should product an error. */
|
|
break;
|
|
|
|
case Tpointer:
|
|
/* Can convert void pointers to associative arrays too. */
|
|
if (tbtype->ty == Taarray && ebtype->nextOf ()->ty == Tvoid)
|
|
return build_vconvert (build_ctype (totype), exp);
|
|
break;
|
|
|
|
case Tnull:
|
|
case Tnoreturn:
|
|
/* Casting from `typeof(null)' for `null' expressions, or `typeof(*null)'
|
|
for `noreturn' expressions is represented as all zeros. */
|
|
result = build_typeof_null_value (totype);
|
|
|
|
/* Make sure the expression is still evaluated if necessary. */
|
|
if (TREE_SIDE_EFFECTS (exp))
|
|
result = compound_expr (exp, result);
|
|
break;
|
|
|
|
case Tvector:
|
|
if (tbtype->ty == Tsarray)
|
|
{
|
|
if (tbtype->size () == ebtype->size ())
|
|
return build_vconvert (build_ctype (totype), exp);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* All casts between imaginary and non-imaginary result in 0.0,
|
|
except for casts between complex and imaginary types. */
|
|
if (!ebtype->iscomplex () && !tbtype->iscomplex ()
|
|
&& (ebtype->isimaginary () != tbtype->isimaginary ()))
|
|
{
|
|
warning (OPT_Wcast_result,
|
|
"cast from %qs to %qs will produce zero result",
|
|
ebtype->toChars (), tbtype->toChars ());
|
|
|
|
return compound_expr (exp, build_zero_cst (build_ctype (tbtype)));
|
|
}
|
|
|
|
gcc_assert (TREE_CODE (exp) != STRING_CST);
|
|
break;
|
|
}
|
|
|
|
return result ? result : convert (build_ctype (totype), exp);
|
|
}
|
|
|
|
/* Return a TREE represenwation of EXPR, whose type has been converted from
|
|
* ETYPE to TOTYPE, and is being used in an rvalue context. */
|
|
|
|
tree
|
|
convert_for_rvalue (tree expr, Type *etype, Type *totype)
|
|
{
|
|
tree result = NULL_TREE;
|
|
|
|
Type *ebtype = etype->toBasetype ();
|
|
Type *tbtype = totype->toBasetype ();
|
|
|
|
switch (ebtype->ty)
|
|
{
|
|
case Tbool:
|
|
/* If casting from bool, the result is either 0 or 1, any other value
|
|
violates @safe code, so enforce that it is never invalid. */
|
|
if (CONSTANT_CLASS_P (expr))
|
|
result = d_truthvalue_conversion (expr);
|
|
else
|
|
{
|
|
/* Reinterpret the boolean as an integer and test the first bit.
|
|
The generated code should end up being equivalent to:
|
|
*cast(ubyte *)&expr & 1; */
|
|
machine_mode bool_mode = TYPE_MODE (TREE_TYPE (expr));
|
|
tree mtype = lang_hooks.types.type_for_mode (bool_mode, 1);
|
|
result = fold_build2 (BIT_AND_EXPR, mtype,
|
|
build_vconvert (mtype, expr),
|
|
build_one_cst (mtype));
|
|
}
|
|
|
|
result = convert (build_ctype (tbtype), result);
|
|
break;
|
|
}
|
|
|
|
if (tbtype->ty == Tsarray
|
|
&& ebtype->ty == Tsarray
|
|
&& tbtype->nextOf ()->ty == ebtype->nextOf ()->ty
|
|
&& INDIRECT_REF_P (expr)
|
|
&& CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (expr, 0)))
|
|
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (expr, 0), 0)) == ADDR_EXPR)
|
|
{
|
|
/* If expression is a vector that was casted to an array either by
|
|
explicit type cast or by taking the vector's `.array' value, strip the
|
|
reinterpret cast and build a constructor instead. */
|
|
tree ptr = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
|
|
|
|
if (VECTOR_TYPE_P (TREE_TYPE (TREE_TYPE (ptr))))
|
|
{
|
|
/* Rewrite: `*(Array *)&vector'
|
|
into: `{ vector[0], vector[1], ... }' */
|
|
tree array = d_save_expr (TREE_OPERAND (ptr, 0));
|
|
array = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (expr), array);
|
|
|
|
uinteger_t dim = tbtype->isTypeSArray ()->dim->toUInteger ();
|
|
vec <constructor_elt, va_gc> *elms = NULL;
|
|
for (uinteger_t i = 0; i < dim; i++)
|
|
{
|
|
tree index = size_int (i);
|
|
tree value = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (array)),
|
|
array, index, NULL_TREE, NULL_TREE);
|
|
CONSTRUCTOR_APPEND_ELT (elms, index, value);
|
|
}
|
|
|
|
return build_constructor (build_ctype (totype), elms);
|
|
}
|
|
}
|
|
|
|
return result ? result : convert_expr (expr, etype, totype);
|
|
}
|
|
|
|
/* Apply semantics of assignment to a value of type TOTYPE to EXPR
|
|
(e.g., pointer = array -> pointer = &array[0])
|
|
|
|
Return a TREE representation of EXPR implicitly converted to TOTYPE
|
|
for use in assignment expressions MODIFY_EXPR, INIT_EXPR. */
|
|
|
|
tree
|
|
convert_for_assignment (tree expr, Type *etype, Type *totype)
|
|
{
|
|
Type *ebtype = etype->toBasetype ();
|
|
Type *tbtype = totype->toBasetype ();
|
|
|
|
/* Assuming this only has to handle converting a non Tsarray type to
|
|
arbitrarily dimensioned Tsarrays. */
|
|
if (tbtype->ty == Tsarray)
|
|
{
|
|
Type *telem = tbtype->nextOf ()->baseElemOf ();
|
|
|
|
if (same_type_p (telem, ebtype))
|
|
{
|
|
TypeSArray *sa_type = tbtype->isTypeSArray ();
|
|
uinteger_t count = sa_type->dim->toUInteger ();
|
|
|
|
tree ctor = build_constructor (build_ctype (totype), NULL);
|
|
if (count)
|
|
{
|
|
vec <constructor_elt, va_gc> *ce = NULL;
|
|
tree index = build2 (RANGE_EXPR, build_ctype (Type::tsize_t),
|
|
size_zero_node, size_int (count - 1));
|
|
tree value = convert_for_assignment (expr, etype, sa_type->next);
|
|
|
|
/* Can't use VAR_DECLs in CONSTRUCTORS. */
|
|
if (VAR_P (value))
|
|
{
|
|
value = DECL_INITIAL (value);
|
|
gcc_assert (value);
|
|
}
|
|
|
|
CONSTRUCTOR_APPEND_ELT (ce, index, value);
|
|
CONSTRUCTOR_ELTS (ctor) = ce;
|
|
}
|
|
TREE_READONLY (ctor) = 1;
|
|
TREE_CONSTANT (ctor) = 1;
|
|
return ctor;
|
|
}
|
|
}
|
|
|
|
/* D Front end uses IntegerExp(0) to mean zero-init an array or structure. */
|
|
if ((tbtype->ty == Tsarray || tbtype->ty == Tstruct)
|
|
&& ebtype->isintegral ())
|
|
{
|
|
if (!integer_zerop (expr))
|
|
gcc_unreachable ();
|
|
|
|
return expr;
|
|
}
|
|
|
|
return convert_for_rvalue (expr, etype, totype);
|
|
}
|
|
|
|
/* Return a TREE representation of EXPR converted to represent
|
|
the parameter type ARG. */
|
|
|
|
tree
|
|
convert_for_argument (tree expr, Parameter *arg)
|
|
{
|
|
/* Lazy arguments: expr should already be a delegate. */
|
|
if (arg->storageClass & STClazy)
|
|
return expr;
|
|
|
|
if (valist_array_p (arg->type))
|
|
{
|
|
/* Do nothing if the va_list has already been decayed to a pointer. */
|
|
if (!POINTER_TYPE_P (TREE_TYPE (expr)))
|
|
return build_address (expr);
|
|
}
|
|
else if (parameter_reference_p (arg))
|
|
{
|
|
/* Front-end shouldn't automatically take the address. */
|
|
return convert (parameter_type (arg), build_address (expr));
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
/* Perform default promotions for data used in expressions.
|
|
Arrays and functions are converted to pointers;
|
|
enumeral types or short or char, to int.
|
|
In addition, manifest constants symbols are replaced by their values.
|
|
|
|
Return truth-value conversion of expression EXPR from value type TYPE. */
|
|
|
|
tree
|
|
convert_for_condition (tree expr, Type *type)
|
|
{
|
|
tree result = NULL_TREE;
|
|
|
|
switch (type->toBasetype ()->ty)
|
|
{
|
|
case Taarray:
|
|
/* Checks that aa.ptr !is null. */
|
|
result = component_ref (expr, TYPE_FIELDS (TREE_TYPE (expr)));
|
|
break;
|
|
|
|
case Tarray:
|
|
{
|
|
/* Checks (arr.length || arr.ptr) (i.e arr !is null). */
|
|
expr = d_save_expr (expr);
|
|
tree len = d_array_length (expr);
|
|
tree ptr = d_array_ptr (expr);
|
|
if (TYPE_MODE (TREE_TYPE (len)) == TYPE_MODE (TREE_TYPE (ptr)))
|
|
{
|
|
result = build2 (BIT_IOR_EXPR, TREE_TYPE (len), len,
|
|
d_convert (TREE_TYPE (len), ptr));
|
|
}
|
|
else
|
|
{
|
|
len = d_truthvalue_conversion (len);
|
|
ptr = d_truthvalue_conversion (ptr);
|
|
/* Probably not worth using TRUTH_OROR here. */
|
|
result = build2 (TRUTH_OR_EXPR, TREE_TYPE (len), len, ptr);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Tdelegate:
|
|
{
|
|
/* Checks (function || object), but what good is it if there is
|
|
a null function pointer? */
|
|
tree obj, func;
|
|
if (METHOD_CALL_EXPR (expr))
|
|
extract_from_method_call (expr, obj, func);
|
|
else
|
|
{
|
|
expr = d_save_expr (expr);
|
|
obj = delegate_object (expr);
|
|
func = delegate_method (expr);
|
|
}
|
|
|
|
obj = d_truthvalue_conversion (obj);
|
|
func = d_truthvalue_conversion (func);
|
|
/* Probably not worth using TRUTH_ORIF here. */
|
|
result = build2 (BIT_IOR_EXPR, TREE_TYPE (obj), obj, func);
|
|
break;
|
|
}
|
|
|
|
case Tnoreturn:
|
|
/* Front-end allows conditionals that never return, represent the
|
|
conditional result value as all zeros. */
|
|
result = build_zero_cst (d_bool_type);
|
|
|
|
/* Make sure the expression is still evaluated if necessary. */
|
|
if (TREE_SIDE_EFFECTS (expr))
|
|
result = compound_expr (expr, result);
|
|
break;
|
|
|
|
default:
|
|
result = expr;
|
|
break;
|
|
}
|
|
|
|
return d_truthvalue_conversion (result);
|
|
}
|
|
|
|
|
|
/* Convert EXP to a dynamic array.
|
|
EXP must be a static array or dynamic array. */
|
|
|
|
tree
|
|
d_array_convert (Expression *exp)
|
|
{
|
|
Type *tb = exp->type->toBasetype ();
|
|
|
|
if (tb->ty == Tarray)
|
|
return build_expr (exp);
|
|
|
|
if (tb->ty == Tsarray)
|
|
{
|
|
Type *totype = tb->nextOf ()->arrayOf ();
|
|
return convert_expr (build_expr (exp), exp->type, totype);
|
|
}
|
|
|
|
/* Invalid type passed. */
|
|
gcc_unreachable ();
|
|
}
|
|
|
|
/* Convert EXP to a dynamic array, where ETYPE is the element type.
|
|
Similar to above, except that EXP is allowed to be an element of an array.
|
|
Temporary variables are created inline if EXP is not an lvalue. */
|
|
|
|
tree
|
|
d_array_convert (Type *etype, Expression *exp)
|
|
{
|
|
Type *tb = exp->type->toBasetype ();
|
|
|
|
if ((tb->ty != Tarray && tb->ty != Tsarray) || same_type_p (tb, etype))
|
|
{
|
|
/* Convert single element to an array. */
|
|
tree expr = build_expr (exp);
|
|
|
|
if (!exp->isLvalue ())
|
|
{
|
|
tree var = build_local_temp (TREE_TYPE (expr));
|
|
expr = compound_expr (modify_expr (var, expr), var);
|
|
}
|
|
|
|
return d_array_value (build_ctype (exp->type->arrayOf ()),
|
|
size_int (1), build_address (expr));
|
|
}
|
|
else
|
|
return d_array_convert (exp);
|
|
}
|