/* Build expressions with type checking for C++ compiler.
- Copyright (C) 1987, 88, 89, 92, 93, 1994 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.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* This file is part of the C++ front end.
#include "rtl.h"
#include "cp-tree.h"
#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));
+#if 0
static tree convert_sequence ();
-/* static */ tree unary_complex_lvalue ();
-tree truthvalue_conversion ();
+#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. */
require_complete_type (value)
tree value;
{
- tree type = TREE_TYPE (value);
+ tree type;
+
+ if (current_template_parms)
+ return value;
+
+ type = TREE_TYPE (value);
/* First, detect a valid value with a complete type. */
if (TYPE_SIZE (type) != 0
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_MAIN_VARIANT (type));
+ if (TYPE_SIZE (type) != 0)
+ return value;
+ }
+
incomplete_type_error (value, type);
return error_mark_node;
}
+tree
+complete_type (type)
+ tree type;
+{
+ if (TYPE_SIZE (type) != NULL_TREE)
+ ;
+ else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
+ {
+ tree t = complete_type (TREE_TYPE (type));
+ if (TYPE_SIZE (t) != NULL_TREE)
+ type = build_cplus_array_type (t, TYPE_DOMAIN (type));
+ }
+ else if (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
+ instantiate_class_template (TYPE_MAIN_VARIANT (type));
+
+ return type;
+}
+
/* Return truthvalue of whether type of EXP is instantiated. */
int
type_unknown_p (exp)
int constflag = TYPE_READONLY (type) || TYPE_READONLY (like);
int volflag = TYPE_VOLATILE (type) || TYPE_VOLATILE (like);
/* @@ Must do member pointers here. */
- return build_type_variant (type, constflag, volflag);
+ return cp_build_type_variant (type, constflag, volflag);
}
\f
/* Return the common type of two parameter lists.
{
if (TREE_PURPOSE (p1) && !TREE_PURPOSE (p2))
{
- /* We used to give a warning here that advised about a default
- argument being given in the prototype but not in the function's
- declaration. It's best not to bother. */
TREE_PURPOSE (n) = TREE_PURPOSE (p1);
any_change = 1;
}
}
else
{
- int cmp = simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2));
- if (cmp < 0)
- my_friendly_abort (111);
- if (cmp == 0)
+ if (1 != simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2)))
any_change = 1;
TREE_PURPOSE (n) = TREE_PURPOSE (p2);
}
{
register enum tree_code code1;
register enum tree_code code2;
+ tree attributes;
/* Save time if the two types are the same. */
if (t2 == error_mark_node)
return t1;
+ /* Merge the attributes */
+
+ { register tree a1, a2;
+ a1 = TYPE_ATTRIBUTES (t1);
+ a2 = TYPE_ATTRIBUTES (t2);
+
+ /* Either one unset? Take the set one. */
+
+ if (!(attributes = a1))
+ attributes = a2;
+
+ /* One that completely contains the other? Take it. */
+
+ else if (a2 && !attribute_list_contained (a1, a2))
+ if (attribute_list_contained (a2, a1))
+ attributes = a2;
+ else
+ {
+ /* Pick the longest list, and hang on the other list. */
+ /* ??? For the moment we punt on the issue of attrs with args. */
+
+ if (list_length (a1) < list_length (a2))
+ attributes = a2, a2 = a1;
+
+ for (; a2; a2 = TREE_CHAIN (a2))
+ if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
+ attributes) == NULL_TREE)
+ {
+ a1 = copy_node (a2);
+ TREE_CHAIN (a1) = attributes;
+ attributes = a1;
+ }
+ }
+ }
+
/* Treat an enum type as the unsigned integer type of the same width. */
if (TREE_CODE (t1) == ENUMERAL_TYPE)
if (TREE_CODE (t2) == ENUMERAL_TYPE)
t2 = type_for_size (TYPE_PRECISION (t2), 1);
+ if (TYPE_PTRMEMFUNC_P (t1))
+ t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+ if (TYPE_PTRMEMFUNC_P (t2))
+ t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
/* If only one is real, use it as the result. */
if (code1 == REAL_TYPE && code2 != REAL_TYPE)
- return t1;
+ return build_type_attribute_variant (t1, attributes);
if (code2 == REAL_TYPE && code1 != REAL_TYPE)
- return t2;
+ return build_type_attribute_variant (t2, attributes);
/* Both real or both integers; use the one with greater precision. */
if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
- return t1;
+ return build_type_attribute_variant (t1, attributes);
else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
- return t2;
+ return build_type_attribute_variant (t2, attributes);
/* Same precision. Prefer longs to ints even when same size. */
-
+
if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
|| TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
- return long_unsigned_type_node;
+ return build_type_attribute_variant (long_unsigned_type_node,
+ attributes);
if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node
|| TYPE_MAIN_VARIANT (t2) == long_integer_type_node)
/* But preserve unsignedness from the other type,
since long cannot hold all the values of an unsigned int. */
if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
- return long_unsigned_type_node;
- return long_integer_type_node;
+ t1 = long_unsigned_type_node;
+ else
+ t1 = long_integer_type_node;
+ return build_type_attribute_variant (t1, attributes);
}
+ if (TYPE_MAIN_VARIANT (t1) == long_double_type_node
+ || TYPE_MAIN_VARIANT (t2) == long_double_type_node)
+ return build_type_attribute_variant (long_double_type_node,
+ attributes);
+
/* Otherwise prefer the unsigned one. */
if (TREE_UNSIGNED (t1))
- return t1;
- else return t2;
+ return build_type_attribute_variant (t1, attributes);
+ else
+ return build_type_attribute_variant (t2, attributes);
case POINTER_TYPE:
case REFERENCE_TYPE:
But ANSI C++ specifies doing this with the qualifiers.
So I turned it on again. */
{
- tree target = common_type (TYPE_MAIN_VARIANT (TREE_TYPE (t1)),
- TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
+ tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (t1));
+ tree tt2 = TYPE_MAIN_VARIANT (TREE_TYPE (t2));
int constp
= TYPE_READONLY (TREE_TYPE (t1)) || TYPE_READONLY (TREE_TYPE (t2));
int volatilep
= TYPE_VOLATILE (TREE_TYPE (t1)) || TYPE_VOLATILE (TREE_TYPE (t2));
- target = build_type_variant (target, constp, volatilep);
+ tree target;
+
+ if (tt1 == tt2)
+ target = tt1;
+ else if (tt1 == void_type_node || tt2 == void_type_node)
+ target = void_type_node;
+ else
+ target = common_type (tt1, tt2);
+
+ target = cp_build_type_variant (target, constp, volatilep);
if (code1 == POINTER_TYPE)
- return build_pointer_type (target);
+ t1 = build_pointer_type (target);
else
- return build_reference_type (target);
- }
-#if 0
- case POINTER_TYPE:
- return build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
+ t1 = build_reference_type (target);
+ t1 = build_type_attribute_variant (t1, attributes);
- case REFERENCE_TYPE:
- return build_reference_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
-#endif
+ if (TREE_CODE (target) == METHOD_TYPE)
+ t1 = build_ptrmemfunc_type (t1);
+
+ return t1;
+ }
case ARRAY_TYPE:
{
tree elt = common_type (TREE_TYPE (t1), TREE_TYPE (t2));
/* Save space: see if the result is identical to one of the args. */
if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
- return t1;
+ return build_type_attribute_variant (t1, attributes);
if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
- return t2;
+ return build_type_attribute_variant (t2, attributes);
/* Merge the element types, and have a size if either arg has one. */
- return build_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);
}
case FUNCTION_TYPE:
/* Save space: see if the result is identical to one of the args. */
if (valtype == TREE_TYPE (t1) && ! p2)
- return t1;
+ return build_type_attribute_variant (t1, attributes);
if (valtype == TREE_TYPE (t2) && ! p1)
- return t2;
+ return build_type_attribute_variant (t2, attributes);
/* Simple way if one arg fails to specify argument types. */
if (p1 == NULL_TREE || TREE_VALUE (p1) == void_type_node)
{
rval = build_function_type (valtype, p2);
if ((raises = TYPE_RAISES_EXCEPTIONS (t2)))
- rval = build_exception_variant (NULL_TREE, rval, raises);
- return rval;
+ rval = build_exception_variant (rval, raises);
+ return build_type_attribute_variant (rval, attributes);
}
raises = TYPE_RAISES_EXCEPTIONS (t1);
if (p2 == NULL_TREE || TREE_VALUE (p2) == void_type_node)
{
rval = build_function_type (valtype, p1);
if (raises)
- rval = build_exception_variant (NULL_TREE, rval, raises);
- return rval;
+ rval = build_exception_variant (rval, raises);
+ return build_type_attribute_variant (rval, attributes);
}
rval = build_function_type (valtype, commonparms (p1, p2));
- return build_exception_variant (NULL_TREE, rval, raises);
+ rval = build_exception_variant (rval, raises);
+ return build_type_attribute_variant (rval, attributes);
}
case RECORD_TYPE:
my_friendly_assert (TYPE_MAIN_VARIANT (t1) == t1
&& TYPE_MAIN_VARIANT (t2) == t2, 306);
- if (binfo_or_else (t1, t2))
- return t1;
- compiler_error ("common_type called with uncommon aggregate types");
- return t1;
+ if (DERIVED_FROM_P (t1, t2) && binfo_or_else (t1, t2))
+ return build_type_attribute_variant (t1, attributes);
+ else if (binfo_or_else (t2, t1))
+ return build_type_attribute_variant (t2, attributes);
+ else
+ compiler_error ("common_type called with uncommon aggregate types");
case METHOD_TYPE:
- if (comptypes (TYPE_METHOD_BASETYPE (t1), TYPE_METHOD_BASETYPE (t2), 1)
- && TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
+ if (TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
{
/* Get this value the long way, since TYPE_METHOD_BASETYPE
is just the main variant of this. */
- tree basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1)));
+ tree basetype;
tree raises, t3;
+ tree b1 = TYPE_OFFSET_BASETYPE (t1);
+ tree b2 = TYPE_OFFSET_BASETYPE (t2);
+
+ if (comptypes (b1, b2, 1)
+ || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
+ basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2)));
+ else
+ {
+ if (binfo_or_else (b2, b1) == NULL_TREE)
+ compiler_error ("common_type called with uncommon method types");
+ basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1)));
+ }
+
raises = TYPE_RAISES_EXCEPTIONS (t1);
/* If this was a member function type, get back to the
t2 = build_function_type (TREE_TYPE (t2), TREE_CHAIN (TYPE_ARG_TYPES (t2)));
t3 = common_type (t1, t2);
t3 = build_cplus_method_type (basetype, TREE_TYPE (t3), TYPE_ARG_TYPES (t3));
- return build_exception_variant (basetype, t3, raises);
+ t1 = build_exception_variant (t3, raises);
}
- compiler_error ("common_type called with uncommon method types");
- return t1;
+ else
+ compiler_error ("common_type called with uncommon method types");
+
+ return build_type_attribute_variant (t1, attributes);
case OFFSET_TYPE:
- if (TYPE_OFFSET_BASETYPE (t1) == TYPE_OFFSET_BASETYPE (t2)
- && TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
+ if (TREE_TYPE (t1) == TREE_TYPE (t2))
{
- tree basetype = TYPE_OFFSET_BASETYPE (t1);
- return build_offset_type (basetype,
- common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
+ tree b1 = TYPE_OFFSET_BASETYPE (t1);
+ tree b2 = TYPE_OFFSET_BASETYPE (t2);
+
+ if (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);
}
compiler_error ("common_type called with uncommon member types");
- return t1;
default:
- return t1;
+ return build_type_attribute_variant (t1, attributes);
}
}
\f
/* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */
int
-compexcepttypes (t1, t2, strict)
+compexcepttypes (t1, t2)
tree t1, t2;
- int strict;
{
return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
}
2 : strict, except that if one type is a reference and
the other is not, compare the target type of the
reference to the type that's not a reference (ARM, p308).
+ This is used for checking for invalid overloading.
1 : strict (compared according to ANSI C)
+ This is used for checking whether two function decls match.
0 : <= (compared according to C++)
-1: <= or >= (relaxed)
Otherwise, pointers involving base classes and derived classes
- can be mixed as legal: i.e. a pointer to a base class may be assigned
+ can be mixed as valid: i.e. a pointer to a base class may be assigned
to a pointer to one of its derived classes, as per C++. A pointer to
a derived class may be passed as a parameter to a function expecting a
pointer to a base classes. These allowances do not commute. In this
{
register tree t1 = type1;
register tree t2 = type2;
+ int attrval, val;
/* Suppress errors caused by previously reported errors */
return 1;
}
+ if (TYPE_PTRMEMFUNC_P (t1))
+ t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+ if (TYPE_PTRMEMFUNC_P (t2))
+ t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
/* Different classes of types can't be compatible. */
if (TREE_CODE (t1) != TREE_CODE (t2))
if (TYPE_READONLY (t1) != TYPE_READONLY (t2))
return 0;
- if (TREE_THIS_VOLATILE (t1) != TREE_THIS_VOLATILE (t2))
+ if (TYPE_VOLATILE (t1) != TYPE_VOLATILE (t2))
return 0;
/* Allow for two different type nodes which have essentially the same
if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return 1;
+ /* ??? COMP_TYPE_ATTRIBUTES is currently useless for variables as each
+ attribute is its own main variant (`val' will remain 0). */
+#ifndef COMP_TYPE_ATTRIBUTES
+#define COMP_TYPE_ATTRIBUTES(t1,t2) 1
+#endif
+
+ /* 1 if no need for warning yet, 2 if warning cause has been seen. */
+ if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2)))
+ return 0;
+
+ /* 1 if no need for warning yet, 2 if warning cause has been seen. */
+ val = 0;
+
switch (TREE_CODE (t1))
{
case RECORD_TYPE:
case UNION_TYPE:
- if (t1 == t2)
- return 1;
+ if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2)
+ && CLASSTYPE_TI_TEMPLATE (t1) == CLASSTYPE_TI_TEMPLATE (t2))
+ {
+ int i = TREE_VEC_LENGTH (CLASSTYPE_TI_ARGS (t1));
+ tree *p1 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t1), 0);
+ tree *p2 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t2), 0);
+
+ while (i--)
+ {
+ if (TREE_CODE_CLASS (TREE_CODE (p1[i])) == 't')
+ {
+ if (! comptypes (p1[i], p2[i], 1))
+ return 0;
+ }
+ else
+ {
+ if (simple_cst_equal (p1[i], p2[i]) <= 0)
+ return 0;
+ }
+ }
+ return 1;
+ }
if (strict <= 0)
goto look_hard;
return 0;
case OFFSET_TYPE:
- return (comptypes (TYPE_POINTER_TO (TYPE_OFFSET_BASETYPE (t1)),
- TYPE_POINTER_TO (TYPE_OFFSET_BASETYPE (t2)), strict)
- && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict));
+ val = (comptypes (build_pointer_type (TYPE_OFFSET_BASETYPE (t1)),
+ build_pointer_type (TYPE_OFFSET_BASETYPE (t2)), strict)
+ && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict));
+ break;
case METHOD_TYPE:
- if (! compexcepttypes (t1, t2, strict))
+ if (! compexcepttypes (t1, t2))
return 0;
/* This case is anti-symmetrical!
to something expecting a derived member (or member function),
but not vice-versa! */
- return (comptypes (TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (t2)),
- TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (t1)), strict)
- && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
- && compparms (TREE_CHAIN (TYPE_ARG_TYPES (t1)),
- TREE_CHAIN (TYPE_ARG_TYPES (t2)), strict));
+ val = (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
+ && compparms (TYPE_ARG_TYPES (t1),
+ TYPE_ARG_TYPES (t2), strict));
+ break;
+
case POINTER_TYPE:
case REFERENCE_TYPE:
t1 = TREE_TYPE (t1);
t2 = TREE_TYPE (t2);
if (t1 == t2)
- return 1;
+ {
+ val = 1;
+ break;
+ }
if (strict <= 0)
{
if (TREE_CODE (t1) == RECORD_TYPE && TREE_CODE (t2) == RECORD_TYPE)
rval = t1 == t2 || UNIQUELY_DERIVED_FROM_P (t1, t2);
if (rval)
- return 1;
+ {
+ val = 1;
+ break;
+ }
if (strict < 0)
- return UNIQUELY_DERIVED_FROM_P (t2, t1);
+ {
+ val = UNIQUELY_DERIVED_FROM_P (t2, t1);
+ break;
+ }
}
return 0;
}
else
- return comptypes (t1, t2, strict);
+ val = comptypes (t1, t2, strict);
+ break;
case FUNCTION_TYPE:
- if (! compexcepttypes (t1, t2, strict))
+ if (! compexcepttypes (t1, t2))
return 0;
- return ((TREE_TYPE (t1) == TREE_TYPE (t2)
- || comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
- && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2), strict));
+ val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
+ || comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
+ && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2), strict));
+ break;
case ARRAY_TYPE:
/* Target types must match incl. qualifiers. */
- return comp_array_types (comptypes, t1, t2, strict);
+ val = comp_array_types (comptypes, t1, t2, strict);
+ break;
case TEMPLATE_TYPE_PARM:
- return 1;
+ return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2);
- case UNINSTANTIATED_P_TYPE:
- return UPT_TEMPLATE (t1) == UPT_TEMPLATE (t2);
+ case TYPENAME_TYPE:
+ if (TYPE_IDENTIFIER (t1) != TYPE_IDENTIFIER (t2))
+ return 0;
+ return comptypes (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2), 1);
}
- return 0;
+ return attrval == 2 && val == 1 ? 2 : val;
}
/* Return 1 if TTL and TTR are pointers to types that are equivalent,
ttr = TYPE_MAIN_VARIANT (ttr);
if (ttl == ttr)
return 1;
- if (TREE_CODE (ttr) == TEMPLATE_TYPE_PARM)
- return 1;
if (TREE_CODE (ttr) != TREE_CODE (ttl))
return 0;
if (TREE_CODE (ttr) == POINTER_TYPE)
- return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs - 1);
+ {
+ ttl = TREE_TYPE (ttl);
+ ttr = TREE_TYPE (ttr);
+
+ if (nptrs > 0)
+ {
+ if (TREE_CODE (ttl) == VOID_TYPE
+ && TREE_CODE (ttr) != FUNCTION_TYPE
+ && TREE_CODE (ttr) != METHOD_TYPE
+ && TREE_CODE (ttr) != OFFSET_TYPE)
+ return 1;
+ else if (TREE_CODE (ttr) == VOID_TYPE
+ && TREE_CODE (ttl) != FUNCTION_TYPE
+ && TREE_CODE (ttl) != METHOD_TYPE
+ && TREE_CODE (ttl) != OFFSET_TYPE)
+ return -1;
+ else if (TREE_CODE (ttl) == POINTER_TYPE
+ || TREE_CODE (ttl) == ARRAY_TYPE)
+ {
+ if (comp_ptr_ttypes (ttl, ttr))
+ return 1;
+ else if (comp_ptr_ttypes (ttr, ttl))
+ return -1;
+ return 0;
+ }
+ }
+
+ /* Const and volatile mean something different for function types,
+ so the usual checks are not appropriate. */
+ if (TREE_CODE (ttl) == FUNCTION_TYPE || TREE_CODE (ttl) == METHOD_TYPE)
+ return comp_target_types (ttl, ttr, nptrs - 1);
+
+ /* Make sure that the cv-quals change only in the same direction as
+ the target type. */
+ {
+ int t;
+ int c = TYPE_READONLY (ttl) - TYPE_READONLY (ttr);
+ int v = TYPE_VOLATILE (ttl) - TYPE_VOLATILE (ttr);
+
+ if ((c > 0 && v < 0) || (c < 0 && v > 0))
+ return 0;
+
+ if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr))
+ return (c + v < 0) ? -1 : 1;
+
+ t = comp_target_types (ttl, ttr, nptrs - 1);
+ if ((t == 1 && c + v >= 0) || (t == -1 && c + v <= 0))
+ return t;
+
+ return 0;
+ }
+ }
if (TREE_CODE (ttr) == REFERENCE_TYPE)
return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs);
case 1:
return 1;
case 2:
- warning ("contravariance violation for method types ignored");
- return 1;
+ return -1;
default:
my_friendly_abort (112);
}
return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs);
else if (comptypes (TYPE_OFFSET_BASETYPE (ttl), TYPE_OFFSET_BASETYPE (ttr), 0)
&& comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs))
- {
- warning ("contravariance violation for member types ignored");
- return 1;
- }
+ return -1;
}
else if (IS_AGGR_TYPE (ttl))
{
if (nptrs < 0)
return 0;
- return comptypes (TYPE_POINTER_TO (ttl), TYPE_POINTER_TO (ttr), 0);
+ if (comptypes (build_pointer_type (ttl), build_pointer_type (ttr), 0))
+ return 1;
+ if (comptypes (build_pointer_type (ttr), build_pointer_type (ttl), 0))
+ return -1;
+ return 0;
}
return 0;
common_base_type (tt1, tt2)
tree tt1, tt2;
{
- tree best = NULL_TREE, tmp;
+ tree best = NULL_TREE;
int i;
/* If one is a baseclass of another, that's good enough. */
if (UNIQUELY_DERIVED_FROM_P (tt2, tt1))
return tt2;
- /* If they share a virtual baseclass, that's good enough. */
- for (tmp = CLASSTYPE_VBASECLASSES (tt1); tmp; tmp = TREE_CHAIN (tmp))
- {
- if (binfo_member (BINFO_TYPE (tmp), CLASSTYPE_VBASECLASSES (tt2)))
- return BINFO_TYPE (tmp);
- }
-
/* Otherwise, try to find a unique baseclass of TT1
that is shared by TT2, and follow that down. */
for (i = CLASSTYPE_N_BASECLASSES (tt1)-1; i >= 0; i--)
return t2 == void_list_node && TREE_PURPOSE (t1);
return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
}
- if (strict != 3 && TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
- {
- int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
- if (cmp < 0)
- my_friendly_abort (113);
- if (cmp == 0)
- return 0;
- }
t1 = TREE_CHAIN (t1);
t2 = TREE_CHAIN (t2);
p2 = TREE_VALUE (t2);
if (p1 == p2)
continue;
- if (TREE_CODE (p2) == TEMPLATE_TYPE_PARM)
- continue;
if ((TREE_CODE (p1) == POINTER_TYPE && TREE_CODE (p2) == POINTER_TYPE)
|| (TREE_CODE (p1) == REFERENCE_TYPE && TREE_CODE (p2) == REFERENCE_TYPE))
== TYPE_MAIN_VARIANT (TREE_TYPE (p2))))
continue;
- if (TREE_CODE (TREE_TYPE (p2)) == TEMPLATE_TYPE_PARM)
- continue;
-
/* The following is wrong for contravariance,
but many programs depend on it. */
if (TREE_TYPE (p1) == void_type_node)
}
if (strict != 0)
return 0;
-#if 0
- /* What good do these cases do? */
- if (strict == 0)
- return p2 == void_type_node && TREE_PURPOSE (t1);
- return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
-#endif
}
/* Target types are compatible--just make sure that if
we use parameter lists, that they are ok as well. */
if (TREE_CHAIN (t) == 0 && type != void_type_node)
return 0;
- if (TYPE_MAIN_VARIANT (type) == float_type_node)
+ if (type == 0)
return 0;
- if (type == 0)
+ if (TYPE_MAIN_VARIANT (type) == float_type_node)
return 0;
if (C_PROMOTING_INTEGER_TYPE_P (type))
return long_unsigned_type_node;
if (type1 == long_long_integer_type_node)
return long_long_unsigned_type_node;
+ if (type1 == intDI_type_node)
+ return unsigned_intDI_type_node;
+ if (type1 == intSI_type_node)
+ return unsigned_intSI_type_node;
+ if (type1 == intHI_type_node)
+ return unsigned_intHI_type_node;
+ if (type1 == intQI_type_node)
+ return unsigned_intQI_type_node;
return type;
}
return long_integer_type_node;
if (type1 == long_long_unsigned_type_node)
return long_long_integer_type_node;
+ if (type1 == unsigned_intDI_type_node)
+ return intDI_type_node;
+ if (type1 == unsigned_intSI_type_node)
+ return intSI_type_node;
+ if (type1 == unsigned_intHI_type_node)
+ return intHI_type_node;
+ if (type1 == unsigned_intQI_type_node)
+ return intQI_type_node;
return type;
}
return type;
}
+/* Compute the value of the `sizeof' operator. */
+
tree
c_sizeof (type)
tree type;
enum tree_code code = TREE_CODE (type);
tree t;
+ if (current_template_parms)
+ return build_min (SIZEOF_EXPR, sizetype, type);
+
if (code == FUNCTION_TYPE)
{
if (pedantic || warn_pointer_arith)
return size_int (0);
}
- if (TYPE_SIZE (type) == 0)
+ if (TYPE_SIZE (complete_type (type)) == 0)
{
- error ("`sizeof' applied to an incomplete type");
+ cp_error ("`sizeof' applied to incomplete type `%T'", type);
return size_int (0);
}
return t;
}
+tree
+expr_sizeof (e)
+ tree e;
+{
+ if (current_template_parms)
+ return build_min (SIZEOF_EXPR, sizetype, e);
+
+ if (TREE_CODE (e) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (e, 1)))
+ error ("sizeof applied to a bit-field");
+ /* ANSI says arrays and functions are converted inside comma.
+ But we can't really convert them in build_compound_expr
+ because that would break commas in lvalues.
+ So do the conversion here if operand was a comma. */
+ if (TREE_CODE (e) == COMPOUND_EXPR
+ && (TREE_CODE (TREE_TYPE (e)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (e)) == FUNCTION_TYPE))
+ e = default_conversion (e);
+ else if (TREE_CODE (e) == TREE_LIST)
+ {
+ tree t = TREE_VALUE (e);
+ if (t != NULL_TREE
+ && ((TREE_TYPE (t)
+ && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
+ || is_overloaded_fn (t)))
+ pedwarn ("ANSI C++ forbids taking the sizeof a function type");
+ }
+ return c_sizeof (TREE_TYPE (e));
+}
+
tree
c_sizeof_nowarn (type)
tree type;
type = TREE_TYPE (type);
if (TYPE_SIZE (type) == 0)
- {
-#if 0
- /* ??? Tiemann, why have any diagnostic here?
- There is none in the corresponding function for C. */
- warning ("sizeof applied to an incomplete type");
-#endif
- return size_int (0);
- }
+ return size_int (0);
/* Convert in case a char is more than one unit. */
t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
- size_int (TYPE_PRECISION (char_type_node)));
+ size_int (TYPE_PRECISION (char_type_node)));
force_fit_type (t, 0);
return t;
}
C++: this will automatically bash references to their target type. */
tree
-default_conversion (exp)
+decay_conversion (exp)
tree exp;
{
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 default_conversion (resolve_offset_ref (exp));
+ return decay_conversion (resolve_offset_ref (exp));
type = TREE_TYPE (type);
code = TREE_CODE (type);
if (TREE_CODE (exp) == CONST_DECL)
exp = DECL_INITIAL (exp);
/* Replace a nonvolatile const static variable with its value. */
- else if (TREE_READONLY_DECL_P (exp) && DECL_MODE (exp) != BLKmode)
+ else if (TREE_READONLY_DECL_P (exp))
{
exp = decl_constant_value (exp);
type = TREE_TYPE (exp);
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
Leave such NOP_EXPRs, since RHS is being used in non-lvalue context. */
- if (code == ENUMERAL_TYPE || code == INTEGER_TYPE)
- {
- tree t = type_promotes_to (type);
- if (t != TYPE_MAIN_VARIANT (type))
- return convert (t, exp);
- }
- if (flag_traditional
- && TYPE_MAIN_VARIANT (type) == float_type_node)
- return convert (double_type_node, exp);
if (code == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
}
if (code == METHOD_TYPE)
{
- if (TREE_CODE (exp) == OFFSET_REF)
- {
- 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);
TREE_REFERENCE_EXPR (inner) = 1;
}
- return convert (TYPE_POINTER_TO (TREE_TYPE (type)), inner);
+ return convert (build_pointer_type (TREE_TYPE (type)), inner);
}
if (TREE_CODE (exp) == COMPOUND_EXPR)
{
- tree op1 = default_conversion (TREE_OPERAND (exp, 1));
+ tree op1 = decay_conversion (TREE_OPERAND (exp, 1));
return build (COMPOUND_EXPR, TREE_TYPE (op1),
TREE_OPERAND (exp, 0), op1);
}
restype = TREE_TYPE (type);
if (TYPE_READONLY (type) || TYPE_VOLATILE (type)
|| constp || volatilep)
- restype = build_type_variant (restype,
- TYPE_READONLY (type) || constp,
- TYPE_VOLATILE (type) || volatilep);
+ restype = cp_build_type_variant (restype,
+ TYPE_READONLY (type) || constp,
+ TYPE_VOLATILE (type) || volatilep);
ptrtype = build_pointer_type (restype);
if (TREE_CODE (exp) == VAR_DECL)
adr = build_unary_op (ADDR_EXPR, exp, 1);
return convert (ptrtype, adr);
}
+
+ return exp;
+}
+
+tree
+default_conversion (exp)
+ tree exp;
+{
+ tree type;
+ enum tree_code code;
+
+ exp = decay_conversion (exp);
+
+ type = TREE_TYPE (exp);
+ code = TREE_CODE (type);
+
+ if (INTEGRAL_CODE_P (code))
+ {
+ tree t = type_promotes_to (type);
+ if (t != type)
+ return 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
build_object_ref (datum, basetype, field)
tree datum, basetype, field;
{
+ tree dtype;
if (datum == error_mark_node)
return error_mark_node;
- else if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (basetype)))
+
+ dtype = TREE_TYPE (datum);
+ if (TREE_CODE (dtype) == REFERENCE_TYPE)
+ dtype = TREE_TYPE (dtype);
+ if (! IS_AGGR_TYPE_CODE (TREE_CODE (dtype)))
+ {
+ cp_error ("request for member `%T::%D' in expression of non-aggregate type `%T'",
+ basetype, field, dtype);
+ return error_mark_node;
+ }
+ else if (IS_SIGNATURE (basetype))
{
warning ("signature name in scope resolution ignored");
return build_component_ref (datum, field, NULL_TREE, 1);
}
- else if (is_aggr_typedef (basetype, 1))
+ else if (is_aggr_type (basetype, 1))
{
- tree real_basetype = IDENTIFIER_TYPE_VALUE (basetype);
- tree binfo = binfo_or_else (real_basetype, TREE_TYPE (datum));
+ tree binfo = binfo_or_else (basetype, dtype);
if (binfo)
return build_component_ref (build_scoped_ref (datum, basetype),
field, binfo, 1);
}
/* 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;
if (TREE_STATIC (field))
return field;
- if (datum == C_C_D)
+ if (datum == current_class_ref)
{
- enum access_type access
- = compute_access (TYPE_BINFO (current_class_type), field);
+ tree access = compute_access (TYPE_BINFO (current_class_type), field);
- if (access == access_private)
+ if (access == access_private_node)
{
cp_error ("field `%D' is private", field);
return error_mark_node;
}
- else if (access == access_protected)
+ else if (access == access_protected_node)
{
cp_error ("field `%D' is protected", field);
return error_mark_node;
build_unary_op (code, TREE_OPERAND (t, 2), 0));
}
+/* Given the TYPE of an anonymous union field inside T, return the
+ 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;
+{
+ tree field;
+
+ for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+ {
+ if (TREE_STATIC (field))
+ continue;
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ /* If we find it directly, return the field. */
+ if (DECL_NAME (field) == NULL_TREE
+ && type == TREE_TYPE (field))
+ {
+ return field;
+ }
+
+ /* Otherwise, it could be nested, search harder. */
+ if (DECL_NAME (field) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ {
+ tree subfield = lookup_anon_field (TREE_TYPE (field), type);
+ if (subfield)
+ return subfield;
+ }
+ }
+ return NULL_TREE;
+}
+
+/* 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;
int protect;
{
register tree basetype = TREE_TYPE (datum);
- register enum tree_code code = TREE_CODE (basetype);
+ register enum tree_code code;
register tree field = NULL;
register tree ref;
- /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it
- unless we are not to support things not strictly ANSI. */
+ if (current_template_parms)
+ return build_min_nt (COMPONENT_REF, datum, component);
+
+ /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it. */
switch (TREE_CODE (datum))
{
case COMPOUND_EXPR:
basetype_path, protect));
}
+ code = TREE_CODE (basetype);
+
if (code == REFERENCE_TYPE)
{
-#if 0
- /* TREE_REFERENCE_EXPRs are not converted by `convert_from_reference'.
- @@ Maybe that is not right. */
- if (TREE_REFERENCE_EXPR (datum))
- datum = build1 (INDIRECT_REF, TREE_TYPE (basetype), datum);
- else
-#endif
- datum = convert_from_reference (datum);
+ datum = convert_from_reference (datum);
+ 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);
}
&& DECL_CHAIN (TREE_VALUE (component)) == NULL_TREE), 309);
return build (COMPONENT_REF, TREE_TYPE (component), datum, component);
}
-#if 0
- if (TREE_CODE (component) == TYPE_EXPR)
- return build_component_type_expr (datum, component, NULL_TREE, protect);
-#endif
if (! IS_AGGR_TYPE_CODE (code))
{
return error_mark_node;
}
- if (TYPE_SIZE (basetype) == 0)
+ if (TYPE_SIZE (complete_type (basetype)) == 0)
{
incomplete_type_error (0, basetype);
return error_mark_node;
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)
+ {
+ field = component;
+ }
else
{
if (basetype_path == NULL_TREE)
if (TREE_CHAIN (fndecls) == NULL_TREE
&& DECL_CHAIN (TREE_VALUE (fndecls)) == NULL_TREE)
{
- enum access_type access;
- tree fndecl;
+ tree access, fndecl;
/* Unique, so use this one now. */
basetype = TREE_PURPOSE (fndecls);
fndecl = TREE_VALUE (fndecls);
access = compute_access (TREE_PURPOSE (fndecls), fndecl);
- if (access == access_public)
+ if (access == access_public_node)
{
if (DECL_VINDEX (fndecl)
&& ! resolves_to_fixed_type_p (datum, 0))
my_friendly_assert (datum != error_mark_node, 310);
fndecl = build_vfn_ref (&addr, datum, DECL_VINDEX (fndecl));
}
+ mark_used (fndecl);
return fndecl;
}
- if (access == access_protected)
+ if (access == access_protected_node)
cp_error ("member function `%D' is protected", fndecl);
else
cp_error ("member function `%D' is private", fndecl);
return error_mark_node;
}
else
- return build (COMPONENT_REF, unknown_type_node, datum, fndecls);
+ {
+ /* Just act like build_offset_ref, since the object does
+ not matter unless we're actually calling the function. */
+ tree t;
+
+ t = build_tree_list (error_mark_node, fndecls);
+ TREE_TYPE (t) = build_offset_type (basetype,
+ unknown_type_node);
+ return t;
+ }
}
-#if 0
- if (component == ansi_opname[(int) TYPE_EXPR])
- cp_error ("`%#T' has no such type conversion operator", basetype);
- else
-#endif
- cp_error ("`%#T' has no member named `%D'", basetype, component);
+ cp_error ("`%#T' has no member named `%D'", basetype, component);
return error_mark_node;
}
else if (TREE_TYPE (field) == error_mark_node)
cp_error ("invalid use of type decl `%#D' as expression", field);
return error_mark_node;
}
- if (DECL_RTL (field) != 0)
- assemble_external (field);
- TREE_USED (field) = 1;
+ else if (DECL_RTL (field) != 0)
+ mark_used (field);
+ else
+ TREE_USED (field) = 1;
return field;
}
}
- if (DECL_FIELD_CONTEXT (field) != basetype
- && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+ /* See if we have to do any conversions so that we pick up the field from the
+ right context. */
+ if (DECL_FIELD_CONTEXT (field) != basetype)
{
- tree addr = build_unary_op (ADDR_EXPR, datum, 0);
- if (integer_zerop (addr))
+ tree context = DECL_FIELD_CONTEXT (field);
+ tree base = context;
+ while (base != basetype && TYPE_NAME (base)
+ && ANON_AGGRNAME_P (TYPE_IDENTIFIER (base)))
{
- error ("invalid reference to NULL ptr, use ptr-to-member instead");
- return error_mark_node;
+ base = TYPE_CONTEXT (base);
}
- addr = convert_pointer_to (DECL_FIELD_CONTEXT (field), addr);
- datum = build_indirect_ref (addr, NULL_PTR);
- my_friendly_assert (datum != error_mark_node, 311);
- }
- ref = build (COMPONENT_REF, TREE_TYPE (field), break_out_cleanups (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;
+ /* Handle base classes here... */
+ if (base != basetype && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+ {
+ tree addr = build_unary_op (ADDR_EXPR, datum, 0);
+ if (integer_zerop (addr))
+ {
+ error ("invalid reference to NULL ptr, use ptr-to-member instead");
+ return error_mark_node;
+ }
+ if (VBASE_NAME_P (DECL_NAME (field)))
+ {
+ /* It doesn't matter which vbase pointer we grab, just
+ find one of them. */
+ tree binfo = get_binfo (base,
+ TREE_TYPE (TREE_TYPE (addr)), 0);
+ addr = convert_pointer_to_real (binfo, addr);
+ }
+ else
+ addr = convert_pointer_to (base, addr);
+ datum = build_indirect_ref (addr, NULL_PTR);
+ my_friendly_assert (datum != error_mark_node, 311);
+ }
+ basetype = base;
+
+ /* Handle things from anon unions here... */
+ if (TYPE_NAME (context) && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
+ {
+ tree subfield = lookup_anon_field (basetype, context);
+ tree subdatum = build_component_ref (datum, subfield,
+ basetype_path, protect);
+ return build_component_ref (subdatum, field, basetype_path, protect);
+ }
+ }
+
+ ref = fold (build (COMPONENT_REF, TREE_TYPE (field),
+ break_out_cleanups (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;
}
tree ptr;
char *errorstring;
{
- tree rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, NULL_TREE);
+ tree rval;
+
+ if (current_template_parms)
+ return build_min_nt (INDIRECT_REF, ptr);
+
+ rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, NULL_TREE);
if (rval)
return rval;
return build_indirect_ref (ptr, errorstring);
tree ptr;
char *errorstring;
{
- register tree pointer = default_conversion (ptr);
+ register tree pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE ?
+ ptr : default_conversion (ptr));
register tree type = TREE_TYPE (pointer);
- if (ptr == current_class_decl)
- return C_C_D;
+ if (ptr == current_class_ptr)
+ return current_class_ref;
+
+ if (IS_AGGR_TYPE (type))
+ {
+ ptr = build_expr_type_conversion (WANT_POINTER, pointer, 1);
+
+ if (ptr)
+ {
+ pointer = ptr;
+ type = TREE_TYPE (pointer);
+ }
+ }
if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE)
{
if (TREE_CODE (pointer) == ADDR_EXPR
- && (TREE_TYPE (TREE_OPERAND (pointer, 0))
- == TREE_TYPE (type)))
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (pointer, 0)))
+ == TYPE_MAIN_VARIANT (TREE_TYPE (type)))
+ && (TREE_READONLY (TREE_OPERAND (pointer, 0))
+ == TYPE_READONLY (TREE_TYPE (type)))
+ && (TREE_THIS_VOLATILE (TREE_OPERAND (pointer, 0))
+ == TYPE_VOLATILE (TREE_TYPE (type))))
return TREE_OPERAND (pointer, 0);
else
{
build_array_ref (array, idx)
tree array, idx;
{
- tree itype;
-
if (idx == 0)
{
error ("subscript missing in array reference");
|| TREE_TYPE (idx) == error_mark_node)
return error_mark_node;
- itype = TREE_TYPE (idx);
- /* We must check here for the reference, so we can do the possible
- conversions immediately afterwards. */
- if (TREE_CODE (itype) == REFERENCE_TYPE)
- {
- idx = convert_from_reference (idx);
- itype = TREE_TYPE (idx);
- }
-
- if (IS_AGGR_TYPE (itype))
- {
- if (TYPE_HAS_INT_CONVERSION (itype))
- idx = build_type_conversion (CONVERT_EXPR,
- integer_type_node, idx, 1);
- else
- {
- error_with_aggr_type (itype,
- "type `%s' requires integer conversion for array indexing");
- return error_mark_node;
- }
- }
-
if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
&& TREE_CODE (array) != INDIRECT_REF)
{
return error_mark_node;
}
- /* Note in C++ we don't bother warning about subscripting a
- `register' array, since it's legal in C++ to take the address
- of something with that storage specification. */
if (pedantic && !lvalue_p (array))
pedwarn ("ANSI C++ forbids subscripting non-lvalue array");
- if (pedantic)
+ /* Note in C++ it is valid to subscript a `register' array, since
+ it is valid to take the address of something with that
+ storage specification. */
+ if (extra_warnings)
{
tree foo = array;
while (TREE_CODE (foo) == COMPONENT_REF)
foo = TREE_OPERAND (foo, 0);
if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo))
- pedwarn ("ANSI C++ forbids subscripting non-lvalue array");
+ warning ("subscripting array declared `register'");
}
type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
\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, 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)
{
}
else if (TREE_CODE (function) == TREE_LIST)
{
-#if 0
- if (TREE_CODE (TREE_VALUE (function)) == TREE_LIST)
- function = TREE_PURPOSE (TREE_VALUE (function));
- else
- function = TREE_PURPOSE (function);
-#else
my_friendly_assert (TREE_CODE (TREE_VALUE (function)) == FUNCTION_DECL, 312);
function = TREE_PURPOSE (function);
-#endif
}
else if (TREE_CODE (function) != IDENTIFIER_NODE)
{
return error_mark_node;
}
/* Yow: call from a static member function. */
- decl = build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type),
+ decl = build1 (NOP_EXPR, build_pointer_type (current_class_type),
error_mark_node);
decl = build_indirect_ref (decl, NULL_PTR);
}
}
else
{
- tree id = TREE_PURPOSE (function);
- function = TREE_VALUE (function);
+ tree val = TREE_VALUE (function);
- if (TREE_CODE (function) == TEMPLATE_DECL)
- return build_overload_call_maybe
- (id, params, LOOKUP_COMPLAIN, (struct candidate *)0);
- else if (DECL_CHAIN (function) != NULL_TREE)
+ if (TREE_CODE (val) == TEMPLATE_DECL)
+ return build_overload_call_real
+ (function, params, LOOKUP_COMPLAIN, (struct candidate *)0, 0);
+ else if (DECL_CHAIN (val) != NULL_TREE)
return build_overload_call
- (id, params, LOOKUP_COMPLAIN, (struct candidate *)0);
- /* else fall out */
+ (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, decl,
+ function = get_member_function_from_ptrfunc (&decl_addr,
TREE_OPERAND (function, 1));
params = tree_cons (NULL_TREE, decl_addr, params);
return build_function_call (function, params);
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
- if (TYPE_LANG_SPECIFIC (type) && TYPE_OVERLOADS_CALL_EXPR (type))
+ if (TYPE_LANG_SPECIFIC (type)
+ && TYPE_OVERLOADS_CALL_EXPR (complete_type (type)))
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE);
}
/* Explicitly named method? */
if (TREE_CODE (function) == FUNCTION_DECL)
- ctypeptr = TYPE_POINTER_TO (DECL_CLASS_CONTEXT (function));
+ ctypeptr = build_pointer_type (DECL_CLASS_CONTEXT (function));
/* Expression with ptr-to-method type? It could either be a plain
usage, or it might be a case where the ptr-to-method is being
passed in as an argument. */
else if (TYPE_PTRMEMFUNC_P (fntype))
{
tree rec = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (fntype)));
- ctypeptr = TYPE_POINTER_TO (rec);
+ ctypeptr = build_pointer_type (rec);
}
/* Unexpected node type? */
else
decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl);
}
else
- decl = build_c_cast (ctypeptr, decl);
+ decl = build_c_cast (ctypeptr, decl, 0);
params = tree_cons (NULL_TREE, decl, params);
}
instance to use, if the member points to a virtual member. */
tree
-get_member_function_from_ptrfunc (instance_ptrptr, instance, function)
+get_member_function_from_ptrfunc (instance_ptrptr, function)
tree *instance_ptrptr;
- tree instance;
tree function;
{
if (TREE_CODE (function) == OFFSET_REF)
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
{
- tree fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
- tree index = save_expr (convert (integer_type_node,
- build_component_ref (function,
- index_identifier,
- 0, 0)));
- tree e1 = build (GT_EXPR, integer_type_node, index, integer_zero_node);
- tree delta = build_component_ref (function, delta_identifier, 0, 0);
- tree delta2 = DELTA2_FROM_PTRMEMFUNC (function);
- tree e2;
- tree e3;
- tree aref, vtbl;
+ tree fntype, index, e1, delta, delta2, e2, e3, aref, vtbl;
+ tree instance;
+
+ tree instance_ptr = *instance_ptrptr;
+
+ if (TREE_SIDE_EFFECTS (instance_ptr))
+ instance_ptr = save_expr (instance_ptr);
+
+ if (TREE_SIDE_EFFECTS (function))
+ function = save_expr (function);
+
+ fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
+ index = save_expr (build_component_ref (function,
+ index_identifier,
+ NULL_TREE, 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, NULL_TREE, 0));
+ delta2 = DELTA2_FROM_PTRMEMFUNC (function);
/* convert down to the right base, before using the instance. */
- instance = convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)),
- build_unary_op (ADDR_EXPR, instance, 0));
+ instance
+ = convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)),
+ instance_ptr);
if (instance == error_mark_node)
return instance;
vtbl
= build (PLUS_EXPR,
build_pointer_type (build_pointer_type (vtable_entry_type)),
- vtbl, convert (sizetype, delta2));
+ vtbl, convert (ptrdiff_type_node, delta2));
vtbl = build_indirect_ref (vtbl, NULL_PTR);
- aref = build_array_ref (vtbl, size_binop (MINUS_EXPR,
- index,
- integer_one_node));
+ aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
+ index,
+ 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 (/* !building_cleanup && */ TREE_CODE (aref) == INDIRECT_REF)
- TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
-
- delta = build (PLUS_EXPR, integer_type_node,
- build_conditional_expr (e1, build_component_ref (aref, delta_identifier, 0, 0), integer_zero_node),
- delta);
+ delta = build_binary_op (PLUS_EXPR,
+ build_conditional_expr (e1, build_component_ref (aref, delta_identifier, NULL_TREE, 0), integer_zero_node),
+ delta, 1);
}
- *instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (*instance_ptrptr),
- *instance_ptrptr,
- convert (integer_type_node, delta));
+ *instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
+ instance_ptr, delta);
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);
+
+ /* Make sure this doesn't get evaluated first inside one of the
+ branches of the COND_EXPR. */
+ if (TREE_CODE (instance_ptr) == SAVE_EXPR)
+ function = build (COMPOUND_EXPR, TREE_TYPE (function),
+ instance_ptr, function);
}
return function;
}
GNU_xref_call (current_function_decl,
IDENTIFIER_POINTER (name ? name
: TYPE_IDENTIFIER (DECL_CLASS_CONTEXT (function))));
- assemble_external (function);
+ mark_used (function);
fndecl = function;
/* Convert anything with function type to a pointer-to-function. */
pedwarn ("ANSI C++ forbids calling `main' from within program");
}
+ if (pedantic && DECL_THIS_INLINE (function) && ! DECL_INITIAL (function)
+ && ! DECL_ARTIFICIAL (function)
+ && ! DECL_PENDING_INLINE_INFO (function))
+ cp_pedwarn ("inline function `%#D' called before definition",
+ function);
+
/* Differs from default_conversion by not setting TREE_ADDRESSABLE
(because calling an inline function does not mean the function
needs to be separately compiled). */
if (DECL_INLINE (function))
{
- fntype = build_type_variant (TREE_TYPE (function),
- TREE_READONLY (function),
- TREE_THIS_VOLATILE (function));
- function = build1 (ADDR_EXPR, build_pointer_type (fntype), 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);
+
+ function = inline_conversion (function);
}
else
- {
- assemble_external (function);
- TREE_USED (function) = 1;
- 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, C_C_D, 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
&& TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)
|| is_method))
{
- error ("called object is not a function");
+ cp_error ("`%E' cannot be used as a function", function);
return error_mark_node;
}
coerced_params = convert_arguments (NULL_TREE, TYPE_ARG_TYPES (fntype),
params, fndecl, 0);
+ if (coerced_params == error_mark_node)
+ if (flags & LOOKUP_SPECULATIVELY)
+ return NULL_TREE;
+ else
+ return error_mark_node;
+
/* Check for errors in format strings. */
if (warn_format && (name || assembler_name))
/* 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;
- /* Remove this sometime. */
- TREE_RAISES (result) |= !! TYPE_RAISES_EXCEPTIONS (fntype);
- if (! require_complete)
- return result;
- if (value_type == void_type_node)
- return result;
- return require_complete_type (result);
+ register tree result
+ = build_call (function, value_type, coerced_params);
+
+ if (require_complete)
+ {
+ if (value_type == void_type_node)
+ return result;
+ result = require_complete_type (result);
+ }
+ return convert_from_reference (result);
}
}
{
return build_function_call_real (function, params, 1, LOOKUP_NORMAL);
}
-
-tree
-build_function_call_maybe (function, params)
- tree function, params;
-{
- return build_function_call_real (function, params, 0, 0);
-}
-
\f
/* Convert the actual parameter expressions in the list VALUES
to the types in the list TYPELIST.
tree return_loc, typelist, values, fndecl;
int flags;
{
- extern tree gc_protect_fndecl;
register tree typetail, valtail;
register tree result = NULL_TREE;
char *called_thing;
- int maybe_raises = 0;
int i = 0;
if (! flag_elide_constructors)
called_thing = "constructor";
else
called_thing = "member function";
- i -= 1;
}
else
- {
- called_thing = "function";
- }
+ called_thing = "function";
}
for (valtail = values, typetail = typelist;
register tree type = typetail ? TREE_VALUE (typetail) : 0;
register tree val = TREE_VALUE (valtail);
+ if (val == error_mark_node)
+ return error_mark_node;
+
if (type == void_type_node)
{
if (fndecl)
{
- 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)
val = resolve_offset_ref (val);
- {
-#if 0
- /* This code forces the assumption that if we have a ptr-to-func
- type in an arglist, that every routine that wants to check
- its validity has done so, and thus we need not do any
- more conversion. I don't remember why this is necessary. */
- else if (TREE_CODE (ttype) == FUNCTION_TYPE
- && (type == NULL
- || TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (type)) == VOID_TYPE))
- {
- type = build_pointer_type (ttype);
- }
-#endif
- }
-
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
Strip such NOP_EXPRs, since VAL is used in non-lvalue context. */
if (TREE_CODE (val) == NOP_EXPR
- && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0)))
+ && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0))
+ && (type == 0 || TREE_CODE (type) != REFERENCE_TYPE))
val = TREE_OPERAND (val, 0);
- if ((type == 0 || TREE_CODE (type) != REFERENCE_TYPE)
- && (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
+ if (type == 0 || TREE_CODE (type) != REFERENCE_TYPE)
+ {
+ if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE))
- val = default_conversion (val);
+ || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
+ val = default_conversion (val);
- val = require_complete_type (val);
+ val = require_complete_type (val);
+ }
if (val == error_mark_node)
- continue;
-
- maybe_raises |= TREE_RAISES (val);
+ return error_mark_node;
if (type != 0)
{
/* Formal parm type is specified by a function prototype. */
tree parmval;
- if (TYPE_SIZE (type) == 0)
+ if (TYPE_SIZE (complete_type (type)) == 0)
{
error ("parameter type of called function is incomplete");
parmval = val;
}
else
{
-#ifdef PROMOTE_PROTOTYPES
- /* Rather than truncating and then reextending,
- convert directly to int, if that's the type we will want. */
- if (! flag_traditional
- && (TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE)
- && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
- type = integer_type_node;
-#endif
- parmval = convert_for_initialization (return_loc, type, val, flags,
+ parmval = convert_for_initialization (return_loc, type, val,
+ flags|INDIRECT_BIND,
"argument passing", fndecl, i);
#ifdef PROMOTE_PROTOTYPES
if ((TREE_CODE (type) == INTEGER_TYPE
parmval = default_conversion (parmval);
#endif
}
+
+ if (parmval == error_mark_node)
+ return error_mark_node;
+
result = tree_cons (NULL_TREE, parmval, result);
}
else
/* Convert `float' to `double'. */
result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
else if (TYPE_LANG_SPECIFIC (TREE_TYPE (val))
- && (TYPE_HAS_INIT_REF (TREE_TYPE (val))
- || TYPE_HAS_ASSIGN_REF (TREE_TYPE (val))))
+ && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (val)))
{
cp_warning ("cannot pass objects of type `%T' through `...'",
TREE_TYPE (val));
result = tree_cons (NULL_TREE, default_conversion (val), result);
}
- if (flag_gc
- /* There are certain functions for which we don't need
- to protect our arguments. GC_PROTECT_FNDECL is one. */
- && fndecl != gc_protect_fndecl
- && type_needs_gc_entry (TREE_TYPE (TREE_VALUE (result)))
- && ! value_safe_from_gc (NULL_TREE, TREE_VALUE (result)))
- /* This will build a temporary variable whose cleanup is
- to clear the obstack entry. */
- TREE_VALUE (result) = protect_value_from_gc (NULL_TREE,
- TREE_VALUE (result));
-
if (typetail)
typetail = TREE_CHAIN (typetail);
}
/* See if there are default arguments that can be used */
if (TREE_PURPOSE (typetail))
{
- while (typetail != void_list_node)
+ for (; typetail != void_list_node; ++i)
{
tree type = TREE_VALUE (typetail);
- tree val = TREE_PURPOSE (typetail);
+ tree val = break_out_target_exprs (TREE_PURPOSE (typetail));
tree parmval;
if (val == NULL_TREE)
parmval = default_conversion (parmval);
#endif
}
- maybe_raises |= TREE_RAISES (parmval);
- if (flag_gc
- && type_needs_gc_entry (TREE_TYPE (parmval))
- && ! value_safe_from_gc (NULL_TREE, parmval))
- parmval = protect_value_from_gc (NULL_TREE, parmval);
+ if (parmval == error_mark_node)
+ return error_mark_node;
result = tree_cons (0, parmval, result);
typetail = TREE_CHAIN (typetail);
return error_mark_list;
}
}
- if (result)
- TREE_RAISES (result) = maybe_raises;
return nreverse (result);
}
enum tree_code code;
tree arg1, arg2;
{
- tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY,
- arg1, arg2, NULL_TREE);
+ tree rval;
+
+ if (current_template_parms)
+ return build_min_nt (code, arg1, arg2);
+
+ rval = build_opfncall (code, LOOKUP_SPECULATIVELY,
+ arg1, arg2, NULL_TREE);
if (rval)
return build_opfncall (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
if (code == MEMBER_REF)
tree arg1, arg2;
int convert_p;
{
- tree type1, type2;
tree args[2];
args[0] = arg1;
if (convert_p)
{
- args[0] = default_conversion (args[0]);
- args[1] = default_conversion (args[1]);
+ tree type0, type1;
+ args[0] = decay_conversion (args[0]);
+ args[1] = decay_conversion (args[1]);
+
+ if (args[0] == error_mark_node || args[1] == error_mark_node)
+ return error_mark_node;
+
+ type0 = TREE_TYPE (args[0]);
+ type1 = TREE_TYPE (args[1]);
if (type_unknown_p (args[0]))
{
- args[0] = instantiate_type (TREE_TYPE (args[1]), args[0], 1);
- args[0] = default_conversion (args[0]);
+ args[0] = instantiate_type (type1, args[0], 1);
+ args[0] = decay_conversion (args[0]);
}
else if (type_unknown_p (args[1]))
{
- args[1] = require_instantiated_type (TREE_TYPE (args[0]),
- args[1],
+ args[1] = require_instantiated_type (type0, args[1],
error_mark_node);
- args[1] = default_conversion (args[1]);
+ args[1] = decay_conversion (args[1]);
}
- type1 = TREE_TYPE (args[0]);
- type2 = TREE_TYPE (args[1]);
-
- if (IS_AGGR_TYPE_2 (type1, type2) && ! TYPE_PTRMEMFUNC_P (type1))
+ if (IS_AGGR_TYPE (type0) || IS_AGGR_TYPE (type1))
{
/* Try to convert this to something reasonable. */
if (! build_default_binary_type_conversion(code, &args[0], &args[1]))
- return error_mark_node;
- }
- else if ((IS_AGGR_TYPE (type1) && ! TYPE_PTRMEMFUNC_P (type1))
- || (IS_AGGR_TYPE (type2) && ! TYPE_PTRMEMFUNC_P (type2)))
- {
- int convert_index = IS_AGGR_TYPE (type2);
- /* Avoid being tripped up by things like (ARG1 != 0). */
- tree types[2], try;
-
- types[0] = type1; types[1] = type2;
- try = build_type_conversion (code, types[convert_index ^ 1],
- args[convert_index], 1);
-
- if (try == 0
- && args[1] == integer_zero_node
- && (code == NE_EXPR || code == EQ_EXPR))
- try = build_type_conversion (code, ptr_type_node,
- args[convert_index], 1);
- if (try == 0)
{
cp_error ("no match for `%O(%#T, %#T)'", code,
- types[convert_index], types[convert_index ^ 1]);
+ TREE_TYPE (arg1), TREE_TYPE (arg2));
return error_mark_node;
}
- if (try == error_mark_node)
- error ("ambiguous pointer conversion");
- args[convert_index] = try;
}
}
return build_binary_op_nodefault (code, args[0], args[1], code);
Zero means they need to be converted to RESULT_TYPE. */
int converted = 0;
+ /* Nonzero means create the expression with this type, rather than
+ RESULT_TYPE. */
+ tree build_type = 0;
+
/* Nonzero means after finally constructing the expression
- give it this type. Otherwise, give it type RESULT_TYPE. */
+ convert it to this type. */
tree final_type = 0;
/* Nonzero if this is an operation like MIN or MAX which can
int common = 0;
/* Apply default conversions. */
- op0 = default_conversion (orig_op0);
- op1 = default_conversion (orig_op1);
+ if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
+ || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
+ || code == TRUTH_XOR_EXPR)
+ {
+ op0 = decay_conversion (orig_op0);
+ op1 = decay_conversion (orig_op1);
+ }
+ else
+ {
+ op0 = default_conversion (orig_op0);
+ op1 = default_conversion (orig_op1);
+ }
type0 = TREE_TYPE (op0);
type1 = TREE_TYPE (op1);
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
{
+ if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
+ cp_warning ("division by zero in `%E / 0'", op0);
+ else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1))
+ cp_warning ("division by zero in `%E / 0.'", op0);
+
if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
resultcode = RDIV_EXPR;
else
/* When dividing two signed integers, we have to promote to int.
- unless we divide by a conatant != -1. Note that default
+ unless we divide by a constant != -1. Note that default
conversion will have been performed on the operands at this
point, so we have to dig out the original type to find out if
it was unsigned. */
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
+ if (code1 == INTEGER_TYPE && integer_zerop (op1))
+ cp_warning ("division by zero in `%E % 0'", op0);
+ else if (code1 == REAL_TYPE && real_zerop (op1))
+ cp_warning ("division by zero in `%E % 0.'", op0);
+
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
/* Although it would be tempting to shorten always here, that loses
case TRUTH_ORIF_EXPR:
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
- if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE || code0 == REAL_TYPE)
- && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE || code1 == REAL_TYPE))
- {
- /* Result of these operations is always an int,
- but that does not mean the operands should be
- converted to ints! */
- result_type = integer_type_node;
- op0 = truthvalue_conversion (op0);
- op1 = truthvalue_conversion (op1);
- converted = 1;
- }
+ result_type = boolean_type_node;
break;
/* Shift operations: result has same type as first operand;
case EQ_EXPR:
case NE_EXPR:
- /* Result of comparison is always int,
- but don't convert the args to int! */
- result_type = integer_type_node;
- converted = 1;
+ build_type = boolean_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
short_compare = 1;
{
register tree tt0 = TYPE_MAIN_VARIANT (TREE_TYPE (type0));
register tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (type1));
- /* Anything compares with void *. void * compares with anything.
- Otherwise, the targets must be the same. */
- if (tt0 != tt1 && TREE_CODE (tt0) == RECORD_TYPE
- && TREE_CODE (tt1) == RECORD_TYPE)
- {
- tree base = common_base_type (tt0, tt1);
- if (base == NULL_TREE)
- warning ("comparison of distinct object pointer types");
- else if (base == error_mark_node)
- {
- message_2_types (error, "comparison of pointer types `%s*' and `%s*' requires conversion to ambiguous supertype", tt0, tt1);
- return error_mark_node;
- }
- else
- {
- if (integer_zerop (op0))
- op0 = null_pointer_node;
- else
- op0 = convert_pointer_to (base, op0);
- if (integer_zerop (op1))
- op1 = null_pointer_node;
- else
- op1 = convert_pointer_to (base, op1);
- }
- }
- else if (comp_target_types (type0, type1, 1))
- ;
+
+ if (comp_target_types (type0, type1, 1))
+ result_type = common_type (type0, type1);
else if (tt0 == void_type_node)
{
if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE
&& tree_int_cst_lt (TYPE_SIZE (type0), TYPE_SIZE (type1)))
pedwarn ("ANSI C++ forbids comparison of `void *' with function pointer");
+ else if (TREE_CODE (tt1) == OFFSET_TYPE)
+ pedwarn ("ANSI C++ forbids conversion of a pointer to member to `void *'");
}
else if (tt1 == void_type_node)
{
&& tree_int_cst_lt (TYPE_SIZE (type1), TYPE_SIZE (type0)))
pedwarn ("ANSI C++ forbids comparison of `void *' with function pointer");
}
- else if ((TYPE_SIZE (tt0) != 0) != (TYPE_SIZE (tt1) != 0))
- pedwarn ("comparison of complete and incomplete pointers");
else
- pedwarn ("comparison of distinct pointer types lacks a cast");
+ cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
+ type0, type1);
+
+ if (result_type == NULL_TREE)
+ result_type = ptr_type_node;
}
else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
&& integer_zerop (op1))
- op1 = null_pointer_node;
+ result_type = type0;
else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
&& integer_zerop (op0))
- op0 = null_pointer_node;
+ result_type = type1;
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
+ result_type = type0;
error ("ANSI C++ forbids comparison between pointer and integer");
- op1 = convert (TREE_TYPE (op0), op1);
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
+ result_type = type1;
error ("ANSI C++ forbids comparison between pointer and integer");
- op0 = convert (TREE_TYPE (op1), op0);
}
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);
}
else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
&& (TYPE_PTRMEMFUNC_FN_TYPE (type0)
&& ((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);
tree delta21 = DELTA2_FROM_PTRMEMFUNC (op1);
tree e1, e2, e3;
tree integer_neg_one_node
- = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+ = build_binary_op (MINUS_EXPR, integer_zero_node, integer_one_node, 1);
e1 = build_binary_op (EQ_EXPR, index0, index1, 1);
e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node, 1);
e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2, build_binary_op (EQ_EXPR, delta20, delta21, 1), 1);
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);
tree delta21 = integer_zero_node;
tree e1, e2, e3;
tree integer_neg_one_node
- = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+ = build_binary_op (MINUS_EXPR, integer_zero_node, integer_one_node, 1);
if (TREE_CODE (TREE_OPERAND (op1, 0)) == FUNCTION_DECL
&& DECL_VINDEX (TREE_OPERAND (op1, 0)))
{
{
return build_binary_op (code, op1, op0, 1);
}
- else
- /* If args are not valid, clear out RESULT_TYPE
- to cause an error message later. */
- result_type = 0;
break;
case MAX_EXPR:
shorten = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- if (! comp_target_types (type0, type1, 1))
- pedwarn ("comparison of distinct pointer types lacks a cast");
- else if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
- != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
- pedwarn ("comparison of complete and incomplete pointers");
- else if (pedantic
- && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids ordered comparisons of pointers to functions");
- result_type = common_type (type0, type1);
+ if (comp_target_types (type0, type1, 1))
+ result_type = common_type (type0, type1);
+ else
+ {
+ cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
+ type0, type1);
+ result_type = ptr_type_node;
+ }
}
break;
case GE_EXPR:
case LT_EXPR:
case GT_EXPR:
+ build_type = boolean_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
&& (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
- if (! comp_target_types (type0, type1, 1))
- pedwarn ("comparison of distinct pointer types lacks a cast");
- else if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
- != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
- pedwarn ("comparison of complete and incomplete pointers");
- else if (pedantic
- && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids ordered comparisons of pointers to functions");
- result_type = integer_type_node;
+ if (comp_target_types (type0, type1, 1))
+ result_type = common_type (type0, type1);
+ else
+ {
+ cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
+ type0, type1);
+ result_type = ptr_type_node;
+ }
}
else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
&& integer_zerop (op1))
- {
- result_type = integer_type_node;
- op1 = null_pointer_node;
- if (pedantic)
- pedwarn ("ordered comparison of pointer with integer zero");
- }
+ result_type = type0;
else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
&& integer_zerop (op0))
- {
- result_type = integer_type_node;
- op0 = null_pointer_node;
- if (pedantic)
- pedwarn ("ANSI C++ forbids ordered comparison of pointer with integer zero");
- }
+ result_type = type1;
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- result_type = integer_type_node;
+ result_type = type0;
if (pedantic)
pedwarn ("ANSI C++ forbids comparison between pointer and integer");
else if (! flag_traditional)
warning ("comparison between pointer and integer");
- op1 = convert (TREE_TYPE (op0), op1);
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
- result_type = integer_type_node;
+ result_type = type1;
if (pedantic)
pedwarn ("ANSI C++ forbids comparison between pointer and integer");
else if (! flag_traditional)
warning ("comparison between pointer and integer");
- op0 = convert (TREE_TYPE (op1), op0);
}
- converted = 1;
break;
}
unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0));
if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
+ /* We can shorten only if the shift count is less than the
+ number of bits in the smaller type size. */
+ && TREE_INT_CST_HIGH (op1) == 0
+ && TYPE_PRECISION (TREE_TYPE (arg0)) > TREE_INT_CST_LOW (op1)
/* If arg is sign-extended and then unsigned-shifted,
we can simulate this with a signed shift in arg's type
only if the extended result is at least twice as wide
it never happens because available widths are 2**N. */
&& (!TREE_UNSIGNED (final_type)
|| unsigned_arg
- || ((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0))
+ || (((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0)))
<= TYPE_PRECISION (result_type))))
{
/* Do an unsigned shift if the operand was zero-extended. */
tree val
= shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
if (val != 0)
- return val;
- op0 = xop0, op1 = xop1, result_type = xresult_type;
+ return convert (boolean_type_node, val);
+ op0 = xop0, op1 = xop1;
+ converted = 1;
resultcode = xresultcode;
}
- if (short_compare && extra_warnings)
+ if (short_compare && warn_sign_compare)
{
+ int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
+ int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
+
int unsignedp0, unsignedp1;
tree primop0 = get_narrower (op0, &unsignedp0);
tree primop1 = get_narrower (op1, &unsignedp1);
- /* Warn if signed and unsigned are being compared in a size larger
- than their original size, as this will always fail. */
+ /* 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
+ && TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
+ != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
+ {
+ cp_warning ("comparison between `%#T' and `%#T'",
+ TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
+ }
- if (unsignedp0 != unsignedp1
- && (TYPE_PRECISION (TREE_TYPE (primop0))
- < TYPE_PRECISION (result_type))
- && (TYPE_PRECISION (TREE_TYPE (primop1))
- < TYPE_PRECISION (result_type)))
- warning ("comparison between promoted unsigned and signed");
+ /* Give warnings for comparisons between signed and unsigned
+ quantities that may fail. */
+ /* Do the checking based on the original operand trees, so that
+ casts will be considered, but default promotions won't be. */
+
+ /* Do not warn if the comparison is being done in a signed type,
+ since the signed type will only be chosen if it can represent
+ all the values of the unsigned type. */
+ if (! TREE_UNSIGNED (result_type))
+ /* OK */;
+ /* Do not warn if both operands are unsigned. */
+ else if (op0_signed == op1_signed)
+ /* OK */;
+ /* Do not warn if the signed quantity is an unsuffixed
+ integer literal (or some static constant expression
+ involving such literals) and it is non-negative. */
+ else if ((op0_signed && TREE_CODE (orig_op0) == INTEGER_CST
+ && tree_int_cst_sgn (orig_op0) >= 0)
+ || (op1_signed && TREE_CODE (orig_op1) == INTEGER_CST
+ && tree_int_cst_sgn (orig_op1) >= 0))
+ /* OK */;
+ /* Do not warn if the comparison is an equality operation,
+ the unsigned quantity is an integral constant and it does
+ not use the most significant bit of result_type. */
+ else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR)
+ && ((op0_signed && TREE_CODE (orig_op1) == INTEGER_CST
+ && int_fits_type_p (orig_op1, signed_type (result_type))
+ || (op1_signed && TREE_CODE (orig_op0) == INTEGER_CST
+ && int_fits_type_p (orig_op0, signed_type (result_type))))))
+ /* OK */;
+ else
+ warning ("comparison between signed and unsigned");
/* Warn if two unsigned values are being compared in a size
larger than their original size, and one (and only one) is the
have all bits set that are set in the ~ operand when it is
extended. */
- else if (TREE_CODE (primop0) == BIT_NOT_EXPR
- ^ TREE_CODE (primop1) == BIT_NOT_EXPR)
+ if ((TREE_CODE (primop0) == BIT_NOT_EXPR)
+ ^ (TREE_CODE (primop1) == BIT_NOT_EXPR))
{
if (TREE_CODE (primop0) == BIT_NOT_EXPR)
primop0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
if (!result_type)
{
- binary_op_error (error_code);
+ cp_error ("invalid operands `%T' and `%T' to binary `%O'",
+ TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), error_code);
return error_mark_node;
}
op1 = convert (result_type, op1);
}
+ if (build_type == NULL_TREE)
+ build_type = result_type;
+
{
- register tree result = build (resultcode, result_type, op0, op1);
+ register tree result = build (resultcode, build_type, op0, op1);
register tree folded;
folded = fold (result);
}
else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
{
- if (pedantic)
+ if (pedantic || warn_pointer_arith)
pedwarn ("ANSI C++ forbids using pointer to a member in arithmetic");
size_exp = integer_one_node;
}
else
- size_exp = size_in_bytes (TREE_TYPE (result_type));
+ size_exp = size_in_bytes (complete_type (TREE_TYPE (result_type)));
/* Needed to make OOPS V2R3 work. */
intop = folded;
intop = TREE_OPERAND (intop, 0);
}
- /* Convert the integer argument to a type the same size as a pointer
+ /* Convert the integer argument to a type the same size as sizetype
so the multiply won't overflow spuriously. */
- if (TYPE_PRECISION (TREE_TYPE (intop)) != POINTER_SIZE)
- intop = convert (type_for_size (POINTER_SIZE, 0), intop);
+ if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype))
+ intop = 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
tree restype = ptrdiff_type_node;
tree target_type = TREE_TYPE (TREE_TYPE (op0));
- if (pedantic)
+ if (pedantic || warn_pointer_arith)
{
if (TREE_CODE (target_type) == VOID_TYPE)
pedwarn ("ANSI C++ forbids using pointer of type `void *' in subtraction");
return error_mark_node;
}
- if (flag_gc)
- cp_warning ("address of `%T::%D' taken", basetype, field);
-
if (TREE_CODE (field) == FIELD_DECL
&& TYPE_USES_COMPLEX_INHERITANCE (basetype))
{
}
else
/* This conversion is harmless. */
- rval = convert (argtype, rval);
+ rval = convert_force (argtype, rval, 0);
if (! integer_zerop (DECL_FIELD_BITPOS (field)))
{
enum tree_code code;
tree xarg;
{
+ if (current_template_parms)
+ return build_min_nt (code, xarg, NULL_TREE);
+
/* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
error message. */
- if (code != ADDR_EXPR || TREE_CODE (TREE_TYPE (xarg)) != RECORD_TYPE
- || TYPE_SIZE (TREE_TYPE (xarg)))
+ if (code == ADDR_EXPR
+ && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
+ && TYPE_SIZE (TREE_TYPE (xarg)) == NULL_TREE)
+ || (TREE_CODE (xarg) == OFFSET_REF)))
+ /* don't look for a function */;
+ else
{
tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg,
NULL_TREE, NULL_TREE);
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);
}
+/* Just like truthvalue_conversion, but we want a CLEANUP_POINT_EXPR. */
+
+tree
+condition_conversion (expr)
+ tree expr;
+{
+ tree t;
+ if (current_template_parms)
+ return expr;
+ t = convert (boolean_type_node, expr);
+ t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
+ return t;
+}
+
/* C++: Must handle pointers to members.
Perhaps type instantiation should be extended to handle conversion
/* No default_conversion here. It causes trouble for ADDR_EXPR. */
register tree arg = xarg;
register tree argtype = 0;
- register enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
char *errstring = NULL;
tree val;
- int isaggrtype;
- if (typecode == ERROR_MARK)
+ if (arg == error_mark_node)
return error_mark_node;
- if (typecode == REFERENCE_TYPE && code != ADDR_EXPR && ! noconvert)
- {
- arg = convert_from_reference (arg);
- typecode = TREE_CODE (TREE_TYPE (arg));
- }
-
- if (typecode == ENUMERAL_TYPE)
- typecode = INTEGER_TYPE;
-
- isaggrtype = IS_AGGR_TYPE_CODE (typecode);
-
switch (code)
{
case CONVERT_EXPR:
/* This is used for unary plus, because a CONVERT_EXPR
is enough to prevent anybody from looking inside for
associativity, but won't generate any code. */
- if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
- errstring = "wrong type argument to unary plus";
- else if (!noconvert)
- arg = default_conversion (arg);
- break;
-
- case NEGATE_EXPR:
- if (isaggrtype)
+ if (!(arg = build_expr_type_conversion
+ (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, 1)))
+ errstring = "wrong type argument to unary plus";
+ else
{
if (!noconvert)
- arg = default_conversion (arg);
- else
- {
- cp_error ("type conversion for type `%T' not allowed",
- TREE_TYPE (arg));
- return error_mark_node;
- }
- typecode = TREE_CODE (TREE_TYPE (arg));
- noconvert = 1;
+ arg = default_conversion (arg);
+ arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
}
+ break;
- if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
- errstring = "wrong type argument to unary minus";
+ case NEGATE_EXPR:
+ if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+ errstring = "wrong type argument to unary minus";
else if (!noconvert)
arg = default_conversion (arg);
break;
case BIT_NOT_EXPR:
- if (isaggrtype)
- {
- if (!noconvert)
- arg = default_conversion (arg);
- else
- {
- cp_error ("type conversion for type `%T' not allowed",
- TREE_TYPE (arg));
- return error_mark_node;
- }
- typecode = TREE_CODE (TREE_TYPE (arg));
- noconvert = 1;
- }
-
- if (typecode != INTEGER_TYPE)
- errstring = "wrong type argument to bit-complement";
+ if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM, arg, 1)))
+ errstring = "wrong type argument to bit-complement";
else if (!noconvert)
arg = default_conversion (arg);
break;
case ABS_EXPR:
- if (isaggrtype)
- {
- if (!noconvert)
- arg = default_conversion (arg);
- else
- {
- cp_error ("type conversion for type `%T' not allowed",
- TREE_TYPE (arg));
- return error_mark_node;
- }
- typecode = TREE_CODE (TREE_TYPE (arg));
- noconvert = 1;
- }
-
- if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
- errstring = "wrong type argument to abs";
+ if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+ errstring = "wrong type argument to abs";
else if (!noconvert)
arg = default_conversion (arg);
break;
case TRUTH_NOT_EXPR:
- if (isaggrtype)
- {
- arg = truthvalue_conversion (arg);
- typecode = TREE_CODE (TREE_TYPE (arg));
- }
-
- if (typecode != INTEGER_TYPE
- && typecode != REAL_TYPE && typecode != POINTER_TYPE
- /* These will convert to a pointer. */
- && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE)
- {
- errstring = "wrong type argument to unary exclamation mark";
- break;
- }
- arg = truthvalue_conversion (arg);
+ arg = convert (boolean_type_node, arg);
val = invert_truthvalue (arg);
- if (val) return val;
+ if (arg != error_mark_node)
+ return val;
+ errstring = "in argument to unary !";
break;
case NOP_EXPR:
/* Report invalid types. */
- if (isaggrtype)
- {
- arg = default_conversion (arg);
- typecode = TREE_CODE (TREE_TYPE (arg));
- }
-
- if (typecode != POINTER_TYPE
- && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
+ if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
+ arg, 1)))
{
if (code == PREINCREMENT_EXPR)
errstring ="no pre-increment operator for type";
/* Compute the increment. */
- if (typecode == POINTER_TYPE)
+ if (TREE_CODE (argtype) == POINTER_TYPE)
{
enum tree_code tmp = TREE_CODE (TREE_TYPE (argtype));
- if (TYPE_SIZE (TREE_TYPE (argtype)) == 0)
+ if (TYPE_SIZE (complete_type (TREE_TYPE (argtype))) == 0)
cp_error ("cannot %s a pointer to incomplete type `%T'",
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
{
- tree incremented, modify, value;
+ tree incremented, modify, value, compound;
+ if (! lvalue_p (arg) && pedantic)
+ pedwarn ("cast to non-reference type used as lvalue");
arg = stabilize_reference (arg);
if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
value = arg;
? PLUS_EXPR : MINUS_EXPR),
argtype, value, inc);
TREE_SIDE_EFFECTS (incremented) = 1;
+
modify = build_modify_expr (arg, NOP_EXPR, incremented);
- return build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+ compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+
+ /* Eliminate warning about unused result of + or -. */
+ TREE_NO_UNUSED_WARNING (compound) = 1;
+ return compound;
}
}
- if (TREE_CODE (arg) == OFFSET_REF)
- arg = resolve_offset_ref (arg);
-
/* Complain about anything else that is not a true lvalue. */
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement")))
return error_mark_node;
- val = build (code, TREE_TYPE (arg), arg, inc);
+ /* Forbid using -- on `bool'. */
+ if (TREE_TYPE (arg) == boolean_type_node)
+ {
+ if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
+ {
+ cp_error ("invalid use of `--' on bool variable `%D'", arg);
+ return error_mark_node;
+ }
+#if 0
+ /* This will only work if someone can convince Kenner to accept
+ my patch to expand_increment. (jason) */
+ val = build (code, TREE_TYPE (arg), arg, inc);
+#else
+ if (code == POSTINCREMENT_EXPR)
+ {
+ arg = stabilize_reference (arg);
+ val = build (MODIFY_EXPR, TREE_TYPE (arg), arg,
+ boolean_true_node);
+ TREE_SIDE_EFFECTS (val) = 1;
+ arg = save_expr (arg);
+ val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+ val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+ }
+ else
+ val = build (MODIFY_EXPR, TREE_TYPE (arg), arg,
+ boolean_true_node);
+#endif
+ }
+ else
+ val = build (code, TREE_TYPE (arg), arg, inc);
+
TREE_SIDE_EFFECTS (val) = 1;
return convert (result_type, val);
}
/* Note that this operation never does default_conversion
regardless of NOCONVERT. */
- if (typecode == REFERENCE_TYPE)
+ 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;
return arg;
}
- else if (TREE_CODE (arg) == FUNCTION_DECL
+ else if (pedantic
+ && TREE_CODE (arg) == FUNCTION_DECL
&& DECL_NAME (arg)
&& DECL_CONTEXT (arg) == NULL_TREE
&& IDENTIFIER_LENGTH (DECL_NAME (arg)) == 4
&& IDENTIFIER_POINTER (DECL_NAME (arg))[0] == 'm'
&& ! strcmp (IDENTIFIER_POINTER (DECL_NAME (arg)), "main"))
- {
- /* ARM $3.4 */
- error ("attempt to take address of function `main'");
- return error_mark_node;
- }
+ /* ARM $3.4 */
+ pedwarn ("taking address of function `main'");
/* 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. */
TREE_OPERAND (arg, 1), 1);
}
- /* For &(++foo), we are really taking the address of the variable
- being acted upon by the increment/decrement operator. ARM $5.3.1
- However, according to ARM $5.2.5, we don't allow postfix ++ and
- --, since the prefix operators return lvalues, but the postfix
- operators do not. */
- if (TREE_CODE (arg) == PREINCREMENT_EXPR
- || TREE_CODE (arg) == PREDECREMENT_EXPR)
- arg = TREE_OPERAND (arg, 0);
-
/* Uninstantiated types are all functions. Taking the
address of a function is a no-op, so just return the
argument. */
if (TREE_CODE (arg) == TREE_LIST)
{
- /* Look at methods with only this name. */
- if (TREE_CODE (TREE_VALUE (arg)) == FUNCTION_DECL)
- {
- tree targ = TREE_VALUE (arg);
-
- /* If this function is unique, or it is a unique
- constructor, we can take its address easily. */
- if (DECL_CHAIN (targ) == NULL_TREE
- || (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (targ))
- && DECL_CHAIN (DECL_CHAIN (targ)) == NULL_TREE))
- {
- if (DECL_CHAIN (targ))
- targ = DECL_CHAIN (targ);
- if (DECL_CLASS_CONTEXT (targ))
- targ = build (OFFSET_REF, TREE_TYPE (targ), C_C_D, targ);
-
- val = unary_complex_lvalue (ADDR_EXPR, targ);
- if (val)
- return val;
- }
-
- /* This possible setting of TREE_CONSTANT is what makes it possible
- with an initializer list to emit the entire thing in the data
- section, rather than a run-time initialization. */
- arg = build1 (ADDR_EXPR, unknown_type_node, arg);
- if (staticp (targ))
- TREE_CONSTANT (arg) = 1;
- return arg;
- }
+ if (TREE_CODE (TREE_VALUE (arg)) == FUNCTION_DECL
+ && DECL_CHAIN (TREE_VALUE (arg)) == NULL_TREE)
+ /* Unique overloaded non-member function. */
+ return build_unary_op (ADDR_EXPR, TREE_VALUE (arg), 0);
if (TREE_CHAIN (arg) == NULL_TREE
&& TREE_CODE (TREE_VALUE (arg)) == TREE_LIST
&& DECL_CHAIN (TREE_VALUE (TREE_VALUE (arg))) == NULL_TREE)
- {
- /* Unique overloaded member function. */
- return build_unary_op (ADDR_EXPR, TREE_VALUE (TREE_VALUE (arg)), 0);
- }
+ /* Unique overloaded member function. */
+ return build_unary_op (ADDR_EXPR, TREE_VALUE (TREE_VALUE (arg)),
+ 0);
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
if (val != 0)
return val;
-#if 0 /* Turned off because inconsistent;
- float f; *&(int)f = 3.4 stores in int format
- whereas (int)f = 3.4 stores in float format. */
- /* Address of a cast is just a cast of the address
- of the operand of the cast. */
switch (TREE_CODE (arg))
{
case NOP_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
- if (pedantic)
- pedwarn ("ANSI C++ forbids taking the address of a cast expression");
- return convert (build_pointer_type (TREE_TYPE (arg)),
- build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0));
+ if (! lvalue_p (arg) && pedantic)
+ pedwarn ("taking the address of a cast to non-reference type");
}
-#endif
/* Allow the address of a constructor if all the elements
are constant. */
;
/* Anything not already handled and not a true memory reference
is an error. */
- else if (typecode != FUNCTION_TYPE
- && typecode != METHOD_TYPE
+ else if (TREE_CODE (argtype) != FUNCTION_TYPE
+ && TREE_CODE (argtype) != METHOD_TYPE
&& !lvalue_or_else (arg, "unary `&'"))
return error_mark_node;
/* Ordinary case; arg is a COMPONENT_REF or a decl. */
- argtype = TREE_TYPE (arg);
/* If the lvalue is const or volatile,
merge that into the type that the address will point to. */
if (TREE_CODE_CLASS (TREE_CODE (arg)) == 'd'
|| TREE_CODE_CLASS (TREE_CODE (arg)) == 'r')
{
if (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg))
- argtype = build_type_variant (argtype,
- TREE_READONLY (arg),
- TREE_THIS_VOLATILE (arg));
+ argtype = cp_build_type_variant (argtype,
+ TREE_READONLY (arg),
+ TREE_THIS_VOLATILE (arg));
}
argtype = build_pointer_type (argtype);
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;
}
}
return error_mark_node;
}
+#if 0
/* If CONVERSIONS is a conversion expression or a nested sequence of such,
convert ARG with the same conversions in the same order
and return the result. */
return arg;
}
}
+#endif
/* Apply unary lvalue-demanding operator CODE to the expression ARG
for certain kinds of expressions which are not really lvalues
if (TREE_CODE (arg) == COND_EXPR)
return rationalize_conditional_expr (code, arg);
- if (TREE_CODE (arg) == MODIFY_EXPR)
+ if (TREE_CODE (arg) == MODIFY_EXPR
+ || TREE_CODE (arg) == PREINCREMENT_EXPR
+ || TREE_CODE (arg) == PREDECREMENT_EXPR)
return unary_complex_lvalue
(code, build (COMPOUND_EXPR, TREE_TYPE (TREE_OPERAND (arg, 0)),
arg, TREE_OPERAND (arg, 0)));
return build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
}
- if (TREE_CODE (arg) == WITH_CLEANUP_EXPR)
- {
- tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
- real_result = build (WITH_CLEANUP_EXPR, TREE_TYPE (real_result),
- real_result, 0, TREE_OPERAND (arg, 2));
- return real_result;
- }
-
if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE
|| TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
return build_unary_op (ADDR_EXPR, t, 0);
else
{
- /* Can't build a pointer to member if the member must
- go through virtual base classes. */
- if (virtual_member (DECL_FIELD_CONTEXT (t),
- CLASSTYPE_VBASECLASSES (TREE_TYPE (TREE_OPERAND (arg, 0)))))
- {
- sorry ("pointer to member via virtual baseclass");
- return error_mark_node;
- }
-
if (TREE_OPERAND (arg, 0)
&& (TREE_CODE (TREE_OPERAND (arg, 0)) != NOP_EXPR
|| TREE_OPERAND (TREE_OPERAND (arg, 0), 0) != error_mark_node))
- {
- /* Don't know if this should return address to just
- _DECL, or actual address resolved in this expression. */
- sorry ("address of bound pointer-to-member expression");
- return error_mark_node;
- }
+ if (TREE_CODE (t) != FIELD_DECL)
+ {
+ /* Don't know if this should return address to just
+ _DECL, or actual address resolved in this expression. */
+ sorry ("address of bound pointer-to-member expression");
+ return error_mark_node;
+ }
- return convert (build_pointer_type (TREE_TYPE (arg)),
- size_binop (EASY_DIV_EXPR,
- DECL_FIELD_BITPOS (t),
- size_int (BITS_PER_UNIT)));
- }
- }
+ /* Add in the offset to the right subobject. */
+ offset = get_delta_difference (DECL_FIELD_CONTEXT (t),
+ TREE_TYPE (TREE_OPERAND (arg, 0)),
+ 0);
- 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);
+ /* 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)));
- 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 convert (build_pointer_type (TREE_TYPE (arg)), offset);
+ }
}
+
/* We permit compiler to make function calls returning
objects of aggregate type look like lvalues. */
{
if (TREE_CODE (arg) == SAVE_EXPR)
targ = arg;
else
- targ = build_cplus_new (TREE_TYPE (arg), arg, 1);
- return build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (arg)), targ);
+ targ = build_cplus_new (TREE_TYPE (arg), arg);
+ return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (arg)), targ);
}
if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == INDIRECT_REF)
- return build (SAVE_EXPR, TYPE_POINTER_TO (TREE_TYPE (arg)),
+ return build (SAVE_EXPR, build_pointer_type (TREE_TYPE (arg)),
TREE_OPERAND (targ, 0), current_function_decl, NULL);
-
- /* We shouldn't wrap WITH_CLEANUP_EXPRs inside of SAVE_EXPRs, but in case
- we do, here's how to handle it. */
- if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == WITH_CLEANUP_EXPR)
- {
-#if 0
- /* Not really a bug, but something to turn on when testing. */
- compiler_error ("WITH_CLEANUP_EXPR wrapped in SAVE_EXPR");
-#endif
- return unary_complex_lvalue (ADDR_EXPR, targ);
- }
}
/* Don't let anything else be handled specially. */
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)
break;
case PARM_DECL:
- if (x == current_class_decl)
+ if (x == current_class_ptr)
{
error ("address of `this' not available");
TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
return 1;
}
case VAR_DECL:
- if (TREE_STATIC (x)
- && TREE_READONLY (x)
+ if (TREE_STATIC (x) && TREE_READONLY (x)
&& DECL_RTL (x) != 0
- && ! decl_in_memory_p (x))
+ && ! DECL_IN_MEMORY_P (x))
{
/* We thought this would make a good constant variable,
but we were wrong. */
be non-zero in the case of processing a default function.
The second may be non-zero in the case of a template function. */
x = DECL_MAIN_VARIANT (x);
- if ((DECL_INLINE (x) || DECL_PENDING_INLINE_INFO (x))
+ if ((DECL_THIS_INLINE (x) || DECL_PENDING_INLINE_INFO (x))
&& (DECL_CONTEXT (x) == NULL_TREE
|| TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (x))) != 't'
|| ! CLASSTYPE_INTERFACE_ONLY (DECL_CONTEXT (x))))
{
tree rval = NULL_TREE;
+ if (current_template_parms)
+ return build_min_nt (COND_EXPR, ifexp, op1, op2);
+
/* See comments in `build_x_binary_op'. */
if (op1 != 0)
rval = build_opfncall (COND_EXPR, LOOKUP_SPECULATIVELY, ifexp, op1, op2);
ifexp = op1 = save_expr (ifexp);
}
- ifexp = truthvalue_conversion (default_conversion (ifexp));
+ ifexp = convert (boolean_type_node, ifexp);
if (TREE_CODE (ifexp) == ERROR_MARK)
return error_mark_node;
code2 = TREE_CODE (type2);
}
-#if 1 /* Produces wrong result if within sizeof. Sorry. */
/* Don't promote the operands separately if they promote
the same way. Return the unpromoted type and let the combined
value get promoted if necessary. */
if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
&& code2 != ARRAY_TYPE
-#if 0
- /* For C++, let the enumeral type come through. */
- && code2 != ENUMERAL_TYPE
-#endif
&& code2 != FUNCTION_TYPE
&& code2 != METHOD_TYPE)
{
else if (TREE_READONLY_DECL_P (op2))
op2 = decl_constant_value (op2);
if (type1 != type2)
- type1 = build_type_variant
+ type1 = cp_build_type_variant
(type1,
TREE_READONLY (op1) || TREE_READONLY (op2),
TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
result = build1 (NOP_EXPR, type1, result);
return result;
}
-#endif
/* They don't match; promote them both and then try to reconcile them.
But don't permit mismatching enum types. */
{
if (code2 == ENUMERAL_TYPE)
{
- message_2_types (error, "enumeral mismatch in conditional expression: `%s' vs `%s'", type1, type2);
+ cp_error ("enumeral mismatch in conditional expression: `%T' vs `%T'", type1, type2);
return error_mark_node;
}
- else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2))
+ else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2)
+ && type2 != type_promotes_to (type1))
warning ("enumeral and non-enumeral type in conditional expression");
}
else if (extra_warnings
- && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1))
+ && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1)
+ && type1 != type_promotes_to (type2))
warning ("enumeral and non-enumeral type in conditional expression");
if (code1 != VOID_TYPE)
{
op1 = default_conversion (op1);
type1 = TREE_TYPE (op1);
+ if (TYPE_PTRMEMFUNC_P (type1))
+ type1 = TYPE_PTRMEMFUNC_FN_TYPE (type1);
code1 = TREE_CODE (type1);
}
if (code2 != VOID_TYPE)
{
op2 = default_conversion (op2);
type2 = TREE_TYPE (op2);
+ if (TYPE_PTRMEMFUNC_P (type2))
+ type2 = TYPE_PTRMEMFUNC_FN_TYPE (type2);
code2 = TREE_CODE (type2);
}
+ if (code1 == RECORD_TYPE && code2 == RECORD_TYPE
+ && real_lvalue_p (op1) && real_lvalue_p (op2)
+ && comptypes (type1, type2, -1))
+ {
+ type1 = build_reference_type (type1);
+ type2 = build_reference_type (type2);
+ result_type = common_type (type1, type2);
+ op1 = convert_to_reference (result_type, op1, CONV_IMPLICIT,
+ LOOKUP_NORMAL, NULL_TREE);
+ op2 = convert_to_reference (result_type, op2, CONV_IMPLICIT,
+ LOOKUP_NORMAL, NULL_TREE);
+ }
/* Quickly detect the usual case where op1 and op2 have the same type
after promotion. */
- if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
+ else if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
{
if (type1 == type2)
result_type = type1;
else
- result_type = build_type_variant
+ result_type = cp_build_type_variant
(type1,
TREE_READONLY (op1) || TREE_READONLY (op2),
TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
{
if (result_type == error_mark_node)
{
- message_2_types (error, "common base type of types `%s' and `%s' is ambiguous",
- TREE_TYPE (type1), TREE_TYPE (type2));
+ cp_error ("common base type of types `%T' and `%T' is ambiguous",
+ TREE_TYPE (type1), TREE_TYPE (type2));
result_type = ptr_type_node;
}
- else result_type = TYPE_POINTER_TO (result_type);
+ else
+ {
+ if (pedantic
+ && result_type != TREE_TYPE (type1)
+ && result_type != TREE_TYPE (type2))
+ cp_pedwarn ("`%T' and `%T' converted to `%T *' in conditional expression",
+ type1, type2, result_type);
+
+ result_type = build_pointer_type (result_type);
+ }
}
else
{
if (!integer_zerop (op2))
pedwarn ("pointer/integer type mismatch in conditional expression");
else
- {
- op2 = null_pointer_node;
-#if 0 /* Sez who? */
- if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids conditional expr between 0 and function pointer");
-#endif
- }
+ op2 = null_pointer_node;
+
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;
-#if 0 /* Sez who? */
- if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids conditional expr between 0 and function pointer");
-#endif
- }
+ op1 = null_pointer_node;
+
result_type = type2;
}
an aggregate value, try converting to a scalar type. */
if (code1 == RECORD_TYPE && code2 == RECORD_TYPE)
{
- message_2_types (error, "aggregate mismatch in conditional expression: `%s' vs `%s'", type1, 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);
+ tree tmp = build_pointer_type
+ (build_type_variant (TREE_TYPE (type2), 1, 1));
+ 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 (type1, 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 = build_pointer_type
+ (build_type_variant (TREE_TYPE (type1), 1, 1));
+ 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)
}
}
+ if (TREE_CODE (result_type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
+ result_type = build_ptrmemfunc_type (result_type);
+
if (result_type != TREE_TYPE (op1))
op1 = convert_and_check (result_type, op1);
if (result_type != TREE_TYPE (op2))
op2 = convert_and_check (result_type, op2);
-#if 0
- /* XXX delete me, I've been here for years. */
- if (IS_AGGR_TYPE_CODE (code1))
- {
- result_type = TREE_TYPE (op1);
- if (TREE_CONSTANT (ifexp))
- return (integer_zerop (ifexp) ? op2 : op1);
-
- if (TYPE_MODE (result_type) == BLKmode)
- {
- register tree tempvar
- = build_decl (VAR_DECL, NULL_TREE, result_type);
- register tree xop1 = build_modify_expr (tempvar, NOP_EXPR, op1);
- register tree xop2 = build_modify_expr (tempvar, NOP_EXPR, op2);
- register tree result = fold (build (COND_EXPR, result_type,
- ifexp, xop1, xop2));
-
- layout_decl (tempvar, 0);
- /* No way to handle variable-sized objects here.
- I fear that the entire handling of BLKmode conditional exprs
- needs to be redone. */
- my_friendly_assert (TREE_CONSTANT (DECL_SIZE (tempvar)), 315);
- DECL_RTL (tempvar)
- = assign_stack_local (DECL_MODE (tempvar),
- (TREE_INT_CST_LOW (DECL_SIZE (tempvar))
- + BITS_PER_UNIT - 1)
- / BITS_PER_UNIT,
- 0);
-
- TREE_SIDE_EFFECTS (result)
- = TREE_SIDE_EFFECTS (ifexp) | TREE_SIDE_EFFECTS (op1)
- | TREE_SIDE_EFFECTS (op2);
- return build (COMPOUND_EXPR, result_type, result, tempvar);
- }
- }
-#endif /* 0 */
-
if (TREE_CONSTANT (ifexp))
return integer_zerop (ifexp) ? op2 : op1;
- return fold (build (COND_EXPR, result_type, ifexp, op1, op2));
+ return convert_from_reference
+ (fold (build (COND_EXPR, result_type, ifexp, op1, op2)));
}
\f
/* Handle overloading of the ',' operator when needed. Otherwise,
tree rest = TREE_CHAIN (list);
tree result;
+ if (current_template_parms)
+ return build_min_nt (COMPOUND_EXPR, list, NULL_TREE);
+
if (rest == NULL_TREE)
return build_compound_expr (list);
TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
if (result)
return build_x_compound_expr (tree_cons (NULL_TREE, result, TREE_CHAIN (rest)));
+
+ if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
+ {
+ /* the left-hand operand of a comma expression is like an expression
+ statement: we should warn if it doesn't have any side-effects,
+ unless it was explicitly cast to (void). */
+ if ((extra_warnings || warn_unused)
+ && !(TREE_CODE (TREE_VALUE(list)) == CONVERT_EXPR
+ && TREE_TYPE (TREE_VALUE(list)) == void_type_node))
+ warning("left-hand operand of comma expression has no effect");
+ }
+#if 0 /* this requires a gcc backend patch to export warn_if_unused_value */
+ else if (warn_unused)
+ warn_if_unused_value (TREE_VALUE(list));
+#endif
+
return build_compound_expr (tree_cons (NULL_TREE, TREE_VALUE (list),
build_tree_list (NULL_TREE, build_x_compound_expr (rest))));
}
rest = build_compound_expr (TREE_CHAIN (list));
- /* When pedantic, a compound expression can be neither an lvalue
- nor an integer constant expression. */
+ /* When pedantic, a compound expression cannot be a constant expression. */
if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)) && ! pedantic)
return rest;
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);
+ return build_c_cast (type, expr, 0);
}
-tree build_reinterpret_cast (type, expr)
+tree
+build_reinterpret_cast (type, expr)
tree type, expr;
{
- return build_c_cast (type, expr);
+ tree intype = TREE_TYPE (expr);
+
+ if (current_template_parms)
+ {
+ tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
+ return t;
+ }
+
+ if (TYPE_PTRMEMFUNC_P (type))
+ if (TYPE_PTRMEMFUNC_P (intype))
+ return build1 (NOP_EXPR, type, expr);
+
+ if (TYPE_PTRMEMFUNC_P (type))
+ type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+
+ if (TYPE_PTRMEMFUNC_P (intype))
+ intype = TYPE_PTRMEMFUNC_FN_TYPE (intype);
+
+ if (! POINTER_TYPE_P (type) && ! TREE_CODE (type) == INTEGER_TYPE)
+ {
+ cp_error ("reinterpret_cast cannot convert to type `%T'", type);
+ return error_mark_node;
+ }
+ if (! POINTER_TYPE_P (intype) && ! TREE_CODE (intype) == INTEGER_TYPE)
+ {
+ cp_error ("reinterpret_cast cannot convert from type `%T'", type);
+ return error_mark_node;
+ }
+ if (TREE_CODE (type) == INTEGER_TYPE && TREE_CODE (intype) != POINTER_TYPE)
+ {
+ cp_error ("reinterpret_cast cannot convert non-pointer type `%T' to `%T'",
+ intype, type);
+ return error_mark_node;
+ }
+ if (TREE_CODE (intype) == INTEGER_TYPE && TREE_CODE (type) != POINTER_TYPE)
+ {
+ cp_error ("reinterpret_cast cannot convert `%T' to non-pointer type `%T'",
+ intype, type);
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (intype) == POINTER_TYPE)
+ expr = convert (ptr_type_node, expr);
+
+ return build_c_cast (type, expr, 0);
}
-tree build_const_cast (type, expr)
+tree
+build_const_cast (type, expr)
tree type, expr;
{
- return build_c_cast (type, expr);
+ tree intype = TREE_TYPE (expr);
+ tree t1, t2;
+
+ 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 (! 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))
+ {
+ cp_error ("const_cast cannot convert rvalue to type `%T'", type);
+ return error_mark_node;
+ }
+ if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (intype) != POINTER_TYPE)
+ {
+ cp_error ("const_cast cannot convert non-pointer type `%T' to type `%T'",
+ intype, type);
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ t1 = TREE_TYPE (type);
+ t2 = intype;
+ }
+ 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))
+ ;
+ }
+
+ if (TREE_CODE (t1) == OFFSET_TYPE && TREE_CODE (t2) == OFFSET_TYPE)
+ {
+ if (TYPE_OFFSET_BASETYPE (t1) != TYPE_OFFSET_BASETYPE (t2))
+ {
+ cp_error ("const_cast cannot convert between pointers to members of different types `%T' and `%T'",
+ TYPE_OFFSET_BASETYPE (t2), TYPE_OFFSET_BASETYPE (t1));
+ 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;
+ }
+
+ return build_c_cast (type, expr, 0);
}
-/* Build an expression representing a cast to type TYPE of expression EXPR. */
+/* Build an expression representing a cast to type TYPE of expression EXPR.
+
+ ALLOW_NONCONVERTING is true if we should allow non-converting constructors
+ when doing the cast. */
tree
-build_c_cast (type, expr)
+build_c_cast (type, expr, allow_nonconverting)
register tree type;
tree expr;
+ int allow_nonconverting;
{
register tree value = expr;
return error_mark_node;
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
- Strip such NOP_EXPRs, since VALUE is being used in non-lvalue context. */
- if (TREE_CODE (value) == NOP_EXPR
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (type) != REFERENCE_TYPE
+ && TREE_CODE (value) == NOP_EXPR
&& TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0)))
value = TREE_OPERAND (value, 0);
}
}
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ {
+ cp_error ("casting to function type `%T'", type);
+ return error_mark_node;
+ }
+
if (IS_SIGNATURE (type))
{
error ("cast specifies signature type");
return error_mark_node;
}
- if (TREE_TYPE (value)
- && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (value)))
+ if (current_template_parms)
{
- /* For C++, we must copy the constness of TYPE into VALUE. */
- if (TREE_READONLY (value) != TYPE_READONLY (type))
- {
- value = copy_node (value);
- TREE_READONLY (value) = TYPE_READONLY (type);
- }
- else if (pedantic)
- {
- if (TREE_CODE (type) == RECORD_TYPE
- || TREE_CODE (type) == UNION_TYPE)
- pedwarn ("ANSI C++ forbids casting nonscalar to the same type");
- }
- return value;
+ tree t = build_min (CAST_EXPR, type,
+ min_tree_cons (NULL_TREE, value, NULL_TREE));
+ return t;
}
- /* 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);
-
- /* Make up for the fact that we do not always perform
- `default_conversion' anymore. */
- if (TREE_READONLY_DECL_P (value))
- value = decl_constant_value (value);
-
if (TREE_CODE (type) == VOID_TYPE)
- value = build1 (NOP_EXPR, type, value);
+ value = build1 (CONVERT_EXPR, type, value);
else if (TREE_TYPE (value) == NULL_TREE
|| type_unknown_p (value))
{
}
else
{
- tree otype, ovalue;
+ tree otype;
+ int flag;
/* Convert functions and arrays to pointers and
convert references to their expanded types,
warning ("cast increases required alignment of target type");
#if 0
+ /* We should see about re-enabling these, they seem useful to
+ me. */
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype))
warning ("cast to pointer from integer of different size");
#endif
- ovalue = value;
- value = convert_force (type, value);
+ flag = allow_nonconverting ? CONV_NONCONVERTING : 0;
- /* Ignore any integer overflow caused by the cast. */
- if (TREE_CODE (value) == INTEGER_CST)
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ value = (convert_from_reference
+ (convert_to_reference (type, value, CONV_OLD_CONVERT|flag,
+ LOOKUP_COMPLAIN, NULL_TREE)));
+ else
{
- TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
- TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+ tree ovalue;
+
+ if (TREE_READONLY_DECL_P (value))
+ value = decl_constant_value (value);
+
+ ovalue = value;
+ value = convert_force (type, value, flag);
+
+ /* Ignore any integer overflow caused by the cast. */
+ if (TREE_CODE (value) == INTEGER_CST)
+ {
+ TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+ TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+ }
}
}
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 (value == expr
- || (pedantic
- && TREE_CODE (value) == INTEGER_CST
- && TREE_CODE (expr) == INTEGER_CST
- && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE))
- {
- tree nvalue = build1 (NOP_EXPR, type, value);
- TREE_CONSTANT (nvalue) = TREE_CONSTANT (value);
- return nvalue;
- }
+ 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)))
+ value = non_lvalue (value);
return value;
}
\f
-#if 0
-/* Build an assignment expression of lvalue LHS from value RHS.
-
- In C++, if the left hand side of the assignment is a REFERENCE_TYPE,
- that reference becomes deferenced down to it base type. */
-
-/* Return a reference to the BASE_INDEX part of EXPR. TYPE is
- the type to which BASE_INDEX applies. */
-static tree
-get_base_ref (type, base_index, expr)
- tree type;
- int base_index;
- tree expr;
-{
- tree binfos = TYPE_BINFO_BASETYPES (type);
- tree base_binfo = TREE_VEC_ELT (binfos, base_index);
- tree ref;
-
- if (TREE_CODE (expr) == ARRAY_REF
- || ! BINFO_OFFSET_ZEROP (base_binfo)
- || TREE_VIA_VIRTUAL (base_binfo)
- || TYPE_MODE (type) != TYPE_MODE (BINFO_TYPE (base_binfo)))
- {
- tree addr = build_unary_op (ADDR_EXPR, expr, 0);
- ref = build_indirect_ref (convert_pointer_to (base_binfo, addr),
- NULL_PTR);
- }
- else
- {
- ref = copy_node (expr);
- TREE_TYPE (ref) = BINFO_TYPE (base_binfo);
- }
- return ref;
-}
-
-/* Build an assignment expression of lvalue LHS from value RHS.
- MODIFYCODE is the code for a binary operator that we use
- 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.
-
- `build_modify_expr_1' implements recursive part of memberwise
- assignment operation. */
-static tree
-build_modify_expr_1 (lhs, modifycode, rhs, basetype_path)
- tree lhs, rhs;
- enum tree_code modifycode;
- tree basetype_path;
-{
- register tree result;
- tree newrhs = rhs;
- tree lhstype = TREE_TYPE (lhs);
- tree olhstype = lhstype;
-
- /* Avoid duplicate error messages from operands that had errors. */
- if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
- return error_mark_node;
-
- /* If a binary op has been requested, combine the old LHS value with the RHS
- producing the value we should actually store into the LHS. */
-
- if (modifycode == INIT_EXPR)
- ;
- else if (modifycode == NOP_EXPR)
- {
- /* must deal with overloading of `operator=' here. */
- if (TREE_CODE (lhstype) == REFERENCE_TYPE)
- lhstype = TREE_TYPE (lhstype);
- else
- lhstype = olhstype;
- }
- else
- {
- lhs = stabilize_reference (lhs);
- newrhs = build_binary_op (modifycode, lhs, rhs, 1);
- modifycode = NOP_EXPR;
- }
-
- /* If storing into a structure or union member,
- it has probably been given type `int'.
- Compute the type that would go with
- the actual amount of storage the member occupies. */
-
- if (TREE_CODE (lhs) == COMPONENT_REF
- && (TREE_CODE (lhstype) == INTEGER_TYPE
- || TREE_CODE (lhstype) == REAL_TYPE
- || TREE_CODE (lhstype) == ENUMERAL_TYPE))
- lhstype = TREE_TYPE (get_unwidened (lhs, 0));
-
- /* C++: The semantics of C++ differ from those of C when an
- assignment of an aggregate is desired. Assignment in C++ is
- now defined as memberwise assignment of non-static members
- and base class objects. This rule applies recursively
- until a member of a built-in type is found.
-
- Also, we cannot do a bit-wise copy of aggregates which
- contain virtual function table pointers. Those
- pointer values must be preserved through the copy.
- However, this is handled in expand_expr, and not here.
- This is because much better code can be generated at
- that stage than this one. */
- if (TREE_CODE (lhstype) == RECORD_TYPE
- && TYPE_LANG_SPECIFIC (lhstype)
- && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
- {
- register tree elt;
- int i;
-
- /* Perform operation on object. */
- if (modifycode == INIT_EXPR && TYPE_HAS_INIT_REF (lhstype))
- {
- result = build_method_call (lhs, constructor_name_full (lhstype),
- build_tree_list (NULL_TREE, rhs),
- basetype_path, LOOKUP_NORMAL);
- return build_indirect_ref (result, NULL_PTR);
- }
- else if (modifycode == NOP_EXPR)
- {
- /* `operator=' is not an inheritable operator; see 13.4.3. */
- if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_HAS_ASSIGNMENT (lhstype))
- {
- result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
- if (result == NULL_TREE)
- return error_mark_node;
- return result;
- }
- }
-
- if (TYPE_USES_VIRTUAL_BASECLASSES (lhstype)
- || (modifycode == NOP_EXPR && TYPE_GETS_ASSIGNMENT (lhstype))
- || (modifycode == INIT_EXPR && TYPE_GETS_INIT_REF (lhstype)))
- {
- tree binfos = BINFO_BASETYPES (TYPE_BINFO (lhstype));
- result = NULL_TREE;
-
- if (binfos != NULL_TREE)
- /* Perform operation on each member, depth-first, left-right. */
- for (i = 0; i <= TREE_VEC_LENGTH (binfos)-1; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- tree base_lhs, base_rhs;
- tree new_result;
-
- /* Assignments from virtual baseclasses handled elsewhere. */
- if (TREE_VIA_VIRTUAL (base_binfo))
- continue;
-
- base_lhs = get_base_ref (lhstype, i, lhs);
- base_rhs = get_base_ref (lhstype, i, newrhs);
-
- BINFO_INHERITANCE_CHAIN (base_binfo) = basetype_path;
- new_result
- = build_modify_expr_1 (base_lhs, modifycode, base_rhs,
- base_binfo);
-
- /* We either get back a compound stmt, or a simple one. */
- if (new_result && TREE_CODE (new_result) == TREE_LIST)
- new_result = build_compound_expr (new_result);
- result = tree_cons (NULL_TREE, new_result, result);
- }
-
- for (elt = TYPE_FIELDS (lhstype); elt; elt = TREE_CHAIN (elt))
- {
- tree vbases = NULL_TREE;
- tree elt_lhs, elt_rhs;
-
- if (TREE_CODE (elt) != FIELD_DECL)
- continue;
- if (DECL_NAME (elt)
- && (VFIELD_NAME_P (DECL_NAME (elt))
- || VBASE_NAME_P (DECL_NAME (elt))))
- continue;
-
- if (TREE_READONLY (elt)
- || TREE_CODE (TREE_TYPE (elt)) == REFERENCE_TYPE)
- {
- cp_error ("cannot generate default `%T::operator ='",
- lhstype);
- if (TREE_CODE (TREE_TYPE (elt)) == REFERENCE_TYPE)
- cp_error_at ("because member `%#D' is a reference", elt);
- else
- cp_error_at ("because member `%#D' is const", elt);
-
- return error_mark_node;
- }
-
- if (IS_AGGR_TYPE (TREE_TYPE (elt))
- && TYPE_LANG_SPECIFIC (TREE_TYPE (elt)))
- vbases = CLASSTYPE_VBASECLASSES (TREE_TYPE (elt));
-
- elt_lhs = build (COMPONENT_REF, TREE_TYPE (elt), lhs, elt);
- elt_rhs = build (COMPONENT_REF, TREE_TYPE (elt), newrhs, elt);
- /* It is not always safe to go through `build_modify_expr_1'
- when performing element-wise copying. This is because
- an element may be of ARRAY_TYPE, which will not
- be properly copied as a naked element. */
- if (TREE_CODE (TREE_TYPE (elt)) == RECORD_TYPE
- && TYPE_LANG_SPECIFIC (TREE_TYPE (elt)))
- basetype_path = TYPE_BINFO (TREE_TYPE (elt));
-
- while (vbases)
- {
- tree elt_lhs_addr = build_unary_op (ADDR_EXPR, elt_lhs, 0);
- tree elt_rhs_addr = build_unary_op (ADDR_EXPR, elt_rhs, 0);
-
- elt_lhs_addr = convert_pointer_to (vbases, elt_lhs_addr);
- elt_rhs_addr = convert_pointer_to (vbases, elt_rhs_addr);
- result
- = tree_cons (NULL_TREE,
- build_modify_expr_1
- (build_indirect_ref (elt_lhs_addr, NULL_PTR),
- modifycode,
- build_indirect_ref (elt_rhs_addr, NULL_PTR),
- basetype_path),
- result);
- if (TREE_VALUE (result) == error_mark_node)
- return error_mark_node;
- vbases = TREE_CHAIN (vbases);
- }
- elt_lhs = build_modify_expr_1 (elt_lhs, modifycode, elt_rhs,
- basetype_path);
- result = tree_cons (NULL_TREE, elt_lhs, result);
- }
-
- if (result)
- return build_compound_expr (result);
- /* No fields to move. */
- return integer_zero_node;
- }
- else
- {
- result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
- void_type_node, lhs, rhs);
- TREE_SIDE_EFFECTS (result) = 1;
- return result;
- }
- }
-
- result = build_modify_expr (lhs, modifycode, newrhs);
- /* ARRAY_TYPEs cannot be converted to anything meaningful,
- and leaving it there screws up `build_compound_expr' when
- it tries to defaultly convert everything. */
- if (TREE_CODE (TREE_TYPE (result)) == ARRAY_TYPE)
- TREE_TYPE (result) = void_type_node;
- return result;
-}
-#endif
-
-/* Taken from expr.c:
- Subroutine of expand_expr:
- record the non-copied parts (LIST) of an expr (LHS), and return a list
- which specifies the initial values of these parts. */
-
-static tree
-init_noncopied_parts (lhs, list)
- tree lhs;
- tree list;
+tree
+expand_target_expr (t)
+ tree t;
{
- tree tail;
- tree parts = 0;
-
- for (tail = list; tail; tail = TREE_CHAIN (tail))
- if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
- parts = chainon (parts, init_noncopied_parts (lhs, TREE_VALUE (tail)));
- else
- {
- tree part = TREE_VALUE (tail);
- tree part_type = TREE_TYPE (part);
- tree to_be_initialized = build (COMPONENT_REF, part_type, lhs, part);
- parts = tree_cons (TREE_PURPOSE (tail), to_be_initialized, parts);
- }
- return parts;
+ extern int temp_slot_level;
+ extern int target_temp_slot_level;
+ int old_temp_level = target_temp_slot_level;
+
+ tree xval = make_node (RTL_EXPR);
+ rtx rtxval;
+
+ /* Any TARGET_EXPR temps live only as long as the outer temp level.
+ Since they are preserved in this new inner level, we know they
+ will make it into the outer level. */
+ push_temp_slots ();
+ target_temp_slot_level = temp_slot_level;
+
+ do_pending_stack_adjust ();
+ start_sequence_for_rtl_expr (xval);
+ emit_note (0, -1);
+ rtxval = expand_expr (t, NULL_RTX, VOIDmode, 0);
+ do_pending_stack_adjust ();
+ TREE_SIDE_EFFECTS (xval) = 1;
+ RTL_EXPR_SEQUENCE (xval) = get_insns ();
+ end_sequence ();
+ RTL_EXPR_RTL (xval) = rtxval;
+ TREE_TYPE (xval) = TREE_TYPE (t);
+
+ pop_temp_slots ();
+ target_temp_slot_level = old_temp_level;
+
+ return xval;
}
/* Build an assignment expression of lvalue LHS from value RHS.
tree newrhs = rhs;
tree lhstype = TREE_TYPE (lhs);
tree olhstype = lhstype;
-
- /* Types that aren't fully specified cannot be used in assignments. */
- lhs = require_complete_type (lhs);
+ tree olhs = lhs;
/* Avoid duplicate error messages from operands that had errors. */
if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
return error_mark_node;
- /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
- Strip such NOP_EXPRs, since RHS is being used in non-lvalue context. */
- if (TREE_CODE (rhs) == NOP_EXPR
- && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0)))
- rhs = TREE_OPERAND (rhs, 0);
-
- /* Decide early if we are going to protect RHS from GC
- before assigning it to LHS. */
- if (type_needs_gc_entry (TREE_TYPE (rhs))
- && ! value_safe_from_gc (lhs, rhs))
- rhs = protect_value_from_gc (lhs, rhs);
+ /* Types that aren't fully specified cannot be used in assignments. */
+ lhs = require_complete_type (lhs);
newrhs = 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),
so the code to compute it is only emitted once. */
tree cond
= build_conditional_expr (TREE_OPERAND (lhs, 0),
- build_modify_expr (TREE_OPERAND (lhs, 1),
+ build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
modifycode, rhs),
- build_modify_expr (TREE_OPERAND (lhs, 2),
+ build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
modifycode, rhs));
if (TREE_CODE (cond) == ERROR_MARK)
return cond;
}
}
+ if (TREE_CODE (lhs) == OFFSET_REF)
+ {
+ if (TREE_OPERAND (lhs, 0) == NULL_TREE)
+ {
+ /* Static class member? */
+ tree member = TREE_OPERAND (lhs, 1);
+ if (TREE_CODE (member) == VAR_DECL)
+ lhs = member;
+ else
+ {
+ compiler_error ("invalid static class member");
+ return error_mark_node;
+ }
+ }
+ else
+ lhs = resolve_offset_ref (lhs);
+
+ olhstype = lhstype = TREE_TYPE (lhs);
+ }
+
+ if (TREE_CODE (lhstype) == REFERENCE_TYPE
+ && modifycode != INIT_EXPR)
+ {
+ lhs = convert_from_reference (lhs);
+ olhstype = lhstype = TREE_TYPE (lhs);
+ }
+
/* If a binary op has been requested, combine the old LHS value with the RHS
producing the value we should actually store into the LHS. */
if (modifycode == INIT_EXPR)
{
- if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_HAS_CONSTRUCTOR (lhstype))
+ if (! IS_AGGR_TYPE (lhstype))
+ /* Do the default thing */;
+ else if (! TYPE_HAS_CONSTRUCTOR (lhstype))
+ {
+ cp_error ("`%T' has no constructors", lhstype);
+ return error_mark_node;
+ }
+ else if (TYPE_HAS_TRIVIAL_INIT_REF (lhstype)
+ && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
+ /* 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 (modifycode == NOP_EXPR)
{
- /* must deal with overloading of `operator=' here. */
- if (TREE_CODE (lhstype) == REFERENCE_TYPE)
- lhstype = TREE_TYPE (lhstype);
-#if 1
/* `operator=' is not an inheritable operator. */
- if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_HAS_ASSIGNMENT (lhstype))
+ if (! IS_AGGR_TYPE (lhstype))
+ /* Do the default thing */;
+ else if (! TYPE_HAS_ASSIGNMENT (lhstype))
{
- result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
- if (result == NULL_TREE)
- return error_mark_node;
- return result;
+ cp_error ("`%T' does not define operator=", lhstype);
+ return error_mark_node;
}
-#else
- /* Treat `operator=' as an inheritable operator. */
- if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_GETS_ASSIGNMENT (lhstype))
+ 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));
+
+ /* Do the default thing */;
+ }
+ else
{
- tree orig_lhstype = lhstype;
- while (! TYPE_HAS_ASSIGNMENT (lhstype))
- {
- int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (lhstype);
- tree basetype = NULL_TREE;
- for (i = 0; i < n_baseclasses; i++)
- if (TYPE_GETS_ASSIGNMENT (TYPE_BINFO_BASETYPE (lhstype, i)))
- {
- if (basetype != NULL_TREE)
- {
- message_2_types (error, "base classes `%s' and `%s' both have operator ='",
- basetype,
- TYPE_BINFO_BASETYPE (lhstype, i));
- return error_mark_node;
- }
- basetype = TYPE_BINFO_BASETYPE (lhstype, i);
- }
- lhstype = basetype;
- }
- if (orig_lhstype != lhstype)
- {
- lhs = build_indirect_ref (convert_pointer_to (lhstype,
- build_unary_op (ADDR_EXPR, lhs, 0)), NULL_PTR);
- if (lhs == error_mark_node)
- {
- cp_error ("conversion to private basetype `%T'", lhstype);
- return error_mark_node;
- }
- }
result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
lhs, rhs, make_node (NOP_EXPR));
if (result == NULL_TREE)
return error_mark_node;
return result;
}
-#endif
lhstype = olhstype;
}
else if (PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE))
if (build_default_binary_type_conversion (modifycode, &lhs_tmp, &rhs_tmp))
{
lhs = stabilize_reference (lhs_tmp);
- /* Forget is was ever anything else. */
+ /* Forget it was ever anything else. */
olhstype = lhstype = TREE_TYPE (lhs);
newrhs = build_binary_op (modifycode, lhs, rhs_tmp, 1);
}
else
- return error_mark_node;
+ {
+ cp_error ("no match for `%Q(%#T, %#T)'", modifycode,
+ TREE_TYPE (lhs), TREE_TYPE (rhs));
+ return error_mark_node;
+ }
}
else
{
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");
+
result = build_modify_expr (inner_lhs, NOP_EXPR,
convert (TREE_TYPE (inner_lhs),
convert (lhstype, newrhs)));
if (TREE_CODE (result) == ERROR_MARK)
return result;
- return convert_force (TREE_TYPE (lhs), result);
+ return convert (TREE_TYPE (lhs), result);
}
}
- if (TREE_CODE (lhs) == OFFSET_REF)
- {
- if (TREE_OPERAND (lhs, 0) == NULL_TREE)
- {
- /* Static class member? */
- tree member = TREE_OPERAND (lhs, 1);
- if (TREE_CODE (member) == VAR_DECL)
- lhs = member;
- else
- {
- compiler_error ("invalid static class member");
- return error_mark_node;
- }
- }
- else
- lhs = resolve_offset_ref (lhs);
- }
-
/* Now we have handled acceptable kinds of LHS that are not truly lvalues.
Reject anything strange now. */
&& (TREE_CODE (lhstype) == INTEGER_TYPE
|| TREE_CODE (lhstype) == REAL_TYPE
|| TREE_CODE (lhstype) == ENUMERAL_TYPE))
- lhstype = TREE_TYPE (get_unwidened (lhs, 0));
-
- /* check to see if there is an assignment to `this' */
- if (lhs == current_class_decl)
{
- if (DECL_NAME (current_function_decl) != NULL_TREE)
+ lhstype = TREE_TYPE (get_unwidened (lhs, 0));
+
+ /* If storing in a field that is in actuality a short or narrower
+ than one, we must store in the field in its actual type. */
+
+ if (lhstype != TREE_TYPE (lhs))
{
- /* ARM 18.3.3 and draft standard section C.11 say that assigning
- something to this is an anachronism. */
- if (pedantic)
- warning ("anachronistic assignment to `this' pointer");
- else if (flag_this_is_variable > 0
- && current_class_name != DECL_NAME (current_function_decl))
- warning ("assignment to `this' not in constructor or destructor");
+ lhs = copy_node (lhs);
+ TREE_TYPE (lhs) = lhstype;
}
+ }
+
+ /* check to see if there is an assignment to `this' */
+ if (lhs == current_class_ptr)
+ {
+ if (flag_this_is_variable > 0
+ && DECL_NAME (current_function_decl) != NULL_TREE
+ && (DECL_NAME (current_function_decl)
+ != constructor_name (current_class_type)))
+ warning ("assignment to `this' not in constructor or destructor");
current_function_just_assigned_this = 1;
}
if (TREE_SIDE_EFFECTS (newrhs))
newrhs = stabilize_reference (newrhs);
- /* C++: The semantics of C++ differ from those of C when an
- assignment of an aggregate is desired. Assignment in C++ is
- now defined as memberwise assignment of non-static members
- and base class objects. This rule applies recursively
- until a member of a built-in type is found.
-
- Also, we cannot do a bit-wise copy of aggregates which
- contain virtual function table pointers. Those
- pointer values must be preserved through the copy.
- However, this is handled in expand_expr, and not here.
- This is because much better code can be generated at
- that stage than this one. */
- if (TREE_CODE (lhstype) == RECORD_TYPE
- && ! TYPE_PTRMEMFUNC_P (lhstype)
- && (TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs))
- || (TREE_CODE (TREE_TYPE (newrhs)) == RECORD_TYPE
- && UNIQUELY_DERIVED_FROM_P (lhstype, TREE_TYPE (newrhs)))))
- {
- /* This was decided in finish_struct. */
- if (modifycode == INIT_EXPR)
- cp_error ("can't generate default copy constructor for `%T'", lhstype);
- else
- cp_error ("can't generate default assignment operator for `%T'",
- lhstype);
-#if 0
- /* This is now done by generating X(X&) and operator=(X&). */
- tree vbases = CLASSTYPE_VBASECLASSES (lhstype);
- tree lhs_addr = build_unary_op (ADDR_EXPR, lhs, 0);
- tree rhs_addr;
-
- /* Memberwise assignment would cause NEWRHS to be
- evaluated for every member that gets assigned.
- By wrapping side-effecting exprs in a SAVE_EXPR,
- NEWRHS will only be evaluated once. */
- if (IS_AGGR_TYPE (TREE_TYPE (newrhs))
- && TREE_SIDE_EFFECTS (newrhs)
- /* This are things we don't have to save. */
- && TREE_CODE (newrhs) != COND_EXPR
- && TREE_CODE (newrhs) != TARGET_EXPR
- && TREE_CODE (newrhs) != WITH_CLEANUP_EXPR)
- /* Call `break_out_cleanups' on NEWRHS in case there are cleanups.
- If NEWRHS is a CALL_EXPR that needs a cleanup, failure to do so
- will result in expand_expr expanding the call without knowing
- that it should run the cleanup. */
- newrhs = save_expr (break_out_cleanups (newrhs));
-
- if (TREE_CODE (newrhs) == COND_EXPR)
- rhs_addr = rationalize_conditional_expr (ADDR_EXPR, newrhs);
- else
- rhs_addr = build_unary_op (ADDR_EXPR, newrhs, 0);
-
- result = tree_cons (NULL_TREE,
- convert (build_reference_type (lhstype), lhs),
- NULL_TREE);
-
- if (! comptypes (TREE_TYPE (lhs_addr), TREE_TYPE (rhs_addr), 1))
- rhs_addr = convert_pointer_to (TREE_TYPE (TREE_TYPE (lhs_addr)), rhs_addr);
- {
- tree noncopied_parts = NULL_TREE;
-
- if (TYPE_NONCOPIED_PARTS (lhstype) != 0)
- noncopied_parts = init_noncopied_parts (lhs,
- TYPE_NONCOPIED_PARTS (lhstype));
- while (noncopied_parts != 0)
- {
- result = tree_cons (NULL_TREE,
- build_modify_expr (convert (ptr_type_node, TREE_VALUE (noncopied_parts)),
- NOP_EXPR,
- TREE_PURPOSE (noncopied_parts)),
- result);
- noncopied_parts = TREE_CHAIN (noncopied_parts);
- }
- }
- /* Once we have our hands on an address, we must change NEWRHS
- to work from there. Otherwise we can get multiple evaluations
- of NEWRHS. */
- if (TREE_CODE (newrhs) != SAVE_EXPR)
- newrhs = build_indirect_ref (rhs_addr, NULL_PTR);
-
- while (vbases)
- {
- tree elt_lhs = convert_pointer_to (vbases, lhs_addr);
- tree elt_rhs = convert_pointer_to (vbases, rhs_addr);
- result
- = tree_cons (NULL_TREE,
- build_modify_expr_1 (build_indirect_ref (elt_lhs, NULL_PTR),
- modifycode,
- build_indirect_ref (elt_rhs, NULL_PTR),
- TYPE_BINFO (lhstype)),
- result);
- if (TREE_VALUE (result) == error_mark_node)
- return error_mark_node;
- vbases = TREE_CHAIN (vbases);
- }
- result = tree_cons (NULL_TREE,
- build_modify_expr_1 (lhs,
- modifycode,
- newrhs,
- TYPE_BINFO (lhstype)),
- result);
- return build_compound_expr (result);
-#endif
- }
-
- /* If storing in a field that is in actuality a short or narrower than one,
- we must store in the field in its actual type. */
-
- if (lhstype != TREE_TYPE (lhs))
- {
- lhs = copy_node (lhs);
- TREE_TYPE (lhs) = lhstype;
- }
-
/* Convert new value to destination type. */
if (TREE_CODE (lhstype) == ARRAY_TYPE)
{
+ int from_array;
+
+ if (! comptypes (lhstype, TREE_TYPE (rhs), 0))
+ {
+ cp_error ("incompatible types in assignment of `%T' to `%T'",
+ TREE_TYPE (rhs), lhstype);
+ return error_mark_node;
+ }
+
/* Allow array assignment in compiler-generated code. */
- if ((pedantic || flag_ansi)
- && ! DECL_ARTIFICIAL (current_function_decl))
- pedwarn ("ANSI C++ forbids assignment between arrays");
+ if (pedantic && ! DECL_ARTIFICIAL (current_function_decl))
+ pedwarn ("ANSI C++ forbids assignment of arrays");
/* Have to wrap this in RTL_EXPR for two cases:
in base or member initialization and if we
/* As a matter of principle, `start_sequence' should do this. */
emit_note (0, -1);
+ from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
+ ? 1 + (modifycode != INIT_EXPR): 0;
expand_vec_init (lhs, lhs, array_type_nelts (lhstype), newrhs,
- 1 + (modifycode != INIT_EXPR));
+ from_array);
do_pending_stack_adjust ();
}
else
{
- if (IS_AGGR_TYPE (lhstype))
- {
- if (result = build_opfncall (MODIFY_EXPR,
- LOOKUP_NORMAL, lhs, newrhs,
- make_node (NOP_EXPR)))
- return result;
- }
/* Avoid warnings on enum bit fields. */
if (TREE_CODE (olhstype) == ENUMERAL_TYPE
&& TREE_CODE (lhstype) == INTEGER_TYPE)
{
newrhs = convert_for_assignment (olhstype, newrhs, "assignment",
NULL_TREE, 0);
- newrhs = convert_force (lhstype, newrhs);
+ newrhs = convert_force (lhstype, newrhs, 0);
}
else
newrhs = convert_for_assignment (lhstype, newrhs, "assignment",
- NULL_TREE, 0);
- if (flag_elide_constructors == 0
- && TREE_CODE (newrhs) == CALL_EXPR
- && TREE_ADDRESSABLE (lhstype))
- {
- /* Can't initialized directly from a CALL_EXPR, since
- we don't know about what doesn't alias what. */
-
- tree temp = get_temp_name (lhstype, 0);
- newrhs = build (COMPOUND_EXPR, lhstype,
- build_modify_expr (temp, INIT_EXPR, newrhs),
- temp);
- }
+ NULL_TREE, 0);
+ if (TREE_CODE (newrhs) == CALL_EXPR
+ && TYPE_NEEDS_CONSTRUCTING (lhstype))
+ newrhs = build_cplus_new (lhstype, newrhs);
+
+ /* Can't initialize directly from a TARGET_EXPR, since that would
+ cause the lhs to be constructed twice, and possibly result in
+ accidental self-initialization. So we force the TARGET_EXPR to be
+ expanded without a target. */
+ if (TREE_CODE (newrhs) == TARGET_EXPR)
+ newrhs = build (COMPOUND_EXPR, TREE_TYPE (newrhs), newrhs,
+ TREE_OPERAND (newrhs, 0));
}
if (TREE_CODE (newrhs) == ERROR_MARK)
TREE_OPERAND (newrhs, 2))));
}
}
- else if (modifycode != INIT_EXPR && TREE_CODE (newrhs) == WITH_CLEANUP_EXPR)
- {
- tree cleanup = TREE_OPERAND (newrhs, 2);
- tree slot;
-
- /* Finish up by running cleanups and having the "value" of the lhs. */
- tree exprlist = tree_cons (NULL_TREE, cleanup,
- build_tree_list (NULL_TREE, lhs));
- newrhs = TREE_OPERAND (newrhs, 0);
- if (TREE_CODE (newrhs) == TARGET_EXPR)
- slot = TREE_OPERAND (newrhs, 0);
- else if (TREE_CODE (newrhs) == ADDR_EXPR)
- {
- /* Bad but legal. */
- slot = newrhs;
- warning ("address taken of temporary object");
- }
- else
- my_friendly_abort (118);
-
- /* Copy the value computed in SLOT into LHS. */
- exprlist = tree_cons (NULL_TREE,
- build_modify_expr (lhs, modifycode, slot),
- exprlist);
- /* Evaluate the expression that needs CLEANUP. This will
- compute the value into SLOT. */
- exprlist = tree_cons (NULL_TREE, newrhs, exprlist);
- result = convert (lhstype, build_compound_expr (exprlist));
- }
else
result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
lhstype, lhs, newrhs);
+
TREE_SIDE_EFFECTS (result) = 1;
/* If we got the LHS in a different type for storing in,
for enum bit fields. */
if (TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
&& TREE_CODE (olhstype) == ENUMERAL_TYPE)
- return convert_force (olhstype, result);
+ {
+ result = build (COMPOUND_EXPR, olhstype, result, olhs);
+ TREE_NO_UNUSED_WARNING (result) = 1;
+ return result;
+ }
return convert_for_assignment (olhstype, result, "assignment",
NULL_TREE, 0);
}
+tree
+build_x_modify_expr (lhs, modifycode, rhs)
+ tree lhs;
+ enum tree_code modifycode;
+ tree rhs;
+{
+ if (current_template_parms)
+ return build_min_nt (MODOP_EXPR, lhs,
+ build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
+
+ if (modifycode != NOP_EXPR)
+ {
+ tree rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
+ make_node (modifycode));
+ if (rval)
+ return rval;
+ }
+ return build_modify_expr (lhs, modifycode, rhs);
+}
/* Return 0 if EXP is not a valid lvalue in this language
even though `lvalue_or_else' would accept it. */
return 1;
}
\f
-/* Get differnce in deltas for different pointer to member function
- types. Return inetger_zero_node, if FROM cannot be converted to a
+/* 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)
}
if (binfo == 0)
{
- error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
+ 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))
{
- warning ("pointer to member conversion to virtual base class will only work if your very careful");
+ 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");
}
- return fold (size_binop (MINUS_EXPR,
- integer_zero_node,
- BINFO_OFFSET (binfo)));
+ delta = BINFO_OFFSET (binfo);
+ delta = convert (ptrdiff_type_node, delta);
+
+ return build_binary_op (MINUS_EXPR,
+ integer_zero_node,
+ delta, 1);
}
if (TREE_VIA_VIRTUAL (binfo))
{
- warning ("pointer to member conversion from virtual base class will only work if your very careful");
+ warning ("pointer to member conversion from virtual base class will only work if you are very careful");
}
return BINFO_OFFSET (binfo);
}
tree npfn;
tree u;
- /* Handle multiple conversions of pointer to member fucntions. */
+ /* Handle multiple conversions of pointer to member functions. */
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
{
tree ndelta, ndelta2, nindex;
/* Is is already the right type? */
-#if 0
- /* Sorry, can't do this, the backend is too stupid. */
- if (TYPE_METHOD_BASETYPE (TREE_TYPE (type))
- == TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))))
- {
- if (type != TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
- {
- npfn = build1 (NOP_EXPR, TYPE_GET_PTRMEMFUNC_TYPE (type), pfn);
- TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
- }
- return pfn;
- }
-#else
if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
return pfn;
-#endif
if (TREE_CODE (pfn) != CONSTRUCTOR)
{
tree e1, e2, e3;
- ndelta = convert (sizetype, build_component_ref (pfn, delta_identifier, 0, 0));
- ndelta2 = convert (sizetype, DELTA2_FROM_PTRMEMFUNC (pfn));
- index = build_component_ref (pfn, index_identifier, 0, 0);
+ ndelta = convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0));
+ ndelta2 = convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
+ index = build_component_ref (pfn, index_identifier, NULL_TREE, 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 = fold (size_binop (PLUS_EXPR, delta, ndelta));
- delta2 = fold (size_binop (PLUS_EXPR, ndelta2, delta2));
- e1 = fold (build (GT_EXPR, integer_type_node, index, integer_zero_node));
+ 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));
- 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))));
+ 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, index,
+ tree_cons (NULL_TREE, u, NULL_TREE))));
e2 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
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))));
+ u = build_nt (CONSTRUCTOR, NULL_TREE, tree_cons (pfn_identifier, npfn, NULL_TREE));
+ u = build_nt (CONSTRUCTOR, NULL_TREE, 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);
}
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, NULL_TREE, tree_cons (pfn_identifier, pfn, NULL_TREE));
+ u = build_nt (CONSTRUCTOR, NULL_TREE, 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 varible nonnull pointer to member functions not supported");
+ sorry ("value casting of variable nonnull pointer to member functions not supported");
return error_mark_node;
}
}
/* Handle null pointer to member function conversions. */
if (integer_zerop (pfn))
{
- pfn = build_c_cast (type, integer_zero_node);
- 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))));
+ pfn = build_c_cast (type, integer_zero_node, 0);
+ u = build_nt (CONSTRUCTOR, NULL_TREE, tree_cons (pfn_identifier, pfn, NULL_TREE));
+ u = build_nt (CONSTRUCTOR, NULL_TREE, 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);
}
+ 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;
+ pfn = build_addr_func (pfn);
+ }
+
/* 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 = fold (size_binop (PLUS_EXPR, delta2, delta));
+ 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");
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));
+ u = build_nt (CONSTRUCTOR, NULL_TREE, tree_cons (delta2_identifier, delta2, NULL_TREE));
}
else
{
- index = fold (size_binop (MINUS_EXPR, integer_zero_node, integer_one_node));
+ index = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
- npfn = build1 (NOP_EXPR, type, pfn);
- TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+ 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 (pfn_identifier, npfn, NULL_TREE));
+ u = build_nt (CONSTRUCTOR, NULL_TREE, 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))));
+ u = build_nt (CONSTRUCTOR, NULL_TREE, 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 error_mark_node;
}
/* Arithmetic types all interconvert. */
- if ((codel == INTEGER_TYPE || codel == REAL_TYPE)
- && (coder == INTEGER_TYPE || coder == REAL_TYPE))
+ if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE)
+ && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE))
{
/* But we should warn if assigning REAL_TYPE to INTEGER_TYPE. */
if (coder == REAL_TYPE && codel == INTEGER_TYPE)
}
/* And we should warn if assigning a negative value to
an unsigned variable. */
- else if (TREE_UNSIGNED (type))
+ else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE)
{
if (TREE_CODE (rhs) == INTEGER_CST
&& TREE_NEGATED_INT (rhs))
}
/* Conversions involving enums. */
else if ((codel == ENUMERAL_TYPE
- && (coder == ENUMERAL_TYPE || coder == INTEGER_TYPE || coder == REAL_TYPE))
+ && (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE))
|| (coder == ENUMERAL_TYPE
- && (codel == ENUMERAL_TYPE || codel == INTEGER_TYPE || codel == REAL_TYPE)))
+ && (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE)))
{
- return convert (type, rhs);
+ return cp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
}
/* Conversions among pointers */
else if (codel == POINTER_TYPE
{
register tree ttl = TREE_TYPE (type);
register tree ttr;
+ int ctt = 0;
if (coder == RECORD_TYPE)
{
Meanwhile, the lhs target must have all the qualifiers of the rhs. */
else if (TYPE_MAIN_VARIANT (ttl) == void_type_node
|| TYPE_MAIN_VARIANT (ttr) == void_type_node
- || comp_target_types (type, rhstype, 1)
+ || (ctt = comp_target_types (type, rhstype, 1))
|| (unsigned_type (TYPE_MAIN_VARIANT (ttl))
== unsigned_type (TYPE_MAIN_VARIANT (ttr))))
{
if (TYPE_MAIN_VARIANT (ttl) == void_type_node
&& TREE_CODE (ttr) == OFFSET_TYPE)
{
- error ("no standard conversion from pointer to member to `void *'");
+ cp_error ("no standard conversion from `%T' to `void *'", ttr);
return error_mark_node;
}
+ if (ctt < 0)
+ 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)
- if (coder == RECORD_TYPE)
- pedwarn ("implicit conversion of signature pointer to type `%s'",
- type_as_string (type, 0));
- else
- pedwarn ("ANSI C++ forbids implicit conversion from `void *' in %s",
- errtype);
+ {
+ if (coder == RECORD_TYPE)
+ cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
+ type);
+ else
+ pedwarn ("ANSI C++ forbids implicit conversion from `void *' in %s",
+ errtype);
+ }
/* Const and volatile mean something different for function types,
so the usual warnings are not appropriate. */
else if ((TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttr) != METHOD_TYPE)
sorry ("%s between pointer to members converting across virtual baseclasses", errtype);
return error_mark_node;
}
- if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
+ else if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
{
if (fndecl)
cp_pedwarn ("passing `%T' as argument %P of `%D' discards const",
cp_pedwarn ("%s to `%T' from `%T' discards const",
errtype, type, rhstype);
}
- if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
+ else if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
{
if (fndecl)
cp_pedwarn ("passing `%T' as argument %P of `%D' discards volatile",
cp_pedwarn ("%s to `%T' from `%T' discards volatile",
errtype, type, rhstype);
}
+ else if (TREE_CODE (ttl) == TREE_CODE (ttr)
+ && ! comp_target_types (type, rhstype, 1))
+ {
+ if (fndecl)
+ cp_pedwarn ("passing `%T' as argument %P of `%D' changes signedness",
+ rhstype, parmnum, fndecl);
+ else
+ cp_pedwarn ("%s to `%T' from `%T' changes signedness",
+ errtype, type, rhstype);
+ }
}
}
else if (TREE_CODE (ttr) == OFFSET_TYPE
some type instantiation if that resolves the
ambiguity of (X Y::*) and (X *). */
- if (current_class_decl)
+ if (current_class_ptr)
{
if (TREE_CODE (rhs) == INTEGER_CST)
{
rhs = build (PLUS_EXPR, build_pointer_type (TREE_TYPE (ttr)),
- current_class_decl, rhs);
+ current_class_ptr, rhs);
return convert_for_assignment (type, rhs,
errtype, fndecl, parmnum);
}
}
else
{
- int const_parity = TYPE_READONLY (type) ^ TYPE_READONLY (rhstype);
- int volatile_parity = TYPE_VOLATILE (type) ^ TYPE_VOLATILE (rhstype);
+ int add_quals = 0, const_parity = 0, volatile_parity = 0;
+ int left_const = 1;
int unsigned_parity;
int nptrs = 0;
- while (TREE_CODE (ttl) == POINTER_TYPE
- && TREE_CODE (ttr) == POINTER_TYPE)
+ /* This code is basically a duplicate of comp_ptr_ttypes_real. */
+ for (; ; ttl = TREE_TYPE (ttl), ttr = TREE_TYPE (ttr))
{
nptrs -= 1;
- const_parity |= TYPE_READONLY (ttl) ^ TYPE_READONLY (ttr);
- volatile_parity |= TYPE_VOLATILE (ttl) ^ TYPE_VOLATILE (ttr);
- ttl = TREE_TYPE (ttl);
- ttr = TREE_TYPE (ttr);
+ const_parity |= (TYPE_READONLY (ttl) < TYPE_READONLY (ttr));
+ volatile_parity |= (TYPE_VOLATILE (ttl) < TYPE_VOLATILE (ttr));
+
+ if (! left_const
+ && (TYPE_READONLY (ttl) > TYPE_READONLY (ttr)
+ || TYPE_VOLATILE (ttl) > TYPE_VOLATILE (ttr)))
+ add_quals = 1;
+ left_const &= TYPE_READONLY (ttl);
+
+ if (TREE_CODE (ttl) != POINTER_TYPE
+ || TREE_CODE (ttr) != POINTER_TYPE)
+ break;
}
unsigned_parity = TREE_UNSIGNED (ttl) - TREE_UNSIGNED (ttr);
if (unsigned_parity)
- if (TREE_UNSIGNED (ttl))
- ttr = unsigned_type (ttr);
- else
- ttl = unsigned_type (ttl);
+ {
+ if (TREE_UNSIGNED (ttl))
+ ttr = unsigned_type (ttr);
+ else
+ ttl = unsigned_type (ttl);
+ }
- if (comp_target_types (ttl, ttr, nptrs))
+ if (comp_target_types (ttl, ttr, nptrs) > 0)
{
+ if (add_quals)
+ {
+ if (fndecl)
+ cp_pedwarn ("passing `%T' as argument %P of `%D' adds cv-quals without intervening `const'",
+ rhstype, parmnum, fndecl);
+ else
+ cp_pedwarn ("%s to `%T' from `%T' adds cv-quals without intervening `const'",
+ errtype, type, rhstype);
+ }
if (const_parity)
{
if (fndecl)
- cp_warning ("passing `%T' as argument %P of `%D' discards const",
+ cp_pedwarn ("passing `%T' as argument %P of `%D' discards const",
rhstype, parmnum, fndecl);
else
- cp_warning ("%s to `%T' from `%T' discards const",
+ cp_pedwarn ("%s to `%T' from `%T' discards const",
errtype, type, rhstype);
}
if (volatile_parity)
{
if (fndecl)
- cp_warning ("passing `%T' as argument %P of `%D' discards volatile",
+ cp_pedwarn ("passing `%T' as argument %P of `%D' discards volatile",
rhstype, parmnum, fndecl);
else
- cp_warning ("%s to `%T' from `%T' discards volatile",
+ cp_pedwarn ("%s to `%T' from `%T' discards volatile",
errtype, type, rhstype);
}
if (unsigned_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)
&& (coder == POINTER_TYPE
|| (coder == RECORD_TYPE
&& (IS_SIGNATURE_POINTER (rhstype)
+ || TYPE_PTRMEMFUNC_FLAG (rhstype)
|| IS_SIGNATURE_REFERENCE (rhstype)))))
{
if (fndecl)
errtype, type, rhstype);
return convert (type, rhs);
}
+ else if (codel == BOOLEAN_TYPE
+ && (coder == POINTER_TYPE
+ || (coder == RECORD_TYPE
+ && (IS_SIGNATURE_POINTER (rhstype)
+ || TYPE_PTRMEMFUNC_FLAG (rhstype)
+ || IS_SIGNATURE_REFERENCE (rhstype)))))
+ return convert (type, rhs);
/* C++ */
- else if (((coder == POINTER_TYPE && TREE_CODE (rhs) == ADDR_EXPR
- && TREE_CODE (rhstype) == POINTER_TYPE
+ else if (((coder == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (rhstype)) == METHOD_TYPE)
|| integer_zerop (rhs)
- || TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
+ || TYPE_PTRMEMFUNC_P (rhstype))
&& TYPE_PTRMEMFUNC_P (type))
{
+ tree ttl = TYPE_PTRMEMFUNC_FN_TYPE (type);
+ tree ttr = (TREE_CODE (rhstype) == POINTER_TYPE ? rhstype
+ : TYPE_PTRMEMFUNC_FN_TYPE (type));
+ int ctt = comp_target_types (ttl, ttr, 1);
+
+ if (ctt < 0)
+ cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
+ ttr, ttl);
+ else if (ctt == 0)
+ cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr);
+
/* compatible pointer to member functions. */
- return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), rhs, 0);
+ return build_ptrmemfunc (ttl, rhs, 0);
}
else if (codel == ERROR_MARK || coder == ERROR_MARK)
return error_mark_node;
`convert_for_initialization'. They should otherwise be
bashed before coming here. */
else if (codel == REFERENCE_TYPE)
- /* Force an abort. */
- my_friendly_assert (codel != REFERENCE_TYPE, 317);
+ my_friendly_abort (317);
else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (rhs)))
{
tree nrhs = build1 (NOP_EXPR, type, rhs);
latter (X(X&)).
If using constructor make sure no conversion operator exists, if one does
- exist, an ambiguity exists. */
+ 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;
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
Strip such NOP_EXPRs, since RHS is used in non-lvalue context. */
if (TREE_CODE (rhs) == NOP_EXPR
- && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0)))
+ && TREE_TYPE (rhs) == TREE_TYPE (TREE_OPERAND (rhs, 0))
+ && codel != REFERENCE_TYPE)
rhs = TREE_OPERAND (rhs, 0);
if (rhs == error_mark_node
rhs = resolve_offset_ref (rhs);
if (rhs == error_mark_node)
return error_mark_node;
- rhstype = TREE_TYPE (rhs);
- coder = TREE_CODE (rhstype);
}
+ if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
+ rhs = convert_from_reference (rhs);
+
if ((TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
- && TREE_CODE (type) != ARRAY_TYPE && TREE_CODE (type) != REFERENCE_TYPE)
+ && TREE_CODE (type) != ARRAY_TYPE
+ && (TREE_CODE (type) != REFERENCE_TYPE
+ || TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))
|| TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
rhs = default_conversion (rhs);
if (coder == ERROR_MARK)
return error_mark_node;
-#if 0
- /* This is *not* the quick way out! It is the way to disaster. */
- if (type == rhstype)
- goto converted;
-#endif
-
/* We accept references to incomplete types, so we can
return here before checking if RHS is of complete type. */
if (codel == REFERENCE_TYPE)
- return convert_to_reference (type, rhs, CONV_IMPLICIT, flags,
- exp ? exp : error_mark_node);
+ {
+ /* This should eventually happen in convert_arguments. */
+ extern int warningcount, errorcount;
+ int savew, savee;
+
+ if (fndecl)
+ savew = warningcount, savee = errorcount;
+ rhs = convert_to_reference (type, rhs, CONV_IMPLICIT, flags,
+ exp ? exp : error_mark_node);
+ if (fndecl)
+ {
+ if (warningcount > savew)
+ cp_warning_at ("in passing argument %P of `%+D'", parmnum, fndecl);
+ else if (errorcount > savee)
+ cp_error_at ("in passing argument %P of `%+D'", parmnum, fndecl);
+ }
+ return rhs;
+ }
rhs = require_complete_type (rhs);
if (rhs == error_mark_node)
&& (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
return build_signature_pointer_constructor (type, rhs);
- if (IS_AGGR_TYPE (type) && TYPE_NEEDS_CONSTRUCTING (type))
+ if (IS_AGGR_TYPE (type)
+ && (TYPE_NEEDS_CONSTRUCTING (type) || TREE_HAS_CONSTRUCTOR (rhs)))
{
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
{
cleanups if it is used. */
if (TREE_CODE (rhs) == CALL_EXPR)
{
- rhs = build_cplus_new (type, rhs, 0);
+ rhs = build_cplus_new (type, rhs);
return rhs;
}
/* Handle the case of default parameter initialization and
initialization of static variables. */
+ else if (TREE_CODE (rhs) == TARGET_EXPR)
+ return rhs;
else if (TREE_CODE (rhs) == INDIRECT_REF && TREE_HAS_CONSTRUCTOR (rhs))
{
my_friendly_assert (TREE_CODE (TREE_OPERAND (rhs, 0)) == CALL_EXPR, 318);
= build_unary_op (ADDR_EXPR, exp, 0);
}
else
- rhs = build_cplus_new (type, TREE_OPERAND (rhs, 0), 0);
+ rhs = build_cplus_new (type, TREE_OPERAND (rhs, 0));
return rhs;
}
+ else if (TYPE_HAS_TRIVIAL_INIT_REF (type))
+ return rhs;
}
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)
|| (IS_AGGR_TYPE (rhstype) && UNIQUELY_DERIVED_FROM_P (type, rhstype)))
{
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);
if (exp == 0)
{
- exp = build_cplus_new (type, init, 0);
+ exp = build_cplus_new (type, init);
return exp;
}
return rhs;
}
- return convert (type, rhs);
+ return cp_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);
- register int use_temp = 0;
int returns_value = 1;
if (TREE_THIS_VOLATILE (current_function_decl))
return;
}
+ if (current_template_parms)
+ {
+ add_tree (build_min_nt (RETURN_STMT, retval));
+ return;
+ }
+
if (retval == NULL_TREE)
{
/* A non-named return value does not count. */
}
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;
+ retval = current_class_ptr;
}
if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
{
whats_returned = TREE_OPERAND (whats_returned, 0);
while (TREE_CODE (whats_returned) == NEW_EXPR
- || TREE_CODE (whats_returned) == TARGET_EXPR
- || TREE_CODE (whats_returned) == WITH_CLEANUP_EXPR)
- /* Get the target. */
- whats_returned = TREE_OPERAND (whats_returned, 0);
+ || TREE_CODE (whats_returned) == TARGET_EXPR)
+ {
+ /* Get the target. */
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ warning ("returning reference to temporary");
+ }
}
if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned))
if (TEMP_NAME_P (DECL_NAME (whats_returned)))
warning ("reference to non-lvalue returned");
else if (! TREE_STATIC (whats_returned)
- && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned)))
+ && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
+ && !TREE_PUBLIC (whats_returned))
cp_warning_at ("reference to local variable `%D' returned", whats_returned);
}
}
if (TREE_CODE (whats_returned) == VAR_DECL
&& DECL_NAME (whats_returned)
&& IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
- && !TREE_STATIC (whats_returned))
+ && !TREE_STATIC (whats_returned)
+ && !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. */
if (TYPE_MODE (valtype) != BLKmode
&& any_pending_cleanups (1))
- {
- retval = get_temp_regvar (valtype, retval);
- use_temp = obey_regdecls;
- }
+ retval = get_temp_regvar (valtype, retval);
}
- else if (IS_AGGR_TYPE (valtype) && TYPE_NEEDS_CONSTRUCTING (valtype))
+ else if (IS_AGGR_TYPE (valtype) && current_function_returns_struct)
{
- /* Throw away the cleanup that `build_functional_cast' gave us. */
- if (TREE_CODE (retval) == WITH_CLEANUP_EXPR
- && TREE_CODE (TREE_OPERAND (retval, 0)) == TARGET_EXPR)
- retval = TREE_OPERAND (retval, 0);
- expand_aggr_init (result, retval, 0);
+ expand_aggr_init (result, retval, 0, LOOKUP_ONLYCONVERTING);
+ expand_cleanups_to (NULL_TREE);
DECL_INITIAL (result) = NULL_TREE;
retval = 0;
}
&& any_pending_cleanups (1))
{
retval = get_temp_regvar (valtype, retval);
- use_temp = obey_regdecls;
+ expand_cleanups_to (NULL_TREE);
result = 0;
}
else
{
/* Everything's great--RETVAL is in RESULT. */
if (original_result_rtx)
- store_expr (result, original_result_rtx, 0);
+ {
+ 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
/* 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);
-
- use_variable (DECL_RTL (result));
- if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
- expand_goto (ctor_label);
- else
- expand_null_return ();
}
else
{
}
else if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
{
- /* Here RETVAL is CURRENT_CLASS_DECL, so there's nothing to do. */
+ /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do. */
expand_goto (ctor_label);
}
else if (retval)
}
current_function_returns_value = returns_value;
- if (original_result_rtx)
- use_variable (original_result_rtx);
- if (use_temp)
- use_variable (DECL_RTL (DECL_RESULT (current_function_decl)));
/* One way to clear out cleanups that EXPR might
generate. Note that this code will really be
exp = index;
}
- expand_start_case (1, exp, type, "switch statement");
+ expand_start_case
+ (1, fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp)),
+ type, "switch statement");
return exp;
}
+
+/* CONSTP remembers whether or not all the intervening pointers in the `to'
+ type have been const. */
+int
+comp_ptr_ttypes_real (to, from, constp)
+ tree to, from;
+ int constp;
+{
+ for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+ {
+ if (TREE_CODE (to) != TREE_CODE (from))
+ return 0;
+
+ /* 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 comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1);
+ }
+}
+
+/* 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);
+}