#include "config.h"
#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "cp-tree.h"
#include "flags.h"
#include "output.h"
#include "expr.h"
#include "toplev.h"
static tree convert_for_assignment PROTO((tree, tree, const char *, tree,
int));
static tree pointer_int_sum PROTO((enum tree_code, tree, tree));
static tree rationalize_conditional_expr PROTO((enum tree_code, tree));
static int comp_target_parms PROTO((tree, tree, int));
static int comp_ptr_ttypes_real PROTO((tree, tree, int));
static int comp_ptr_ttypes_const PROTO((tree, tree));
static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
static int comp_array_types PROTO((int (*) (tree, tree, int), tree,
tree, int));
static tree common_base_type PROTO((tree, tree));
#if 0
static tree convert_sequence PROTO((tree, tree));
#endif
static tree lookup_anon_field PROTO((tree, tree));
static tree pointer_diff PROTO((tree, tree, tree));
static tree build_component_addr PROTO((tree, tree));
static tree qualify_type PROTO((tree, tree));
static tree get_delta_difference PROTO((tree, tree, int));
static int comp_cv_target_types PROTO((tree, tree, int));
tree
target_type (type)
tree type;
{
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
while (TREE_CODE (type) == POINTER_TYPE
|| TREE_CODE (type) == ARRAY_TYPE
|| TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE
|| TREE_CODE (type) == OFFSET_TYPE)
type = TREE_TYPE (type);
return type;
}
tree
require_complete_type (value)
tree value;
{
tree type;
if (processing_template_decl || value == error_mark_node)
return value;
if (TREE_CODE (value) == OVERLOAD)
type = unknown_type_node;
else
type = TREE_TYPE (value);
if (TYPE_SIZE (type) != 0
&& TYPE_SIZE (type) != size_zero_node
&& ! (TYPE_LANG_SPECIFIC (type)
&& (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))
&& TYPE_SIZE (SIGNATURE_TYPE (type)) == 0))
return value;
if (TREE_CODE (value) == OFFSET_REF
&& current_class_ref != 0
&& TREE_OPERAND (value, 0) == current_class_ref)
{
tree base, member = TREE_OPERAND (value, 1);
tree basetype = TYPE_OFFSET_BASETYPE (type);
my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305);
base = convert_pointer_to (basetype, current_class_ptr);
value = build (COMPONENT_REF, TREE_TYPE (member),
build_indirect_ref (base, NULL_PTR), member);
return require_complete_type (value);
}
if (complete_type_or_else (type, value))
return value;
else
return error_mark_node;
}
tree
require_complete_type_in_void (expr)
tree expr;
{
switch (TREE_CODE (expr))
{
case COND_EXPR:
{
tree op;
op = TREE_OPERAND (expr,2);
op = require_complete_type_in_void (op);
TREE_OPERAND (expr,2) = op;
if (op == error_mark_node)
{
expr = op;
break;
}
}
case COMPOUND_EXPR:
{
tree op;
op = TREE_OPERAND (expr,1);
op = require_complete_type_in_void (op);
TREE_OPERAND (expr,1) = op;
if (op == error_mark_node)
{
expr = op;
break;
}
break;
}
case NON_LVALUE_EXPR:
case NOP_EXPR:
{
tree op;
op = TREE_OPERAND (expr,0);
op = require_complete_type_in_void (op);
TREE_OPERAND (expr,0) = op;
if (op == error_mark_node)
{
expr = op;
break;
}
break;
}
case CALL_EXPR:
case RTL_EXPR:
case DELETE_EXPR:
case VEC_DELETE_EXPR:
case INTEGER_CST:
case EXIT_EXPR:
case LOOP_EXPR:
case BIND_EXPR:
case THROW_EXPR:
case MODIFY_EXPR:
case CONVERT_EXPR:
break;
case INDIRECT_REF:
{
tree op = TREE_OPERAND (expr,0);
if (TREE_CODE (op) == CALL_EXPR
&& TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
break;
}
default:
expr = require_complete_type (expr);
break;
}
return expr;
}
tree
complete_type (type)
tree type;
{
if (type == NULL_TREE)
return error_mark_node;
if (type == error_mark_node || TYPE_SIZE (type) != NULL_TREE)
;
else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
{
tree t = complete_type (TREE_TYPE (type));
if (TYPE_SIZE (t) != NULL_TREE && ! processing_template_decl)
layout_type (type);
TYPE_NEEDS_CONSTRUCTING (type)
= TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
TYPE_NEEDS_DESTRUCTOR (type)
= TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (t));
}
else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
instantiate_class_template (TYPE_MAIN_VARIANT (type));
return type;
}
tree
complete_type_or_else (type, value)
tree type;
tree value;
{
type = complete_type (type);
if (type == error_mark_node)
return NULL_TREE;
else if (!TYPE_SIZE (type) || TYPE_SIZE (type) == size_zero_node)
{
incomplete_type_error (value, type);
return NULL_TREE;
}
else
return type;
}
int
type_unknown_p (exp)
tree exp;
{
return (TREE_CODE (exp) == OVERLOAD
|| TREE_CODE (exp) == TREE_LIST
|| TREE_TYPE (exp) == unknown_type_node
|| (TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE
&& TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node));
}
int
fntype_p (t)
tree t;
{
return (TREE_CODE (t) == FUNCTION_TYPE || TREE_CODE (t) == METHOD_TYPE
|| (TREE_CODE (t) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)));
}
static tree
qualify_type (type, like)
tree type, like;
{
return cp_build_qualified_type (type, (CP_TYPE_QUALS (type)
| CP_TYPE_QUALS (like)));
}
tree
commonparms (p1, p2)
tree p1, p2;
{
tree oldargs = p1, newargs, n;
int i, len;
int any_change = 0;
char *first_obj = (char *) oballoc (0);
len = list_length (p1);
newargs = tree_last (p1);
if (newargs == void_list_node)
i = 1;
else
{
i = 0;
newargs = 0;
}
for (; i < len; i++)
newargs = tree_cons (NULL_TREE, NULL_TREE, newargs);
n = newargs;
for (i = 0; p1;
p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n), i++)
{
if (TREE_PURPOSE (p1) && !TREE_PURPOSE (p2))
{
TREE_PURPOSE (n) = TREE_PURPOSE (p1);
any_change = 1;
}
else if (! TREE_PURPOSE (p1))
{
if (TREE_PURPOSE (p2))
{
TREE_PURPOSE (n) = TREE_PURPOSE (p2);
any_change = 1;
}
}
else
{
if (1 != simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2)))
any_change = 1;
TREE_PURPOSE (n) = TREE_PURPOSE (p2);
}
if (TREE_VALUE (p1) != TREE_VALUE (p2))
{
any_change = 1;
TREE_VALUE (n) = common_type (TREE_VALUE (p1), TREE_VALUE (p2));
}
else
TREE_VALUE (n) = TREE_VALUE (p1);
}
if (! any_change)
{
obfree (first_obj);
return oldargs;
}
return newargs;
}
tree
original_type (t)
tree t;
{
while (TYPE_NAME (t) != NULL_TREE)
{
tree x = TYPE_NAME (t);
if (TREE_CODE (x) != TYPE_DECL)
break;
x = DECL_ORIGINAL_TYPE (x);
if (x == NULL_TREE)
break;
t = x;
}
return t;
}
tree
common_type (t1, t2)
tree t1, t2;
{
register enum tree_code code1;
register enum tree_code code2;
tree attributes;
if (t1 == t2)
return t1;
t1 = original_type (t1);
t2 = original_type (t2);
if (t1 == t2)
return t1;
if (t1 == error_mark_node)
return t2;
if (t2 == error_mark_node)
return t1;
attributes = merge_machine_type_attributes (t1, t2);
{ register tree a1, a2;
a1 = TYPE_ATTRIBUTES (t1);
a2 = TYPE_ATTRIBUTES (t2);
if (!(attributes = a1))
attributes = a2;
else if (a2 && !attribute_list_contained (a1, a2))
{
if (attribute_list_contained (a2, a1))
attributes = a2;
else
{
if (list_length (a1) < list_length (a2))
attributes = a2, a2 = a1;
for (; a2; a2 = TREE_CHAIN (a2))
if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
attributes) == NULL_TREE)
{
a1 = copy_node (a2);
TREE_CHAIN (a1) = attributes;
attributes = a1;
}
}
}
}
if (TREE_CODE (t1) == ENUMERAL_TYPE)
t1 = type_for_size (TYPE_PRECISION (t1), 1);
if (TREE_CODE (t2) == ENUMERAL_TYPE)
t2 = type_for_size (TYPE_PRECISION (t2), 1);
if (TYPE_PTRMEMFUNC_P (t1))
t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
if (TYPE_PTRMEMFUNC_P (t2))
t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
{
tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
tree subtype = common_type (subtype1, subtype2);
if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
return build_type_attribute_variant (t1, attributes);
else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
return build_type_attribute_variant (t2, attributes);
else
return build_type_attribute_variant (build_complex_type (subtype),
attributes);
}
switch (code1)
{
case INTEGER_TYPE:
case REAL_TYPE:
if (code1 == REAL_TYPE && code2 != REAL_TYPE)
return build_type_attribute_variant (t1, attributes);
if (code2 == REAL_TYPE && code1 != REAL_TYPE)
return build_type_attribute_variant (t2, attributes);
if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
return build_type_attribute_variant (t1, attributes);
else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
return build_type_attribute_variant (t2, attributes);
if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
|| TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
return build_type_attribute_variant (long_unsigned_type_node,
attributes);
if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node
|| TYPE_MAIN_VARIANT (t2) == long_integer_type_node)
{
if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
t1 = long_unsigned_type_node;
else
t1 = long_integer_type_node;
return build_type_attribute_variant (t1, attributes);
}
if (TYPE_MAIN_VARIANT (t1) == long_double_type_node
|| TYPE_MAIN_VARIANT (t2) == long_double_type_node)
return build_type_attribute_variant (long_double_type_node,
attributes);
if (TREE_UNSIGNED (t1))
return build_type_attribute_variant (t1, attributes);
else
return build_type_attribute_variant (t2, attributes);
case POINTER_TYPE:
case REFERENCE_TYPE:
{
tree tt1 = TREE_TYPE (t1);
tree tt2 = TREE_TYPE (t2);
tree b1, b2;
int type_quals;
tree target;
if (TREE_CODE (tt1) == OFFSET_TYPE)
{
b1 = TYPE_OFFSET_BASETYPE (tt1);
b2 = TYPE_OFFSET_BASETYPE (tt2);
tt1 = TREE_TYPE (tt1);
tt2 = TREE_TYPE (tt2);
}
else
b1 = b2 = NULL_TREE;
type_quals = (CP_TYPE_QUALS (tt1) | CP_TYPE_QUALS (tt2));
tt1 = TYPE_MAIN_VARIANT (tt1);
tt2 = TYPE_MAIN_VARIANT (tt2);
if (tt1 == tt2)
target = tt1;
else if (tt1 == void_type_node || tt2 == void_type_node)
target = void_type_node;
else if (tt1 == unknown_type_node)
target = tt2;
else if (tt2 == unknown_type_node)
target = tt1;
else
target = common_type (tt1, tt2);
target = cp_build_qualified_type (target, type_quals);
if (b1)
{
if (same_type_p (b1, b2)
|| (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
target = build_offset_type (b2, target);
else if (binfo_or_else (b2, b1))
target = build_offset_type (b1, target);
}
if (code1 == POINTER_TYPE)
t1 = build_pointer_type (target);
else
t1 = build_reference_type (target);
t1 = build_type_attribute_variant (t1, attributes);
if (TREE_CODE (target) == METHOD_TYPE)
t1 = build_ptrmemfunc_type (t1);
return t1;
}
case ARRAY_TYPE:
{
tree elt = common_type (TREE_TYPE (t1), TREE_TYPE (t2));
if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
return build_type_attribute_variant (t1, attributes);
if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
return build_type_attribute_variant (t2, attributes);
t1 = build_cplus_array_type
(elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
return build_type_attribute_variant (t1, attributes);
}
case FUNCTION_TYPE:
{
tree valtype = common_type (TREE_TYPE (t1), TREE_TYPE (t2));
tree p1 = TYPE_ARG_TYPES (t1);
tree p2 = TYPE_ARG_TYPES (t2);
tree rval, raises;
if (valtype == TREE_TYPE (t1) && ! p2)
return build_type_attribute_variant (t1, attributes);
if (valtype == TREE_TYPE (t2) && ! p1)
return build_type_attribute_variant (t2, attributes);
if (p1 == NULL_TREE || TREE_VALUE (p1) == void_type_node)
{
rval = build_function_type (valtype, p2);
if ((raises = TYPE_RAISES_EXCEPTIONS (t2)))
rval = build_exception_variant (rval, raises);
return build_type_attribute_variant (rval, attributes);
}
raises = TYPE_RAISES_EXCEPTIONS (t1);
if (p2 == NULL_TREE || TREE_VALUE (p2) == void_type_node)
{
rval = build_function_type (valtype, p1);
if (raises)
rval = build_exception_variant (rval, raises);
return build_type_attribute_variant (rval, attributes);
}
rval = build_function_type (valtype, commonparms (p1, p2));
rval = build_exception_variant (rval, raises);
return build_type_attribute_variant (rval, attributes);
}
case RECORD_TYPE:
case UNION_TYPE:
t1 = TYPE_MAIN_VARIANT (t1);
t2 = TYPE_MAIN_VARIANT (t2);
if (DERIVED_FROM_P (t1, t2) && binfo_or_else (t1, t2))
return build_type_attribute_variant (t1, attributes);
else if (binfo_or_else (t2, t1))
return build_type_attribute_variant (t2, attributes);
else
{
compiler_error ("common_type called with uncommon aggregate types");
return error_mark_node;
}
case METHOD_TYPE:
if (TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
{
tree basetype;
tree raises, t3;
tree b1 = TYPE_OFFSET_BASETYPE (t1);
tree b2 = TYPE_OFFSET_BASETYPE (t2);
if (same_type_p (b1, b2)
|| (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2)));
else
{
if (binfo_or_else (b2, b1) == NULL_TREE)
compiler_error ("common_type called with uncommon method types");
basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1)));
}
raises = TYPE_RAISES_EXCEPTIONS (t1);
t1 = build_function_type (TREE_TYPE (t1),
TREE_CHAIN (TYPE_ARG_TYPES (t1)));
t2 = build_function_type (TREE_TYPE (t2),
TREE_CHAIN (TYPE_ARG_TYPES (t2)));
t3 = common_type (t1, t2);
t3 = build_cplus_method_type (basetype, TREE_TYPE (t3),
TYPE_ARG_TYPES (t3));
t1 = build_exception_variant (t3, raises);
}
else
compiler_error ("common_type called with uncommon method types");
return build_type_attribute_variant (t1, attributes);
case OFFSET_TYPE:
my_friendly_abort (990325);
default:
return build_type_attribute_variant (t1, attributes);
}
}
int
compexcepttypes (t1, t2)
tree t1, t2;
{
return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
}
static int
comp_array_types (cmp, t1, t2, strict)
register int (*cmp) PROTO((tree, tree, int));
tree t1, t2;
int strict;
{
tree d1;
tree d2;
if (t1 == t2)
return 1;
if (!(TREE_TYPE (t1) == TREE_TYPE (t2)
|| (*cmp) (TREE_TYPE (t1), TREE_TYPE (t2),
strict & ~COMPARE_REDECLARATION)))
return 0;
d1 = TYPE_DOMAIN (t1);
d2 = TYPE_DOMAIN (t2);
if (d1 == d2)
return 1;
if (!d1 || !d2)
return strict & COMPARE_REDECLARATION;
return (cp_tree_equal (TYPE_MIN_VALUE (d1),
TYPE_MIN_VALUE (d2))
&& cp_tree_equal (TYPE_MAX_VALUE (d1),
TYPE_MAX_VALUE (d2)));
}
int
comptypes (type1, type2, strict)
tree type1, type2;
int strict;
{
register tree t1 = type1;
register tree t2 = type2;
int attrval, val;
int orig_strict = strict;
strict &= ~COMPARE_REDECLARATION;
if (t1 == t2)
return 1;
my_friendly_assert (t1 != error_mark_node, 307);
if (t2 == error_mark_node)
return 0;
if (strict & COMPARE_RELAXED)
{
if (TREE_CODE (t1) == ENUMERAL_TYPE)
t1 = type_for_size (TYPE_PRECISION (t1), 1);
if (TREE_CODE (t2) == ENUMERAL_TYPE)
t2 = type_for_size (TYPE_PRECISION (t2), 1);
if (t1 == t2)
return 1;
}
if (TYPE_PTRMEMFUNC_P (t1))
t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
if (TYPE_PTRMEMFUNC_P (t2))
t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
if (TREE_CODE (t1) != TREE_CODE (t2))
return 0;
if (CP_TYPE_QUALS (t1) != CP_TYPE_QUALS (t2))
return 0;
if (strict == COMPARE_STRICT
&& TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
return 0;
if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return 1;
#ifndef COMP_TYPE_ATTRIBUTES
#define COMP_TYPE_ATTRIBUTES(t1,t2) 1
#endif
if (strict & COMPARE_NO_ATTRIBUTES)
attrval = 1;
else if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2)))
return 0;
val = 0;
switch (TREE_CODE (t1))
{
case TEMPLATE_TEMPLATE_PARM:
if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
|| TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
return 0;
if (! comp_template_parms (DECL_TEMPLATE_PARMS (TYPE_NAME (t1)),
DECL_TEMPLATE_PARMS (TYPE_NAME (t2))))
return 0;
if (!TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t1)
&& ! TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2))
return 1;
strict = COMPARE_STRICT;
case RECORD_TYPE:
case UNION_TYPE:
#ifdef OBJCPLUS
if (maybe_objc_comptypes (t1, t2, 0) == 1)
return 1;
#endif
if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2)
&& (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
|| TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM))
val = comp_template_args (TYPE_TI_ARGS (t1),
TYPE_TI_ARGS (t2));
look_hard:
if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
{
val = 1;
break;
}
if ((strict & COMPARE_RELAXED) && DERIVED_FROM_P (t2, t1))
{
val = 1;
break;
}
break;
case OFFSET_TYPE:
val = (comptypes (build_pointer_type (TYPE_OFFSET_BASETYPE (t1)),
build_pointer_type (TYPE_OFFSET_BASETYPE (t2)), strict)
&& comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict));
break;
case METHOD_TYPE:
if (! compexcepttypes (t1, t2))
return 0;
val = (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
&& compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)));
break;
case POINTER_TYPE:
case REFERENCE_TYPE:
t1 = TREE_TYPE (t1);
t2 = TREE_TYPE (t2);
#ifdef OBJCPLUS
if (maybe_objc_comptypes (t1, t2, 0) == 1)
return 1;
#endif
val = comptypes (t1, t2, strict);
if (val)
break;
if (TREE_CODE (t1) == RECORD_TYPE
&& TREE_CODE (t2) == RECORD_TYPE)
goto look_hard;
break;
case FUNCTION_TYPE:
if (! compexcepttypes (t1, t2))
return 0;
val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
|| comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
&& compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)));
break;
case ARRAY_TYPE:
val = comp_array_types (comptypes, t1, t2, orig_strict);
break;
case TEMPLATE_TYPE_PARM:
return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2)
&& TEMPLATE_TYPE_LEVEL (t1) == TEMPLATE_TYPE_LEVEL (t2);
case TYPENAME_TYPE:
if (TYPE_IDENTIFIER (t1) != TYPE_IDENTIFIER (t2))
return 0;
return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
default:
break;
}
return attrval == 2 && val == 1 ? 2 : val;
}
static int
comp_cv_target_types (ttl, ttr, nptrs)
tree ttl, ttr;
int nptrs;
{
int t;
if (!at_least_as_qualified_p (ttl, ttr)
&& !at_least_as_qualified_p (ttr, ttl))
return 0;
if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr))
return more_qualified_p (ttr, ttl) ? -1 : 1;
t = comp_target_types (ttl, ttr, nptrs);
if ((t == 1 && at_least_as_qualified_p (ttl, ttr))
|| (t == -1 && at_least_as_qualified_p (ttr, ttl)))
return t;
return 0;
}
int
comp_target_types (ttl, ttr, nptrs)
tree ttl, ttr;
int nptrs;
{
ttl = TYPE_MAIN_VARIANT (ttl);
ttr = TYPE_MAIN_VARIANT (ttr);
#ifdef OBJCPLUS
if (maybe_objc_comptypes (ttl, ttr, 1) == 1)
return 1;
#endif
if (same_type_p (ttl, ttr))
return 1;
if (TREE_CODE (ttr) != TREE_CODE (ttl))
return 0;
if ((TREE_CODE (ttr) == POINTER_TYPE
|| TREE_CODE (ttr) == REFERENCE_TYPE)
&& nptrs > 0)
{
int is_ptr = TREE_CODE (ttr) == POINTER_TYPE;
ttl = TREE_TYPE (ttl);
ttr = TREE_TYPE (ttr);
if (is_ptr)
{
if (TREE_CODE (ttl) == UNKNOWN_TYPE
|| TREE_CODE (ttr) == UNKNOWN_TYPE)
return 1;
else if (TREE_CODE (ttl) == VOID_TYPE
&& TREE_CODE (ttr) != FUNCTION_TYPE
&& TREE_CODE (ttr) != METHOD_TYPE
&& TREE_CODE (ttr) != OFFSET_TYPE)
return 1;
else if (TREE_CODE (ttr) == VOID_TYPE
&& TREE_CODE (ttl) != FUNCTION_TYPE
&& TREE_CODE (ttl) != METHOD_TYPE
&& TREE_CODE (ttl) != OFFSET_TYPE)
return -1;
else if (TREE_CODE (ttl) == POINTER_TYPE
|| TREE_CODE (ttl) == ARRAY_TYPE)
{
if (comp_ptr_ttypes (ttl, ttr))
return 1;
else if (comp_ptr_ttypes (ttr, ttl))
return -1;
return 0;
}
}
if (TREE_CODE (ttl) == FUNCTION_TYPE || TREE_CODE (ttl) == METHOD_TYPE)
return comp_target_types (ttl, ttr, nptrs - 1);
return comp_cv_target_types (ttl, ttr, nptrs - 1);
}
if (TREE_CODE (ttr) == ARRAY_TYPE)
return comp_array_types (comp_target_types, ttl, ttr, COMPARE_STRICT);
else if (TREE_CODE (ttr) == FUNCTION_TYPE || TREE_CODE (ttr) == METHOD_TYPE)
{
tree argsl, argsr;
int saw_contra = 0;
if (pedantic)
{
if (!same_type_p (TREE_TYPE (ttl), TREE_TYPE (ttr)))
return 0;
}
else
{
switch (comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), -1))
{
case 0:
return 0;
case -1:
saw_contra = 1;
}
}
argsl = TYPE_ARG_TYPES (ttl);
argsr = TYPE_ARG_TYPES (ttr);
if (TREE_CODE (ttr) == METHOD_TYPE)
{
tree tl = TYPE_METHOD_BASETYPE (ttl);
tree tr = TYPE_METHOD_BASETYPE (ttr);
if (!same_or_base_type_p (tr, tl))
{
if (same_or_base_type_p (tl, tr))
saw_contra = 1;
else
return 0;
}
argsl = TREE_CHAIN (argsl);
argsr = TREE_CHAIN (argsr);
}
switch (comp_target_parms (argsl, argsr, 1))
{
case 0:
return 0;
case -1:
saw_contra = 1;
}
return saw_contra ? -1 : 1;
}
else if (TREE_CODE (ttr) == OFFSET_TYPE)
{
int base;
if (same_or_base_type_p (TYPE_OFFSET_BASETYPE (ttr),
TYPE_OFFSET_BASETYPE (ttl)))
base = 1;
else if (same_or_base_type_p (TYPE_OFFSET_BASETYPE (ttl),
TYPE_OFFSET_BASETYPE (ttr)))
{
tree tmp = ttl;
ttl = ttr;
ttr = tmp;
base = -1;
}
else
return 0;
ttl = TREE_TYPE (ttl);
ttr = TREE_TYPE (ttr);
if (TREE_CODE (ttl) == POINTER_TYPE
|| TREE_CODE (ttl) == ARRAY_TYPE)
{
if (comp_ptr_ttypes (ttl, ttr))
return base;
return 0;
}
else
{
if (comp_cv_target_types (ttl, ttr, nptrs) == 1)
return base;
return 0;
}
}
else if (IS_AGGR_TYPE (ttl))
{
if (nptrs < 0)
return 0;
if (same_or_base_type_p (build_pointer_type (ttl),
build_pointer_type (ttr)))
return 1;
if (same_or_base_type_p (build_pointer_type (ttr),
build_pointer_type (ttl)))
return -1;
return 0;
}
return 0;
}
int
at_least_as_qualified_p (type1, type2)
tree type1;
tree type2;
{
return ((CP_TYPE_QUALS (type1) & CP_TYPE_QUALS (type2))
== CP_TYPE_QUALS (type2));
}
int
more_qualified_p (type1, type2)
tree type1;
tree type2;
{
return (CP_TYPE_QUALS (type1) != CP_TYPE_QUALS (type2)
&& at_least_as_qualified_p (type1, type2));
}
int
comp_cv_qualification (type1, type2)
tree type1;
tree type2;
{
if (CP_TYPE_QUALS (type1) == CP_TYPE_QUALS (type2))
return 0;
if (at_least_as_qualified_p (type1, type2))
return 1;
else if (at_least_as_qualified_p (type2, type1))
return -1;
return 0;
}
int
comp_cv_qual_signature (type1, type2)
tree type1;
tree type2;
{
if (comp_ptr_ttypes_real (type2, type1, -1))
return 1;
else if (comp_ptr_ttypes_real (type1, type2, -1))
return -1;
else
return 0;
}
static tree
common_base_type (tt1, tt2)
tree tt1, tt2;
{
tree best = NULL_TREE;
int i;
if (UNIQUELY_DERIVED_FROM_P (tt1, tt2))
return tt1;
if (UNIQUELY_DERIVED_FROM_P (tt2, tt1))
return tt2;
for (i = CLASSTYPE_N_BASECLASSES (tt1)-1; i >= 0; i--)
{
tree basetype = TYPE_BINFO_BASETYPE (tt1, i);
tree trial = common_base_type (basetype, tt2);
if (trial)
{
if (trial == error_mark_node)
return trial;
if (best == NULL_TREE)
best = trial;
else if (best != trial)
return error_mark_node;
}
}
for (i = CLASSTYPE_N_BASECLASSES (tt2)-1; i >= 0; i--)
{
tree basetype = TYPE_BINFO_BASETYPE (tt2, i);
tree trial = common_base_type (tt1, basetype);
if (trial)
{
if (trial == error_mark_node)
return trial;
if (best == NULL_TREE)
best = trial;
else if (best != trial)
return error_mark_node;
}
}
return best;
}
int
compparms (parms1, parms2)
tree parms1, parms2;
{
register tree t1 = parms1, t2 = parms2;
while (1)
{
if (t1 == 0 && t2 == 0)
return 1;
if (t1 == 0 || t2 == 0)
return 0;
if (!same_type_p (TREE_VALUE (t2), TREE_VALUE (t1)))
return 0;
t1 = TREE_CHAIN (t1);
t2 = TREE_CHAIN (t2);
}
}
static int
comp_target_parms (parms1, parms2, strict)
tree parms1, parms2;
int strict;
{
register tree t1 = parms1, t2 = parms2;
int warn_contravariance = 0;
if (t1 == 0 && t2 != 0)
{
if (! flag_strict_prototype && t2 == void_list_node)
;
else
cp_pedwarn ("ANSI C++ prohibits conversion from `%#T' to `(...)'",
parms2);
return self_promoting_args_p (t2);
}
if (t2 == 0)
return self_promoting_args_p (t1);
for (; t1 || t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
{
tree p1, p2;
if (t1 == 0 || t2 == 0)
{
if (strict > 0)
return 0;
if (strict < 0)
return 1 + warn_contravariance;
return ((t1 && TREE_PURPOSE (t1)) + warn_contravariance);
}
p1 = TREE_VALUE (t1);
p2 = TREE_VALUE (t2);
if (same_type_p (p1, p2))
continue;
if (pedantic)
return 0;
if ((TREE_CODE (p1) == POINTER_TYPE && TREE_CODE (p2) == POINTER_TYPE)
|| (TREE_CODE (p1) == REFERENCE_TYPE
&& TREE_CODE (p2) == REFERENCE_TYPE))
{
if (strict <= 0
&& (TYPE_MAIN_VARIANT (TREE_TYPE (p1))
== TYPE_MAIN_VARIANT (TREE_TYPE (p2))))
continue;
if (TREE_TYPE (p1) == void_type_node)
continue;
if (TREE_TYPE (p2) == void_type_node)
{
warn_contravariance = 1;
continue;
}
if (IS_AGGR_TYPE (TREE_TYPE (p1))
&& !same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (p1)),
TYPE_MAIN_VARIANT (TREE_TYPE (p2))))
return 0;
}
if (comp_target_types (p2, p1, 1) <= 0)
{
if (comp_target_types (p1, p2, 1) > 0)
{
warn_contravariance = 1;
continue;
}
if (strict != 0)
return 0;
}
}
return warn_contravariance ? -1 : 1;
}
int
self_promoting_args_p (parms)
tree parms;
{
register tree t;
for (t = parms; t; t = TREE_CHAIN (t))
{
register tree type = TREE_VALUE (t);
if (TREE_CHAIN (t) == 0 && type != void_type_node)
return 0;
if (type == 0)
return 0;
if (TYPE_MAIN_VARIANT (type) == float_type_node)
return 0;
if (C_PROMOTING_INTEGER_TYPE_P (type))
return 0;
}
return 1;
}
tree
c_vec_step (type)
tree type;
{
enum tree_code code = TREE_CODE (type);
if (code != VECTOR_TYPE)
{
error ("operand of `vec_step' must be a vector type");
return size_int (0);
}
return size_binop (CEIL_DIV_EXPR, size_int (16),
c_sizeof (TREE_TYPE (type)));
}
tree
c_vec_step_expr (expr)
tree expr;
{
return c_vec_step (TREE_TYPE (expr));
}
tree
build_vector_constant (type, values)
tree type;
tree values;
{
tree vtype;
tree valarray[16], valtail;
int valnum, elements;
vtype = TREE_TYPE (type);
elements = (TREE_INT_CST_LOW (TYPE_SIZE (type))
/ TREE_INT_CST_LOW (TYPE_SIZE (vtype)));
for (valtail = values, valnum = 0;
valtail;
valtail = TREE_CHAIN (valtail), valnum++)
{
register tree val = TREE_VALUE (valtail);
STRIP_NOPS (val);
if (TREE_CODE (val) != INTEGER_CST && TREE_CODE (val) != REAL_CST)
{
error("expected a constant expression");
return error_mark_node;
}
valarray[valnum] = convert_for_assignment (vtype, val, "assignment",
NULL_TREE, 0);
}
if (valnum != 1 && valnum != elements)
{
error (valnum < elements
? "too few initializers" : "too many initializers");
return error_mark_node;
}
while (valnum < elements)
valarray[valnum++] = valarray[0];
while (elements > 4)
{
int i, j;
for (i = 2, j = 0; i <= elements; i += 2, j++)
{
unsigned HOST_WIDE_INT a = TREE_INT_CST_LOW (valarray[i-2]);
unsigned HOST_WIDE_INT b = TREE_INT_CST_LOW (valarray[i-1]);
int bits = 128 / elements;
valarray[j] = build_int_2 ((a << bits) | (b & ((1 << bits) - 1)), 0);
}
elements /= 2;
}
return build_vector (type, valarray[0], valarray[1],
valarray[2], valarray[3]);
}
tree
unsigned_type (type)
tree type;
{
tree type1 = TYPE_MAIN_VARIANT (type);
if (type1 == signed_char_type_node || type1 == char_type_node)
return unsigned_char_type_node;
if (type1 == integer_type_node)
return unsigned_type_node;
if (type1 == short_integer_type_node)
return short_unsigned_type_node;
if (type1 == long_integer_type_node)
return long_unsigned_type_node;
if (type1 == long_long_integer_type_node)
return long_long_unsigned_type_node;
#if HOST_BITS_PER_WIDE_INT >= 64
if (type1 == intTI_type_node)
return unsigned_intTI_type_node;
#endif
if (type1 == intDI_type_node)
return unsigned_intDI_type_node;
if (type1 == intSI_type_node)
return unsigned_intSI_type_node;
if (type1 == intHI_type_node)
return unsigned_intHI_type_node;
if (type1 == intQI_type_node)
return unsigned_intQI_type_node;
return signed_or_unsigned_type (1, type);
}
tree
signed_type (type)
tree type;
{
tree type1 = TYPE_MAIN_VARIANT (type);
if (type1 == unsigned_char_type_node || type1 == char_type_node)
return signed_char_type_node;
if (type1 == unsigned_type_node)
return integer_type_node;
if (type1 == short_unsigned_type_node)
return short_integer_type_node;
if (type1 == long_unsigned_type_node)
return long_integer_type_node;
if (type1 == long_long_unsigned_type_node)
return long_long_integer_type_node;
#if HOST_BITS_PER_WIDE_INT >= 64
if (type1 == unsigned_intTI_type_node)
return intTI_type_node;
#endif
if (type1 == unsigned_intDI_type_node)
return intDI_type_node;
if (type1 == unsigned_intSI_type_node)
return intSI_type_node;
if (type1 == unsigned_intHI_type_node)
return intHI_type_node;
if (type1 == unsigned_intQI_type_node)
return intQI_type_node;
return signed_or_unsigned_type (0, type);
}
tree
signed_or_unsigned_type (unsignedp, type)
int unsignedp;
tree type;
{
if (! INTEGRAL_TYPE_P (type)
|| TREE_UNSIGNED (type) == unsignedp)
return type;
if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
return unsignedp ? unsigned_type_node : integer_type_node;
if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
return unsignedp ? short_unsigned_type_node : short_integer_type_node;
if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
return (unsignedp ? long_long_unsigned_type_node
: long_long_integer_type_node);
return type;
}
tree
c_sizeof (type)
tree type;
{
enum tree_code code = TREE_CODE (type);
tree t;
if (processing_template_decl)
return build_min (SIZEOF_EXPR, sizetype, type);
if (code == FUNCTION_TYPE)
{
if (pedantic || warn_pointer_arith)
pedwarn ("ANSI C++ forbids taking the sizeof a function type");
return size_int (1);
}
if (code == METHOD_TYPE)
{
if (pedantic || warn_pointer_arith)
pedwarn ("ANSI C++ forbids taking the sizeof a method type");
return size_int (1);
}
if (code == VOID_TYPE)
{
if (pedantic || warn_pointer_arith)
pedwarn ("ANSI C++ forbids taking the sizeof a void type");
return size_int (1);
}
if (code == ERROR_MARK)
return size_int (1);
if (code == REFERENCE_TYPE)
type = TREE_TYPE (type);
if (code == OFFSET_TYPE)
type = TREE_TYPE (type);
if (IS_SIGNATURE (type))
{
error ("`sizeof' applied to a signature type");
return size_int (0);
}
if (TYPE_SIZE (complete_type (type)) == 0)
{
cp_error ("`sizeof' applied to incomplete type `%T'", type);
return size_int (0);
}
t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (TYPE_PRECISION (char_type_node)));
t = convert (sizetype, t);
if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0))
TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) = 1;
return t;
}
tree
expr_sizeof (e)
tree e;
{
if (processing_template_decl)
return build_min (SIZEOF_EXPR, sizetype, e);
if (TREE_CODE (e) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
error ("sizeof applied to a bit-field");
if (TREE_CODE (e) == COMPOUND_EXPR
&& (TREE_CODE (TREE_TYPE (e)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (e)) == FUNCTION_TYPE))
e = default_conversion (e);
else if (is_overloaded_fn (e))
{
pedwarn ("ANSI C++ forbids taking the sizeof a function type");
return size_int (1);
}
else if (type_unknown_p (e))
{
incomplete_type_error (e, TREE_TYPE (e));
return size_int (1);
}
return c_sizeof (TREE_TYPE (e));
}
tree
c_sizeof_nowarn (type)
tree type;
{
enum tree_code code = TREE_CODE (type);
tree t;
if (code == FUNCTION_TYPE
|| code == METHOD_TYPE
|| code == VOID_TYPE
|| code == ERROR_MARK)
return size_int (1);
if (code == REFERENCE_TYPE)
type = TREE_TYPE (type);
if (TYPE_SIZE (type) == 0)
return size_int (0);
t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (TYPE_PRECISION (char_type_node)));
t = convert (sizetype, t);
force_fit_type (t, 0);
return t;
}
tree
c_alignof (type)
tree type;
{
enum tree_code code = TREE_CODE (type);
tree t;
if (processing_template_decl)
return build_min (ALIGNOF_EXPR, sizetype, type);
if (code == FUNCTION_TYPE || code == METHOD_TYPE)
return size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (code == VOID_TYPE || code == ERROR_MARK)
return size_int (1);
if (code == REFERENCE_TYPE)
type = TREE_TYPE (type);
if (IS_SIGNATURE (type))
{
error ("`__alignof' applied to a signature type");
return size_int (1);
}
t = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
force_fit_type (t, 0);
return t;
}
tree
decay_conversion (exp)
tree exp;
{
register tree type;
register enum tree_code code;
if (TREE_CODE (exp) == OFFSET_REF)
exp = resolve_offset_ref (exp);
type = TREE_TYPE (exp);
code = TREE_CODE (type);
if (code == REFERENCE_TYPE)
{
exp = convert_from_reference (exp);
type = TREE_TYPE (exp);
code = TREE_CODE (type);
}
if (TREE_CODE (exp) == CONST_DECL)
exp = DECL_INITIAL (exp);
else if (TREE_READONLY_DECL_P (exp)
&& (code != ARRAY_TYPE
|| (TREE_CODE (exp) == VAR_DECL && DECL_IGNORED_P (exp))))
{
exp = decl_constant_value (exp);
type = TREE_TYPE (exp);
}
if (code == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
return error_mark_node;
}
if (code == METHOD_TYPE)
my_friendly_abort (990506);
if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
return build_unary_op (ADDR_EXPR, exp, 0);
if (code == ARRAY_TYPE)
{
register tree adr;
tree ptrtype;
if (TREE_CODE (exp) == INDIRECT_REF)
{
tree inner = TREE_OPERAND (exp, 0);
if (TREE_CODE (TREE_TYPE (inner)) == REFERENCE_TYPE)
{
inner = build1 (CONVERT_EXPR,
build_pointer_type (TREE_TYPE
(TREE_TYPE (inner))),
inner);
TREE_CONSTANT (inner) = TREE_CONSTANT (TREE_OPERAND (inner, 0));
}
return cp_convert (build_pointer_type (TREE_TYPE (type)), inner);
}
if (TREE_CODE (exp) == COMPOUND_EXPR)
{
tree op1 = decay_conversion (TREE_OPERAND (exp, 1));
return build (COMPOUND_EXPR, TREE_TYPE (op1),
TREE_OPERAND (exp, 0), op1);
}
if (!lvalue_p (exp)
&& ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
{
error ("invalid use of non-lvalue array");
return error_mark_node;
}
ptrtype = build_pointer_type (TREE_TYPE (type));
if (TREE_CODE (exp) == VAR_DECL)
{
adr = build1 (ADDR_EXPR, ptrtype, exp);
if (mark_addressable (exp) == 0)
return error_mark_node;
TREE_CONSTANT (adr) = staticp (exp);
TREE_SIDE_EFFECTS (adr) = 0;
return adr;
}
adr = build_unary_op (ADDR_EXPR, exp, 1);
return cp_convert (ptrtype, adr);
}
return exp;
}
tree
default_conversion (exp)
tree exp;
{
tree type;
enum tree_code code;
exp = decay_conversion (exp);
type = TREE_TYPE (exp);
code = TREE_CODE (type);
if (INTEGRAL_CODE_P (code))
{
tree t = type_promotes_to (type);
if (t != type)
return cp_convert (t, exp);
}
return exp;
}
tree
inline_conversion (exp)
tree exp;
{
if (TREE_CODE (exp) == FUNCTION_DECL)
exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
return exp;
}
int
string_conv_p (totype, exp, warn)
tree totype, exp;
int warn;
{
tree t;
if (! flag_const_strings || TREE_CODE (totype) != POINTER_TYPE)
return 0;
t = TREE_TYPE (totype);
if (!same_type_p (t, char_type_node)
&& !same_type_p (t, wchar_type_node))
return 0;
if (TREE_CODE (exp) == STRING_CST)
{
if (!same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (exp))), t))
return 0;
}
else
{
t = build_pointer_type (build_qualified_type (t, TYPE_QUAL_CONST));
if (!same_type_p (TREE_TYPE (exp), t))
return 0;
STRIP_NOPS (exp);
if (TREE_CODE (exp) != ADDR_EXPR
|| TREE_CODE (TREE_OPERAND (exp, 0)) != STRING_CST)
return 0;
}
if (warn && warn_write_strings)
cp_warning ("deprecated conversion from string constant to `%T'", totype);
return 1;
}
tree
build_object_ref (datum, basetype, field)
tree datum, basetype, field;
{
tree dtype;
if (datum == error_mark_node)
return error_mark_node;
dtype = TREE_TYPE (datum);
if (TREE_CODE (dtype) == REFERENCE_TYPE)
dtype = TREE_TYPE (dtype);
if (! IS_AGGR_TYPE_CODE (TREE_CODE (dtype)))
{
cp_error ("request for member `%T::%D' in expression of non-aggregate type `%T'",
basetype, field, dtype);
return error_mark_node;
}
else if (IS_SIGNATURE (basetype))
{
warning ("signature name in scope resolution ignored");
return build_component_ref (datum, field, NULL_TREE, 1);
}
else if (is_aggr_type (basetype, 1))
{
tree binfo = binfo_or_else (basetype, dtype);
if (binfo)
return build_x_component_ref (build_scoped_ref (datum, basetype),
field, binfo, 1);
}
return error_mark_node;
}
tree
build_component_ref_1 (datum, field, protect)
tree datum, field;
int protect;
{
return convert_from_reference
(build_component_ref (datum, field, NULL_TREE, protect));
}
static tree
rationalize_conditional_expr (code, t)
enum tree_code code;
tree t;
{
if (TREE_CODE (t) == MIN_EXPR || TREE_CODE (t) == MAX_EXPR)
{
return
build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
? LE_EXPR : GE_EXPR),
TREE_OPERAND (t, 0),
TREE_OPERAND (t, 1)),
build_unary_op (code, TREE_OPERAND (t, 0), 0),
build_unary_op (code, TREE_OPERAND (t, 1), 0));
}
return
build_conditional_expr (TREE_OPERAND (t, 0),
build_unary_op (code, TREE_OPERAND (t, 1), 0),
build_unary_op (code, TREE_OPERAND (t, 2), 0));
}
static tree
lookup_anon_field (t, type)
tree t, type;
{
tree field;
for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
{
if (TREE_STATIC (field))
continue;
if (TREE_CODE (field) != FIELD_DECL)
continue;
if (DECL_NAME (field) == NULL_TREE
&& type == TREE_TYPE (field))
{
return field;
}
if (DECL_NAME (field) == NULL_TREE
&& TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
{
tree subfield = lookup_anon_field (TREE_TYPE (field), type);
if (subfield)
return subfield;
}
}
return NULL_TREE;
}
tree
build_component_ref (datum, component, basetype_path, protect)
tree datum, component, basetype_path;
int protect;
{
register tree basetype;
register enum tree_code code;
register tree field = NULL;
register tree ref;
tree field_type;
int type_quals;
if (processing_template_decl)
return build_min_nt (COMPONENT_REF, datum, component);
if (datum == error_mark_node
|| TREE_TYPE (datum) == error_mark_node)
return error_mark_node;
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));
switch (TREE_CODE (datum))
{
case COMPOUND_EXPR:
{
tree value = build_component_ref (TREE_OPERAND (datum, 1), component,
basetype_path, protect);
return build (COMPOUND_EXPR, TREE_TYPE (value),
TREE_OPERAND (datum, 0), value);
}
case COND_EXPR:
return build_conditional_expr
(TREE_OPERAND (datum, 0),
build_component_ref (TREE_OPERAND (datum, 1), component,
basetype_path, protect),
build_component_ref (TREE_OPERAND (datum, 2), component,
basetype_path, protect));
case TEMPLATE_DECL:
cp_error ("invalid use of %D", datum);
datum = error_mark_node;
break;
default:
break;
}
code = TREE_CODE (basetype);
if (code == REFERENCE_TYPE)
{
datum = convert_from_reference (datum);
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));
code = TREE_CODE (basetype);
}
if (TREE_CODE (datum) == OFFSET_REF)
{
datum = resolve_offset_ref (datum);
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));
code = TREE_CODE (basetype);
}
if (TREE_CODE (component) == TREE_LIST)
{
my_friendly_abort (980326);
#ifdef DEAD
my_friendly_assert (!(TREE_CHAIN (component) == NULL_TREE
&& DECL_CHAIN (TREE_VALUE (component)) == NULL_TREE), 309);
#endif
return build (COMPONENT_REF, TREE_TYPE (component), datum, component);
}
if (! IS_AGGR_TYPE_CODE (code))
{
if (code != ERROR_MARK)
cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
component, datum, basetype);
return error_mark_node;
}
if (!complete_type_or_else (basetype, datum))
return error_mark_node;
if (TREE_CODE (component) == BIT_NOT_EXPR)
{
if (TYPE_IDENTIFIER (basetype) != TREE_OPERAND (component, 0))
{
cp_error ("destructor specifier `%T::~%T' must have matching names",
basetype, TREE_OPERAND (component, 0));
return error_mark_node;
}
if (! TYPE_HAS_DESTRUCTOR (basetype))
{
cp_error ("type `%T' has no destructor", basetype);
return error_mark_node;
}
return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 1);
}
if (CLASSTYPE_VFIELD (basetype)
&& DECL_NAME (CLASSTYPE_VFIELD (basetype)) == component)
field = CLASSTYPE_VFIELD (basetype);
else if (TREE_CODE (component) == FIELD_DECL)
field = component;
else if (TREE_CODE (component) == TYPE_DECL)
{
cp_error ("invalid use of type decl `%#D' as expression", component);
return error_mark_node;
}
else
{
tree name = component;
if (TREE_CODE (component) == VAR_DECL)
name = DECL_NAME (component);
if (basetype_path == NULL_TREE)
basetype_path = TYPE_BINFO (basetype);
field = lookup_field (basetype_path, name,
protect && !VFIELD_NAME_P (name), 0);
if (field == error_mark_node)
return error_mark_node;
if (field == NULL_TREE)
{
tree fndecls = lookup_fnfields (basetype_path, name, 1);
if (fndecls == error_mark_node)
return error_mark_node;
if (fndecls)
{
if (TREE_CHAIN (fndecls) == NULL_TREE
&& TREE_CODE (TREE_VALUE (fndecls)) == FUNCTION_DECL)
{
if (DECL_STATIC_FUNCTION_P (TREE_VALUE (fndecls)))
{
tree fndecl = TREE_VALUE (fndecls);
enforce_access (TREE_PURPOSE (fndecls), fndecl);
mark_used (fndecl);
return fndecl;
}
else
{
TREE_VALUE (fndecls)
= scratch_ovl_cons (TREE_VALUE (fndecls), NULL_TREE);
}
}
ref = build (COMPONENT_REF, unknown_type_node,
datum, TREE_VALUE (fndecls));
return ref;
}
cp_error ("`%#T' has no member named `%D'", basetype, name);
return error_mark_node;
}
else if (TREE_TYPE (field) == error_mark_node)
return error_mark_node;
if (TREE_CODE (field) != FIELD_DECL)
{
if (TREE_CODE (field) == TYPE_DECL)
cp_pedwarn ("invalid use of type decl `%#D' as expression", field);
else if (DECL_RTL (field) != 0)
mark_used (field);
else
TREE_USED (field) = 1;
return field;
}
}
if (DECL_FIELD_CONTEXT (field) != basetype)
{
tree context = DECL_FIELD_CONTEXT (field);
tree base = context;
while (!same_type_p (base, basetype) && TYPE_NAME (base)
&& ANON_UNION_TYPE_P (base))
{
base = TYPE_CONTEXT (base);
}
if (base != basetype && TYPE_USES_COMPLEX_INHERITANCE (basetype))
{
tree addr = build_unary_op (ADDR_EXPR, datum, 0);
if (integer_zerop (addr))
{
error ("invalid reference to NULL ptr, use ptr-to-member instead");
return error_mark_node;
}
if (VBASE_NAME_P (DECL_NAME (field)))
{
tree binfo = get_binfo (base,
TREE_TYPE (TREE_TYPE (addr)), 0);
addr = convert_pointer_to_real (binfo, addr);
}
else
addr = convert_pointer_to (base, addr);
datum = build_indirect_ref (addr, NULL_PTR);
my_friendly_assert (datum != error_mark_node, 311);
}
basetype = base;
if (TYPE_NAME (context) && ANON_UNION_TYPE_P (context))
{
tree subfield = lookup_anon_field (basetype, context);
tree subdatum = build_component_ref (datum, subfield,
basetype_path, protect);
return build_component_ref (subdatum, field, basetype_path, protect);
}
}
type_quals = TYPE_UNQUALIFIED;
field_type = TREE_TYPE (field);
if (TREE_CODE (field_type) == REFERENCE_TYPE)
;
else
{
type_quals = (CP_TYPE_QUALS (field_type)
| CP_TYPE_QUALS (TREE_TYPE (datum)));
if (DECL_LANG_SPECIFIC (field) && DECL_MUTABLE_P (field))
type_quals &= ~TYPE_QUAL_CONST;
if (!IS_SIGNATURE (field_type))
field_type = cp_build_qualified_type (field_type, type_quals);
}
ref = fold (build (COMPONENT_REF, field_type,
break_out_cleanups (datum), field));
if (type_quals & TYPE_QUAL_CONST)
TREE_READONLY (ref) = 1;
else if (type_quals & TYPE_QUAL_VOLATILE)
TREE_THIS_VOLATILE (ref) = 1;
return ref;
}
tree
build_x_component_ref (datum, component, basetype_path, protect)
tree datum, component, basetype_path;
int protect;
{
tree t = build_component_ref (datum, component, basetype_path, protect);
if (! processing_template_decl)
t = convert_from_reference (t);
return t;
}
tree
build_x_indirect_ref (ptr, errorstring)
tree ptr;
const char *errorstring;
{
tree rval;
if (processing_template_decl)
return build_min_nt (INDIRECT_REF, ptr);
rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
NULL_TREE);
if (rval)
return rval;
return build_indirect_ref (ptr, errorstring);
}
tree
build_indirect_ref (ptr, errorstring)
tree ptr;
const char *errorstring;
{
register tree pointer, type;
if (ptr == error_mark_node)
return error_mark_node;
if (ptr == current_class_ptr)
return current_class_ref;
pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
? ptr : default_conversion (ptr));
type = TREE_TYPE (pointer);
if (TYPE_PTR_P (type) || TREE_CODE (type) == REFERENCE_TYPE)
{
tree t = canonical_type_variant (TREE_TYPE (type));
if (TREE_CODE (pointer) == ADDR_EXPR
&& !flag_volatile
&& same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
return TREE_OPERAND (pointer, 0);
else
{
tree ref = build1 (INDIRECT_REF, t, pointer);
TREE_READONLY (ref) = CP_TYPE_CONST_P (t);
TREE_THIS_VOLATILE (ref) = CP_TYPE_VOLATILE_P (t);
TREE_SIDE_EFFECTS (ref)
= (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (pointer)
|| flag_volatile);
return ref;
}
}
else if (TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type))
error ("invalid use of `%s' on pointer to member", errorstring);
else if (TREE_CODE (type) == RECORD_TYPE
&& (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
error ("cannot dereference signature pointer/reference");
else if (pointer != error_mark_node)
{
if (errorstring)
error ("invalid type argument of `%s'", errorstring);
else
error ("invalid type argument");
}
return error_mark_node;
}
tree
build_array_ref (array, idx)
tree array, idx;
{
if (idx == 0)
{
error ("subscript missing in array reference");
return error_mark_node;
}
if (TREE_TYPE (array) == error_mark_node
|| TREE_TYPE (idx) == error_mark_node)
return error_mark_node;
if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
&& TREE_CODE (array) != INDIRECT_REF)
{
tree rval, type;
if (warn_char_subscripts
&& TYPE_MAIN_VARIANT (TREE_TYPE (idx)) == char_type_node)
warning ("array subscript has type `char'");
idx = default_conversion (idx);
if (TREE_CODE (TREE_TYPE (idx)) != INTEGER_TYPE)
{
error ("array subscript is not an integer");
return error_mark_node;
}
if (TREE_CODE (idx) != INTEGER_CST
|| (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))))
!= INTEGER_CST)))
{
if (mark_addressable (array) == 0)
return error_mark_node;
}
if (TREE_CODE (idx) == INTEGER_CST
&& TYPE_VALUES (TREE_TYPE (array))
&& ! int_fits_type_p (idx, TYPE_VALUES (TREE_TYPE (array))))
{
if (mark_addressable (array) == 0)
return error_mark_node;
}
if (pedantic && !lvalue_p (array))
pedwarn ("ANSI C++ forbids subscripting non-lvalue array");
if (extra_warnings)
{
tree foo = array;
while (TREE_CODE (foo) == COMPONENT_REF)
foo = TREE_OPERAND (foo, 0);
if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo))
warning ("subscripting array declared `register'");
}
type = TREE_TYPE (TREE_TYPE (array));
rval = build (ARRAY_REF, type, array, idx);
TREE_READONLY (rval)
|= (CP_TYPE_CONST_P (type) | TREE_READONLY (array));
TREE_SIDE_EFFECTS (rval)
|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
TREE_THIS_VOLATILE (rval)
|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
return require_complete_type (fold (rval));
}
{
tree ar = default_conversion (array);
tree ind = default_conversion (idx);
if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE)
{
tree temp = ar;
ar = ind;
ind = temp;
}
if (ar == error_mark_node)
return ar;
if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE)
{
error ("subscripted value is neither array nor pointer");
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE)
{
error ("array subscript is not an integer");
return error_mark_node;
}
return build_indirect_ref (build_binary_op_nodefault (PLUS_EXPR, ar,
ind, PLUS_EXPR),
"array indexing");
}
}
tree
build_x_function_call (function, params, decl)
tree function, params, decl;
{
tree type;
tree template_id = NULL_TREE;
int is_method;
if (function == error_mark_node)
return error_mark_node;
if (processing_template_decl)
return build_min_nt (CALL_EXPR, function, params, NULL_TREE);
if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
{
template_id = function;
function = TREE_OPERAND (function, 0);
}
type = TREE_TYPE (function);
if (TREE_CODE (type) == OFFSET_TYPE
&& TREE_TYPE (type) == unknown_type_node
&& TREE_CODE (function) == TREE_LIST
&& TREE_CHAIN (function) == NULL_TREE)
{
type = TYPE_OFFSET_BASETYPE (type);
function = TREE_VALUE (function);
my_friendly_assert (TREE_CODE (function) == TREE_LIST, 999);
my_friendly_assert (TREE_CHAIN (function) == NULL_TREE, 999);
function = TREE_VALUE (function);
if (TREE_CODE (function) == OVERLOAD)
function = OVL_FUNCTION (function);
my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 999);
function = DECL_NAME (function);
return build_method_call (decl, function, params,
TYPE_BINFO (type), LOOKUP_NORMAL);
}
if ((TREE_CODE (function) == FUNCTION_DECL
&& DECL_STATIC_FUNCTION_P (function))
|| (TREE_CODE (function) == TEMPLATE_DECL
&& DECL_STATIC_FUNCTION_P (DECL_RESULT (function))))
return build_member_call(DECL_CONTEXT (function),
template_id
? template_id : DECL_NAME (function),
params);
is_method = ((TREE_CODE (function) == TREE_LIST
&& current_class_type != NULL_TREE
&& (IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function))
== function))
|| (TREE_CODE (function) == OVERLOAD
&& DECL_FUNCTION_MEMBER_P (OVL_CURRENT (function)))
|| TREE_CODE (function) == IDENTIFIER_NODE
|| TREE_CODE (type) == METHOD_TYPE
|| TYPE_PTRMEMFUNC_P (type));
if (! is_method && TREE_CODE (function) == TEMPLATE_DECL)
function = scratch_ovl_cons (function, NULL_TREE);
if (is_method)
{
tree basetype = NULL_TREE;
if (TREE_CODE (function) == OVERLOAD)
function = OVL_CURRENT (function);
if (TREE_CODE (function) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (function))
{
basetype = DECL_CLASS_CONTEXT (function);
if (DECL_NAME (function))
function = DECL_NAME (function);
else
function = TYPE_IDENTIFIER (DECL_CLASS_CONTEXT (function));
}
else if (TREE_CODE (function) == TREE_LIST)
{
my_friendly_assert (TREE_CODE (TREE_VALUE (function))
== FUNCTION_DECL, 312);
basetype = DECL_CLASS_CONTEXT (TREE_VALUE (function));
function = TREE_PURPOSE (function);
}
else if (TREE_CODE (function) != IDENTIFIER_NODE)
{
if (TREE_CODE (function) == OFFSET_REF)
{
if (TREE_OPERAND (function, 0))
decl = TREE_OPERAND (function, 0);
}
if (decl == NULL_TREE)
{
error ("pointer to member function called, but not in class scope");
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (function)) != POINTER_TYPE
&& ! TYPE_PTRMEMFUNC_P (TREE_TYPE (function))
&& TREE_CODE (function) != OFFSET_REF)
function = build (OFFSET_REF, TREE_TYPE (type), NULL_TREE,
function);
goto do_x_function;
}
if (basetype && (! current_class_type
|| ! DERIVED_FROM_P (basetype, current_class_type)))
return build_member_call (basetype, function, params);
if (decl == NULL_TREE)
{
if (current_class_type == NULL_TREE)
{
cp_error ("object missing in call to method `%D'", function);
return error_mark_node;
}
decl = build_dummy_object (current_class_type);
}
if (template_id)
function = template_id;
return build_method_call (decl, function, params,
NULL_TREE, LOOKUP_NORMAL);
}
else if (TREE_CODE (function) == COMPONENT_REF
&& type == unknown_type_node)
{
decl = TREE_OPERAND (function, 0);
function = TREE_OPERAND (function, 1);
function = DECL_NAME (OVL_CURRENT (function));
if (template_id)
{
TREE_OPERAND (template_id, 0) = function;
function = template_id;
}
return build_method_call (decl, function, params,
NULL_TREE, LOOKUP_NORMAL);
}
else if (really_overloaded_fn (function))
{
if (OVL_FUNCTION (function) == NULL_TREE)
{
cp_error ("function `%D' declared overloaded, but no definitions appear with which to resolve it?!?",
TREE_PURPOSE (function));
return error_mark_node;
}
else
{
if (template_id)
function = template_id;
return build_new_function_call (function, params);
}
}
else
function = OVL_CURRENT (function);
do_x_function:
if (TREE_CODE (function) == OFFSET_REF)
{
tree decl_addr;
if (TREE_OPERAND (function, 0))
decl = TREE_OPERAND (function, 0);
else
decl = current_class_ref;
decl_addr = build_unary_op (ADDR_EXPR, decl, 0);
if (TREE_CODE (TREE_OPERAND (function, 1)) == FIELD_DECL)
function = resolve_offset_ref (function);
else
function = TREE_OPERAND (function, 1);
function = get_member_function_from_ptrfunc (&decl_addr, function);
params = expr_tree_cons (NULL_TREE, decl_addr, params);
return build_function_call (function, params);
}
type = TREE_TYPE (function);
if (type != error_mark_node)
{
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
if (IS_AGGR_TYPE (type))
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE);
}
if (is_method)
{
tree fntype = TREE_TYPE (function);
tree ctypeptr = NULL_TREE;
if (TREE_CODE (function) == FUNCTION_DECL)
ctypeptr = build_pointer_type (DECL_CLASS_CONTEXT (function));
else if (TYPE_PTRMEMFUNC_P (fntype))
{
tree rec = TYPE_METHOD_BASETYPE (TREE_TYPE
(TYPE_PTRMEMFUNC_FN_TYPE (fntype)));
ctypeptr = build_pointer_type (rec);
}
else
my_friendly_abort (116);
if (decl == NULL_TREE)
{
if (current_function_decl
&& DECL_STATIC_FUNCTION_P (current_function_decl))
error ("invalid call to member function needing `this' in static member function scope");
else
error ("pointer to member function called, but not in class scope");
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE
&& ! TYPE_PTRMEMFUNC_P (TREE_TYPE (decl)))
{
decl = build_unary_op (ADDR_EXPR, decl, 0);
decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl);
}
else
decl = build_c_cast (ctypeptr, decl);
params = expr_tree_cons (NULL_TREE, decl, params);
}
return build_function_call (function, params);
}
tree
get_member_function_from_ptrfunc (instance_ptrptr, function)
tree *instance_ptrptr;
tree function;
{
if (TREE_CODE (function) == OFFSET_REF)
{
function = TREE_OPERAND (function, 1);
}
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
{
tree fntype, idx, e1, delta, delta2, e2, e3, aref, vtbl;
tree instance, basetype;
tree instance_ptr = *instance_ptrptr;
if (TREE_SIDE_EFFECTS (instance_ptr))
instance_ptr = save_expr (instance_ptr);
if (TREE_SIDE_EFFECTS (function))
function = save_expr (function);
fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
delta = cp_convert (ptrdiff_type_node,
build_component_ref (function, delta_identifier,
NULL_TREE, 0));
e3 = PFN_FROM_PTRMEMFUNC (function);
if (TYPE_SIZE (basetype) != NULL_TREE
&& ! TYPE_VIRTUAL_P (basetype))
e1 = e3;
else
{
idx = save_expr (default_conversion
(build_component_ref (function,
index_identifier,
NULL_TREE, 0)));
e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
instance = convert_pointer_to_real (basetype, instance_ptr);
if (instance == error_mark_node && instance_ptr != error_mark_node)
return instance;
vtbl = convert_pointer_to (ptr_type_node, instance);
delta2 = DELTA2_FROM_PTRMEMFUNC (function);
vtbl = build
(PLUS_EXPR,
build_pointer_type (build_pointer_type (vtable_entry_type)),
vtbl, cp_convert (ptrdiff_type_node, delta2));
vtbl = build_indirect_ref (vtbl, NULL_PTR);
aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
idx,
integer_one_node));
if (! flag_vtable_thunks)
{
aref = save_expr (aref);
delta = build_binary_op
(PLUS_EXPR,
build_conditional_expr (e1,
build_component_ref (aref,
delta_identifier,
NULL_TREE, 0),
integer_zero_node),
delta);
}
if (flag_vtable_thunks)
e2 = aref;
else
e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
TREE_TYPE (e2) = TREE_TYPE (e3);
e1 = build_conditional_expr (e1, e2, e3);
if (TREE_CODE (instance_ptr) == SAVE_EXPR)
e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
instance_ptr, e1);
}
*instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
instance_ptr, delta);
if (instance_ptr == error_mark_node
&& TREE_CODE (e1) != ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (e1, 0)) != FUNCTION_DECL)
cp_error ("object missing in `%E'", function);
function = e1;
}
return function;
}
tree
build_function_call_real (function, params, require_complete, flags)
tree function, params;
int require_complete, flags;
{
register tree fntype, fndecl;
register tree value_type;
register tree coerced_params;
tree name = NULL_TREE, assembler_name = NULL_TREE;
int is_method;
if (TREE_CODE (function) == NOP_EXPR
&& TREE_TYPE (function) == TREE_TYPE (TREE_OPERAND (function, 0)))
function = TREE_OPERAND (function, 0);
if (TREE_CODE (function) == FUNCTION_DECL
&& DECL_TARGET_OVERLOADED_INTRINSIC_P (function))
{
#ifdef SELECT_TARGET_OVERLOADED_INTRINSIC
function = SELECT_TARGET_OVERLOADED_INTRINSIC (function, params);
if (function == NULL_TREE)
#endif
return error_mark_node;
}
if (TREE_CODE (function) == FUNCTION_DECL)
{
name = DECL_NAME (function);
assembler_name = DECL_ASSEMBLER_NAME (function);
GNU_xref_call (current_function_decl,
IDENTIFIER_POINTER (name ? name
: TYPE_IDENTIFIER (DECL_CLASS_CONTEXT
(function))));
mark_used (function);
fndecl = function;
if (pedantic && DECL_MAIN_P (function))
pedwarn ("ANSI C++ forbids calling `main' from within program");
if (DECL_INLINE (function))
function = inline_conversion (function);
else
function = build_addr_func (function);
}
else
{
fndecl = NULL_TREE;
function = build_addr_func (function);
}
if (function == error_mark_node)
return error_mark_node;
fntype = TREE_TYPE (function);
if (TYPE_PTRMEMFUNC_P (fntype))
{
cp_error ("must use .* or ->* to call pointer-to-member function in `%E (...)'",
function);
return error_mark_node;
}
is_method = (TREE_CODE (fntype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (fntype)) == METHOD_TYPE);
if (!((TREE_CODE (fntype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)
|| is_method
|| TREE_CODE (function) == TEMPLATE_ID_EXPR))
{
cp_error ("`%E' cannot be used as a function", function);
return error_mark_node;
}
fntype = TREE_TYPE (fntype);
if (flags & LOOKUP_COMPLAIN)
coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
params, fndecl, LOOKUP_NORMAL);
else
coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
params, fndecl, 0);
if (coerced_params == error_mark_node)
{
if (flags & LOOKUP_SPECULATIVELY)
return NULL_TREE;
else
return error_mark_node;
}
if (warn_format && (name || assembler_name))
check_function_format (name, assembler_name, coerced_params);
if (TREE_CODE (function) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (function, 0)))
switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0)))
{
case BUILT_IN_ABS:
case BUILT_IN_LABS:
case BUILT_IN_FABS:
if (coerced_params == 0)
return integer_zero_node;
return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
default:
break;
}
value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
{
register tree result
= build_call (function, value_type, coerced_params);
if (require_complete)
{
if (TREE_CODE (value_type) == VOID_TYPE)
return result;
result = require_complete_type (result);
}
if (IS_AGGR_TYPE (value_type))
result = build_cplus_new (value_type, result);
return convert_from_reference (result);
}
}
tree
build_function_call (function, params)
tree function, params;
{
return build_function_call_real (function, params, 1, LOOKUP_NORMAL);
}
tree
convert_arguments (typelist, values, fndecl, flags)
tree typelist, values, fndecl;
int flags;
{
register tree typetail, valtail;
register tree result = NULL_TREE;
const char *called_thing = 0;
int i = 0;
flags |= LOOKUP_ONLYCONVERTING;
if (fndecl)
{
if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
{
if (DECL_NAME (fndecl) == NULL_TREE
|| IDENTIFIER_HAS_TYPE_VALUE (DECL_NAME (fndecl)))
called_thing = "constructor";
else
called_thing = "member function";
}
else
called_thing = "function";
}
for (valtail = values, typetail = typelist;
valtail;
valtail = TREE_CHAIN (valtail), i++)
{
register tree type = typetail ? TREE_VALUE (typetail) : 0;
register tree val = TREE_VALUE (valtail);
if (val == error_mark_node)
return error_mark_node;
if (type == void_type_node)
{
if (fndecl)
{
cp_error_at ("too many arguments to %s `%+#D'", called_thing,
fndecl);
error ("at this point in file");
}
else
error ("too many arguments to function");
if (result)
TREE_TYPE (tree_last (result)) = error_mark_node;
break;
}
if (TREE_CODE (val) == OFFSET_REF)
val = resolve_offset_ref (val);
if (TREE_CODE (val) == NOP_EXPR
&& TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0))
&& (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
val = TREE_OPERAND (val, 0);
if (type == 0 || TREE_CODE (type) != REFERENCE_TYPE)
{
if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
val = default_conversion (val);
}
if (val == error_mark_node)
return error_mark_node;
if (type != 0)
{
tree parmval;
if (TYPE_SIZE (complete_type (type)) == 0)
{
error ("parameter type of called function is incomplete");
parmval = val;
}
else
{
parmval = convert_for_initialization
(NULL_TREE, type, val, flags,
"argument passing", fndecl, i);
#ifdef PROMOTE_PROTOTYPES
if ((TREE_CODE (type) == INTEGER_TYPE
|| TREE_CODE (type) == ENUMERAL_TYPE)
&& (TYPE_PRECISION (type)
< TYPE_PRECISION (integer_type_node)))
parmval = default_conversion (parmval);
#endif
}
if (parmval == error_mark_node)
return error_mark_node;
result = expr_tree_cons (NULL_TREE, parmval, result);
}
else
{
if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
val = convert_from_reference (val);
result = expr_tree_cons (NULL_TREE,
convert_arg_to_ellipsis (val),
result);
}
if (typetail)
typetail = TREE_CHAIN (typetail);
}
if (typetail != 0 && typetail != void_list_node)
{
if (TREE_PURPOSE (typetail))
{
for (; typetail != void_list_node; ++i)
{
tree parmval
= convert_default_arg (TREE_VALUE (typetail),
TREE_PURPOSE (typetail),
fndecl);
if (parmval == error_mark_node)
return error_mark_node;
result = expr_tree_cons (0, parmval, result);
typetail = TREE_CHAIN (typetail);
if (typetail == NULL_TREE)
break;
}
}
else
{
if (fndecl)
{
cp_error_at ("too few arguments to %s `%+#D'",
called_thing, fndecl);
error ("at this point in file");
}
else
error ("too few arguments to function");
return error_mark_list;
}
}
return nreverse (result);
}
tree
build_x_binary_op (code, arg1, arg2)
enum tree_code code;
tree arg1, arg2;
{
if (processing_template_decl)
return build_min_nt (code, arg1, arg2);
return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
}
tree
build_binary_op (code, arg1, arg2)
enum tree_code code;
tree arg1, arg2;
{
return build_binary_op_nodefault (code, arg1, arg2, code);
}
tree
build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
enum tree_code code;
tree orig_op0, orig_op1;
enum tree_code error_code;
{
tree op0, op1;
register enum tree_code code0, code1;
tree type0, type1;
register enum tree_code resultcode = code;
register tree result_type = NULL;
int converted = 0;
tree build_type = 0;
tree final_type = 0;
int shorten = 0;
int short_compare = 0;
int short_shift = 0;
int common = 0;
if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
|| code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
|| code == TRUTH_XOR_EXPR)
{
op0 = decay_conversion (orig_op0);
op1 = decay_conversion (orig_op1);
}
else
{
op0 = default_conversion (orig_op0);
op1 = default_conversion (orig_op1);
}
STRIP_TYPE_NOPS (op0);
STRIP_TYPE_NOPS (op1);
if (type_unknown_p (op0))
{
tree t = instantiate_type (TREE_TYPE (op1), op0, 0);
if (t != error_mark_node)
{
cp_pedwarn ("assuming cast to `%T' from overloaded function",
TREE_TYPE (t));
op0 = t;
}
}
if (type_unknown_p (op1))
{
tree t = instantiate_type (TREE_TYPE (op0), op1, 0);
if (t != error_mark_node)
{
cp_pedwarn ("assuming cast to `%T' from overloaded function",
TREE_TYPE (t));
op1 = t;
}
}
type0 = TREE_TYPE (op0);
type1 = TREE_TYPE (op1);
code0 = TREE_CODE (type0);
code1 = TREE_CODE (type1);
if (code0 == ERROR_MARK || code1 == ERROR_MARK)
return error_mark_node;
switch (code)
{
case PLUS_EXPR:
if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
return pointer_int_sum (PLUS_EXPR, op0, op1);
else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
return pointer_int_sum (PLUS_EXPR, op1, op0);
else
common = 1;
break;
case MINUS_EXPR:
if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
&& comp_target_types (type0, type1, 1))
return pointer_diff (op0, op1, common_type (type0, type1));
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
return pointer_int_sum (MINUS_EXPR, op0, op1);
else
common = 1;
break;
case MULT_EXPR:
common = 1;
break;
case TRUNC_DIV_EXPR:
case CEIL_DIV_EXPR:
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == COMPLEX_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == COMPLEX_TYPE))
{
if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
cp_warning ("division by zero in `%E / 0'", op0);
else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1))
cp_warning ("division by zero in `%E / 0.'", op0);
if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
resultcode = RDIV_EXPR;
else
shorten = ((TREE_CODE (op0) == NOP_EXPR
&& TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
|| (TREE_CODE (op1) == INTEGER_CST
&& (TREE_INT_CST_LOW (op1) != -1
|| TREE_INT_CST_HIGH (op1) != -1)));
common = 1;
}
break;
case BIT_AND_EXPR:
case BIT_ANDTC_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
shorten = -1;
if (TREE_CODE (op0) == INTEGER_CST
&& TREE_CODE (op1) == NOP_EXPR
&& (TYPE_PRECISION (type1)
> TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0))))
&& TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op1, 0))))
{
final_type = result_type;
op1 = TREE_OPERAND (op1, 0);
result_type = TREE_TYPE (op1);
}
if (TREE_CODE (op1) == INTEGER_CST
&& TREE_CODE (op0) == NOP_EXPR
&& (TYPE_PRECISION (type0)
> TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0))))
&& TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
{
final_type = result_type;
op0 = TREE_OPERAND (op0, 0);
result_type = TREE_TYPE (op0);
}
break;
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
if (code1 == INTEGER_TYPE && integer_zerop (op1))
cp_warning ("division by zero in `%E %% 0'", op0);
else if (code1 == REAL_TYPE && real_zerop (op1))
cp_warning ("division by zero in `%E %% 0.'", op0);
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
shorten = ((TREE_CODE (op0) == NOP_EXPR
&& TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
|| (TREE_CODE (op1) == INTEGER_CST
&& (TREE_INT_CST_LOW (op1) != -1
|| TREE_INT_CST_HIGH (op1) != -1)));
common = 1;
}
break;
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
result_type = boolean_type_node;
break;
case RSHIFT_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_lt (op1, integer_zero_node))
warning ("right shift count is negative");
else
{
if (TREE_INT_CST_LOW (op1) | TREE_INT_CST_HIGH (op1))
short_shift = 1;
if (TREE_INT_CST_HIGH (op1) != 0
|| ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1)
>= TYPE_PRECISION (type0)))
warning ("right shift count >= width of type");
}
}
if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
op1 = cp_convert (integer_type_node, op1);
converted = 1;
}
break;
case LSHIFT_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_lt (op1, integer_zero_node))
warning ("left shift count is negative");
else if (TREE_INT_CST_HIGH (op1) != 0
|| ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1)
>= TYPE_PRECISION (type0)))
warning ("left shift count >= width of type");
}
if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
op1 = cp_convert (integer_type_node, op1);
converted = 1;
}
break;
case RROTATE_EXPR:
case LROTATE_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_lt (op1, integer_zero_node))
warning ("%s rotate count is negative",
(code == LROTATE_EXPR) ? "left" : "right");
else if (TREE_INT_CST_HIGH (op1) != 0
|| ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1)
>= TYPE_PRECISION (type0)))
warning ("%s rotate count >= width of type",
(code == LROTATE_EXPR) ? "left" : "right");
}
if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
op1 = cp_convert (integer_type_node, op1);
}
break;
case EQ_EXPR:
case NE_EXPR:
build_type = boolean_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == COMPLEX_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == COMPLEX_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
register tree tt0 = TYPE_MAIN_VARIANT (TREE_TYPE (type0));
register tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (type1));
if (comp_target_types (type0, type1, 1))
result_type = common_type (type0, type1);
else if (tt0 == void_type_node)
{
if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE
&& tree_int_cst_lt (TYPE_SIZE (type0), TYPE_SIZE (type1)))
pedwarn ("ANSI C++ forbids comparison of `void *' with function pointer");
else if (TREE_CODE (tt1) == OFFSET_TYPE)
pedwarn ("ANSI C++ forbids conversion of a pointer to member to `void *'");
}
else if (tt1 == void_type_node)
{
if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE
&& tree_int_cst_lt (TYPE_SIZE (type1), TYPE_SIZE (type0)))
pedwarn ("ANSI C++ forbids comparison of `void *' with function pointer");
}
else
#ifdef OBJCPLUS
{
if (maybe_objc_comptypes (tt0, tt1, 1) != 1)
cp_pedwarn ("comparison of distinct object pointer types");
}
#else
cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
type0, type1);
#endif
if (result_type == NULL_TREE)
result_type = ptr_type_node;
}
else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
&& integer_zerop (op1))
result_type = type0;
else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
&& integer_zerop (op0))
result_type = type1;
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
error ("ANSI C++ forbids comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
error ("ANSI C++ forbids comparison between pointer and integer");
}
else if (TYPE_PTRMEMFUNC_P (type0) && TREE_CODE (op1) == INTEGER_CST
&& integer_zerop (op1))
{
op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
op1 = integer_zero_node;
result_type = TREE_TYPE (op0);
}
else if (TYPE_PTRMEMFUNC_P (type1) && TREE_CODE (op0) == INTEGER_CST
&& integer_zerop (op0))
{
op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0);
op1 = integer_zero_node;
result_type = TREE_TYPE (op0);
}
else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
&& same_type_p (type0, type1))
{
tree index0 = build_component_ref (op0, index_identifier,
NULL_TREE, 0);
tree index1 = save_expr (build_component_ref (op1, index_identifier,
NULL_TREE, 0));
tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
tree pfn1 = PFN_FROM_PTRMEMFUNC (op1);
tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
tree delta21 = DELTA2_FROM_PTRMEMFUNC (op1);
tree e1, e2, e3;
tree integer_neg_one_node
= build_binary_op (MINUS_EXPR, integer_zero_node,
integer_one_node);
e1 = build_binary_op (EQ_EXPR, index0, index1);
e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node);
e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
build_binary_op (EQ_EXPR, delta20, delta21));
e3 = build (EQ_EXPR, boolean_type_node, pfn0, pfn1);
e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3);
e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
if (code == EQ_EXPR)
return e2;
return build_binary_op (EQ_EXPR, e2, integer_zero_node);
}
else if (TYPE_PTRMEMFUNC_P (type0)
&& same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type0), type1))
{
tree index0 = build_component_ref (op0, index_identifier,
NULL_TREE, 0);
tree index1;
tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
tree delta21 = integer_zero_node;
tree e1, e2, e3;
tree integer_neg_one_node
= build_binary_op (MINUS_EXPR, integer_zero_node, integer_one_node);
if (TREE_CODE (TREE_OPERAND (op1, 0)) == FUNCTION_DECL
&& DECL_VINDEX (TREE_OPERAND (op1, 0)))
{
index1 = size_binop (PLUS_EXPR,
DECL_VINDEX (TREE_OPERAND (op1, 0)),
integer_one_node);
op1 = integer_zero_node;
delta21 = CLASSTYPE_VFIELD (TYPE_METHOD_BASETYPE
(TREE_TYPE (type1)));
delta21 = DECL_FIELD_BITPOS (delta21);
delta21 = size_binop (FLOOR_DIV_EXPR, delta21,
size_int (BITS_PER_UNIT));
delta21 = convert (sizetype, delta21);
}
else
index1 = integer_neg_one_node;
{
tree nop1 = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type0),
op1);
TREE_CONSTANT (nop1) = TREE_CONSTANT (op1);
op1 = nop1;
}
e1 = build_binary_op (EQ_EXPR, index0, index1);
e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node);
e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
build_binary_op (EQ_EXPR, delta20, delta21));
e3 = build (EQ_EXPR, boolean_type_node, pfn0, op1);
e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3);
e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
if (code == EQ_EXPR)
return e2;
return build_binary_op (EQ_EXPR, e2, integer_zero_node);
}
else if (TYPE_PTRMEMFUNC_P (type1)
&& same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type1), type0))
return build_binary_op (code, op1, op0);
break;
case MAX_EXPR:
case MIN_EXPR:
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
shorten = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
if (comp_target_types (type0, type1, 1))
result_type = common_type (type0, type1);
else
{
cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
type0, type1);
result_type = ptr_type_node;
}
}
break;
case LE_EXPR:
case GE_EXPR:
case LT_EXPR:
case GT_EXPR:
build_type = boolean_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
if (comp_target_types (type0, type1, 1))
result_type = common_type (type0, type1);
else
{
cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
type0, type1);
result_type = ptr_type_node;
}
}
else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
&& integer_zerop (op1))
result_type = type0;
else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
&& integer_zerop (op0))
result_type = type1;
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
pedwarn ("ANSI C++ forbids comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
pedwarn ("ANSI C++ forbids comparison between pointer and integer");
}
break;
default:
break;
}
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
&&
(code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
{
int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
if (shorten || common || short_compare)
result_type = common_type (type0, type1);
if (shorten && none_complex)
{
int unsigned0, unsigned1;
tree arg0 = get_narrower (op0, &unsigned0);
tree arg1 = get_narrower (op1, &unsigned1);
int uns = TREE_UNSIGNED (result_type);
tree type;
final_type = result_type;
if (op0 == arg0 && TREE_TYPE (op0) != final_type)
unsigned0 = TREE_UNSIGNED (TREE_TYPE (op0));
if (op1 == arg1 && TREE_TYPE (op1) != final_type)
unsigned1 = TREE_UNSIGNED (TREE_TYPE (op1));
if (shorten == -1)
uns = unsigned0;
if ((TYPE_PRECISION (TREE_TYPE (arg0))
< TYPE_PRECISION (result_type))
&& (TYPE_PRECISION (TREE_TYPE (arg1))
== TYPE_PRECISION (TREE_TYPE (arg0)))
&& unsigned0 == unsigned1
&& (unsigned0 || !uns))
result_type
= signed_or_unsigned_type (unsigned0,
common_type (TREE_TYPE (arg0),
TREE_TYPE (arg1)));
else if (TREE_CODE (arg0) == INTEGER_CST
&& (unsigned1 || !uns)
&& (TYPE_PRECISION (TREE_TYPE (arg1))
< TYPE_PRECISION (result_type))
&& (type = signed_or_unsigned_type (unsigned1,
TREE_TYPE (arg1)),
int_fits_type_p (arg0, type)))
result_type = type;
else if (TREE_CODE (arg1) == INTEGER_CST
&& (unsigned0 || !uns)
&& (TYPE_PRECISION (TREE_TYPE (arg0))
< TYPE_PRECISION (result_type))
&& (type = signed_or_unsigned_type (unsigned0,
TREE_TYPE (arg0)),
int_fits_type_p (arg1, type)))
result_type = type;
}
if (short_shift)
{
int unsigned_arg;
tree arg0 = get_narrower (op0, &unsigned_arg);
final_type = result_type;
if (arg0 == op0 && final_type == TREE_TYPE (op0))
unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0));
if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
&& TREE_INT_CST_HIGH (op1) == 0
&& TYPE_PRECISION (TREE_TYPE (arg0)) > TREE_INT_CST_LOW (op1)
&& (!TREE_UNSIGNED (final_type)
|| unsigned_arg
|| (((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0)))
<= TYPE_PRECISION (result_type))))
{
result_type
= signed_or_unsigned_type (unsigned_arg,
TREE_TYPE (arg0));
if (TREE_TYPE (op0) != result_type)
op0 = cp_convert (result_type, op0);
converted = 1;
}
}
if (short_compare)
{
tree xop0 = op0, xop1 = op1, xresult_type = result_type;
enum tree_code xresultcode = resultcode;
tree val
= shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
if (val != 0)
return cp_convert (boolean_type_node, val);
op0 = xop0, op1 = xop1;
converted = 1;
resultcode = xresultcode;
}
if (short_compare && warn_sign_compare)
{
int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
int unsignedp0, unsignedp1;
tree primop0 = get_narrower (op0, &unsignedp0);
tree primop1 = get_narrower (op1, &unsignedp1);
if (TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE
&& TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE
&& TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
!= TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
{
cp_warning ("comparison between `%#T' and `%#T'",
TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
}
if (! TREE_UNSIGNED (result_type))
;
else if (op0_signed == op1_signed)
;
else if ((op0_signed && TREE_CODE (orig_op0) == INTEGER_CST
&& tree_int_cst_sgn (orig_op0) >= 0)
|| (op1_signed && TREE_CODE (orig_op1) == INTEGER_CST
&& tree_int_cst_sgn (orig_op1) >= 0))
;
else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR)
&& ((op0_signed && TREE_CODE (orig_op1) == INTEGER_CST
&& int_fits_type_p (orig_op1,
signed_type (result_type)))
|| (op1_signed && TREE_CODE (orig_op0) == INTEGER_CST
&& int_fits_type_p (orig_op0,
signed_type (result_type)))))
;
else
warning ("comparison between signed and unsigned");
if ((TREE_CODE (primop0) == BIT_NOT_EXPR)
^ (TREE_CODE (primop1) == BIT_NOT_EXPR))
{
if (TREE_CODE (primop0) == BIT_NOT_EXPR)
primop0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
if (TREE_CODE (primop1) == BIT_NOT_EXPR)
primop1 = get_narrower (TREE_OPERAND (op1, 0), &unsignedp1);
if (TREE_CODE (primop0) == INTEGER_CST
|| TREE_CODE (primop1) == INTEGER_CST)
{
tree primop;
HOST_WIDE_INT constant, mask;
int unsignedp;
unsigned bits;
if (TREE_CODE (primop0) == INTEGER_CST)
{
primop = primop1;
unsignedp = unsignedp1;
constant = TREE_INT_CST_LOW (primop0);
}
else
{
primop = primop0;
unsignedp = unsignedp0;
constant = TREE_INT_CST_LOW (primop1);
}
bits = TYPE_PRECISION (TREE_TYPE (primop));
if (bits < TYPE_PRECISION (result_type)
&& bits < HOST_BITS_PER_LONG && unsignedp)
{
mask = (~ (HOST_WIDE_INT) 0) << bits;
if ((mask & constant) != mask)
warning ("comparison of promoted ~unsigned with constant");
}
}
else if (unsignedp0 && unsignedp1
&& (TYPE_PRECISION (TREE_TYPE (primop0))
< TYPE_PRECISION (result_type))
&& (TYPE_PRECISION (TREE_TYPE (primop1))
< TYPE_PRECISION (result_type)))
warning ("comparison of promoted ~unsigned with unsigned");
}
}
}
if (!result_type)
{
cp_error ("invalid operands `%T' and `%T' to binary `%O'",
TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), error_code);
return error_mark_node;
}
if (
!(code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
&& (
(orig_op0 == null_node
&& TREE_CODE (TREE_TYPE (op1)) != POINTER_TYPE)
|| (orig_op1 == null_node
&& TREE_CODE (TREE_TYPE (op0)) != POINTER_TYPE)
|| (orig_op0 == null_node && orig_op1 == null_node
&& code != EQ_EXPR && code != NE_EXPR)))
cp_warning ("NULL used in arithmetic");
if (! converted)
{
if (TREE_TYPE (op0) != result_type)
op0 = cp_convert (result_type, op0);
if (TREE_TYPE (op1) != result_type)
op1 = cp_convert (result_type, op1);
if (op0 == error_mark_node || op1 == error_mark_node)
return error_mark_node;
}
if (build_type == NULL_TREE)
build_type = result_type;
{
register tree result = build (resultcode, build_type, op0, op1);
register tree folded;
folded = fold (result);
if (folded == result)
TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
if (final_type != 0)
return cp_convert (final_type, folded);
return folded;
}
}
static tree
pointer_int_sum (resultcode, ptrop, intop)
enum tree_code resultcode;
register tree ptrop, intop;
{
tree size_exp;
register tree result;
register tree folded = fold (intop);
register tree result_type = TREE_TYPE (ptrop);
if (!complete_type_or_else (result_type, ptrop))
return error_mark_node;
if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
{
if (pedantic || warn_pointer_arith)
pedwarn ("ANSI C++ forbids using pointer of type `void *' in arithmetic");
size_exp = integer_one_node;
}
else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
{
if (pedantic || warn_pointer_arith)
pedwarn ("ANSI C++ forbids using pointer to a function in arithmetic");
size_exp = integer_one_node;
}
else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
{
if (pedantic || warn_pointer_arith)
pedwarn ("ANSI C++ forbids using pointer to a method in arithmetic");
size_exp = integer_one_node;
}
else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
{
if (pedantic || warn_pointer_arith)
pedwarn ("ANSI C++ forbids using pointer to a member in arithmetic");
size_exp = integer_one_node;
}
else
size_exp = size_in_bytes (complete_type (TREE_TYPE (result_type)));
intop = folded;
if (TREE_CODE (intop) == INTEGER_CST
&& TREE_INT_CST_LOW (intop) == 0
&& TREE_INT_CST_HIGH (intop) == 0)
return ptrop;
if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
&& ! TREE_CONSTANT (intop)
&& TREE_CONSTANT (TREE_OPERAND (intop, 1))
&& TREE_CONSTANT (size_exp))
{
enum tree_code subcode = resultcode;
if (TREE_CODE (intop) == MINUS_EXPR)
subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
ptrop = build_binary_op (subcode, ptrop, TREE_OPERAND (intop, 1));
intop = TREE_OPERAND (intop, 0);
}
if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype))
intop = cp_convert (type_for_size (TYPE_PRECISION (sizetype), 0), intop);
intop = cp_convert (result_type,
build_binary_op (MULT_EXPR, intop,
cp_convert (TREE_TYPE (intop),
size_exp)));
result = build (resultcode, result_type, ptrop, intop);
folded = fold (result);
if (folded == result)
TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
return folded;
}
static tree
pointer_diff (op0, op1, ptrtype)
register tree op0, op1;
register tree ptrtype;
{
register tree result, folded;
tree restype = ptrdiff_type_node;
tree target_type = TREE_TYPE (ptrtype);
if (!complete_type_or_else (target_type, NULL_TREE))
return error_mark_node;
if (pedantic || warn_pointer_arith)
{
if (TREE_CODE (target_type) == VOID_TYPE)
pedwarn ("ANSI C++ forbids using pointer of type `void *' in subtraction");
if (TREE_CODE (target_type) == FUNCTION_TYPE)
pedwarn ("ANSI C++ forbids using pointer to a function in subtraction");
if (TREE_CODE (target_type) == METHOD_TYPE)
pedwarn ("ANSI C++ forbids using pointer to a method in subtraction");
if (TREE_CODE (target_type) == OFFSET_TYPE)
pedwarn ("ANSI C++ forbids using pointer to a member in subtraction");
}
op0 = build_binary_op (MINUS_EXPR, cp_convert (restype, op0),
cp_convert (restype, op1));
if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0)
error ("arithmetic on pointer to an incomplete type");
op1 = ((TREE_CODE (target_type) == VOID_TYPE
|| TREE_CODE (target_type) == FUNCTION_TYPE
|| TREE_CODE (target_type) == METHOD_TYPE
|| TREE_CODE (target_type) == OFFSET_TYPE)
? integer_one_node
: size_in_bytes (target_type));
result = build (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
folded = fold (result);
if (folded == result)
TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
return folded;
}
static tree
build_component_addr (arg, argtype)
tree arg, argtype;
{
tree field = TREE_OPERAND (arg, 1);
tree basetype = decl_type_context (field);
tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
my_friendly_assert (TREE_CODE (field) == FIELD_DECL, 981018);
if (DECL_C_BIT_FIELD (field))
{
cp_error ("attempt to take address of bit-field structure member `%D'",
field);
return error_mark_node;
}
if (TREE_CODE (field) == FIELD_DECL
&& TYPE_USES_COMPLEX_INHERITANCE (basetype))
{
rval = build1 (NOP_EXPR, argtype,
convert_pointer_to (basetype, rval));
TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
}
else
rval = convert_force (argtype, rval, 0);
if (! integer_zerop (DECL_FIELD_BITPOS (field)))
{
tree offset = size_binop (EASY_DIV_EXPR, DECL_FIELD_BITPOS (field),
size_int (BITS_PER_UNIT));
int flag = TREE_CONSTANT (rval);
offset = convert (sizetype, offset);
rval = fold (build (PLUS_EXPR, argtype,
rval, cp_convert (argtype, offset)));
TREE_CONSTANT (rval) = flag;
}
return rval;
}
tree
build_x_unary_op (code, xarg)
enum tree_code code;
tree xarg;
{
if (processing_template_decl)
return build_min_nt (code, xarg, NULL_TREE);
if (code == ADDR_EXPR
&& TREE_CODE (xarg) != TEMPLATE_ID_EXPR
&& ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
&& TYPE_SIZE (TREE_TYPE (xarg)) == NULL_TREE)
|| (TREE_CODE (xarg) == OFFSET_REF)))
;
else
{
tree rval;
rval = build_new_op (code, LOOKUP_NORMAL, xarg,
NULL_TREE, NULL_TREE);
if (rval || code != ADDR_EXPR)
return rval;
}
if (code == ADDR_EXPR)
{
if (TREE_CODE (xarg) == TARGET_EXPR)
warning ("taking address of temporary");
}
return build_unary_op (code, xarg, 0);
}
tree
condition_conversion (expr)
tree expr;
{
tree t;
if (processing_template_decl)
return expr;
t = cp_convert (boolean_type_node, expr);
t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
return t;
}
tree
build_unary_op (code, xarg, noconvert)
enum tree_code code;
tree xarg;
int noconvert;
{
register tree arg = xarg;
register tree argtype = 0;
const char *errstring = NULL;
tree val;
if (arg == error_mark_node)
return error_mark_node;
switch (code)
{
case CONVERT_EXPR:
if (!(arg = build_expr_type_conversion
(WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, 1)))
errstring = "wrong type argument to unary plus";
else
{
if (!noconvert)
arg = default_conversion (arg);
arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
}
break;
case NEGATE_EXPR:
if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
errstring = "wrong type argument to unary minus";
else if (!noconvert)
arg = default_conversion (arg);
break;
case BIT_NOT_EXPR:
if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
{
code = CONJ_EXPR;
if (!noconvert)
arg = default_conversion (arg);
}
else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM,
arg, 1)))
errstring = "wrong type argument to bit-complement";
else if (!noconvert)
arg = default_conversion (arg);
break;
case ABS_EXPR:
if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
errstring = "wrong type argument to abs";
else if (!noconvert)
arg = default_conversion (arg);
break;
case CONJ_EXPR:
if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
errstring = "wrong type argument to conjugation";
else if (!noconvert)
arg = default_conversion (arg);
break;
case TRUTH_NOT_EXPR:
arg = cp_convert (boolean_type_node, arg);
val = invert_truthvalue (arg);
if (arg != error_mark_node)
return val;
errstring = "in argument to unary !";
break;
case NOP_EXPR:
break;
case REALPART_EXPR:
if (TREE_CODE (arg) == COMPLEX_CST)
return TREE_REALPART (arg);
else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
else
return arg;
case IMAGPART_EXPR:
if (TREE_CODE (arg) == COMPLEX_CST)
return TREE_IMAGPART (arg);
else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
else
return cp_convert (TREE_TYPE (arg), integer_zero_node);
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
case POSTDECREMENT_EXPR:
val = unary_complex_lvalue (code, arg);
if (val != 0)
return val;
if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
{
tree real, imag;
arg = stabilize_reference (arg);
real = build_unary_op (REALPART_EXPR, arg, 1);
imag = build_unary_op (IMAGPART_EXPR, arg, 1);
return build (COMPLEX_EXPR, TREE_TYPE (arg),
build_unary_op (code, real, 1), imag);
}
if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
arg, 1)))
{
if (code == PREINCREMENT_EXPR)
errstring ="no pre-increment operator for type";
else if (code == POSTINCREMENT_EXPR)
errstring ="no post-increment operator for type";
else if (code == PREDECREMENT_EXPR)
errstring ="no pre-decrement operator for type";
else
errstring ="no post-decrement operator for type";
break;
}
if (CP_TYPE_CONST_P (TREE_TYPE (arg))
|| TREE_READONLY (arg))
readonly_error (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"),
0);
{
register tree inc;
tree result_type = TREE_TYPE (arg);
arg = get_unwidened (arg, 0);
argtype = TREE_TYPE (arg);
if (TREE_CODE (argtype) == ENUMERAL_TYPE)
pedwarn ("ANSI C++ forbids %sing an enum",
(code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
? "increment" : "decrement");
if (TREE_CODE (argtype) == POINTER_TYPE)
{
enum tree_code tmp = TREE_CODE (TREE_TYPE (argtype));
if (TYPE_SIZE (complete_type (TREE_TYPE (argtype))) == 0)
cp_error ("cannot %s a pointer to incomplete type `%T'",
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"), TREE_TYPE (argtype));
else if ((pedantic || warn_pointer_arith)
&& (tmp == FUNCTION_TYPE || tmp == METHOD_TYPE
|| tmp == VOID_TYPE || tmp == OFFSET_TYPE))
cp_pedwarn ("ANSI C++ forbids %sing a pointer of type `%T'",
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"), argtype);
inc = c_sizeof_nowarn (TREE_TYPE (argtype));
}
else
inc = integer_one_node;
inc = cp_convert (argtype, inc);
switch (TREE_CODE (arg))
{
case NOP_EXPR:
case CONVERT_EXPR:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
{
tree incremented, modify, value, compound;
if (! lvalue_p (arg) && pedantic)
pedwarn ("cast to non-reference type used as lvalue");
arg = stabilize_reference (arg);
if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
value = arg;
else
value = save_expr (arg);
incremented = build (((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? PLUS_EXPR : MINUS_EXPR),
argtype, value, inc);
TREE_SIDE_EFFECTS (incremented) = 1;
modify = build_modify_expr (arg, NOP_EXPR, incremented);
compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
TREE_NO_UNUSED_WARNING (compound) = 1;
return compound;
}
default:
break;
}
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement")))
return error_mark_node;
if (TREE_TYPE (arg) == boolean_type_node)
{
if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
{
cp_error ("invalid use of `--' on bool variable `%D'", arg);
return error_mark_node;
}
#if 0
val = build (code, TREE_TYPE (arg), arg, inc);
#else
if (code == POSTINCREMENT_EXPR)
{
arg = stabilize_reference (arg);
val = build (MODIFY_EXPR, TREE_TYPE (arg), arg,
boolean_true_node);
TREE_SIDE_EFFECTS (val) = 1;
arg = save_expr (arg);
val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
}
else
val = build (MODIFY_EXPR, TREE_TYPE (arg), arg,
boolean_true_node);
#endif
}
else
val = build (code, TREE_TYPE (arg), arg, inc);
TREE_SIDE_EFFECTS (val) = 1;
return cp_convert (result_type, val);
}
case ADDR_EXPR:
argtype = lvalue_type (arg);
if (TREE_CODE (argtype) == REFERENCE_TYPE)
{
arg = build1
(CONVERT_EXPR,
build_pointer_type (TREE_TYPE (argtype)), arg);
TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
return arg;
}
else if (pedantic && DECL_MAIN_P (arg))
pedwarn ("taking address of function `main'");
if (TREE_CODE (arg) == INDIRECT_REF)
{
if (arg == current_class_ref)
return current_class_ptr;
arg = TREE_OPERAND (arg, 0);
if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
{
arg = build1
(CONVERT_EXPR,
build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
}
else if (lvalue_p (arg))
return non_lvalue (arg);
return arg;
}
if (TREE_CODE (arg) == ARRAY_REF)
{
if (mark_addressable (TREE_OPERAND (arg, 0)) == 0)
return error_mark_node;
return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
TREE_OPERAND (arg, 1));
}
if (TREE_CODE (arg) == IDENTIFIER_NODE
&& IDENTIFIER_OPNAME_P (arg))
{
my_friendly_abort (117);
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
&& OVL_NEXT (TREE_OPERAND (arg, 1)) == NULL_TREE)
{
tree base, name;
if (current_class_type
&& TREE_OPERAND (arg, 0) == current_class_ref)
pedwarn ("taking the address of a non-static member function");
else
pedwarn ("taking the address of a bound member function");
base = TREE_TYPE (TREE_OPERAND (arg, 0));
name = DECL_NAME (OVL_CURRENT (TREE_OPERAND (arg, 1)));
cp_pedwarn (" to form a pointer to member function, say `&%T::%D'",
base, name);
arg = build_offset_ref (base, name);
}
if (type_unknown_p (arg))
return build1 (ADDR_EXPR, unknown_type_node, arg);
val = unary_complex_lvalue (code, arg);
if (val != 0)
return val;
switch (TREE_CODE (arg))
{
case NOP_EXPR:
case CONVERT_EXPR:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
if (! lvalue_p (arg) && pedantic)
pedwarn ("taking the address of a cast to non-reference type");
break;
default:
break;
}
if (TREE_CODE (arg) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (arg)
&& TREE_CONSTANT (arg))
;
else if (TREE_CODE (argtype) != FUNCTION_TYPE
&& TREE_CODE (argtype) != METHOD_TYPE
&& !lvalue_or_else (arg, "unary `&'"))
return error_mark_node;
if (argtype != error_mark_node)
argtype = build_pointer_type (argtype);
if (mark_addressable (arg) == 0)
return error_mark_node;
{
tree addr;
if (TREE_CODE (arg) == COMPONENT_REF)
addr = build_component_addr (arg, argtype);
else
addr = build1 (ADDR_EXPR, argtype, arg);
if (staticp (arg))
TREE_CONSTANT (addr) = 1;
if (TREE_CODE (argtype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
{
build_ptrmemfunc_type (argtype);
addr = build_ptrmemfunc (argtype, addr, 0);
}
return addr;
}
default:
break;
}
if (!errstring)
{
if (argtype == 0)
argtype = TREE_TYPE (arg);
return fold (build1 (code, argtype, arg));
}
error (errstring);
return error_mark_node;
}
#if 0
static tree
convert_sequence (conversions, arg)
tree conversions;
tree arg;
{
switch (TREE_CODE (conversions))
{
case NOP_EXPR:
case CONVERT_EXPR:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
return cp_convert (TREE_TYPE (conversions),
convert_sequence (TREE_OPERAND (conversions, 0),
arg));
default:
return arg;
}
}
#endif
tree
unary_complex_lvalue (code, arg)
enum tree_code code;
tree arg;
{
if (TREE_CODE (arg) == COMPOUND_EXPR)
{
tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0);
return build (COMPOUND_EXPR, TREE_TYPE (real_result),
TREE_OPERAND (arg, 0), real_result);
}
if (TREE_CODE (arg) == COND_EXPR
|| TREE_CODE (arg) == MIN_EXPR || TREE_CODE (arg) == MAX_EXPR)
return rationalize_conditional_expr (code, arg);
if (TREE_CODE (arg) == MODIFY_EXPR
|| TREE_CODE (arg) == PREINCREMENT_EXPR
|| TREE_CODE (arg) == PREDECREMENT_EXPR)
return unary_complex_lvalue
(code, build (COMPOUND_EXPR, TREE_TYPE (TREE_OPERAND (arg, 0)),
arg, TREE_OPERAND (arg, 0)));
if (code != ADDR_EXPR)
return 0;
if (TREE_CODE (arg) == MODIFY_EXPR
|| TREE_CODE (arg) == INIT_EXPR)
{
tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
arg = build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
TREE_NO_UNUSED_WARNING (arg) = 1;
return arg;
}
if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE
|| TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
{
tree t;
my_friendly_assert (TREE_CODE (arg) != SCOPE_REF, 313);
if (TREE_CODE (arg) != OFFSET_REF)
return 0;
t = TREE_OPERAND (arg, 1);
if (TREE_CODE (t) == FUNCTION_DECL)
{
if (DECL_DESTRUCTOR_P (t))
cp_error ("taking address of destructor");
return build_unary_op (ADDR_EXPR, t, 0);
}
if (TREE_CODE (t) == VAR_DECL)
return build_unary_op (ADDR_EXPR, t, 0);
else
{
tree type;
if (TREE_OPERAND (arg, 0)
&& ! is_dummy_object (TREE_OPERAND (arg, 0))
&& TREE_CODE (t) != FIELD_DECL)
{
cp_error ("taking address of bound pointer-to-member expression");
return error_mark_node;
}
type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
type = build_pointer_type (type);
t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
return t;
}
}
{
tree targ = arg;
if (TREE_CODE (targ) == SAVE_EXPR)
targ = TREE_OPERAND (targ, 0);
if (TREE_CODE (targ) == CALL_EXPR && IS_AGGR_TYPE (TREE_TYPE (targ)))
{
if (TREE_CODE (arg) == SAVE_EXPR)
targ = arg;
else
targ = build_cplus_new (TREE_TYPE (arg), arg);
return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (arg)), targ);
}
if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == INDIRECT_REF)
return build (SAVE_EXPR, build_pointer_type (TREE_TYPE (arg)),
TREE_OPERAND (targ, 0), current_function_decl, NULL);
}
return 0;
}
int
mark_addressable (exp)
tree exp;
{
register tree x = exp;
if (TREE_ADDRESSABLE (x) == 1)
return 1;
while (1)
switch (TREE_CODE (x))
{
case ADDR_EXPR:
case COMPONENT_REF:
case ARRAY_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
x = TREE_OPERAND (x, 0);
break;
case PARM_DECL:
if (x == current_class_ptr)
{
if (! flag_this_is_variable)
error ("address of `this' not available");
TREE_ADDRESSABLE (x) = 1;
put_var_into_stack (x);
return 1;
}
case VAR_DECL:
if (TREE_STATIC (x) && TREE_READONLY (x)
&& DECL_RTL (x) != 0
&& ! DECL_IN_MEMORY_P (x))
{
push_obstacks_nochange ();
end_temporary_allocation ();
TREE_ASM_WRITTEN (x) = 0;
DECL_RTL (x) = 0;
rest_of_decl_compilation (x, 0,
!DECL_FUNCTION_SCOPE_P (x),
0);
TREE_ADDRESSABLE (x) = 1;
pop_obstacks ();
return 1;
}
my_friendly_assert (DECL_LANG_SPECIFIC (x) == 0
|| DECL_IN_AGGR_P (x) == 0
|| TREE_STATIC (x)
|| DECL_EXTERNAL (x), 314);
case CONST_DECL:
case RESULT_DECL:
if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
&& !DECL_ARTIFICIAL (x) && extra_warnings)
cp_warning ("address requested for `%D', which is declared `register'",
x);
put_var_into_stack (x);
TREE_ADDRESSABLE (x) = 1;
return 1;
case FUNCTION_DECL:
if (DECL_LANG_SPECIFIC (x) != 0)
{
x = DECL_MAIN_VARIANT (x);
if (DECL_TEMPLATE_INFO (x) && !DECL_TEMPLATE_SPECIALIZATION (x))
mark_used (x);
}
TREE_ADDRESSABLE (x) = 1;
TREE_USED (x) = 1;
TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
return 1;
case CONSTRUCTOR:
TREE_ADDRESSABLE (x) = 1;
return 1;
case TARGET_EXPR:
TREE_ADDRESSABLE (x) = 1;
mark_addressable (TREE_OPERAND (x, 0));
return 1;
default:
return 1;
}
}
tree
build_x_conditional_expr (ifexp, op1, op2)
tree ifexp, op1, op2;
{
if (processing_template_decl)
return build_min_nt (COND_EXPR, ifexp, op1, op2);
return build_new_op (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
}
tree
build_conditional_expr (ifexp, op1, op2)
tree ifexp, op1, op2;
{
register tree type1;
register tree type2;
register enum tree_code code1;
register enum tree_code code2;
register tree result_type = NULL_TREE;
if (op1 == 0)
{
if (pedantic)
pedwarn ("ANSI C++ forbids omitting the middle term of a ?: expression");
ifexp = op1 = save_expr (ifexp);
}
type1 = TREE_TYPE (op1);
code1 = TREE_CODE (type1);
type2 = TREE_TYPE (op2);
code2 = TREE_CODE (type2);
if (op1 == error_mark_node || op2 == error_mark_node
|| type1 == error_mark_node || type2 == error_mark_node)
return error_mark_node;
ifexp = cp_convert (boolean_type_node, ifexp);
if (TREE_CODE (ifexp) == ERROR_MARK)
return error_mark_node;
if (code1 == REFERENCE_TYPE)
{
op1 = convert_from_reference (op1);
type1 = TREE_TYPE (op1);
code1 = TREE_CODE (type1);
}
if (code2 == REFERENCE_TYPE)
{
op2 = convert_from_reference (op2);
type2 = TREE_TYPE (op2);
code2 = TREE_CODE (type2);
}
if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
&& code2 != ARRAY_TYPE
&& code2 != FUNCTION_TYPE
&& code2 != METHOD_TYPE)
{
tree result;
if (TREE_CONSTANT (ifexp)
&& (TREE_CODE (ifexp) == INTEGER_CST
|| TREE_CODE (ifexp) == ADDR_EXPR))
return (integer_zerop (ifexp) ? op2 : op1);
if (TREE_CODE (op1) == CONST_DECL)
op1 = DECL_INITIAL (op1);
else if (TREE_READONLY_DECL_P (op1))
op1 = decl_constant_value (op1);
if (TREE_CODE (op2) == CONST_DECL)
op2 = DECL_INITIAL (op2);
else if (TREE_READONLY_DECL_P (op2))
op2 = decl_constant_value (op2);
if (type1 != type2)
type1 = cp_build_qualified_type
(type1, (CP_TYPE_QUALS (TREE_TYPE (op1))
| CP_TYPE_QUALS (TREE_TYPE (op2))));
result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
if (TREE_TYPE (result) != type1)
result = build1 (NOP_EXPR, type1, result);
if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR)
{
tree slot = build (VAR_DECL, TREE_TYPE (result));
layout_decl (slot, 0);
result = build (TARGET_EXPR, TREE_TYPE (result),
slot, result, NULL_TREE, NULL_TREE);
}
return result;
}
if (code1 == ENUMERAL_TYPE)
{
if (code2 == ENUMERAL_TYPE)
{
cp_error ("enumeral mismatch in conditional expression: `%T' vs `%T'",
type1, type2);
return error_mark_node;
}
else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2)
&& type2 != type_promotes_to (type1))
warning ("enumeral and non-enumeral type in conditional expression");
}
else if (extra_warnings
&& code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1)
&& type1 != type_promotes_to (type2))
warning ("enumeral and non-enumeral type in conditional expression");
if (code1 != VOID_TYPE)
{
op1 = default_conversion (op1);
type1 = TREE_TYPE (op1);
if (TYPE_PTRMEMFUNC_P (type1))
type1 = TYPE_PTRMEMFUNC_FN_TYPE (type1);
code1 = TREE_CODE (type1);
}
if (code2 != VOID_TYPE)
{
op2 = default_conversion (op2);
type2 = TREE_TYPE (op2);
if (TYPE_PTRMEMFUNC_P (type2))
type2 = TYPE_PTRMEMFUNC_FN_TYPE (type2);
code2 = TREE_CODE (type2);
}
if (code1 == RECORD_TYPE && code2 == RECORD_TYPE
&& real_lvalue_p (op1) && real_lvalue_p (op2)
&& comptypes (type1, type2, COMPARE_BASE | COMPARE_RELAXED))
{
type1 = build_reference_type (type1);
type2 = build_reference_type (type2);
result_type = common_type (type1, type2);
op1 = convert_to_reference (result_type, op1, CONV_IMPLICIT,
LOOKUP_NORMAL, NULL_TREE);
op2 = convert_to_reference (result_type, op2, CONV_IMPLICIT,
LOOKUP_NORMAL, NULL_TREE);
}
else if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
{
if (type1 == type2)
result_type = type1;
else
result_type =
cp_build_qualified_type (type1,
CP_TYPE_QUALS (TREE_TYPE (op1))
| CP_TYPE_QUALS (TREE_TYPE (op2)));
}
else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE)
&& (code2 == INTEGER_TYPE || code2 == REAL_TYPE))
{
result_type = common_type (type1, type2);
}
else if (code1 == VOID_TYPE || code2 == VOID_TYPE)
{
if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE))
pedwarn ("ANSI C++ forbids conditional expr with only one void side");
result_type = void_type_node;
}
else if (code1 == POINTER_TYPE && null_ptr_cst_p (op2))
result_type = qualify_type (type1, type2);
else if (code2 == POINTER_TYPE && null_ptr_cst_p (op1))
result_type = qualify_type (type2, type1);
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
if (comp_target_types (type1, type2, 1))
result_type = common_type (type1, type2);
else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
{
if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer");
result_type = qualify_type (type1, type2);
}
else if (TYPE_MAIN_VARIANT (TREE_TYPE (type2)) == void_type_node)
{
if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer");
result_type = qualify_type (type2, type1);
}
else if (same_or_base_type_p (type2, type1))
result_type = type2;
else if (IS_AGGR_TYPE (TREE_TYPE (type1))
&& IS_AGGR_TYPE (TREE_TYPE (type2))
&& (result_type = common_base_type (TREE_TYPE (type1),
TREE_TYPE (type2))))
{
if (result_type == error_mark_node)
{
cp_error ("common base type of types `%T' and `%T' is ambiguous",
TREE_TYPE (type1), TREE_TYPE (type2));
result_type = ptr_type_node;
}
else
{
if (pedantic
&& result_type != TREE_TYPE (type1)
&& result_type != TREE_TYPE (type2))
cp_pedwarn ("`%T' and `%T' converted to `%T *' in conditional expression",
type1, type2, result_type);
result_type = build_pointer_type (result_type);
}
}
else
{
pedwarn ("pointer type mismatch in conditional expression");
result_type = ptr_type_node;
}
}
else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
{
pedwarn ("pointer/integer type mismatch in conditional expression");
result_type = type1;
}
else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
pedwarn ("pointer/integer type mismatch in conditional expression");
result_type = type2;
}
if (type2 == unknown_type_node)
result_type = type1;
else if (type1 == unknown_type_node)
result_type = type2;
if (!result_type)
{
if (code1 == RECORD_TYPE && code2 == RECORD_TYPE)
{
cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'",
type1, type2);
return error_mark_node;
}
if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
{
tree tmp;
if (code2 == POINTER_TYPE)
tmp = build_pointer_type
(cp_build_qualified_type (TREE_TYPE (type2),
TYPE_QUAL_CONST
| TYPE_QUAL_VOLATILE
| TYPE_QUAL_RESTRICT));
else
tmp = type2;
tmp = build_type_conversion (tmp, op1, 0);
if (tmp == NULL_TREE)
{
cp_error ("incompatible types `%T' and `%T' in `?:'",
type1, type2);
return error_mark_node;
}
if (tmp == error_mark_node)
error ("ambiguous pointer conversion");
else
STRIP_NOPS (tmp);
result_type = common_type (type2, TREE_TYPE (tmp));
op1 = tmp;
}
else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
{
tree tmp;
if (code1 == POINTER_TYPE)
tmp = build_pointer_type
(cp_build_qualified_type (TREE_TYPE (type1),
TYPE_QUAL_CONST
| TYPE_QUAL_VOLATILE
| TYPE_QUAL_RESTRICT));
else
tmp = type1;
tmp = build_type_conversion (tmp, op2, 0);
if (tmp == NULL_TREE)
{
cp_error ("incompatible types `%T' and `%T' in `?:'",
type1, type2);
return error_mark_node;
}
if (tmp == error_mark_node)
error ("ambiguous pointer conversion");
else
STRIP_NOPS (tmp);
result_type = common_type (type1, TREE_TYPE (tmp));
op2 = tmp;
}
else if (flag_cond_mismatch)
result_type = void_type_node;
else
{
error ("type mismatch in conditional expression");
return error_mark_node;
}
}
if (TREE_CODE (result_type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
result_type = build_ptrmemfunc_type (result_type);
if (result_type != TREE_TYPE (op1))
op1 = convert_for_initialization
(NULL_TREE, result_type, op1, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
if (result_type != TREE_TYPE (op2))
op2 = convert_for_initialization
(NULL_TREE, result_type, op2, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
if (TREE_CODE (ifexp) == INTEGER_CST)
return integer_zerop (ifexp) ? op2 : op1;
return convert_from_reference
(fold (build (COND_EXPR, result_type, ifexp, op1, op2)));
}
tree
build_x_compound_expr (list)
tree list;
{
tree rest = TREE_CHAIN (list);
tree result;
if (processing_template_decl)
return build_min_nt (COMPOUND_EXPR, list, NULL_TREE);
if (rest == NULL_TREE)
return build_compound_expr (list);
result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
if (result)
return build_x_compound_expr (expr_tree_cons (NULL_TREE, result,
TREE_CHAIN (rest)));
if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
{
if ((extra_warnings || warn_unused)
&& !(TREE_CODE (TREE_VALUE(list)) == CONVERT_EXPR
&& TREE_TYPE (TREE_VALUE(list)) == void_type_node))
warning("left-hand operand of comma expression has no effect");
}
#if 0
else if (warn_unused)
warn_if_unused_value (TREE_VALUE(list));
#endif
return build_compound_expr
(expr_tree_cons (NULL_TREE, TREE_VALUE (list),
build_expr_list (NULL_TREE,
build_x_compound_expr (rest))));
}
tree
build_compound_expr (list)
tree list;
{
register tree rest;
tree first;
if (TREE_READONLY_DECL_P (TREE_VALUE (list)))
TREE_VALUE (list) = decl_constant_value (TREE_VALUE (list));
if (TREE_CHAIN (list) == 0)
{
if (TREE_CODE (list) == NOP_EXPR
&& TREE_TYPE (list) == TREE_TYPE (TREE_OPERAND (list, 0)))
list = TREE_OPERAND (list, 0);
if (TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE)
return default_conversion (TREE_VALUE (list));
else
return TREE_VALUE (list);
}
first = TREE_VALUE (list);
first = require_complete_type_in_void (first);
if (first == error_mark_node)
return error_mark_node;
rest = build_compound_expr (TREE_CHAIN (list));
if (rest == error_mark_node)
return error_mark_node;
if (! TREE_SIDE_EFFECTS (first) && ! pedantic)
return rest;
return build (COMPOUND_EXPR, TREE_TYPE (rest),
break_out_cleanups (first), rest);
}
tree
build_static_cast (type, expr)
tree type, expr;
{
tree intype, binfo;
int ok;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (TREE_CODE (expr) == OFFSET_REF)
expr = resolve_offset_ref (expr);
if (processing_template_decl)
{
tree t = build_min (STATIC_CAST_EXPR, copy_to_permanent (type),
expr);
return t;
}
if (TREE_CODE (type) != REFERENCE_TYPE
&& TREE_CODE (expr) == NOP_EXPR
&& TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
expr = TREE_OPERAND (expr, 0);
if (TREE_CODE (type) == VOID_TYPE)
return build1 (CONVERT_EXPR, type, expr);
if (TREE_CODE (type) == REFERENCE_TYPE)
return (convert_from_reference
(convert_to_reference (type, expr, CONV_STATIC|CONV_IMPLICIT,
LOOKUP_COMPLAIN, NULL_TREE)));
if (IS_AGGR_TYPE (type))
return build_cplus_new
(type, (build_method_call
(NULL_TREE, ctor_identifier, build_expr_list (NULL_TREE, expr),
TYPE_BINFO (type), LOOKUP_NORMAL)));
expr = decay_conversion (expr);
intype = TREE_TYPE (expr);
ok = 0;
if (can_convert_arg (type, intype, expr))
ok = 1;
else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
{
tree binfo;
if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
&& at_least_as_qualified_p (TREE_TYPE (type),
TREE_TYPE (intype))
&& (binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 0))
&& ! TREE_VIA_VIRTUAL (binfo))
ok = 1;
}
else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
{
if (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))),
TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (intype))))
&& at_least_as_qualified_p (TREE_TYPE (TREE_TYPE (type)),
TREE_TYPE (TREE_TYPE (intype)))
&& (binfo = get_binfo (TYPE_OFFSET_BASETYPE (TREE_TYPE (type)),
TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)), 0))
&& ! TREE_VIA_VIRTUAL (binfo))
ok = 1;
}
else if (TREE_CODE (intype) != BOOLEAN_TYPE
&& TREE_CODE (type) != ARRAY_TYPE
&& TREE_CODE (type) != FUNCTION_TYPE
&& can_convert (intype, type))
ok = 1;
if (ok)
return build_c_cast (type, expr);
cp_error ("static_cast from `%T' to `%T'", intype, type);
return error_mark_node;
}
tree
build_reinterpret_cast (type, expr)
tree type, expr;
{
tree intype;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (TREE_CODE (expr) == OFFSET_REF)
expr = resolve_offset_ref (expr);
if (processing_template_decl)
{
tree t = build_min (REINTERPRET_CAST_EXPR,
copy_to_permanent (type), expr);
return t;
}
if (TREE_CODE (type) != REFERENCE_TYPE)
{
expr = decay_conversion (expr);
if (TREE_CODE (expr) == NOP_EXPR
&& TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
expr = TREE_OPERAND (expr, 0);
}
intype = TREE_TYPE (expr);
if (TREE_CODE (type) == REFERENCE_TYPE)
{
if (! real_lvalue_p (expr))
{
cp_error ("reinterpret_cast from `%T' rvalue to `%T'", intype, type);
return error_mark_node;
}
expr = build_unary_op (ADDR_EXPR, expr, 0);
if (expr != error_mark_node)
expr = build_reinterpret_cast
(build_pointer_type (TREE_TYPE (type)), expr);
if (expr != error_mark_node)
expr = build_indirect_ref (expr, 0);
return expr;
}
else if (same_type_p (TYPE_MAIN_VARIANT (intype),
TYPE_MAIN_VARIANT (type)))
return build_static_cast (type, expr);
if (TYPE_PTR_P (type) && (TREE_CODE (intype) == INTEGER_TYPE
|| TREE_CODE (intype) == ENUMERAL_TYPE))
;
else if (TREE_CODE (type) == INTEGER_TYPE && TYPE_PTR_P (intype))
{
if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
cp_pedwarn ("reinterpret_cast from `%T' to `%T' loses precision",
intype, type);
}
else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
{
if (TREE_READONLY_DECL_P (expr))
expr = decl_constant_value (expr);
return fold (build1 (NOP_EXPR, type, expr));
}
else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|| (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
{
if (! comp_ptr_ttypes_reinterpret (TREE_TYPE (type), TREE_TYPE (intype)))
cp_pedwarn ("reinterpret_cast from `%T' to `%T' casts away const (or volatile)",
intype, type);
if (TREE_READONLY_DECL_P (expr))
expr = decl_constant_value (expr);
return fold (build1 (NOP_EXPR, type, expr));
}
else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
|| (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
{
pedwarn ("ANSI C++ forbids casting between pointers to functions and objects");
if (TREE_READONLY_DECL_P (expr))
expr = decl_constant_value (expr);
return fold (build1 (NOP_EXPR, type, expr));
}
else
{
cp_error ("reinterpret_cast from `%T' to `%T'", intype, type);
return error_mark_node;
}
return cp_convert (type, expr);
}
tree
build_const_cast (type, expr)
tree type, expr;
{
tree intype;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (TREE_CODE (expr) == OFFSET_REF)
expr = resolve_offset_ref (expr);
if (processing_template_decl)
{
tree t = build_min (CONST_CAST_EXPR, copy_to_permanent (type),
expr);
return t;
}
if (!POINTER_TYPE_P (type))
{
cp_error ("`%T' is not a pointer, reference, or pointer-to-data-member type",
type);
cp_error ("as required by const_cast");
}
else if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
{
cp_error ("`%T' is a pointer or reference to a function type",
type);
cp_error ("which is forbidden by const_cast");
return error_mark_node;
}
if (TREE_CODE (type) != REFERENCE_TYPE)
{
expr = decay_conversion (expr);
if (TREE_CODE (expr) == NOP_EXPR
&& TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
expr = TREE_OPERAND (expr, 0);
}
intype = TREE_TYPE (expr);
if (same_type_p (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type)))
return build_static_cast (type, expr);
else if (TREE_CODE (type) == REFERENCE_TYPE)
{
if (! real_lvalue_p (expr))
{
cp_error ("const_cast from `%T' rvalue to `%T'", intype, type);
return error_mark_node;
}
if (comp_ptr_ttypes_const (TREE_TYPE (type), intype))
{
expr = build_unary_op (ADDR_EXPR, expr, 0);
expr = build1 (NOP_EXPR, type, expr);
return convert_from_reference (expr);
}
}
else if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (intype) == POINTER_TYPE
&& comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
return cp_convert (type, expr);
cp_error ("const_cast from `%T' to `%T'", intype, type);
return error_mark_node;
}
tree
build_c_cast (type, expr)
tree type, expr;
{
register tree value = expr;
tree otype;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (TREE_CODE (type) != REFERENCE_TYPE
&& TREE_CODE (value) == NOP_EXPR
&& TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0)))
value = TREE_OPERAND (value, 0);
if (TREE_CODE (value) == OFFSET_REF)
value = resolve_offset_ref (value);
if (TREE_CODE (type) == ARRAY_TYPE)
{
if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
{
if (pedantic)
pedwarn ("ANSI C++ forbids casting to an array type");
type = build_pointer_type (TREE_TYPE (type));
}
else
{
error ("ANSI C++ forbids casting to an array type");
return error_mark_node;
}
}
if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
{
cp_error ("casting to function type `%T'", type);
return error_mark_node;
}
if (IS_SIGNATURE (type))
{
error ("cast specifies signature type");
return error_mark_node;
}
if (processing_template_decl)
{
tree t = build_min (CAST_EXPR, type,
min_tree_cons (NULL_TREE, value, NULL_TREE));
return t;
}
if (!IS_AGGR_TYPE (type))
{
if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
|| (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
&& ! (TREE_CODE (type) == POINTER_TYPE
&& bound_pmf_p (value)))
|| TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
value = default_conversion (value);
}
else if (TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
value = convert_from_reference (value);
otype = TREE_TYPE (value);
if (warn_cast_qual
&& TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& !at_least_as_qualified_p (TREE_TYPE (type),
TREE_TYPE (otype)))
cp_warning ("cast discards qualifiers from pointer target type");
if (STRICT_ALIGNMENT && warn_cast_align
&& TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
&& TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
&& TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
warning ("cast increases required alignment of target type");
#if 0
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype))
warning ("cast from pointer to integer of different size");
if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == INTEGER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype)
&& !(TREE_CODE (value) == INTEGER_CST && integer_zerop (value)))
warning ("cast to pointer from integer of different size");
#endif
if (TREE_CODE (type) == VOID_TYPE)
{
value = require_complete_type_in_void (value);
if (value != error_mark_node)
value = build1 (CONVERT_EXPR, void_type_node, value);
}
else if (TREE_CODE (type) == REFERENCE_TYPE)
value = (convert_from_reference
(convert_to_reference (type, value, CONV_C_CAST,
LOOKUP_COMPLAIN, NULL_TREE)));
else
{
tree ovalue;
if (TREE_READONLY_DECL_P (value))
value = decl_constant_value (value);
ovalue = value;
value = convert_force (type, value, CONV_C_CAST);
if (TREE_CODE (value) == INTEGER_CST)
{
TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
}
}
if (TREE_CODE (type) != REFERENCE_TYPE && value == expr
&& real_lvalue_p (value))
value = non_lvalue (value);
return value;
}
tree
build_modify_expr (lhs, modifycode, rhs)
tree lhs;
enum tree_code modifycode;
tree rhs;
{
register tree result;
tree newrhs = rhs;
tree lhstype = TREE_TYPE (lhs);
tree olhstype = lhstype;
tree olhs = lhs;
if (lhs == error_mark_node || rhs == error_mark_node)
return error_mark_node;
lhs = require_complete_type (lhs);
newrhs = rhs;
if (TYPE_LANG_SPECIFIC (lhstype)
&& (IS_SIGNATURE_POINTER (lhstype) || IS_SIGNATURE_REFERENCE (lhstype)))
{
return build_signature_pointer_constructor (lhs, rhs);
}
switch (TREE_CODE (lhs))
{
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
lhs = build (TREE_CODE (lhs), TREE_TYPE (lhs),
stabilize_reference (TREE_OPERAND (lhs, 0)),
TREE_OPERAND (lhs, 1));
return build (COMPOUND_EXPR, lhstype,
lhs,
build_modify_expr (TREE_OPERAND (lhs, 0),
modifycode, rhs));
case COMPOUND_EXPR:
newrhs = build_modify_expr (TREE_OPERAND (lhs, 1),
modifycode, rhs);
if (newrhs == error_mark_node)
return error_mark_node;
return build (COMPOUND_EXPR, lhstype,
TREE_OPERAND (lhs, 0), newrhs);
case MODIFY_EXPR:
newrhs = build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs);
if (newrhs == error_mark_node)
return error_mark_node;
return build (COMPOUND_EXPR, lhstype, lhs, newrhs);
case COND_EXPR:
rhs = save_expr (rhs);
{
tree cond
= build_conditional_expr (TREE_OPERAND (lhs, 0),
build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
modifycode, rhs),
build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
modifycode, rhs));
if (cond == error_mark_node)
return cond;
return build (COMPOUND_EXPR, TREE_TYPE (lhs),
cp_convert (void_type_node, rhs), cond);
}
default:
break;
}
if (TREE_CODE (lhs) == OFFSET_REF)
{
if (TREE_OPERAND (lhs, 0) == NULL_TREE)
{
tree member = TREE_OPERAND (lhs, 1);
if (TREE_CODE (member) == VAR_DECL)
lhs = member;
else
{
compiler_error ("invalid static class member");
return error_mark_node;
}
}
else
lhs = resolve_offset_ref (lhs);
olhstype = lhstype = TREE_TYPE (lhs);
}
if (lhs == error_mark_node)
return lhs;
if (TREE_CODE (lhstype) == REFERENCE_TYPE
&& modifycode != INIT_EXPR)
{
lhs = convert_from_reference (lhs);
olhstype = lhstype = TREE_TYPE (lhs);
}
if (modifycode == INIT_EXPR)
{
if (! IS_AGGR_TYPE (lhstype))
;
else
{
result = build_method_call (lhs, ctor_identifier,
build_expr_list (NULL_TREE, rhs),
TYPE_BINFO (lhstype), LOOKUP_NORMAL);
if (result == NULL_TREE)
return error_mark_node;
return result;
}
}
else if (modifycode == NOP_EXPR)
{
if (! IS_AGGR_TYPE (lhstype))
;
else
{
result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
lhs, rhs, make_node (NOP_EXPR));
if (result == NULL_TREE)
return error_mark_node;
return result;
}
lhstype = olhstype;
}
else if (PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE))
{
my_friendly_abort (978652);
}
else
{
lhs = stabilize_reference (lhs);
newrhs = build_binary_op (modifycode, lhs, rhs);
if (newrhs == error_mark_node)
{
cp_error (" in evaluation of `%Q(%#T, %#T)'", modifycode,
TREE_TYPE (lhs), TREE_TYPE (rhs));
return error_mark_node;
}
}
switch (TREE_CODE (lhs))
{
case NOP_EXPR:
case CONVERT_EXPR:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE
|| TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE)
newrhs = default_conversion (newrhs);
{
tree inner_lhs = TREE_OPERAND (lhs, 0);
tree result;
if (! lvalue_p (lhs))
pedwarn ("ANSI C++ forbids cast to non-reference type used as lvalue");
result = build_modify_expr (inner_lhs, NOP_EXPR,
cp_convert (TREE_TYPE (inner_lhs),
cp_convert (lhstype, newrhs)));
if (result == error_mark_node)
return result;
return cp_convert (TREE_TYPE (lhs), result);
}
default:
break;
}
if (!lvalue_or_else (lhs, "assignment"))
return error_mark_node;
GNU_xref_assign (lhs);
if (modifycode != INIT_EXPR
&& ! (TREE_CODE (lhs) == COMPONENT_REF
&& (IS_SIGNATURE_POINTER (TREE_TYPE (TREE_OPERAND (lhs, 0)))
|| IS_SIGNATURE_REFERENCE (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
&& (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)
|| TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE
|| ((TREE_CODE (lhstype) == RECORD_TYPE
|| TREE_CODE (lhstype) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (lhstype))
|| (TREE_CODE (lhstype) == REFERENCE_TYPE
&& CP_TYPE_CONST_P (TREE_TYPE (lhstype)))))
readonly_error (lhs, "assignment", 0);
if (TREE_CODE (lhs) == COMPONENT_REF
&& (TREE_CODE (lhstype) == INTEGER_TYPE
|| TREE_CODE (lhstype) == REAL_TYPE
|| TREE_CODE (lhstype) == ENUMERAL_TYPE))
{
lhstype = TREE_TYPE (get_unwidened (lhs, 0));
if (lhstype != TREE_TYPE (lhs))
{
lhs = copy_node (lhs);
TREE_TYPE (lhs) = lhstype;
}
}
if (lhs == current_class_ptr)
{
if (flag_this_is_variable > 0
&& DECL_NAME (current_function_decl) != NULL_TREE
&& (DECL_NAME (current_function_decl)
!= constructor_name (current_class_type)))
warning ("assignment to `this' not in constructor or destructor");
current_function_just_assigned_this = 1;
}
if (modifycode != INIT_EXPR)
{
modifycode = NOP_EXPR;
if (TREE_CODE (lhstype) == REFERENCE_TYPE)
{
tree tmp = convert_from_reference (lhs);
lhstype = TREE_TYPE (tmp);
if (TYPE_SIZE (lhstype) == 0)
{
incomplete_type_error (lhs, lhstype);
return error_mark_node;
}
lhs = tmp;
olhstype = lhstype;
}
if (TREE_CODE (TREE_TYPE (newrhs)) == REFERENCE_TYPE)
{
tree tmp = convert_from_reference (newrhs);
if (TYPE_SIZE (TREE_TYPE (tmp)) == 0)
{
incomplete_type_error (newrhs, TREE_TYPE (tmp));
return error_mark_node;
}
newrhs = tmp;
}
}
if (TREE_SIDE_EFFECTS (lhs))
lhs = stabilize_reference (lhs);
if (TREE_SIDE_EFFECTS (newrhs))
newrhs = stabilize_reference (newrhs);
if (TREE_CODE (lhstype) == ARRAY_TYPE)
{
int from_array;
if (!same_or_base_type_p (lhstype, TREE_TYPE (rhs)))
{
cp_error ("incompatible types in assignment of `%T' to `%T'",
TREE_TYPE (rhs), lhstype);
return error_mark_node;
}
if (pedantic && ! DECL_ARTIFICIAL (current_function_decl))
pedwarn ("ANSI C++ forbids assignment of arrays");
result = make_node (RTL_EXPR);
TREE_TYPE (result) = void_type_node;
do_pending_stack_adjust ();
start_sequence_for_rtl_expr (result);
emit_note (0, -1);
from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
? 1 + (modifycode != INIT_EXPR): 0;
expand_vec_init (lhs, lhs, array_type_nelts (lhstype), newrhs,
from_array);
do_pending_stack_adjust ();
TREE_SIDE_EFFECTS (result) = 1;
RTL_EXPR_SEQUENCE (result) = get_insns ();
RTL_EXPR_RTL (result) = const0_rtx;
end_sequence ();
return result;
}
if (modifycode == INIT_EXPR)
{
newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
"assignment", NULL_TREE, 0);
if (lhs == DECL_RESULT (current_function_decl))
{
if (DECL_INITIAL (lhs))
warning ("return value from function receives multiple initializations");
DECL_INITIAL (lhs) = newrhs;
}
}
else
{
if (TREE_CODE (olhstype) == ENUMERAL_TYPE
&& TREE_CODE (lhstype) == INTEGER_TYPE)
{
newrhs = convert_for_assignment (olhstype, newrhs, "assignment",
NULL_TREE, 0);
newrhs = convert_force (lhstype, newrhs, 0);
}
else
newrhs = convert_for_assignment (lhstype, newrhs, "assignment",
NULL_TREE, 0);
if (TREE_CODE (newrhs) == CALL_EXPR
&& TYPE_NEEDS_CONSTRUCTING (lhstype))
newrhs = build_cplus_new (lhstype, newrhs);
if (TREE_CODE (newrhs) == TARGET_EXPR)
newrhs = build (COMPOUND_EXPR, TREE_TYPE (newrhs), newrhs,
TREE_OPERAND (newrhs, 0));
}
if (newrhs == error_mark_node)
return error_mark_node;
if (TREE_CODE (newrhs) == COND_EXPR)
{
tree lhs1;
tree cond = TREE_OPERAND (newrhs, 0);
if (TREE_SIDE_EFFECTS (lhs))
cond = build_compound_expr (tree_cons
(NULL_TREE, lhs,
build_expr_list (NULL_TREE, cond)));
lhs1 = break_out_calls (lhs);
if (lhs == lhs1)
result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
lhstype, lhs, newrhs);
else
{
tree result_type = TREE_TYPE (newrhs);
result
= build (COND_EXPR, result_type, cond,
build_modify_expr (lhs, modifycode,
cp_convert (result_type,
TREE_OPERAND (newrhs, 1))),
build_modify_expr (lhs1, modifycode,
cp_convert (result_type,
TREE_OPERAND (newrhs, 2))));
}
}
else
result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
lhstype, lhs, newrhs);
TREE_SIDE_EFFECTS (result) = 1;
if (olhstype == TREE_TYPE (result))
return result;
if (TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
&& TREE_CODE (olhstype) == ENUMERAL_TYPE)
{
result = build (COMPOUND_EXPR, olhstype, result, olhs);
TREE_NO_UNUSED_WARNING (result) = 1;
return result;
}
return convert_for_assignment (olhstype, result, "assignment",
NULL_TREE, 0);
}
tree
build_x_modify_expr (lhs, modifycode, rhs)
tree lhs;
enum tree_code modifycode;
tree rhs;
{
if (processing_template_decl)
return build_min_nt (MODOP_EXPR, lhs,
build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
if (modifycode != NOP_EXPR)
{
tree rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
make_node (modifycode));
if (rval)
return rval;
}
return build_modify_expr (lhs, modifycode, rhs);
}
static tree
get_delta_difference (from, to, force)
tree from, to;
int force;
{
tree delta = integer_zero_node;
tree binfo;
if (to == from)
return delta;
binfo = get_binfo (from, to, 1);
if (binfo == error_mark_node)
{
error (" in pointer to member function conversion");
return delta;
}
if (binfo == 0)
{
if (!force)
{
error_not_base_type (from, to);
error (" in pointer to member conversion");
return delta;
}
binfo = get_binfo (to, from, 1);
if (binfo == 0 || binfo == error_mark_node)
return delta;
if (TREE_VIA_VIRTUAL (binfo))
{
binfo = binfo_member (BINFO_TYPE (binfo),
CLASSTYPE_VBASECLASSES (from));
cp_warning ("pointer to member cast to virtual base `%T'",
BINFO_TYPE (binfo));
warning (" will only work if you are very careful");
}
delta = BINFO_OFFSET (binfo);
delta = cp_convert (ptrdiff_type_node, delta);
return build_binary_op (MINUS_EXPR,
integer_zero_node,
delta);
}
if (TREE_VIA_VIRTUAL (binfo))
{
if (force)
{
cp_warning ("pointer to member cast from virtual base `%T'",
BINFO_TYPE (binfo));
warning (" will only work if you are very careful");
}
else
cp_error ("pointer to member conversion from virtual base `%T'",
BINFO_TYPE (binfo));
}
return BINFO_OFFSET (binfo);
}
tree
build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
tree type, delta, idx, pfn, delta2;
{
tree u;
#if 0
if (pfn)
{
u = build_nt (CONSTRUCTOR, NULL_TREE,
expr_tree_cons (pfn_identifier, pfn, NULL_TREE));
}
else
{
u = build_nt (CONSTRUCTOR, NULL_TREE,
expr_tree_cons (delta2_identifier, delta2, NULL_TREE));
}
u = build_nt (CONSTRUCTOR, NULL_TREE,
expr_tree_cons (NULL_TREE, delta,
expr_tree_cons (NULL_TREE, idx,
expr_tree_cons (NULL_TREE, u, NULL_TREE))));
return digest_init (type, u, (tree*)0);
#else
tree delta_field, idx_field, pfn_or_delta2_field, pfn_field, delta2_field;
tree subtype;
int allconstant, allsimple;
delta_field = TYPE_FIELDS (type);
idx_field = TREE_CHAIN (delta_field);
pfn_or_delta2_field = TREE_CHAIN (idx_field);
subtype = TREE_TYPE (pfn_or_delta2_field);
pfn_field = TYPE_FIELDS (subtype);
delta2_field = TREE_CHAIN (pfn_field);
if (pfn)
{
allconstant = TREE_CONSTANT (pfn);
allsimple = !! initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
u = expr_tree_cons (pfn_field, pfn, NULL_TREE);
}
else
{
delta2 = convert_and_check (delta_type_node, delta2);
allconstant = TREE_CONSTANT (delta2);
allsimple = !! initializer_constant_valid_p (delta2, TREE_TYPE (delta2));
u = expr_tree_cons (delta2_field, delta2, NULL_TREE);
}
delta = convert_and_check (delta_type_node, delta);
idx = convert_and_check (delta_type_node, idx);
allconstant = allconstant && TREE_CONSTANT (delta) && TREE_CONSTANT (idx);
allsimple = allsimple
&& initializer_constant_valid_p (delta, TREE_TYPE (delta))
&& initializer_constant_valid_p (idx, TREE_TYPE (idx));
u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
u = expr_tree_cons (delta_field, delta,
expr_tree_cons (idx_field, idx,
expr_tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
u = build (CONSTRUCTOR, type, NULL_TREE, u);
TREE_CONSTANT (u) = allconstant;
TREE_STATIC (u) = allconstant && allsimple;
return u;
#endif
}
tree
build_ptrmemfunc (type, pfn, force)
tree type, pfn;
int force;
{
tree fn;
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
{
tree idx = integer_zero_node;
tree delta = integer_zero_node;
tree delta2 = integer_zero_node;
tree npfn = NULL_TREE;
tree ndelta, ndelta2;
tree e1, e2, e3, n;
tree pfn_type;
if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
return pfn;
pfn_type = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn));
if (!force
&& comp_target_types (type, pfn_type, 1) != 1)
cp_error ("conversion to `%T' from `%T'", type, pfn_type);
if (TREE_CODE (pfn) == PTRMEM_CST)
{
expand_ptrmemfunc_cst (pfn, &ndelta, &idx, &npfn, &ndelta2);
if (npfn)
ndelta2 = integer_zero_node;
}
else
{
ndelta = cp_convert (ptrdiff_type_node,
build_component_ref (pfn,
delta_identifier,
NULL_TREE, 0));
ndelta2 = cp_convert (ptrdiff_type_node,
DELTA2_FROM_PTRMEMFUNC (pfn));
idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0);
}
n = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (pfn_type)),
TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
force);
delta = build_binary_op (PLUS_EXPR, ndelta, n);
delta2 = build_binary_op (PLUS_EXPR, ndelta2, n);
e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node));
e2 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx,
NULL_TREE, delta2);
pfn = PFN_FROM_PTRMEMFUNC (pfn);
npfn = build1 (NOP_EXPR, type, pfn);
TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
e3 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta,
idx, npfn, NULL_TREE);
return build_conditional_expr (e1, e2, e3);
}
if (integer_zerop (pfn))
{
pfn = build_c_cast (type, integer_zero_node);
return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type),
integer_zero_node, integer_zero_node,
pfn, NULL_TREE);
}
if (type_unknown_p (pfn))
return instantiate_type (type, pfn, 1);
fn = TREE_OPERAND (pfn, 0);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
return make_ptrmem_cst (build_ptrmemfunc_type (type), fn);
}
void
expand_ptrmemfunc_cst (cst, delta, idx, pfn, delta2)
tree cst;
tree *delta;
tree *idx;
tree *pfn;
tree *delta2;
{
tree type = TREE_TYPE (cst);
tree fn = PTRMEM_CST_MEMBER (cst);
tree ptr_class, fn_class;
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
fn_class = DECL_CLASS_CONTEXT (fn);
ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
*delta = get_delta_difference (fn_class, ptr_class, 0);
if (!DECL_VIRTUAL_P (fn))
{
*idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
*pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
*delta2 = NULL_TREE;
}
else
{
tree orig_class = DECL_VIRTUAL_CONTEXT (fn);
tree binfo = binfo_or_else (orig_class, fn_class);
*delta = size_binop (PLUS_EXPR, *delta, BINFO_OFFSET (binfo));
*idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), integer_one_node);
*pfn = NULL_TREE;
*delta2 = size_binop (PLUS_EXPR, *delta,
get_vfield_offset (TYPE_BINFO (orig_class)));
}
}
tree
delta2_from_ptrmemfunc (t)
tree t;
{
if (TREE_CODE (t) == PTRMEM_CST)
{
tree delta;
tree idx;
tree pfn;
tree delta2;
expand_ptrmemfunc_cst (t, &delta, &idx, &pfn, &delta2);
if (delta2)
return delta2;
}
return (build_component_ref
(build_component_ref (t,
pfn_or_delta2_identifier, NULL_TREE,
0),
delta2_identifier, NULL_TREE, 0));
}
tree
pfn_from_ptrmemfunc (t)
tree t;
{
if (TREE_CODE (t) == PTRMEM_CST)
{
tree delta;
tree idx;
tree pfn;
tree delta2;
expand_ptrmemfunc_cst (t, &delta, &idx, &pfn, &delta2);
if (pfn)
return pfn;
}
return (build_component_ref
(build_component_ref (t,
pfn_or_delta2_identifier, NULL_TREE,
0),
pfn_identifier, NULL_TREE, 0));
}
static tree
convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
tree type, rhs;
const char *errtype;
tree fndecl;
int parmnum;
{
register enum tree_code codel = TREE_CODE (type);
register tree rhstype;
register enum tree_code coder;
if (codel == OFFSET_TYPE)
my_friendly_abort (990505);
if (TREE_CODE (rhs) == OFFSET_REF)
rhs = resolve_offset_ref (rhs);
if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
rhs = TREE_OPERAND (rhs, 0);
if (rhs == error_mark_node || TREE_TYPE (rhs) == error_mark_node)
return error_mark_node;
if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)
return error_mark_node;
if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
|| is_overloaded_fn (rhs))
rhs = default_conversion (rhs);
else if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
rhs = convert_from_reference (rhs);
if (type_unknown_p (rhs))
return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
rhstype = TREE_TYPE (rhs);
coder = TREE_CODE (rhstype);
if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
cp_warning ("converting NULL to non-pointer type");
if (TREE_CODE (rhs) == CONST_DECL)
rhs = DECL_INITIAL (rhs);
else if (TREE_READONLY_DECL_P (rhs))
rhs = decl_constant_value (rhs);
if (same_type_p (type, rhstype))
{
overflow_warning (rhs);
return rhs;
}
#ifdef OBJCPLUS
if (maybe_objc_comptypes (type, rhstype, 0) == 1)
return rhs;
#endif
if (coder == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
return error_mark_node;
}
if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE
|| codel == COMPLEX_TYPE)
&& (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE
|| coder == COMPLEX_TYPE))
{
if (coder == REAL_TYPE && codel == INTEGER_TYPE)
{
if (fndecl)
cp_warning ("`%T' used for argument %P of `%D'",
rhstype, parmnum, fndecl);
else
cp_warning ("%s to `%T' from `%T'", errtype, type, rhstype);
}
else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE)
{
if (TREE_CODE (rhs) == INTEGER_CST
&& TREE_NEGATED_INT (rhs))
{
if (fndecl)
cp_warning ("negative value `%E' passed as argument %P of `%D'",
rhs, parmnum, fndecl);
else
cp_warning ("%s of negative value `%E' to `%T'",
errtype, rhs, type);
}
overflow_warning (rhs);
if (TREE_CONSTANT (rhs))
rhs = fold (rhs);
}
return convert_and_check (type, rhs);
}
else if ((codel == ENUMERAL_TYPE
&& (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE))
|| (coder == ENUMERAL_TYPE
&& (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE)))
{
return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
}
else if (codel == POINTER_TYPE
&& (coder == POINTER_TYPE
|| (coder == RECORD_TYPE
&& (IS_SIGNATURE_POINTER (rhstype)
|| IS_SIGNATURE_REFERENCE (rhstype)))))
{
register tree ttl = TREE_TYPE (type);
register tree ttr;
int ctt = 0;
if (coder == RECORD_TYPE)
{
rhs = build_optr_ref (rhs);
rhstype = TREE_TYPE (rhs);
}
ttr = TREE_TYPE (rhstype);
#ifdef OBJCPLUS
if (maybe_objc_comptypes (ttl, ttr, 0) == 1)
return convert (type, rhs);
#endif
if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
{
tree binfo;
if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr)
|| type == class_star_type_node
|| rhstype == class_star_type_node)
binfo = TYPE_BINFO (ttl);
else
binfo = get_binfo (ttl, ttr, 1);
if (binfo == error_mark_node)
return error_mark_node;
if (binfo == 0)
return error_not_base_type (ttl, ttr);
if (!at_least_as_qualified_p (ttl, ttr))
{
if (fndecl)
cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
rhstype, parmnum, fndecl);
else
cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
errtype, type, rhstype);
}
}
else if (TYPE_MAIN_VARIANT (ttl) == void_type_node
|| TYPE_MAIN_VARIANT (ttr) == void_type_node
|| (ctt = comp_target_types (type, rhstype, 1))
|| (unsigned_type (TYPE_MAIN_VARIANT (ttl))
== unsigned_type (TYPE_MAIN_VARIANT (ttr))))
{
if (TYPE_MAIN_VARIANT (ttl) == void_type_node
&& TREE_CODE (ttr) == OFFSET_TYPE)
{
cp_error ("no standard conversion from `%T' to `void *'", ttr);
return error_mark_node;
}
if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr))
cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
rhstype, type);
if (TYPE_MAIN_VARIANT (ttl) != void_type_node
&& TYPE_MAIN_VARIANT (ttr) == void_type_node
&& ! null_ptr_cst_p (rhs))
{
if (coder == RECORD_TYPE)
cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
type);
else
#ifdef OBJCPLUS
{
extern int doing_objc_thang;
if (!doing_objc_thang)
pedwarn ("ANSI C++ forbids implicit conversion from `void *' in %s", errtype);
}
#else
pedwarn ("ANSI C++ forbids implicit conversion from `void *' in %s",
errtype);
#endif
}
else if ((TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttr) != METHOD_TYPE)
|| (TREE_CODE (ttl) != FUNCTION_TYPE && TREE_CODE (ttl) != METHOD_TYPE))
{
if (TREE_CODE (ttl) == OFFSET_TYPE
&& binfo_member (TYPE_OFFSET_BASETYPE (ttr),
CLASSTYPE_VBASECLASSES (TYPE_OFFSET_BASETYPE (ttl))))
{
error ("%s between pointer to members converting across virtual baseclasses", errtype);
return error_mark_node;
}
else if (!at_least_as_qualified_p (ttl, ttr))
{
if (string_conv_p (type, rhs, 1))
;
else if (fndecl)
{
if (!(TREE_CODE (fndecl) == FUNCTION_DECL
&& DECL_TARGET_INTRINSIC_P (fndecl)))
cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
rhstype, parmnum, fndecl);
}
else
cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
errtype, type, rhstype);
}
else if (TREE_CODE (ttl) == TREE_CODE (ttr)
&& ! comp_target_types (type, rhstype, 1))
{
if (fndecl)
cp_warning ("passing `%T' as argument %P of `%D' changes signedness",
rhstype, parmnum, fndecl);
else
cp_pedwarn ("%s to `%T' from `%T' changes signedness",
errtype, type, rhstype);
}
}
}
else
{
int add_quals = 0;
int drops_quals = 0;
int left_const = 1;
int unsigned_parity;
int nptrs = 0;
for (; ; ttl = TREE_TYPE (ttl), ttr = TREE_TYPE (ttr))
{
nptrs -= 1;
drops_quals |= !at_least_as_qualified_p (ttl, ttr);
if (! left_const
&& !at_least_as_qualified_p (ttr, ttl))
add_quals = 1;
left_const &= TYPE_READONLY (ttl);
if (TREE_CODE (ttl) != POINTER_TYPE
|| TREE_CODE (ttr) != POINTER_TYPE)
break;
}
unsigned_parity = TREE_UNSIGNED (ttl) - TREE_UNSIGNED (ttr);
if (unsigned_parity)
{
if (TREE_UNSIGNED (ttl))
ttr = unsigned_type (ttr);
else
ttl = unsigned_type (ttl);
}
if (comp_target_types (ttl, ttr, nptrs) > 0)
{
if (add_quals)
{
if (fndecl)
cp_pedwarn ("passing `%T' as argument %P of `%D' adds cv-quals without intervening `const'",
rhstype, parmnum, fndecl);
else
cp_pedwarn ("%s to `%T' from `%T' adds cv-quals without intervening `const'",
errtype, type, rhstype);
}
if (drops_quals)
{
if (fndecl)
cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
rhstype, parmnum, fndecl);
else
cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
errtype, type, rhstype);
}
if (unsigned_parity > 0)
{
if (fndecl)
cp_pedwarn ("passing `%T' as argument %P of `%D' changes signed to unsigned",
rhstype, parmnum, fndecl);
else
cp_pedwarn ("%s to `%T' from `%T' changes signed to unsigned",
errtype, type, rhstype);
}
else if (unsigned_parity < 0)
{
if (fndecl)
cp_pedwarn ("passing `%T' as argument %P of `%D' changes unsigned to signed",
rhstype, parmnum, fndecl);
else
cp_pedwarn ("%s to `%T' from `%T' changes unsigned to signed",
errtype, type, rhstype);
}
if (TREE_CODE (ttl) == FUNCTION_TYPE
|| TREE_CODE (ttl) == METHOD_TYPE)
if (!same_or_base_type_p (ttl, ttr))
{
warning ("conflicting function types in %s:", errtype);
cp_warning ("\t`%T' != `%T'", type, rhstype);
}
}
else
{
if (fndecl)
cp_error ("passing `%T' as argument %P of `%D'",
rhstype, parmnum, fndecl);
else
cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
return error_mark_node;
}
}
return cp_convert (type, rhs);
}
else if (codel == POINTER_TYPE
&& (coder == INTEGER_TYPE
|| coder == BOOLEAN_TYPE))
{
if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs)))
{
if (fndecl)
cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast",
rhstype, parmnum, fndecl);
else
cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
errtype, type, rhstype);
}
return cp_convert (type, rhs);
}
else if (codel == INTEGER_TYPE
&& (coder == POINTER_TYPE
|| (coder == RECORD_TYPE
&& (IS_SIGNATURE_POINTER (rhstype)
|| TYPE_PTRMEMFUNC_FLAG (rhstype)
|| IS_SIGNATURE_REFERENCE (rhstype)))))
{
if (fndecl)
cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast",
rhstype, parmnum, fndecl);
else
cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
errtype, type, rhstype);
return cp_convert (type, rhs);
}
else if (codel == BOOLEAN_TYPE
&& (coder == POINTER_TYPE
|| (coder == RECORD_TYPE
&& (IS_SIGNATURE_POINTER (rhstype)
|| TYPE_PTRMEMFUNC_FLAG (rhstype)
|| IS_SIGNATURE_REFERENCE (rhstype)))))
return cp_convert (type, rhs);
else if (((coder == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (rhstype)) == METHOD_TYPE)
|| integer_zerop (rhs)
|| TYPE_PTRMEMFUNC_P (rhstype))
&& TYPE_PTRMEMFUNC_P (type))
{
tree ttl = TYPE_PTRMEMFUNC_FN_TYPE (type);
tree ttr = (TYPE_PTRMEMFUNC_P (rhstype)
? TYPE_PTRMEMFUNC_FN_TYPE (rhstype)
: rhstype);
int ctt = (TREE_CODE (rhstype) == INTEGER_TYPE ? 1
: comp_target_types (ttl, ttr, 1));
if (ctt < 0)
cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
ttr, ttl);
else if (ctt == 0)
cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr);
return build_ptrmemfunc (ttl, rhs, 0);
}
else if (codel == ERROR_MARK || coder == ERROR_MARK)
return error_mark_node;
else if (codel == REFERENCE_TYPE)
my_friendly_abort (317);
else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (rhs)))
{
tree nrhs = build1 (NOP_EXPR, type, rhs);
TREE_CONSTANT (nrhs) = TREE_CONSTANT (rhs);
return nrhs;
}
else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
return cp_convert (type, rhs);
else if (TREE_CODE (type) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
|| TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
&& TREE_TYPE (rhs)
&& TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
return cp_convert (type, rhs);
cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
return error_mark_node;
}
tree
convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
tree exp, type, rhs;
int flags;
const char *errtype;
tree fndecl;
int parmnum;
{
register enum tree_code codel = TREE_CODE (type);
register tree rhstype;
register enum tree_code coder;
if (TREE_CODE (rhs) == NOP_EXPR
&& TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0))
&& codel != REFERENCE_TYPE)
rhs = TREE_OPERAND (rhs, 0);
if (rhs == error_mark_node
|| (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node))
return error_mark_node;
if (TREE_CODE (rhs) == OFFSET_REF)
{
rhs = resolve_offset_ref (rhs);
if (rhs == error_mark_node)
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
rhs = convert_from_reference (rhs);
if ((TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
&& TREE_CODE (type) != ARRAY_TYPE
&& (TREE_CODE (type) != REFERENCE_TYPE
|| TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))
|| (TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE
&& (TREE_CODE (type) != REFERENCE_TYPE
|| TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE))
|| TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
rhs = default_conversion (rhs);
rhstype = TREE_TYPE (rhs);
coder = TREE_CODE (rhstype);
if (coder == ERROR_MARK)
return error_mark_node;
if (codel == REFERENCE_TYPE)
{
extern int warningcount, errorcount;
int savew = 0, savee = 0;
if (fndecl)
savew = warningcount, savee = errorcount;
rhs = convert_to_reference (type, rhs, CONV_IMPLICIT, flags,
exp ? exp : error_mark_node);
if (fndecl)
{
if (warningcount > savew)
cp_warning_at ("in passing argument %P of `%+D'", parmnum, fndecl);
else if (errorcount > savee)
cp_error_at ("in passing argument %P of `%+D'", parmnum, fndecl);
}
return rhs;
}
if (exp != 0)
exp = require_complete_type (exp);
if (exp == error_mark_node)
return error_mark_node;
if (TREE_CODE (rhstype) == REFERENCE_TYPE)
rhstype = TREE_TYPE (rhstype);
type = complete_type (type);
if (TYPE_LANG_SPECIFIC (type)
&& (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
return build_signature_pointer_constructor (type, rhs);
if (IS_AGGR_TYPE (type))
return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
if (type == TREE_TYPE (rhs))
{
if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
cp_warning ("converting NULL to non-pointer type");
if (TREE_READONLY_DECL_P (rhs))
rhs = decl_constant_value (rhs);
return rhs;
}
return convert_for_assignment (type, rhs, errtype, fndecl, parmnum);
}
void
c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
tree string, outputs, inputs, clobbers;
int vol;
char *filename;
int line;
{
int noutputs = list_length (outputs);
register int i;
register tree *o = (tree *) alloca (noutputs * sizeof (tree));
register tree tail;
for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
o[i] = TREE_VALUE (tail);
expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line);
for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
{
if (o[i] != TREE_VALUE (tail))
{
expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)),
const0_rtx, VOIDmode, EXPAND_NORMAL);
free_temp_slots ();
}
else
{
tree type = TREE_TYPE (o[i]);
if (CP_TYPE_CONST_P (type)
|| ((TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (type)))
readonly_error (o[i], "modification by `asm'", 1);
}
}
emit_queue ();
}
void
c_expand_return (retval)
tree retval;
{
extern struct nesting *cond_stack, *loop_stack, *case_stack;
extern tree dtor_label, ctor_label;
tree result = DECL_RESULT (current_function_decl);
tree valtype = TREE_TYPE (result);
if (TREE_THIS_VOLATILE (current_function_decl))
warning ("function declared `noreturn' has a `return' statement");
if (retval == error_mark_node)
{
current_function_returns_null = 1;
return;
}
if (processing_template_decl)
{
add_tree (build_min_nt (RETURN_STMT, retval));
return;
}
if (dtor_label)
{
if (retval)
error ("returning a value from a destructor");
expand_goto (dtor_label);
return;
}
if ((DECL_NAME (current_function_decl) == ansi_opname[(int) NEW_EXPR]
|| DECL_NAME (current_function_decl) == ansi_opname[(int) VEC_NEW_EXPR])
&& !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
&& null_ptr_cst_p (retval))
cp_warning ("operator new should throw an exception, not return NULL");
if (retval == NULL_TREE)
{
if (DECL_CONSTRUCTOR_P (current_function_decl))
retval = current_class_ptr;
else if (DECL_NAME (result) != NULL_TREE
&& TREE_CODE (valtype) != VOID_TYPE)
retval = result;
else
{
current_function_returns_null = 1;
if (valtype != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE)
{
if (DECL_NAME (DECL_RESULT (current_function_decl)) == NULL_TREE)
{
pedwarn ("`return' with no value, in function returning non-void");
current_function_returns_null = 0;
}
}
expand_null_return ();
return;
}
}
else if (DECL_CONSTRUCTOR_P (current_function_decl))
{
if (flag_this_is_variable)
error ("return from a constructor: use `this = ...' instead");
else
error ("returning a value from a constructor");
retval = current_class_ptr;
}
if (warn_ecpp
&& DECL_NAME (current_function_decl) == ansi_opname[(int) MODIFY_EXPR]
&& retval != current_class_ref)
cp_warning ("`operator=' should return a reference to `*this'");
if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
{
current_function_returns_null = 1;
if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
pedwarn ("`return' with a value, in function returning void");
expand_return (retval);
return;
}
if (retval == result
|| DECL_CONSTRUCTOR_P (current_function_decl))
;
else if (TREE_CODE (TREE_TYPE (retval)) == VOID_TYPE)
{
pedwarn ("return of void value in function returning non-void");
expand_expr_stmt (retval);
retval = 0;
}
else
{
tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
retval = convert_for_initialization
(NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
"return", NULL_TREE, 0);
retval = convert (valtype, retval);
if (retval == error_mark_node)
{
expand_null_return ();
return;
}
else if (! current_function_returns_struct
&& TREE_CODE (retval) == TARGET_EXPR
&& TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
TREE_OPERAND (retval, 0));
else if (TREE_CODE (valtype) == REFERENCE_TYPE)
{
tree whats_returned;
whats_returned = retval;
if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
{
whats_returned = TREE_OPERAND (whats_returned, 1);
if (TREE_CODE (whats_returned) == ADDR_EXPR)
whats_returned = TREE_OPERAND (whats_returned, 0);
}
while (TREE_CODE (whats_returned) == CONVERT_EXPR
|| TREE_CODE (whats_returned) == NOP_EXPR)
whats_returned = TREE_OPERAND (whats_returned, 0);
if (TREE_CODE (whats_returned) == ADDR_EXPR)
{
whats_returned = TREE_OPERAND (whats_returned, 0);
while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
|| TREE_CODE (whats_returned) == TARGET_EXPR)
{
whats_returned = TREE_OPERAND (whats_returned, 0);
warning ("returning reference to temporary");
}
}
if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned))
{
if (TEMP_NAME_P (DECL_NAME (whats_returned)))
warning ("reference to non-lvalue returned");
else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE
&& DECL_FUNCTION_SCOPE_P (whats_returned)
&& !(TREE_STATIC (whats_returned)
|| TREE_PUBLIC (whats_returned)))
cp_warning_at ("reference to local variable `%D' returned", whats_returned);
}
}
else if (TREE_CODE (retval) == ADDR_EXPR)
{
tree whats_returned = TREE_OPERAND (retval, 0);
if (TREE_CODE (whats_returned) == VAR_DECL
&& DECL_NAME (whats_returned)
&& DECL_FUNCTION_SCOPE_P (whats_returned)
&& !(TREE_STATIC (whats_returned)
|| TREE_PUBLIC (whats_returned)))
cp_warning_at ("address of local variable `%D' returned", whats_returned);
}
}
if (retval != NULL_TREE
&& TREE_CODE_CLASS (TREE_CODE (retval)) == 'd'
&& cond_stack == 0 && loop_stack == 0 && case_stack == 0)
current_function_return_value = retval;
if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
{
expand_goto (ctor_label);
}
if (retval && retval != result)
{
result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
TREE_SIDE_EFFECTS (result) = 1;
}
expand_start_target_temps ();
expand_return (result);
expand_end_target_temps ();
current_function_returns_value = 1;
}
tree
c_expand_start_case (exp)
tree exp;
{
tree type, idx;
exp = build_expr_type_conversion (WANT_INT | WANT_ENUM, exp, 1);
if (exp == NULL_TREE)
{
error ("switch quantity not an integer");
exp = error_mark_node;
}
if (exp == error_mark_node)
return error_mark_node;
exp = default_conversion (exp);
type = TREE_TYPE (exp);
idx = get_unwidened (exp, 0);
if (TREE_UNSIGNED (TREE_TYPE (exp)) == TREE_UNSIGNED (TREE_TYPE (idx)))
exp = idx;
expand_start_case
(1, fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp)),
type, "switch statement");
return exp;
}
static int
comp_ptr_ttypes_real (to, from, constp)
tree to, from;
int constp;
{
int to_more_cv_qualified = 0;
for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
{
if (TREE_CODE (to) != TREE_CODE (from))
return 0;
if (TREE_CODE (from) == OFFSET_TYPE
&& same_type_p (TYPE_OFFSET_BASETYPE (from),
TYPE_OFFSET_BASETYPE (to)))
continue;
if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
{
if (!at_least_as_qualified_p (to, from))
return 0;
if (!at_least_as_qualified_p (from, to))
{
if (constp == 0)
return 0;
else
++to_more_cv_qualified;
}
if (constp > 0)
constp &= TYPE_READONLY (to);
}
if (TREE_CODE (to) != POINTER_TYPE)
return
same_type_p (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from))
&& (constp >= 0 || to_more_cv_qualified);
}
}
int
comp_ptr_ttypes (to, from)
tree to, from;
{
return comp_ptr_ttypes_real (to, from, 1);
}
int
ptr_reasonably_similar (to, from)
tree to, from;
{
for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
{
if (TREE_CODE (to) != TREE_CODE (from))
return 0;
if (TREE_CODE (from) == OFFSET_TYPE
&& comptypes (TYPE_OFFSET_BASETYPE (to),
TYPE_OFFSET_BASETYPE (from),
COMPARE_BASE | COMPARE_RELAXED))
continue;
if (TREE_CODE (to) != POINTER_TYPE)
return comptypes
(TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from),
COMPARE_BASE | COMPARE_RELAXED);
}
}
static int
comp_ptr_ttypes_const (to, from)
tree to, from;
{
for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
{
if (TREE_CODE (to) != TREE_CODE (from))
return 0;
if (TREE_CODE (from) == OFFSET_TYPE
&& same_type_p (TYPE_OFFSET_BASETYPE (from),
TYPE_OFFSET_BASETYPE (to)))
continue;
if (TREE_CODE (to) != POINTER_TYPE)
return same_type_p (TYPE_MAIN_VARIANT (to),
TYPE_MAIN_VARIANT (from));
}
}
static int
comp_ptr_ttypes_reinterpret (to, from)
tree to, from;
{
int constp = 1;
for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
{
if (TREE_CODE (from) == OFFSET_TYPE)
from = TREE_TYPE (from);
if (TREE_CODE (to) == OFFSET_TYPE)
to = TREE_TYPE (to);
if (TREE_CODE (from) != FUNCTION_TYPE && TREE_CODE (from) != METHOD_TYPE
&& TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
{
if (!at_least_as_qualified_p (to, from))
return 0;
if (! constp
&& !at_least_as_qualified_p (from, to))
return 0;
constp &= TYPE_READONLY (to);
}
if (TREE_CODE (from) != POINTER_TYPE
|| TREE_CODE (to) != POINTER_TYPE)
return 1;
}
}
int
cp_type_quals (type)
tree type;
{
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
return TYPE_QUALS (type);
}
int
cp_has_mutable_p (type)
tree type;
{
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
}