#include "config.h"
#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "expr.h"
#include "cp-tree.h"
#include "tm_p.h"
#include "flags.h"
#include "output.h"
#include "toplev.h"
#include "diagnostic.h"
#include "target.h"
static tree convert_for_assignment PARAMS ((tree, tree, const char *, tree,
int));
static tree cp_pointer_int_sum PARAMS ((enum tree_code, tree, tree));
static tree rationalize_conditional_expr PARAMS ((enum tree_code, tree));
static int comp_target_parms PARAMS ((tree, tree));
static int comp_ptr_ttypes_real PARAMS ((tree, tree, int));
static int comp_ptr_ttypes_const PARAMS ((tree, tree));
static int comp_ptr_ttypes_reinterpret PARAMS ((tree, tree));
static int comp_except_types PARAMS ((tree, tree, int));
static int comp_array_types PARAMS ((int (*) (tree, tree, int), tree,
tree, int));
static tree common_base_type PARAMS ((tree, tree));
static tree lookup_anon_field PARAMS ((tree, tree));
static tree pointer_diff PARAMS ((tree, tree, tree));
static tree qualify_type_recursive PARAMS ((tree, tree));
static tree get_delta_difference PARAMS ((tree, tree, int));
static int comp_cv_target_types PARAMS ((tree, tree, int));
static void casts_away_constness_r PARAMS ((tree *, tree *));
static int casts_away_constness PARAMS ((tree, tree));
static void maybe_warn_about_returning_address_of_local PARAMS ((tree));
static tree strip_all_pointer_quals PARAMS ((tree));
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 (COMPLETE_TYPE_P (type))
return value;
if (TREE_CODE (value) == OFFSET_REF
&& current_class_ref != 0
&& TREE_OPERAND (value, 0) == current_class_ref)
{
value = resolve_offset_ref (value);
return require_complete_type (value);
}
if (complete_type_or_else (type, value))
return value;
else
return error_mark_node;
}
tree
complete_type (type)
tree type;
{
if (type == NULL_TREE)
return error_mark_node;
if (type == error_mark_node || COMPLETE_TYPE_P (type))
;
else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
{
tree t = complete_type (TREE_TYPE (type));
if (COMPLETE_TYPE_P (t) && ! processing_template_decl)
layout_type (type);
TYPE_NEEDS_CONSTRUCTING (type)
= TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
= TYPE_HAS_NONTRIVIAL_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_diagnostic (type, value, diag_type)
tree type;
tree value;
int diag_type;
{
type = complete_type (type);
if (type == error_mark_node)
return NULL_TREE;
else if (!COMPLETE_TYPE_P (type))
{
cxx_incomplete_type_diagnostic (value, type, diag_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));
}
static tree
qualify_type_recursive (t1, t2)
tree t1, t2;
{
if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
|| (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2)))
{
tree tt1;
tree tt2;
tree b1;
int type_quals;
tree tgt;
tree attributes = (*targetm.merge_type_attributes) (t1, t2);
if (TYPE_PTRMEM_P (t1))
{
b1 = TYPE_PTRMEM_CLASS_TYPE (t1);
tt1 = TYPE_PTRMEM_POINTED_TO_TYPE (t1);
tt2 = TYPE_PTRMEM_POINTED_TO_TYPE (t2);
}
else
{
b1 = NULL_TREE;
tt1 = TREE_TYPE (t1);
tt2 = TREE_TYPE (t2);
}
type_quals = (cp_type_quals (tt1) | cp_type_quals (tt2));
tgt = qualify_type_recursive (tt1, tt2);
tgt = cp_build_qualified_type (tgt, type_quals);
if (b1)
t1 = build_ptrmem_type (b1, tgt);
else
t1 = build_pointer_type (tgt);
t1 = build_type_attribute_variant (t1, attributes);
}
return t1;
}
tree
commonparms (p1, p2)
tree p1, p2;
{
tree oldargs = p1, newargs, n;
int i, len;
int any_change = 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) = merge_types (TREE_VALUE (p1), TREE_VALUE (p2));
}
else
TREE_VALUE (n) = TREE_VALUE (p1);
}
if (! any_change)
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
type_after_usual_arithmetic_conversions (t1, t2)
tree t1;
tree t2;
{
enum tree_code code1 = TREE_CODE (t1);
enum tree_code code2 = TREE_CODE (t2);
tree attributes;
my_friendly_assert (ARITHMETIC_TYPE_P (t1)
|| TREE_CODE (t1) == COMPLEX_TYPE
|| TREE_CODE (t1) == ENUMERAL_TYPE,
19990725);
my_friendly_assert (ARITHMETIC_TYPE_P (t2)
|| TREE_CODE (t2) == COMPLEX_TYPE
|| TREE_CODE (t2) == ENUMERAL_TYPE,
19990725);
attributes = (*targetm.merge_type_attributes) (t1, 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
= type_after_usual_arithmetic_conversions (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);
}
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 (code1 != REAL_TYPE)
{
t1 = type_promotes_to (t1);
t2 = type_promotes_to (t2);
}
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) == TYPE_MAIN_VARIANT (t2))
return build_type_attribute_variant (t1, attributes);
if (code1 != REAL_TYPE)
{
if (TYPE_IS_SIZETYPE (t1) > TYPE_IS_SIZETYPE (t2))
return build_type_attribute_variant (t1, attributes);
if (TYPE_IS_SIZETYPE (t2) > TYPE_IS_SIZETYPE (t1))
return build_type_attribute_variant (t2, attributes);
if (same_type_p (TYPE_MAIN_VARIANT (t1), long_long_unsigned_type_node)
|| same_type_p (TYPE_MAIN_VARIANT (t2), long_long_unsigned_type_node))
return build_type_attribute_variant (long_long_unsigned_type_node,
attributes);
if (same_type_p (TYPE_MAIN_VARIANT (t1), long_long_integer_type_node)
|| same_type_p (TYPE_MAIN_VARIANT (t2), long_long_integer_type_node))
{
tree t = ((TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
? long_long_unsigned_type_node
: long_long_integer_type_node);
return build_type_attribute_variant (t, attributes);
}
if (same_type_p (TYPE_MAIN_VARIANT (t1), long_unsigned_type_node)
|| same_type_p (TYPE_MAIN_VARIANT (t2), long_unsigned_type_node))
return build_type_attribute_variant (long_unsigned_type_node,
attributes);
if (same_type_p (TYPE_MAIN_VARIANT (t1), long_integer_type_node)
|| same_type_p (TYPE_MAIN_VARIANT (t2), long_integer_type_node))
{
tree t = ((TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
? long_unsigned_type_node : long_integer_type_node);
return build_type_attribute_variant (t, attributes);
}
if (TREE_UNSIGNED (t1))
return build_type_attribute_variant (t1, attributes);
else
return build_type_attribute_variant (t2, attributes);
}
else
{
if (same_type_p (TYPE_MAIN_VARIANT (t1), long_double_type_node)
|| same_type_p (TYPE_MAIN_VARIANT (t2), long_double_type_node))
return build_type_attribute_variant (long_double_type_node,
attributes);
if (same_type_p (TYPE_MAIN_VARIANT (t1), double_type_node)
|| same_type_p (TYPE_MAIN_VARIANT (t2), double_type_node))
return build_type_attribute_variant (double_type_node,
attributes);
if (same_type_p (TYPE_MAIN_VARIANT (t1), float_type_node)
|| same_type_p (TYPE_MAIN_VARIANT (t2), float_type_node))
return build_type_attribute_variant (float_type_node,
attributes);
return build_type_attribute_variant (t1, attributes);
}
}
tree
composite_pointer_type (t1, t2, arg1, arg2, location)
tree t1;
tree t2;
tree arg1;
tree arg2;
const char* location;
{
tree result_type;
tree attributes;
if (null_ptr_cst_p (arg1))
return t2;
if (null_ptr_cst_p (arg2))
return t1;
if (TYPE_PTRMEMFUNC_P (t1))
t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
if (TYPE_PTRMEMFUNC_P (t2))
t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
attributes = (*targetm.merge_type_attributes) (t1, t2);
if (VOID_TYPE_P (TREE_TYPE (t2)))
{
tree t;
t = t1;
t1 = t2;
t2 = t;
}
if (VOID_TYPE_P (TREE_TYPE (t1)))
{
if (pedantic && TYPE_PTRFN_P (t2))
pedwarn ("ISO C++ forbids %s between pointer of type `void *' and pointer-to-function", location);
t1 = TREE_TYPE (t1);
t2 = TREE_TYPE (t2);
result_type = cp_build_qualified_type (void_type_node,
(cp_type_quals (t1)
| cp_type_quals (t2)));
result_type = build_pointer_type (result_type);
}
else
{
tree full1 = qualify_type_recursive (t1, t2);
tree full2 = qualify_type_recursive (t2, t1);
int val = comp_target_types (full1, full2, 1);
if (val > 0)
result_type = full1;
else if (val < 0)
result_type = full2;
else
{
pedwarn ("%s between distinct pointer types `%T' and `%T' lacks a cast",
location, t1, t2);
result_type = ptr_type_node;
}
}
return build_type_attribute_variant (result_type, attributes);
}
tree
merge_types (t1, t2)
tree t1, t2;
{
register enum tree_code code1;
register enum tree_code code2;
tree attributes;
if (t1 == t2)
return t1;
if (original_type (t1) == original_type (t2))
return t1;
if (t1 == error_mark_node)
return t2;
if (t2 == error_mark_node)
return t1;
attributes = (*targetm.merge_type_attributes) (t1, t2);
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);
switch (code1)
{
case POINTER_TYPE:
case REFERENCE_TYPE:
{
tree target = merge_types (TREE_TYPE (t1), TREE_TYPE (t2));
int quals = cp_type_quals (t1);
if (code1 == POINTER_TYPE)
t1 = build_pointer_type (target);
else
t1 = build_reference_type (target);
t1 = build_type_attribute_variant (t1, attributes);
t1 = cp_build_qualified_type (t1, quals);
if (TREE_CODE (target) == METHOD_TYPE)
t1 = build_ptrmemfunc_type (t1);
return t1;
}
case OFFSET_TYPE:
{
tree base = TYPE_OFFSET_BASETYPE (t1);
tree target = merge_types (TREE_TYPE (t1), TREE_TYPE (t2));
t1 = build_offset_type (base, target);
break;
}
case ARRAY_TYPE:
{
tree elt = merge_types (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));
break;
}
case FUNCTION_TYPE:
{
tree valtype = merge_types (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));
t1 = build_exception_variant (rval, raises);
break;
}
case METHOD_TYPE:
{
tree basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2)));
tree raises = TYPE_RAISES_EXCEPTIONS (t1);
tree t3;
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 = merge_types (t1, t2);
t3 = build_cplus_method_type (basetype, TREE_TYPE (t3),
TYPE_ARG_TYPES (t3));
t1 = build_exception_variant (t3, raises);
break;
}
default:;
}
return build_type_attribute_variant (t1, attributes);
}
tree
common_type (t1, t2)
tree t1, t2;
{
enum tree_code code1;
enum tree_code code2;
if (t1 == error_mark_node || t2 == error_mark_node)
return error_mark_node;
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
if ((ARITHMETIC_TYPE_P (t1) || code1 == ENUMERAL_TYPE
|| code1 == COMPLEX_TYPE)
&& (ARITHMETIC_TYPE_P (t2) || code2 == ENUMERAL_TYPE
|| code2 == COMPLEX_TYPE))
return type_after_usual_arithmetic_conversions (t1, t2);
else if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
|| (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
|| (TYPE_PTRMEMFUNC_P (t1) && TYPE_PTRMEMFUNC_P (t2)))
return composite_pointer_type (t1, t2, error_mark_node, error_mark_node,
"conversion");
else
abort ();
}
static int
comp_except_types (a, b, exact)
tree a, b;
int exact;
{
if (same_type_p (a, b))
return 1;
else if (!exact)
{
if (cp_type_quals (a) || cp_type_quals (b))
return 0;
if (TREE_CODE (a) == POINTER_TYPE
&& TREE_CODE (b) == POINTER_TYPE)
{
a = TREE_TYPE (a);
b = TREE_TYPE (b);
if (cp_type_quals (a) || cp_type_quals (b))
return 0;
}
if (TREE_CODE (a) != RECORD_TYPE
|| TREE_CODE (b) != RECORD_TYPE)
return 0;
if (ACCESSIBLY_UNIQUELY_DERIVED_P (a, b))
return 2;
}
return 0;
}
int
comp_except_specs (t1, t2, exact)
tree t1, t2;
int exact;
{
tree probe;
tree base;
int length = 0;
if (t1 == t2)
return 1;
if (t1 == NULL_TREE)
return t2 == NULL_TREE || !exact;
if (!TREE_VALUE (t1))
return t2 != NULL_TREE && !TREE_VALUE (t2);
if (t2 == NULL_TREE)
return 0;
if (TREE_VALUE (t1) && !TREE_VALUE (t2))
return !exact;
for (base = t1; t2 != NULL_TREE; t2 = TREE_CHAIN (t2))
{
for (probe = base; probe != NULL_TREE; probe = TREE_CHAIN (probe))
{
tree a = TREE_VALUE (probe);
tree b = TREE_VALUE (t2);
if (comp_except_types (a, b, exact))
{
if (probe == base && exact)
base = TREE_CHAIN (probe);
length++;
break;
}
}
if (probe == NULL_TREE)
return 0;
}
return !exact || base == NULL_TREE || length == list_length (t1);
}
static int
comp_array_types (cmp, t1, t2, strict)
register int (*cmp) PARAMS ((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 (t1, t2, strict)
tree t1;
tree t2;
int strict;
{
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 (TREE_CODE (t1) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t1)
&& TYPE_DOMAIN (t1) != 0)
t1 = TYPE_DOMAIN (t1);
if (TREE_CODE (t2) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t2)
&& TYPE_DOMAIN (t2) != 0)
t2 = TYPE_DOMAIN (t2);
if (strict & COMPARE_RELAXED)
{
if (TREE_CODE (t1) == ENUMERAL_TYPE)
t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1);
if (TREE_CODE (t2) == ENUMERAL_TYPE)
t2 = c_common_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;
if (strict & COMPARE_NO_ATTRIBUTES)
attrval = 1;
else if (! (attrval = (*targetm.comp_type_attributes) (t1, t2)))
return 0;
val = 0;
switch (TREE_CODE (t1))
{
case TEMPLATE_TEMPLATE_PARM:
case BOUND_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 (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t1)),
DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2))))
return 0;
if (TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM)
return 1;
strict = COMPARE_STRICT;
case RECORD_TYPE:
case UNION_TYPE:
if (flag_objc && objc_comptypes (t1, t2, 0) == 1)
return 1;
if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2)
&& (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
|| TREE_CODE (t1) == BOUND_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;
else if ((strict & COMPARE_RELAXED) && DERIVED_FROM_P (t2, t1))
val = 1;
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 POINTER_TYPE:
case REFERENCE_TYPE:
t1 = TREE_TYPE (t1);
t2 = TREE_TYPE (t2);
if (flag_objc && cp_type_quals (t1) == cp_type_quals (t2)
&& objc_comptypes (t1, t2, 0) == 1)
return 1;
val = comptypes (t1, t2, strict);
if (val)
break;
if (TREE_CODE (t1) == RECORD_TYPE
&& TREE_CODE (t2) == RECORD_TYPE)
goto look_hard;
break;
case METHOD_TYPE:
case FUNCTION_TYPE:
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 (cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1),
TYPENAME_TYPE_FULLNAME (t2)) < 1)
return 0;
return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
case UNBOUND_CLASS_TEMPLATE:
if (cp_tree_equal (TYPE_IDENTIFIER (t1),
TYPE_IDENTIFIER (t2)) < 1)
return 0;
return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
case COMPLEX_TYPE:
return same_type_p (TREE_TYPE (t1), TREE_TYPE (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);
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))
{
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)
tree parms1, parms2;
{
register tree t1 = parms1, t2 = parms2;
int warn_contravariance = 0;
if (t1 == 0 && t2 != 0)
{
pedwarn ("ISO 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)
return 0;
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 (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_ignoring_top_level_qualifiers_p (TREE_TYPE (p1),
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;
}
return 0;
}
}
return warn_contravariance ? -1 : 1;
}
tree
cxx_sizeof_or_alignof_type (type, op, complain)
tree type;
enum tree_code op;
int complain;
{
enum tree_code type_code;
tree value;
const char *op_name;
my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
if (processing_template_decl)
return build_min_nt (op, type);
op_name = operator_name_info[(int) op].name;
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
type_code = TREE_CODE (type);
if (type_code == METHOD_TYPE)
{
if (complain && (pedantic || warn_pointer_arith))
pedwarn ("invalid application of `%s' to a member function", op_name);
value = size_one_node;
}
else if (type_code == OFFSET_TYPE)
{
if (complain)
error ("invalid application of `%s' to non-static member", op_name);
value = size_zero_node;
}
else
value = c_sizeof_or_alignof_type (complete_type (type), op, complain);
return value;
}
tree
expr_sizeof (e)
tree e;
{
if (processing_template_decl)
return build_min_nt (SIZEOF_EXPR, e);
if (TREE_CODE (e) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
error ("sizeof applied to a bit-field");
if (is_overloaded_fn (e))
{
pedwarn ("ISO C++ forbids applying `sizeof' to an expression of function type");
return c_sizeof (char_type_node);
}
else if (type_unknown_p (e))
{
cxx_incomplete_type_error (e, TREE_TYPE (e));
return c_sizeof (char_type_node);
}
else if (TREE_CODE (e) == OFFSET_REF)
e = resolve_offset_ref (e);
if (e == error_mark_node)
return e;
return cxx_sizeof (TREE_TYPE (e));
}
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 (type == error_mark_node)
return error_mark_node;
if (type_unknown_p (exp))
{
cxx_incomplete_type_error (exp, TREE_TYPE (exp));
return error_mark_node;
}
if (TREE_CODE (exp) == CONST_DECL)
exp = DECL_INITIAL (exp);
else if (code != ARRAY_TYPE)
{
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)
abort ();
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 (!cxx_mark_addressable (exp))
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);
}
if (! CLASS_TYPE_P (type))
exp = cp_convert (TYPE_MAIN_VARIANT (type), exp);
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)
warning ("deprecated conversion from string constant to `%T'", totype);
return 1;
}
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 || DECL_ARTIFICIAL (field))
continue;
if (DECL_NAME (field) == NULL_TREE
&& type == TYPE_MAIN_VARIANT (TREE_TYPE (field)))
{
return field;
}
if (DECL_NAME (field) == NULL_TREE
&& ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
tree subfield = lookup_anon_field (TREE_TYPE (field), type);
if (subfield)
return subfield;
}
}
return NULL_TREE;
}
tree
build_class_member_access_expr (tree object, tree member,
tree access_path, bool preserve_reference)
{
tree object_type;
tree member_scope;
tree result = NULL_TREE;
if (object == error_mark_node || member == error_mark_node)
return error_mark_node;
my_friendly_assert (DECL_P (member) || BASELINK_P (member),
20020801);
if (TREE_CODE (object) == COMPOUND_EXPR)
{
result = build_class_member_access_expr (TREE_OPERAND (object, 1),
member, access_path,
preserve_reference);
return build (COMPOUND_EXPR, TREE_TYPE (result),
TREE_OPERAND (object, 0), result);
}
else if (TREE_CODE (object) == COND_EXPR)
return (build_conditional_expr
(TREE_OPERAND (object, 0),
build_class_member_access_expr (TREE_OPERAND (object, 1),
member, access_path,
preserve_reference),
build_class_member_access_expr (TREE_OPERAND (object, 2),
member, access_path,
preserve_reference)));
object_type = TREE_TYPE (object);
if (!complete_type_or_else (object_type, object))
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
error ("request for member `%D' in `%E', which is of non-class type `%T'",
member, object, object_type);
return error_mark_node;
}
if (DECL_P (member))
{
member_scope = DECL_CLASS_CONTEXT (member);
mark_used (member);
if (TREE_DEPRECATED (member))
warn_deprecated_use (member);
}
else
member_scope = BINFO_TYPE (BASELINK_BINFO (member));
while (ANON_AGGR_TYPE_P (member_scope)
&& !same_type_ignoring_top_level_qualifiers_p (member_scope,
object_type))
member_scope = TYPE_CONTEXT (member_scope);
if (!member_scope || !DERIVED_FROM_P (member_scope, object_type))
{
error ("`%D' is not a member of `%T'", member, object_type);
return error_mark_node;
}
if (TREE_CODE (member) == VAR_DECL)
{
result = member;
if (TREE_SIDE_EFFECTS (object))
result = build (COMPOUND_EXPR, TREE_TYPE (result), object, result);
}
else if (TREE_CODE (member) == FIELD_DECL)
{
bool null_object_p;
int type_quals;
tree member_type;
null_object_p = (TREE_CODE (object) == INDIRECT_REF
&& integer_zerop (TREE_OPERAND (object, 0)));
if (!same_type_p (object_type, member_scope))
{
tree binfo;
base_kind kind;
binfo = lookup_base (access_path ? access_path : object_type,
member_scope, ba_ignore, &kind);
if (binfo == error_mark_node)
return error_mark_node;
if (null_object_p && kind == bk_via_virtual)
{
error ("invalid access to non-static data member `%D' of NULL object",
member);
error ("(perhaps the `offsetof' macro was used incorrectly)");
return error_mark_node;
}
object = build_base_path (PLUS_EXPR, object, binfo,
1);
my_friendly_assert (object != error_mark_node,
20020801);
}
if (null_object_p && warn_invalid_offsetof
&& CLASSTYPE_NON_POD_P (object_type))
{
warning ("invalid access to non-static data member `%D' of NULL object",
member);
warning ("(perhaps the `offsetof' macro was used incorrectly)");
}
if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member))
&& (!same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (object), DECL_CONTEXT (member))))
{
tree anonymous_union;
anonymous_union = lookup_anon_field (TREE_TYPE (object),
DECL_CONTEXT (member));
object = build_class_member_access_expr (object,
anonymous_union,
NULL_TREE,
preserve_reference);
}
type_quals = TYPE_UNQUALIFIED;
member_type = TREE_TYPE (member);
if (TREE_CODE (member_type) != REFERENCE_TYPE)
{
type_quals = (cp_type_quals (member_type)
| cp_type_quals (object_type));
if (DECL_MUTABLE_P (member))
type_quals &= ~TYPE_QUAL_CONST;
member_type = cp_build_qualified_type (member_type, type_quals);
}
result = fold (build (COMPONENT_REF, member_type, object, member));
if (type_quals & TYPE_QUAL_CONST)
TREE_READONLY (result) = 1;
else if (type_quals & TYPE_QUAL_VOLATILE)
TREE_THIS_VOLATILE (result) = 1;
}
else if (BASELINK_P (member))
{
tree functions;
functions = BASELINK_FUNCTIONS (member);
if (TREE_CODE (functions) == FUNCTION_DECL
&& DECL_STATIC_FUNCTION_P (functions))
{
result = functions;
mark_used (result);
if (TREE_SIDE_EFFECTS (object))
result = build (COMPOUND_EXPR, TREE_TYPE (result),
object, result);
}
else
result = build (COMPONENT_REF, unknown_type_node, object, member);
}
else if (TREE_CODE (member) == CONST_DECL)
{
result = member;
if (TREE_SIDE_EFFECTS (object))
result = build (COMPOUND_EXPR, TREE_TYPE (result),
object, result);
}
else
{
error ("invalid use of `%D'", member);
return error_mark_node;
}
if (!preserve_reference)
result = convert_from_reference (result);
return result;
}
tree
finish_class_member_access_expr (tree object, tree name)
{
tree object_type;
tree member;
tree access_path = NULL_TREE;
if (object == error_mark_node || name == error_mark_node)
return error_mark_node;
if (processing_template_decl)
return build_min_nt (COMPONENT_REF, object, name);
if (TREE_CODE (object) == OFFSET_REF)
object = resolve_offset_ref (object);
object_type = TREE_TYPE (object);
if (TREE_CODE (object_type) == REFERENCE_TYPE)
{
object = convert_from_reference (object);
object_type = TREE_TYPE (object);
}
if (!complete_type_or_else (object_type, object))
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
error ("request for member `%D' in `%E', which is of non-class type `%T'",
name, object, object_type);
return error_mark_node;
}
if (BASELINK_P (name))
{
my_friendly_assert ((TREE_CODE (BASELINK_FUNCTIONS (name))
== TEMPLATE_ID_EXPR),
20020805);
member = name;
}
else
{
bool is_template_id = false;
tree template_args = NULL_TREE;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
{
is_template_id = true;
template_args = TREE_OPERAND (name, 1);
name = TREE_OPERAND (name, 0);
}
if (TREE_CODE (name) == SCOPE_REF)
{
tree scope;
scope = TREE_OPERAND (name, 0);
name = TREE_OPERAND (name, 1);
my_friendly_assert ((CLASS_TYPE_P (scope)
|| TREE_CODE (scope) == NAMESPACE_DECL),
20020804);
my_friendly_assert ((TREE_CODE (name) == IDENTIFIER_NODE
|| TREE_CODE (name) == BIT_NOT_EXPR),
20020804);
if (TREE_CODE (scope) == NAMESPACE_DECL)
{
error ("`%D::%D' is not a member of `%T'",
scope, name, object_type);
return error_mark_node;
}
access_path = lookup_base (object_type, scope, ba_check, NULL);
if (!access_path || access_path == error_mark_node)
return error_mark_node;
member = lookup_member (access_path, name, 1,
0);
if (member == NULL_TREE)
{
error ("'%D' has no member named '%E'", object_type, name);
return error_mark_node;
}
else if (member == error_mark_node)
return error_mark_node;
}
else if (TREE_CODE (name) == BIT_NOT_EXPR)
{
if (TYPE_IDENTIFIER (object_type) != TREE_OPERAND (name, 0))
{
error ("destructor specifier `%T::~%T' must have matching names",
object_type, TREE_OPERAND (name, 0));
return error_mark_node;
}
if (! TYPE_HAS_DESTRUCTOR (object_type))
{
error ("type `%T' has no destructor", object_type);
return error_mark_node;
}
member = CLASSTYPE_DESTRUCTORS (object_type);
}
else if (TREE_CODE (name) == IDENTIFIER_NODE)
{
member = lookup_member (object_type, name, 1,
0);
if (member == NULL_TREE)
{
error ("'%D' has no member named '%E'", object_type, name);
return error_mark_node;
}
else if (member == error_mark_node)
return error_mark_node;
}
else
{
error ("invalid use of `%D'", name);
return error_mark_node;
}
if (is_template_id)
{
tree template = member;
if (BASELINK_P (template))
BASELINK_FUNCTIONS (template)
= build_nt (TEMPLATE_ID_EXPR,
BASELINK_FUNCTIONS (template),
template_args);
else
{
error ("`%D' is not a member template function", name);
return error_mark_node;
}
}
}
return build_class_member_access_expr (object, member, access_path,
false);
}
tree
build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
{
tree ptrmem_type;
tree member;
tree member_type;
ptrmem_type = TREE_TYPE (ptrmem);
if (!flag_apple_kext)
my_friendly_assert (TYPE_PTRMEMFUNC_P (ptrmem_type), 20020804);
member = lookup_member (ptrmem_type, member_name, 0,
0);
member_type = cp_build_qualified_type (TREE_TYPE (member),
cp_type_quals (ptrmem_type));
return fold (build (COMPONENT_REF, member_type, ptrmem, member));
}
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 (VOID_TYPE_P (t))
{
error ("`%T' is not a pointer-to-object type", type);
return error_mark_node;
}
else 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 (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;
switch (TREE_CODE (array))
{
case COMPOUND_EXPR:
{
tree value = build_array_ref (TREE_OPERAND (array, 1), idx);
return build (COMPOUND_EXPR, TREE_TYPE (value),
TREE_OPERAND (array, 0), value);
}
case COND_EXPR:
return build_conditional_expr
(TREE_OPERAND (array, 0),
build_array_ref (TREE_OPERAND (array, 1), idx),
build_array_ref (TREE_OPERAND (array, 2), idx));
default:
break;
}
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
|| (COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (array)))
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))))
!= INTEGER_CST)))
{
if (!cxx_mark_addressable (array))
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 (!cxx_mark_addressable (array))
return error_mark_node;
}
if (pedantic && !lvalue_p (array))
pedwarn ("ISO 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 (cp_build_binary_op (PLUS_EXPR, ar, ind),
"array indexing");
}
}
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 idx, delta, e1, e2, e3, vtbl, basetype;
tree delta2;
tree fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
tree instance_ptr = *instance_ptrptr;
tree instance_save_expr = 0;
if (instance_ptr == error_mark_node)
{
if (TREE_CODE (function) == PTRMEM_CST)
{
e1 = build_addr_func (PTRMEM_CST_MEMBER (function));
e1 = convert (fntype, e1);
return e1;
}
else
{
error ("object missing in use of `%E'", function);
return error_mark_node;
}
}
if (TREE_SIDE_EFFECTS (instance_ptr))
instance_ptr = instance_save_expr = save_expr (instance_ptr);
if (TREE_SIDE_EFFECTS (function))
function = save_expr (function);
e3 = PFN_FROM_PTRMEMFUNC (function);
delta = build_ptrmemfunc_access_expr (function, delta_identifier);
if (flag_apple_kext)
{
idx = build_ptrmemfunc_access_expr (function, index_identifier);
idx = save_expr (default_conversion (idx));
e1 = cp_build_binary_op (GE_EXPR, idx, integer_zero_node);
}
else
{
idx = build1 (NOP_EXPR, vtable_index_type, e3);
switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
{
case ptrmemfunc_vbit_in_pfn:
e1 = cp_build_binary_op (BIT_AND_EXPR, idx, integer_one_node);
idx = cp_build_binary_op (MINUS_EXPR, idx, integer_one_node);
break;
case ptrmemfunc_vbit_in_delta:
e1 = cp_build_binary_op (BIT_AND_EXPR, delta, integer_one_node);
delta = cp_build_binary_op (RSHIFT_EXPR, delta, integer_one_node);
break;
default:
abort ();
}
}
if (flag_apple_kext)
{
delta2 = build_ptrmemfunc_access_expr (function,
pfn_or_delta2_identifier);
delta2 = build_ptrmemfunc_access_expr (delta2,
delta2_identifier);
}
basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
basetype, ba_check, NULL);
instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype, 1);
if (instance_ptr == error_mark_node)
return error_mark_node;
if (flag_apple_kext)
vtbl = build (PLUS_EXPR,build_pointer_type (vtbl_ptr_type_node),
instance_ptr, cp_convert (ptrdiff_type_node, delta2));
instance_ptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
instance_ptr, delta);
*instance_ptrptr = instance_ptr;
if (!flag_apple_kext)
vtbl = build1 (NOP_EXPR, build_pointer_type (vtbl_ptr_type_node),
instance_ptr);
vtbl = build_indirect_ref (vtbl, NULL);
#ifdef ADJUST_VTABLE_INDEX
if (0) ADJUST_VTABLE_INDEX (idx, vtbl);
#endif
if (flag_apple_kext)
{
idx = cp_build_binary_op (MINUS_EXPR, idx, integer_one_node);
idx = cp_build_binary_op (LSHIFT_EXPR, idx, integer_two_node);
}
e2 = fold (build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx));
e2 = build_indirect_ref (e2, NULL);
TREE_CONSTANT (e2) = 1;
if (TARGET_VTABLE_USES_DESCRIPTORS)
e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
build_unary_op (ADDR_EXPR, e2, 1));
TREE_TYPE (e2) = TREE_TYPE (e3);
e1 = build_conditional_expr (e1, e2, e3);
if (instance_save_expr)
e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
instance_save_expr, e1);
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 result;
tree name = NULL_TREE, assembler_name = NULL_TREE;
int is_method;
tree original = function;
#ifdef SELECT_TARGET_OVERLOADED_INTRINSIC
if (TREE_CODE (function) == FUNCTION_DECL
&& DECL_TARGET_OVERLOADED_INTRINSIC_P (function))
{
function = SELECT_TARGET_OVERLOADED_INTRINSIC (function, params);
if (function == NULL_TREE)
return error_mark_node;
}
#endif
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)
{
name = DECL_NAME (function);
assembler_name = DECL_ASSEMBLER_NAME (function);
mark_used (function);
fndecl = function;
if (pedantic && DECL_MAIN_P (function))
pedwarn ("ISO 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))
{
error ("must use .* or ->* to call pointer-to-member function in `%E (...)'",
original);
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))
{
error ("`%E' cannot be used as a function", original);
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)
check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params);
if (TREE_CODE (function) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
&& DECL_BUILT_IN (TREE_OPERAND (function, 0)))
{
result = expand_tree_builtin (TREE_OPERAND (function, 0),
params, coerced_params);
if (result)
return result;
}
result = fold (build_call (function, coerced_params));
value_type = TREE_TYPE (result);
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 (!COMPLETE_TYPE_P (complete_type (type)))
{
error ("parameter type of called function is incomplete");
parmval = val;
}
else
{
parmval = convert_for_initialization
(NULL_TREE, type, val, flags,
"argument passing", fndecl, i);
parmval = convert_for_arg_passing (type, parmval);
}
if (parmval == error_mark_node)
return error_mark_node;
result = tree_cons (NULL_TREE, parmval, result);
}
else
{
if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
val = convert_from_reference (val);
if (fndecl && DECL_BUILT_IN (fndecl)
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CONSTANT_P)
val = require_complete_type (val);
else
val = convert_arg_to_ellipsis (val);
result = tree_cons (NULL_TREE, 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, i);
if (parmval == error_mark_node)
return error_mark_node;
result = 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, orig_op0, orig_op1, convert_p)
enum tree_code code;
tree orig_op0, orig_op1;
int convert_p ATTRIBUTE_UNUSED;
{
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;
op0 = orig_op0;
op1 = orig_op1;
if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
|| code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
|| code == TRUTH_XOR_EXPR)
{
if (!really_overloaded_fn (op0))
op0 = decay_conversion (op0);
if (!really_overloaded_fn (op1))
op1 = decay_conversion (op1);
}
else
{
if (!really_overloaded_fn (op0))
op0 = default_conversion (op0);
if (!really_overloaded_fn (op1))
op1 = default_conversion (op1);
}
STRIP_TYPE_NOPS (op0);
STRIP_TYPE_NOPS (op1);
if (type_unknown_p (op0))
{
tree t = instantiate_type (TREE_TYPE (op1), op0, tf_none);
if (t != error_mark_node)
{
pedwarn ("assuming cast to type `%T' from overloaded function",
TREE_TYPE (t));
op0 = t;
}
}
if (type_unknown_p (op1))
{
tree t = instantiate_type (TREE_TYPE (op0), op1, tf_none);
if (t != error_mark_node)
{
pedwarn ("assuming cast to type `%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 cp_pointer_int_sum (PLUS_EXPR, op0, op1);
else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
return cp_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 cp_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))
warning ("division by zero in `%E / 0'", op0);
else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1))
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
&& ! integer_all_onesp (op1)));
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;
break;
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
if (code1 == INTEGER_TYPE && integer_zerop (op1))
warning ("division by zero in `%E %% 0'", op0);
else if (code1 == REAL_TYPE && real_zerop (op1))
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
&& ! integer_all_onesp (op1)));
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 (! integer_zerop (op1))
short_shift = 1;
if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
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 (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
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 (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
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:
if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
warning ("comparing floating point with == or != is unsafe");
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)
result_type = composite_pointer_type (type0, type1, op0, op1,
"comparison");
else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
result_type = type0;
else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0))
result_type = type1;
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
error ("ISO C++ forbids comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
error ("ISO C++ forbids comparison between pointer and integer");
}
else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
{
if (flag_apple_kext)
op0 = build_ptrmemfunc_access_expr (op0, index_identifier);
else
op0 = build_ptrmemfunc_access_expr (op0, pfn_identifier);
op1 = cp_convert (TREE_TYPE (op0), integer_zero_node);
result_type = TREE_TYPE (op0);
}
else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
return cp_build_binary_op (code, op1, op0);
else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
&& same_type_p (type0, type1))
{
tree e;
tree e1;
tree e2;
tree pfn0;
tree pfn1;
tree delta0;
tree delta1;
if (TREE_SIDE_EFFECTS (op0))
op0 = save_expr (op0);
if (TREE_SIDE_EFFECTS (op1))
op1 = save_expr (op1);
pfn0 = pfn_from_ptrmemfunc (op0);
pfn1 = pfn_from_ptrmemfunc (op1);
delta0 = build_ptrmemfunc_access_expr (op0,
delta_identifier);
delta1 = build_ptrmemfunc_access_expr (op1,
delta_identifier);
e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1);
e2 = cp_build_binary_op (EQ_EXPR,
pfn0,
cp_convert (TREE_TYPE (pfn0),
integer_zero_node));
e1 = cp_build_binary_op (TRUTH_ORIF_EXPR, e1, e2);
e2 = build (EQ_EXPR, boolean_type_node, pfn0, pfn1);
e = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1);
if (code == EQ_EXPR)
return e;
return cp_build_binary_op (EQ_EXPR, e, integer_zero_node);
}
else if ((TYPE_PTRMEMFUNC_P (type0)
&& same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type0), type1))
|| (TYPE_PTRMEMFUNC_P (type1)
&& same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type1), type0)))
abort ();
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)
result_type = composite_pointer_type (type0, type1, op0, op1,
"comparison");
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)
result_type = composite_pointer_type (type0, type1, op0, op1,
"comparison");
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 ("ISO C++ forbids comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
pedwarn ("ISO C++ forbids comparison between pointer and integer");
}
break;
case UNORDERED_EXPR:
case ORDERED_EXPR:
case UNLT_EXPR:
case UNLE_EXPR:
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
build_type = integer_type_node;
if (code0 != REAL_TYPE || code1 != REAL_TYPE)
{
error ("unordered comparison on non-floating point argument");
return error_mark_node;
}
common = 1;
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 = c_common_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 = c_common_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 = c_common_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)
&& compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0
&& (!TREE_UNSIGNED (final_type)
|| unsigned_arg
|| (((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0)))
<= TYPE_PRECISION (result_type))))
{
result_type
= c_common_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 || code == MIN_EXPR || code == MAX_EXPR)
&& 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)))
{
warning ("comparison between types `%#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_expr_nonnegative_p (orig_op0))
|| (op1_signed && tree_expr_nonnegative_p (orig_op1)))
;
else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR)
&& ((op0_signed && TREE_CODE (orig_op1) == INTEGER_CST
&& int_fits_type_p (orig_op1, c_common_signed_type
(result_type)))
|| (op1_signed && TREE_CODE (orig_op0) == INTEGER_CST
&& int_fits_type_p (orig_op0, c_common_signed_type
(result_type)))))
;
else
warning ("comparison between signed and unsigned integer expressions");
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 (host_integerp (primop0, 0) || host_integerp (primop1, 0))
{
tree primop;
HOST_WIDE_INT constant, mask;
int unsignedp;
unsigned int bits;
if (host_integerp (primop0, 0))
{
primop = primop1;
unsignedp = unsignedp1;
constant = tree_low_cst (primop0, 0);
}
else
{
primop = primop0;
unsignedp = unsignedp0;
constant = tree_low_cst (primop1, 0);
}
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)
{
error ("invalid operands of types `%T' and `%T' to binary `%O'",
TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), 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)))
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
cp_pointer_int_sum (resultcode, ptrop, intop)
enum tree_code resultcode;
register tree ptrop, intop;
{
tree res_type = TREE_TYPE (ptrop);
complete_type (TREE_TYPE (res_type));
return pointer_int_sum (resultcode, ptrop, fold (intop));
}
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 ("ISO C++ forbids using pointer of type `void *' in subtraction");
if (TREE_CODE (target_type) == FUNCTION_TYPE)
pedwarn ("ISO C++ forbids using pointer to a function in subtraction");
if (TREE_CODE (target_type) == METHOD_TYPE)
pedwarn ("ISO C++ forbids using pointer to a method in subtraction");
if (TREE_CODE (target_type) == OFFSET_TYPE)
pedwarn ("ISO C++ forbids using pointer to a member in subtraction");
}
op0 = cp_build_binary_op (MINUS_EXPR,
cp_convert (restype, op0),
cp_convert (restype, op1));
if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
error ("invalid use of a pointer to an incomplete type in pointer arithmetic");
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;
}
tree
build_x_unary_op (code, xarg)
enum tree_code code;
tree xarg;
{
tree exp;
int ptrmem = 0;
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)))
&& !COMPLETE_TYPE_P (TREE_TYPE (xarg)))
|| (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 (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
&& (TREE_CODE (xarg) != OFFSET_REF || !PTRMEM_OK_P (xarg)))
{
if (TREE_CODE (xarg) != OFFSET_REF)
{
error ("invalid use of '%E' to form a pointer-to-member-function. Use a qualified-id.",
xarg);
return error_mark_node;
}
else
{
error ("parenthesis around '%E' cannot be used to form a pointer-to-member-function",
xarg);
PTRMEM_OK_P (xarg) = 1;
}
}
if (TREE_CODE (xarg) == OFFSET_REF)
{
ptrmem = PTRMEM_OK_P (xarg);
if (!ptrmem && !flag_ms_extensions
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (xarg, 1))) == METHOD_TYPE)
{
xarg = build (OFFSET_REF, TREE_TYPE (xarg),
TREE_OPERAND (xarg, 0),
ovl_cons (TREE_OPERAND (xarg, 1), NULL_TREE));
PTRMEM_OK_P (xarg) = ptrmem;
}
}
else if (TREE_CODE (xarg) == TARGET_EXPR)
warning ("taking address of temporary");
}
exp = build_unary_op (code, xarg, 0);
if (TREE_CODE (exp) == ADDR_EXPR)
PTRMEM_OK_P (exp) = ptrmem;
return exp;
}
tree
cp_truthvalue_conversion (expr)
tree expr;
{
tree type = TREE_TYPE (expr);
if (TYPE_PTRMEM_P (type))
return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
else
return c_common_truthvalue_conversion (expr);
}
tree
condition_conversion (expr)
tree expr;
{
tree t;
if (processing_template_decl)
return expr;
if (TREE_CODE (expr) == OFFSET_REF)
expr = resolve_offset_ref (expr);
t = perform_implicit_conversion (boolean_type_node, expr);
t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
return t;
}
tree
build_address (tree t)
{
tree addr;
if (error_operand_p (t) || !cxx_mark_addressable (t))
return error_mark_node;
addr = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (t)),
t);
if (staticp (t))
TREE_CONSTANT (addr) = 1;
return addr;
}
tree
build_nop (tree type, tree expr)
{
tree nop;
if (type == error_mark_node || error_operand_p (expr))
return expr;
nop = build1 (NOP_EXPR, type, expr);
if (TREE_CONSTANT (expr))
TREE_CONSTANT (nop) = 1;
return nop;
}
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 ("ISO 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));
tree type = complete_type (TREE_TYPE (argtype));
if (!COMPLETE_OR_VOID_TYPE_P (type))
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))
pedwarn ("ISO C++ forbids %sing a pointer of type `%T'",
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"), argtype);
inc = cxx_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);
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)
{
error ("invalid use of `--' on bool variable `%D'", arg);
return error_mark_node;
}
#if 0
val = build (code, TREE_TYPE (arg), arg, inc);
#else
val = boolean_increment (code, arg);
#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 ("ISO C++ forbids 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 (!cxx_mark_addressable (TREE_OPERAND (arg, 0)))
return error_mark_node;
return cp_build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
TREE_OPERAND (arg, 1));
}
if (TREE_CODE (arg) == IDENTIFIER_NODE
&& IDENTIFIER_OPNAME_P (arg))
{
abort ();
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
&& !really_overloaded_fn (TREE_OPERAND (arg, 1)))
{
tree base = TREE_TYPE (TREE_OPERAND (arg, 0));
tree name = DECL_NAME (get_first_fn (TREE_OPERAND (arg, 1)));
if (! flag_ms_extensions)
{
if (current_class_type
&& TREE_OPERAND (arg, 0) == current_class_ref)
pedwarn ("ISO C++ forbids taking the address of an unqualified non-static member function to form a pointer to member function. Say `&%T::%D'", base, name);
else
pedwarn ("ISO C++ forbids taking the address of a bound member function 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 ("ISO C++ forbids taking the address of a cast to a non-lvalue expression");
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
&& !non_cast_lvalue_or_else (arg, "unary `&'"))
return error_mark_node;
if (argtype != error_mark_node)
argtype = build_pointer_type (argtype);
{
tree addr;
if (TREE_CODE (arg) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
{
error ("attempt to take address of bit-field structure member `%D'",
TREE_OPERAND (arg, 1));
return error_mark_node;
}
else if (TREE_CODE (arg) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (arg, 0)) == INDIRECT_REF
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0))
== INTEGER_CST))
{
tree field = TREE_OPERAND (arg, 1);
tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)),
decl_type_context (field),
ba_check, NULL);
rval = build_base_path (PLUS_EXPR, rval, binfo, 1);
rval = build1 (NOP_EXPR, argtype, rval);
TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
addr = fold (build (PLUS_EXPR, argtype, rval,
cp_convert (argtype, byte_position (field))));
}
else
addr = build_address (arg);
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 ("%s", errstring);
return error_mark_node;
}
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)
{
tree lvalue = TREE_OPERAND (arg, 0);
if (TREE_SIDE_EFFECTS (lvalue))
{
lvalue = stabilize_reference (lvalue);
arg = build (TREE_CODE (arg), TREE_TYPE (arg),
lvalue, TREE_OPERAND (arg, 1));
}
return unary_complex_lvalue
(code, build (COMPOUND_EXPR, TREE_TYPE (lvalue), arg, lvalue));
}
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))
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)
{
error ("taking address of bound pointer-to-member expression");
return error_mark_node;
}
if (!PTRMEM_OK_P (arg))
{
arg = resolve_offset_ref (arg);
return build_unary_op (code, arg, 0);
}
if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
{
error ("cannot create pointer to reference member `%D'", t);
return error_mark_node;
}
type = build_ptrmem_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
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;
}
bool
cxx_mark_addressable (exp)
tree exp;
{
register tree x = exp;
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)
{
error ("cannot take the address of `this', which is an rvalue expression");
TREE_ADDRESSABLE (x) = 1;
return true;
}
case VAR_DECL:
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)
warning ("address requested for `%D', which is declared `register'",
x);
TREE_ADDRESSABLE (x) = 1;
put_var_into_stack (x);
return true;
case FUNCTION_DECL:
TREE_ADDRESSABLE (x) = 1;
TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
return true;
case CONSTRUCTOR:
TREE_ADDRESSABLE (x) = 1;
return true;
case TARGET_EXPR:
TREE_ADDRESSABLE (x) = 1;
cxx_mark_addressable (TREE_OPERAND (x, 0));
return true;
default:
return true;
}
}
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_conditional_expr (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 (tree_cons (NULL_TREE, result,
TREE_CHAIN (rest)));
if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
{
if ((extra_warnings || warn_unused_value)
&& !(TREE_CODE (TREE_VALUE(list)) == CONVERT_EXPR
&& VOID_TYPE_P (TREE_TYPE (TREE_VALUE(list)))))
warning("left-hand operand of comma expression has no effect");
}
#if 0
else if (warn_unused_value)
warn_if_unused_value (TREE_VALUE(list));
#endif
return build_compound_expr
(tree_cons (NULL_TREE, TREE_VALUE (list),
build_tree_list (NULL_TREE,
build_x_compound_expr (rest))));
}
tree
build_compound_expr (list)
tree list;
{
register tree rest;
tree first;
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);
return TREE_VALUE (list);
}
first = TREE_VALUE (list);
first = convert_to_void (first, "left-hand operand of comma");
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), first, rest);
}
tree
build_static_cast (type, expr)
tree type, expr;
{
tree intype;
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, 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)
{
expr = convert_to_void (expr, NULL);
return 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_special_member_call
(NULL_TREE, complete_ctor_identifier,
build_tree_list (NULL_TREE, expr),
TYPE_BINFO (type), LOOKUP_NORMAL)));
intype = TREE_TYPE (expr);
ok = 0;
if (IS_AGGR_TYPE (intype)
? can_convert_arg (type, intype, expr)
: can_convert_arg (strip_all_pointer_quals (type),
strip_all_pointer_quals (intype), expr))
ok = 1;
else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
{
base_kind kind;
if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
&& lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
ba_ignore | ba_quiet, &kind)
&& kind != bk_via_virtual)
ok = 1;
}
else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
{
base_kind kind;
if (same_type_p
(strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (type))),
strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (intype))))
&& (lookup_base (TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)),
TYPE_OFFSET_BASETYPE (TREE_TYPE (type)),
ba_ignore | ba_quiet, &kind))
&& kind != bk_via_virtual)
ok = 1;
}
else if (TREE_CODE (intype) != BOOLEAN_TYPE
&& TREE_CODE (type) != ARRAY_TYPE
&& TREE_CODE (type) != FUNCTION_TYPE
&& can_convert (intype, strip_all_pointer_quals (type)))
ok = 1;
else if (TREE_CODE (intype) == ENUMERAL_TYPE
&& TREE_CODE (type) == ENUMERAL_TYPE)
ok = 1;
else if (TREE_CODE (intype) == VECTOR_TYPE
&& TREE_CODE (type) == VECTOR_TYPE)
ok = 1;
if (ok && casts_away_constness (intype, type))
{
error ("static_cast from type `%T' to type `%T' casts away constness",
intype, type);
return error_mark_node;
}
if (ok)
return build_c_cast (type, expr);
error ("invalid static_cast from type `%T' to type `%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, 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))
{
error ("invalid reinterpret_cast of an rvalue expression of type `%T' to type `%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_ignoring_top_level_qualifiers_p (intype, 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))
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)))
{
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)))
pedwarn ("reinterpret_cast from `%T' to `%T' casts away const (or volatile)",
intype, type);
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 ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
expr = decl_constant_value (expr);
return fold (build1 (NOP_EXPR, type, expr));
}
else
{
error ("invalid reinterpret_cast from type `%T' to type `%T'",
intype, type);
return error_mark_node;
}
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (intype) == POINTER_TYPE
&& TYPE_PRECISION (type) > TYPE_PRECISION (intype)
&& TREE_UNSIGNED (type))
expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 1), expr);
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, type, expr);
return t;
}
if (!POINTER_TYPE_P (type))
error ("invalid use of const_cast with type `%T', which is not a pointer, reference, nor a pointer-to-data-member type", type);
else if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
{
error ("invalid use of const_cast with type `%T', which is a pointer or reference to a function type", type);
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_ignoring_top_level_qualifiers_p (intype, type))
return build_static_cast (type, expr);
else if (TREE_CODE (type) == REFERENCE_TYPE)
{
if (! real_lvalue_p (expr))
{
error ("invalid const_cast of an rvalue of type `%T' to type `%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);
error ("invalid const_cast from type `%T' to type `%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 (processing_template_decl)
{
tree t = build_min (CAST_EXPR, type,
tree_cons (NULL_TREE, value, NULL_TREE));
return t;
}
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)
{
pedwarn ("ISO C++ forbids casting to an array type `%T'", type);
type = build_pointer_type (TREE_TYPE (type));
}
else
{
error ("ISO C++ forbids casting to an array type `%T'", type);
return error_mark_node;
}
}
if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
{
error ("invalid cast to function type `%T'", type);
return error_mark_node;
}
if (TREE_CODE (type) == VOID_TYPE)
{
value = convert_to_void (value, NULL);
return value;
}
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)))
warning ("cast from `%T' to `%T' discards qualifiers from pointer target type",
otype, type);
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_CONSTANT (value))
warning ("cast to pointer from integer of different size");
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;
value = decl_constant_value (value);
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TYPE_PRECISION (type) > TYPE_PRECISION (otype)
&& TREE_UNSIGNED (type))
value = convert_force (c_common_type_for_size (POINTER_SIZE, 1),
value,
CONV_C_CAST);
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 (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
&& COMPLETE_TYPE_P (TREE_TYPE (otype))
&& COMPLETE_TYPE_P (TREE_TYPE (type))
&& TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
warning ("cast from `%T' to `%T' increases required alignment of target type",
otype, type);
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;
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:
{
tree cond;
tree preeval = NULL_TREE;
rhs = stabilize_expr (rhs, &preeval);
if (!lvalue_or_else (lhs, "assignment"))
return error_mark_node;
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), preeval, cond);
}
case OFFSET_REF:
lhs = resolve_offset_ref (lhs);
if (lhs == error_mark_node)
return error_mark_node;
olhstype = lhstype = TREE_TYPE (lhs);
default:
break;
}
if (modifycode == INIT_EXPR)
{
if (TREE_CODE (rhs) == CONSTRUCTOR)
{
my_friendly_assert (same_type_p (TREE_TYPE (rhs), lhstype),
20011220);
result = build (INIT_EXPR, lhstype, lhs, rhs);
TREE_SIDE_EFFECTS (result) = 1;
return result;
}
else if (! IS_AGGR_TYPE (lhstype))
;
else
{
result = build_special_member_call (lhs, complete_ctor_identifier,
build_tree_list (NULL_TREE, rhs),
TYPE_BINFO (lhstype),
LOOKUP_NORMAL);
if (result == NULL_TREE)
return error_mark_node;
return result;
}
}
else
{
if (TREE_CODE (lhstype) == REFERENCE_TYPE)
{
lhs = convert_from_reference (lhs);
olhstype = lhstype = TREE_TYPE (lhs);
}
lhs = require_complete_type (lhs);
if (lhs == error_mark_node)
return error_mark_node;
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
{
my_friendly_assert (!PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE),
978652);
lhs = stabilize_reference (lhs);
newrhs = cp_build_binary_op (modifycode, lhs, rhs);
if (newrhs == error_mark_node)
{
error (" in evaluation of `%Q(%#T, %#T)'", modifycode,
TREE_TYPE (lhs), TREE_TYPE (rhs));
return error_mark_node;
}
modifycode = NOP_EXPR;
}
my_friendly_assert (TREE_CODE (lhstype) != REFERENCE_TYPE, 20011220);
my_friendly_assert (TREE_CODE (TREE_TYPE (newrhs)) != REFERENCE_TYPE,
20011220);
}
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:
{
tree inner_lhs = TREE_OPERAND (lhs, 0);
tree result;
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);
if (! lvalue_p (lhs))
pedwarn ("ISO 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;
if (modifycode != INIT_EXPR
&& (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)
|| TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (lhs)) == METHOD_TYPE
|| (IS_AGGR_TYPE_CODE (TREE_CODE (lhstype))
&& C_TYPE_FIELDS_READONLY (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 (TREE_CODE (lhstype) != REFERENCE_TYPE)
{
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 (TYPE_MAIN_VARIANT (lhstype),
TYPE_MAIN_VARIANT (TREE_TYPE (rhs))))
{
error ("incompatible types in assignment of `%T' to `%T'",
TREE_TYPE (rhs), lhstype);
return error_mark_node;
}
if (! DECL_ARTIFICIAL (current_function_decl))
pedwarn ("ISO C++ forbids assignment of arrays");
from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
? 1 + (modifycode != INIT_EXPR): 0;
return build_vec_init (lhs, NULL_TREE, newrhs, from_array);
}
if (modifycode == INIT_EXPR)
newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
"initialization", NULL_TREE, 0);
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_tree_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;
tree virt_binfo;
base_kind kind;
binfo = lookup_base (to, from, ba_check, &kind);
if (kind == bk_inaccessible || kind == bk_ambig)
{
error (" in pointer to member function conversion");
return delta;
}
if (!binfo)
{
if (!force)
{
error_not_base_type (from, to);
error (" in pointer to member conversion");
return delta;
}
binfo = lookup_base (from, to, ba_check, &kind);
if (binfo == 0)
return delta;
virt_binfo = binfo_from_vbase (binfo);
if (virt_binfo)
{
warning ("pointer to member cast via virtual base `%T' of `%T'",
BINFO_TYPE (virt_binfo),
BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
return delta;
}
delta = BINFO_OFFSET (binfo);
delta = cp_convert (ptrdiff_type_node, delta);
delta = cp_build_binary_op (MINUS_EXPR,
integer_zero_node,
delta);
return delta;
}
virt_binfo = binfo_from_vbase (binfo);
if (virt_binfo)
{
if (force)
warning ("pointer to member cast via virtual base `%T' of `%T'",
BINFO_TYPE (virt_binfo),
BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
else
error ("pointer to member conversion via virtual base `%T' of `%T'",
BINFO_TYPE (virt_binfo),
BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
return delta;
}
delta = BINFO_OFFSET (binfo);
return cp_convert (ptrdiff_type_node, delta);
}
tree
build_ptrmemfunc1 (type, delta, pfn)
tree type, delta, pfn;
{
tree u = NULL_TREE;
tree delta_field;
tree pfn_field;
if (flag_apple_kext)
{
tree subtype, pfn_or_delta2_field, idx, idx_field, delta2_field;
tree delta2 = integer_zero_node;
int ixval = 0;
int allconstant = 0, allsimple = 0;
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 (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn)
{
allconstant = TREE_CONSTANT (pfn);
allsimple = !! initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
if (TREE_CODE (pfn) == INTEGER_CST && (TREE_INT_CST_LOW (pfn) & 1))
{
int vt_entry_sz = 4;
tree vt_entry_sz_tree = TYPE_SIZE_UNIT (vtable_entry_type);
if (TREE_CODE (vt_entry_sz_tree) == INTEGER_CST)
vt_entry_sz = TREE_INT_CST_LOW (vt_entry_sz_tree);
ixval = (TREE_INT_CST_LOW (pfn) - 1);
ixval /= vt_entry_sz;
ixval += 2 + 1;
u = tree_cons (delta2_field, delta, NULL_TREE);
}
else
if (TREE_CODE (pfn) == INTEGER_CST && TREE_INT_CST_LOW (pfn) == 0)
{
ixval = 0;
pfn = integer_zero_node;
delta = integer_zero_node;
u = tree_cons (pfn_field, pfn, NULL_TREE);
}
else
{
ixval = -1;
u = tree_cons (pfn_field, pfn, NULL_TREE);
}
}
else
{
abort ();
allconstant = TREE_CONSTANT (delta);
allsimple = !! initializer_constant_valid_p (delta,
TREE_TYPE (delta));
u = tree_cons (delta2_field, delta2, NULL_TREE);
}
delta = convert_and_check (delta_type_node, delta);
idx = convert_and_check (delta_type_node, ssize_int (ixval));
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 = tree_cons (delta_field, delta,
tree_cons (idx_field, idx,
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;
}
pfn_field = TYPE_FIELDS (type);
delta_field = TREE_CHAIN (pfn_field);
delta = convert_and_check (delta_type_node, delta);
u = tree_cons (pfn_field, pfn,
build_tree_list (delta_field, delta));
u = build (CONSTRUCTOR, type, NULL_TREE, u);
TREE_CONSTANT (u) = TREE_CONSTANT (pfn) && TREE_CONSTANT (delta);
TREE_STATIC (u) = (TREE_CONSTANT (u)
&& (initializer_constant_valid_p (pfn, TREE_TYPE (pfn))
!= NULL_TREE)
&& (initializer_constant_valid_p (delta, TREE_TYPE (delta))
!= NULL_TREE));
return u;
}
tree
build_ptrmemfunc (type, pfn, force)
tree type, pfn;
int force;
{
tree fn;
tree pfn_type;
tree to_type;
if (error_operand_p (pfn))
return error_mark_node;
pfn_type = TREE_TYPE (pfn);
to_type = build_ptrmemfunc_type (type);
if (TYPE_PTRMEMFUNC_P (pfn_type))
{
tree delta = NULL_TREE;
tree npfn = NULL_TREE;
tree n;
if (!force
&& !can_convert_arg (to_type, TREE_TYPE (pfn), pfn))
error ("invalid conversion to type `%T' from type `%T'",
to_type, pfn_type);
n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
force);
if (TREE_CODE (pfn) != PTRMEM_CST)
{
if (same_type_p (to_type, pfn_type))
return pfn;
else if (integer_zerop (n))
return build_reinterpret_cast (to_type, pfn);
}
if (TREE_SIDE_EFFECTS (pfn))
pfn = save_expr (pfn);
if (TREE_CODE (pfn) == PTRMEM_CST)
expand_ptrmemfunc_cst (pfn, &delta, &npfn);
else
{
npfn = build_ptrmemfunc_access_expr (pfn, pfn_identifier);
delta = build_ptrmemfunc_access_expr (pfn, delta_identifier);
}
delta = cp_convert (ptrdiff_type_node, delta);
if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_delta)
n = cp_build_binary_op (LSHIFT_EXPR, n, integer_one_node);
delta = cp_build_binary_op (PLUS_EXPR, delta, n);
return build_ptrmemfunc1 (to_type, delta, npfn);
}
if (integer_zerop (pfn))
{
pfn = build_c_cast (type, integer_zero_node);
return build_ptrmemfunc1 (to_type,
integer_zero_node,
pfn);
}
if (type_unknown_p (pfn))
return instantiate_type (type, pfn, tf_error | tf_warning);
fn = TREE_OPERAND (pfn, 0);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
return make_ptrmem_cst (to_type, fn);
}
void
expand_ptrmemfunc_cst (cst, delta, pfn)
tree cst;
tree *delta;
tree *pfn;
{
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_CONTEXT (fn);
ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
*delta = get_delta_difference (fn_class, ptr_class, 0);
if (!DECL_VIRTUAL_P (fn))
*pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
else
{
tree orig_class = DECL_CONTEXT (fn);
tree binfo = binfo_or_else (orig_class, fn_class);
*delta = fold (build (PLUS_EXPR, TREE_TYPE (*delta),
*delta, BINFO_OFFSET (binfo)));
*pfn = DECL_VINDEX (fn);
*pfn = fold (build (MULT_EXPR, integer_type_node, *pfn,
TYPE_SIZE_UNIT (vtable_entry_type)));
switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
{
case ptrmemfunc_vbit_in_pfn:
*pfn = fold (build (PLUS_EXPR, integer_type_node, *pfn,
integer_one_node));
break;
case ptrmemfunc_vbit_in_delta:
*delta = fold (build (LSHIFT_EXPR, TREE_TYPE (*delta),
*delta, integer_one_node));
*delta = fold (build (PLUS_EXPR, TREE_TYPE (*delta),
*delta, integer_one_node));
break;
default:
abort ();
}
*pfn = fold (build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),
*pfn));
}
}
tree
pfn_from_ptrmemfunc (t)
tree t;
{
if (flag_apple_kext)
{
if (TREE_CODE (t) == PTRMEM_CST)
{
tree fn = PTRMEM_CST_MEMBER (t);
if (!DECL_VIRTUAL_P (fn))
return convert (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t)),
build_addr_func (fn));
}
t = build_ptrmemfunc_access_expr (t, pfn_or_delta2_identifier);
return build_ptrmemfunc_access_expr (t, pfn_identifier);
}
if (TREE_CODE (t) == PTRMEM_CST)
{
tree delta;
tree pfn;
expand_ptrmemfunc_cst (t, &delta, &pfn);
if (pfn)
return pfn;
}
return build_ptrmemfunc_access_expr (t, pfn_identifier);
}
tree
dubious_conversion_warnings (type, expr, errtype, fndecl, parmnum)
tree type;
tree expr;
const char *errtype;
tree fndecl;
int parmnum;
{
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
if (ARITHMETIC_TYPE_P (type) && expr == null_node)
{
if (fndecl)
warning ("passing NULL used for non-pointer %s %P of `%D'",
errtype, parmnum, fndecl);
else
warning ("%s to non-pointer type `%T' from NULL", errtype, type);
}
if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
&& TREE_CODE (type) == INTEGER_TYPE)
{
if (fndecl)
warning ("passing `%T' for %s %P of `%D'",
TREE_TYPE (expr), errtype, parmnum, fndecl);
else
warning ("%s to `%T' from `%T'", errtype, type, TREE_TYPE (expr));
}
else if (TREE_UNSIGNED (type) && TREE_CODE (type) != BOOLEAN_TYPE)
{
if (TREE_CODE (expr) == INTEGER_CST
&& TREE_NEGATED_INT (expr))
{
if (fndecl)
warning ("passing negative value `%E' for %s %P of `%D'",
expr, errtype, parmnum, fndecl);
else
warning ("%s of negative value `%E' to `%T'",
errtype, expr, type);
}
overflow_warning (expr);
if (TREE_CONSTANT (expr))
expr = fold (expr);
}
return expr;
}
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)
abort ();
if (TREE_CODE (rhs) == OFFSET_REF)
rhs = resolve_offset_ref (rhs);
if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
rhs = TREE_OPERAND (rhs, 0);
rhstype = TREE_TYPE (rhs);
coder = TREE_CODE (rhstype);
if (rhs == error_mark_node || rhstype == error_mark_node)
return error_mark_node;
if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)
return error_mark_node;
rhs = dubious_conversion_warnings (type, rhs, errtype, fndecl, parmnum);
if (coder == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
return error_mark_node;
}
if (TREE_CODE (rhs) == CONST_DECL)
rhs = DECL_INITIAL (rhs);
if (!can_convert_arg_bad (type, rhstype, rhs))
{
if (!warn_pmf2ptr
&& TYPE_PTR_P (type)
&& TYPE_PTRMEMFUNC_P (rhstype))
rhs = cp_convert (strip_top_quals (type), rhs);
else
{
if (rhstype == unknown_type_node)
instantiate_type (type, rhs, tf_error | tf_warning);
else if (flag_objc
&& (objc_comptypes (type, rhstype, 0) == 1
|| (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (rhstype) == POINTER_TYPE
&& objc_comptypes (TREE_TYPE (type),
TREE_TYPE (rhstype),
0) == 1)))
;
else if (fndecl)
error ("cannot convert `%T' to `%T' for argument `%P' to `%D'",
rhstype, type, parmnum, fndecl);
else
error ("cannot convert `%T' to `%T' in %s", rhstype, type,
errtype);
return error_mark_node;
}
}
return perform_implicit_conversion (strip_top_quals (type), rhs);
}
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)
{
int savew = 0, savee = 0;
if (fndecl)
savew = warningcount, savee = errorcount;
rhs = initialize_reference (type, rhs, NULL_TREE);
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 (IS_AGGR_TYPE (type))
return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
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;
const 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 ();
TREE_VALUE (tail) = o[i];
}
else
{
tree type = TREE_TYPE (o[i]);
if (type != error_mark_node
&& (CP_TYPE_CONST_P (type)
|| (IS_AGGR_TYPE_CODE (TREE_CODE (type))
&& C_TYPE_FIELDS_READONLY (type))))
readonly_error (o[i], "modification by `asm'", 1);
}
}
emit_queue ();
}
static void
maybe_warn_about_returning_address_of_local (retval)
tree retval;
{
tree valtype = TREE_TYPE (DECL_RESULT (current_function_decl));
tree whats_returned = retval;
for (;;)
{
if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
whats_returned = TREE_OPERAND (whats_returned, 1);
else if (TREE_CODE (whats_returned) == CONVERT_EXPR
|| TREE_CODE (whats_returned) == NON_LVALUE_EXPR
|| TREE_CODE (whats_returned) == NOP_EXPR)
whats_returned = TREE_OPERAND (whats_returned, 0);
else
break;
}
if (TREE_CODE (whats_returned) != ADDR_EXPR)
return;
whats_returned = TREE_OPERAND (whats_returned, 0);
if (TREE_CODE (valtype) == REFERENCE_TYPE)
{
if (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");
return;
}
if (TREE_CODE (whats_returned) == VAR_DECL
&& DECL_NAME (whats_returned)
&& TEMP_NAME_P (DECL_NAME (whats_returned)))
{
warning ("reference to non-lvalue returned");
return;
}
}
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)))
{
if (TREE_CODE (valtype) == REFERENCE_TYPE)
cp_warning_at ("reference to local variable `%D' returned",
whats_returned);
else
cp_warning_at ("address of local variable `%D' returned",
whats_returned);
return;
}
}
tree
check_return_expr (retval)
tree retval;
{
tree result;
tree valtype;
int fn_returns_value_p;
if (TREE_THIS_VOLATILE (current_function_decl))
warning ("function declared `noreturn' has a `return' statement");
if (DECL_DESTRUCTOR_P (current_function_decl))
{
if (retval)
error ("returning a value from a destructor");
return NULL_TREE;
}
else if (DECL_CONSTRUCTOR_P (current_function_decl))
{
if (in_function_try_handler)
error ("cannot return from a handler of a function-try-block of a constructor");
else if (retval)
error ("returning a value from a constructor");
return NULL_TREE;
}
result = DECL_RESULT (current_function_decl);
valtype = TREE_TYPE (result);
my_friendly_assert (valtype != NULL_TREE, 19990924);
fn_returns_value_p = !VOID_TYPE_P (valtype);
if (!retval && DECL_NAME (result) && fn_returns_value_p)
retval = result;
if (!retval && fn_returns_value_p)
{
pedwarn ("return-statement with no value, in function declared with a non-void return type");
current_function_returns_null = 0;
}
else if (retval && !fn_returns_value_p)
{
if (VOID_TYPE_P (TREE_TYPE (retval)))
finish_expr_stmt (retval);
else
pedwarn ("return-statement with a value, in function declared with a void return type");
current_function_returns_null = 1;
return NULL_TREE;
}
else if (!retval)
current_function_returns_null = 1;
else
current_function_returns_value = 1;
if ((DECL_OVERLOADED_OPERATOR_P (current_function_decl) == NEW_EXPR
|| DECL_OVERLOADED_OPERATOR_P (current_function_decl) == VEC_NEW_EXPR)
&& !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
&& ! flag_check_new
&& null_ptr_cst_p (retval))
warning ("`operator new' must not return NULL unless it is declared `throw()' (or -fcheck-new is in effect)");
if (warn_ecpp
&& DECL_NAME (current_function_decl) == ansi_assopname(NOP_EXPR)
&& retval != current_class_ref)
warning ("`operator=' should return a reference to `*this'");
if (fn_returns_value_p && flag_elide_constructors)
{
if (retval != NULL_TREE
&& (current_function_return_value == NULL_TREE
|| current_function_return_value == retval)
&& TREE_CODE (retval) == VAR_DECL
&& DECL_CONTEXT (retval) == current_function_decl
&& ! TREE_STATIC (retval)
&& (DECL_ALIGN (retval)
>= DECL_ALIGN (DECL_RESULT (current_function_decl)))
&& same_type_p ((TYPE_MAIN_VARIANT
(TREE_TYPE (retval))),
(TYPE_MAIN_VARIANT
(TREE_TYPE (TREE_TYPE (current_function_decl))))))
current_function_return_value = retval;
else
current_function_return_value = error_mark_node;
}
if (!retval || retval == error_mark_node)
return retval;
if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl))
;
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)
return retval;
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
maybe_warn_about_returning_address_of_local (retval);
}
if (retval && retval != result)
retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
return retval;
}
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_ignoring_top_level_qualifiers_p (to, 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) == VOID_TYPE
|| TREE_CODE (from) == VOID_TYPE)
return 1;
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) == INTEGER_TYPE
&& TYPE_PRECISION (to) == TYPE_PRECISION (from))
return 1;
if (TREE_CODE (to) == FUNCTION_TYPE)
return 1;
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_ignoring_top_level_qualifiers_p (to, 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;
{
type = strip_array_types (type);
if (type == error_mark_node)
return TYPE_UNQUALIFIED;
return TYPE_QUALS (type);
}
int
cp_has_mutable_p (type)
tree type;
{
type = strip_array_types (type);
return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
}
static void
casts_away_constness_r (t1, t2)
tree *t1;
tree *t2;
{
int quals1;
int quals2;
if (TYPE_PTRMEM_P (*t1))
*t1 = build_pointer_type (TREE_TYPE (TREE_TYPE (*t1)));
if (TYPE_PTRMEM_P (*t2))
*t2 = build_pointer_type (TREE_TYPE (TREE_TYPE (*t2)));
if (TREE_CODE (*t1) != POINTER_TYPE
|| TREE_CODE (*t2) != POINTER_TYPE)
{
*t1 = cp_build_qualified_type (void_type_node,
cp_type_quals (*t1));
*t2 = cp_build_qualified_type (void_type_node,
cp_type_quals (*t2));
return;
}
quals1 = cp_type_quals (*t1);
quals2 = cp_type_quals (*t2);
*t1 = TREE_TYPE (*t1);
*t2 = TREE_TYPE (*t2);
casts_away_constness_r (t1, t2);
*t1 = build_pointer_type (*t1);
*t2 = build_pointer_type (*t2);
*t1 = cp_build_qualified_type (*t1, quals1);
*t2 = cp_build_qualified_type (*t2, quals2);
}
static int
casts_away_constness (t1, t2)
tree t1;
tree t2;
{
if (TREE_CODE (t2) == REFERENCE_TYPE)
{
t1 = (TREE_CODE (t1) == REFERENCE_TYPE
? TREE_TYPE (t1) : t1);
return casts_away_constness (build_pointer_type (t1),
build_pointer_type (TREE_TYPE (t2)));
}
if (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
return casts_away_constness
(build_pointer_type (TREE_TYPE (TREE_TYPE (t1))),
build_pointer_type (TREE_TYPE (TREE_TYPE (t2))));
if (TREE_CODE (t1) != POINTER_TYPE
|| TREE_CODE (t2) != POINTER_TYPE)
return 0;
t1 = TYPE_MAIN_VARIANT (t1);
t2 = TYPE_MAIN_VARIANT (t2);
casts_away_constness_r (&t1, &t2);
if (!can_convert (t2, t1))
return 1;
return 0;
}
static tree
strip_all_pointer_quals (type)
tree type;
{
if (TREE_CODE (type) == POINTER_TYPE)
return build_pointer_type (strip_all_pointer_quals (TREE_TYPE (type)));
else if (TREE_CODE (type) == OFFSET_TYPE)
return build_offset_type (TYPE_OFFSET_BASETYPE (type),
strip_all_pointer_quals (TREE_TYPE (type)));
else
return TYPE_MAIN_VARIANT (type);
}