/* Build expressions with type checking for C++ compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
static bool comp_array_types (tree, tree, bool);
static tree common_base_type (tree, tree);
static tree pointer_diff (tree, tree, tree);
-static tree get_delta_difference (tree, tree, int);
+static tree get_delta_difference (tree, tree, bool, bool);
static void casts_away_constness_r (tree *, tree *);
static bool casts_away_constness (tree, tree);
static void maybe_warn_about_returning_address_of_local (tree);
static tree lookup_destructor (tree, tree, tree);
-
-/* Return the target type of TYPE, which means return T for:
- T*, T&, T[], T (...), and otherwise, just T. */
-
-tree
-target_type (tree type)
-{
- type = non_reference (type);
- while (TREE_CODE (type) == POINTER_TYPE
- || TREE_CODE (type) == ARRAY_TYPE
- || TREE_CODE (type) == FUNCTION_TYPE
- || TREE_CODE (type) == METHOD_TYPE
- || TYPE_PTRMEM_P (type))
- type = TREE_TYPE (type);
- return type;
-}
+static tree convert_arguments (tree, tree, tree, int);
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.)
}
/* Like complete_type, but issue an error if the TYPE cannot be completed.
- VALUE is used for informative diagnostics. DIAG_TYPE indicates the type
- of diagnostic: 0 for an error, 1 for a warning, 2 for a pedwarn.
+ VALUE is used for informative diagnostics.
Returns NULL_TREE if the type cannot be made complete. */
tree
-complete_type_or_diagnostic (tree type, tree value, int diag_type)
+complete_type_or_else (tree type, tree value)
{
type = complete_type (type);
if (type == error_mark_node)
return NULL_TREE;
else if (!COMPLETE_TYPE_P (type))
{
- cxx_incomplete_type_diagnostic (value, type, diag_type);
+ cxx_incomplete_type_diagnostic (value, type, 0);
return NULL_TREE;
}
else
As an optimization, free the space we allocate if the parameter
lists are already common. */
-tree
+static tree
commonparms (tree p1, tree p2)
{
tree oldargs = p1, newargs, n;
return build_type_attribute_variant (result_type, attributes);
}
+ if (c_dialect_objc () && TREE_CODE (t1) == POINTER_TYPE
+ && TREE_CODE (t2) == POINTER_TYPE)
+ {
+ if (objc_compare_types (t1, t2, -3, NULL_TREE))
+ return t1;
+ }
+
/* [expr.eq] permits the application of a pointer conversion to
bring the pointers to a common type. */
if (TREE_CODE (t1) == POINTER_TYPE && TREE_CODE (t2) == POINTER_TYPE
bool
comptypes (tree t1, tree t2, int strict)
{
- int retval;
-
if (t1 == t2)
return true;
&& TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return true;
- if (!(*targetm.comp_type_attributes) (t1, t2))
- return false;
-
+ /* Compare the types. Break out if they could be the same. */
switch (TREE_CODE (t1))
{
case TEMPLATE_TEMPLATE_PARM:
DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2))))
return false;
if (TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM)
- return true;
+ break;
/* Don't check inheritance. */
strict = COMPARE_STRICT;
/* Fall through. */
&& (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
|| TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM)
&& comp_template_args (TYPE_TI_ARGS (t1), TYPE_TI_ARGS (t2)))
- return true;
+ break;
if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
- return true;
+ break;
else if ((strict & COMPARE_DERIVED) && DERIVED_FROM_P (t2, t1))
- return true;
+ break;
- /* We may be dealing with Objective-C instances... */
- if (TREE_CODE (t1) == RECORD_TYPE
- && (retval = objc_comptypes (t1, t2, 0) >= 0))
- return retval;
- /* ...but fall through if we are not. */
-
return false;
case OFFSET_TYPE:
if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2),
strict & ~COMPARE_REDECLARATION))
return false;
- /* Fall through. */
+ if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
+ break;
case POINTER_TYPE:
case REFERENCE_TYPE:
- return same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+ if (TYPE_MODE (t1) != TYPE_MODE (t2)
+ || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)
+ || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
+ break;
case METHOD_TYPE:
case FUNCTION_TYPE:
if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
return false;
- return compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2));
+ if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)))
+ return false;
+ break;
case ARRAY_TYPE:
/* Target types must match incl. qualifiers. */
- return comp_array_types (t1, t2, !!(strict & COMPARE_REDECLARATION));
+ if (!comp_array_types (t1, t2, !!(strict & COMPARE_REDECLARATION)))
+ return false;
+ break;
case TEMPLATE_TYPE_PARM:
- return (TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2)
- && TEMPLATE_TYPE_LEVEL (t1) == TEMPLATE_TYPE_LEVEL (t2));
+ if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
+ || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+ return false;
+ break;
case TYPENAME_TYPE:
if (!cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1),
TYPENAME_TYPE_FULLNAME (t2)))
return false;
- return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
+ if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
+ return false;
+ break;
case UNBOUND_CLASS_TEMPLATE:
if (!cp_tree_equal (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2)))
return false;
- return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
+ if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
+ return false;
+ break;
case COMPLEX_TYPE:
- return same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+ if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
+ break;
case VECTOR_TYPE:
- return TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
- && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+ if (TYPE_VECTOR_SUBPARTS (t1) != TYPE_VECTOR_SUBPARTS (t2)
+ || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
break;
default:
- break;
+ return false;
}
- return false;
+
+ /* If we get here, we know that from a target independent POV the
+ types are the same. Make sure the target attributes are also
+ the same. */
+ return targetm.comp_type_attributes (t1, t2);
}
/* Returns 1 if TYPE1 is at least as qualified as TYPE2. */
return (q1 & q2) == q2;
}
-/* Returns 1 if TYPE1 is more qualified than TYPE2. */
-
-bool
-more_qualified_p (tree type1, tree type2)
-{
- int q1 = cp_type_quals (type1);
- int q2 = cp_type_quals (type2);
-
- return q1 != q2 && (q1 & q2) == q2;
-}
-
/* Returns 1 if TYPE1 is more cv-qualified than TYPE2, -1 if TYPE2 is
more cv-qualified that TYPE1, and 0 otherwise. */
if (type == error_mark_node)
return error_mark_node;
- if (processing_template_decl)
+ if (dependent_type_p (type))
{
value = build_min (op, size_type_node, type);
TREE_READONLY (value) = 1;
value = size_one_node;
}
else
- value = c_sizeof_or_alignof_type (complete_type (type), op, complain);
+ value = c_sizeof_or_alignof_type (complete_type (type),
+ op == SIZEOF_EXPR,
+ complain);
return value;
}
type = TREE_TYPE (exp);
code = TREE_CODE (type);
- if (code == REFERENCE_TYPE)
- {
- exp = convert_from_reference (exp);
- type = TREE_TYPE (exp);
- code = TREE_CODE (type);
- }
-
if (type == error_mark_node)
return error_mark_node;
cxx_incomplete_type_error (exp, TREE_TYPE (exp));
return error_mark_node;
}
-
- /* Constants can be used directly unless they're not loadable. */
- if (TREE_CODE (exp) == CONST_DECL)
- exp = DECL_INITIAL (exp);
- /* Replace a nonvolatile const static variable with its value. We
- don't do this for arrays, though; we want the address of the
- first element of the array, not the address of the first element
- of its initializing constant. */
- else if (code != ARRAY_TYPE)
- {
- exp = decl_constant_value (exp);
- type = TREE_TYPE (exp);
- }
+ exp = integral_constant_value (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. */
/* This warning is not very useful, as it complains about printf. */
if (warn && warn_write_strings)
- warning ("deprecated conversion from string constant to %qT'", totype);
+ warning (0, "deprecated conversion from string constant to %qT'", totype);
return 1;
}
if (object == error_mark_node || member == error_mark_node)
return error_mark_node;
- if (TREE_CODE (member) == PSEUDO_DTOR_EXPR)
- return member;
-
gcc_assert (DECL_P (member) || BASELINK_P (member));
/* [expr.ref]
&& !DECL_FIELD_IS_BASE (member)
&& !skip_evaluation)
{
- warning ("invalid access to non-static data member %qD of NULL object",
+ warning (0, "invalid access to non-static data member %qD of NULL object",
member);
- warning ("(perhaps the %<offsetof%> macro was used incorrectly)");
+ warning (0, "(perhaps the %<offsetof%> macro was used incorrectly)");
}
/* If MEMBER is from an anonymous aggregate, we have converted
expression itself. */
if (type_quals & TYPE_QUAL_CONST)
TREE_READONLY (result) = 1;
- else if (type_quals & TYPE_QUAL_VOLATILE)
+ if (type_quals & TYPE_QUAL_VOLATILE)
TREE_THIS_VOLATILE (result) = 1;
}
else if (BASELINK_P (member))
TYPE_MAIN_VARIANT (object_type), dtor_type);
return error_mark_node;
}
- if (!TYPE_HAS_DESTRUCTOR (dtor_type))
- return build3 (PSEUDO_DTOR_EXPR, void_type_node, object, scope,
- dtor_type);
expr = lookup_member (dtor_type, complete_dtor_identifier,
/*protect=*/1, /*want_type=*/false);
expr = (adjust_result_of_qualified_name_lookup
if (object == error_mark_node || name == error_mark_node)
return error_mark_node;
+ /* If OBJECT is an ObjC class instance, we must obey ObjC access rules. */
+ if (!objc_is_public (object, name))
+ return error_mark_node;
+
object_type = TREE_TYPE (object);
if (processing_template_decl)
object = build_non_dependent_expr (object);
}
- if (TREE_CODE (object_type) == REFERENCE_TYPE)
- {
- object = convert_from_reference (object);
- object_type = TREE_TYPE (object);
- }
-
/* [expr.ref]
The type of the first expression shall be "class object" (of a
/*want_type=*/false);
member_type = cp_build_qualified_type (TREE_TYPE (member),
cp_type_quals (ptrmem_type));
- return fold (build3 (COMPONENT_REF, member_type,
- ptrmem, member, NULL_TREE));
+ return fold_build3 (COMPONENT_REF, member_type,
+ ptrmem, member, NULL_TREE);
}
/* Given an expression PTR for a pointer, return an expression
? ptr : decay_conversion (ptr));
type = TREE_TYPE (pointer);
- if (TYPE_PTR_P (type) || TREE_CODE (type) == REFERENCE_TYPE)
+ if (POINTER_TYPE_P (type))
{
/* [expr.unary.op]
must have done so deliberately. */
if (warn_char_subscripts
&& TYPE_MAIN_VARIANT (TREE_TYPE (idx)) == char_type_node)
- warning ("array subscript has type %<char%>");
+ warning (0, "array subscript has type %<char%>");
if (!INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (idx)))
{
/* Apply integral promotions *after* noticing character types.
(It is unclear why we do these promotions -- the standard
- does not say that we should. In fact, the natual thing would
+ does not say that we should. In fact, the natural thing would
seem to be to convert IDX to ptrdiff_t; we're performing
pointer arithmetic.) */
idx = perform_integral_promotions (idx);
while (TREE_CODE (foo) == COMPONENT_REF)
foo = TREE_OPERAND (foo, 0);
if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo))
- warning ("subscripting array declared %<register%>");
+ warning (0, "subscripting array declared %<register%>");
}
type = TREE_TYPE (TREE_TYPE (array));
function = save_expr (function);
/* Start by extracting all the information from the PMF itself. */
- e3 = PFN_FROM_PTRMEMFUNC (function);
+ e3 = pfn_from_ptrmemfunc (function);
delta = build_ptrmemfunc_access_expr (function, delta_identifier);
idx = build1 (NOP_EXPR, vtable_index_type, e3);
switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
gcc_unreachable ();
}
- /* Convert down to the right base before using the instance. First
- use the type... */
+ /* Convert down to the right base before using the instance. A
+ special case is that in a pointer to member of class C, C may
+ be incomplete. In that case, the function will of course be
+ a member of C, and no conversion is required. In fact,
+ lookup_base will fail in that case, because incomplete
+ classes do not have BINFOs. */
basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
- basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
- basetype, ba_check, NULL);
- instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype, 1);
- if (instance_ptr == error_mark_node)
- return error_mark_node;
+ if (!same_type_ignoring_top_level_qualifiers_p
+ (basetype, TREE_TYPE (TREE_TYPE (instance_ptr))))
+ {
+ basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
+ basetype, ba_check, NULL);
+ instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype,
+ 1);
+ if (instance_ptr == error_mark_node)
+ return error_mark_node;
+ }
/* ...and then the delta in the PMF. */
instance_ptr = build2 (PLUS_EXPR, TREE_TYPE (instance_ptr),
instance_ptr, delta);
vtbl = build_indirect_ref (vtbl, NULL);
/* Finally, extract the function pointer from the vtable. */
- e2 = fold (build2 (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx));
+ e2 = fold_build2 (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx);
e2 = build_indirect_ref (e2, NULL);
TREE_CONSTANT (e2) = 1;
TREE_INVARIANT (e2) = 1;
int is_method;
tree original = function;
+ /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
+ expressions, like those used for ObjC messenger dispatches. */
+ function = objc_rewrite_function_call (function, params);
+
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
Strip such NOP_EXPRs, since FUNCTION is used in non-lvalue context. */
if (TREE_CODE (function) == NOP_EXPR
In C++, unspecified trailing parameters can be filled in with their
default arguments, if such were specified. Do so here. */
-tree
+static tree
convert_arguments (tree typelist, tree values, tree fndecl, int flags)
{
tree typetail, valtail;
}
else
{
- if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
- val = convert_from_reference (val);
-
if (fndecl && DECL_BUILT_IN (fndecl)
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CONSTANT_P)
/* Don't do ellipsis conversion for __built_in_constant_p
|| code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
{
if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
- warning ("division by zero in %<%E / 0%>", op0);
+ warning (0, "division by zero in %<%E / 0%>", op0);
else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1))
- warning ("division by zero in %<%E / 0.%>", op0);
+ warning (0, "division by zero in %<%E / 0.%>", op0);
if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
code0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
if (code1 == INTEGER_TYPE && integer_zerop (op1))
- warning ("division by zero in %<%E %% 0%>", op0);
+ warning (0, "division by zero in %<%E %% 0%>", op0);
else if (code1 == REAL_TYPE && real_zerop (op1))
- warning ("division by zero in %<%E %% 0.%>", op0);
+ warning (0, "division by zero in %<%E %% 0.%>", op0);
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_lt (op1, integer_zero_node))
- warning ("right shift count is negative");
+ warning (0, "right shift count is negative");
else
{
if (! integer_zerop (op1))
short_shift = 1;
if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning ("right shift count >= width of type");
+ warning (0, "right shift count >= width of type");
}
}
/* Convert the shift-count to an integer, regardless of
if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_lt (op1, integer_zero_node))
- warning ("left shift count is negative");
+ warning (0, "left shift count is negative");
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning ("left shift count >= width of type");
+ warning (0, "left shift count >= width of type");
}
/* Convert the shift-count to an integer, regardless of
size of value being shifted. */
if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_lt (op1, integer_zero_node))
- warning ("%s rotate count is negative",
+ warning (0, "%s rotate count is negative",
(code == LROTATE_EXPR) ? "left" : "right");
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning ("%s rotate count >= width of type",
+ warning (0, "%s rotate count >= width of type",
(code == LROTATE_EXPR) ? "left" : "right");
}
/* Convert the shift-count to an integer, regardless of
case EQ_EXPR:
case NE_EXPR:
if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
- warning ("comparing floating point with == or != is unsafe");
+ warning (0, "comparing floating point with == or != is unsafe");
build_type = boolean_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
/* If we're in a template, the only thing we need to know is the
RESULT_TYPE. */
if (processing_template_decl)
- return build2 (resultcode, result_type, op0, op1);
+ return build2 (resultcode,
+ build_type ? build_type : result_type,
+ op0, op1);
if (arithmetic_types_p)
{
&& TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
!= TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
{
- warning ("comparison between types %q#T and %q#T",
+ warning (0, "comparison between types %q#T and %q#T",
TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
}
(result_type)))))
/* OK */;
else
- warning ("comparison between signed and unsigned integer expressions");
+ warning (0, "comparison between signed and unsigned integer expressions");
/* Warn if two unsigned values are being compared in a size
larger than their original size, and one (and only one) is the
{
mask = (~ (HOST_WIDE_INT) 0) << bits;
if ((mask & constant) != mask)
- warning ("comparison of promoted ~unsigned with constant");
+ warning (0, "comparison of promoted ~unsigned with constant");
}
}
else if (unsignedp0 && unsignedp1
< TYPE_PRECISION (result_type))
&& (TYPE_PRECISION (TREE_TYPE (primop1))
< TYPE_PRECISION (result_type)))
- warning ("comparison of promoted ~unsigned with unsigned");
+ warning (0, "comparison of promoted ~unsigned with unsigned");
}
}
}
performed. Note that pointer-difference and pointer-addition
have already been handled above, and so we don't end up here in
that case. */
- warning ("NULL used in arithmetic");
+ warning (0, "NULL used in arithmetic");
if (! converted)
{
if (type_dependent_expression_p (xarg))
return build_min_nt (code, xarg, NULL_TREE);
- /* For non-dependent pointer-to-member, the SCOPE_REF will be
- processed during template substitution. Just compute the
- right type here and build an ADDR_EXPR around it for
- diagnostics. */
- if (code == ADDR_EXPR && TREE_CODE (xarg) == SCOPE_REF)
- {
- tree type;
- if (TREE_TYPE (xarg) == unknown_type_node)
- type = unknown_type_node;
- else if (TREE_CODE (TREE_TYPE (xarg)) == FUNCTION_TYPE)
- type = build_pointer_type (TREE_TYPE (xarg));
- else
- type = build_ptrmem_type (TREE_OPERAND (xarg, 0),
- TREE_TYPE (xarg));
- return build_min (code, type, xarg, NULL_TREE);
- }
-
xarg = build_non_dependent_expr (xarg);
}
{
if (TREE_CODE (xarg) != OFFSET_REF)
{
- error ("invalid use of '%E' to form a pointer-to-member-function. Use a qualified-id.",
+ error ("invalid use of %qE to form a pointer-to-member-function."
+ " Use a qualified-id.",
xarg);
return error_mark_node;
}
else
{
- error ("parenthesis around '%E' cannot be used to form a pointer-to-member-function",
+ error ("parenthesis around %qE cannot be used to form a"
+ " pointer-to-member-function",
xarg);
PTRMEM_OK_P (xarg) = 1;
}
}
}
else if (TREE_CODE (xarg) == TARGET_EXPR)
- warning ("taking address of temporary");
+ warning (0, "taking address of temporary");
exp = build_unary_op (ADDR_EXPR, xarg, 0);
- if (TREE_CODE (exp) == ADDR_EXPR)
- PTRMEM_OK_P (exp) = ptrmem;
}
if (processing_template_decl && exp != error_mark_node)
- return build_min_non_dep (code, exp, orig_expr,
- /*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE);
+ exp = build_min_non_dep (code, exp, orig_expr,
+ /*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE);
+ if (TREE_CODE (exp) == ADDR_EXPR)
+ PTRMEM_OK_P (exp) = ptrmem;
return exp;
}
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 (!(arg = build_expr_type_conversion
- (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, true)))
- errstring = "wrong type argument to unary plus";
- else
- {
- if (!noconvert)
- arg = default_conversion (arg);
- arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
- }
- break;
-
+ case UNARY_PLUS_EXPR:
case NEGATE_EXPR:
- if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
- errstring = "wrong type argument to unary minus";
- else if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
- arg = perform_integral_promotions (arg);
+ {
+ int flags = WANT_ARITH | WANT_ENUM;
+ /* Unary plus (but not unary minus) is allowed on pointers. */
+ if (code == UNARY_PLUS_EXPR)
+ flags |= WANT_POINTER;
+ arg = build_expr_type_conversion (flags, arg, true);
+ if (!arg)
+ errstring = (code == NEGATE_EXPR
+ ? "wrong type argument to unary minus"
+ : "wrong type argument to unary plus");
+ else
+ {
+ if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+ arg = perform_integral_promotions (arg);
+
+ /* Make sure the result is not a lvalue: a unary plus or minus
+ expression is always a rvalue. */
+ if (real_lvalue_p (arg))
+ arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
+ }
+ }
break;
case BIT_NOT_EXPR:
/* Complain about anything else that is not a true lvalue. */
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
- ? "increment" : "decrement")))
+ ? lv_increment : lv_decrement)))
return error_mark_node;
/* Forbid using -- on `bool'. */
arg = OVL_CURRENT (arg);
break;
+ case OFFSET_REF:
+ /* Turn a reference to a non-static data member into a
+ pointer-to-member. */
+ {
+ tree type;
+ tree t;
+
+ if (!PTRMEM_OK_P (arg))
+ return build_unary_op (code, arg, 0);
+
+ t = TREE_OPERAND (arg, 1);
+ if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+ {
+ error ("cannot create pointer to reference member %qD", t);
+ return error_mark_node;
+ }
+
+ type = build_ptrmem_type (context_for_name_lookup (t),
+ TREE_TYPE (t));
+ t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
+ return t;
+ }
+
default:
break;
}
is an error. */
else if (TREE_CODE (argtype) != FUNCTION_TYPE
&& TREE_CODE (argtype) != METHOD_TYPE
- && !lvalue_or_else (arg, "unary %<&$>"))
+ && TREE_CODE (arg) != OFFSET_REF
+ && !lvalue_or_else (arg, lv_addressof))
return error_mark_node;
if (argtype != error_mark_node)
expression so we can just form an ADDR_EXPR with the
correct type. */
|| processing_template_decl)
- addr = build_address (arg);
+ {
+ addr = build_address (arg);
+ if (TREE_CODE (arg) == OFFSET_REF)
+ PTRMEM_OK_P (addr) = PTRMEM_OK_P (arg);
+ }
else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
{
tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
}
else
{
+ tree object = TREE_OPERAND (arg, 0);
tree field = TREE_OPERAND (arg, 1);
- tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
- tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)),
- decl_type_context (field),
- ba_check, NULL);
-
- rval = build_base_path (PLUS_EXPR, rval, binfo, 1);
-
- TREE_OPERAND (arg, 0) = build_indirect_ref (rval, NULL);
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (object), decl_type_context (field)));
addr = build_address (arg);
}
&& TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
{
build_ptrmemfunc_type (argtype);
- addr = build_ptrmemfunc (argtype, addr, 0);
+ addr = build_ptrmemfunc (argtype, addr, 0,
+ /*c_cast_p=*/false);
}
return addr;
for certain kinds of expressions which are not really lvalues
but which we can accept as lvalues.
- If ARG is not a kind of expression we can handle, return zero. */
+ If ARG is not a kind of expression we can handle, return
+ NULL_TREE. */
tree
unary_complex_lvalue (enum tree_code code, tree arg)
{
+ /* Inside a template, making these kinds of adjustments is
+ pointless; we are only concerned with the type of the
+ expression. */
+ if (processing_template_decl)
+ return NULL_TREE;
+
/* Handle (a, b) used as an "lvalue". */
if (TREE_CODE (arg) == COMPOUND_EXPR)
{
if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE
|| TREE_CODE (arg) == OFFSET_REF)
- {
- tree t;
-
- gcc_assert (TREE_CODE (arg) != SCOPE_REF);
-
- if (TREE_CODE (arg) != OFFSET_REF)
- return 0;
-
- t = TREE_OPERAND (arg, 1);
-
- /* Check all this code for right semantics. */
- if (TREE_CODE (t) == FUNCTION_DECL)
- {
- if (DECL_DESTRUCTOR_P (t))
- error ("taking address of destructor");
- return build_unary_op (ADDR_EXPR, t, 0);
- }
- if (TREE_CODE (t) == VAR_DECL)
- return build_unary_op (ADDR_EXPR, t, 0);
- else
- {
- tree type;
-
- if (TREE_OPERAND (arg, 0)
- && ! is_dummy_object (TREE_OPERAND (arg, 0))
- && TREE_CODE (t) != FIELD_DECL)
- {
- error ("taking address of bound pointer-to-member expression");
- return error_mark_node;
- }
- if (!PTRMEM_OK_P (arg))
- return build_unary_op (code, arg, 0);
-
- if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
- {
- error ("cannot create pointer to reference member %qD", t);
- return error_mark_node;
- }
-
- type = build_ptrmem_type (context_for_name_lookup (t),
- TREE_TYPE (t));
- t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
- return t;
- }
- }
-
+ return NULL_TREE;
/* We permit compiler to make function calls returning
objects of aggregate type look like lvalues. */
case PARM_DECL:
if (x == current_class_ptr)
{
- error ("cannot take the address of `this', which is an rvalue expression");
+ error ("cannot take the address of %<this%>, which is an rvalue expression");
TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later. */
return true;
}
case CONST_DECL:
case RESULT_DECL:
if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
- && !DECL_ARTIFICIAL (x) && extra_warnings)
- warning ("address requested for %qD, which is declared `register'",
- x);
+ && !DECL_ARTIFICIAL (x))
+ {
+ if (DECL_HARD_REGISTER (x) != 0)
+ {
+ error
+ ("address of explicit register variable %qD requested", x);
+ return false;
+ }
+ else if (extra_warnings)
+ warning
+ (0, "address requested for %qD, which is declared %<register%>", x);
+ }
TREE_ADDRESSABLE (x) = 1;
return true;
tree
build_compound_expr (tree lhs, tree rhs)
{
- lhs = decl_constant_value (lhs);
lhs = convert_to_void (lhs, "left-hand operand of comma");
if (lhs == error_mark_node || rhs == error_mark_node)
description, src_type, dest_type);
}
+/* Convert EXPR (an expression with pointer-to-member type) to TYPE
+ (another pointer-to-member type in the same hierarchy) and return
+ the converted expression. If ALLOW_INVERSE_P is permitted, a
+ pointer-to-derived may be converted to pointer-to-base; otherwise,
+ only the other direction is permitted. If C_CAST_P is true, this
+ conversion is taking place as part of a C-style cast. */
+
+tree
+convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
+ bool c_cast_p)
+{
+ if (TYPE_PTRMEM_P (type))
+ {
+ tree delta;
+
+ if (TREE_CODE (expr) == PTRMEM_CST)
+ expr = cplus_expand_constant (expr);
+ delta = get_delta_difference (TYPE_PTRMEM_CLASS_TYPE (TREE_TYPE (expr)),
+ TYPE_PTRMEM_CLASS_TYPE (type),
+ allow_inverse_p,
+ c_cast_p);
+ if (!integer_zerop (delta))
+ expr = cp_build_binary_op (PLUS_EXPR,
+ build_nop (ptrdiff_type_node, expr),
+ delta);
+ return build_nop (type, expr);
+ }
+ else
+ return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
+ allow_inverse_p, c_cast_p);
+}
+
/* Perform a static_cast from EXPR to TYPE. When C_CAST_P is true,
this static_cast is being attempted as one of the possible casts
allowed by a C-style cast. (In that case, accessibility of base
{
/* C-style casts are allowed to cast away constness. With
WARN_CAST_QUAL, we still want to issue a warning. */
- diag_fn = warn_cast_qual ? warning : NULL;
+ diag_fn = warn_cast_qual ? warning0 : NULL;
desc = "cast";
}
else
promotions, floating point promotion, integral conversions,
floating point conversions, floating-integral conversions,
pointer conversions, and pointer to member conversions. */
- if ((ARITHMETIC_TYPE_P (type) && ARITHMETIC_TYPE_P (intype))
- /* DR 128
-
- A value of integral _or enumeration_ type can be explicitly
- converted to an enumeration type. */
- || (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
- && INTEGRAL_OR_ENUMERATION_TYPE_P (intype)))
+ /* DR 128
+
+ A value of integral _or enumeration_ type can be explicitly
+ converted to an enumeration type. */
+ /* The effect of all that is that any conversion between any two
+ types which are integral, floating, or enumeration types can be
+ performed. */
+ if ((INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type))
+ && (INTEGRAL_TYPE_P (intype) || SCALAR_FLOAT_TYPE_P (intype)))
{
- expr = decl_constant_value (expr);
expr = ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
/* Ignore any integer overflow caused by the cast. */
if (can_convert (t1, t2))
{
if (!c_cast_p)
- check_for_casting_away_constness (intype, type, diag_fn, desc);
- if (TYPE_PTRMEM_P (type))
- {
- tree delta;
-
- if (TREE_CODE (expr) == PTRMEM_CST)
- expr = cplus_expand_constant (expr);
- delta = get_delta_difference (c1, c2, /*force=*/1);
- if (!integer_zerop (delta))
- expr = cp_build_binary_op (PLUS_EXPR,
- build_nop (ptrdiff_type_node, expr),
- delta);
- return build_nop (type, expr);
- }
- else
- return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
- /*force=*/1);
+ check_for_casting_away_constness (intype, type, diag_fn,
+ desc);
+ return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
+ c_cast_p);
}
}
expr = build_min (STATIC_CAST_EXPR, type, expr);
/* We don't know if it will or will not have side effects. */
TREE_SIDE_EFFECTS (expr) = 1;
- return expr;
+ return convert_from_reference (expr);
}
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
|| TREE_CODE (intype) == METHOD_TYPE);
if (pedantic || warn_pmf2ptr)
- pedwarn ("converting from `%T' to `%T'", intype, type);
+ pedwarn ("converting from %qT to %qT", intype, type);
if (TREE_CODE (intype) == METHOD_TYPE)
expr = build_addr_func (expr);
if (TYPE_PTR_P (intype)
&& (comptypes (TREE_TYPE (intype), TREE_TYPE (type),
COMPARE_BASE | COMPARE_DERIVED)))
- warning ("casting `%T' to `%T' does not dereference pointer",
+ warning (0, "casting %qT to %qT does not dereference pointer",
intype, type);
expr = build_unary_op (ADDR_EXPR, expr, 0);
;
else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
- {
- expr = decl_constant_value (expr);
- return fold_if_not_in_template (build_nop (type, expr));
- }
+ return fold_if_not_in_template (build_nop (type, expr));
else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|| (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
{
&& COMPLETE_TYPE_P (TREE_TYPE (type))
&& COMPLETE_TYPE_P (TREE_TYPE (intype))
&& TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (intype)))
- warning ("cast from %qT to %qT increases required alignment of "
+ warning (0, "cast from %qT to %qT increases required alignment of "
"target type",
intype, type);
- expr = decl_constant_value (expr);
+
return fold_if_not_in_template (build_nop (type, expr));
}
else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
|| (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
{
- if (pedantic || !c_cast_p)
- pedwarn ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
- expr = decl_constant_value (expr);
+ if (pedantic)
+ /* Only issue a warning, as we have always supported this
+ where possible, and it is necessary in some cases. DR 195
+ addresses this issue, but as of 2004/10/26 is still in
+ drafting. */
+ warning (0, "ISO C++ forbids casting between pointer-to-function and pointer-to-object");
return fold_if_not_in_template (build_nop (type, expr));
}
+ else if (TREE_CODE (type) == VECTOR_TYPE)
+ return fold_if_not_in_template (convert_to_vector (type, expr));
+ else if (TREE_CODE (intype) == VECTOR_TYPE)
+ return fold_if_not_in_template (convert_to_integer (type, expr));
else
{
if (valid_p)
&& type_dependent_expression_p (expr))
/* There might turn out to be side effects inside expr. */
TREE_SIDE_EFFECTS (t) = 1;
- return t;
+ return convert_from_reference (t);
}
return build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false,
tree
build_const_cast (tree type, tree expr)
{
- if (type == error_mark_node || expr == error_mark_node)
+ if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
if (processing_template_decl)
&& type_dependent_expression_p (expr))
/* There might turn out to be side effects inside expr. */
TREE_SIDE_EFFECTS (t) = 1;
- return t;
+ return convert_from_reference (t);
}
return build_const_cast_1 (type, expr, /*complain=*/true,
tree_cons (NULL_TREE, value, NULL_TREE));
/* We don't know if it will or will not have side effects. */
TREE_SIDE_EFFECTS (t) = 1;
- return t;
+ return convert_from_reference (t);
}
/* Casts to a (pointer to a) specific ObjC class (or 'id' or
case MAX_EXPR:
/* MIN_EXPR and MAX_EXPR are currently only permitted as lvalues,
when neither operand has side-effects. */
- if (!lvalue_or_else (lhs, "assignment"))
+ if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))
/* Check this here to avoid odd errors when trying to convert
a throw to the type of the COND_EXPR. */
- if (!lvalue_or_else (lhs, "assignment"))
+ if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
cond = build_conditional_expr
}
else
{
- if (TREE_CODE (lhstype) == REFERENCE_TYPE)
- {
- lhs = convert_from_reference (lhs);
- olhstype = lhstype = TREE_TYPE (lhs);
- }
lhs = require_complete_type (lhs);
if (lhs == error_mark_node)
return error_mark_node;
}
/* The left-hand side must be an lvalue. */
- if (!lvalue_or_else (lhs, "assignment"))
+ if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
/* Warn about modifying something that is `const'. Don't warn if
if (newrhs == error_mark_node)
return error_mark_node;
+ if (c_dialect_objc () && flag_objc_gc)
+ {
+ result = objc_generate_write_barrier (lhs, modifycode, newrhs);
+
+ if (result)
+ return result;
+ }
+
result = build2 (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
lhstype, lhs, newrhs);
\f
/* Get difference in deltas for different pointer to member function
types. Returns an integer constant of type PTRDIFF_TYPE_NODE. If
- the conversion is invalid, the constant is zero. If FORCE is true,
- then allow reverse conversions as well.
+ the conversion is invalid, the constant is zero. If
+ ALLOW_INVERSE_P is true, then allow reverse conversions as well.
+ If C_CAST_P is true this conversion is taking place as part of a
+ C-style cast.
Note that the naming of FROM and TO is kind of backwards; the return
value is what we add to a TO in order to get a FROM. They are named
a pointer to member of FROM to a pointer to member of TO. */
static tree
-get_delta_difference (tree from, tree to, int force)
+get_delta_difference (tree from, tree to,
+ bool allow_inverse_p,
+ bool c_cast_p)
{
tree binfo;
- tree virt_binfo;
base_kind kind;
tree result;
/* Assume no conversion is required. */
result = integer_zero_node;
- binfo = lookup_base (to, from, ba_check, &kind);
+ binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
if (kind == bk_inaccessible || kind == bk_ambig)
error (" in pointer to member function conversion");
- else if (!binfo)
+ else if (binfo)
{
- if (!force)
- {
- error_not_base_type (from, to);
- error (" in pointer to member conversion");
- }
- else
- {
- binfo = lookup_base (from, to, ba_check, &kind);
- if (binfo)
- {
- virt_binfo = binfo_from_vbase (binfo);
- if (virt_binfo)
- /* This is a reinterpret cast, we choose to do nothing. */
- warning ("pointer to member cast via virtual base `%T'",
- BINFO_TYPE (virt_binfo));
- else
- result = size_diffop (size_zero_node, BINFO_OFFSET (binfo));
- }
- }
- }
- else
- {
- virt_binfo = binfo_from_vbase (binfo);
- if (!virt_binfo)
+ if (kind != bk_via_virtual)
result = BINFO_OFFSET (binfo);
else
{
+ tree virt_binfo = binfo_from_vbase (binfo);
+
/* This is a reinterpret cast, we choose to do nothing. */
- if (force)
- warning ("pointer to member cast via virtual base %qT",
+ if (allow_inverse_p)
+ warning (0, "pointer to member cast via virtual base %qT",
BINFO_TYPE (virt_binfo));
else
error ("pointer to member conversion via virtual base %qT",
BINFO_TYPE (virt_binfo));
}
}
+ else if (same_type_ignoring_top_level_qualifiers_p (from, to))
+ /* Pointer to member of incomplete class is permitted*/;
+ else if (!allow_inverse_p)
+ {
+ error_not_base_type (from, to);
+ error (" in pointer to member conversion");
+ }
+ else
+ {
+ binfo = lookup_base (from, to, c_cast_p ? ba_unique : ba_check, &kind);
+ if (binfo)
+ {
+ if (kind != bk_via_virtual)
+ result = size_diffop (size_zero_node, BINFO_OFFSET (binfo));
+ else
+ {
+ /* This is a reinterpret cast, we choose to do nothing. */
+ tree virt_binfo = binfo_from_vbase (binfo);
+
+ warning (0, "pointer to member cast via virtual base %qT",
+ BINFO_TYPE (virt_binfo));
+ }
+ }
+ }
return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node,
result));
If FORCE is nonzero, then force this conversion, even if
we would rather not do it. Usually set when using an explicit
- cast.
+ cast. A C-style cast is being processed iff C_CAST_P is true.
Return error_mark_node, if something goes wrong. */
tree
-build_ptrmemfunc (tree type, tree pfn, int force)
+build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
{
tree fn;
tree pfn_type;
n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
- force);
+ force,
+ c_cast_p);
/* We don't have to do any conversion to convert a
pointer-to-member to its own type. But, we don't want to
return instantiate_type (type, pfn, tf_error | tf_warning);
fn = TREE_OPERAND (pfn, 0);
- gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
+ gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
+ /* In a template, we will have preserved the
+ OFFSET_REF. */
+ || (processing_template_decl && TREE_CODE (fn) == OFFSET_REF));
return make_ptrmem_cst (to_type, fn);
}
ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
/* First, calculate the adjustment to the function's class. */
- *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0);
+ *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0,
+ /*c_cast_p=*/0);
if (!DECL_VIRTUAL_P (fn))
*pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
return build_ptrmemfunc_access_expr (t, pfn_identifier);
}
-/* Expression EXPR is about to be implicitly converted to TYPE. Warn
- if this is a potentially dangerous thing to do. Returns a possibly
- marked EXPR. */
-
-tree
-dubious_conversion_warnings (tree type, tree expr,
- const char *errtype, tree fndecl, int parmnum)
-{
- type = non_reference (type);
-
- /* Issue warnings about peculiar, but valid, uses of NULL. */
- if (ARITHMETIC_TYPE_P (type) && expr == null_node)
- {
- if (fndecl)
- warning ("passing NULL used for non-pointer %s %P of %qD",
- errtype, parmnum, fndecl);
- else
- warning ("%s to non-pointer type %qT from NULL", errtype, type);
- }
-
- /* Warn about assigning a floating-point type to an integer type. */
- if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
- && TREE_CODE (type) == INTEGER_TYPE)
- {
- if (fndecl)
- warning ("passing %qT for %s %P of %qD",
- TREE_TYPE (expr), errtype, parmnum, fndecl);
- else
- warning ("%s to %qT from %qT", errtype, type, TREE_TYPE (expr));
- }
- /* And warn about assigning a negative value to an unsigned
- variable. */
- else if (TYPE_UNSIGNED (type) && TREE_CODE (type) != BOOLEAN_TYPE)
- {
- if (TREE_CODE (expr) == INTEGER_CST && TREE_NEGATED_INT (expr))
- {
- if (fndecl)
- warning ("passing negative value %qE for %s %P of %qD",
- expr, errtype, parmnum, fndecl);
- else
- warning ("%s of negative value %qE to %qT", errtype, expr, type);
- }
-
- overflow_warning (expr);
-
- if (TREE_CONSTANT (expr))
- expr = fold_if_not_in_template (expr);
- }
- return expr;
-}
-
/* Convert value RHS to type TYPE as preparation for an assignment to
an lvalue of type TYPE. ERRTYPE is a string to use in error
messages: "assignment", "return", etc. If FNDECL is non-NULL, we
/* Simplify the RHS if possible. */
if (TREE_CODE (rhs) == CONST_DECL)
rhs = DECL_INITIAL (rhs);
-
- /* We do not use decl_constant_value here because of this case:
- const char* const s = "s";
-
- The conversion rules for a string literal are more lax than for a
- variable; in particular, a string literal can be converted to a
- "char *" but the variable "s" cannot be converted in the same
- way. If the conversion is allowed, the optimization should be
- performed while creating the converted expression. */
+ if (c_dialect_objc ())
+ {
+ int parmno;
+ tree rname = fndecl;
+
+ if (!strcmp (errtype, "assignment"))
+ parmno = -1;
+ else if (!strcmp (errtype, "initialization"))
+ parmno = -2;
+ else
+ {
+ tree selector = objc_message_selector ();
+
+ parmno = parmnum;
+
+ if (selector && parmno > 1)
+ {
+ rname = selector;
+ parmno -= 1;
+ }
+ }
+
+ if (objc_compare_types (type, rhstype, parmno, rname))
+ return convert (type, rhs);
+ }
/* [expr.ass]
|| (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node))
return error_mark_node;
- if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
- rhs = convert_from_reference (rhs);
-
if ((TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
&& TREE_CODE (type) != ARRAY_TYPE
&& (TREE_CODE (type) != REFERENCE_TYPE
if (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
|| TREE_CODE (whats_returned) == TARGET_EXPR)
{
- warning ("returning reference to temporary");
+ warning (0, "returning reference to temporary");
return;
}
if (TREE_CODE (whats_returned) == VAR_DECL
&& DECL_NAME (whats_returned)
&& TEMP_NAME_P (DECL_NAME (whats_returned)))
{
- warning ("reference to non-lvalue returned");
+ warning (0, "reference to non-lvalue returned");
return;
}
}
(This is a G++ extension, used to get better code for functions
that call the `volatile' function.) */
if (TREE_THIS_VOLATILE (current_function_decl))
- warning ("function declared `noreturn' has a `return' statement");
+ warning (0, "function declared %<noreturn%> has a %<return%> statement");
/* Check for various simple errors. */
if (DECL_DESTRUCTOR_P (current_function_decl))
that's supposed to return a value. */
if (!retval && fn_returns_value_p)
{
- pedwarn ("return-statement with no value, in function returning '%T'",
+ pedwarn ("return-statement with no value, in function returning %qT",
valtype);
/* Clear this, so finish_function won't say that we reach the
end of a non-void function (which we don't, we gave a
/* Remember that this function did return a value. */
current_function_returns_value = 1;
+ /* Check for erroneous operands -- but after giving ourselves a
+ chance to provide an error about returning a value from a void
+ function. */
+ if (error_operand_p (retval))
+ {
+ current_function_return_value = error_mark_node;
+ return error_mark_node;
+ }
+
/* Only operator new(...) throw(), can return NULL [expr.new/13]. */
if ((DECL_OVERLOADED_OPERATOR_P (current_function_decl) == NEW_EXPR
|| DECL_OVERLOADED_OPERATOR_P (current_function_decl) == VEC_NEW_EXPR)
&& !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
&& ! flag_check_new
&& null_ptr_cst_p (retval))
- warning ("%<operator new%> must not return NULL unless it is "
+ warning (0, "%<operator new%> must not return NULL unless it is "
"declared %<throw()%> (or -fcheck-new is in effect)");
/* Effective C++ rule 15. See also start_function. */
}
if (warn)
- warning ("%<operator=%> should return a reference to %<*this%>");
+ warning (0, "%<operator=%> should return a reference to %<*this%>");
}
/* The fabled Named Return Value optimization, as per [class.copy]/15:
/* We don't need to do any conversions when there's nothing being
returned. */
- if (!retval || retval == error_mark_node)
- return retval;
+ if (!retval)
+ return NULL_TREE;
/* Do any required conversions. */
if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl))
so the usual checks are not appropriate. */
if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
{
- if (!at_least_as_qualified_p (to, from))
+ /* In Objective-C++, some types may have been 'volatilized' by
+ the compiler for EH; when comparing them here, the volatile
+ qualification must be ignored. */
+ bool objc_quals_match = objc_type_quals_match (to, from);
+
+ if (!at_least_as_qualified_p (to, from) && !objc_quals_match)
return 0;
- if (!at_least_as_qualified_p (from, to))
+ if (!at_least_as_qualified_p (from, to) && !objc_quals_match)
{
if (constp == 0)
return 0;
COMPARE_BASE | COMPARE_DERIVED))
continue;
+ if (TREE_CODE (to) == VECTOR_TYPE
+ && vector_types_convertible_p (to, from))
+ return 1;
+
if (TREE_CODE (to) == INTEGER_TYPE
&& TYPE_PRECISION (to) == TYPE_PRECISION (from))
return 1;
return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
}
+/* Apply the TYPE_QUALS to the new DECL. */
+void
+cp_apply_type_quals_to_decl (int type_quals, tree decl)
+{
+ tree type = TREE_TYPE (decl);
+
+ if (type == error_mark_node)
+ return;
+
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ && type_quals != TYPE_UNQUALIFIED)
+ {
+ /* This was an error in C++98 (cv-qualifiers cannot be added to
+ a function type), but DR 295 makes the code well-formed by
+ dropping the extra qualifiers. */
+ if (pedantic)
+ {
+ tree bad_type = build_qualified_type (type, type_quals);
+ pedwarn ("ignoring %qV qualifiers added to function type %qT",
+ bad_type, type);
+ }
+
+ TREE_TYPE (decl) = TYPE_MAIN_VARIANT (type);
+ return;
+ }
+
+ /* Avoid setting TREE_READONLY incorrectly. */
+ if (/* If the object has a constructor, the constructor may modify
+ the object. */
+ TYPE_NEEDS_CONSTRUCTING (type)
+ /* If the type isn't complete, we don't know yet if it will need
+ constructing. */
+ || !COMPLETE_TYPE_P (type)
+ /* If the type has a mutable component, that component might be
+ modified. */
+ || TYPE_HAS_MUTABLE_P (type))
+ type_quals &= ~TYPE_QUAL_CONST;
+
+ c_apply_type_quals_to_decl (type_quals, decl);
+}
+
/* Subroutine of casts_away_constness. Make T1 and T2 point at
exemplar types such that casting T1 to T2 is casting away constness
if and only if there is no implicit conversion from T1 to T2. */
and pointers to members (conv.qual), the "member" aspect of a
pointer to member level is ignored when determining if a const
cv-qualifier has been cast away. */
- if (TYPE_PTRMEM_P (*t1))
- *t1 = build_pointer_type (TYPE_PTRMEM_POINTED_TO_TYPE (*t1));
- if (TYPE_PTRMEM_P (*t2))
- *t2 = build_pointer_type (TYPE_PTRMEM_POINTED_TO_TYPE (*t2));
-
/* [expr.const.cast]
For two pointer types:
to
Tcv2,(M-K+1) * cv2,(M-K+2) * ... cv2,M *. */
-
- if (TREE_CODE (*t1) != POINTER_TYPE
- || TREE_CODE (*t2) != POINTER_TYPE)
+ if ((!TYPE_PTR_P (*t1) && !TYPE_PTRMEM_P (*t1))
+ || (!TYPE_PTR_P (*t2) && !TYPE_PTRMEM_P (*t2)))
{
*t1 = cp_build_qualified_type (void_type_node,
cp_type_quals (*t1));
quals1 = cp_type_quals (*t1);
quals2 = cp_type_quals (*t2);
- *t1 = TREE_TYPE (*t1);
- *t2 = TREE_TYPE (*t2);
+
+ if (TYPE_PTRMEM_P (*t1))
+ *t1 = TYPE_PTRMEM_POINTED_TO_TYPE (*t1);
+ else
+ *t1 = TREE_TYPE (*t1);
+ if (TYPE_PTRMEM_P (*t2))
+ *t2 = TYPE_PTRMEM_POINTED_TO_TYPE (*t2);
+ else
+ *t2 = TREE_TYPE (*t2);
+
casts_away_constness_r (t1, t2);
*t1 = build_pointer_type (*t1);
*t2 = build_pointer_type (*t2);
t = TREE_TYPE (t);
return t;
}
+
+
+/* Return nonzero if REF is an lvalue valid for this language;
+ otherwise, print an error message and return zero. USE says
+ how the lvalue is being used and so selects the error message. */
+
+int
+lvalue_or_else (tree ref, enum lvalue_use use)
+{
+ int win = lvalue_p (ref);
+
+ if (!win)
+ lvalue_error (use);
+
+ return win;
+}