/* 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;
result_type = composite_pointer_type_r (pointee1, pointee2, location);
else
{
- pedwarn ("%s between distinct pointer types `%T' and `%T' "
+ pedwarn ("%s between distinct pointer types %qT and %qT "
"lacks a cast",
location, t1, t2);
result_type = void_type_node;
{
if (!same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
TYPE_PTRMEM_CLASS_TYPE (t2)))
- pedwarn ("%s between distinct pointer types `%T' and `%T' "
+ pedwarn ("%s between distinct pointer types %qT and %qT "
"lacks a cast",
location, t1, t2);
result_type = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
tree result_type;
if (pedantic && TYPE_PTRFN_P (t2))
- pedwarn ("ISO C++ forbids %s between pointer of type `void *' and pointer-to-function", location);
+ pedwarn ("ISO C++ forbids %s between pointer of type %<void *%> "
+ "and pointer-to-function", location);
result_type
= cp_build_qualified_type (void_type_node,
(cp_type_quals (TREE_TYPE (t1))
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
(cp_build_qualified_type (class2, TYPE_QUALS (class1))));
else
{
- error ("%s between distinct pointer types `%T' and `%T' "
+ error ("%s between distinct pointer types %qT and %qT "
"lacks a cast", location, t1, t2);
return error_mark_node;
}
t2 = build_ptrmem_type (class1, TYPE_PTRMEM_POINTED_TO_TYPE (t2));
else
{
- error ("%s between distinct pointer-to-member types `%T' and `%T' "
+ error ("%s between distinct pointer-to-member types %qT and %qT "
"lacks a cast", location, t1, t2);
return error_mark_node;
}
|| TREE_CODE (b) != RECORD_TYPE)
return false;
- if (ACCESSIBLY_UNIQUELY_DERIVED_P (a, b))
+ if (PUBLICLY_UNIQUELY_DERIVED_P (a, b))
return true;
}
return false;
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;
if (type_code == METHOD_TYPE)
{
if (complain && (pedantic || warn_pointer_arith))
- pedwarn ("invalid application of `%s' to a member function", op_name);
+ pedwarn ("invalid application of %qs to a member function", op_name);
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;
}
&& TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
{
- error ("invalid application of `%s' to a bit-field", op_name);
+ error ("invalid application of %qs to a bit-field", op_name);
e = char_type_node;
}
else if (is_overloaded_fn (e))
{
- pedwarn ("ISO C++ forbids applying `%s' to an expression of function type", op_name);
+ pedwarn ("ISO C++ forbids applying %qs to an expression of "
+ "function type", op_name);
e = char_type_node;
}
else if (type_unknown_p (e))
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 `%T'", totype);
+ warning (0, "deprecated conversion from string constant to %qT'", totype);
return 1;
}
are equal, so we know what conditional expression this used to be. */
if (TREE_CODE (t) == MIN_EXPR || TREE_CODE (t) == MAX_EXPR)
{
+ /* The following code is incorrect if either operand side-effects. */
+ gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0))
+ && !TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)));
return
build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
? LE_EXPR : GE_EXPR),
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]
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
- error ("request for member `%D' in `%E', which is of non-class type `%T'",
+ error ("request for member %qD in %qE, which is of non-class type %qT",
member, object, object_type);
return error_mark_node;
}
if (!member_scope || !DERIVED_FROM_P (member_scope, object_type))
{
if (TREE_CODE (member) == FIELD_DECL)
- error ("invalid use of nonstatic data member '%E'", member);
+ error ("invalid use of nonstatic data member %qE", member);
else
- error ("`%D' is not a member of `%T'", member, object_type);
+ error ("%qD is not a member of %qT", member, object_type);
return error_mark_node;
}
base_kind kind;
binfo = lookup_base (access_path ? access_path : object_type,
- member_scope, ba_ignore, &kind);
+ member_scope, ba_unique, &kind);
if (binfo == error_mark_node)
return error_mark_node;
offsetof macro. */
if (null_object_p && kind == bk_via_virtual)
{
- error ("invalid access to non-static data member `%D' of NULL object",
+ error ("invalid access to non-static data member %qD of "
+ "NULL object",
member);
- error ("(perhaps the `offsetof' macro was used incorrectly)");
+ error ("(perhaps the %<offsetof%> macro was used incorrectly)");
return error_mark_node;
}
&& !DECL_FIELD_IS_BASE (member)
&& !skip_evaluation)
{
- warning ("invalid access to non-static data member `%D' 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
member_type = cp_build_qualified_type (member_type, type_quals);
}
- result = fold (build3 (COMPONENT_REF, member_type, object, member,
- NULL_TREE));
+ result = build3 (COMPONENT_REF, member_type, object, member,
+ NULL_TREE);
+ result = fold_if_not_in_template (result);
/* Mark the expression const or volatile, as appropriate. Even
though we've dealt with the type above, we still have to mark the
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))
}
else
{
- error ("invalid use of `%D'", member);
+ error ("invalid use of %qD", member);
return error_mark_node;
}
if (scope && !check_dtor_name (scope, dtor_name))
{
- error ("qualified type `%T' does not match destructor name `~%T'",
+ error ("qualified type %qT does not match destructor name ~%qT",
scope, dtor_type);
return error_mark_node;
}
if (!DERIVED_FROM_P (dtor_type, TYPE_MAIN_VARIANT (object_type)))
{
- error ("the type being destroyed is `%T', but the destructor refers to `%T'",
+ error ("the type being destroyed is %qT, but the destructor refers to %qT",
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
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
- error ("request for member `%D' in `%E', which is of non-class type `%T'",
+ error ("request for member %qD in %qE, which is of non-class type %qT",
name, object, object_type);
return error_mark_node;
}
name a member of OBJECT_TYPE. */
if (TREE_CODE (scope) == NAMESPACE_DECL)
{
- error ("`%D::%D' is not a member of `%T'",
+ error ("%<%D::%D%> is not a member of %qT",
scope, name, object_type);
return error_mark_node;
}
return error_mark_node;
if (!access_path)
{
- error ("`%T' is not a base of `%T'", scope, object_type);
+ error ("%qT is not a base of %qT", scope, object_type);
return error_mark_node;
}
}
/*want_type=*/false);
if (member == NULL_TREE)
{
- error ("'%D' has no member named '%E'", object_type, name);
+ error ("%qD has no member named %qE", object_type, name);
return error_mark_node;
}
if (member == error_mark_node)
template = lookup_template_function (template, template_args);
else
{
- error ("`%D' is not a member template function", name);
+ error ("%qD is not a member template function", name);
return error_mark_node;
}
}
/*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]
{
/* A pointer to incomplete type (other than cv void) can be
dereferenced [expr.unary.op]/1 */
- error ("`%T' is not a pointer-to-object type", type);
+ error ("%qT is not a pointer-to-object type", type);
return error_mark_node;
}
else if (TREE_CODE (pointer) == ADDR_EXPR
/* `pointer' won't be an error_mark_node if we were given a
pointer to member, so it's cool to check for this here. */
else if (TYPE_PTR_TO_MEMBER_P (type))
- error ("invalid use of `%s' on pointer to member", errorstring);
+ error ("invalid use of %qs on pointer to member", errorstring);
else if (pointer != error_mark_node)
{
if (errorstring)
- error ("invalid type argument of `%s'", errorstring);
+ error ("invalid type argument of %qs", errorstring);
else
error ("invalid type argument");
}
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));
|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
TREE_THIS_VOLATILE (rval)
|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
- return require_complete_type (fold (rval));
+ return require_complete_type (fold_if_not_in_template (rval));
}
{
}
else
{
- error ("object missing in use of `%E'", function);
+ error ("object missing in use of %qE", function);
return error_mark_node;
}
}
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
/* Convert anything with function type to a pointer-to-function. */
if (pedantic && DECL_MAIN_P (function))
- pedwarn ("ISO C++ forbids calling `::main' from within program");
+ pedwarn ("ISO C++ forbids calling %<::main%> from within program");
/* Differs from default_conversion by not setting TREE_ADDRESSABLE
(because calling an inline function does not mean the function
if (TYPE_PTRMEMFUNC_P (fntype))
{
- error ("must use .* or ->* to call pointer-to-member function in `%E (...)'",
- original);
+ error ("must use %<.*%> or %<->*%> to call pointer-to-member "
+ "function in %<%E (...)%>",
+ original);
return error_mark_node;
}
|| is_method
|| TREE_CODE (function) == TEMPLATE_ID_EXPR))
{
- error ("`%E' cannot be used as a function", original);
+ error ("%qE cannot be used as a function", original);
return error_mark_node;
}
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;
{
if (fndecl)
{
- cp_error_at ("too many arguments to %s `%+#D'", called_thing,
+ cp_error_at ("too many arguments to %s %q+#D", called_thing,
fndecl);
error ("at this point in file");
}
if (!COMPLETE_TYPE_P (complete_type (type)))
{
if (fndecl)
- error ("parameter %P of `%D' has incomplete type `%T'",
+ error ("parameter %P of %qD has incomplete type %qT",
i, fndecl, type);
else
- error ("parameter %P has incomplete type `%T'", i, type);
+ error ("parameter %P has incomplete type %qT", i, type);
parmval = error_mark_node;
}
else
}
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
{
if (fndecl)
{
- cp_error_at ("too few arguments to %s `%+#D'",
+ cp_error_at ("too few arguments to %s %q+#D",
called_thing, fndecl);
error ("at this point in file");
}
convert it to this type. */
tree final_type = 0;
+ tree result;
+
/* Nonzero if this is an operation like MIN or MAX which can
safely be computed in short if both args are promoted shorts.
Also implies COMMON.
/* Nonzero means set RESULT_TYPE to the common type of the args. */
int common = 0;
+ /* True if both operands have arithmetic type. */
+ bool arithmetic_types_p;
+
/* Apply default conversions. */
op0 = orig_op0;
op1 = orig_op1;
tree t = instantiate_type (TREE_TYPE (op1), op0, tf_none);
if (t != error_mark_node)
{
- pedwarn ("assuming cast to type `%T' from overloaded function",
- TREE_TYPE (t));
+ pedwarn ("assuming cast to type %qT from overloaded function",
+ TREE_TYPE (t));
op0 = t;
}
}
tree t = instantiate_type (TREE_TYPE (op0), op1, tf_none);
if (t != error_mark_node)
{
- pedwarn ("assuming cast to type `%T' from overloaded function",
- TREE_TYPE (t));
+ pedwarn ("assuming cast to type %qT from overloaded function",
+ TREE_TYPE (t));
op1 = t;
}
}
|| 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
break;
}
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
- &&
- (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
+ arithmetic_types_p =
+ ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+ || code1 == COMPLEX_TYPE));
+ /* Determine the RESULT_TYPE, if it is not already known. */
+ if (!result_type
+ && arithmetic_types_p
+ && (shorten || common || short_compare))
+ result_type = common_type (type0, type1);
+
+ if (!result_type)
{
- int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
+ error ("invalid operands of types %qT and %qT to binary %qO",
+ TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+ return error_mark_node;
+ }
- if (shorten || common || short_compare)
- result_type = common_type (type0, type1);
+ /* If we're in a template, the only thing we need to know is the
+ RESULT_TYPE. */
+ if (processing_template_decl)
+ return build2 (resultcode,
+ build_type ? build_type : result_type,
+ op0, op1);
+
+ if (arithmetic_types_p)
+ {
+ int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
/* For certain operations (which identify themselves by shorten != 0)
if both args were extended from the same smaller type,
&& TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
!= TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
{
- warning ("comparison between types `%#T' and `%#T'",
- TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
+ warning (0, "comparison between types %q#T and %q#T",
+ TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
}
/* Give warnings for comparisons between signed and unsigned
(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");
}
}
}
- /* At this point, RESULT_TYPE must be nonzero to avoid an error message.
- If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
+ /* If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
Then the expression will be built.
It will be given type FINAL_TYPE if that is nonzero;
otherwise, it will be given type RESULT_TYPE. */
- if (!result_type)
- {
- error ("invalid operands of types `%T' and `%T' to binary `%O'",
- TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
- return error_mark_node;
- }
-
/* Issue warnings about peculiar, but valid, uses of NULL. */
if (/* It's reasonable to use pointer values as operands of &&
and ||, so NULL is no exception. */
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 (build_type == NULL_TREE)
build_type = result_type;
- {
- tree result = fold (build2 (resultcode, build_type, op0, op1));
- if (final_type != 0)
- result = cp_convert (final_type, result);
- return result;
- }
+ result = build2 (resultcode, build_type, op0, op1);
+ result = fold_if_not_in_template (result);
+ if (final_type != 0)
+ result = cp_convert (final_type, result);
+ return result;
}
\f
/* Return a tree for the sum or difference (RESULTCODE says which)
pointer_int_sum() anyway. */
complete_type (TREE_TYPE (res_type));
- return pointer_int_sum (resultcode, ptrop, fold (intop));
+ return pointer_int_sum (resultcode, ptrop,
+ fold_if_not_in_template (intop));
}
/* Return a tree for the difference of pointers OP0 and OP1.
if (pedantic || warn_pointer_arith)
{
if (TREE_CODE (target_type) == VOID_TYPE)
- pedwarn ("ISO C++ forbids using pointer of type `void *' in subtraction");
+ pedwarn ("ISO C++ forbids using pointer of type %<void *%> in subtraction");
if (TREE_CODE (target_type) == FUNCTION_TYPE)
pedwarn ("ISO C++ forbids using pointer to a function in subtraction");
if (TREE_CODE (target_type) == METHOD_TYPE)
/* Do the division. */
result = build2 (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
- return fold (result);
+ return fold_if_not_in_template (result);
}
\f
/* Construct and perhaps optimize a tree representation
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;
}
if (processing_template_decl)
return expr;
t = perform_implicit_conversion (boolean_type_node, expr);
- t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
+ t = fold_build_cleanup_point_expr (boolean_type_node, t);
return t;
}
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:
if (TREE_CODE (arg) == COMPLEX_CST)
return TREE_REALPART (arg);
else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
- return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+ {
+ arg = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
+ return fold_if_not_in_template (arg);
+ }
else
return arg;
if (TREE_CODE (arg) == COMPLEX_CST)
return TREE_IMAGPART (arg);
else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
- return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+ {
+ arg = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
+ return fold_if_not_in_template (arg);
+ }
else
return cp_convert (TREE_TYPE (arg), integer_zero_node);
tree type = complete_type (TREE_TYPE (argtype));
if (!COMPLETE_OR_VOID_TYPE_P (type))
- error ("cannot %s a pointer to incomplete type `%T'",
- ((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? "increment" : "decrement"), TREE_TYPE (argtype));
+ error ("cannot %s a pointer to incomplete type %qT",
+ ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? "increment" : "decrement"), TREE_TYPE (argtype));
else if ((pedantic || warn_pointer_arith)
&& !TYPE_PTROB_P (argtype))
- pedwarn ("ISO C++ forbids %sing a pointer of type `%T'",
- ((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? "increment" : "decrement"), argtype);
+ pedwarn ("ISO C++ forbids %sing a pointer of type %qT",
+ ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? "increment" : "decrement"), argtype);
inc = cxx_sizeof_nowarn (TREE_TYPE (argtype));
}
else
/* 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'. */
{
if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
{
- error ("invalid use of `--' on bool variable `%D'", arg);
+ error ("invalid use of %<--%> on bool variable %qD", arg);
return error_mark_node;
}
val = boolean_increment (code, arg);
}
else if (pedantic && DECL_MAIN_P (arg))
/* ARM $3.4 */
- pedwarn ("ISO C++ forbids taking address of function `::main'");
+ pedwarn ("ISO C++ forbids taking address of function %<::main%>");
/* Let &* cancel out to simplify resulting code. */
if (TREE_CODE (arg) == INDIRECT_REF)
/* An expression like &memfn. */
pedwarn ("ISO C++ forbids taking the address of an unqualified"
" or parenthesized non-static member function to form"
- " a pointer to member function. Say `&%T::%D'",
+ " a pointer to member function. Say %<&%T::%D%>",
base, name);
else
pedwarn ("ISO C++ forbids taking the address of a bound member"
" function to form a pointer to member function."
- " Say `&%T::%D'",
+ " Say %<&%T::%D%>",
base, name);
}
arg = build_offset_ref (base, name, /*address_p=*/true);
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 if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
{
- error ("attempt to take address of bit-field structure member `%D'",
+ error ("attempt to take address of bit-field structure member %qD",
TREE_OPERAND (arg, 1));
return error_mark_node;
}
else
{
+ tree object = TREE_OPERAND (arg, 0);
tree field = TREE_OPERAND (arg, 1);
- 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;
{
if (argtype == 0)
argtype = TREE_TYPE (arg);
- return fold (build1 (code, argtype, arg));
+ return fold_if_not_in_template (build1 (code, argtype, arg));
}
error ("%s", errstring);
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 `%D'", 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 `%D', 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)
return build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs);
}
-/* Issue an error message if casting from SRC_TYPE to DEST_TYPE casts
- away constness. DESCRIPTION explains what operation is taking
- place. */
+/* Issue a diagnostic message if casting from SRC_TYPE to DEST_TYPE
+ casts away constness. DIAG_FN gives the function to call if we
+ need to issue a diagnostic; if it is NULL, no diagnostic will be
+ issued. DESCRIPTION explains what operation is taking place. */
static void
check_for_casting_away_constness (tree src_type, tree dest_type,
+ void (*diag_fn)(const char *, ...),
const char *description)
{
- if (casts_away_constness (src_type, dest_type))
- error ("%s from type `%T' to type `%T' casts away constness",
+ if (diag_fn && casts_away_constness (src_type, dest_type))
+ error ("%s from type %qT to type %qT casts away constness",
description, src_type, dest_type);
}
-/* Return an expression representing static_cast<TYPE>(EXPR). */
+/* 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
-build_static_cast (tree type, tree expr)
+tree
+convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
+ bool c_cast_p)
{
- tree intype;
- tree result;
-
- if (type == error_mark_node || expr == error_mark_node)
- return error_mark_node;
-
- if (processing_template_decl)
+ if (TYPE_PTRMEM_P (type))
{
- 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;
+ 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);
+}
- /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
- Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
- if (TREE_CODE (type) != REFERENCE_TYPE
- && TREE_CODE (expr) == NOP_EXPR
- && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
- expr = TREE_OPERAND (expr, 0);
+/* 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
+ classes is not considered, and it is OK to cast away
+ constness.) Return the result of the cast. *VALID_P is set to
+ indicate whether or not the cast was valid. */
+
+static tree
+build_static_cast_1 (tree type, tree expr, bool c_cast_p,
+ bool *valid_p)
+{
+ tree intype;
+ tree result;
+ tree orig;
+ void (*diag_fn)(const char*, ...);
+ const char *desc;
+
+ /* Assume the cast is valid. */
+ *valid_p = true;
intype = TREE_TYPE (expr);
+ /* Determine what to do when casting away constness. */
+ if (c_cast_p)
+ {
+ /* 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 ? warning0 : NULL;
+ desc = "cast";
+ }
+ else
+ {
+ /* A static_cast may not cast away constness. */
+ diag_fn = error;
+ desc = "static_cast";
+ }
+
/* [expr.static.cast]
An lvalue of type "cv1 B", where B is a class type, can be cast
&& can_convert (build_pointer_type (TYPE_MAIN_VARIANT (intype)),
build_pointer_type (TYPE_MAIN_VARIANT
(TREE_TYPE (type))))
- && at_least_as_qualified_p (TREE_TYPE (type), intype))
+ && (c_cast_p
+ || at_least_as_qualified_p (TREE_TYPE (type), intype)))
{
+ tree base;
+
/* There is a standard conversion from "D*" to "B*" even if "B"
- is ambiguous or inaccessible. Therefore, we ask lookup_base
- to check these conditions. */
- tree base = lookup_base (TREE_TYPE (type), intype, ba_check, NULL);
+ is ambiguous or inaccessible. If this is really a
+ static_cast, then we check both for inaccessibility and
+ ambiguity. However, if this is a static_cast being performed
+ because the user wrote a C-style cast, then accessibility is
+ not considered. */
+ base = lookup_base (TREE_TYPE (type), intype,
+ c_cast_p ? ba_unique : ba_check,
+ NULL);
/* Convert from "B*" to "D*". This function will check that "B"
is not a virtual base of "D". */
return convert_from_reference (build_nop (type, expr));
}
+ orig = expr;
+
/* [expr.static.cast]
An expression e can be explicitly converted to a type T using a
static_cast of the form static_cast<T>(e) if the declaration T
t(e);" is well-formed, for some invented temporary variable
t. */
- result = perform_direct_initialization_if_possible (type, expr);
+ result = perform_direct_initialization_if_possible (type, expr,
+ c_cast_p);
if (result)
{
result = convert_from_reference (result);
+
+ /* Ignore any integer overflow caused by the cast. */
+ if (TREE_CODE (result) == INTEGER_CST
+ && CONSTANT_CLASS_P (orig))
+ {
+ TREE_OVERFLOW (result) = TREE_OVERFLOW (orig);
+ TREE_CONSTANT_OVERFLOW (result)
+ = TREE_CONSTANT_OVERFLOW (orig);
+ }
/* [expr.static.cast]
If T is a reference type, the result is an lvalue; otherwise,
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)))
- /* Really, build_c_cast should defer to this function rather
- than the other way around. */
- return build_c_cast (type, expr);
-
+ /* 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 = ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
+
+ /* Ignore any integer overflow caused by the cast. */
+ if (TREE_CODE (expr) == INTEGER_CST
+ && CONSTANT_CLASS_P (orig))
+ {
+ TREE_OVERFLOW (expr) = TREE_OVERFLOW (orig);
+ TREE_CONSTANT_OVERFLOW (expr) = TREE_CONSTANT_OVERFLOW (orig);
+ }
+ return expr;
+ }
+
if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
&& CLASS_TYPE_P (TREE_TYPE (type))
&& CLASS_TYPE_P (TREE_TYPE (intype))
{
tree base;
- check_for_casting_away_constness (intype, type, "static_cast");
- base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), ba_check,
+ if (!c_cast_p)
+ check_for_casting_away_constness (intype, type, diag_fn, desc);
+ base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
+ c_cast_p ? ba_unique : ba_check,
NULL);
return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
}
}
if (can_convert (t1, t2))
{
- check_for_casting_away_constness (intype, type, "static_cast");
- 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);
+ if (!c_cast_p)
+ check_for_casting_away_constness (intype, type, diag_fn,
+ desc);
+ return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
+ c_cast_p);
}
}
&& VOID_TYPE_P (TREE_TYPE (intype))
&& TYPE_PTROB_P (type))
{
- check_for_casting_away_constness (intype, type, "static_cast");
+ if (!c_cast_p)
+ check_for_casting_away_constness (intype, type, diag_fn, desc);
return build_nop (type, expr);
}
- error ("invalid static_cast from type `%T' to type `%T'", intype, type);
+ *valid_p = false;
return error_mark_node;
}
+/* Return an expression representing static_cast<TYPE>(EXPR). */
+
tree
-build_reinterpret_cast (tree type, tree expr)
+build_static_cast (tree type, tree expr)
{
- tree intype;
+ tree result;
+ bool valid_p;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
- tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
-
- if (!TREE_SIDE_EFFECTS (t)
- && type_dependent_expression_p (expr))
- /* There might turn out to be side effects inside expr. */
- TREE_SIDE_EFFECTS (t) = 1;
- return t;
+ 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 convert_from_reference (expr);
}
- if (TREE_CODE (type) != REFERENCE_TYPE)
- {
- expr = decay_conversion (expr);
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (type) != REFERENCE_TYPE
+ && TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
- /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
- Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
- if (TREE_CODE (expr) == NOP_EXPR
- && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
- expr = TREE_OPERAND (expr, 0);
+ result = build_static_cast_1 (type, expr, /*c_cast_p=*/false, &valid_p);
+ if (valid_p)
+ return result;
+
+ error ("invalid static_cast from type %qT to type %qT",
+ TREE_TYPE (expr), type);
+ return error_mark_node;
+}
+
+/* EXPR is an expression with member function or pointer-to-member
+ function type. TYPE is a pointer type. Converting EXPR to TYPE is
+ not permitted by ISO C++, but we accept it in some modes. If we
+ are not in one of those modes, issue a diagnostic. Return the
+ converted expression. */
+
+tree
+convert_member_func_to_ptr (tree type, tree expr)
+{
+ tree intype;
+ tree decl;
+
+ intype = TREE_TYPE (expr);
+ gcc_assert (TYPE_PTRMEMFUNC_P (intype)
+ || TREE_CODE (intype) == METHOD_TYPE);
+
+ if (pedantic || warn_pmf2ptr)
+ pedwarn ("converting from %qT to %qT", intype, type);
+
+ if (TREE_CODE (intype) == METHOD_TYPE)
+ expr = build_addr_func (expr);
+ else if (TREE_CODE (expr) == PTRMEM_CST)
+ expr = build_address (PTRMEM_CST_MEMBER (expr));
+ else
+ {
+ decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 0);
+ decl = build_address (decl);
+ expr = get_member_function_from_ptrfunc (&decl, expr);
}
+ return build_nop (type, expr);
+}
+
+/* Return a representation for a reinterpret_cast from EXPR to TYPE.
+ If C_CAST_P is true, this reinterpret cast is being done as part of
+ a C-style cast. If VALID_P is non-NULL, *VALID_P is set to
+ indicate whether or not reinterpret_cast was valid. */
+
+static tree
+build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
+ bool *valid_p)
+{
+ tree intype;
+
+ /* Assume the cast is invalid. */
+ if (valid_p)
+ *valid_p = true;
+
+ if (type == error_mark_node || error_operand_p (expr))
+ return error_mark_node;
+
intype = TREE_TYPE (expr);
+ /* [expr.reinterpret.cast]
+ An lvalue expression of type T1 can be cast to the type
+ "reference to T2" if an expression of type "pointer to T1" can be
+ explicitly converted to the type "pointer to T2" using a
+ reinterpret_cast. */
if (TREE_CODE (type) == REFERENCE_TYPE)
{
if (! real_lvalue_p (expr))
{
- error ("invalid reinterpret_cast of an rvalue expression of type `%T' to type `%T'", intype, type);
+ error ("invalid cast of an rvalue expression of type "
+ "%qT to type %qT",
+ intype, type);
return error_mark_node;
}
+
+ /* Warn about a reinterpret_cast from "A*" to "B&" if "A" and
+ "B" are related class types; the reinterpret_cast does not
+ adjust the pointer. */
+ if (TYPE_PTR_P (intype)
+ && (comptypes (TREE_TYPE (intype), TREE_TYPE (type),
+ COMPARE_BASE | COMPARE_DERIVED)))
+ warning (0, "casting %qT to %qT does not dereference pointer",
+ intype, type);
+
expr = build_unary_op (ADDR_EXPR, expr, 0);
if (expr != error_mark_node)
- expr = build_reinterpret_cast
- (build_pointer_type (TREE_TYPE (type)), expr);
+ expr = build_reinterpret_cast_1
+ (build_pointer_type (TREE_TYPE (type)), expr, c_cast_p,
+ valid_p);
if (expr != error_mark_node)
expr = build_indirect_ref (expr, 0);
return expr;
}
- else if (same_type_ignoring_top_level_qualifiers_p (intype, type))
- return build_static_cast (type, expr);
- if (TYPE_PTR_P (type) && (TREE_CODE (intype) == INTEGER_TYPE
- || TREE_CODE (intype) == ENUMERAL_TYPE))
- /* OK */;
- else if (TREE_CODE (type) == INTEGER_TYPE && TYPE_PTR_P (intype))
+ /* As a G++ extension, we consider conversions from member
+ functions, and pointers to member functions to
+ pointer-to-function and pointer-to-void types. If
+ -Wno-pmf-conversions has not been specified,
+ convert_member_func_to_ptr will issue an error message. */
+ if ((TYPE_PTRMEMFUNC_P (intype)
+ || TREE_CODE (intype) == METHOD_TYPE)
+ && TYPE_PTR_P (type)
+ && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+ || VOID_TYPE_P (TREE_TYPE (type))))
+ return convert_member_func_to_ptr (type, expr);
+
+ /* If the cast is not to a reference type, the lvalue-to-rvalue,
+ array-to-pointer, and function-to-pointer conversions are
+ performed. */
+ expr = decay_conversion (expr);
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
+
+ if (error_operand_p (expr))
+ return error_mark_node;
+
+ intype = TREE_TYPE (expr);
+
+ /* [expr.reinterpret.cast]
+ A pointer can be converted to any integral type large enough to
+ hold it. */
+ if (CP_INTEGRAL_TYPE_P (type) && TYPE_PTR_P (intype))
{
if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
- pedwarn ("reinterpret_cast from `%T' to `%T' loses precision",
- intype, type);
- }
+ pedwarn ("cast from %qT to %qT loses precision",
+ intype, type);
+ }
+ /* [expr.reinterpret.cast]
+ A value of integral or enumeration type can be explicitly
+ converted to a pointer. */
+ else if (TYPE_PTR_P (type) && INTEGRAL_OR_ENUMERATION_TYPE_P (intype))
+ /* OK */
+ ;
else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
- {
- expr = decl_constant_value (expr);
- return fold (build1 (NOP_EXPR, type, expr));
- }
+ 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)))
{
- check_for_casting_away_constness (intype, type, "reinterpret_cast");
- expr = decl_constant_value (expr);
- return fold (build1 (NOP_EXPR, type, expr));
+ if (!c_cast_p)
+ check_for_casting_away_constness (intype, type, error,
+ "reinterpret_cast");
+ /* Warn about possible alignment problems. */
+ if (STRICT_ALIGNMENT && warn_cast_align
+ && !VOID_TYPE_P (type)
+ && TREE_CODE (TREE_TYPE (intype)) != FUNCTION_TYPE
+ && COMPLETE_TYPE_P (TREE_TYPE (type))
+ && COMPLETE_TYPE_P (TREE_TYPE (intype))
+ && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (intype)))
+ warning (0, "cast from %qT to %qT increases required alignment of "
+ "target type",
+ intype, type);
+
+ 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)))
{
- pedwarn ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
- expr = decl_constant_value (expr);
- return fold (build1 (NOP_EXPR, type, expr));
- }
+ 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
{
- error ("invalid reinterpret_cast from type `%T' to type `%T'",
- intype, type);
+ if (valid_p)
+ *valid_p = false;
+ error ("invalid cast from type %qT to type %qT", intype, type);
return error_mark_node;
}
}
tree
-build_const_cast (tree type, tree expr)
+build_reinterpret_cast (tree type, tree expr)
{
- tree intype;
-
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
- tree t = build_min (CONST_CAST_EXPR, type, expr);
+ tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
if (!TREE_SIDE_EFFECTS (t)
&& 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);
}
- if (!POINTER_TYPE_P (type) && !TYPE_PTRMEM_P (type))
- error ("invalid use of const_cast with type `%T', which is not a pointer, reference, nor a pointer-to-data-member type", type);
- else if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
- {
- error ("invalid use of const_cast with type `%T', which is a pointer or reference to a function type", type);
+ return build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false,
+ /*valid_p=*/NULL);
+}
+
+/* Perform a const_cast from EXPR to TYPE. If the cast is valid,
+ return an appropriate expression. Otherwise, return
+ error_mark_node. If the cast is not valid, and COMPLAIN is true,
+ then a diagnostic will be issued. If VALID_P is non-NULL, its
+ value upon return will indicate whether or not the conversion
+ succeeded. */
+
+static tree
+build_const_cast_1 (tree dst_type, tree expr, bool complain,
+ bool *valid_p)
+{
+ tree src_type;
+ tree reference_type;
+
+ /* Callers are responsible for handling error_mark_node as a
+ destination type. */
+ gcc_assert (dst_type != error_mark_node);
+ /* In a template, callers should be building syntactic
+ representations of casts, not using this machinery. */
+ gcc_assert (!processing_template_decl);
+
+ /* Assume the conversion is invalid. */
+ if (valid_p)
+ *valid_p = false;
+
+ if (!POINTER_TYPE_P (dst_type) && !TYPE_PTRMEM_P (dst_type))
+ {
+ if (complain)
+ error ("invalid use of const_cast with type %qT, "
+ "which is not a pointer, "
+ "reference, nor a pointer-to-data-member type", dst_type);
return error_mark_node;
}
- if (TREE_CODE (type) != REFERENCE_TYPE)
+ if (TREE_CODE (TREE_TYPE (dst_type)) == FUNCTION_TYPE)
{
- expr = decay_conversion (expr);
-
- /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
- Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
- if (TREE_CODE (expr) == NOP_EXPR
- && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
- expr = TREE_OPERAND (expr, 0);
+ if (complain)
+ error ("invalid use of const_cast with type %qT, which is a pointer "
+ "or reference to a function type", dst_type);
+ return error_mark_node;
}
- intype = TREE_TYPE (expr);
-
- if (same_type_ignoring_top_level_qualifiers_p (intype, type))
- return build_static_cast (type, expr);
- else if (TREE_CODE (type) == REFERENCE_TYPE)
+ src_type = TREE_TYPE (expr);
+ /* Expressions do not really have reference types. */
+ if (TREE_CODE (src_type) == REFERENCE_TYPE)
+ src_type = TREE_TYPE (src_type);
+
+ /* [expr.const.cast]
+
+ An lvalue of type T1 can be explicitly converted to an lvalue of
+ type T2 using the cast const_cast<T2&> (where T1 and T2 are object
+ types) if a pointer to T1 can be explicitly converted to the type
+ pointer to T2 using a const_cast. */
+ if (TREE_CODE (dst_type) == REFERENCE_TYPE)
{
+ reference_type = dst_type;
if (! real_lvalue_p (expr))
{
- error ("invalid const_cast of an rvalue of type `%T' to type `%T'", intype, type);
+ if (complain)
+ error ("invalid const_cast of an rvalue of type %qT to type %qT",
+ src_type, dst_type);
return error_mark_node;
}
+ dst_type = build_pointer_type (TREE_TYPE (dst_type));
+ src_type = build_pointer_type (src_type);
+ }
+ else
+ {
+ reference_type = NULL_TREE;
+ /* If the destination type is not a reference type, the
+ lvalue-to-rvalue, array-to-pointer, and function-to-pointer
+ conversions are performed. */
+ src_type = type_decays_to (src_type);
+ if (src_type == error_mark_node)
+ return error_mark_node;
+ }
- if (comp_ptr_ttypes_const (TREE_TYPE (type), intype))
+ if ((TYPE_PTR_P (src_type) || TYPE_PTRMEM_P (src_type))
+ && comp_ptr_ttypes_const (dst_type, src_type))
+ {
+ if (valid_p)
+ *valid_p = true;
+ if (reference_type)
{
expr = build_unary_op (ADDR_EXPR, expr, 0);
- expr = build1 (NOP_EXPR, type, expr);
+ expr = build_nop (reference_type, expr);
return convert_from_reference (expr);
}
+ else
+ {
+ expr = decay_conversion (expr);
+ /* build_c_cast puts on a NOP_EXPR to make the result not an
+ lvalue. Strip such NOP_EXPRs if VALUE is being used in
+ non-lvalue context. */
+ if (TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
+ return build_nop (dst_type, expr);
+ }
}
- else if (((TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (intype) == POINTER_TYPE)
- || (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)))
- && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
- return cp_convert (type, expr);
- error ("invalid const_cast from type `%T' to type `%T'", intype, type);
+ if (complain)
+ error ("invalid const_cast from type %qT to type %qT",
+ src_type, dst_type);
return error_mark_node;
}
-/* Build an expression representing a cast to type TYPE of expression EXPR.
+tree
+build_const_cast (tree type, tree expr)
+{
+ if (type == error_mark_node || error_operand_p (expr))
+ return error_mark_node;
- ALLOW_NONCONVERTING is true if we should allow non-converting constructors
- when doing the cast. */
+ if (processing_template_decl)
+ {
+ tree t = build_min (CONST_CAST_EXPR, type, expr);
+
+ if (!TREE_SIDE_EFFECTS (t)
+ && type_dependent_expression_p (expr))
+ /* There might turn out to be side effects inside expr. */
+ TREE_SIDE_EFFECTS (t) = 1;
+ return convert_from_reference (t);
+ }
+
+ return build_const_cast_1 (type, expr, /*complain=*/true,
+ /*valid_p=*/NULL);
+}
+
+/* Build an expression representing an explicit C-style cast to type
+ TYPE of expression EXPR. */
tree
build_c_cast (tree type, tree expr)
{
tree value = expr;
- tree otype;
+ tree result;
+ bool valid_p;
- 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)
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
NIHCL uses it. It is not valid ISO C++ however. */
if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
{
- pedwarn ("ISO C++ forbids casting to an array type `%T'", type);
+ pedwarn ("ISO C++ forbids casting to an array type %qT", type);
type = build_pointer_type (TREE_TYPE (type));
}
else
{
- error ("ISO C++ forbids casting to an array type `%T'", type);
+ error ("ISO C++ forbids casting to an array type %qT", type);
return error_mark_node;
}
}
if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
{
- error ("invalid cast to function type `%T'", type);
+ error ("invalid cast to function type %qT", type);
return error_mark_node;
}
- if (TREE_CODE (type) == VOID_TYPE)
- {
- /* Conversion to void does not cause any of the normal function to
- * pointer, array to pointer and lvalue to rvalue decays. */
-
- value = convert_to_void (value, /*implicit=*/NULL);
- return value;
- }
-
- if (!complete_type_or_else (type, NULL_TREE))
- return error_mark_node;
-
- /* Convert functions and arrays to pointers and
- convert references to their expanded types,
- but don't convert any other types. If, however, we are
- casting to a class type, there's no reason to do this: the
- cast will only succeed if there is a converting constructor,
- and the default conversions will be done at that point. In
- fact, doing the default conversion here is actually harmful
- in cases like this:
-
- typedef int A[2];
- struct S { S(const A&); };
-
- since we don't want the array-to-pointer conversion done. */
- if (!IS_AGGR_TYPE (type))
- {
- if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
- || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
- /* Don't do the default conversion on a ->* expression. */
- && ! (TREE_CODE (type) == POINTER_TYPE
- && bound_pmf_p (value)))
- || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
- value = decay_conversion (value);
- }
- else if (TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
- /* However, even for class types, we still need to strip away
- the reference type, since the call to convert_force below
- does not expect the input expression to be of reference
- type. */
- value = convert_from_reference (value);
-
- otype = TREE_TYPE (value);
-
- /* Optionally warn about potentially worrisome casts. */
-
- if (warn_cast_qual
- && TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (otype) == POINTER_TYPE
- && !at_least_as_qualified_p (TREE_TYPE (type),
- TREE_TYPE (otype)))
- warning ("cast from `%T' to `%T' discards qualifiers from pointer target type",
- otype, type);
-
- if (TREE_CODE (type) == INTEGER_TYPE
- && TYPE_PTR_P (otype)
- && TYPE_PRECISION (type) != TYPE_PRECISION (otype))
- warning ("cast from pointer to integer of different size");
-
- if (TYPE_PTR_P (type)
- && TREE_CODE (otype) == INTEGER_TYPE
- && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
- /* Don't warn about converting any constant. */
- && !TREE_CONSTANT (value))
- warning ("cast to pointer from integer of different size");
+ /* A C-style cast can be a const_cast. */
+ result = build_const_cast_1 (type, value, /*complain=*/false,
+ &valid_p);
+ if (valid_p)
+ return result;
- if (TREE_CODE (type) == REFERENCE_TYPE)
- value = (convert_from_reference
- (convert_to_reference (type, value, CONV_C_CAST,
- LOOKUP_COMPLAIN, NULL_TREE)));
- else
+ /* Or a static cast. */
+ result = build_static_cast_1 (type, value, /*c_cast_p=*/true,
+ &valid_p);
+ /* Or a reinterpret_cast. */
+ if (!valid_p)
+ result = build_reinterpret_cast_1 (type, value, /*c_cast_p=*/true,
+ &valid_p);
+ /* The static_cast or reinterpret_cast may be followed by a
+ const_cast. */
+ if (valid_p
+ /* A valid cast may result in errors if, for example, a
+ conversion to am ambiguous base class is required. */
+ && !error_operand_p (result))
{
- tree ovalue;
-
- value = decl_constant_value (value);
-
- ovalue = value;
- value = convert_force (type, value, CONV_C_CAST);
+ tree result_type;
- /* Ignore any integer overflow caused by the cast. */
- if (TREE_CODE (value) == INTEGER_CST)
+ /* Non-class rvalues always have cv-unqualified type. */
+ if (!CLASS_TYPE_P (type))
+ type = TYPE_MAIN_VARIANT (type);
+ result_type = TREE_TYPE (result);
+ if (!CLASS_TYPE_P (result_type))
+ result_type = TYPE_MAIN_VARIANT (result_type);
+ /* If the type of RESULT does not match TYPE, perform a
+ const_cast to make it match. If the static_cast or
+ reinterpret_cast succeeded, we will differ by at most
+ cv-qualification, so the follow-on const_cast is guaranteed
+ to succeed. */
+ if (!same_type_p (non_reference (type), non_reference (result_type)))
{
- TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
-
- if (TREE_CODE_CLASS (TREE_CODE (ovalue)) == 'c')
- TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+ result = build_const_cast_1 (type, result, false, &valid_p);
+ gcc_assert (valid_p);
}
+ return result;
}
- /* Warn about possible alignment problems. Do this here when we will have
- instantiated any necessary template types. */
- if (STRICT_ALIGNMENT && warn_cast_align
- && TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (otype) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
- && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
- && COMPLETE_TYPE_P (TREE_TYPE (otype))
- && COMPLETE_TYPE_P (TREE_TYPE (type))
- && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
- warning ("cast from `%T' to `%T' increases required alignment of target type",
- otype, type);
-
- /* Always produce some operator for an explicit cast,
- so we can tell (for -pedantic) that the cast is no lvalue. */
- if (TREE_CODE (type) != REFERENCE_TYPE && value == expr
- && real_lvalue_p (value))
- value = non_lvalue (value);
-
- return value;
+ return error_mark_node;
}
\f
/* Build an assignment expression of lvalue LHS from value RHS.
return error_mark_node;
return build2 (COMPOUND_EXPR, lhstype, lhs, newrhs);
+ case MIN_EXPR:
+ 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, lv_assign))
+ return error_mark_node;
+
+ gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))
+ && !TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 1)));
+
+ lhs = build3 (COND_EXPR, TREE_TYPE (lhs),
+ build2 (TREE_CODE (lhs) == MIN_EXPR ? LE_EXPR : GE_EXPR,
+ boolean_type_node,
+ TREE_OPERAND (lhs, 0),
+ TREE_OPERAND (lhs, 1)),
+ TREE_OPERAND (lhs, 0),
+ TREE_OPERAND (lhs, 1));
+ /* Fall through. */
+
/* Handle (a ? b : c) used as an "lvalue". */
case COND_EXPR:
{
/* 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;
newrhs = cp_build_binary_op (modifycode, lhs, rhs);
if (newrhs == error_mark_node)
{
- error (" in evaluation of `%Q(%#T, %#T)'", modifycode,
+ error (" in evaluation of %<%Q(%#T, %#T)%>", modifycode,
TREE_TYPE (lhs), TREE_TYPE (rhs));
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 (!same_or_base_type_p (TYPE_MAIN_VARIANT (lhstype),
TYPE_MAIN_VARIANT (TREE_TYPE (rhs))))
{
- error ("incompatible types in assignment of `%T' to `%T'",
+ error ("incompatible types in assignment of %qT to %qT",
TREE_TYPE (rhs), lhstype);
return error_mark_node;
}
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");
- }
+ if (kind != bk_via_virtual)
+ result = BINFO_OFFSET (binfo);
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));
- }
+ tree virt_binfo = binfo_from_vbase (binfo);
+
+ /* This is a reinterpret cast, we choose to do nothing. */
+ 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
{
- virt_binfo = binfo_from_vbase (binfo);
- if (!virt_binfo)
- result = BINFO_OFFSET (binfo);
- else
+ binfo = lookup_base (from, to, c_cast_p ? ba_unique : ba_check, &kind);
+ if (binfo)
{
- /* This is a reinterpret cast, we choose to do nothing. */
- if (force)
- warning ("pointer to member cast via virtual base `%T'",
- BINFO_TYPE (virt_binfo));
+ if (kind != bk_via_virtual)
+ result = size_diffop (size_zero_node, BINFO_OFFSET (binfo));
else
- error ("pointer to member conversion via virtual base `%T'",
- BINFO_TYPE (virt_binfo));
+ {
+ /* 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 (convert_to_integer (ptrdiff_type_node, result));
+ return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node,
+ result));
}
/* Return a constructor for the pointer-to-member-function TYPE using
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;
if (!force
&& !can_convert_arg (to_type, TREE_TYPE (pfn), pfn))
- error ("invalid conversion to type `%T' from type `%T'",
- to_type, pfn_type);
+ error ("invalid conversion to type %qT from type %qT",
+ to_type, pfn_type);
n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
- force);
+ 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));
fn; the call will do the opposite adjustment. */
tree orig_class = DECL_CONTEXT (fn);
tree binfo = binfo_or_else (orig_class, fn_class);
- *delta = fold (build2 (PLUS_EXPR, TREE_TYPE (*delta),
- *delta, BINFO_OFFSET (binfo)));
+ *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
+ *delta, BINFO_OFFSET (binfo));
+ *delta = fold_if_not_in_template (*delta);
/* We set PFN to the vtable offset at which the function can be
found, plus one (unless ptrmemfunc_vbit_in_delta, in which
case delta is shifted left, and then incremented). */
*pfn = DECL_VINDEX (fn);
- *pfn = fold (build2 (MULT_EXPR, integer_type_node, *pfn,
- TYPE_SIZE_UNIT (vtable_entry_type)));
+ *pfn = build2 (MULT_EXPR, integer_type_node, *pfn,
+ TYPE_SIZE_UNIT (vtable_entry_type));
+ *pfn = fold_if_not_in_template (*pfn);
switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
{
case ptrmemfunc_vbit_in_pfn:
- *pfn = fold (build2 (PLUS_EXPR, integer_type_node, *pfn,
- integer_one_node));
+ *pfn = build2 (PLUS_EXPR, integer_type_node, *pfn,
+ integer_one_node);
+ *pfn = fold_if_not_in_template (*pfn);
break;
case ptrmemfunc_vbit_in_delta:
- *delta = fold (build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
- *delta, integer_one_node));
- *delta = fold (build2 (PLUS_EXPR, TREE_TYPE (*delta),
- *delta, integer_one_node));
+ *delta = build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
+ *delta, integer_one_node);
+ *delta = fold_if_not_in_template (*delta);
+ *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
+ *delta, integer_one_node);
+ *delta = fold_if_not_in_template (*delta);
break;
default:
gcc_unreachable ();
}
- *pfn = fold (build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),
- *pfn));
+ *pfn = build_nop (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
+ *pfn = fold_if_not_in_template (*pfn);
}
}
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 `%D'",
- errtype, parmnum, fndecl);
- else
- warning ("%s to non-pointer type `%T' 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 `%T' for %s %P of `%D'",
- TREE_TYPE (expr), errtype, parmnum, fndecl);
- else
- warning ("%s to `%T' from `%T'", 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 `%E' for %s %P of `%D'",
- expr, errtype, parmnum, fndecl);
- else
- warning ("%s of negative value `%E' to `%T'",
- errtype, expr, type);
- }
-
- overflow_warning (expr);
-
- if (TREE_CONSTANT (expr))
- expr = fold (expr);
- }
- return expr;
-}
-
/* 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]
if (rhstype == unknown_type_node)
instantiate_type (type, rhs, tf_error | tf_warning);
else if (fndecl)
- error ("cannot convert `%T' to `%T' for argument `%P' to `%D'",
- rhstype, type, parmnum, fndecl);
+ error ("cannot convert %qT to %qT for argument %qP to %qD",
+ rhstype, type, parmnum, fndecl);
else
- error ("cannot convert `%T' to `%T' in %s", rhstype, type,
- errtype);
+ error ("cannot convert %qT to %qT in %s", rhstype, type, errtype);
return error_mark_node;
}
}
|| (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 (fndecl)
{
if (warningcount > savew)
- cp_warning_at ("in passing argument %P of `%+D'", parmnum, fndecl);
+ cp_warning_at ("in passing argument %P of %q+D", parmnum, fndecl);
else if (errorcount > savee)
- cp_error_at ("in passing argument %P of `%+D'", parmnum, fndecl);
+ cp_error_at ("in passing argument %P of %q+D", parmnum, fndecl);
}
return rhs;
}
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;
}
}
|| TREE_PUBLIC (whats_returned)))
{
if (TREE_CODE (valtype) == REFERENCE_TYPE)
- cp_warning_at ("reference to local variable `%D' returned",
+ cp_warning_at ("reference to local variable %qD returned",
whats_returned);
else
- cp_warning_at ("address of local variable `%D' returned",
+ cp_warning_at ("address of local variable %qD returned",
whats_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 declared `throw()' (or -fcheck-new is in effect)");
+ 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_ecpp
}
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 castness
+ 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. */
static void
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;
+}