/* Build expressions with type checking for C++ compiler.
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
#include "flags.h"
#include "output.h"
-int mark_addressable ();
-static tree convert_for_assignment ();
-/* static */ tree convert_for_initialization ();
+int mark_addressable PROTO((tree));
+static tree convert_for_assignment PROTO((tree, tree, char*, tree, int));
+/* static */ tree convert_for_initialization PROTO((tree, tree, tree, int, char*, tree, int));
extern tree shorten_compare ();
-extern void binary_op_error ();
-static tree pointer_int_sum ();
-static tree pointer_diff ();
+static tree pointer_int_sum PROTO((enum tree_code, register tree, register tree));
+static tree pointer_diff PROTO((register tree, register tree));
+static int comp_target_parms PROTO((tree, tree, int));
+static int comp_ptr_ttypes_const PROTO((tree, tree));
+static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
+#if 0
static tree convert_sequence ();
-/* static */ tree unary_complex_lvalue ();
+#endif
+/* static */ tree unary_complex_lvalue PROTO((enum tree_code, tree));
static tree get_delta_difference PROTO((tree, tree, int));
-extern rtx original_result_rtx;
-extern int warn_synth;
-
/* Return the target type of TYPE, which meas return T for:
T*, T&, T[], T (...), and otherwise, just T. */
{
tree type;
- if (current_template_parms)
+ if (processing_template_decl)
return value;
type = TREE_TYPE (value);
not been laid out. Try to avoid an error by interpreting
it as this->X::Y, if reasonable. */
if (TREE_CODE (value) == OFFSET_REF
- && C_C_D != 0
- && TREE_OPERAND (value, 0) == C_C_D)
+ && current_class_ref != 0
+ && TREE_OPERAND (value, 0) == current_class_ref)
{
tree base, member = TREE_OPERAND (value, 1);
tree basetype = TYPE_OFFSET_BASETYPE (type);
my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305);
- base = convert_pointer_to (basetype, current_class_decl);
+ base = convert_pointer_to (basetype, current_class_ptr);
value = build (COMPONENT_REF, TREE_TYPE (member),
build_indirect_ref (base, NULL_PTR), member);
return require_complete_type (value);
if (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
{
- instantiate_class_template (type);
+ instantiate_class_template (TYPE_MAIN_VARIANT (type));
if (TYPE_SIZE (type) != 0)
return value;
}
complete_type (type)
tree type;
{
- if (TYPE_SIZE (type) != NULL_TREE)
+ if (type == error_mark_node || TYPE_SIZE (type) != NULL_TREE)
;
- else if (TREE_CODE (type) == ARRAY_TYPE)
+ else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
{
tree t = complete_type (TREE_TYPE (type));
- if (TYPE_SIZE (t) != NULL_TREE)
- type = build_cplus_array_type (t, TYPE_DOMAIN (type));
+ if (TYPE_SIZE (t) != NULL_TREE && ! processing_template_decl)
+ layout_type (type);
+ TYPE_NEEDS_CONSTRUCTING (type)
+ = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
+ TYPE_NEEDS_DESTRUCTOR (type)
+ = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (t));
}
else if (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
instantiate_class_template (TYPE_MAIN_VARIANT (type));
}
/* Return truthvalue of whether type of EXP is instantiated. */
+
int
type_unknown_p (exp)
tree exp;
}
/* Return truthvalue of whether T is function (or pfn) type. */
+
int
fntype_p (t)
tree t;
/* Do `exp = require_instantiated_type (type, exp);' to make sure EXP
does not have an uninstantiated type.
TYPE is type to instantiate with, if uninstantiated. */
+
tree
require_instantiated_type (type, exp, errval)
tree type, exp, errval;
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
+ /* If one type is complex, form the common type of the non-complex
+ components, then make that complex. Use T1 or T2 if it is the
+ required type. */
+ if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
+ {
+ tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
+ tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
+ tree subtype = common_type (subtype1, subtype2);
+
+ if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
+ return build_type_attribute_variant (t1, attributes);
+ else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
+ return build_type_attribute_variant (t2, attributes);
+ else
+ return build_type_attribute_variant (build_complex_type (subtype),
+ attributes);
+ }
+
switch (code1)
{
case INTEGER_TYPE:
if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
return build_type_attribute_variant (t2, attributes);
/* Merge the element types, and have a size if either arg has one. */
- t1 = build_cplus_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ t1 = build_cplus_array_type
+ (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
return build_type_attribute_variant (t1, attributes);
}
tree b1 = TYPE_OFFSET_BASETYPE (t1);
tree b2 = TYPE_OFFSET_BASETYPE (t2);
- if (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2))
+ if (comptypes (b1, b2, 1)
+ || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
return build_type_attribute_variant (t2, attributes);
else if (binfo_or_else (b2, b1))
return build_type_attribute_variant (t1, attributes);
}
\f
/* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */
+
int
compexcepttypes (t1, t2)
tree t1, t2;
pointer to a base classes. These allowances do not commute. In this
case, TYPE1 is assumed to be the base class, and TYPE2 is assumed to
be the derived class. */
+
int
comptypes (type1, type2, strict)
tree type1, type2;
{
int rval;
look_hard:
- rval = t1 == t2 || UNIQUELY_DERIVED_FROM_P (t1, t2);
+ rval = t1 == t2 || DERIVED_FROM_P (t1, t2);
if (rval)
{
}
if (strict < 0)
{
- val = UNIQUELY_DERIVED_FROM_P (t2, t1);
+ val = DERIVED_FROM_P (t2, t1);
break;
}
}
/* If two types share a common base type, return that basetype.
If there is not a unique most-derived base type, this function
returns ERROR_MARK_NODE. */
-tree
+
+static tree
common_base_type (tt1, tt2)
tree tt1, tt2;
{
C++: See comment above about TYPE1, TYPE2, STRICT.
If STRICT == 3, it means checking is strict, but do not compare
default parameter values. */
+
int
compparms (parms1, parms2, strict)
tree parms1, parms2;
/* This really wants return whether or not parameter type lists
would make their owning functions assignment compatible or not. */
-int
+
+static int
comp_target_parms (parms1, parms2, strict)
tree parms1, parms2;
int strict;
return unsigned_intHI_type_node;
if (type1 == intQI_type_node)
return unsigned_intQI_type_node;
- return type;
+
+ return signed_or_unsigned_type (1, type);
}
/* Return a signed type the same as TYPE in other respects. */
return intHI_type_node;
if (type1 == unsigned_intQI_type_node)
return intQI_type_node;
- return type;
+
+ return signed_or_unsigned_type (0, type);
}
/* Return a type the same as TYPE except unsigned or
int unsignedp;
tree type;
{
- if (! INTEGRAL_TYPE_P (type))
+ if (! INTEGRAL_TYPE_P (type)
+ || TREE_UNSIGNED (type) == unsignedp)
return type;
+
if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
enum tree_code code = TREE_CODE (type);
tree t;
- if (current_template_parms)
+ if (processing_template_decl)
return build_min (SIZEOF_EXPR, sizetype, type);
if (code == FUNCTION_TYPE)
expr_sizeof (e)
tree e;
{
- if (current_template_parms)
+ if (processing_template_decl)
return build_min (SIZEOF_EXPR, sizetype, e);
if (TREE_CODE (e) == COMPONENT_REF
register tree type = TREE_TYPE (exp);
register enum tree_code code = TREE_CODE (type);
- if (code == OFFSET_TYPE /* || TREE_CODE (exp) == OFFSET_REF */ )
+ if (code == OFFSET_TYPE)
{
if (TREE_CODE (exp) == OFFSET_REF)
return decay_conversion (resolve_offset_ref (exp));
type = TREE_TYPE (type);
code = TREE_CODE (type);
+
+ if (type == unknown_type_node)
+ {
+ cp_pedwarn ("assuming & on overloaded member function");
+ return build_unary_op (ADDR_EXPR, exp, 0);
+ }
}
if (code == REFERENCE_TYPE)
}
if (code == METHOD_TYPE)
{
- if (TREE_CODE (exp) == OFFSET_REF)
- {
- /* FIXME: We should emit an error here about using a ptrmemfunc
- for something other than a function call. */
- my_friendly_assert (TREE_CODE (TREE_OPERAND (exp, 1)) == FUNCTION_DECL,
- 308);
- return build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0);
- }
+ cp_pedwarn ("assuming & on `%E'", exp);
return build_unary_op (ADDR_EXPR, exp, 0);
}
if (code == ARRAY_TYPE)
inner = build1 (CONVERT_EXPR,
build_pointer_type (TREE_TYPE (TREE_TYPE (inner))),
inner);
- TREE_REFERENCE_EXPR (inner) = 1;
+ TREE_CONSTANT (inner) = TREE_CONSTANT (TREE_OPERAND (inner, 0));
}
- return convert (build_pointer_type (TREE_TYPE (type)), inner);
+ return cp_convert (build_pointer_type (TREE_TYPE (type)), inner);
}
if (TREE_CODE (exp) == COMPOUND_EXPR)
/* This way is better for a COMPONENT_REF since it can
simplify the offset for a component. */
adr = build_unary_op (ADDR_EXPR, exp, 1);
- return convert (ptrtype, adr);
+ return cp_convert (ptrtype, adr);
}
return exp;
{
tree t = type_promotes_to (type);
if (t != type)
- return convert (t, exp);
+ return cp_convert (t, exp);
}
- if (flag_traditional
- && TYPE_MAIN_VARIANT (type) == float_type_node)
- return convert (double_type_node, exp);
return exp;
}
+
+/* Take the address of an inline function without setting TREE_ADDRESSABLE
+ or TREE_USED. */
+
+tree
+inline_conversion (exp)
+ tree exp;
+{
+ if (TREE_CODE (exp) == FUNCTION_DECL)
+ {
+ tree type = build_type_variant
+ (TREE_TYPE (exp), TREE_READONLY (exp), TREE_THIS_VOLATILE (exp));
+ exp = build1 (ADDR_EXPR, build_pointer_type (type), exp);
+ }
+ return exp;
+}
\f
tree
build_object_ref (datum, basetype, field)
{
tree binfo = binfo_or_else (basetype, dtype);
if (binfo)
- return build_component_ref (build_scoped_ref (datum, basetype),
- field, binfo, 1);
+ return build_x_component_ref (build_scoped_ref (datum, basetype),
+ field, binfo, 1);
}
return error_mark_node;
}
/* Like `build_component_ref, but uses an already found field.
- Must compute access for C_C_D. Otherwise, ok. */
+ Must compute access for current_class_ref. Otherwise, ok. */
+
tree
build_component_ref_1 (datum, field, protect)
tree datum, field;
int protect;
{
- register tree basetype = TREE_TYPE (datum);
- register enum tree_code code = TREE_CODE (basetype);
- register tree ref;
-
- if (code == REFERENCE_TYPE)
- {
- datum = convert_from_reference (datum);
- basetype = TREE_TYPE (datum);
- code = TREE_CODE (basetype);
- }
-
- if (! IS_AGGR_TYPE_CODE (code))
- {
- if (code != ERROR_MARK)
- cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
- field, datum, basetype);
- return error_mark_node;
- }
-
- if (TYPE_SIZE (basetype) == 0)
- {
- incomplete_type_error (0, basetype);
- return error_mark_node;
- }
-
- /* Look up component name in the structure type definition. */
-
- if (field == error_mark_node)
- my_friendly_abort (115);
-
- if (TREE_STATIC (field))
- return field;
-
- if (datum == C_C_D)
- {
- tree access = compute_access (TYPE_BINFO (current_class_type), field);
-
- if (access == access_private_node)
- {
- cp_error ("field `%D' is private", field);
- return error_mark_node;
- }
- else if (access == access_protected_node)
- {
- cp_error ("field `%D' is protected", field);
- return error_mark_node;
- }
- }
-
- ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
-
- if (TREE_READONLY (datum) || TREE_READONLY (field))
- TREE_READONLY (ref) = 1;
- if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field))
- TREE_THIS_VOLATILE (ref) = 1;
- if (DECL_MUTABLE_P (field))
- TREE_READONLY (ref) = 0;
-
- return ref;
+ return build_component_ref (datum, field, NULL_TREE, protect);
}
/* Given a COND_EXPR in T, return it in a form that we can, for
we're dealing with aggregates. So, we now call this in unary_complex_lvalue,
and in build_modify_expr. The case (in particular) that led to this was
with CODE == ADDR_EXPR, since it's not an lvalue when we'd get it there. */
+
static tree
rationalize_conditional_expr (code, t)
enum tree_code code;
FIELD_DECL for the field. If not found return NULL_TREE. Because
anonymous unions can nest, we must also search all anonymous unions
that are directly reachable. */
+
static tree
lookup_anon_field (t, type)
tree t, type;
/* Build a COMPONENT_REF for a given DATUM, and it's member COMPONENT.
COMPONENT can be an IDENTIFIER_NODE that is the name of the member
that we are interested in, or it can be a FIELD_DECL. */
+
tree
build_component_ref (datum, component, basetype_path, protect)
tree datum, component, basetype_path;
register tree field = NULL;
register tree ref;
- if (current_template_parms)
+ if (processing_template_decl)
return build_min_nt (COMPONENT_REF, datum, component);
- /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it. */
+ /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference
+ inside it. */
switch (TREE_CODE (datum))
{
case COMPOUND_EXPR:
basetype = TREE_TYPE (datum);
code = TREE_CODE (basetype);
}
+ if (TREE_CODE (datum) == OFFSET_REF)
+ {
+ datum = resolve_offset_ref (datum);
+ basetype = TREE_TYPE (datum);
+ code = TREE_CODE (basetype);
+ }
- /* First, see if there is a field or component with name COMPONENT. */
+ /* First, see if there is a field or component with name COMPONENT. */
if (TREE_CODE (component) == TREE_LIST)
{
my_friendly_assert (!(TREE_CHAIN (component) == NULL_TREE
cp_error ("type `%T' has no destructor", basetype);
return error_mark_node;
}
- return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0);
+ return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 1);
}
/* Look up component name in the structure type definition. */
hierarchy, the compiler will abort (because vptr lookups are
not supposed to be ambiguous. */
field = CLASSTYPE_VFIELD (basetype);
- else if (TREE_CODE (component) == FIELD_DECL)
+ else if (TREE_CODE (component) == FIELD_DECL
+ || TREE_CODE (component) == TYPE_DECL)
{
field = component;
}
else
{
+ tree name = component;
+ if (TREE_CODE (component) == VAR_DECL)
+ name = DECL_NAME (component);
if (basetype_path == NULL_TREE)
basetype_path = TYPE_BINFO (basetype);
- field = lookup_field (basetype_path, component,
- protect && ! VFIELD_NAME_P (component), 0);
+ field = lookup_field (basetype_path, name,
+ protect && !VFIELD_NAME_P (name), 0);
if (field == error_mark_node)
return error_mark_node;
/* Not found as a data field, look for it as a method. If found,
then if this is the only possible one, return it, else
report ambiguity error. */
- tree fndecls = lookup_fnfields (basetype_path, component, 1);
+ tree fndecls = lookup_fnfields (basetype_path, name, 1);
if (fndecls == error_mark_node)
return error_mark_node;
if (fndecls)
&& ! resolves_to_fixed_type_p (datum, 0))
{
tree addr = build_unary_op (ADDR_EXPR, datum, 0);
+ tree fntype = TREE_TYPE (fndecl);
+
addr = convert_pointer_to (DECL_CONTEXT (fndecl), addr);
datum = build_indirect_ref (addr, NULL_PTR);
my_friendly_assert (datum != error_mark_node, 310);
fndecl = build_vfn_ref (&addr, datum, DECL_VINDEX (fndecl));
+ TREE_TYPE (fndecl) = build_pointer_type (fntype);
}
- mark_used (fndecl);
- return fndecl;
+ else
+ mark_used (fndecl);
+ return build (OFFSET_REF, TREE_TYPE (fndecl), datum, fndecl);
}
if (access == access_protected_node)
cp_error ("member function `%D' is protected", fndecl);
}
}
- cp_error ("`%#T' has no member named `%D'", basetype, component);
+ cp_error ("`%#T' has no member named `%D'", basetype, name);
return error_mark_node;
}
else if (TREE_TYPE (field) == error_mark_node)
{
tree context = DECL_FIELD_CONTEXT (field);
tree base = context;
- while (base != basetype && ANON_AGGRNAME_P (TYPE_IDENTIFIER (base)))
+ while (base != basetype && TYPE_NAME (base)
+ && ANON_AGGRNAME_P (TYPE_IDENTIFIER (base)))
{
base = TYPE_CONTEXT (base);
}
basetype = base;
/* Handle things from anon unions here... */
- if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
+ if (TYPE_NAME (context) && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
{
tree subfield = lookup_anon_field (basetype, context);
tree subdatum = build_component_ref (datum, subfield,
return ref;
}
+
+/* Variant of build_component_ref for use in expressions, which should
+ never have REFERENCE_TYPE. */
+
+tree
+build_x_component_ref (datum, component, basetype_path, protect)
+ tree datum, component, basetype_path;
+ int protect;
+{
+ tree t = build_component_ref (datum, component, basetype_path, protect);
+
+ if (! processing_template_decl)
+ t = convert_from_reference (t);
+
+ return t;
+}
\f
/* Given an expression PTR for a pointer, return an expression
for the value pointed to.
{
tree rval;
- if (current_template_parms)
+ if (processing_template_decl)
return build_min_nt (INDIRECT_REF, ptr);
rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, NULL_TREE);
tree ptr;
char *errorstring;
{
- register tree pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE ?
- ptr : default_conversion (ptr));
- register tree type = TREE_TYPE (pointer);
+ register tree pointer, type;
+
+ if (ptr == error_mark_node)
+ return error_mark_node;
- if (ptr == current_class_decl)
- return C_C_D;
+ pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
+ ? ptr : default_conversion (ptr));
+ type = TREE_TYPE (pointer);
+
+ if (ptr == current_class_ptr)
+ return current_class_ref;
if (IS_AGGR_TYPE (type))
{
will inherit the type of the array, which will be some pointer type. */
tree
-build_x_array_ref (array, index)
- tree array, index;
-{
- tree rval = build_opfncall (ARRAY_REF, LOOKUP_NORMAL, array, index, NULL_TREE);
- if (rval)
- return rval;
- return build_array_ref (array, index);
-}
-
-tree
build_array_ref (array, idx)
tree array, idx;
{
\f
/* Build a function call to function FUNCTION with parameters PARAMS.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
- TREE_VALUE of each node is a parameter-expression.
- FUNCTION's data type may be a function type or a pointer-to-function.
+ TREE_VALUE of each node is a parameter-expression. The PARAMS do
+ not include any object pointer that may be required. FUNCTION's
+ data type may be a function type or a pointer-to-function.
For C++: If FUNCTION's data type is a TREE_LIST, then the tree list
is the list of possible methods that FUNCTION could conceivably
In the second case, TREE_PURPOSE (function) is the function's
name directly.
- DECL is the class instance variable, usually CURRENT_CLASS_DECL. */
+ DECL is the class instance variable, usually CURRENT_CLASS_REF.
+
+ When calling a TEMPLATE_DECL, we don't require a complete return
+ type. */
-/*
- * [eichin:19911015.1726EST] actually return a possibly incomplete
- * type
- */
tree
build_x_function_call (function, params, decl)
tree function, params, decl;
if (function == error_mark_node)
return error_mark_node;
- if (current_template_parms)
- return build_min_nt (CALL_EXPR, function, params, 0);
+ if (processing_template_decl)
+ return build_min_nt (CALL_EXPR, function, params, NULL_TREE);
type = TREE_TYPE (function);
+
+ if (TREE_CODE (type) == OFFSET_TYPE
+ && TREE_TYPE (type) == unknown_type_node
+ && TREE_CODE (function) == TREE_LIST
+ && TREE_CHAIN (function) == NULL_TREE)
+ {
+ /* Undo (Foo:bar)()... */
+ type = TYPE_OFFSET_BASETYPE (type);
+ function = TREE_VALUE (function);
+ my_friendly_assert (TREE_CODE (function) == TREE_LIST, 999);
+ my_friendly_assert (TREE_CHAIN (function) == NULL_TREE, 999);
+ function = TREE_VALUE (function);
+ my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 999);
+ function = DECL_NAME (function);
+ return build_method_call (decl, function, params, TYPE_BINFO (type), LOOKUP_NORMAL);
+ }
+
is_method = ((TREE_CODE (function) == TREE_LIST
&& current_class_type != NULL_TREE
&& IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function)) == function)
|| TREE_CODE (type) == METHOD_TYPE
|| TYPE_PTRMEMFUNC_P (type));
+ if (TREE_CODE (function) == FUNCTION_DECL
+ && DECL_STATIC_FUNCTION_P (function))
+ return build_member_call
+ (DECL_CONTEXT (function), DECL_NAME (function), params);
+
/* Handle methods, friends, and overloaded functions, respectively. */
if (is_method)
{
+ tree basetype = NULL_TREE;
+
if (TREE_CODE (function) == FUNCTION_DECL)
{
+ basetype = DECL_CLASS_CONTEXT (function);
+
if (DECL_NAME (function))
function = DECL_NAME (function);
else
else if (TREE_CODE (function) == TREE_LIST)
{
my_friendly_assert (TREE_CODE (TREE_VALUE (function)) == FUNCTION_DECL, 312);
+ basetype = DECL_CLASS_CONTEXT (TREE_VALUE (function));
function = TREE_PURPOSE (function);
}
else if (TREE_CODE (function) != IDENTIFIER_NODE)
must go through here in case it is a virtual function.
@@ Perhaps this could be optimized. */
+ if (basetype && (! current_class_type
+ || ! DERIVED_FROM_P (basetype, current_class_type)))
+ return build_member_call (basetype, function, params);
+
if (decl == NULL_TREE)
{
if (current_class_type == NULL_TREE)
{
/* Should we undo what was done in build_component_ref? */
if (TREE_CODE (TREE_PURPOSE (TREE_OPERAND (function, 1))) == TREE_VEC)
- /* Get the name that build_component_ref hid. */
+ /* Get the name that build_component_ref hid. */
function = DECL_NAME (TREE_VALUE (TREE_OPERAND (function, 1)));
else
function = TREE_PURPOSE (TREE_OPERAND (function, 1));
{
tree val = TREE_VALUE (function);
+ if (flag_ansi_overloading)
+ return build_new_function_call (function, params, NULL_TREE);
+
if (TREE_CODE (val) == TEMPLATE_DECL)
- return build_overload_call_maybe
- (function, params, LOOKUP_COMPLAIN, (struct candidate *)0);
+ return build_overload_call_real
+ (function, params, LOOKUP_COMPLAIN, (struct candidate *)0, 0);
else if (DECL_CHAIN (val) != NULL_TREE)
return build_overload_call
- (function, params, LOOKUP_COMPLAIN, (struct candidate *)0);
+ (function, params, LOOKUP_COMPLAIN);
else
my_friendly_abort (360);
}
if (TREE_OPERAND (function, 0))
decl = TREE_OPERAND (function, 0);
else
- decl = C_C_D;
+ decl = current_class_ref;
decl_addr = build_unary_op (ADDR_EXPR, decl, 0);
function = get_member_function_from_ptrfunc (&decl_addr,
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
- if (TYPE_LANG_SPECIFIC (type)
- && TYPE_OVERLOADS_CALL_EXPR (complete_type (type)))
+ if (IS_AGGR_TYPE (type))
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE);
}
decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl);
}
else
- decl = build_c_cast (ctypeptr, decl, 0);
+ decl = build_c_cast (ctypeptr, decl);
params = tree_cons (NULL_TREE, decl, params);
}
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
{
- tree fntype, index, e1, delta, delta2, e2, e3, aref, vtbl;
+ tree fntype, idx, e1, delta, delta2, e2, e3, aref, vtbl;
tree instance;
tree instance_ptr = *instance_ptrptr;
function = save_expr (function);
fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
- index = save_expr (build_component_ref (function,
- index_identifier,
- 0, 0));
- e1 = build (GT_EXPR, boolean_type_node, index,
- convert (delta_type_node, integer_zero_node));
- delta = convert (ptrdiff_type_node,
- build_component_ref (function, delta_identifier, 0, 0));
+ idx = save_expr (build_component_ref (function,
+ index_identifier,
+ NULL_TREE, 0));
+ e1 = fold (build (GT_EXPR, boolean_type_node, idx,
+ cp_convert (delta_type_node, integer_zero_node)));
+ delta = cp_convert (ptrdiff_type_node,
+ build_component_ref (function, delta_identifier, NULL_TREE, 0));
delta2 = DELTA2_FROM_PTRMEMFUNC (function);
- /* convert down to the right base, before using the instance. */
+ /* Convert down to the right base, before using the instance. */
instance
= convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)),
instance_ptr);
- if (instance == error_mark_node)
+ if (instance == error_mark_node && instance_ptr != error_mark_node)
return instance;
vtbl = convert_pointer_to (ptr_type_node, instance);
vtbl
= build (PLUS_EXPR,
build_pointer_type (build_pointer_type (vtable_entry_type)),
- vtbl, convert (ptrdiff_type_node, delta2));
+ vtbl, cp_convert (ptrdiff_type_node, delta2));
vtbl = build_indirect_ref (vtbl, NULL_PTR);
aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
- index,
+ idx,
integer_one_node, 1));
if (! flag_vtable_thunks)
{
aref = save_expr (aref);
- /* Save the intermediate result in a SAVE_EXPR so we don't have to
- compute each component of the virtual function pointer twice. */
- if (TREE_CODE (aref) == INDIRECT_REF)
- TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
-
delta = build_binary_op (PLUS_EXPR,
- build_conditional_expr (e1, build_component_ref (aref, delta_identifier, 0, 0), integer_zero_node),
+ build_conditional_expr (e1, build_component_ref (aref, delta_identifier, NULL_TREE, 0), integer_zero_node),
delta, 1);
}
if (flag_vtable_thunks)
e2 = aref;
else
- e2 = build_component_ref (aref, pfn_identifier, 0, 0);
+ e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
e3 = PFN_FROM_PTRMEMFUNC (function);
TREE_TYPE (e2) = TREE_TYPE (e3);
- function = build_conditional_expr (e1, e2, e3);
+ e1 = build_conditional_expr (e1, e2, e3);
+
+ if (instance_ptr == error_mark_node
+ && TREE_CODE (e1) != ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (e1, 0)) != FUNCTION_DECL)
+ cp_error ("object missing in `%E'", function);
+
+ function = e1;
/* Make sure this doesn't get evaluated first inside one of the
branches of the COND_EXPR. */
needs to be separately compiled). */
if (DECL_INLINE (function))
- {
- /* Is it a synthesized method that needs to be synthesized? */
- if (DECL_ARTIFICIAL (function) && ! DECL_INITIAL (function)
- /* Kludge: don't synthesize for default args. */
- && current_function_decl)
- synthesize_method (function);
-
- fntype = build_type_variant (TREE_TYPE (function),
- TREE_READONLY (function),
- TREE_THIS_VOLATILE (function));
- function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
- }
+ function = inline_conversion (function);
else
- function = default_conversion (function);
+ function = build_addr_func (function);
}
else
{
fndecl = NULL_TREE;
- /* Convert anything with function type to a pointer-to-function. */
- if (function == error_mark_node)
- return error_mark_node;
- function = default_conversion (function);
+ function = build_addr_func (function);
}
+ if (function == error_mark_node)
+ return error_mark_node;
+
fntype = TREE_TYPE (function);
if (TYPE_PTRMEMFUNC_P (fntype))
{
- tree instance_ptr = build_unary_op (ADDR_EXPR, C_C_D, 0);
- fntype = TYPE_PTRMEMFUNC_FN_TYPE (fntype);
- function = get_member_function_from_ptrfunc (&instance_ptr, function);
+ cp_error ("must use .* or ->* to call pointer-to-member function in `%E (...)'",
+ function);
+ return error_mark_node;
}
is_method = (TREE_CODE (fntype) == POINTER_TYPE
/* C++ */
value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
{
- register tree result =
- build (CALL_EXPR, value_type,
- function, coerced_params, NULL_TREE);
-
- TREE_SIDE_EFFECTS (result) = 1;
+ register tree result
+ = build_call (function, value_type, coerced_params);
- if (! require_complete)
- return convert_from_reference (result);
- if (value_type == void_type_node)
- return result;
- result = require_complete_type (result);
+ if (require_complete)
+ {
+ if (value_type == void_type_node)
+ return result;
+ result = require_complete_type (result);
+ }
+ if (IS_AGGR_TYPE (value_type))
+ result = build_cplus_new (value_type, result);
return convert_from_reference (result);
}
}
if (! flag_elide_constructors)
return_loc = 0;
+ /* Argument passing is always copy-initialization. */
+ flags |= LOOKUP_ONLYCONVERTING;
+
if (fndecl)
{
if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
{
if (fndecl)
{
- char *buf = (char *)alloca (40 + strlen (called_thing));
- sprintf (buf, "too many arguments to %s `%%s'", called_thing);
- error_with_decl (fndecl, buf);
+ cp_error_at ("too many arguments to %s `%+D'", called_thing,
+ fndecl);
error ("at this point in file");
}
else
else if (TREE_CODE (val) == OFFSET_REF
&& TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
{
- /* This is unclean. Should be handled elsewhere. */
+ /* This is unclean. Should be handled elsewhere. */
val = build_unary_op (ADDR_EXPR, val, 0);
}
else if (TREE_CODE (val) == OFFSET_REF)
}
else
{
- parmval = convert_for_initialization (return_loc, type, val,
- flags|INDIRECT_BIND,
- "argument passing", fndecl, i);
+ parmval = convert_for_initialization
+ (return_loc, type, val, flags,
+ "argument passing", fndecl, i);
#ifdef PROMOTE_PROTOTYPES
if ((TREE_CODE (type) == INTEGER_TYPE
|| TREE_CODE (type) == ENUMERAL_TYPE)
&& (TYPE_PRECISION (TREE_TYPE (val))
< TYPE_PRECISION (double_type_node)))
/* Convert `float' to `double'. */
- result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
+ result = tree_cons (NULL_TREE, cp_convert (double_type_node, val), result);
else if (TYPE_LANG_SPECIFIC (TREE_TYPE (val))
&& ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (val)))
{
{
tree rval;
- if (current_template_parms)
+ if (processing_template_decl)
return build_min_nt (code, arg1, arg2);
+ if (flag_ansi_overloading)
+ return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
+
rval = build_opfncall (code, LOOKUP_SPECULATIVELY,
arg1, arg2, NULL_TREE);
if (rval)
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+ || code0 == COMPLEX_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+ || code1 == COMPLEX_TYPE))
{
if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
cp_warning ("division by zero in `%E / 0'", op0);
/* Convert the shift-count to an integer, regardless of
size of value being shifted. */
if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
- op1 = convert (integer_type_node, op1);
+ op1 = cp_convert (integer_type_node, op1);
/* Avoid converting op1 to result_type later. */
converted = 1;
}
/* Convert the shift-count to an integer, regardless of
size of value being shifted. */
if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
- op1 = convert (integer_type_node, op1);
+ op1 = cp_convert (integer_type_node, op1);
/* Avoid converting op1 to result_type later. */
converted = 1;
}
/* Convert the shift-count to an integer, regardless of
size of value being shifted. */
if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
- op1 = convert (integer_type_node, op1);
+ op1 = cp_convert (integer_type_node, op1);
}
break;
case EQ_EXPR:
case NE_EXPR:
build_type = boolean_type_node;
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+ || code0 == COMPLEX_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+ || code1 == COMPLEX_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
else if (TYPE_PTRMEMFUNC_P (type0) && TREE_CODE (op1) == INTEGER_CST
&& integer_zerop (op1))
{
- op0 = build_component_ref (op0, index_identifier, 0, 0);
+ op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
op1 = integer_zero_node;
result_type = TREE_TYPE (op0);
}
else if (TYPE_PTRMEMFUNC_P (type1) && TREE_CODE (op0) == INTEGER_CST
&& integer_zerop (op0))
{
- op0 = build_component_ref (op1, index_identifier, 0, 0);
+ op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0);
op1 = integer_zero_node;
result_type = TREE_TYPE (op0);
}
&& ((op1.index != -1 && op0.delta2 == op1.delta2)
|| op0.pfn == op1.pfn)) */
- tree index0 = build_component_ref (op0, index_identifier, 0, 0);
- tree index1 = save_expr (build_component_ref (op1, index_identifier, 0, 0));
+ tree index0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
+ tree index1 = save_expr (build_component_ref (op1, index_identifier, NULL_TREE, 0));
tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
tree pfn1 = PFN_FROM_PTRMEMFUNC (op1);
tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
else if (TYPE_PTRMEMFUNC_P (type0)
&& TYPE_PTRMEMFUNC_FN_TYPE (type0) == type1)
{
- tree index0 = build_component_ref (op0, index_identifier, 0, 0);
+ tree index0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
tree index1;
tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
- if (pedantic)
- pedwarn ("ANSI C++ forbids comparison between pointer and integer");
- else if (! flag_traditional)
- warning ("comparison between pointer and integer");
+ pedwarn ("ANSI C++ forbids comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
- if (pedantic)
- pedwarn ("ANSI C++ forbids comparison between pointer and integer");
- else if (! flag_traditional)
- warning ("comparison between pointer and integer");
+ pedwarn ("ANSI C++ forbids comparison between pointer and integer");
}
break;
}
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
+ &&
+ (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
{
+ int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
+
if (shorten || common || short_compare)
result_type = common_type (type0, type1);
Eg, (short)-1 | (unsigned short)-1 is (int)-1
but calculated in (unsigned short) it would be (unsigned short)-1. */
- if (shorten)
+ if (shorten && none_complex)
{
int unsigned0, unsigned1;
tree arg0 = get_narrower (op0, &unsigned0);
TREE_TYPE (arg0));
/* Convert value-to-be-shifted to that type. */
if (TREE_TYPE (op0) != result_type)
- op0 = convert (result_type, op0);
+ op0 = cp_convert (result_type, op0);
converted = 1;
}
}
tree val
= shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
if (val != 0)
- return convert (boolean_type_node, val);
+ return cp_convert (boolean_type_node, val);
op0 = xop0, op1 = xop1;
converted = 1;
resultcode = xresultcode;
tree primop0 = get_narrower (op0, &unsignedp0);
tree primop1 = get_narrower (op1, &unsignedp1);
- /* Check for comparison of different enum types. */
+ /* Check for comparison of different enum types. */
if (flag_int_enum_equivalence == 0
&& TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE
&& TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE
if (! converted)
{
if (TREE_TYPE (op0) != result_type)
- op0 = convert (result_type, op0);
+ op0 = cp_convert (result_type, op0);
if (TREE_TYPE (op1) != result_type)
- op1 = convert (result_type, op1);
+ op1 = cp_convert (result_type, op1);
}
if (build_type == NULL_TREE)
if (folded == result)
TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
if (final_type != 0)
- return convert (final_type, folded);
+ return cp_convert (final_type, folded);
return folded;
}
}
so the multiply won't overflow spuriously. */
if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype))
- intop = convert (type_for_size (TYPE_PRECISION (sizetype), 0), intop);
+ intop = cp_convert (type_for_size (TYPE_PRECISION (sizetype), 0), intop);
/* Replace the integer argument with a suitable product by the object size.
Do this multiplication as signed, then convert to the appropriate
pointer type (actually unsigned integral). */
- intop = convert (result_type,
- build_binary_op (MULT_EXPR, intop,
- convert (TREE_TYPE (intop), size_exp), 1));
+ intop = cp_convert (result_type,
+ build_binary_op (MULT_EXPR, intop,
+ cp_convert (TREE_TYPE (intop), size_exp), 1));
/* Create the sum or difference. */
then drop through to build the divide operator. */
op0 = build_binary_op (MINUS_EXPR,
- convert (restype, op0), convert (restype, op1), 1);
+ cp_convert (restype, op0), cp_convert (restype, op1), 1);
/* This generates an error if op1 is a pointer to an incomplete type. */
if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0)
/* Do the division. */
- result = build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1));
+ result = build (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
folded = fold (result);
if (folded == result)
size_int (BITS_PER_UNIT));
int flag = TREE_CONSTANT (rval);
rval = fold (build (PLUS_EXPR, argtype,
- rval, convert (argtype, offset)));
+ rval, cp_convert (argtype, offset)));
TREE_CONSTANT (rval) = flag;
}
return rval;
enum tree_code code;
tree xarg;
{
- if (current_template_parms)
+ if (processing_template_decl)
return build_min_nt (code, xarg, NULL_TREE);
/* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
- error message. */
+ error message. */
if (code == ADDR_EXPR
&& ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
&& TYPE_SIZE (TREE_TYPE (xarg)) == NULL_TREE)
/* don't look for a function */;
else
{
- tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg,
- NULL_TREE, NULL_TREE);
- if (rval)
- return build_opfncall (code, LOOKUP_NORMAL, xarg,
+ tree rval;
+
+ if (flag_ansi_overloading)
+ {
+ rval = build_new_op (code, LOOKUP_NORMAL, xarg,
NULL_TREE, NULL_TREE);
+ if (rval || code != ADDR_EXPR)
+ return rval;
+ }
+ else
+ {
+ rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg,
+ NULL_TREE, NULL_TREE);
+ if (rval)
+ return build_opfncall (code, LOOKUP_NORMAL, xarg,
+ NULL_TREE, NULL_TREE);
+ }
+ }
+
+ if (code == ADDR_EXPR)
+ {
+ if (TREE_CODE (xarg) == TARGET_EXPR)
+ warning ("taking address of temporary");
}
+
return build_unary_op (code, xarg, 0);
}
tree expr;
{
tree t;
- if (current_template_parms)
+ if (processing_template_decl)
return expr;
- t = convert (boolean_type_node, expr);
+ t = cp_convert (boolean_type_node, expr);
t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
return t;
}
NOCONVERT nonzero suppresses the default promotions
(such as from short to int). */
+
tree
build_unary_op (code, xarg, noconvert)
enum tree_code code;
break;
case BIT_NOT_EXPR:
- if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM, arg, 1)))
+ if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+ {
+ code = CONJ_EXPR;
+ if (!noconvert)
+ arg = default_conversion (arg);
+ }
+ else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM,
+ arg, 1)))
errstring = "wrong type argument to bit-complement";
else if (!noconvert)
arg = default_conversion (arg);
arg = default_conversion (arg);
break;
+ case CONJ_EXPR:
+ /* Conjugating a real value is a no-op, but allow it anyway. */
+ if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+ errstring = "wrong type argument to conjugation";
+ else if (!noconvert)
+ arg = default_conversion (arg);
+ break;
+
case TRUTH_NOT_EXPR:
- arg = convert (boolean_type_node, arg);
+ arg = cp_convert (boolean_type_node, arg);
val = invert_truthvalue (arg);
if (arg != error_mark_node)
return val;
case NOP_EXPR:
break;
+ case REALPART_EXPR:
+ if (TREE_CODE (arg) == COMPLEX_CST)
+ return TREE_REALPART (arg);
+ else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+ return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+ else
+ return arg;
+
+ case IMAGPART_EXPR:
+ if (TREE_CODE (arg) == COMPLEX_CST)
+ return TREE_IMAGPART (arg);
+ else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+ return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+ else
+ return cp_convert (TREE_TYPE (arg), integer_zero_node);
+
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
if (val != 0)
return val;
+ /* Increment or decrement the real part of the value,
+ and don't change the imaginary part. */
+ if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+ {
+ tree real, imag;
+
+ arg = stabilize_reference (arg);
+ real = build_unary_op (REALPART_EXPR, arg, 1);
+ imag = build_unary_op (IMAGPART_EXPR, arg, 1);
+ return build (COMPLEX_EXPR, TREE_TYPE (arg),
+ build_unary_op (code, real, 1), imag);
+ }
+
/* Report invalid types. */
if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
else
inc = integer_one_node;
- inc = convert (argtype, inc);
+ inc = cp_convert (argtype, inc);
/* Handle incrementing a cast-expression. */
modify = build_modify_expr (arg, NOP_EXPR, incremented);
compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
- /* Eliminate warning about unused result of + or -. */
+ /* Eliminate warning about unused result of + or -. */
TREE_NO_UNUSED_WARNING (compound) = 1;
return compound;
}
val = build (code, TREE_TYPE (arg), arg, inc);
TREE_SIDE_EFFECTS (val) = 1;
- return convert (result_type, val);
+ return cp_convert (result_type, val);
}
case ADDR_EXPR:
argtype = TREE_TYPE (arg);
if (TREE_CODE (argtype) == REFERENCE_TYPE)
{
- arg = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
- TREE_REFERENCE_EXPR (arg) = 1;
+ arg = build1
+ (CONVERT_EXPR,
+ build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
+ TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
return arg;
}
else if (pedantic
/* Let &* cancel out to simplify resulting code. */
if (TREE_CODE (arg) == INDIRECT_REF)
{
- /* We don't need to have `current_class_decl' wrapped in a
+ /* We don't need to have `current_class_ptr' wrapped in a
NON_LVALUE_EXPR node. */
- if (arg == C_C_D)
- return current_class_decl;
+ if (arg == current_class_ref)
+ return current_class_ptr;
- /* Keep `default_conversion' from converting if
- ARG is of REFERENCE_TYPE. */
arg = TREE_OPERAND (arg, 0);
if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
{
- if (TREE_CODE (arg) == VAR_DECL && DECL_INITIAL (arg)
- && !TREE_SIDE_EFFECTS (DECL_INITIAL (arg)))
- arg = DECL_INITIAL (arg);
- arg = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
- TREE_REFERENCE_EXPR (arg) = 1;
+ arg = build1
+ (CONVERT_EXPR,
+ build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
}
else if (lvalue_p (arg))
function counts as a constant */
if (staticp (arg))
TREE_CONSTANT (addr) = 1;
+
+ if (TREE_CODE (argtype) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
+ {
+ build_ptrmemfunc_type (argtype);
+ addr = build_ptrmemfunc (argtype, addr, 0);
+ }
+
return addr;
}
}
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
- return convert (TREE_TYPE (conversions),
- convert_sequence (TREE_OPERAND (conversions, 0),
- arg));
+ return cp_convert (TREE_TYPE (conversions),
+ convert_sequence (TREE_OPERAND (conversions, 0),
+ arg));
default:
return arg;
|| TREE_CODE (arg) == INIT_EXPR)
{
tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
- return build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
+ arg = build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
+ TREE_NO_UNUSED_WARNING (arg) = 1;
+ return arg;
}
if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
is really the representation of a pointer to it.
Here give the representation its true type. */
tree t;
- tree offset;
my_friendly_assert (TREE_CODE (arg) != SCOPE_REF, 313);
t = TREE_OPERAND (arg, 1);
- if (TREE_CODE (t) == FUNCTION_DECL) /* Check all this code for right semantics. */
+ if (TREE_CODE (t) == FUNCTION_DECL) /* Check all this code for right semantics. */
return build_unary_op (ADDR_EXPR, t, 0);
if (TREE_CODE (t) == VAR_DECL)
return build_unary_op (ADDR_EXPR, t, 0);
else
{
+ tree type;
+ tree offset = integer_zero_node;
+
if (TREE_OPERAND (arg, 0)
&& (TREE_CODE (TREE_OPERAND (arg, 0)) != NOP_EXPR
|| TREE_OPERAND (TREE_OPERAND (arg, 0), 0) != error_mark_node))
return error_mark_node;
}
- offset = get_delta_difference (DECL_FIELD_CONTEXT (t),
- TREE_TYPE (TREE_OPERAND (arg, 0)),
- 0);
+ type = TREE_TYPE (TREE_OPERAND (arg, 0));
+
+ if (TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
+ {
+ /* Add in the offset to the intermediate subobject, if any. */
+ offset = get_delta_difference (TYPE_OFFSET_BASETYPE (TREE_TYPE (arg)),
+ type,
+ 0);
+ type = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg));
+ }
+
+ /* Now in the offset to the final subobject. */
+ offset = size_binop (PLUS_EXPR,
+ offset,
+ get_delta_difference (DECL_FIELD_CONTEXT (t),
+ type,
+ 0));
+
+ /* Add in the offset to the field. */
offset = size_binop (PLUS_EXPR, offset,
size_binop (EASY_DIV_EXPR,
DECL_FIELD_BITPOS (t),
size_int (BITS_PER_UNIT)));
- return convert (build_pointer_type (TREE_TYPE (arg)), offset);
- }
- }
-
- if (TREE_CODE (arg) == OFFSET_REF)
- {
- tree left = TREE_OPERAND (arg, 0), left_addr;
- tree right_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 1), 0);
- if (left == 0)
- if (current_class_decl)
- left_addr = current_class_decl;
- else
- {
- error ("no `this' for pointer to member");
- return error_mark_node;
- }
- else
- left_addr = build_unary_op (ADDR_EXPR, left, 0);
+ /* We offset all pointer to data memebers by 1 so that we can
+ distinguish between a null pointer to data member and the first
+ data member of a structure. */
+ offset = size_binop (PLUS_EXPR, offset, size_int (1));
- return build (PLUS_EXPR, build_pointer_type (TREE_TYPE (arg)),
- build1 (NOP_EXPR, integer_type_node, left_addr),
- build1 (NOP_EXPR, integer_type_node, right_addr));
+ return cp_convert (build_pointer_type (TREE_TYPE (arg)), offset);
+ }
}
+
/* We permit compiler to make function calls returning
objects of aggregate type look like lvalues. */
{
address of it; it should not be allocated in a register.
Value is 1 if successful.
- C++: we do not allow `current_class_decl' to be addressable. */
+ C++: we do not allow `current_class_ptr' to be addressable. */
int
mark_addressable (exp)
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_decl)
+ if (x == current_class_ptr)
{
- error ("address of `this' not available");
+ if (! flag_this_is_variable)
+ error ("address of `this' not available");
TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
put_var_into_stack (x);
return 1;
case CONST_DECL:
case RESULT_DECL:
- /* For C++, we don't warn about taking the address of a register
- variable for CONST_DECLs; ARM p97 explicitly says it's okay. */
+ if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
+ && !DECL_ARTIFICIAL (x) && extra_warnings)
+ cp_warning ("address requested for `%D', which is declared `register'",
+ x);
put_var_into_stack (x);
TREE_ADDRESSABLE (x) = 1;
return 1;
TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
return 1;
+ case CONSTRUCTOR:
+ TREE_ADDRESSABLE (x) = 1;
+ return 1;
+
+ case TARGET_EXPR:
+ TREE_ADDRESSABLE (x) = 1;
+ mark_addressable (TREE_OPERAND (x, 0));
+ return 1;
+
default:
return 1;
}
{
tree rval = NULL_TREE;
- if (current_template_parms)
+ if (processing_template_decl)
return build_min_nt (COND_EXPR, ifexp, op1, op2);
+ if (flag_ansi_overloading)
+ return build_new_op (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
+
/* See comments in `build_x_binary_op'. */
if (op1 != 0)
rval = build_opfncall (COND_EXPR, LOOKUP_SPECULATIVELY, ifexp, op1, op2);
register enum tree_code code1;
register enum tree_code code2;
register tree result_type = NULL_TREE;
- tree orig_op1 = op1, orig_op2 = op2;
/* If second operand is omitted, it is the same as the first one;
make sure it is calculated only once. */
ifexp = op1 = save_expr (ifexp);
}
- ifexp = convert (boolean_type_node, ifexp);
+ ifexp = cp_convert (boolean_type_node, ifexp);
if (TREE_CODE (ifexp) == ERROR_MARK)
return error_mark_node;
result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
if (TREE_TYPE (result) != type1)
result = build1 (NOP_EXPR, type1, result);
+ /* Expand both sides into the same slot,
+ hopefully the target of the ?: expression. */
+ if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR)
+ {
+ tree slot = build (VAR_DECL, TREE_TYPE (result));
+ layout_decl (slot, 0);
+ result = build (TARGET_EXPR, TREE_TYPE (result),
+ slot, result, NULL_TREE, NULL_TREE);
+ }
return result;
}
pedwarn ("ANSI C++ forbids conditional expr with only one void side");
result_type = void_type_node;
}
+ else if (code1 == POINTER_TYPE && null_ptr_cst_p (op2))
+ result_type = qualify_type (type1, type2);
+ else if (code2 == POINTER_TYPE && null_ptr_cst_p (op1))
+ result_type = qualify_type (type2, type1);
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
if (comp_target_types (type1, type2, 1))
result_type = common_type (type1, type2);
- else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
- && TREE_CODE (orig_op1) != NOP_EXPR)
- result_type = qualify_type (type2, type1);
- else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node
- && TREE_CODE (orig_op2) != NOP_EXPR)
- result_type = qualify_type (type1, type2);
else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
{
if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
}
else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
{
- if (!integer_zerop (op2))
- pedwarn ("pointer/integer type mismatch in conditional expression");
- else
- op2 = null_pointer_node;
-
+ pedwarn ("pointer/integer type mismatch in conditional expression");
result_type = type1;
}
else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- if (!integer_zerop (op1))
- pedwarn ("pointer/integer type mismatch in conditional expression");
- else
- op1 = null_pointer_node;
-
+ pedwarn ("pointer/integer type mismatch in conditional expression");
result_type = type2;
}
cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'", type1, type2);
return error_mark_node;
}
+ /* Warning: this code assumes that conversion between cv-variants of
+ a type is done using NOP_EXPRs. */
if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
{
- tree tmp = build_type_conversion (CONVERT_EXPR, type2, op1, 0);
+ /* There are other types besides pointers and records. */
+ tree tmp;
+ if (code2 == POINTER_TYPE)
+ tmp = build_pointer_type
+ (build_type_variant (TREE_TYPE (type2), 1, 1));
+ else
+ tmp = type2;
+ tmp = build_type_conversion (CONVERT_EXPR, tmp, op1, 0);
if (tmp == NULL_TREE)
{
- cp_error ("aggregate type `%T' could not convert on lhs of `:'", type1);
+ cp_error ("incompatible types `%T' and `%T' in `?:'",
+ type1, type2);
return error_mark_node;
}
if (tmp == error_mark_node)
error ("ambiguous pointer conversion");
- result_type = type2;
+ else
+ STRIP_NOPS (tmp);
+ result_type = common_type (type2, TREE_TYPE (tmp));
op1 = tmp;
}
else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
{
- tree tmp = build_type_conversion (CONVERT_EXPR, type1, op2, 0);
+ tree tmp;
+ if (code1 == POINTER_TYPE)
+ tmp = build_pointer_type
+ (build_type_variant (TREE_TYPE (type1), 1, 1));
+ else
+ tmp = type1;
+
+ tmp = build_type_conversion (CONVERT_EXPR, tmp, op2, 0);
if (tmp == NULL_TREE)
{
- cp_error ("aggregate type `%T' could not convert on rhs of `:'", type2);
+ cp_error ("incompatible types `%T' and `%T' in `?:'",
+ type1, type2);
return error_mark_node;
}
if (tmp == error_mark_node)
error ("ambiguous pointer conversion");
- result_type = type1;
+ else
+ STRIP_NOPS (tmp);
+ result_type = common_type (type1, TREE_TYPE (tmp));
op2 = tmp;
}
else if (flag_cond_mismatch)
\f
/* Handle overloading of the ',' operator when needed. Otherwise,
this function just builds an expression list. */
+
tree
build_x_compound_expr (list)
tree list;
tree rest = TREE_CHAIN (list);
tree result;
- if (current_template_parms)
+ if (processing_template_decl)
return build_min_nt (COMPOUND_EXPR, list, NULL_TREE);
if (rest == NULL_TREE)
break_out_cleanups (TREE_VALUE (list)), rest);
}
-tree build_static_cast (type, expr)
+tree
+build_static_cast (type, expr)
tree type, expr;
{
- return build_c_cast (type, expr, 0);
+ tree intype, binfo;
+ int ok;
+
+ if (type == error_mark_node || expr == error_mark_node)
+ return error_mark_node;
+
+ if (TREE_CODE (expr) == OFFSET_REF)
+ expr = resolve_offset_ref (expr);
+
+ if (processing_template_decl)
+ {
+ tree t = build_min (STATIC_CAST_EXPR, type, expr);
+ return t;
+ }
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (type) != REFERENCE_TYPE
+ && TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
+
+ if (TREE_CODE (type) == VOID_TYPE)
+ return build1 (CONVERT_EXPR, type, expr);
+
+ if (type_unknown_p (expr))
+ {
+ expr = instantiate_type (type, expr, 1);
+ if (expr == error_mark_node)
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ return (convert_from_reference
+ (convert_to_reference (type, expr, CONV_STATIC|CONV_IMPLICIT,
+ LOOKUP_COMPLAIN, NULL_TREE)));
+
+ if (IS_AGGR_TYPE (type))
+ return build_cplus_new
+ (type, (build_method_call
+ (NULL_TREE, ctor_identifier, build_tree_list (NULL_TREE, expr),
+ TYPE_BINFO (type), LOOKUP_NORMAL)));
+
+ expr = decay_conversion (expr);
+ intype = TREE_TYPE (expr);
+
+ /* FIXME handle casting to array type. */
+
+ ok = 0;
+ if (can_convert_arg (type, intype, expr))
+ ok = 1;
+ else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
+ {
+ tree binfo;
+ if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
+ && (TYPE_READONLY (TREE_TYPE (type))
+ >= TYPE_READONLY (TREE_TYPE (intype)))
+ && (TYPE_VOLATILE (TREE_TYPE (type))
+ >= TYPE_VOLATILE (TREE_TYPE (intype)))
+ && (binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 0))
+ && ! TREE_VIA_VIRTUAL (binfo))
+ ok = 1;
+ }
+ else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+ {
+ if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))),
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (intype))), 1)
+ && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (type)))
+ >= TYPE_READONLY (TREE_TYPE (TREE_TYPE (intype))))
+ && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (type)))
+ >= TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (intype))))
+ && (binfo = get_binfo (TYPE_OFFSET_BASETYPE (intype),
+ TYPE_OFFSET_BASETYPE (type), 0))
+ && ! TREE_VIA_VIRTUAL (binfo))
+ ok = 1;
+ }
+ else if (TREE_CODE (intype) != BOOLEAN_TYPE
+ && TREE_CODE (type) != ARRAY_TYPE
+ && TREE_CODE (type) != FUNCTION_TYPE
+ && can_convert (intype, type))
+ ok = 1;
+
+ if (ok)
+ return build_c_cast (type, expr);
+
+ cp_error ("static_cast from `%T' to `%T'", intype, type);
+ return error_mark_node;
}
-tree build_reinterpret_cast (type, expr)
+tree
+build_reinterpret_cast (type, expr)
tree type, expr;
{
- tree intype = TREE_TYPE (expr);
+ tree intype;
- if (TYPE_PTRMEMFUNC_P (type))
- type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+ if (type == error_mark_node || expr == error_mark_node)
+ return error_mark_node;
- if (current_template_parms)
+ if (TREE_CODE (expr) == OFFSET_REF)
+ expr = resolve_offset_ref (expr);
+
+ if (processing_template_decl)
{
tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
return t;
}
- if (TYPE_PTRMEMFUNC_P (intype))
- intype = TYPE_PTRMEMFUNC_FN_TYPE (intype);
+ if (TREE_CODE (type) != REFERENCE_TYPE)
+ {
+ expr = decay_conversion (expr);
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
+ }
- if (! POINTER_TYPE_P (type) && ! TREE_CODE (type) == INTEGER_TYPE)
+ if (type_unknown_p (expr))
{
- cp_error ("reinterpret_cast cannot convert to type `%T'", type);
- return error_mark_node;
+ expr = instantiate_type (type, expr, 1);
+ if (expr == error_mark_node)
+ return error_mark_node;
}
- if (! POINTER_TYPE_P (intype) && ! TREE_CODE (intype) == INTEGER_TYPE)
+
+ intype = TREE_TYPE (expr);
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
{
- cp_error ("reinterpret_cast cannot convert from type `%T'", type);
- return error_mark_node;
+ if (! real_lvalue_p (expr))
+ {
+ cp_error ("reinterpret_cast from `%T' rvalue to `%T'", intype, type);
+ return error_mark_node;
+ }
+ expr = build_unary_op (ADDR_EXPR, expr, 0);
+ if (expr != error_mark_node)
+ expr = build_reinterpret_cast
+ (build_pointer_type (TREE_TYPE (type)), expr);
+ if (expr != error_mark_node)
+ expr = build_indirect_ref (expr, 0);
+ return expr;
}
- if (TREE_CODE (type) == INTEGER_TYPE && TREE_CODE (intype) != POINTER_TYPE)
+ else if (comptypes (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type), 1))
+ return build_static_cast (type, expr);
+
+ if (TYPE_PTR_P (type) && (TREE_CODE (intype) == INTEGER_TYPE
+ || TREE_CODE (intype) == ENUMERAL_TYPE))
+ /* OK */;
+ else if (TREE_CODE (type) == INTEGER_TYPE && TYPE_PTR_P (intype))
{
- cp_error ("reinterpret_cast cannot convert non-pointer type `%T' to `%T'",
- intype, type);
- return error_mark_node;
+ if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
+ cp_pedwarn ("reinterpret_cast from `%T' to `%T' loses precision",
+ intype, type);
}
- if (TREE_CODE (intype) == INTEGER_TYPE && TREE_CODE (type) != POINTER_TYPE)
+ else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
+ || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
{
- cp_error ("reinterpret_cast cannot convert `%T' to non-pointer type `%T'",
- intype, type);
- return error_mark_node;
+ if (TREE_READONLY_DECL_P (expr))
+ expr = decl_constant_value (expr);
+ return fold (build1 (NOP_EXPR, type, expr));
}
+ else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+ || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
+ {
+ if (! comp_ptr_ttypes_reinterpret (TREE_TYPE (type), TREE_TYPE (intype)))
+ cp_pedwarn ("reinterpret_cast from `%T' to `%T' casts away const (or volatile)",
+ intype, type);
- if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (intype) == POINTER_TYPE)
- expr = convert (ptr_type_node, expr);
-
- return build_c_cast (type, expr, 0);
+ if (TREE_READONLY_DECL_P (expr))
+ expr = decl_constant_value (expr);
+ return fold (build1 (NOP_EXPR, type, expr));
+ }
+ else
+ {
+ cp_error ("reinterpret_cast from `%T' to `%T'", intype, type);
+ return error_mark_node;
+ }
+
+ return cp_convert (type, expr);
}
-tree build_const_cast (type, expr)
+tree
+build_const_cast (type, expr)
tree type, expr;
{
- tree intype = TREE_TYPE (expr);
- tree t1, t2;
+ tree intype;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
- if (TYPE_PTRMEMFUNC_P (type))
- type = TYPE_PTRMEMFUNC_FN_TYPE (type);
- if (TYPE_PTRMEMFUNC_P (intype))
- intype = TYPE_PTRMEMFUNC_FN_TYPE (intype);
+ if (TREE_CODE (expr) == OFFSET_REF)
+ expr = resolve_offset_ref (expr);
- if (! POINTER_TYPE_P (type))
- {
- cp_error ("const_cast cannot convert to non-pointer type `%T'", type);
- return error_mark_node;
- }
- if (TREE_CODE (type) == REFERENCE_TYPE && ! real_lvalue_p (expr))
+ if (processing_template_decl)
{
- cp_error ("const_cast cannot convert rvalue to type `%T'", type);
- return error_mark_node;
+ tree t = build_min (CONST_CAST_EXPR, type, expr);
+ return t;
}
- if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (intype) != POINTER_TYPE)
+
+ if (TREE_CODE (type) != REFERENCE_TYPE)
{
- cp_error ("const_cast cannot convert non-pointer type `%T' to type `%T'",
- intype, type);
- return error_mark_node;
+ expr = decay_conversion (expr);
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
}
- if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (type_unknown_p (expr))
{
- t1 = TREE_TYPE (type);
- t2 = intype;
+ expr = instantiate_type (type, expr, 1);
+ if (expr == error_mark_node)
+ return error_mark_node;
}
- else
- {
- t1 = TREE_TYPE (type);
- t2 = TREE_TYPE (intype);
- for (; TREE_CODE (t1) == POINTER_TYPE && TREE_CODE (t2) == POINTER_TYPE;
- t1 = TREE_TYPE (t1), t2 = TREE_TYPE (t2))
- ;
- }
+ intype = TREE_TYPE (expr);
- if (TREE_CODE (t1) == OFFSET_TYPE && TREE_CODE (t2) == OFFSET_TYPE)
+ if (comptypes (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type), 1))
+ return build_static_cast (type, expr);
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
{
- if (TYPE_OFFSET_BASETYPE (t1) != TYPE_OFFSET_BASETYPE (t2))
+ if (! real_lvalue_p (expr))
{
- cp_error ("const_cast cannot convert between pointers to members of different types `%T' and `%T'",
- TYPE_OFFSET_BASETYPE (t2), TYPE_OFFSET_BASETYPE (t1));
+ cp_error ("const_cast from `%T' rvalue to `%T'", intype, type);
return error_mark_node;
}
- t1 = TREE_TYPE (t1);
- t2 = TREE_TYPE (t2);
- }
- if (TYPE_MAIN_VARIANT (t1) != TYPE_MAIN_VARIANT (t2))
- {
- cp_error ("const_cast cannot convert unrelated type `%T' to `%T'",
- t2, t1);
- return error_mark_node;
+ if (comp_ptr_ttypes_const (TREE_TYPE (type), intype))
+ return (convert_from_reference
+ (convert_to_reference (type, expr, CONV_CONST|CONV_IMPLICIT,
+ LOOKUP_COMPLAIN, NULL_TREE)));
}
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (intype) == POINTER_TYPE
+ && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
+ return cp_convert (type, expr);
- return build_c_cast (type, expr, 0);
+ cp_error ("const_cast from `%T' to `%T'", intype, type);
+ return error_mark_node;
}
/* Build an expression representing a cast to type TYPE of expression EXPR.
when doing the cast. */
tree
-build_c_cast (type, expr, allow_nonconverting)
- register tree type;
- tree expr;
- int allow_nonconverting;
+build_c_cast (type, expr)
+ tree type, expr;
{
register tree value = expr;
return error_mark_node;
}
- /* If there's only one function in the overloaded space,
- just take it. */
- if (TREE_CODE (value) == TREE_LIST
- && TREE_CHAIN (value) == NULL_TREE)
- value = TREE_VALUE (value);
-
- if (current_template_parms)
+ if (processing_template_decl)
{
tree t = build_min (CAST_EXPR, type,
min_tree_cons (NULL_TREE, value, NULL_TREE));
else
{
tree otype;
- int flag;
/* Convert functions and arrays to pointers and
convert references to their expanded types,
but don't convert any other types. */
if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
+ || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
+ /* Don't do the default conversion if we want a
+ pointer to a function. */
+ && ! (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE))
|| TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
value = default_conversion (value);
warning ("cast to pointer from integer of different size");
#endif
- flag = allow_nonconverting ? CONV_NONCONVERTING : 0;
-
if (TREE_CODE (type) == REFERENCE_TYPE)
value = (convert_from_reference
- (convert_to_reference (type, value, CONV_OLD_CONVERT|flag,
+ (convert_to_reference (type, value, CONV_C_CAST,
LOOKUP_COMPLAIN, NULL_TREE)));
else
{
value = decl_constant_value (value);
ovalue = value;
- value = convert_force (type, value, flag);
+ value = convert_force (type, value, CONV_C_CAST);
/* Ignore any integer overflow caused by the cast. */
if (TREE_CODE (value) == INTEGER_CST)
}
/* Always produce some operator for an explicit cast,
- so we can tell (for -pedantic) that the cast is no lvalue.
- Also, pedantically, don't let (void *) (FOO *) 0 be a null
- pointer constant. */
- if (TREE_CODE (type) != REFERENCE_TYPE
- && (value == expr
- || (pedantic
- && TREE_CODE (value) == INTEGER_CST
- && TREE_CODE (expr) == INTEGER_CST
- && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)))
+ so we can tell (for -pedantic) that the cast is no lvalue. */
+ if (TREE_CODE (type) != REFERENCE_TYPE && value == expr
+ && real_lvalue_p (value))
value = non_lvalue (value);
return value;
do_pending_stack_adjust ();
start_sequence_for_rtl_expr (xval);
emit_note (0, -1);
- rtxval = expand_expr (t, NULL, VOIDmode, 0);
+ rtxval = expand_expr (t, NULL_RTX, VOIDmode, 0);
do_pending_stack_adjust ();
TREE_SIDE_EFFECTS (xval) = 1;
RTL_EXPR_SEQUENCE (xval) = get_insns ();
to combine the old value of LHS with RHS to get the new value.
Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.
- C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.
-*/
+ C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed. */
+
tree
build_modify_expr (lhs, modifycode, rhs)
tree lhs;
tree olhs = lhs;
/* Avoid duplicate error messages from operands that had errors. */
- if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
+ if (lhs == error_mark_node || rhs == error_mark_node)
return error_mark_node;
/* Types that aren't fully specified cannot be used in assignments. */
/* Handle assignment to signature pointers/refs. */
- if (TYPE_LANG_SPECIFIC (lhstype) &&
- (IS_SIGNATURE_POINTER (lhstype) || IS_SIGNATURE_REFERENCE (lhstype)))
+ if (TYPE_LANG_SPECIFIC (lhstype)
+ && (IS_SIGNATURE_POINTER (lhstype) || IS_SIGNATURE_REFERENCE (lhstype)))
{
return build_signature_pointer_constructor (lhs, rhs);
}
case PREINCREMENT_EXPR:
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
lhs = build (TREE_CODE (lhs), TREE_TYPE (lhs),
- stabilize_reference (TREE_OPERAND (lhs, 0)));
+ stabilize_reference (TREE_OPERAND (lhs, 0)),
+ TREE_OPERAND (lhs, 1));
return build (COMPOUND_EXPR, lhstype,
lhs,
build_modify_expr (TREE_OPERAND (lhs, 0),
case COMPOUND_EXPR:
newrhs = build_modify_expr (TREE_OPERAND (lhs, 1),
modifycode, rhs);
- if (TREE_CODE (newrhs) == ERROR_MARK)
+ if (newrhs == error_mark_node)
return error_mark_node;
return build (COMPOUND_EXPR, lhstype,
TREE_OPERAND (lhs, 0), newrhs);
case MODIFY_EXPR:
newrhs = build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs);
- if (TREE_CODE (newrhs) == ERROR_MARK)
+ if (newrhs == error_mark_node)
return error_mark_node;
return build (COMPOUND_EXPR, lhstype, lhs, newrhs);
so the code to compute it is only emitted once. */
tree cond
= build_conditional_expr (TREE_OPERAND (lhs, 0),
- build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
+ build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
modifycode, rhs),
- build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
+ build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
modifycode, rhs));
- if (TREE_CODE (cond) == ERROR_MARK)
+ if (cond == error_mark_node)
return cond;
/* Make sure the code to compute the rhs comes out
before the split. */
return build (COMPOUND_EXPR, TREE_TYPE (lhs),
/* Case to void to suppress warning
from warn_if_unused_value. */
- convert (void_type_node, rhs), cond);
+ cp_convert (void_type_node, rhs), cond);
}
}
/* Do the default thing */;
else
{
- result = build_method_call (lhs, constructor_name_full (lhstype),
+ result = build_method_call (lhs, ctor_identifier,
build_tree_list (NULL_TREE, rhs),
- NULL_TREE, LOOKUP_NORMAL);
+ TYPE_BINFO (lhstype), LOOKUP_NORMAL);
if (result == NULL_TREE)
return error_mark_node;
return result;
else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (lhstype)
&& TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
{
- if (warn_synth)
- /* If we care about this, do overload resolution. */
- build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
+ build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
+ lhs, rhs, make_node (NOP_EXPR));
/* Do the default thing */;
}
}
else
{
- cp_error ("no match for `%O(%#T, %#T)'", modifycode,
+ cp_error ("no match for `%Q(%#T, %#T)'", modifycode,
TREE_TYPE (lhs), TREE_TYPE (rhs));
return error_mark_node;
}
{
lhs = stabilize_reference (lhs);
newrhs = build_binary_op (modifycode, lhs, rhs, 1);
+ if (newrhs == error_mark_node)
+ {
+ cp_error (" in evaluation of `%Q(%#T, %#T)'", modifycode,
+ TREE_TYPE (lhs), TREE_TYPE (rhs));
+ return error_mark_node;
+ }
}
/* Handle a cast used as an "lvalue".
{
tree inner_lhs = TREE_OPERAND (lhs, 0);
tree result;
- if (! lvalue_p (lhs) && pedantic)
- pedwarn ("cast to non-reference type used as lvalue");
+
+ /* WP 5.4.1: The result is an lvalue if T is a reference type,
+ otherwise the result is an rvalue. */
+ if (! lvalue_p (lhs))
+ pedwarn ("ANSI C++ forbids cast to non-reference type used as lvalue");
result = build_modify_expr (inner_lhs, NOP_EXPR,
- convert (TREE_TYPE (inner_lhs),
- convert (lhstype, newrhs)));
- if (TREE_CODE (result) == ERROR_MARK)
+ cp_convert (TREE_TYPE (inner_lhs),
+ cp_convert (lhstype, newrhs)));
+ if (result == error_mark_node)
return result;
- return convert (TREE_TYPE (lhs), result);
+ return cp_convert (TREE_TYPE (lhs), result);
}
}
}
/* check to see if there is an assignment to `this' */
- if (lhs == current_class_decl)
+ if (lhs == current_class_ptr)
{
if (flag_this_is_variable > 0
&& DECL_NAME (current_function_decl) != NULL_TREE
}
else
{
- /* Avoid warnings on enum bit fields. */
+ /* Avoid warnings on enum bit fields. */
if (TREE_CODE (olhstype) == ENUMERAL_TYPE
&& TREE_CODE (lhstype) == INTEGER_TYPE)
{
expanded without a target. */
if (TREE_CODE (newrhs) == TARGET_EXPR)
newrhs = build (COMPOUND_EXPR, TREE_TYPE (newrhs), newrhs,
- TREE_VALUE (newrhs));
+ TREE_OPERAND (newrhs, 0));
}
- if (TREE_CODE (newrhs) == ERROR_MARK)
+ if (newrhs == error_mark_node)
return error_mark_node;
if (TREE_CODE (newrhs) == COND_EXPR)
result
= build (COND_EXPR, result_type, cond,
build_modify_expr (lhs, modifycode,
- convert (result_type,
- TREE_OPERAND (newrhs, 1))),
+ cp_convert (result_type,
+ TREE_OPERAND (newrhs, 1))),
build_modify_expr (lhs1, modifycode,
- convert (result_type,
- TREE_OPERAND (newrhs, 2))));
+ cp_convert (result_type,
+ TREE_OPERAND (newrhs, 2))));
}
}
else
if (olhstype == TREE_TYPE (result))
return result;
/* Avoid warnings converting integral types back into enums
- for enum bit fields. */
+ for enum bit fields. */
if (TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
&& TREE_CODE (olhstype) == ENUMERAL_TYPE)
{
enum tree_code modifycode;
tree rhs;
{
- if (current_template_parms)
+ if (processing_template_decl)
return build_min_nt (MODOP_EXPR, lhs,
- build_min_nt (modifycode, 0, 0), rhs);
+ build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
if (modifycode != NOP_EXPR)
{
/* Get difference in deltas for different pointer to member function
types. Return integer_zero_node, if FROM cannot be converted to a
TO type. If FORCE is true, then allow reverse conversions as well. */
+
static tree
get_delta_difference (from, to, force)
tree from, to;
binfo = get_binfo (from, to, 1);
if (binfo == error_mark_node)
{
- error (" in pointer to member function conversion");
+ error (" in pointer to member function conversiona");
return delta;
}
if (binfo == 0)
if (!force)
{
error_not_base_type (from, to);
- error (" in pointer to member function conversion");
+ error (" in pointer to member conversion");
return delta;
}
binfo = get_binfo (to, from, 1);
if (binfo == error_mark_node)
{
- error (" in pointer to member function conversion");
+ if (!force)
+ error (" in pointer to member conversion");
return delta;
}
if (binfo == 0)
{
- error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
+ if (!force)
+ cp_error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
return delta;
}
if (TREE_VIA_VIRTUAL (binfo))
{
+ binfo = binfo_member (BINFO_TYPE (binfo),
+ CLASSTYPE_VBASECLASSES (from));
warning ("pointer to member conversion to virtual base class will only work if you are very careful");
}
+ delta = BINFO_OFFSET (binfo);
+ delta = cp_convert (ptrdiff_type_node, delta);
+
return build_binary_op (MINUS_EXPR,
integer_zero_node,
- BINFO_OFFSET (binfo), 1);
+ delta, 1);
}
if (TREE_VIA_VIRTUAL (binfo))
{
return BINFO_OFFSET (binfo);
}
+static tree
+build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
+ tree type, delta, idx, pfn, delta2;
+{
+ tree u;
+
+#if 0
+ /* This is the old way we did it. We want to avoid calling
+ digest_init, so that it can give an error if we use { } when
+ initializing a pointer to member function. */
+
+ if (pfn)
+ {
+ u = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (pfn_identifier, pfn, NULL_TREE));
+ }
+ else
+ {
+ u = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (delta2_identifier, delta2, NULL_TREE));
+ }
+
+ u = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE, delta,
+ tree_cons (NULL_TREE, idx,
+ tree_cons (NULL_TREE, u, NULL_TREE))));
+
+ return digest_init (type, u, (tree*)0);
+#else
+ tree delta_field, idx_field, pfn_or_delta2_field, pfn_field, delta2_field;
+ tree subtype;
+ int allconstant, allsimple;
+
+ delta_field = TYPE_FIELDS (type);
+ idx_field = TREE_CHAIN (delta_field);
+ pfn_or_delta2_field = TREE_CHAIN (idx_field);
+ subtype = TREE_TYPE (pfn_or_delta2_field);
+ pfn_field = TYPE_FIELDS (subtype);
+ delta2_field = TREE_CHAIN (pfn_field);
+
+ if (pfn)
+ {
+ allconstant = TREE_CONSTANT (pfn);
+ allsimple = initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
+ u = tree_cons (pfn_field, pfn, NULL_TREE);
+ }
+ else
+ {
+ delta2 = convert_and_check (delta_type_node, delta2);
+ allconstant = TREE_CONSTANT (delta2);
+ allsimple = initializer_constant_valid_p (delta2, TREE_TYPE (delta2));
+ u = tree_cons (delta2_field, delta2, NULL_TREE);
+ }
+
+ delta = convert_and_check (delta_type_node, delta);
+ idx = convert_and_check (delta_type_node, idx);
+
+ allconstant = allconstant && TREE_CONSTANT (delta) && TREE_CONSTANT (idx);
+ allsimple = allsimple
+ && initializer_constant_valid_p (delta, TREE_TYPE (delta))
+ && initializer_constant_valid_p (idx, TREE_TYPE (idx));
+
+ u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
+ u = tree_cons (delta_field, delta,
+ tree_cons (idx_field, idx,
+ tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
+ u = build (CONSTRUCTOR, type, NULL_TREE, u);
+ TREE_CONSTANT (u) = allconstant;
+ TREE_STATIC (u) = allconstant && allsimple;
+ return u;
+#endif
+}
+
/* Build a constructor for a pointer to member function. It can be
used to initialize global variables, local variable, or used
as a value in expressions. TYPE is the POINTER to METHOD_TYPE we
tree type, pfn;
int force;
{
- tree index = integer_zero_node;
+ tree idx = integer_zero_node;
tree delta = integer_zero_node;
tree delta2 = integer_zero_node;
tree vfield_offset;
- tree npfn;
- tree u;
+ tree npfn = NULL_TREE;
- /* Handle multiple conversions of pointer to member functions. */
+ /* Handle multiple conversions of pointer to member functions. */
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
{
- tree ndelta, ndelta2, nindex;
+ tree ndelta, ndelta2;
+ tree e1, e2, e3, n;
+
/* Is is already the right type? */
if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
return pfn;
- if (TREE_CODE (pfn) != CONSTRUCTOR)
- {
- tree e1, e2, e3;
- ndelta = convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, 0, 0));
- ndelta2 = convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
- index = build_component_ref (pfn, index_identifier, 0, 0);
- delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
- TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
- force);
- delta = build_binary_op (PLUS_EXPR, delta, ndelta, 1);
- delta2 = build_binary_op (PLUS_EXPR, ndelta2, delta2, 1);
- e1 = fold (build (GT_EXPR, boolean_type_node, index, integer_zero_node));
+ ndelta = cp_convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0));
+ ndelta2 = cp_convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
+ idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0);
+
+ n = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
+ TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
+ force);
+
+ delta = build_binary_op (PLUS_EXPR, ndelta, n, 1);
+ delta2 = build_binary_op (PLUS_EXPR, ndelta2, n, 1);
+ e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node));
- u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
- u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, index,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- e2 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+ e2 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx,
+ NULL_TREE, delta2);
- pfn = PFN_FROM_PTRMEMFUNC (pfn);
- npfn = build1 (NOP_EXPR, type, pfn);
- TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+ pfn = PFN_FROM_PTRMEMFUNC (pfn);
+ npfn = build1 (NOP_EXPR, type, pfn);
+ TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
- u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
- u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, index,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- e3 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
- return build_conditional_expr (e1, e2, e3);
- }
-
- ndelta = TREE_VALUE (CONSTRUCTOR_ELTS (pfn));
- nindex = TREE_VALUE (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn)));
- npfn = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn))));
- npfn = TREE_VALUE (CONSTRUCTOR_ELTS (npfn));
- if (integer_zerop (nindex))
- pfn = integer_zero_node;
- else if (integer_zerop (fold (size_binop (PLUS_EXPR, nindex, integer_one_node))))
- {
- tree e3;
- delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
- TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
- force);
- delta = build_binary_op (PLUS_EXPR, delta, ndelta, 1);
- pfn = build1 (NOP_EXPR, type, npfn);
- TREE_CONSTANT (pfn) = TREE_CONSTANT (npfn);
-
- u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, pfn, NULL_TREE));
- u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, nindex,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- e3 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
- return e3;
- }
- else
- {
- sorry ("value casting of variable nonnull pointer to member functions not supported");
- return error_mark_node;
- }
+ e3 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn,
+ NULL_TREE);
+ return build_conditional_expr (e1, e2, e3);
}
- /* Handle null pointer to member function conversions. */
+ /* Handle null pointer to member function conversions. */
if (integer_zerop (pfn))
{
- pfn = build_c_cast (type, integer_zero_node, 0);
- u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, pfn, NULL_TREE));
- u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, integer_zero_node,
- tree_cons (NULL_TREE, integer_zero_node,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+ pfn = build_c_cast (type, integer_zero_node);
+ return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type),
+ integer_zero_node, integer_zero_node,
+ pfn, NULL_TREE);
}
if (TREE_CODE (pfn) == TREE_LIST
|| (TREE_CODE (pfn) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (pfn, 0)) == TREE_LIST))
- {
- pfn = instantiate_type (type, pfn, 1);
- if (pfn == error_mark_node)
- return error_mark_node;
- if (TREE_CODE (pfn) != ADDR_EXPR)
- pfn = build_unary_op (ADDR_EXPR, pfn, 0);
- }
+ return instantiate_type (type, pfn, 1);
- /* Allow pointer to member conversions here. */
+ /* Allow pointer to member conversions here. */
delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
force);
delta2 = build_binary_op (PLUS_EXPR, delta2, delta, 1);
+#if 0
+ /* We need to check the argument types to see if they are compatible
+ (any const or volatile violations. */
+ something like this:
+ comptype (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (type))),
+ TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn)))), ?);
+#endif
+
if (TREE_CODE (TREE_OPERAND (pfn, 0)) != FUNCTION_DECL)
warning ("assuming pointer to member function is non-virtual");
if (TREE_CODE (TREE_OPERAND (pfn, 0)) == FUNCTION_DECL
&& DECL_VINDEX (TREE_OPERAND (pfn, 0)))
{
- /* Find the offset to the vfield pointer in the object. */
+ /* Find the offset to the vfield pointer in the object. */
vfield_offset = get_binfo (DECL_CONTEXT (TREE_OPERAND (pfn, 0)),
DECL_CLASS_CONTEXT (TREE_OPERAND (pfn, 0)),
0);
delta2 = size_binop (PLUS_EXPR, vfield_offset, delta2);
/* Map everything down one to make room for the null pointer to member. */
- index = size_binop (PLUS_EXPR,
- DECL_VINDEX (TREE_OPERAND (pfn, 0)),
- integer_one_node);
- u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
+ idx = size_binop (PLUS_EXPR,
+ DECL_VINDEX (TREE_OPERAND (pfn, 0)),
+ integer_one_node);
}
else
{
- index = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
-
- npfn = build1 (NOP_EXPR, type, pfn);
- TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+ idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
- u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
+ if (type == TREE_TYPE (pfn))
+ {
+ npfn = pfn;
+ }
+ else
+ {
+ npfn = build1 (NOP_EXPR, type, pfn);
+ TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+ }
}
- u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, index,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+ return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, delta2);
}
/* Convert value RHS to type TYPE as preparation for an assignment
return error_mark_node;
}
/* Arithmetic types all interconvert. */
- if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE)
- && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE))
+ if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE
+ || codel == COMPLEX_TYPE)
+ && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE
+ || coder == COMPLEX_TYPE))
{
/* But we should warn if assigning REAL_TYPE to INTEGER_TYPE. */
if (coder == REAL_TYPE && codel == INTEGER_TYPE)
|| (coder == ENUMERAL_TYPE
&& (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE)))
{
- return cp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
+ return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
}
/* Conversions among pointers */
else if (codel == POINTER_TYPE
return error_mark_node;
}
- if (ctt < 0)
+ if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr))
cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
rhstype, type);
if (TYPE_MAIN_VARIANT (ttl) != void_type_node
&& TYPE_MAIN_VARIANT (ttr) == void_type_node
- && rhs != null_pointer_node)
+ && ! null_ptr_cst_p (rhs))
{
if (coder == RECORD_TYPE)
cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
}
}
}
- else if (TREE_CODE (ttr) == OFFSET_TYPE
- && TREE_CODE (ttl) != OFFSET_TYPE)
- {
- /* Normally, pointers to different type codes (other
- than void) are not compatible, but we perform
- some type instantiation if that resolves the
- ambiguity of (X Y::*) and (X *). */
-
- if (current_class_decl)
- {
- if (TREE_CODE (rhs) == INTEGER_CST)
- {
- rhs = build (PLUS_EXPR, build_pointer_type (TREE_TYPE (ttr)),
- current_class_decl, rhs);
- return convert_for_assignment (type, rhs,
- errtype, fndecl, parmnum);
- }
- }
- if (TREE_CODE (ttl) == METHOD_TYPE)
- error ("%s between pointer-to-method and pointer-to-member types",
- errtype);
- else
- error ("%s between pointer and pointer-to-member types", errtype);
- return error_mark_node;
- }
else
{
int add_quals = 0, const_parity = 0, volatile_parity = 0;
cp_warning ("\t`%T' != `%T'", type, rhstype);
}
}
- else if (TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
- {
- /* When does this happen? */
- my_friendly_abort (119);
- /* Conversion of a pointer-to-member type to void *. */
- rhs = build_unary_op (ADDR_EXPR, rhs, 0);
- TREE_TYPE (rhs) = type;
- return rhs;
- }
- else if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
- {
- /* When does this happen? */
- my_friendly_abort (120);
- /* Conversion of a pointer-to-member type to void *. */
- rhs = build_unary_op (ADDR_EXPR, rhs, 0);
- TREE_TYPE (rhs) = type;
- return rhs;
- }
else
{
if (fndecl)
return error_mark_node;
}
}
- return convert (type, rhs);
+ return cp_convert (type, rhs);
}
else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
{
else
cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
errtype, type, rhstype);
- return convert (type, rhs);
}
- return null_pointer_node;
+ return cp_convert (type, rhs);
}
else if (codel == INTEGER_TYPE
&& (coder == POINTER_TYPE
else
cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
errtype, type, rhstype);
- return convert (type, rhs);
+ return cp_convert (type, rhs);
}
else if (codel == BOOLEAN_TYPE
&& (coder == POINTER_TYPE
&& (IS_SIGNATURE_POINTER (rhstype)
|| TYPE_PTRMEMFUNC_FLAG (rhstype)
|| IS_SIGNATURE_REFERENCE (rhstype)))))
- return convert (type, rhs);
+ return cp_convert (type, rhs);
/* C++ */
else if (((coder == POINTER_TYPE
else if (ctt == 0)
cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr);
- /* compatible pointer to member functions. */
+ /* compatible pointer to member functions. */
return build_ptrmemfunc (ttl, rhs, 0);
}
else if (codel == ERROR_MARK || coder == ERROR_MARK)
return nrhs;
}
else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
- return convert (type, rhs);
+ return cp_convert (type, rhs);
+ /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+ || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
+ && TREE_TYPE (rhs)
+ && TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
+ return cp_convert (type, rhs);
cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
return error_mark_node;
exist, an ambiguity exists.
If flags doesn't include LOOKUP_COMPLAIN, don't complain about anything. */
+
tree
convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
tree exp, type, rhs;
if (TREE_CODE (rhstype) == REFERENCE_TYPE)
rhstype = TREE_TYPE (rhstype);
+ type = complete_type (type);
+
if (TYPE_LANG_SPECIFIC (type)
&& (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
return build_signature_pointer_constructor (type, rhs);
if (IS_AGGR_TYPE (type)
&& (TYPE_NEEDS_CONSTRUCTING (type) || TREE_HAS_CONSTRUCTOR (rhs)))
{
+ if (flag_ansi_overloading)
+ return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
+
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
{
/* This is sufficient to perform initialization. No need,
{
if (TYPE_HAS_INIT_REF (type))
{
- tree init = build_method_call (exp, constructor_name_full (type),
+ tree init = build_method_call (exp, ctor_identifier,
build_tree_list (NULL_TREE, rhs),
TYPE_BINFO (type), LOOKUP_NORMAL);
return rhs;
}
- return cp_convert (type, rhs, CONV_OLD_CONVERT, flags);
+ return ocp_convert (type, rhs, CONV_OLD_CONVERT,
+ flags | LOOKUP_NO_CONVERSION);
}
if (type == TREE_TYPE (rhs))
extern tree dtor_label, ctor_label;
tree result = DECL_RESULT (current_function_decl);
tree valtype = TREE_TYPE (result);
- int returns_value = 1;
if (TREE_THIS_VOLATILE (current_function_decl))
warning ("function declared `noreturn' has a `return' statement");
return;
}
- if (current_template_parms)
+ if (processing_template_decl)
{
add_tree (build_min_nt (RETURN_STMT, retval));
return;
}
if (DECL_CONSTRUCTOR_P (current_function_decl))
- retval = current_class_decl;
+ retval = current_class_ptr;
else if (DECL_NAME (result) != NULL_TREE
&& TREE_CODE (valtype) != VOID_TYPE)
retval = result;
}
}
else if (DECL_CONSTRUCTOR_P (current_function_decl)
- && retval != current_class_decl)
+ && retval != current_class_ptr)
{
- error ("return from a constructor: use `this = ...' instead");
- retval = current_class_decl;
+ if (flag_this_is_variable)
+ error ("return from a constructor: use `this = ...' instead");
+ else
+ error ("return from a constructor");
+ retval = current_class_ptr;
}
+ /* Effective C++ rule 15. See also start_function. */
+ if (warn_ecpp
+ && DECL_NAME (current_function_decl) == ansi_opname[(int) MODIFY_EXPR]
+ && retval != current_class_ref)
+ cp_warning ("`operator=' should return a reference to `*this'");
+
if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
{
current_function_returns_null = 1;
- /* We do this here so we'll avoid a warning about how the function
- "may or may not return a value" in finish_function. */
- returns_value = 0;
-
- if (retval)
+ if ((pedantic && ! DECL_ARTIFICIAL (current_function_decl))
+ || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
pedwarn ("`return' with a value, in function returning void");
expand_return (retval);
+ return;
}
/* Add some useful error checking for C++. */
else if (TREE_CODE (valtype) == REFERENCE_TYPE)
/* convert to reference now, so we can give error if we
return an reference to a non-lvalue. */
- retval = convert_for_initialization (tmp_result, valtype, retval,
- LOOKUP_NORMAL, "return",
- NULL_TREE, 0);
+ retval = convert_for_initialization
+ (tmp_result, valtype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
+ "return", NULL_TREE, 0);
/* Sort through common things to see what it is
we are returning. */
if (TREE_CODE (whats_returned) == ADDR_EXPR)
whats_returned = TREE_OPERAND (whats_returned, 0);
}
+ if (TREE_CODE (whats_returned) == CONVERT_EXPR)
+ whats_returned = TREE_OPERAND (whats_returned, 0);
if (TREE_CODE (whats_returned) == ADDR_EXPR)
{
whats_returned = TREE_OPERAND (whats_returned, 0);
&& !TREE_PUBLIC (whats_returned))
cp_warning_at ("address of local variable `%D' returned", whats_returned);
}
+ else if (TREE_CODE (retval) == VAR_DECL)
+ {
+ if (TREE_CODE (TREE_TYPE (retval)) == ARRAY_TYPE
+ && DECL_NAME (retval)
+ && IDENTIFIER_LOCAL_VALUE (DECL_NAME (retval))
+ && !TREE_STATIC (retval)
+ && !TREE_PUBLIC (retval))
+ cp_warning_at ("address of local array `%D' returned", retval);
+ }
/* Now deal with possible C++ hair:
(1) Compute the return value.
(3) If an X(X&) constructor is defined, the return
value must be returned via that. */
- /* If we're returning in a register, we can't initialize the
- return value from a TARGET_EXPR. */
- if (TREE_CODE (retval) == TARGET_EXPR
- && TYPE_MAIN_VARIANT (TREE_TYPE (retval)) == TYPE_MAIN_VARIANT (valtype)
- && ! current_function_returns_struct)
- retval = expand_target_expr (retval);
-
if (retval == result
- /* Watch out for constructors, which "return" aggregates
- via initialization, but which otherwise "return" a pointer. */
|| DECL_CONSTRUCTOR_P (current_function_decl))
+ /* It's already done for us. */;
+ else if (TREE_TYPE (retval) == void_type_node)
{
- /* This is just an error--it's already been reported. */
- if (TYPE_SIZE (valtype) == NULL_TREE)
- return;
-
- if (TYPE_MODE (valtype) != BLKmode
- && any_pending_cleanups (1))
- retval = get_temp_regvar (valtype, retval);
- }
- else if (IS_AGGR_TYPE (valtype) && current_function_returns_struct)
- {
- expand_aggr_init (result, retval, 0, LOOKUP_ONLYCONVERTING);
- expand_cleanups_to (NULL_TREE);
- DECL_INITIAL (result) = NULL_TREE;
+ pedwarn ("return of void value in function returning non-void");
+ expand_expr_stmt (retval);
retval = 0;
}
else
{
- if (TYPE_MODE (valtype) == VOIDmode)
- {
- if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode
- && warn_return_type)
- warning ("return of void value in function returning non-void");
- expand_expr_stmt (retval);
- retval = 0;
- result = 0;
- }
- else if (TYPE_MODE (valtype) != BLKmode
- && any_pending_cleanups (1))
- {
- retval = get_temp_regvar (valtype, retval);
- expand_cleanups_to (NULL_TREE);
- result = 0;
- }
- else
+ /* We already did this above for refs, don't do it again. */
+ if (TREE_CODE (valtype) != REFERENCE_TYPE)
+ retval = convert_for_initialization
+ (NULL_TREE, valtype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
+ "return", NULL_TREE, 0);
+
+ /* We can't initialize a register from a NEW_EXPR. */
+ if (! current_function_returns_struct
+ && TREE_CODE (retval) == TARGET_EXPR
+ && TREE_CODE (TREE_OPERAND (retval, 1)) == NEW_EXPR)
+ retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
+ TREE_OPERAND (retval, 0));
+
+ if (retval == error_mark_node)
{
- retval = convert_for_initialization (result, valtype, retval,
- LOOKUP_NORMAL,
- "return", NULL_TREE, 0);
- DECL_INITIAL (result) = NULL_TREE;
+ /* Avoid warning about control reaching end of function. */
+ expand_null_return ();
+ return;
}
- if (retval == error_mark_node)
- return;
}
- emit_queue ();
-
if (retval != NULL_TREE
&& TREE_CODE_CLASS (TREE_CODE (retval)) == 'd'
&& cond_stack == 0 && loop_stack == 0 && case_stack == 0)
current_function_return_value = retval;
- if (result)
+ if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
{
- /* Everything's great--RETVAL is in RESULT. */
- if (original_result_rtx)
- {
- store_expr (result, original_result_rtx, 0);
- expand_cleanups_to (NULL_TREE);
- use_variable (DECL_RTL (result));
- if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
- expand_goto (ctor_label);
- else
- expand_null_return ();
- }
- else if (retval && retval != result)
- {
- /* Clear this out so the later call to decl_function_context
- won't end up bombing on us. */
- if (DECL_CONTEXT (result) == error_mark_node)
- DECL_CONTEXT (result) = NULL_TREE;
- /* Here is where we finally get RETVAL into RESULT.
- `expand_return' does the magic of protecting
- RESULT from cleanups. */
- retval = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (result),
- retval));
- /* This part _must_ come second, because expand_return looks for
- the INIT_EXPR as the toplevel node only. :-( */
- retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
- TREE_SIDE_EFFECTS (retval) = 1;
- expand_return (retval);
- }
- else
- expand_return (result);
+ /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do. */
+ expand_goto (ctor_label);
}
- else
+
+ if (retval && retval != result)
{
- /* We may still need to put RETVAL into RESULT. */
- result = DECL_RESULT (current_function_decl);
- if (original_result_rtx)
- {
- /* Here we have a named return value that went
- into memory. We can compute RETVAL into that. */
- if (retval)
- expand_assignment (result, retval, 0, 0);
- else
- store_expr (result, original_result_rtx, 0);
- result = make_tree (TREE_TYPE (result), original_result_rtx);
- }
- else if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
- {
- /* Here RETVAL is CURRENT_CLASS_DECL, so there's nothing to do. */
- expand_goto (ctor_label);
- }
- else if (retval)
- {
- /* Here is where we finally get RETVAL into RESULT.
- `expand_return' does the magic of protecting
- RESULT from cleanups. */
- result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
- TREE_SIDE_EFFECTS (result) = 1;
- expand_return (result);
- }
- else if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode)
- expand_return (result);
+ result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
+ TREE_SIDE_EFFECTS (result) = 1;
}
-
- current_function_returns_value = returns_value;
-
- /* One way to clear out cleanups that EXPR might
- generate. Note that this code will really be
- dead code, but that is ok--cleanups that were
- needed were handled by the magic of `return'. */
- expand_cleanups_to (NULL_TREE);
+ expand_return (result);
+ current_function_returns_value = 1;
}
\f
/* Start a C switch statement, testing expression EXP.
}
else
{
- tree index;
+ tree idx;
exp = default_conversion (exp);
type = TREE_TYPE (exp);
- index = get_unwidened (exp, 0);
+ idx = get_unwidened (exp, 0);
/* We can't strip a conversion from a signed type to an unsigned,
because if we did, int_fits_type_p would do the wrong thing
when checking case values for being in range,
and it's too hard to do the right thing. */
if (TREE_UNSIGNED (TREE_TYPE (exp))
- == TREE_UNSIGNED (TREE_TYPE (index)))
- exp = index;
+ == TREE_UNSIGNED (TREE_TYPE (idx)))
+ exp = idx;
}
expand_start_case
/* CONSTP remembers whether or not all the intervening pointers in the `to'
type have been const. */
-int
+
+static int
comp_ptr_ttypes_real (to, from, constp)
tree to, from;
int constp;
if (TREE_CODE (to) != TREE_CODE (from))
return 0;
+ if (TREE_CODE (from) == OFFSET_TYPE
+ && comptypes (TYPE_OFFSET_BASETYPE (from),
+ TYPE_OFFSET_BASETYPE (to), 1))
+ continue;
+
/* Const and volatile mean something different for function types,
so the usual checks are not appropriate. */
if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
/* When comparing, say, char ** to char const **, this function takes the
'char *' and 'char const *'. Do not pass non-pointer types to this
function. */
+
int
comp_ptr_ttypes (to, from)
tree to, from;
{
return comp_ptr_ttypes_real (to, from, 1);
}
+
+/* Returns 1 if to and from are (possibly multi-level) pointers to the same
+ type or inheritance-related types, regardless of cv-quals. */
+
+int
+ptr_reasonably_similar (to, from)
+ tree to, from;
+{
+ for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+ {
+ if (TREE_CODE (to) != TREE_CODE (from))
+ return 0;
+
+ if (TREE_CODE (from) == OFFSET_TYPE
+ && comptypes (TYPE_OFFSET_BASETYPE (to),
+ TYPE_OFFSET_BASETYPE (from), -1))
+ continue;
+
+ if (TREE_CODE (to) != POINTER_TYPE)
+ return comptypes
+ (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), -1);
+ }
+}
+
+/* Like comp_ptr_ttypes, for const_cast. */
+
+static int
+comp_ptr_ttypes_const (to, from)
+ tree to, from;
+{
+ for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+ {
+ if (TREE_CODE (to) != TREE_CODE (from))
+ return 0;
+
+ if (TREE_CODE (from) == OFFSET_TYPE
+ && comptypes (TYPE_OFFSET_BASETYPE (from),
+ TYPE_OFFSET_BASETYPE (to), 1))
+ continue;
+
+ if (TREE_CODE (to) != POINTER_TYPE)
+ return comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1);
+ }
+}
+
+/* Like comp_ptr_ttypes, for reinterpret_cast. */
+
+static int
+comp_ptr_ttypes_reinterpret (to, from)
+ tree to, from;
+{
+ int constp = 1;
+
+ for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+ {
+ if (TREE_CODE (from) == OFFSET_TYPE)
+ from = TREE_TYPE (from);
+ if (TREE_CODE (to) == OFFSET_TYPE)
+ to = TREE_TYPE (to);
+
+ if (TREE_CODE (to) != TREE_CODE (from))
+ return 1;
+
+ /* Const and volatile mean something different for function types,
+ so the usual checks are not appropriate. */
+ if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
+ {
+ if (TYPE_READONLY (from) > TYPE_READONLY (to)
+ || TYPE_VOLATILE (from) > TYPE_VOLATILE (to))
+ return 0;
+
+ if (! constp
+ && (TYPE_READONLY (to) > TYPE_READONLY (from)
+ || TYPE_VOLATILE (to) > TYPE_READONLY (from)))
+ return 0;
+ constp &= TYPE_READONLY (to);
+ }
+
+ if (TREE_CODE (to) != POINTER_TYPE)
+ return 1;
+ }
+}