#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.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"
#include "convert.h"
#include "c-common.h"
static tree pfn_from_ptrmemfunc (tree);
static tree convert_for_assignment (tree, tree, const char *, tree, int);
static tree cp_pointer_int_sum (enum tree_code, tree, tree);
static tree rationalize_conditional_expr (enum tree_code, tree);
static int comp_ptr_ttypes_real (tree, tree, int);
static bool comp_except_types (tree, tree, bool);
static bool comp_array_types (tree, tree, bool);
static tree common_base_type (tree, tree);
static tree pointer_diff (tree, tree, tree);
static tree get_delta_difference (tree, tree, bool, bool);
static void casts_away_constness_r (tree *, tree *);
static bool casts_away_constness (tree, tree);
static void maybe_warn_about_returning_address_of_local (tree);
static tree lookup_destructor (tree, tree, tree);
static tree convert_arguments (tree, tree, tree, int, int);
tree
require_complete_type (tree value)
{
tree type;
if (processing_template_decl || value == error_mark_node)
return value;
if (TREE_CODE (value) == OVERLOAD)
type = unknown_type_node;
else
type = TREE_TYPE (value);
if (type == error_mark_node)
return error_mark_node;
if (COMPLETE_TYPE_P (type))
return value;
if (complete_type_or_else (type, value))
return value;
else
return error_mark_node;
}
tree
complete_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));
unsigned int needs_constructing, has_nontrivial_dtor;
if (COMPLETE_TYPE_P (t) && !dependent_type_p (type))
layout_type (type);
needs_constructing
= TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
has_nontrivial_dtor
= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (t));
for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
{
TYPE_NEEDS_CONSTRUCTING (t) = needs_constructing;
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = has_nontrivial_dtor;
}
}
else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
instantiate_class_template (TYPE_MAIN_VARIANT (type));
return type;
}
tree
complete_type_or_else (tree type, tree value)
{
type = complete_type (type);
if (type == error_mark_node)
return NULL_TREE;
else if (!COMPLETE_TYPE_P (type))
{
cxx_incomplete_type_diagnostic (value, type, 0);
return NULL_TREE;
}
else
return type;
}
int
type_unknown_p (tree exp)
{
return (TREE_CODE (exp) == TREE_LIST
|| TREE_TYPE (exp) == unknown_type_node);
}
static tree
commonparms (tree p1, tree 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;
}
static tree
original_type (tree t)
{
int quals = cp_type_quals (t);
while (t != error_mark_node
&& 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;
if (x == t)
break;
t = x;
}
return cp_build_qualified_type (t, quals);
}
tree
type_after_usual_arithmetic_conversions (tree t1, tree t2)
{
enum tree_code code1 = TREE_CODE (t1);
enum tree_code code2 = TREE_CODE (t2);
tree attributes;
gcc_assert (ARITHMETIC_TYPE_P (t1)
|| TREE_CODE (t1) == VECTOR_TYPE
|| TREE_CODE (t1) == ENUMERAL_TYPE);
gcc_assert (ARITHMETIC_TYPE_P (t2)
|| TREE_CODE (t2) == VECTOR_TYPE
|| TREE_CODE (t2) == ENUMERAL_TYPE);
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 == VECTOR_TYPE)
{
if (TYPE_UNSIGNED (t1))
return build_type_attribute_variant (t1, attributes);
else
return build_type_attribute_variant (t2, 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 = ((TYPE_UNSIGNED (t1) || TYPE_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 = ((TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
? long_unsigned_type_node : long_integer_type_node);
return build_type_attribute_variant (t, attributes);
}
if (TYPE_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);
}
}
static tree
composite_pointer_type_r (tree t1, tree t2, const char* location)
{
tree pointee1;
tree pointee2;
tree result_type;
tree attributes;
if (TREE_CODE (t1) == POINTER_TYPE || TREE_CODE (t1) == BLOCK_POINTER_TYPE)
{
pointee1 = TREE_TYPE (t1);
pointee2 = TREE_TYPE (t2);
}
else
{
pointee1 = TYPE_PTRMEM_POINTED_TO_TYPE (t1);
pointee2 = TYPE_PTRMEM_POINTED_TO_TYPE (t2);
}
if (same_type_ignoring_top_level_qualifiers_p (pointee1, pointee2))
result_type = pointee1;
else if ((TREE_CODE (pointee1) == POINTER_TYPE
&& TREE_CODE (pointee2) == POINTER_TYPE)
|| (TYPE_PTR_TO_MEMBER_P (pointee1)
&& TYPE_PTR_TO_MEMBER_P (pointee2)))
result_type = composite_pointer_type_r (pointee1, pointee2, location);
else
{
pedwarn ("%s between distinct pointer types %qT and %qT "
"lacks a cast",
location, t1, t2);
result_type = void_type_node;
}
result_type = cp_build_qualified_type (result_type,
(cp_type_quals (pointee1)
| cp_type_quals (pointee2)));
if (TYPE_PTR_TO_MEMBER_P (t1))
{
if (!same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
TYPE_PTRMEM_CLASS_TYPE (t2)))
pedwarn ("%s between distinct pointer types %qT and %qT "
"lacks a cast",
location, t1, t2);
result_type = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
result_type);
}
else if (TREE_CODE (t1) == BLOCK_POINTER_TYPE
&& result_type != void_type_node)
result_type = build_block_pointer_type (result_type);
else
result_type = build_pointer_type (result_type);
attributes = (*targetm.merge_type_attributes) (t1, t2);
return build_type_attribute_variant (result_type, attributes);
}
tree
composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
const char* location)
{
tree class1;
tree class2;
if (null_ptr_cst_p (arg1))
return t2;
if (null_ptr_cst_p (arg2))
return t1;
if (TREE_CODE (t2) == POINTER_TYPE && VOID_TYPE_P (TREE_TYPE (t2)))
{
tree t;
t = t1;
t1 = t2;
t2 = t;
}
if (TREE_CODE (t1) == POINTER_TYPE && VOID_TYPE_P (TREE_TYPE (t1)))
{
tree attributes;
tree result_type;
if (pedantic && TYPE_PTRFN_P (t2))
pedwarn ("ISO C++ forbids %s between pointer of type %<void *%> "
"and pointer-to-function", location);
result_type
= cp_build_qualified_type (void_type_node,
(cp_type_quals (TREE_TYPE (t1))
| cp_type_quals (TREE_TYPE (t2))));
result_type = build_pointer_type (result_type);
attributes = (*targetm.merge_type_attributes) (t1, t2);
return build_type_attribute_variant (result_type, attributes);
}
if (c_dialect_objc () && TREE_CODE (t1) == POINTER_TYPE
&& TREE_CODE (t2) == POINTER_TYPE)
{
if (objc_have_common_type (t1, t2, -3, NULL_TREE, location))
return objc_common_type (t1, t2);
}
if (TREE_CODE (t1) == POINTER_TYPE && TREE_CODE (t2) == POINTER_TYPE
&& CLASS_TYPE_P (TREE_TYPE (t1))
&& CLASS_TYPE_P (TREE_TYPE (t2))
&& !same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (t1),
TREE_TYPE (t2)))
{
class1 = TREE_TYPE (t1);
class2 = TREE_TYPE (t2);
if (DERIVED_FROM_P (class1, class2))
t2 = (build_pointer_type
(cp_build_qualified_type (class1, TYPE_QUALS (class2))));
else if (DERIVED_FROM_P (class2, class1))
t1 = (build_pointer_type
(cp_build_qualified_type (class2, TYPE_QUALS (class1))));
else
{
error ("%s between distinct pointer types %qT and %qT "
"lacks a cast", location, t1, t2);
return error_mark_node;
}
}
else if (TYPE_PTR_TO_MEMBER_P (t1)
&& !same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
TYPE_PTRMEM_CLASS_TYPE (t2)))
{
class1 = TYPE_PTRMEM_CLASS_TYPE (t1);
class2 = TYPE_PTRMEM_CLASS_TYPE (t2);
if (DERIVED_FROM_P (class1, class2))
t1 = build_ptrmem_type (class2, TYPE_PTRMEM_POINTED_TO_TYPE (t1));
else if (DERIVED_FROM_P (class2, class1))
t2 = build_ptrmem_type (class1, TYPE_PTRMEM_POINTED_TO_TYPE (t2));
else
{
error ("%s between distinct pointer-to-member types %qT and %qT "
"lacks a cast", location, t1, t2);
return error_mark_node;
}
}
else if (TREE_CODE (t1) != TREE_CODE (t2))
{
error ("%s between distinct pointer types %qT and %qT "
"lacks a cast", location, t1, t2);
return error_mark_node;
}
return composite_pointer_type_r (t1, t2, location);
}
tree
merge_types (tree t1, tree t2)
{
enum tree_code code1;
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:
{
int quals;
tree pointee;
quals = cp_type_quals (t1);
pointee = merge_types (TYPE_PTRMEM_POINTED_TO_TYPE (t1),
TYPE_PTRMEM_POINTED_TO_TYPE (t2));
t1 = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
pointee);
t1 = cp_build_qualified_type (t1, quals);
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 cp_build_type_attribute_variant (t1, attributes);
if (valtype == TREE_TYPE (t2) && ! p1)
return cp_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 cp_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 cp_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_method_type_directly (basetype, TREE_TYPE (t3),
TYPE_ARG_TYPES (t3));
t1 = build_exception_variant (t3, raises);
break;
}
case TYPENAME_TYPE:
return t1;
default:;
}
if (attribute_list_equal (TYPE_ATTRIBUTES (t1), attributes))
return t1;
else if (attribute_list_equal (TYPE_ATTRIBUTES (t2), attributes))
return t2;
else
return cp_build_type_attribute_variant (t1, attributes);
}
tree
common_type (tree t1, tree 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 == VECTOR_TYPE)
&& (ARITHMETIC_TYPE_P (t2) || code2 == ENUMERAL_TYPE
|| code2 == VECTOR_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
gcc_unreachable ();
}
static bool
comp_except_types (tree a, tree b, bool exact)
{
if (same_type_p (a, b))
return true;
else if (!exact)
{
if (cp_type_quals (a) || cp_type_quals (b))
return false;
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 false;
}
if (TREE_CODE (a) != RECORD_TYPE
|| TREE_CODE (b) != RECORD_TYPE)
return false;
if (PUBLICLY_UNIQUELY_DERIVED_P (a, b))
return true;
}
return false;
}
bool
comp_except_specs (tree t1, tree t2, bool exact)
{
tree probe;
tree base;
int length = 0;
if (t1 == t2)
return true;
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 false;
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 false;
}
return !exact || base == NULL_TREE || length == list_length (t1);
}
static bool
comp_array_types (tree t1, tree t2, bool allow_redeclaration)
{
tree d1;
tree d2;
tree max1, max2;
if (t1 == t2)
return true;
if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
return false;
d1 = TYPE_DOMAIN (t1);
d2 = TYPE_DOMAIN (t2);
if (d1 == d2)
return true;
if (!d1 || !d2)
return allow_redeclaration;
if (!cp_tree_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2)))
return false;
max1 = TYPE_MAX_VALUE (d1);
max2 = TYPE_MAX_VALUE (d2);
if (processing_template_decl && !abi_version_at_least (2)
&& !value_dependent_expression_p (max1)
&& !value_dependent_expression_p (max2))
{
max1 = fold (max1);
max2 = fold (max2);
}
if (!cp_tree_equal (max1, max2))
return false;
return true;
}
bool
comptypes (tree t1, tree t2, int strict)
{
if (t1 == t2)
return true;
if (t1 == error_mark_node || t2 == error_mark_node)
return false;
gcc_assert (TYPE_P (t1) && TYPE_P (t2));
if (TREE_CODE (t1) == TYPENAME_TYPE)
{
tree resolved = resolve_typename_type (t1, true);
if (resolved != error_mark_node)
t1 = resolved;
}
if (TREE_CODE (t2) == TYPENAME_TYPE)
{
tree resolved = resolve_typename_type (t2, true);
if (resolved != error_mark_node)
t2 = resolved;
}
if (TREE_CODE (t1) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t1)
&& TYPE_ORIG_SIZE_TYPE (t1))
t1 = TYPE_ORIG_SIZE_TYPE (t1);
if (TREE_CODE (t2) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t2)
&& TYPE_ORIG_SIZE_TYPE (t2))
t2 = TYPE_ORIG_SIZE_TYPE (t2);
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 false;
if (TREE_CODE (t1) != ARRAY_TYPE
&& TYPE_QUALS (t1) != TYPE_QUALS (t2))
return false;
if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
return false;
if (TREE_CODE (t1) != ARRAY_TYPE
&& TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return true;
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 false;
if (!comp_template_parms
(DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t1)),
DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2))))
return false;
if (TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM)
break;
strict = COMPARE_STRICT;
case RECORD_TYPE:
case UNION_TYPE:
if (TYPE_TEMPLATE_INFO (t1) && TYPE_TEMPLATE_INFO (t2)
&& (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
|| TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM)
&& comp_template_args (TYPE_TI_ARGS (t1), TYPE_TI_ARGS (t2)))
break;
if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
break;
else if ((strict & COMPARE_DERIVED) && DERIVED_FROM_P (t2, t1))
break;
return false;
case OFFSET_TYPE:
if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2),
strict & ~COMPARE_REDECLARATION))
return false;
if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
return false;
break;
case BLOCK_POINTER_TYPE:
if (TREE_CODE (t2) == BLOCK_POINTER_TYPE)
{
tree pt1 = TREE_TYPE (t1);
tree pt2 = TREE_TYPE (t2);
if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (pt1),
TREE_TYPE (pt2)))
return false;
if (!compparms (TYPE_ARG_TYPES (pt1), TYPE_ARG_TYPES (pt2)))
return false;
break;
}
case POINTER_TYPE:
case REFERENCE_TYPE:
if (TYPE_MODE (t1) != TYPE_MODE (t2)
|| TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)
|| !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
return false;
break;
case METHOD_TYPE:
case FUNCTION_TYPE:
if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
return false;
if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)))
return false;
break;
case ARRAY_TYPE:
if (!comp_array_types (t1, t2, !!(strict & COMPARE_REDECLARATION)))
return false;
break;
case TEMPLATE_TYPE_PARM:
if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
|| TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
return false;
break;
case TYPENAME_TYPE:
if (!cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1),
TYPENAME_TYPE_FULLNAME (t2)))
return false;
if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
return false;
break;
case UNBOUND_CLASS_TEMPLATE:
if (!cp_tree_equal (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2)))
return false;
if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
return false;
break;
case COMPLEX_TYPE:
if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
return false;
break;
case VECTOR_TYPE:
if (TYPE_VECTOR_SUBPARTS (t1) != TYPE_VECTOR_SUBPARTS (t2)
|| !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
return false;
break;
default:
return false;
}
return targetm.comp_type_attributes (t1, t2);
}
bool
at_least_as_qualified_p (tree type1, tree type2)
{
int q1 = cp_type_quals (type1);
int q2 = cp_type_quals (type2);
return (q1 & q2) == q2;
}
int
comp_cv_qualification (tree type1, tree type2)
{
int q1 = cp_type_quals (type1);
int q2 = cp_type_quals (type2);
if (q1 == q2)
return 0;
if ((q1 & q2) == q2)
return 1;
else if ((q1 & q2) == q1)
return -1;
return 0;
}
int
comp_cv_qual_signature (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 (tree tt1, tree 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 = BINFO_N_BASE_BINFOS (TYPE_BINFO (tt1))-1; i >= 0; i--)
{
tree basetype = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (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 = BINFO_N_BASE_BINFOS (TYPE_BINFO (tt2))-1; i >= 0; i--)
{
tree basetype = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (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;
}
bool
compparms (tree parms1, tree parms2)
{
tree t1, t2;
for (t1 = parms1, t2 = parms2;
t1 || t2;
t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
{
if (!t1 || !t2)
return false;
if (!same_type_p (TREE_VALUE (t1), TREE_VALUE (t2)))
return false;
}
return true;
}
tree
cxx_sizeof_or_alignof_type (tree type, enum tree_code op, bool complain)
{
tree value;
bool dependent_p;
gcc_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR);
if (type == error_mark_node)
return error_mark_node;
type = non_reference (type);
if (TREE_CODE (type) == METHOD_TYPE)
{
if (complain && (pedantic || warn_pointer_arith))
pedwarn ("invalid application of %qs to a member function",
operator_name_info[(int) op].name);
value = size_one_node;
}
dependent_p = dependent_type_p (type);
if (!dependent_p)
complete_type (type);
if (dependent_p
|| (processing_template_decl
&& COMPLETE_TYPE_P (type)
&& TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST))
{
value = build_min (op, size_type_node, type);
TREE_READONLY (value) = 1;
return value;
}
return c_sizeof_or_alignof_type (complete_type (type),
op == SIZEOF_EXPR,
complain);
}
static tree
cxx_sizeof_expr (tree e)
{
if (e == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
e = build_min (SIZEOF_EXPR, size_type_node, e);
TREE_SIDE_EFFECTS (e) = 0;
TREE_READONLY (e) = 1;
return e;
}
if (TREE_CODE (e) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
{
error ("invalid application of %<sizeof%> to a bit-field");
e = char_type_node;
}
else if (is_overloaded_fn (e))
{
pedwarn ("ISO C++ forbids applying %<sizeof%> to an expression of "
"function type");
e = char_type_node;
}
else if (type_unknown_p (e))
{
cxx_incomplete_type_error (e, TREE_TYPE (e));
e = char_type_node;
}
else
e = TREE_TYPE (e);
return cxx_sizeof_or_alignof_type (e, SIZEOF_EXPR, true);
}
static tree
cxx_alignof_expr (tree e)
{
tree t;
if (e == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
e = build_min (ALIGNOF_EXPR, size_type_node, e);
TREE_SIDE_EFFECTS (e) = 0;
TREE_READONLY (e) = 1;
return e;
}
if (TREE_CODE (e) == VAR_DECL)
t = size_int (DECL_ALIGN_UNIT (e));
else if (TREE_CODE (e) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
{
error ("invalid application of %<__alignof%> to a bit-field");
t = size_one_node;
}
else if (TREE_CODE (e) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL)
t = size_int (DECL_ALIGN_UNIT (TREE_OPERAND (e, 1)));
else if (is_overloaded_fn (e))
{
pedwarn ("ISO C++ forbids applying %<__alignof%> to an expression of "
"function type");
if (TREE_CODE (e) == FUNCTION_DECL)
t = size_int (DECL_ALIGN_UNIT (e));
else
t = size_one_node;
}
else if (type_unknown_p (e))
{
cxx_incomplete_type_error (e, TREE_TYPE (e));
t = size_one_node;
}
else
return cxx_sizeof_or_alignof_type (TREE_TYPE (e), ALIGNOF_EXPR, true);
return fold_convert (size_type_node, t);
}
tree
cxx_sizeof_or_alignof_expr (tree e, enum tree_code op)
{
if (op == SIZEOF_EXPR)
return cxx_sizeof_expr (e);
else
return cxx_alignof_expr (e);
}
bool
invalid_nonstatic_memfn_p (tree expr)
{
if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE)
{
error ("invalid use of non-static member function");
return true;
}
return false;
}
tree
is_bitfield_expr_with_lowered_type (tree exp)
{
switch (TREE_CODE (exp))
{
case COND_EXPR:
if (!is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1)))
return NULL_TREE;
return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 2));
case COMPOUND_EXPR:
return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1));
case MODIFY_EXPR:
case SAVE_EXPR:
return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
case COMPONENT_REF:
{
tree field;
field = TREE_OPERAND (exp, 1);
if (TREE_CODE (field) != FIELD_DECL || !DECL_C_BIT_FIELD (field))
return NULL_TREE;
if (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (exp), DECL_BIT_FIELD_TYPE (field)))
return NULL_TREE;
return DECL_BIT_FIELD_TYPE (field);
}
default:
return NULL_TREE;
}
}
tree
unlowered_expr_type (tree exp)
{
tree type;
type = is_bitfield_expr_with_lowered_type (exp);
if (!type)
type = TREE_TYPE (exp);
return type;
}
tree
decay_conversion (tree exp)
{
tree type;
enum tree_code code;
type = TREE_TYPE (exp);
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;
}
exp = decl_constant_value (exp);
if (error_operand_p (exp))
return error_mark_node;
code = TREE_CODE (type);
if (code == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
return error_mark_node;
}
if (invalid_nonstatic_memfn_p (exp))
return error_mark_node;
if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
return build_unary_op (ADDR_EXPR, exp, 0);
if (code == ARRAY_TYPE)
{
tree adr;
tree ptrtype;
if (TREE_CODE (exp) == INDIRECT_REF)
return build_nop (build_pointer_type (TREE_TYPE (type)),
TREE_OPERAND (exp, 0));
if (TREE_CODE (exp) == COMPOUND_EXPR)
{
tree op1 = decay_conversion (TREE_OPERAND (exp, 1));
return build2 (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)
{
if (!cxx_mark_addressable (exp))
return error_mark_node;
adr = build_nop (ptrtype, build_address (exp));
return adr;
}
adr = build_unary_op (ADDR_EXPR, exp, 1);
return cp_convert (ptrtype, adr);
}
exp = convert_bitfield_to_declared_type (exp);
type = TREE_TYPE (exp);
if (!CLASS_TYPE_P (type) && cp_type_quals (type))
exp = build_nop (TYPE_MAIN_VARIANT (type), exp);
return exp;
}
tree
default_conversion (tree exp)
{
if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (exp)))
exp = perform_integral_promotions (exp);
exp = decay_conversion (exp);
return exp;
}
tree
perform_integral_promotions (tree expr)
{
tree type;
tree promoted_type;
type = is_bitfield_expr_with_lowered_type (expr);
if (!type || TREE_CODE (type) != ENUMERAL_TYPE)
type = TREE_TYPE (expr);
gcc_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type));
promoted_type = type_promotes_to (type);
if (type != promoted_type)
expr = cp_convert (promoted_type, expr);
return expr;
}
tree
inline_conversion (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 (tree totype, tree exp, int warn)
{
tree t;
if (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)
warning (OPT_Wwrite_strings,
"deprecated conversion from string constant to %qT",
totype);
return 1;
}
static tree
rationalize_conditional_expr (enum tree_code code, tree t)
{
if (TREE_CODE (t) == MIN_EXPR || TREE_CODE (t) == MAX_EXPR)
{
gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0))
&& !TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)));
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),
NULL),
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));
}
tree
lookup_anon_field (tree t, tree 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 (error_operand_p (object) || error_operand_p (member))
return error_mark_node;
gcc_assert (DECL_P (member) || BASELINK_P (member));
if (DECL_P (member)
&& (result = objc_v2_build_ivar_ref (object, DECL_NAME (member))))
return result;
object_type = TREE_TYPE (object);
if (!currently_open_class (object_type)
&& !complete_type_or_else (object_type, object))
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
error ("request for member %qD in %qE, which is of non-class type %qT",
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))
{
if (TREE_CODE (member) == FIELD_DECL)
error ("invalid use of nonstatic data member %qE", member);
else
error ("%qD is not a member of %qT", member, object_type);
return error_mark_node;
}
{
tree temp = unary_complex_lvalue (ADDR_EXPR, object);
if (temp)
object = build_indirect_ref (temp, NULL);
}
if (TREE_CODE (member) == VAR_DECL)
{
result = member;
if (TREE_SIDE_EFFECTS (object))
result = build2 (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 (TYPE_MAIN_VARIANT (object_type),
TYPE_MAIN_VARIANT (member_scope)))
{
tree binfo;
base_kind kind;
binfo = lookup_base (access_path ? access_path : object_type,
member_scope, ba_unique, &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 %qD 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);
gcc_assert (object != error_mark_node);
}
if (null_object_p && warn_invalid_offsetof
&& CLASSTYPE_NON_POD_P (object_type)
&& !DECL_FIELD_IS_BASE (member)
&& !skip_evaluation)
{
warning (0, "invalid access to non-static data member %qD of NULL object",
member);
warning (0, "(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 = build3 (COMPONENT_REF, member_type, object, member,
NULL_TREE);
objc_volatilize_component_ref (result, TREE_TYPE (member));
result = fold_if_not_in_template (result);
if (type_quals & TYPE_QUAL_CONST)
TREE_READONLY (result) = 1;
if (type_quals & TYPE_QUAL_VOLATILE)
TREE_THIS_VOLATILE (result) = 1;
}
else if (BASELINK_P (member))
{
tree functions;
tree type;
functions = BASELINK_FUNCTIONS (member);
if (TREE_CODE (functions) == FUNCTION_DECL
&& DECL_STATIC_FUNCTION_P (functions))
type = TREE_TYPE (functions);
else
type = unknown_type_node;
result = build3 (COMPONENT_REF, type, object, member, NULL_TREE);
}
else if (TREE_CODE (member) == CONST_DECL)
{
result = member;
if (TREE_SIDE_EFFECTS (object))
result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
object, result);
}
else
{
error ("invalid use of %qD", member);
return error_mark_node;
}
if (!preserve_reference)
result = convert_from_reference (result);
return result;
}
static tree
lookup_destructor (tree object, tree scope, tree dtor_name)
{
tree object_type = TREE_TYPE (object);
tree dtor_type = TREE_OPERAND (dtor_name, 0);
tree expr;
if (scope && !check_dtor_name (scope, dtor_type))
{
error ("qualified type %qT does not match destructor name ~%qT",
scope, dtor_type);
return error_mark_node;
}
if (!DERIVED_FROM_P (dtor_type, TYPE_MAIN_VARIANT (object_type)))
{
error ("the type being destroyed is %qT, but the destructor refers to %qT",
TYPE_MAIN_VARIANT (object_type), dtor_type);
return error_mark_node;
}
expr = lookup_member (dtor_type, complete_dtor_identifier,
1, false);
expr = (adjust_result_of_qualified_name_lookup
(expr, dtor_type, object_type));
return expr;
}
void
check_template_keyword (tree decl)
{
if (TREE_CODE (decl) != TEMPLATE_DECL
&& TREE_CODE (decl) != TEMPLATE_ID_EXPR)
{
if (!is_overloaded_fn (decl))
pedwarn ("%qD is not a template", decl);
else
{
tree fns;
fns = decl;
if (BASELINK_P (fns))
fns = BASELINK_FUNCTIONS (fns);
while (fns)
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) == TEMPLATE_DECL
|| TREE_CODE (fn) == TEMPLATE_ID_EXPR)
break;
if (TREE_CODE (fn) == FUNCTION_DECL
&& DECL_USE_TEMPLATE (fn)
&& PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (fn)))
break;
fns = OVL_NEXT (fns);
}
if (!fns)
pedwarn ("%qD is not a template", decl);
}
}
}
tree
finish_class_member_access_expr (tree object, tree name, bool template_p)
{
tree expr;
tree object_type;
tree member;
tree access_path = NULL_TREE;
tree orig_object = object;
tree orig_name = name;
if (object == error_mark_node || name == error_mark_node)
return error_mark_node;
if (!objc_is_public (object, name))
return error_mark_node;
if (!processing_template_decl)
{
if (TREE_CODE (name) == IDENTIFIER_NODE
&& (expr = objc_build_property_reference_expr (object, name)))
return expr;
else if (objc_property_reference_expr (object))
object = objc_build_property_getter_func_call (object);
}
object_type = TREE_TYPE (object);
if (processing_template_decl)
{
if (
dependent_type_p (object_type)
|| TREE_CODE (object) == IDENTIFIER_NODE
|| (TREE_CODE (name) == TEMPLATE_ID_EXPR
&& dependent_template_id_p (TREE_OPERAND (name, 0),
TREE_OPERAND (name, 1)))
|| (TREE_CODE (name) == SCOPE_REF
&& TYPE_P (TREE_OPERAND (name, 0))
&& dependent_type_p (TREE_OPERAND (name, 0))))
return build_min_nt (COMPONENT_REF, object, name, NULL_TREE);
object = build_non_dependent_expr (object);
}
if (!currently_open_class (object_type)
&& !complete_type_or_else (object_type, object))
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
error ("request for member %qD in %qE, which is of non-class type %qT",
name, object, object_type);
return error_mark_node;
}
if (BASELINK_P (name))
member = name;
else
{
bool is_template_id = false;
tree template_args = NULL_TREE;
tree scope;
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) == OVERLOAD)
name = DECL_NAME (get_first_fn (name));
else if (DECL_P (name))
name = DECL_NAME (name);
}
if (TREE_CODE (name) == SCOPE_REF)
{
scope = TREE_OPERAND (name, 0);
name = TREE_OPERAND (name, 1);
if (TREE_CODE (scope) == NAMESPACE_DECL)
{
error ("%<%D::%D%> is not a member of %qT",
scope, name, object_type);
return error_mark_node;
}
gcc_assert (CLASS_TYPE_P (scope));
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE
|| TREE_CODE (name) == BIT_NOT_EXPR);
access_path = lookup_base (object_type, scope, ba_check, NULL);
if (access_path == error_mark_node)
return error_mark_node;
if (!access_path)
{
error ("%qT is not a base of %qT", scope, object_type);
return error_mark_node;
}
}
else
{
scope = NULL_TREE;
access_path = object_type;
}
if (TREE_CODE (name) == BIT_NOT_EXPR)
member = lookup_destructor (object, scope, name);
else
{
member = lookup_member (access_path, name, 1,
false);
if (member == NULL_TREE)
{
error ("%qD has no member named %qE", object_type, name);
return error_mark_node;
}
if (member == error_mark_node)
return error_mark_node;
}
if (is_template_id)
{
tree template = member;
if (BASELINK_P (template))
template = lookup_template_function (template, template_args);
else
{
error ("%qD is not a member template function", name);
return error_mark_node;
}
}
}
if (TREE_DEPRECATED (member))
warn_deprecated_use (member);
if (template_p)
check_template_keyword (member);
expr = build_class_member_access_expr (object, member, access_path,
false);
if (processing_template_decl && expr != error_mark_node)
{
if (BASELINK_P (member))
{
if (TREE_CODE (orig_name) == SCOPE_REF)
BASELINK_QUALIFIED_P (member) = 1;
orig_name = member;
}
return build_min_non_dep (COMPONENT_REF, expr,
orig_object, orig_name,
NULL_TREE);
}
return expr;
}
tree
build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
{
tree ptrmem_type;
tree member;
tree member_type;
ptrmem_type = TREE_TYPE (ptrmem);
if (TARGET_KEXTABI != 1)
gcc_assert (TYPE_PTRMEMFUNC_P (ptrmem_type));
member = lookup_member (ptrmem_type, member_name, 0,
false);
member_type = cp_build_qualified_type (TREE_TYPE (member),
cp_type_quals (ptrmem_type));
return fold_build3 (COMPONENT_REF, member_type,
ptrmem, member, NULL_TREE);
}
tree
build_x_indirect_ref (tree expr, const char *errorstring)
{
tree orig_expr = expr;
tree rval;
if (processing_template_decl)
{
if (type_dependent_expression_p (expr))
return build_min_nt (INDIRECT_REF, expr);
expr = build_non_dependent_expr (expr);
}
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
NULL_TREE, NULL);
if (!rval)
rval = build_indirect_ref (expr, errorstring);
if (processing_template_decl && rval != error_mark_node)
return build_min_non_dep (INDIRECT_REF, rval, orig_expr);
else
return rval;
}
tree
build_indirect_ref (tree ptr, const char *errorstring)
{
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 : decay_conversion (ptr));
type = TREE_TYPE (pointer);
if (POINTER_TYPE_P (type))
{
tree t = canonical_type_variant (TREE_TYPE (type));
if (VOID_TYPE_P (t))
{
error ("%qT is not a pointer-to-object type", type);
return error_mark_node;
}
else if (TREE_CODE (pointer) == ADDR_EXPR
&& 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));
return ref;
}
}
else if (TYPE_PTR_TO_MEMBER_P (type))
error ("invalid use of %qs on pointer to member", errorstring);
else if (pointer != error_mark_node)
{
if (errorstring)
error ("invalid type argument of %qs", errorstring);
else
error ("invalid type argument");
}
return error_mark_node;
}
tree
build_array_ref (tree array, tree 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 build2 (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 rval, type;
warn_array_subscript_with_type_char (idx);
if (!INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (idx)))
{
error ("array subscript is not an integer");
return error_mark_node;
}
idx = perform_integral_promotions (idx);
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_DOMAIN (TREE_TYPE (array))
&& ! int_fits_type_p (idx, TYPE_DOMAIN (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 (OPT_Wextra, "subscripting array declared %<register%>");
}
type = TREE_TYPE (TREE_TYPE (array));
rval = build4 (ARRAY_REF, type, array, idx, NULL_TREE, NULL_TREE);
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_if_not_in_template (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 (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 = vtbl, basetype;
tree delta2 = 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 %qE", 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 (TARGET_KEXTABI == 1)
{
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:
gcc_unreachable ();
}
}
if (TARGET_KEXTABI == 1)
{
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));
if (!same_type_ignoring_top_level_qualifiers_p
(basetype, TREE_TYPE (TREE_TYPE (instance_ptr))))
{
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 (TARGET_KEXTABI == 1)
vtbl = build2 (PLUS_EXPR, build_pointer_type (vtbl_ptr_type_node),
instance_ptr, cp_convert (ptrdiff_type_node, delta2));
instance_ptr = build2 (PLUS_EXPR, TREE_TYPE (instance_ptr),
instance_ptr, delta);
*instance_ptrptr = instance_ptr;
if (TARGET_KEXTABI != 1)
vtbl = build1 (NOP_EXPR, build_pointer_type (vtbl_ptr_type_node),
instance_ptr);
vtbl = build_indirect_ref (vtbl, NULL);
if (TARGET_KEXTABI == 1)
{
idx = cp_build_binary_op (MINUS_EXPR, idx, integer_one_node);
idx = cp_build_binary_op (LSHIFT_EXPR, idx, integer_two_node);
}
e2 = fold_build2 (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx);
e2 = build_indirect_ref (e2, NULL);
TREE_CONSTANT (e2) = 1;
TREE_INVARIANT (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 = build2 (COMPOUND_EXPR, TREE_TYPE (e1),
instance_save_expr, e1);
function = e1;
}
return function;
}
static tree
build_block_call (tree fntype, tree block_ptr_exp, tree params)
{
tree function_ptr_exp;
tree typelist;
tree result;
bool block_ptr_exp_side_effect = TREE_SIDE_EFFECTS (block_ptr_exp);
block_ptr_exp = convert (ptr_type_node, block_ptr_exp);
gcc_assert (generic_block_literal_struct_type);
block_ptr_exp = convert (build_pointer_type (generic_block_literal_struct_type),
block_ptr_exp);
if (block_ptr_exp_side_effect)
block_ptr_exp = save_expr (block_ptr_exp);
function_ptr_exp =
finish_class_member_access_expr (build_indirect_ref (block_ptr_exp, "->"),
get_identifier ("__FuncPtr"), false);
gcc_assert (function_ptr_exp);
typelist = TYPE_ARG_TYPES (fntype);
typelist = tree_cons (NULL_TREE, ptr_type_node, typelist);
fntype = build_function_type (TREE_TYPE (fntype), typelist);
function_ptr_exp = convert (build_pointer_type (fntype), function_ptr_exp);
params = tree_cons (NULL_TREE, block_ptr_exp, params);
result = build3 (CALL_EXPR, TREE_TYPE (fntype),
function_ptr_exp, params, NULL_TREE);
result = convert_from_reference (result);
return result;
}
tree
build_function_call (tree function, tree params)
{
tree fntype, fndecl;
tree coerced_params;
tree name = NULL_TREE;
int is_method;
tree original = function;
function = objc_rewrite_function_call (function, params);
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);
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 (fntype) == BLOCK_POINTER_TYPE)
&& TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)
|| is_method
|| TREE_CODE (function) == TEMPLATE_ID_EXPR))
{
error ("%qE cannot be used as a function", original);
return error_mark_node;
}
fntype = TREE_TYPE (fntype);
coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
params, fndecl, LOOKUP_NORMAL,
(TREE_CODE (TREE_TYPE (function)) == BLOCK_POINTER_TYPE));
if (coerced_params == error_mark_node)
return error_mark_node;
check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params,
TYPE_ARG_TYPES (fntype));
if (TREE_CODE (TREE_TYPE (function)) == BLOCK_POINTER_TYPE)
return build_block_call (fntype, function, coerced_params);
return build_cxx_call (function, coerced_params);
}
static tree
convert_arguments (tree typelist, tree values, tree fndecl, int flags, int block_call)
{
tree typetail, valtail;
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++)
{
tree type = typetail ? TREE_VALUE (typetail) : 0;
tree val = TREE_VALUE (valtail);
if (val == error_mark_node || type == error_mark_node)
return error_mark_node;
if (type == void_type_node)
{
if (fndecl)
{
error ("too many arguments to %s %q+#D", called_thing, fndecl);
error ("at this point in file");
}
else
error ("too many arguments to %s", (block_call ? "block call" : "function"));
if (result)
TREE_TYPE (tree_last (result)) = error_mark_node;
break;
}
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 = decay_conversion (val);
}
if (val == error_mark_node)
return error_mark_node;
if (type != 0)
{
tree parmval;
if (!COMPLETE_TYPE_P (complete_type (type)))
{
if (fndecl)
error ("parameter %P of %qD has incomplete type %qT",
i, fndecl, type);
else
error ("parameter %P has incomplete type %qT", i, type);
parmval = error_mark_node;
}
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 (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)
&& TREE_CODE (TREE_PURPOSE (typetail)) != DEFAULT_ARG)
{
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)
{
error ("too few arguments to %s %q+#D", called_thing, fndecl);
error ("at this point in file");
}
else
error ("too few arguments to %s", (block_call ? "block call" : "function"));
return error_mark_node;
}
}
return nreverse (result);
}
tree
build_x_binary_op (enum tree_code code, tree arg1, tree arg2,
bool *overloaded_p)
{
tree orig_arg1;
tree orig_arg2;
tree expr;
if (inside_iasm_block)
if (TREE_CODE (arg1) == IDENTIFIER_NODE
|| TREE_CODE (arg2) == IDENTIFIER_NODE
|| TREE_TYPE (arg1) == NULL_TREE
|| TREE_TYPE (arg2) == NULL_TREE)
{
return build2 (code, NULL_TREE, arg1, arg2);
}
orig_arg1 = arg1;
orig_arg2 = arg2;
if (processing_template_decl)
{
if (type_dependent_expression_p (arg1)
|| type_dependent_expression_p (arg2))
return build_min_nt (code, arg1, arg2);
arg1 = build_non_dependent_expr (arg1);
arg2 = build_non_dependent_expr (arg2);
}
if (code == DOTSTAR_EXPR)
expr = build_m_component_ref (arg1, arg2);
else
expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
overloaded_p);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
return expr;
}
tree
build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
int convert_p ATTRIBUTE_UNUSED)
{
tree op0, op1;
enum tree_code code0, code1;
tree type0, type1;
const char *invalid_op_diag;
enum tree_code resultcode = code;
tree result_type = NULL;
int converted = 0;
tree build_type = 0;
tree final_type = 0;
tree result;
int shorten = 0;
int short_compare = 0;
int short_shift = 0;
int common = 0;
bool arithmetic_types_p;
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 %qT 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 %qT 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;
if ((invalid_op_diag
= targetm.invalid_binary_op (code, type0, type1)))
{
error (invalid_op_diag, "");
return error_mark_node;
}
switch (code)
{
case MINUS_EXPR:
if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
&& same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type0),
TREE_TYPE (type1)))
return pointer_diff (op0, op1, common_type (type0, type1));
else if (!(code0 == POINTER_TYPE && code1 == INTEGER_TYPE))
{
common = 1;
break;
}
case PLUS_EXPR:
if ((code0 == POINTER_TYPE || code1 == POINTER_TYPE)
&& (code0 == INTEGER_TYPE || code1 == INTEGER_TYPE))
{
tree ptr_operand;
tree int_operand;
ptr_operand = ((code0 == POINTER_TYPE) ? op0 : op1);
int_operand = ((code0 == INTEGER_TYPE) ? op0 : op1);
if (processing_template_decl)
{
result_type = TREE_TYPE (ptr_operand);
break;
}
return cp_pointer_int_sum (code,
ptr_operand,
int_operand);
}
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 || code0 == VECTOR_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE
|| code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
{
enum tree_code tcode0 = code0, tcode1 = code1;
if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
warning (OPT_Wdiv_by_zero, "division by zero in %<%E / 0%>", op0);
else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1))
warning (OPT_Wdiv_by_zero, "division by zero in %<%E / 0.%>", op0);
if (tcode0 == COMPLEX_TYPE || tcode0 == VECTOR_TYPE)
tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
if (tcode1 == COMPLEX_TYPE || tcode1 == VECTOR_TYPE)
tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
if (!(tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE))
resultcode = RDIV_EXPR;
else
shorten = ((TREE_CODE (op0) == NOP_EXPR
&& TYPE_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_IOR_EXPR:
case BIT_XOR_EXPR:
if ((code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
|| (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE))
shorten = -1;
break;
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
if (code1 == INTEGER_TYPE && integer_zerop (op1))
warning (OPT_Wdiv_by_zero, "division by zero in %<%E %% 0%>", op0);
else if (code1 == REAL_TYPE && real_zerop (op1))
warning (OPT_Wdiv_by_zero, "division by zero in %<%E %% 0.%>", op0);
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
shorten = ((TREE_CODE (op0) == NOP_EXPR
&& TYPE_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 (0, "right shift count is negative");
else
{
if (! integer_zerop (op1))
short_shift = 1;
if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
warning (0, "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 (0, "left shift count is negative");
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
warning (0, "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 (0, "%s rotate count is negative",
(code == LROTATE_EXPR) ? "left" : "right");
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
warning (0, "%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 (code0 == REAL_TYPE || code1 == REAL_TYPE)
warning (OPT_Wfloat_equal,
"comparing floating point with == or != is unsafe");
if ((TREE_CODE (orig_op0) == STRING_CST && !integer_zerop (op1))
|| (TREE_CODE (orig_op1) == STRING_CST && !integer_zerop (op0)))
warning (OPT_Waddress,
"comparison with string literal results in unspecified behavior");
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 || code0 == BLOCK_POINTER_TYPE)
&& (code1 == POINTER_TYPE || code1 == BLOCK_POINTER_TYPE))
|| (TYPE_PTRMEM_P (type0) && TYPE_PTRMEM_P (type1)))
result_type = composite_pointer_type (type0, type1, op0, op1,
"comparison");
else if ((code0 == POINTER_TYPE || code0 == BLOCK_POINTER_TYPE || TYPE_PTRMEM_P (type0))
&& null_ptr_cst_p (op1))
result_type = type0;
else if ((code1 == POINTER_TYPE || code1 == BLOCK_POINTER_TYPE || TYPE_PTRMEM_P (type1))
&& null_ptr_cst_p (op0))
result_type = type1;
else if ((code0 == POINTER_TYPE || code0 == BLOCK_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 || code1 == BLOCK_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 (TARGET_KEXTABI == 1)
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 = build2 (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
{
gcc_assert (!TYPE_PTRMEMFUNC_P (type0)
|| !same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type0),
type1));
gcc_assert (!TYPE_PTRMEMFUNC_P (type1)
|| !same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type1),
type0));
}
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:
if (TREE_CODE (orig_op0) == STRING_CST
|| TREE_CODE (orig_op1) == STRING_CST)
warning (OPT_Waddress,
"comparison with string literal results in unspecified behavior");
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)))
arithmetic_types_p = 1;
else
{
arithmetic_types_p = 0;
if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
{
if (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1))
|| !same_scalar_type_ignoring_signedness (TREE_TYPE (type0),
TREE_TYPE (type1)))
{
binary_op_error (code, type0, type1);
return error_mark_node;
}
arithmetic_types_p = 1;
}
}
if (!result_type
&& arithmetic_types_p
&& (shorten || common || short_compare))
result_type = common_type (type0, type1);
if (!result_type)
{
error ("invalid operands of types %qT and %qT to binary %qO",
TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
return error_mark_node;
}
if (processing_template_decl)
return build2 (resultcode,
build_type ? build_type : result_type,
op0, op1);
if (arithmetic_types_p)
{
int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
if (shorten && none_complex)
{
int unsigned0, unsigned1;
tree arg0 = get_narrower (op0, &unsigned0);
tree arg1 = get_narrower (op1, &unsigned1);
int uns = TYPE_UNSIGNED (result_type);
tree type;
final_type = result_type;
if (op0 == arg0 && TREE_TYPE (op0) != final_type)
unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0));
if (op1 == arg1 && TREE_TYPE (op1) != final_type)
unsigned1 = TYPE_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 = TYPE_UNSIGNED (TREE_TYPE (op0));
if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
&& compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0
&& (!TYPE_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
&& !processing_template_decl)
{
int op0_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op0));
int op1_signed = !TYPE_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 (0, "comparison between types %q#T and %q#T",
TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
}
if (!TYPE_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 (0, "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 (0, "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 (0, "comparison of promoted ~unsigned with unsigned");
}
}
}
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 (0, "NULL used in arithmetic");
if (! converted)
{
if (final_type == 0)
{
if (TREE_TYPE (op0) != result_type)
op0 = cp_convert_and_check (result_type, op0);
if (TREE_TYPE (op1) != result_type)
op1 = cp_convert_and_check (result_type, op1);
}
else
{
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;
result = build2 (resultcode, build_type, op0, op1);
result = fold_if_not_in_template (result);
if (final_type != 0)
result = cp_convert (final_type, result);
return result;
}
static tree
cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
{
tree res_type = TREE_TYPE (ptrop);
complete_type (TREE_TYPE (res_type));
return pointer_int_sum (resultcode, ptrop,
fold_if_not_in_template (intop));
}
static tree
pointer_diff (tree op0, tree op1, tree ptrtype)
{
tree result;
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");
}
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 = (TYPE_PTROB_P (ptrtype)
? size_in_bytes (target_type)
: integer_one_node);
result = build2 (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
return fold_if_not_in_template (result);
}
tree
build_x_unary_op (enum tree_code code, tree xarg)
{
tree orig_expr = xarg;
tree exp;
int ptrmem = 0;
if (processing_template_decl)
{
if (type_dependent_expression_p (xarg))
return build_min_nt (code, xarg, NULL_TREE);
xarg = build_non_dependent_expr (xarg);
}
exp = NULL_TREE;
if (code == ADDR_EXPR
&& TREE_CODE (xarg) != TEMPLATE_ID_EXPR
&& ((CLASS_TYPE_P (TREE_TYPE (xarg))
&& !COMPLETE_TYPE_P (complete_type (TREE_TYPE (xarg))))
|| (TREE_CODE (xarg) == OFFSET_REF)))
;
else
exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE,
NULL);
if (!exp && 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
|| !TYPE_P (TREE_OPERAND (xarg, 0)))
{
error ("invalid use of %qE to form a pointer-to-member-function",
xarg);
if (TREE_CODE (xarg) != OFFSET_REF)
inform (" a qualified-id is required");
return error_mark_node;
}
else
{
error ("parentheses around %qE 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 = build2 (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 (0, "taking address of temporary");
exp = build_unary_op (ADDR_EXPR, xarg, 0);
}
if (processing_template_decl && exp != error_mark_node)
exp = build_min_non_dep (code, exp, orig_expr,
NULL_TREE);
if (TREE_CODE (exp) == ADDR_EXPR)
PTRMEM_OK_P (exp) = ptrmem;
return exp;
}
tree
cp_truthvalue_conversion (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 (tree expr)
{
tree t;
if (processing_template_decl)
return expr;
t = perform_implicit_conversion (boolean_type_node, expr);
t = fold_build_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);
return addr;
}
tree
build_nop (tree type, tree expr)
{
if (type == error_mark_node || error_operand_p (expr))
return expr;
return build1 (NOP_EXPR, type, expr);
}
tree
build_unary_op (enum tree_code code, tree xarg, int noconvert)
{
tree arg = xarg;
tree argtype = 0;
const char *errstring = NULL;
tree val;
const char *invalid_op_diag;
if (arg == error_mark_node)
return error_mark_node;
if ((invalid_op_diag
= targetm.invalid_unary_op ((code == UNARY_PLUS_EXPR
? CONVERT_EXPR
: code),
TREE_TYPE (xarg))))
{
error (invalid_op_diag, "");
return error_mark_node;
}
switch (code)
{
case UNARY_PLUS_EXPR:
case NEGATE_EXPR:
{
int flags = WANT_ARITH | WANT_ENUM;
if (code == UNARY_PLUS_EXPR)
flags |= WANT_POINTER;
arg = build_expr_type_conversion (flags, arg, true);
if (!arg)
errstring = (code == NEGATE_EXPR
? "wrong type argument to unary minus"
: "wrong type argument to unary plus");
else
{
if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
arg = perform_integral_promotions (arg);
arg = rvalue (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
| WANT_VECTOR,
arg, true)))
errstring = "wrong type argument to bit-complement";
else if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
arg = perform_integral_promotions (arg);
break;
case ABS_EXPR:
if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
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, true)))
errstring = "wrong type argument to conjugation";
else if (!noconvert)
arg = default_conversion (arg);
break;
case TRUTH_NOT_EXPR:
arg = perform_implicit_conversion (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)
{
arg = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
return fold_if_not_in_template (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)
{
arg = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
return fold_if_not_in_template (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 build2 (COMPLEX_EXPR, TREE_TYPE (arg),
build_unary_op (code, real, 1), imag);
}
if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
arg, true)))
{
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);
{
tree inc;
tree declared_type;
tree result_type = TREE_TYPE (arg);
declared_type = unlowered_expr_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)
{
tree type = complete_type (TREE_TYPE (argtype));
if (!COMPLETE_OR_VOID_TYPE_P (type))
error ("cannot %s a pointer to incomplete type %qT",
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"), TREE_TYPE (argtype));
else if ((pedantic || warn_pointer_arith)
&& !TYPE_PTROB_P (argtype))
pedwarn ("ISO C++ forbids %sing a pointer of type %qT",
((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 = build2 (((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? PLUS_EXPR : MINUS_EXPR),
argtype, value, inc);
modify = build_modify_expr (arg, NOP_EXPR, incremented);
compound = build2 (COMPOUND_EXPR, TREE_TYPE (arg),
modify, value);
TREE_NO_WARNING (compound) = 1;
return compound;
}
default:
break;
}
if ((val = objc_build_incr_decr_setter_call (code, arg, inc)))
return val;
if (!lvalue_or_else (&arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? lv_increment
: lv_decrement)))
return error_mark_node;
if (same_type_p (declared_type, boolean_type_node))
{
if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
{
error ("invalid use of %<--%> on bool variable %qD", arg);
return error_mark_node;
}
val = boolean_increment (code, arg);
}
else
val = build2 (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 (arg) == OFFSET_REF)
goto offset_ref;
if (TREE_CODE (argtype) == REFERENCE_TYPE)
{
tree type = build_pointer_type (TREE_TYPE (argtype));
arg = build1 (CONVERT_EXPR, type, arg);
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)
{
tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg)));
arg = build1 (CONVERT_EXPR, type, arg);
}
else
arg = rvalue (arg);
return arg;
}
gcc_assert (TREE_CODE (arg) != IDENTIFIER_NODE
|| !IDENTIFIER_OPNAME_P (arg));
if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
&& !really_overloaded_fn (TREE_OPERAND (arg, 1)))
{
tree base = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg, 0)));
tree fn = get_first_fn (TREE_OPERAND (arg, 1));
mark_used (fn);
if (! flag_ms_extensions)
{
tree name = DECL_NAME (fn);
if (current_class_type
&& TREE_OPERAND (arg, 0) == current_class_ref)
pedwarn ("ISO C++ forbids taking the address of an unqualified"
" or parenthesized 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, fn, true);
}
offset_ref:
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;
case BASELINK:
arg = BASELINK_FUNCTIONS (arg);
case OVERLOAD:
arg = OVL_CURRENT (arg);
break;
case OFFSET_REF:
{
tree type;
tree t;
if (!PTRMEM_OK_P (arg))
return build_unary_op (code, arg, 0);
t = TREE_OPERAND (arg, 1);
if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
{
error ("cannot create pointer to reference member %qD", t);
return error_mark_node;
}
type = build_ptrmem_type (context_for_name_lookup (t),
TREE_TYPE (t));
t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
return t;
}
default:
break;
}
if (TREE_CODE (argtype) != FUNCTION_TYPE
&& TREE_CODE (argtype) != METHOD_TYPE
&& TREE_CODE (arg) != OFFSET_REF
&& !lvalue_or_else (&arg, lv_addressof))
return error_mark_node;
if (argtype != error_mark_node)
argtype = build_pointer_type (argtype);
if (processing_template_decl)
{
val = build_address (arg);
if (TREE_CODE (arg) == OFFSET_REF)
PTRMEM_OK_P (val) = PTRMEM_OK_P (arg);
return val;
}
if (TREE_CODE (arg) != COMPONENT_REF)
{
val = build_address (arg);
if (TREE_CODE (arg) == OFFSET_REF)
PTRMEM_OK_P (val) = PTRMEM_OK_P (arg);
}
else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
{
tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
&& DECL_STATIC_FUNCTION_P (fn));
mark_used (fn);
val = build_address (fn);
if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0)))
val = build2 (COMPOUND_EXPR, TREE_TYPE (val),
TREE_OPERAND (arg, 0), val);
}
else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
{
error ("attempt to take address of bit-field structure member %qD",
TREE_OPERAND (arg, 1));
return error_mark_node;
}
else
{
tree object = TREE_OPERAND (arg, 0);
tree field = TREE_OPERAND (arg, 1);
gcc_assert (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (object), decl_type_context (field)));
val = build_address (arg);
}
if (TREE_CODE (argtype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
{
build_ptrmemfunc_type (argtype);
val = build_ptrmemfunc (argtype, val, 0,
false);
}
return val;
default:
break;
}
if (!errstring)
{
if (argtype == 0)
argtype = TREE_TYPE (arg);
return fold_if_not_in_template (build1 (code, argtype, arg));
}
error ("%s", errstring);
return error_mark_node;
}
tree
unary_complex_lvalue (enum tree_code code, tree arg)
{
if (processing_template_decl)
return NULL_TREE;
if (TREE_CODE (arg) == COMPOUND_EXPR)
{
tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0);
return build2 (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 = build2 (TREE_CODE (arg), TREE_TYPE (arg),
lvalue, TREE_OPERAND (arg, 1));
}
return unary_complex_lvalue
(code, build2 (COMPOUND_EXPR, TREE_TYPE (lvalue), arg, lvalue));
}
if (code != ADDR_EXPR)
return NULL_TREE;
if (TREE_CODE (arg) == MODIFY_EXPR
|| TREE_CODE (arg) == INIT_EXPR)
{
tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
arg = build2 (COMPOUND_EXPR, TREE_TYPE (real_result),
arg, real_result);
TREE_NO_WARNING (arg) = 1;
return arg;
}
if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE
|| TREE_CODE (arg) == OFFSET_REF)
return NULL_TREE;
{
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 build3 (SAVE_EXPR, build_pointer_type (TREE_TYPE (arg)),
TREE_OPERAND (targ, 0), current_function_decl, NULL);
}
return NULL_TREE;
}
bool
cxx_mark_addressable (tree exp)
{
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:
gcc_assert (DECL_LANG_SPECIFIC (x) == 0
|| DECL_IN_AGGR_P (x) == 0
|| TREE_STATIC (x)
|| DECL_EXTERNAL (x));
case CONST_DECL:
case RESULT_DECL:
if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
&& !DECL_ARTIFICIAL (x))
{
if (TREE_CODE (x) == VAR_DECL && DECL_HARD_REGISTER (x))
{
error
("address of explicit register variable %qD requested", x);
return false;
}
else if (extra_warnings)
warning
(OPT_Wextra, "address requested for %qD, which is declared %<register%>", x);
}
TREE_ADDRESSABLE (x) = 1;
return true;
case FUNCTION_DECL:
TREE_ADDRESSABLE (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 (tree ifexp, tree op1, tree op2)
{
tree orig_ifexp = ifexp;
tree orig_op1 = op1;
tree orig_op2 = op2;
tree expr;
if (processing_template_decl)
{
if (type_dependent_expression_p (ifexp)
|| (op1 && type_dependent_expression_p (op1))
|| type_dependent_expression_p (op2))
return build_min_nt (COND_EXPR, ifexp, op1, op2);
ifexp = build_non_dependent_expr (ifexp);
if (op1)
op1 = build_non_dependent_expr (op1);
op2 = build_non_dependent_expr (op2);
}
expr = build_conditional_expr (ifexp, op1, op2);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (COND_EXPR, expr,
orig_ifexp, orig_op1, orig_op2);
return expr;
}
tree build_x_compound_expr_from_list (tree list, const char *msg)
{
tree expr = TREE_VALUE (list);
if (TREE_CHAIN (list))
{
if (msg)
pedwarn ("%s expression list treated as compound expression", msg);
for (list = TREE_CHAIN (list); list; list = TREE_CHAIN (list))
expr = build_x_compound_expr (expr, TREE_VALUE (list));
}
return expr;
}
tree
build_x_compound_expr (tree op1, tree op2)
{
tree result;
tree orig_op1 = op1;
tree orig_op2 = op2;
if (processing_template_decl)
{
if (type_dependent_expression_p (op1)
|| type_dependent_expression_p (op2))
return build_min_nt (COMPOUND_EXPR, op1, op2);
op1 = build_non_dependent_expr (op1);
op2 = build_non_dependent_expr (op2);
}
result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
NULL);
if (!result)
result = build_compound_expr (op1, op2);
if (processing_template_decl && result != error_mark_node)
return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2);
return result;
}
tree
build_compound_expr (tree lhs, tree rhs)
{
lhs = convert_to_void (lhs, targetm.cast_expr_as_vector_init
? NULL
: "left-hand operand of comma");
if (lhs == error_mark_node || rhs == error_mark_node)
return error_mark_node;
if (TREE_CODE (rhs) == TARGET_EXPR)
{
tree init = TREE_OPERAND (rhs, 1);
init = build2 (COMPOUND_EXPR, TREE_TYPE (init), lhs, init);
TREE_OPERAND (rhs, 1) = init;
return rhs;
}
return build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs);
}
static void
check_for_casting_away_constness (tree src_type, tree dest_type,
void (*diag_fn)(const char *, ...) ATTRIBUTE_GCC_CXXDIAG(1,2),
const char *description)
{
if (diag_fn && casts_away_constness (src_type, dest_type))
diag_fn ("%s from type %qT to type %qT casts away constness",
description, src_type, dest_type);
}
tree
convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
bool c_cast_p)
{
if (TYPE_PTRMEM_P (type))
{
tree delta;
if (TREE_CODE (expr) == PTRMEM_CST)
expr = cplus_expand_constant (expr);
delta = get_delta_difference (TYPE_PTRMEM_CLASS_TYPE (TREE_TYPE (expr)),
TYPE_PTRMEM_CLASS_TYPE (type),
allow_inverse_p,
c_cast_p);
if (!integer_zerop (delta))
expr = cp_build_binary_op (PLUS_EXPR,
build_nop (ptrdiff_type_node, expr),
delta);
return build_nop (type, expr);
}
else
return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
allow_inverse_p, c_cast_p);
}
static tree
ignore_overflows (tree expr, tree orig)
{
if (TREE_CODE (expr) == INTEGER_CST
&& CONSTANT_CLASS_P (orig)
&& TREE_CODE (orig) != STRING_CST
&& (TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig)
|| TREE_CONSTANT_OVERFLOW (expr)
!= TREE_CONSTANT_OVERFLOW (orig)))
{
if (!TREE_OVERFLOW (orig) && !TREE_CONSTANT_OVERFLOW (orig))
expr = build_int_cst_wide (TREE_TYPE (expr),
TREE_INT_CST_LOW (expr),
TREE_INT_CST_HIGH (expr));
else
{
expr = copy_node (expr);
TREE_OVERFLOW (expr) = TREE_OVERFLOW (orig);
TREE_CONSTANT_OVERFLOW (expr)
= TREE_CONSTANT_OVERFLOW (orig);
}
}
return expr;
}
static tree
build_static_cast_1 (tree type, tree expr, bool c_cast_p,
bool *valid_p)
{
tree intype;
tree result;
tree orig;
void (*diag_fn)(const char*, ...) ATTRIBUTE_GCC_CXXDIAG(1,2);
const char *desc;
*valid_p = true;
intype = TREE_TYPE (expr);
used_types_insert (type);
if (c_cast_p)
{
diag_fn = warn_cast_qual ? warning0 : NULL;
desc = "cast";
}
else
{
diag_fn = error;
desc = "static_cast";
}
if (TREE_CODE (type) == REFERENCE_TYPE
&& CLASS_TYPE_P (TREE_TYPE (type))
&& CLASS_TYPE_P (intype)
&& real_lvalue_p (expr)
&& DERIVED_FROM_P (intype, TREE_TYPE (type))
&& can_convert (build_pointer_type (TYPE_MAIN_VARIANT (intype)),
build_pointer_type (TYPE_MAIN_VARIANT
(TREE_TYPE (type))))
&& (c_cast_p
|| at_least_as_qualified_p (TREE_TYPE (type), intype)))
{
tree base;
base = lookup_base (TREE_TYPE (type), intype,
c_cast_p ? ba_unique : ba_check,
NULL);
expr = build_base_path (MINUS_EXPR, build_address (expr),
base, false);
return convert_from_reference (build_nop (type, expr));
}
orig = expr;
result = perform_direct_initialization_if_possible (type, expr,
c_cast_p);
if (result)
{
result = convert_from_reference (result);
result = ignore_overflows (result, orig);
if (TREE_CODE (type) != REFERENCE_TYPE)
result = rvalue (result);
return result;
}
if (TREE_CODE (type) == VOID_TYPE)
return convert_to_void (expr, NULL);
if ((INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type))
&& (INTEGRAL_TYPE_P (intype) || SCALAR_FLOAT_TYPE_P (intype)))
{
expr = ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
expr = ignore_overflows (expr, orig);
return expr;
}
if (objc_is_object_ptr (type)
&& objc_is_object_ptr (intype))
return build_nop (type, expr);
if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
&& CLASS_TYPE_P (TREE_TYPE (type))
&& CLASS_TYPE_P (TREE_TYPE (intype))
&& can_convert (build_pointer_type (TYPE_MAIN_VARIANT
(TREE_TYPE (intype))),
build_pointer_type (TYPE_MAIN_VARIANT
(TREE_TYPE (type)))))
{
tree base;
if (!c_cast_p)
check_for_casting_away_constness (intype, type, diag_fn, desc);
base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
c_cast_p ? ba_unique : ba_check,
NULL);
return build_base_path (MINUS_EXPR, expr, base, false);
}
if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
{
tree c1;
tree c2;
tree t1;
tree t2;
c1 = TYPE_PTRMEM_CLASS_TYPE (intype);
c2 = TYPE_PTRMEM_CLASS_TYPE (type);
if (TYPE_PTRMEM_P (type))
{
t1 = (build_ptrmem_type
(c1,
TYPE_MAIN_VARIANT (TYPE_PTRMEM_POINTED_TO_TYPE (intype))));
t2 = (build_ptrmem_type
(c2,
TYPE_MAIN_VARIANT (TYPE_PTRMEM_POINTED_TO_TYPE (type))));
}
else
{
t1 = intype;
t2 = type;
}
if (can_convert (t1, t2))
{
if (!c_cast_p)
check_for_casting_away_constness (intype, type, diag_fn,
desc);
return convert_ptrmem (type, expr, 1,
c_cast_p);
}
}
if (TREE_CODE (intype) == POINTER_TYPE
&& VOID_TYPE_P (TREE_TYPE (intype))
&& TYPE_PTROB_P (type))
{
if (!c_cast_p)
check_for_casting_away_constness (intype, type, diag_fn, desc);
return build_nop (type, expr);
}
*valid_p = false;
return error_mark_node;
}
tree
build_static_cast (tree type, tree expr)
{
tree result;
bool valid_p;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
expr = build_min (STATIC_CAST_EXPR, type, expr);
TREE_SIDE_EFFECTS (expr) = 1;
return convert_from_reference (expr);
}
if (TREE_CODE (type) == VECTOR_TYPE && targetm.cast_expr_as_vector_init)
return vector_constructor_from_expr (expr, type);
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);
result = build_static_cast_1 (type, expr, false, &valid_p);
if (valid_p)
return result;
error ("invalid static_cast from type %qT to type %qT",
TREE_TYPE (expr), type);
return error_mark_node;
}
tree
convert_member_func_to_ptr (tree type, tree expr)
{
tree intype;
tree decl;
intype = TREE_TYPE (expr);
gcc_assert (TYPE_PTRMEMFUNC_P (intype)
|| TREE_CODE (intype) == METHOD_TYPE);
if (TARGET_KEXTABI)
{
error ("converting from `%T' to `%T' in a kext. Use OSMemberFunctionCast() instead.", intype, type);
return error_mark_node;
}
if (pedantic || warn_pmf2ptr)
pedwarn ("converting from %qT to %qT", intype, type);
if (TREE_CODE (intype) == METHOD_TYPE)
expr = build_addr_func (expr);
else if (TREE_CODE (expr) == PTRMEM_CST)
expr = build_address (PTRMEM_CST_MEMBER (expr));
else
{
decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 0);
decl = build_address (decl);
expr = get_member_function_from_ptrfunc (&decl, expr);
}
return build_nop (type, expr);
}
static tree
build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
bool *valid_p)
{
tree intype;
if (valid_p)
*valid_p = true;
if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
intype = TREE_TYPE (expr);
used_types_insert (type);
if (TREE_CODE (type) == REFERENCE_TYPE)
{
if (! real_lvalue_p (expr))
{
error ("invalid cast of an rvalue expression of type "
"%qT to type %qT",
intype, type);
return error_mark_node;
}
if (TYPE_PTR_P (intype)
&& (comptypes (TREE_TYPE (intype), TREE_TYPE (type),
COMPARE_BASE | COMPARE_DERIVED)))
warning (0, "casting %qT to %qT does not dereference pointer",
intype, type);
expr = build_unary_op (ADDR_EXPR, expr, 0);
if (expr != error_mark_node)
expr = build_reinterpret_cast_1
(build_pointer_type (TREE_TYPE (type)), expr, c_cast_p,
valid_p);
if (expr != error_mark_node)
expr = build_indirect_ref (expr, 0);
return expr;
}
if ((TYPE_PTRMEMFUNC_P (intype)
|| TREE_CODE (intype) == METHOD_TYPE)
&& TYPE_PTR_P (type)
&& (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
|| VOID_TYPE_P (TREE_TYPE (type))))
return convert_member_func_to_ptr (type, expr);
expr = decay_conversion (expr);
if (TREE_CODE (expr) == NOP_EXPR
&& TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
expr = TREE_OPERAND (expr, 0);
if (error_operand_p (expr))
return error_mark_node;
intype = TREE_TYPE (expr);
if (CP_INTEGRAL_TYPE_P (type) && TYPE_PTR_P (intype))
{
if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
pedwarn ("cast from %qT to %qT loses precision",
intype, type);
}
else if (TYPE_PTR_P (type) && INTEGRAL_OR_ENUMERATION_TYPE_P (intype))
;
else if (TREE_CODE (type) == INTEGER_TYPE && TREE_CODE (intype) == BLOCK_POINTER_TYPE)
{
if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
pedwarn ("cast from %qT to %qT loses precision",
intype, type);
}
else if (TREE_CODE (type) == BLOCK_POINTER_TYPE && TREE_CODE (intype) == INTEGER_TYPE)
;
else if (TREE_CODE (type) == BLOCK_POINTER_TYPE && TREE_CODE (intype) == BLOCK_POINTER_TYPE)
;
else if (TREE_CODE (intype) == BLOCK_POINTER_TYPE
&& (objc_is_id (type)
|| (TREE_CODE (type) == POINTER_TYPE && VOID_TYPE_P (TREE_TYPE (type)))))
;
else if (TREE_CODE (type) == BLOCK_POINTER_TYPE
&& TREE_CODE (intype) == POINTER_TYPE
&& (objc_is_id (intype) || VOID_TYPE_P (TREE_TYPE (intype))))
;
else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
return fold_if_not_in_template (build_nop (type, expr));
else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|| (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
{
tree sexpr = expr;
if (!c_cast_p)
check_for_casting_away_constness (intype, type, error,
"reinterpret_cast");
if (STRICT_ALIGNMENT && warn_cast_align
&& !VOID_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (intype)) != FUNCTION_TYPE
&& COMPLETE_TYPE_P (TREE_TYPE (type))
&& COMPLETE_TYPE_P (TREE_TYPE (intype))
&& TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (intype)))
warning (0, "cast from %qT to %qT increases required alignment of "
"target type",
intype, type);
STRIP_NOPS (sexpr);
strict_aliasing_warning (intype, type, sexpr);
return fold_if_not_in_template (build_nop (type, expr));
}
else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
|| (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
{
if (pedantic)
warning (0, "ISO C++ forbids casting between pointer-to-function and pointer-to-object");
return fold_if_not_in_template (build_nop (type, expr));
}
else if (TREE_CODE (type) == VECTOR_TYPE)
return fold_if_not_in_template (convert_to_vector (type, expr));
else if (TREE_CODE (intype) == VECTOR_TYPE && INTEGRAL_TYPE_P (type))
return fold_if_not_in_template (convert_to_integer (type, expr));
else
{
if (valid_p)
*valid_p = false;
error ("invalid cast from type %qT to type %qT", intype, type);
return error_mark_node;
}
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (intype) == POINTER_TYPE
&& TYPE_PRECISION (type) > TYPE_PRECISION (intype)
&& TYPE_UNSIGNED (type))
expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 1), expr);
return cp_convert (type, expr);
}
tree
build_reinterpret_cast (tree type, tree expr)
{
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
if (!TREE_SIDE_EFFECTS (t)
&& type_dependent_expression_p (expr))
TREE_SIDE_EFFECTS (t) = 1;
return convert_from_reference (t);
}
if (TREE_CODE (type) == VECTOR_TYPE && targetm.cast_expr_as_vector_init)
return vector_constructor_from_expr (expr, type);
return build_reinterpret_cast_1 (type, expr, false,
NULL);
}
static tree
build_const_cast_1 (tree dst_type, tree expr, bool complain,
bool *valid_p)
{
tree src_type;
tree reference_type;
gcc_assert (dst_type != error_mark_node);
gcc_assert (!processing_template_decl);
if (valid_p)
*valid_p = false;
if (!POINTER_TYPE_P (dst_type) && !TYPE_PTRMEM_P (dst_type))
{
if (complain)
error ("invalid use of const_cast with type %qT, "
"which is not a pointer, "
"reference, nor a pointer-to-data-member type", dst_type);
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (dst_type)) == FUNCTION_TYPE)
{
if (complain)
error ("invalid use of const_cast with type %qT, which is a pointer "
"or reference to a function type", dst_type);
return error_mark_node;
}
used_types_insert (dst_type);
src_type = TREE_TYPE (expr);
if (TREE_CODE (src_type) == REFERENCE_TYPE)
src_type = TREE_TYPE (src_type);
if (TREE_CODE (dst_type) == REFERENCE_TYPE)
{
reference_type = dst_type;
if (! real_lvalue_p (expr))
{
if (complain)
error ("invalid const_cast of an rvalue of type %qT to type %qT",
src_type, dst_type);
return error_mark_node;
}
dst_type = build_pointer_type (TREE_TYPE (dst_type));
src_type = build_pointer_type (src_type);
}
else
{
reference_type = NULL_TREE;
src_type = type_decays_to (src_type);
if (src_type == error_mark_node)
return error_mark_node;
}
if ((TYPE_PTR_P (src_type) || TYPE_PTRMEM_P (src_type))
&& comp_ptr_ttypes_const (dst_type, src_type))
{
if (valid_p)
{
*valid_p = true;
if (warn_cast_qual)
check_for_casting_away_constness (src_type, dst_type,
warning0,
"cast");
}
if (reference_type)
{
expr = build_unary_op (ADDR_EXPR, expr, 0);
expr = build_nop (reference_type, expr);
return convert_from_reference (expr);
}
else
{
expr = decay_conversion (expr);
if (TREE_CODE (expr) == NOP_EXPR
&& TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
expr = TREE_OPERAND (expr, 0);
return build_nop (dst_type, expr);
}
}
if (complain)
error ("invalid const_cast from type %qT to type %qT",
src_type, dst_type);
return error_mark_node;
}
tree
build_const_cast (tree type, tree expr)
{
if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
if (processing_template_decl)
{
tree t = build_min (CONST_CAST_EXPR, type, expr);
if (!TREE_SIDE_EFFECTS (t)
&& type_dependent_expression_p (expr))
TREE_SIDE_EFFECTS (t) = 1;
return convert_from_reference (t);
}
return build_const_cast_1 (type, expr, true,
NULL);
}
tree
build_c_cast (tree type, tree expr)
{
tree value = expr;
tree result;
bool valid_p;
if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
if (processing_template_decl)
{
tree t = build_min (CAST_EXPR, type,
tree_cons (NULL_TREE, value, NULL_TREE));
TREE_SIDE_EFFECTS (t) = 1;
return convert_from_reference (t);
}
if (TREE_CODE (type) == VECTOR_TYPE
&& targetm.cast_expr_as_vector_init
&& !IS_AGGR_TYPE (TREE_TYPE (expr)))
return vector_constructor_from_expr (expr, type);
diagnose_selector_cast (type, expr);
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 (type) == ARRAY_TYPE)
{
if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
{
pedwarn ("ISO C++ forbids casting to an array type %qT", type);
type = build_pointer_type (TREE_TYPE (type));
}
else
{
error ("ISO C++ forbids casting to an array type %qT", type);
return error_mark_node;
}
}
if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
{
error ("invalid cast to function type %qT", type);
return error_mark_node;
}
result = build_const_cast_1 (type, value, false,
&valid_p);
if (valid_p)
return result;
result = build_static_cast_1 (type, value, true,
&valid_p);
if (!valid_p)
result = build_reinterpret_cast_1 (type, value, true,
&valid_p);
if (valid_p
&& !error_operand_p (result))
{
tree result_type;
if (!CLASS_TYPE_P (type))
type = TYPE_MAIN_VARIANT (type);
result_type = TREE_TYPE (result);
if (!CLASS_TYPE_P (result_type))
result_type = TYPE_MAIN_VARIANT (result_type);
if (!same_type_p (non_reference (type), non_reference (result_type)))
{
result = build_const_cast_1 (type, result, false, &valid_p);
gcc_assert (valid_p);
}
return result;
}
return error_mark_node;
}
tree
build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
{
tree result;
tree newrhs = rhs;
tree lhstype = TREE_TYPE (lhs);
tree olhstype = lhstype;
tree olhs = NULL_TREE;
bool plain_assign = (modifycode == NOP_EXPR);
if (error_operand_p (lhs) || error_operand_p (rhs))
return error_mark_node;
if (c_dialect_objc () && flag_objc_gc)
{
objc_weak_reference_expr (&lhs);
lhstype = TREE_TYPE (lhs);
olhstype = lhstype;
}
switch (TREE_CODE (lhs))
{
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
stabilize_reference (TREE_OPERAND (lhs, 0)),
TREE_OPERAND (lhs, 1));
return build2 (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 build2 (COMPOUND_EXPR, lhstype,
TREE_OPERAND (lhs, 0), newrhs);
case MODIFY_EXPR:
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
stabilize_reference (TREE_OPERAND (lhs, 0)),
TREE_OPERAND (lhs, 1));
newrhs = build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs);
if (newrhs == error_mark_node)
return error_mark_node;
return build2 (COMPOUND_EXPR, lhstype, lhs, newrhs);
case MIN_EXPR:
case MAX_EXPR:
if (!lvalue_or_else (&lhs, lv_assign))
return error_mark_node;
gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))
&& !TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 1)));
lhs = build3 (COND_EXPR, TREE_TYPE (lhs),
build2 (TREE_CODE (lhs) == MIN_EXPR ? LE_EXPR : GE_EXPR,
boolean_type_node,
TREE_OPERAND (lhs, 0),
TREE_OPERAND (lhs, 1)),
TREE_OPERAND (lhs, 0),
TREE_OPERAND (lhs, 1));
case COND_EXPR:
{
tree cond;
tree preeval = NULL_TREE;
if (VOID_TYPE_P (TREE_TYPE (rhs)))
{
error ("void value not ignored as it ought to be");
return error_mark_node;
}
rhs = stabilize_expr (rhs, &preeval);
if (!lvalue_or_else (&lhs, lv_assign))
return error_mark_node;
cond = build_conditional_expr
(TREE_OPERAND (lhs, 0),
build_modify_expr (TREE_OPERAND (lhs, 1),
modifycode, rhs),
build_modify_expr (TREE_OPERAND (lhs, 2),
modifycode, rhs));
if (cond == error_mark_node)
return cond;
if (preeval)
cond = build2 (COMPOUND_EXPR, TREE_TYPE (lhs), preeval, cond);
return cond;
}
default:
break;
}
if (modifycode == INIT_EXPR)
{
if (TREE_CODE (rhs) == CONSTRUCTOR)
{
if (! same_type_p (TREE_TYPE (rhs), lhstype))
rhs = convert (lhstype, rhs);
result = build2 (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),
lhstype, LOOKUP_NORMAL);
if (result == NULL_TREE)
return error_mark_node;
return result;
}
}
else
{
lhs = require_complete_type (lhs);
if (lhs == error_mark_node)
return error_mark_node;
if (modifycode == NOP_EXPR)
{
if (c_dialect_objc ())
{
result = objc_build_setter_call (lhs, rhs);
if (result)
return result;
}
if (! IS_AGGR_TYPE (lhstype))
;
else
{
result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
lhs, rhs, make_node (NOP_EXPR),
NULL);
if (c_dialect_objc () && flag_objc_gc
&& result && TREE_CODE (result) == MODIFY_EXPR)
{
tree t = objc_generate_write_barrier (lhs, MODIFY_EXPR, rhs);
if (t)
result = t;
}
if (result == NULL_TREE)
return error_mark_node;
return result;
}
lhstype = olhstype;
}
else
{
gcc_assert (!PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE));
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;
if (c_dialect_objc ())
{
result = objc_build_setter_call (lhs, newrhs);
if (result)
return result;
}
}
gcc_assert (TREE_CODE (lhstype) != REFERENCE_TYPE);
gcc_assert (TREE_CODE (TREE_TYPE (newrhs)) != REFERENCE_TYPE);
}
if (!lvalue_or_else (&lhs, lv_assign))
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
|| (CLASS_TYPE_P (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))
{
if (TREE_CODE (lhstype) == INTEGER_TYPE
&& TREE_CODE (olhstype) == ENUMERAL_TYPE)
{
if (TREE_SIDE_EFFECTS (lhs))
lhs = stabilize_reference (lhs);
olhs = lhs;
}
lhs = copy_node (lhs);
TREE_TYPE (lhs) = lhstype;
}
}
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 %qT to %qT",
TREE_TYPE (rhs), lhstype);
return error_mark_node;
}
if (! DECL_ARTIFICIAL (current_function_decl))
{
if (modifycode == INIT_EXPR)
error ("array used as initializer");
else
error ("invalid array assignment");
return error_mark_node;
}
from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
? 1 + (modifycode != INIT_EXPR): 0;
return build_vec_init (lhs, NULL_TREE, newrhs,
false,
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 = build2 (COMPOUND_EXPR, TREE_TYPE (newrhs), newrhs,
TREE_OPERAND (newrhs, 0));
}
if (newrhs == error_mark_node)
return error_mark_node;
if (c_dialect_objc () && flag_objc_gc)
{
result = objc_generate_write_barrier (lhs, modifycode, newrhs);
if (result)
return result;
}
result = build2 (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
lhstype, lhs, newrhs);
TREE_SIDE_EFFECTS (result) = 1;
if (!plain_assign)
TREE_NO_WARNING (result) = 1;
if (olhstype == TREE_TYPE (result))
return result;
if (olhs)
{
result = build2 (COMPOUND_EXPR, olhstype, result, olhs);
TREE_NO_WARNING (result) = 1;
return result;
}
return convert_for_assignment (olhstype, result, "assignment",
NULL_TREE, 0);
}
tree
build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
{
bool insert_sequence_point = false;
if (processing_template_decl)
return build_min_nt (MODOP_EXPR, lhs,
build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
if (TREE_CODE (lhs) == COMPONENT_REF)
{
tree inner = TREE_OPERAND (lhs, 0);
if (TREE_CODE (inner) == INDIRECT_REF)
{
inner = TREE_OPERAND (inner, 0);
if (TREE_CODE (inner) == COMPONENT_REF)
{
inner = TREE_OPERAND (inner, 0);
if (TREE_CODE (inner) == VAR_DECL
&& COPYABLE_BYREF_LOCAL_VAR (inner))
{
tree old_rhs = rhs;
rhs = save_expr (rhs);
if (rhs != old_rhs)
insert_sequence_point = true;
}
}
}
}
if (modifycode != NOP_EXPR)
{
tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
make_node (modifycode),
NULL);
if (rval)
{
if (insert_sequence_point)
rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), rhs, rval);
TREE_NO_WARNING (rval) = 1;
return rval;
}
}
lhs = build_modify_expr (lhs, modifycode, rhs);
if (insert_sequence_point)
lhs = build2 (COMPOUND_EXPR, TREE_TYPE (lhs), rhs, lhs);
return lhs;
}
static tree
get_delta_difference (tree from, tree to,
bool allow_inverse_p,
bool c_cast_p)
{
tree binfo;
base_kind kind;
tree result;
result = integer_zero_node;
binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
if (kind == bk_inaccessible || kind == bk_ambig)
error (" in pointer to member function conversion");
else if (binfo)
{
if (kind != bk_via_virtual)
result = BINFO_OFFSET (binfo);
else
{
tree virt_binfo = binfo_from_vbase (binfo);
if (allow_inverse_p)
warning (0, "pointer to member cast via virtual base %qT",
BINFO_TYPE (virt_binfo));
else
error ("pointer to member conversion via virtual base %qT",
BINFO_TYPE (virt_binfo));
}
}
else if (same_type_ignoring_top_level_qualifiers_p (from, to))
;
else if (!allow_inverse_p)
{
error_not_base_type (from, to);
error (" in pointer to member conversion");
}
else
{
binfo = lookup_base (from, to, c_cast_p ? ba_unique : ba_check, &kind);
if (binfo)
{
if (kind != bk_via_virtual)
result = size_diffop (size_zero_node, BINFO_OFFSET (binfo));
else
{
tree virt_binfo = binfo_from_vbase (binfo);
warning (0, "pointer to member cast via virtual base %qT",
BINFO_TYPE (virt_binfo));
}
}
}
return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node,
result));
}
tree
build_ptrmemfunc1 (tree type, tree delta, tree pfn)
{
tree u = NULL_TREE;
tree delta_field;
tree pfn_field;
VEC(constructor_elt, gc) *v;
if (TARGET_KEXTABI == 1)
{
tree subtype, pfn_or_delta2_field, idx, idx_field, delta2_field;
int ixval = 0;
int allconstant = 0, allsimple = 0, allinvariant = 0;
tree virt_p;
int pfn_offset = 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)
{
virt_p = pfn;
pfn_offset = 1;
}
else
{
virt_p = delta;
}
allconstant = TREE_CONSTANT (virt_p);
allinvariant = TREE_INVARIANT (virt_p);
allsimple = !! initializer_constant_valid_p (virt_p, TREE_TYPE (virt_p));
if (TREE_CODE (virt_p) == INTEGER_CST && (TREE_INT_CST_LOW (virt_p) & 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) - pfn_offset);
ixval /= vt_entry_sz;
ixval += 2 + 1;
if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_delta)
{
delta = build2 (RSHIFT_EXPR, TREE_TYPE (delta),
delta, integer_one_node);
delta = fold_if_not_in_template (delta);
}
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);
}
delta = convert_and_check (delta_type_node, delta);
idx = convert_and_check (delta_type_node, ssize_int (ixval));
u = build_constructor_from_list (subtype, u);
TREE_CONSTANT (u) = allconstant;
TREE_INVARIANT (u) = allinvariant;
TREE_STATIC (u) = allconstant && allsimple;
allconstant = allconstant && TREE_CONSTANT (delta) && TREE_CONSTANT (idx);
allinvariant = allinvariant && TREE_INVARIANT (delta) && TREE_INVARIANT (idx);
allsimple = allsimple
&& initializer_constant_valid_p (delta, TREE_TYPE (delta))
&& initializer_constant_valid_p (idx, TREE_TYPE (idx));
u = tree_cons (delta_field, delta,
tree_cons (idx_field, idx,
tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
u = build_constructor_from_list (type, u);
TREE_CONSTANT (u) = allconstant;
TREE_INVARIANT (u) = allinvariant;
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);
v = VEC_alloc(constructor_elt, gc, 2);
CONSTRUCTOR_APPEND_ELT(v, pfn_field, pfn);
CONSTRUCTOR_APPEND_ELT(v, delta_field, delta);
u = build_constructor (type, v);
TREE_CONSTANT (u) = TREE_CONSTANT (pfn) & TREE_CONSTANT (delta);
TREE_INVARIANT (u) = TREE_INVARIANT (pfn) & TREE_INVARIANT (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 (tree type, tree pfn, int force, bool c_cast_p)
{
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, LOOKUP_NORMAL))
error ("invalid conversion to type %qT from type %qT",
to_type, pfn_type);
n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
force,
c_cast_p);
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);
}
gcc_assert (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (delta), ptrdiff_type_node));
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_warning_or_error);
fn = TREE_OPERAND (pfn, 0);
gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
|| (processing_template_decl && TREE_CODE (fn) == OFFSET_REF));
return make_ptrmem_cst (to_type, fn);
}
void
expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
{
tree type = TREE_TYPE (cst);
tree fn = PTRMEM_CST_MEMBER (cst);
tree ptr_class, fn_class;
gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
fn_class = DECL_CONTEXT (fn);
ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
*delta = get_delta_difference (fn_class, ptr_class, 0,
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 = build2 (PLUS_EXPR, TREE_TYPE (*delta),
*delta, BINFO_OFFSET (binfo));
*delta = fold_if_not_in_template (*delta);
*pfn = DECL_VINDEX (fn);
*pfn = build2 (MULT_EXPR, integer_type_node, *pfn,
TYPE_SIZE_UNIT (vtable_entry_type));
*pfn = fold_if_not_in_template (*pfn);
switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
{
case ptrmemfunc_vbit_in_pfn:
*pfn = build2 (PLUS_EXPR, integer_type_node, *pfn,
integer_one_node);
*pfn = fold_if_not_in_template (*pfn);
break;
case ptrmemfunc_vbit_in_delta:
*delta = build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
*delta, integer_one_node);
*delta = fold_if_not_in_template (*delta);
*delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
*delta, integer_one_node);
*delta = fold_if_not_in_template (*delta);
break;
default:
gcc_unreachable ();
}
*pfn = build_nop (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
*pfn = fold_if_not_in_template (*pfn);
}
}
static tree
pfn_from_ptrmemfunc (tree t)
{
if (TARGET_KEXTABI == 1)
{
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);
}
static tree
convert_for_assignment (tree type, tree rhs,
const char *errtype, tree fndecl, int parmnum)
{
tree rhstype;
enum tree_code coder;
tree new_rhs = NULL_TREE;
if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
rhs = TREE_OPERAND (rhs, 0);
rhstype = TREE_TYPE (rhs);
coder = TREE_CODE (rhstype);
if (TREE_CODE (type) == VECTOR_TYPE && coder == VECTOR_TYPE
&& vector_types_convertible_p (type, rhstype, true))
return convert (type, rhs);
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;
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 (c_dialect_objc ())
{
int parmno;
tree rname = fndecl;
if (!strcmp (errtype, "assignment"))
parmno = -1;
else if (!strcmp (errtype, "initialization"))
parmno = -2;
else
{
tree selector = objc_message_selector ();
parmno = parmnum;
if (selector && parmno > 1)
{
rname = selector;
parmno -= 1;
}
}
if (objc_compare_types (type, rhstype, parmno, rname, "comparison"))
new_rhs = convert (type, rhs);
}
if (!new_rhs && !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_warning_or_error);
else if (fndecl)
error ("cannot convert %qT to %qT for argument %qP to %qD",
rhstype, type, parmnum, fndecl);
else
error ("cannot convert %qT to %qT in %s", rhstype, type, errtype);
return error_mark_node;
}
}
if (warn_missing_format_attribute)
{
const enum tree_code codel = TREE_CODE (type);
if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
&& coder == codel
&& check_missing_format_attribute (type, rhstype))
warning (OPT_Wmissing_format_attribute,
"%s might be a candidate for a format attribute",
errtype);
}
return !new_rhs ? perform_implicit_conversion (strip_top_quals (type), rhs) : new_rhs;
}
tree
convert_for_initialization (tree exp, tree type, tree rhs, int flags,
const char *errtype, tree fndecl, int parmnum)
{
enum tree_code codel = TREE_CODE (type);
tree rhstype;
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 (type == error_mark_node
|| rhs == error_mark_node
|| (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node))
return error_mark_node;
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 = decay_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,
NULL);
if (fndecl)
{
if (warningcount > savew)
warning (0, "in passing argument %P of %q+D", parmnum, fndecl);
else if (errorcount > savee)
error ("in passing argument %P of %q+D", parmnum, fndecl);
}
return rhs;
}
if (exp != 0)
exp = require_complete_type (exp);
if (exp == error_mark_node)
return error_mark_node;
rhstype = non_reference (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);
}
static void
maybe_warn_about_returning_address_of_local (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)
{
warning (0, "returning reference to temporary");
return;
}
if (TREE_CODE (whats_returned) == VAR_DECL
&& DECL_NAME (whats_returned)
&& TEMP_NAME_P (DECL_NAME (whats_returned)))
{
warning (0, "reference to non-lvalue returned");
return;
}
}
while (TREE_CODE (whats_returned) == COMPONENT_REF
|| TREE_CODE (whats_returned) == ARRAY_REF)
whats_returned = TREE_OPERAND (whats_returned, 0);
if (DECL_P (whats_returned)
&& DECL_NAME (whats_returned)
&& DECL_FUNCTION_SCOPE_P (whats_returned)
&& !(TREE_STATIC (whats_returned)
|| TREE_PUBLIC (whats_returned)))
{
if (TREE_CODE (valtype) == REFERENCE_TYPE)
warning (0, "reference to local variable %q+D returned",
whats_returned);
else if (TREE_CODE (valtype) == BLOCK_POINTER_TYPE)
error ("returning block that lives on the local stack");
else
warning (0, "address of local variable %q+D returned",
whats_returned);
return;
}
}
static bool
types_are_block_compatible (tree t1, tree t2)
{
return comptypes (t1, t2, COMPARE_STRICT);
}
tree
check_return_expr (tree retval, bool *no_warning)
{
tree result;
tree valtype;
int fn_returns_value_p;
*no_warning = false;
if (TREE_THIS_VOLATILE (current_function_decl))
warning (0, "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;
}
if (cur_block && !cur_block->block_has_return_type)
{
if (cur_block->return_type == NULL_TREE)
{
if (retval)
{
tree restype;
retval = decay_conversion (retval);
restype = TYPE_MAIN_VARIANT (TREE_TYPE (retval));
TREE_TYPE (current_function_decl)
= build_function_type (restype,
TYPE_ARG_TYPES (TREE_TYPE (current_function_decl)));
TREE_TYPE (DECL_RESULT (current_function_decl)) = restype;
relayout_decl (DECL_RESULT (current_function_decl));
cur_block->return_type = restype;
}
else
cur_block->return_type = void_type_node;
}
if (TREE_CODE (cur_block->return_type) == VOID_TYPE)
{
if (retval)
{
error ("void block should not return a value");
return error_mark_node;
}
}
else if (!retval)
{
error ("non-void block should return a value");
return error_mark_node;
}
if (retval)
{
valtype = TREE_TYPE (retval);
if (!types_are_block_compatible (cur_block->return_type, valtype))
{
error ("incompatible type returning %qT, expected %qT",
valtype, cur_block->return_type);
return error_mark_node;
}
}
}
if (processing_template_decl)
{
current_function_returns_value = 1;
return retval;
}
result = DECL_RESULT (current_function_decl);
valtype = TREE_TYPE (result);
gcc_assert (valtype != NULL_TREE);
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 returning %qT",
valtype);
current_function_returns_null = 0;
*no_warning = true;
}
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 "
"returning 'void'");
current_function_returns_null = 1;
return NULL_TREE;
}
else if (!retval)
current_function_returns_null = 1;
else
current_function_returns_value = 1;
if (error_operand_p (retval))
{
current_function_return_value = error_mark_node;
return error_mark_node;
}
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 (0, "%<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))
{
bool warn = true;
if (TREE_CODE (valtype) == REFERENCE_TYPE
&& same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (valtype), TREE_TYPE (current_class_ref)))
{
if (retval == current_class_ref)
warn = false;
else if (TREE_CODE (retval) == INDIRECT_REF
&& TREE_CODE (TREE_OPERAND (retval, 0)) == CALL_EXPR)
warn = false;
}
if (warn)
warning (OPT_Weffc__, "%<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)
return NULL_TREE;
if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl))
;
else
{
tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
if (VOID_TYPE_P (functype))
return error_mark_node;
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 = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
TREE_OPERAND (retval, 0));
else
maybe_warn_about_returning_address_of_local (retval);
}
if (retval && retval != result)
retval = build2 (INIT_EXPR, TREE_TYPE (result), result, retval);
return retval;
}
static int
comp_ptr_ttypes_real (tree to, tree from, int constp)
{
bool to_more_cv_qualified = false;
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)))
return 0;
if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
{
tree nv_to = objc_non_volatilized_type (to);
tree nv_from = objc_non_volatilized_type (from);
if (!at_least_as_qualified_p (nv_to, nv_from))
return 0;
if (!at_least_as_qualified_p (nv_from, nv_to))
{
if (constp == 0)
return 0;
to_more_cv_qualified = true;
}
if (constp > 0)
constp &= TYPE_READONLY (nv_to);
}
if (TREE_CODE (to) != POINTER_TYPE && !TYPE_PTRMEM_P (to))
return ((constp >= 0 || to_more_cv_qualified)
&& same_type_ignoring_top_level_qualifiers_p (to, from));
}
}
int
comp_ptr_ttypes (tree to, tree from)
{
return comp_ptr_ttypes_real (to, from, 1);
}
int
ptr_reasonably_similar (tree to, tree 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_DERIVED))
continue;
if (TREE_CODE (to) == VECTOR_TYPE
&& vector_types_convertible_p (to, from, false))
return 1;
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_DERIVED);
}
}
bool
comp_ptr_ttypes_const (tree to, tree from)
{
for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
{
if (TREE_CODE (to) != TREE_CODE (from))
return false;
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);
}
}
int
cp_type_quals (tree type)
{
type = strip_array_types (type);
if (type == error_mark_node)
return TYPE_UNQUALIFIED;
return TYPE_QUALS (type);
}
bool
cp_type_readonly (tree type)
{
type = strip_array_types (type);
return TYPE_READONLY (type);
}
bool
cp_has_mutable_p (tree type)
{
type = strip_array_types (type);
return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
}
void
cp_apply_type_quals_to_decl (int type_quals, tree decl)
{
tree type = TREE_TYPE (decl);
if (type == error_mark_node)
return;
if (TREE_CODE (type) == FUNCTION_TYPE
&& type_quals != TYPE_UNQUALIFIED)
{
if (pedantic)
{
tree bad_type = build_qualified_type (type, type_quals);
pedwarn ("ignoring %qV qualifiers added to function type %qT",
bad_type, type);
}
TREE_TYPE (decl) = TYPE_MAIN_VARIANT (type);
return;
}
if (
TYPE_NEEDS_CONSTRUCTING (type)
|| !COMPLETE_TYPE_P (type)
|| TYPE_HAS_MUTABLE_P (type))
type_quals &= ~TYPE_QUAL_CONST;
c_apply_type_quals_to_decl (type_quals, decl);
}
static void
casts_away_constness_r (tree *t1, tree *t2)
{
int quals1;
int quals2;
if ((!TYPE_PTR_P (*t1) && !TYPE_PTRMEM_P (*t1))
|| (!TYPE_PTR_P (*t2) && !TYPE_PTRMEM_P (*t2)))
{
*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);
if (TYPE_PTRMEM_P (*t1))
*t1 = TYPE_PTRMEM_POINTED_TO_TYPE (*t1);
else
*t1 = TREE_TYPE (*t1);
if (TYPE_PTRMEM_P (*t2))
*t2 = TYPE_PTRMEM_POINTED_TO_TYPE (*t2);
else
*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 bool
casts_away_constness (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 (TYPE_PTRMEM_POINTED_TO_TYPE (t1)),
build_pointer_type (TYPE_PTRMEM_POINTED_TO_TYPE (t2)));
if (TREE_CODE (t1) != POINTER_TYPE
|| TREE_CODE (t2) != POINTER_TYPE)
return false;
t1 = TYPE_MAIN_VARIANT (t1);
t2 = TYPE_MAIN_VARIANT (t2);
casts_away_constness_r (&t1, &t2);
if (!can_convert (t2, t1))
return true;
return false;
}
tree
non_reference (tree t)
{
if (TREE_CODE (t) == REFERENCE_TYPE)
t = TREE_TYPE (t);
return t;
}
tree
iasm_cp_build_component_ref (tree datum, tree component)
{
tree expr = finish_class_member_access_expr (datum, component, false);
if (TREE_CODE (datum) == TYPE_DECL)
expr = TREE_OPERAND (expr, 1);
return expr;
}
int
lvalue_or_else (tree* ref, enum lvalue_use use)
{
int win = lvalue_p (*ref);
if (!win)
win = lvalue_or_else_1 (ref, use);
if (!win)
lvalue_error (use);
return win;
}