/* 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, 2005, 2006, 2007
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
#include "params.h"
static tree pfn_from_ptrmemfunc (tree);
-static tree convert_for_assignment (tree, tree, const char *, tree, int);
+static tree delta_from_ptrmemfunc (tree);
+static tree convert_for_assignment (tree, tree, const char *, tree, int,
+ tsubst_flags_t);
static tree cp_pointer_int_sum (enum tree_code, tree, tree);
-static tree rationalize_conditional_expr (enum tree_code, tree);
+static tree rationalize_conditional_expr (enum tree_code, tree,
+ tsubst_flags_t);
static int comp_ptr_ttypes_real (tree, tree, int);
static bool comp_except_types (tree, tree, bool);
static bool comp_array_types (const_tree, const_tree, bool);
static bool casts_away_constness (tree, tree);
static void maybe_warn_about_returning_address_of_local (tree);
static tree lookup_destructor (tree, tree, tree);
-static int convert_arguments (int, tree *, tree, tree, tree, int);
+static int convert_arguments (int, tree *, tree, tree, tree, int,
+ tsubst_flags_t);
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.)
case. See that function for documentation fo the parameters. */
static tree
-composite_pointer_type_r (tree t1, tree t2, const char* location)
+composite_pointer_type_r (tree t1, tree t2, const char* location,
+ tsubst_flags_t complain)
{
tree pointee1;
tree pointee2;
&& TREE_CODE (pointee2) == POINTER_TYPE)
|| (TYPE_PTR_TO_MEMBER_P (pointee1)
&& TYPE_PTR_TO_MEMBER_P (pointee2)))
- result_type = composite_pointer_type_r (pointee1, pointee2, location);
+ result_type = composite_pointer_type_r (pointee1, pointee2, location,
+ complain);
else
{
- pedwarn ("%s between distinct pointer types %qT and %qT "
- "lacks a cast",
- location, t1, t2);
+ if (complain & tf_error)
+ pedwarn ("%s between distinct pointer types %qT and %qT "
+ "lacks a cast",
+ location, t1, t2);
result_type = void_type_node;
}
result_type = cp_build_qualified_type (result_type,
if (TYPE_PTR_TO_MEMBER_P (t1))
{
if (!same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
- TYPE_PTRMEM_CLASS_TYPE (t2)))
+ TYPE_PTRMEM_CLASS_TYPE (t2))
+ && (complain & tf_error))
pedwarn ("%s between distinct pointer types %qT and %qT "
"lacks a cast",
location, t1, t2);
tree
composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
- const char* location)
+ const char* location, tsubst_flags_t complain)
{
tree class1;
tree class2;
tree attributes;
tree result_type;
- if (pedantic && TYPE_PTRFN_P (t2))
+ if (pedantic && TYPE_PTRFN_P (t2) && (complain & tf_error))
pedwarn ("ISO C++ forbids %s between pointer of type %<void *%> "
"and pointer-to-function", location);
result_type
(cp_build_qualified_type (class2, TYPE_QUALS (class1))));
else
{
- error ("%s between distinct pointer types %qT and %qT "
- "lacks a cast", location, t1, t2);
+ if (complain & tf_error)
+ 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 %qT and %qT "
- "lacks a cast", location, t1, t2);
+ if (complain & tf_error)
+ error ("%s between distinct pointer-to-member types %qT and %qT "
+ "lacks a cast", location, t1, t2);
return error_mark_node;
}
}
- return composite_pointer_type_r (t1, t2, location);
+ return composite_pointer_type_r (t1, t2, location, complain);
}
/* Return the merged type of two types.
if (code1 == POINTER_TYPE)
t1 = build_pointer_type (target);
else
- t1 = build_reference_type (target);
+ t1 = cp_build_reference_type (target, TYPE_REF_IS_RVALUE (t1));
t1 = build_type_attribute_variant (t1, attributes);
t1 = cp_build_qualified_type (t1, quals);
|| (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
|| (TYPE_PTRMEMFUNC_P (t1) && TYPE_PTRMEMFUNC_P (t2)))
return composite_pointer_type (t1, t2, error_mark_node, error_mark_node,
- "conversion");
+ "conversion", tf_warning_or_error);
else
gcc_unreachable ();
}
/* Compare the types. Break out if they could be the same. */
switch (TREE_CODE (t1))
{
+ case VOID_TYPE:
+ case BOOLEAN_TYPE:
+ /* All void and bool types are the same. */
+ break;
+
+ case INTEGER_TYPE:
+ case FIXED_POINT_TYPE:
+ case REAL_TYPE:
+ /* With these nodes, we can't determine type equivalence by
+ looking at what is stored in the nodes themselves, because
+ two nodes might have different TYPE_MAIN_VARIANTs but still
+ represent the same type. For example, wchar_t and int could
+ have the same properties (TYPE_PRECISION, TYPE_MIN_VALUE,
+ TYPE_MAX_VALUE, etc.), but have different TYPE_MAIN_VARIANTs
+ and are distinct types. On the other hand, int and the
+ following typedef
+
+ typedef int INT __attribute((may_alias));
+
+ have identical properties, different TYPE_MAIN_VARIANTs, but
+ represent the same type. The canonical type system keeps
+ track of equivalence in this case, so we fall back on it. */
+ return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
+
case TEMPLATE_TEMPLATE_PARM:
case BOUND_TEMPLATE_TEMPLATE_PARM:
if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
complain);
}
+/* Return the size of the type, without producing any warnings for
+ types whose size cannot be taken. This routine should be used only
+ in some other routine that has already produced a diagnostic about
+ using the size of such a type. */
+tree
+cxx_sizeof_nowarn (tree type)
+{
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == VOID_TYPE
+ || TREE_CODE (type) == ERROR_MARK)
+ return size_one_node;
+ else if (!COMPLETE_TYPE_P (type))
+ return size_zero_node;
+ else
+ return cxx_sizeof_or_alignof_type (type, SIZEOF_EXPR, false);
+}
+
/* Process a sizeof expression where the operand is an expression. */
static tree
-cxx_sizeof_expr (tree e)
+cxx_sizeof_expr (tree e, tsubst_flags_t complain)
{
if (e == error_mark_node)
return error_mark_node;
&& TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
{
- error ("invalid application of %<sizeof%> to a bit-field");
+ if (complain & tf_error)
+ error ("invalid application of %<sizeof%> to a bit-field");
+ else
+ return error_mark_node;
e = char_type_node;
}
else if (is_overloaded_fn (e))
{
- pedwarn ("ISO C++ forbids applying %<sizeof%> to an expression of "
- "function type");
+ if (complain & tf_error)
+ pedwarn ("ISO C++ forbids applying %<sizeof%> to an expression of "
+ "function type");
+ else
+ return error_mark_node;
e = char_type_node;
}
else if (type_unknown_p (e))
{
- cxx_incomplete_type_error (e, TREE_TYPE (e));
+ if (complain & tf_error)
+ cxx_incomplete_type_error (e, TREE_TYPE (e));
+ else
+ return error_mark_node;
e = char_type_node;
}
else
e = TREE_TYPE (e);
- return cxx_sizeof_or_alignof_type (e, SIZEOF_EXPR, true);
+ return cxx_sizeof_or_alignof_type (e, SIZEOF_EXPR, complain & tf_error);
}
/* Implement the __alignof keyword: Return the minimum required
"aligned" __attribute__ specification). */
static tree
-cxx_alignof_expr (tree e)
+cxx_alignof_expr (tree e, tsubst_flags_t complain)
{
tree t;
&& TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL
&& DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
{
- error ("invalid application of %<__alignof%> to a bit-field");
+ if (complain & tf_error)
+ error ("invalid application of %<__alignof%> to a bit-field");
+ else
+ return error_mark_node;
t = size_one_node;
}
else if (TREE_CODE (e) == COMPONENT_REF
t = size_int (DECL_ALIGN_UNIT (TREE_OPERAND (e, 1)));
else if (is_overloaded_fn (e))
{
- pedwarn ("ISO C++ forbids applying %<__alignof%> to an expression of "
- "function type");
+ if (complain & tf_error)
+ pedwarn ("ISO C++ forbids applying %<__alignof%> to an expression of "
+ "function type");
+ else
+ return error_mark_node;
if (TREE_CODE (e) == FUNCTION_DECL)
t = size_int (DECL_ALIGN_UNIT (e));
else
}
else if (type_unknown_p (e))
{
- cxx_incomplete_type_error (e, TREE_TYPE (e));
+ if (complain & tf_error)
+ cxx_incomplete_type_error (e, TREE_TYPE (e));
+ else
+ return error_mark_node;
t = size_one_node;
}
else
- return cxx_sizeof_or_alignof_type (TREE_TYPE (e), ALIGNOF_EXPR, true);
+ return cxx_sizeof_or_alignof_type (TREE_TYPE (e), ALIGNOF_EXPR,
+ complain & tf_error);
return fold_convert (size_type_node, t);
}
is an expression. */
tree
-cxx_sizeof_or_alignof_expr (tree e, enum tree_code op)
+cxx_sizeof_or_alignof_expr (tree e, enum tree_code op, bool complain)
{
if (op == SIZEOF_EXPR)
- return cxx_sizeof_expr (e);
+ return cxx_sizeof_expr (e, complain? tf_warning_or_error : tf_none);
else
- return cxx_alignof_expr (e);
+ return cxx_alignof_expr (e, complain? tf_warning_or_error : tf_none);
}
\f
/* EXPR is being used in a context that is not a function call.
violates these rules. */
bool
-invalid_nonstatic_memfn_p (const_tree expr)
+invalid_nonstatic_memfn_p (const_tree expr, tsubst_flags_t complain)
{
if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE)
{
- error ("invalid use of non-static member function");
+ if (complain & tf_error)
+ error ("invalid use of non-static member function");
return true;
}
return false;
switch (TREE_CODE (exp))
{
case COND_EXPR:
- if (!is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1)))
+ if (!is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1)
+ ? TREE_OPERAND (exp, 1)
+ : TREE_OPERAND (exp, 0)))
return NULL_TREE;
return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 2));
tree field;
field = TREE_OPERAND (exp, 1);
- if (TREE_CODE (field) != FIELD_DECL || !DECL_C_BIT_FIELD (field))
+ if (TREE_CODE (field) != FIELD_DECL || !DECL_BIT_FIELD_TYPE (field))
return NULL_TREE;
if (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (exp), DECL_BIT_FIELD_TYPE (field)))
return DECL_BIT_FIELD_TYPE (field);
}
+ CASE_CONVERT:
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp, 0)))
+ == TYPE_MAIN_VARIANT (TREE_TYPE (exp)))
+ return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
+ /* Fallthrough. */
+
default:
return NULL_TREE;
}
error ("void value not ignored as it ought to be");
return error_mark_node;
}
- if (invalid_nonstatic_memfn_p (exp))
+ if (invalid_nonstatic_memfn_p (exp, tf_warning_or_error))
return error_mark_node;
if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
- return build_unary_op (ADDR_EXPR, exp, 0);
+ return cp_build_unary_op (ADDR_EXPR, exp, 0, tf_warning_or_error);
if (code == ARRAY_TYPE)
{
tree adr;
}
/* This way is better for a COMPONENT_REF since it can
simplify the offset for a component. */
- adr = build_unary_op (ADDR_EXPR, exp, 1);
+ adr = cp_build_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error);
return cp_convert (ptrtype, adr);
}
t = TREE_TYPE (totype);
if (!same_type_p (t, char_type_node)
+ && !same_type_p (t, char16_type_node)
+ && !same_type_p (t, char32_type_node)
&& !same_type_p (t, wchar_type_node))
return 0;
if (TREE_CODE (exp) == STRING_CST)
{
- /* Make sure that we don't try to convert between char and wchar_t. */
+ /* Make sure that we don't try to convert between char and wide chars. */
if (!same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (exp))), t))
return 0;
}
get it there. */
static tree
-rationalize_conditional_expr (enum tree_code code, tree t)
+rationalize_conditional_expr (enum tree_code code, tree t,
+ tsubst_flags_t complain)
{
/* For MIN_EXPR or MAX_EXPR, fold-const.c has arranged things so that
the first operand is always the one to be used if both operands
? LE_EXPR : GE_EXPR),
op0, TREE_CODE (op0),
op1, TREE_CODE (op1),
- /*overloaded_p=*/NULL),
- build_unary_op (code, op0, 0),
- build_unary_op (code, op1, 0));
+ /*overloaded_p=*/NULL,
+ complain),
+ cp_build_unary_op (code, op0, 0, complain),
+ cp_build_unary_op (code, op1, 0, complain),
+ complain);
}
return
build_conditional_expr (TREE_OPERAND (t, 0),
- build_unary_op (code, TREE_OPERAND (t, 1), 0),
- build_unary_op (code, TREE_OPERAND (t, 2), 0));
+ cp_build_unary_op (code, TREE_OPERAND (t, 1), 0,
+ complain),
+ cp_build_unary_op (code, TREE_OPERAND (t, 2), 0,
+ complain),
+ complain);
}
/* Given the TYPE of an anonymous union field inside T, return the
tree
build_class_member_access_expr (tree object, tree member,
- tree access_path, bool preserve_reference)
+ tree access_path, bool preserve_reference,
+ tsubst_flags_t complain)
{
tree object_type;
tree member_scope;
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
- error ("request for member %qD in %qE, which is of non-class type %qT",
- member, object, object_type);
+ if (complain & tf_error)
+ error ("request for member %qD in %qE, which is of non-class type %qT",
+ member, object, object_type);
return error_mark_node;
}
warn_deprecated_use (member);
}
else
- member_scope = BINFO_TYPE (BASELINK_BINFO (member));
+ member_scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (member));
/* If MEMBER is from an anonymous aggregate, MEMBER_SCOPE will
presently be the anonymous union. Go outwards until we find a
type related to OBJECT_TYPE. */
member_scope = TYPE_CONTEXT (member_scope);
if (!member_scope || !DERIVED_FROM_P (member_scope, object_type))
{
- if (TREE_CODE (member) == FIELD_DECL)
- error ("invalid use of nonstatic data member %qE", member);
- else
- error ("%qD is not a member of %qT", member, object_type);
+ if (complain & tf_error)
+ {
+ if (TREE_CODE (member) == FIELD_DECL)
+ error ("invalid use of nonstatic data member %qE", member);
+ else
+ error ("%qD is not a member of %qT", member, object_type);
+ }
return error_mark_node;
}
{
tree temp = unary_complex_lvalue (ADDR_EXPR, object);
if (temp)
- object = build_indirect_ref (temp, NULL);
+ object = cp_build_indirect_ref (temp, NULL, complain);
}
/* In [expr.ref], there is an explicit list of the valid choices for
offsetof macro. */
if (null_object_p && kind == bk_via_virtual)
{
- error ("invalid access to non-static data member %qD of "
- "NULL object",
- member);
- error ("(perhaps the %<offsetof%> macro was used incorrectly)");
+ if (complain & tf_error)
+ {
+ error ("invalid access to non-static data member %qD of "
+ "NULL object",
+ member);
+ error ("(perhaps the %<offsetof%> macro was used incorrectly)");
+ }
return error_mark_node;
}
if (null_object_p && warn_invalid_offsetof
&& CLASSTYPE_NON_POD_P (object_type)
&& !DECL_FIELD_IS_BASE (member)
- && !skip_evaluation)
+ && !skip_evaluation
+ && (complain & tf_warning))
{
- warning (0, "invalid access to non-static data member %qD of NULL object",
- member);
- warning (0, "(perhaps the %<offsetof%> macro was used incorrectly)");
+ warning (OPT_Winvalid_offsetof,
+ "invalid access to non-static data member %qD "
+ " of NULL object", member);
+ warning (OPT_Winvalid_offsetof,
+ "(perhaps the %<offsetof%> macro was used incorrectly)");
}
/* If MEMBER is from an anonymous aggregate, we have converted
object = build_class_member_access_expr (object,
anonymous_union,
/*access_path=*/NULL_TREE,
- preserve_reference);
+ preserve_reference,
+ complain);
}
/* Compute the type of the field, as described in [expr.ref]. */
}
else
{
- error ("invalid use of %qD", member);
+ if (complain & tf_error)
+ error ("invalid use of %qD", member);
return error_mark_node;
}
be a template via the use of the "A::template B" syntax. */
tree
-finish_class_member_access_expr (tree object, tree name, bool template_p)
+finish_class_member_access_expr (tree object, tree name, bool template_p,
+ tsubst_flags_t complain)
{
tree expr;
tree object_type;
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
- error ("request for member %qD in %qE, which is of non-class type %qT",
- name, object, object_type);
+ if (complain & tf_error)
+ 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 %qT",
- scope, name, object_type);
+ if (complain & tf_error)
+ 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 ("%qT is not a base of %qT", scope, object_type);
+ if (complain & tf_error)
+ error ("%qT is not a base of %qT", scope, object_type);
return error_mark_node;
}
}
/*want_type=*/false);
if (member == NULL_TREE)
{
- error ("%qD has no member named %qE", object_type, name);
+ if (complain & tf_error)
+ 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 ("%qD is not a member template function", name);
+ if (complain & tf_error)
+ error ("%qD is not a member template function", name);
return error_mark_node;
}
}
check_template_keyword (member);
expr = build_class_member_access_expr (object, member, access_path,
- /*preserve_reference=*/false);
+ /*preserve_reference=*/false,
+ complain);
if (processing_template_decl && expr != error_mark_node)
{
if (BASELINK_P (member))
Must also handle REFERENCE_TYPEs for C++. */
tree
-build_x_indirect_ref (tree expr, const char *errorstring)
+build_x_indirect_ref (tree expr, const char *errorstring,
+ tsubst_flags_t complain)
{
tree orig_expr = expr;
tree rval;
}
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
- NULL_TREE, /*overloaded_p=*/NULL);
+ NULL_TREE, /*overloaded_p=*/NULL, complain);
if (!rval)
- rval = build_indirect_ref (expr, errorstring);
+ rval = cp_build_indirect_ref (expr, errorstring, complain);
if (processing_template_decl && rval != error_mark_node)
return build_min_non_dep (INDIRECT_REF, rval, orig_expr);
return rval;
}
+/* Helper function called from c-common. */
tree
build_indirect_ref (tree ptr, const char *errorstring)
{
+ return cp_build_indirect_ref (ptr, errorstring, tf_warning_or_error);
+}
+
+tree
+cp_build_indirect_ref (tree ptr, const char *errorstring,
+ tsubst_flags_t complain)
+{
tree pointer, type;
if (ptr == error_mark_node)
types. */
tree t = canonical_type_variant (TREE_TYPE (type));
- if (TREE_CODE (ptr) == CONVERT_EXPR
- || TREE_CODE (ptr) == NOP_EXPR
+ if (CONVERT_EXPR_P (ptr)
|| TREE_CODE (ptr) == VIEW_CONVERT_EXPR)
{
/* If a warning is issued, mark it to avoid duplicates from
{
/* A pointer to incomplete type (other than cv void) can be
dereferenced [expr.unary.op]/1 */
- error ("%qT is not a pointer-to-object type", type);
+ if (complain & tf_error)
+ error ("%qT is not a pointer-to-object type", type);
return error_mark_node;
}
else if (TREE_CODE (pointer) == ADDR_EXPR
return ref;
}
}
+ else if (!(complain & tf_error))
+ /* Don't emit any errors; we'll just return ERROR_MARK_NODE later. */
+ ;
/* `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))
return build_conditional_expr
(TREE_OPERAND (array, 0),
build_array_ref (TREE_OPERAND (array, 1), idx),
- build_array_ref (TREE_OPERAND (array, 2), idx));
+ build_array_ref (TREE_OPERAND (array, 2), idx),
+ tf_warning_or_error);
default:
break;
warn_array_subscript_with_type_char (idx);
- return build_indirect_ref (cp_build_binary_op (PLUS_EXPR, ar, ind),
- "array indexing");
+ return cp_build_indirect_ref (cp_build_binary_op (PLUS_EXPR, ar, ind,
+ tf_warning_or_error),
+ "array indexing",
+ tf_warning_or_error);
}
}
\f
/* Start by extracting all the information from the PMF itself. */
e3 = pfn_from_ptrmemfunc (function);
- delta = build_ptrmemfunc_access_expr (function, delta_identifier);
+ delta = delta_from_ptrmemfunc (function);
idx = build1 (NOP_EXPR, vtable_index_type, e3);
switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
{
case ptrmemfunc_vbit_in_pfn:
- e1 = cp_build_binary_op (BIT_AND_EXPR, idx, integer_one_node);
- idx = cp_build_binary_op (MINUS_EXPR, idx, integer_one_node);
+ e1 = cp_build_binary_op (BIT_AND_EXPR, idx, integer_one_node,
+ tf_warning_or_error);
+ idx = cp_build_binary_op (MINUS_EXPR, idx, integer_one_node,
+ tf_warning_or_error);
break;
case ptrmemfunc_vbit_in_delta:
- e1 = cp_build_binary_op (BIT_AND_EXPR, delta, integer_one_node);
- delta = cp_build_binary_op (RSHIFT_EXPR, delta, integer_one_node);
+ e1 = cp_build_binary_op (BIT_AND_EXPR, delta, integer_one_node,
+ tf_warning_or_error);
+ delta = cp_build_binary_op (RSHIFT_EXPR, delta, integer_one_node,
+ tf_warning_or_error);
break;
default:
/* Next extract the vtable pointer from the object. */
vtbl = build1 (NOP_EXPR, build_pointer_type (vtbl_ptr_type_node),
instance_ptr);
- vtbl = build_indirect_ref (vtbl, NULL);
+ vtbl = cp_build_indirect_ref (vtbl, NULL, tf_warning_or_error);
/* Finally, extract the function pointer from the vtable. */
e2 = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
fold_convert (sizetype, idx));
- e2 = build_indirect_ref (e2, NULL);
+ e2 = cp_build_indirect_ref (e2, NULL, tf_warning_or_error);
TREE_CONSTANT (e2) = 1;
- TREE_INVARIANT (e2) = 1;
/* When using function descriptors, the address of the
vtable entry is treated as a function pointer. */
if (TARGET_VTABLE_USES_DESCRIPTORS)
e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
- build_unary_op (ADDR_EXPR, e2, /*noconvert=*/1));
+ cp_build_unary_op (ADDR_EXPR, e2, /*noconvert=*/1,
+ tf_warning_or_error));
e2 = fold_convert (TREE_TYPE (e3), e2);
- e1 = build_conditional_expr (e1, e2, e3);
+ e1 = build_conditional_expr (e1, e2, e3, tf_warning_or_error);
/* Make sure this doesn't get evaluated first inside one of the
branches of the COND_EXPR. */
return function;
}
+/* Used by the C-common bits. */
tree
build_function_call (tree function, tree params)
{
+ return cp_build_function_call (function, params, tf_warning_or_error);
+}
+
+tree
+cp_build_function_call (tree function, tree params, tsubst_flags_t complain)
+{
tree fntype, fndecl;
tree name = NULL_TREE;
int is_method;
fndecl = function;
/* Convert anything with function type to a pointer-to-function. */
- if (pedantic && DECL_MAIN_P (function))
+ if (pedantic && DECL_MAIN_P (function) && (complain & tf_error))
pedwarn ("ISO C++ forbids calling %<::main%> from within program");
/* Differs from default_conversion by not setting TREE_ADDRESSABLE
if (TYPE_PTRMEMFUNC_P (fntype))
{
- error ("must use %<.*%> or %<->*%> to call pointer-to-member "
- "function in %<%E (...)%>",
- original);
+ if (complain & tf_error)
+ 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 ("%qE cannot be used as a function", original);
+ if (complain & tf_error)
+ error ("%qE cannot be used as a function", original);
return error_mark_node;
}
/* Convert the parameters to the types declared in the
function prototype, or apply default promotions. */
nargs = convert_arguments (nargs, argarray, parm_types,
- params, fndecl, LOOKUP_NORMAL);
+ params, fndecl, LOOKUP_NORMAL,
+ complain);
if (nargs < 0)
return error_mark_node;
+ /* Check that arguments to builtin functions match the expectations. */
+ if (fndecl
+ && DECL_BUILT_IN (fndecl)
+ && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ && !check_builtin_function_arguments (fndecl, nargs, argarray))
+ return error_mark_node;
+
/* Check for errors in format strings and inappropriately
null parameters. */
-
check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
parm_types);
static int
convert_arguments (int nargs, tree *argarray,
- tree typelist, tree values, tree fndecl, int flags)
+ tree typelist, tree values, tree fndecl, int flags,
+ tsubst_flags_t complain)
{
tree typetail, valtail;
const char *called_thing = 0;
if (type == void_type_node)
{
- if (fndecl)
- {
- error ("too many arguments to %s %q+#D", called_thing, fndecl);
- error ("at this point in file");
- }
- else
- error ("too many arguments to function");
- return i;
+ if (complain & tf_error)
+ {
+ if (fndecl)
+ {
+ error ("too many arguments to %s %q+#D",
+ called_thing, fndecl);
+ error ("at this point in file");
+ }
+ else
+ error ("too many arguments to function");
+ return i;
+ }
+ else
+ return -1;
}
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
if (!COMPLETE_TYPE_P (complete_type (type)))
{
- if (fndecl)
- error ("parameter %P of %qD has incomplete type %qT",
- i, fndecl, type);
- else
- error ("parameter %P has incomplete type %qT", i, type);
+ if (complain & tf_error)
+ {
+ if (fndecl)
+ error ("parameter %P of %qD has incomplete type %qT",
+ i, fndecl, type);
+ else
+ error ("parameter %P has incomplete type %qT", i, type);
+ }
parmval = error_mark_node;
}
else
{
parmval = convert_for_initialization
(NULL_TREE, type, val, flags,
- "argument passing", fndecl, i);
+ "argument passing", fndecl, i, complain);
parmval = convert_for_arg_passing (type, parmval);
}
}
else
{
- if (fndecl)
- {
- error ("too few arguments to %s %q+#D", called_thing, fndecl);
- error ("at this point in file");
- }
- else
- error ("too few arguments to function");
+ if (complain & tf_error)
+ {
+ if (fndecl)
+ {
+ error ("too few arguments to %s %q+#D",
+ called_thing, fndecl);
+ error ("at this point in file");
+ }
+ else
+ error ("too few arguments to function");
+ }
return -1;
}
}
tree
build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code,
- tree arg2, enum tree_code arg2_code, bool *overloaded_p)
+ tree arg2, enum tree_code arg2_code, bool *overloaded_p,
+ tsubst_flags_t complain)
{
tree orig_arg1;
tree orig_arg2;
expr = build_m_component_ref (arg1, arg2);
else
expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
- overloaded_p);
+ overloaded_p, complain);
/* Check for cases such as x+y<<z which users are likely to
misinterpret. But don't warn about obj << x + y, since that is a
return expr;
}
+/* For the c-common bits. */
+tree
+build_binary_op (enum tree_code code, tree op0, tree op1,
+ int convert_p ATTRIBUTE_UNUSED)
+{
+ return cp_build_binary_op(code, op0, op1, tf_warning_or_error);
+}
+
+
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
This function differs from `build' in several ways:
multiple inheritance, and deal with pointer to member functions. */
tree
-build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
- int convert_p ATTRIBUTE_UNUSED)
+cp_build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
+ tsubst_flags_t complain)
{
tree op0, op1;
enum tree_code code0, code1;
Also implies COMMON. */
int short_compare = 0;
- /* Nonzero if this is a right-shift operation, which can be computed on the
- original short and then promoted if the operand is a promoted short. */
- int short_shift = 0;
-
/* Nonzero means set RESULT_TYPE to the common type of the args. */
int common = 0;
tree t = instantiate_type (TREE_TYPE (op1), op0, tf_none);
if (t != error_mark_node)
{
- pedwarn ("assuming cast to type %qT from overloaded function",
- TREE_TYPE (t));
+ if (complain & tf_error)
+ 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 %qT from overloaded function",
- TREE_TYPE (t));
+ if (complain & tf_error)
+ pedwarn ("assuming cast to type %qT from overloaded function",
+ TREE_TYPE (t));
op1 = t;
}
}
if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_lt (op1, integer_zero_node))
- warning (0, "right shift count is negative");
+ {
+ if (complain & tf_warning)
+ warning (0, "right shift count is negative");
+ }
else
{
- if (! integer_zerop (op1))
- short_shift = 1;
- if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
+ if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0
+ && (complain & tf_warning))
warning (0, "right shift count >= width of type");
}
}
if (TREE_CODE (op1) == INTEGER_CST)
{
if (tree_int_cst_lt (op1, integer_zero_node))
- warning (0, "left shift count is negative");
+ {
+ if (complain & tf_warning)
+ warning (0, "left shift count is negative");
+ }
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning (0, "left shift count >= width of type");
+ {
+ if (complain & tf_warning)
+ 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 (0, (code == LROTATE_EXPR)
- ? G_("left rotate count is negative")
- : G_("right rotate count is negative"));
+ {
+ if (complain & tf_warning)
+ warning (0, (code == LROTATE_EXPR)
+ ? G_("left rotate count is negative")
+ : G_("right rotate count is negative"));
+ }
else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
- warning (0, (code == LROTATE_EXPR)
- ? G_("left rotate count >= width of type")
- : G_("right rotate count >= width of type"));
+ {
+ if (complain & tf_warning)
+ warning (0, (code == LROTATE_EXPR)
+ ? G_("left rotate count >= width of type")
+ : G_("right rotate count >= width of type"));
+ }
}
/* Convert the shift-count to an integer, regardless of
size of value being shifted. */
case EQ_EXPR:
case NE_EXPR:
- if (code0 == REAL_TYPE || code1 == REAL_TYPE)
+ if ((complain & tf_warning)
+ && (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1)))
warning (OPT_Wfloat_equal,
"comparing floating point with == or != is unsafe");
- if ((TREE_CODE (orig_op0) == STRING_CST && !integer_zerop (op1))
- || (TREE_CODE (orig_op1) == STRING_CST && !integer_zerop (op0)))
+ if ((complain & tf_warning)
+ && ((TREE_CODE (orig_op0) == STRING_CST && !integer_zerop (op1))
+ || (TREE_CODE (orig_op1) == STRING_CST && !integer_zerop (op0))))
warning (OPT_Waddress, "comparison with string literal results in unspecified behaviour");
build_type = boolean_type_node;
else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
|| (TYPE_PTRMEM_P (type0) && TYPE_PTRMEM_P (type1)))
result_type = composite_pointer_type (type0, type1, op0, op1,
- "comparison");
+ "comparison", complain);
else if ((code0 == POINTER_TYPE || TYPE_PTRMEM_P (type0))
&& null_ptr_cst_p (op1))
{
if (TREE_CODE (op0) == ADDR_EXPR
&& decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
- warning (OPT_Waddress, "the address of %qD will never be NULL",
- TREE_OPERAND (op0, 0));
+ {
+ if (complain & tf_warning)
+ warning (OPT_Waddress, "the address of %qD will never be NULL",
+ TREE_OPERAND (op0, 0));
+ }
result_type = type0;
}
else if ((code1 == POINTER_TYPE || TYPE_PTRMEM_P (type1))
{
if (TREE_CODE (op1) == ADDR_EXPR
&& decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
- warning (OPT_Waddress, "the address of %qD will never be NULL",
- TREE_OPERAND (op1, 0));
+ {
+ if (complain & tf_warning)
+ warning (OPT_Waddress, "the address of %qD will never be NULL",
+ TREE_OPERAND (op1, 0));
+ }
result_type = type1;
}
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
- error ("ISO C++ forbids comparison between pointer and integer");
+ if (complain & tf_error)
+ pedwarn ("ISO C++ forbids comparison between pointer and integer");
+ else
+ return error_mark_node;
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
- error ("ISO C++ forbids comparison between pointer and integer");
+ if (complain & tf_error)
+ pedwarn ("ISO C++ forbids comparison between pointer and integer");
+ else
+ return error_mark_node;
}
else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
{
== ptrmemfunc_vbit_in_delta)
{
tree pfn0 = pfn_from_ptrmemfunc (op0);
- tree delta0 = build_ptrmemfunc_access_expr (op0,
- delta_identifier);
+ tree delta0 = delta_from_ptrmemfunc (op0);
tree e1 = cp_build_binary_op (EQ_EXPR,
pfn0,
fold_convert (TREE_TYPE (pfn0),
- integer_zero_node));
+ integer_zero_node),
+ complain);
tree e2 = cp_build_binary_op (BIT_AND_EXPR,
delta0,
- integer_one_node);
- e2 = cp_build_binary_op (EQ_EXPR, e2, integer_zero_node);
- op0 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e1, e2);
+ integer_one_node,
+ complain);
+ e2 = cp_build_binary_op (EQ_EXPR, e2, integer_zero_node,
+ complain);
+ op0 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e1, e2,
+ complain);
op1 = cp_convert (TREE_TYPE (op0), integer_one_node);
}
else
result_type = TREE_TYPE (op0);
}
else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
- return cp_build_binary_op (code, op1, op0);
- else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
- && same_type_p (type0, type1))
+ return cp_build_binary_op (code, op1, op0, complain);
+ else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1))
{
+ tree type;
/* E will be the final comparison. */
tree e;
/* E1 and E2 are for scratch. */
tree delta0;
tree delta1;
+ type = composite_pointer_type (type0, type1, op0, op1, "comparison",
+ complain);
+
+ if (!same_type_p (TREE_TYPE (op0), type))
+ op0 = cp_convert_and_check (type, op0);
+ if (!same_type_p (TREE_TYPE (op1), type))
+ op1 = cp_convert_and_check (type, op1);
+
+ if (op0 == error_mark_node || op1 == error_mark_node)
+ return error_mark_node;
+
if (TREE_SIDE_EFFECTS (op0))
op0 = save_expr (op0);
if (TREE_SIDE_EFFECTS (op1))
pfn0 = pfn_from_ptrmemfunc (op0);
pfn1 = pfn_from_ptrmemfunc (op1);
- delta0 = build_ptrmemfunc_access_expr (op0,
- delta_identifier);
- delta1 = build_ptrmemfunc_access_expr (op1,
- delta_identifier);
+ delta0 = delta_from_ptrmemfunc (op0);
+ delta1 = delta_from_ptrmemfunc (op1);
if (TARGET_PTRMEMFUNC_VBIT_LOCATION
== ptrmemfunc_vbit_in_delta)
{
e1 = cp_build_binary_op (BIT_AND_EXPR,
delta0,
- integer_one_node);
- e1 = cp_build_binary_op (EQ_EXPR, e1, integer_zero_node);
+ integer_one_node,
+ complain);
+ e1 = cp_build_binary_op (EQ_EXPR, e1, integer_zero_node,
+ complain);
e2 = cp_build_binary_op (BIT_AND_EXPR,
delta1,
- integer_one_node);
- e2 = cp_build_binary_op (EQ_EXPR, e2, integer_zero_node);
- e1 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1);
+ integer_one_node,
+ complain);
+ e2 = cp_build_binary_op (EQ_EXPR, e2, integer_zero_node,
+ complain);
+ e1 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1,
+ complain);
e2 = cp_build_binary_op (EQ_EXPR,
pfn0,
fold_convert (TREE_TYPE (pfn0),
- integer_zero_node));
- e2 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1);
- e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1);
- e1 = cp_build_binary_op (TRUTH_ORIF_EXPR, e1, e2);
+ integer_zero_node),
+ complain);
+ e2 = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1, complain);
+ e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1, complain);
+ e1 = cp_build_binary_op (TRUTH_ORIF_EXPR, e1, e2, complain);
}
else
{
pointer-to-member is any member with a zero PFN; the
DELTA field is unspecified. */
- e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1);
+ e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1, complain);
e2 = cp_build_binary_op (EQ_EXPR,
pfn0,
fold_convert (TREE_TYPE (pfn0),
- integer_zero_node));
- e1 = cp_build_binary_op (TRUTH_ORIF_EXPR, e1, e2);
+ integer_zero_node),
+ complain);
+ e1 = cp_build_binary_op (TRUTH_ORIF_EXPR, e1, e2, complain);
}
e2 = build2 (EQ_EXPR, boolean_type_node, pfn0, pfn1);
- e = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1);
+ e = cp_build_binary_op (TRUTH_ANDIF_EXPR, e2, e1, complain);
if (code == EQ_EXPR)
return e;
- return cp_build_binary_op (EQ_EXPR, e, integer_zero_node);
+ return cp_build_binary_op (EQ_EXPR, e, integer_zero_node, complain);
}
else
{
shorten = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
result_type = composite_pointer_type (type0, type1, op0, op1,
- "comparison");
+ "comparison", complain);
break;
case LE_EXPR:
case GT_EXPR:
if (TREE_CODE (orig_op0) == STRING_CST
|| TREE_CODE (orig_op1) == STRING_CST)
- warning (OPT_Waddress, "comparison with string literal results in unspecified behaviour");
+ {
+ if (complain & tf_warning)
+ warning (OPT_Waddress, "comparison with string literal results in unspecified behaviour");
+ }
build_type = boolean_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
result_type = composite_pointer_type (type0, type1, op0, op1,
- "comparison");
+ "comparison", complain);
else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
&& integer_zerop (op1))
result_type = type0;
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
- pedwarn ("ISO C++ forbids comparison between pointer and integer");
+ if (complain & tf_error)
+ pedwarn ("ISO C++ forbids comparison between pointer and integer");
+ else
+ return error_mark_node;
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
- pedwarn ("ISO C++ forbids comparison between pointer and integer");
+ if (complain & tf_error)
+ pedwarn ("ISO C++ forbids comparison between pointer and integer");
+ else
+ return error_mark_node;
}
break;
build_type = integer_type_node;
if (code0 != REAL_TYPE || code1 != REAL_TYPE)
{
- error ("unordered comparison on non-floating point argument");
+ if (complain & tf_error)
+ error ("unordered comparison on non-floating point argument");
return error_mark_node;
}
common = 1;
if (!result_type)
{
- error ("invalid operands of types %qT and %qT to binary %qO",
- TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+ if (complain & tf_error)
+ error ("invalid operands of types %qT and %qT to binary %qO",
+ TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
return error_mark_node;
}
result_type = type;
}
- /* Shifts can be shortened if shifting right. */
-
- if (short_shift)
- {
- int unsigned_arg;
- tree arg0 = get_narrower (op0, &unsigned_arg);
-
- final_type = result_type;
-
- if (arg0 == op0 && final_type == TREE_TYPE (op0))
- unsigned_arg = TYPE_UNSIGNED (TREE_TYPE (op0));
-
- if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
- /* We can shorten only if the shift count is less than the
- number of bits in the smaller type size. */
- && compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0
- /* If arg is sign-extended and then unsigned-shifted,
- we can simulate this with a signed shift in arg's type
- only if the extended result is at least twice as wide
- as the arg. Otherwise, the shift could use up all the
- ones made by sign-extension and bring in zeros.
- We can't optimize that case at all, but in most machines
- it never happens because available widths are 2**N. */
- && (!TYPE_UNSIGNED (final_type)
- || unsigned_arg
- || (((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0)))
- <= TYPE_PRECISION (result_type))))
- {
- /* Do an unsigned shift if the operand was zero-extended. */
- result_type
- = c_common_signed_or_unsigned_type (unsigned_arg,
- TREE_TYPE (arg0));
- /* Convert value-to-be-shifted to that type. */
- if (TREE_TYPE (op0) != result_type)
- op0 = cp_convert (result_type, op0);
- converted = 1;
- }
- }
-
/* Comparison operations are shortened too but differently.
They identify themselves by setting short_compare = 1. */
if (TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE
&& TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE
&& TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
- != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
+ != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1))
+ && (complain & tf_warning))
{
- warning (0, "comparison between types %q#T and %q#T",
+ warning (OPT_Wsign_compare, "comparison between types %q#T and %q#T",
TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
}
&& int_fits_type_p (orig_op0, c_common_signed_type
(result_type)))))
/* OK */;
- else
- warning (0, "comparison between signed and unsigned integer expressions");
+ else if (complain & tf_warning)
+ warning (OPT_Wsign_compare,
+ "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
&& bits < HOST_BITS_PER_LONG && unsignedp)
{
mask = (~ (HOST_WIDE_INT) 0) << bits;
- if ((mask & constant) != mask)
- warning (0, "comparison of promoted ~unsigned with constant");
+ if ((mask & constant) != mask
+ && (complain & tf_warning))
+ warning (OPT_Wsign_compare, "comparison of promoted ~unsigned with constant");
}
}
else if (unsignedp0 && unsignedp1
&& (TYPE_PRECISION (TREE_TYPE (primop0))
< TYPE_PRECISION (result_type))
&& (TYPE_PRECISION (TREE_TYPE (primop1))
- < TYPE_PRECISION (result_type)))
- warning (0, "comparison of promoted ~unsigned with unsigned");
+ < TYPE_PRECISION (result_type))
+ && (complain & tf_warning))
+ warning (OPT_Wsign_compare, "comparison of promoted ~unsigned with unsigned");
}
}
}
&& code != EQ_EXPR && code != NE_EXPR)
/* Or if one of OP0 or OP1 is neither a pointer nor NULL. */
|| (!null_ptr_cst_p (orig_op0) && TREE_CODE (TREE_TYPE (op0)) != POINTER_TYPE)
- || (!null_ptr_cst_p (orig_op1) && TREE_CODE (TREE_TYPE (op1)) != POINTER_TYPE)))
+ || (!null_ptr_cst_p (orig_op1) && TREE_CODE (TREE_TYPE (op1)) != POINTER_TYPE))
+ && (complain & tf_warning))
/* Some sort of arithmetic operation involving NULL was
performed. Note that pointer-difference and pointer-addition
have already been handled above, and so we don't end up here in
op0 = cp_build_binary_op (MINUS_EXPR,
cp_convert (restype, op0),
- cp_convert (restype, op1));
+ cp_convert (restype, op1),
+ tf_warning_or_error);
/* This generates an error if op1 is a pointer to an incomplete type. */
if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
and XARG is the operand. */
tree
-build_x_unary_op (enum tree_code code, tree xarg)
+build_x_unary_op (enum tree_code code, tree xarg, tsubst_flags_t complain)
{
tree orig_expr = xarg;
tree exp;
/* Don't look for a function. */;
else
exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE,
- /*overloaded_p=*/NULL);
+ /*overloaded_p=*/NULL, complain);
if (!exp && code == ADDR_EXPR)
{
/* A pointer to member-function can be formed only by saying
if (TREE_CODE (xarg) != OFFSET_REF
|| !TYPE_P (TREE_OPERAND (xarg, 0)))
{
- error ("invalid use of %qE to form a pointer-to-member-function",
- xarg);
- if (TREE_CODE (xarg) != OFFSET_REF)
- inform (" a qualified-id is required");
+ error ("invalid use of %qE to form a pointer-to-member-function",
+ xarg);
+ if (TREE_CODE (xarg) != OFFSET_REF)
+ inform (" a qualified-id is required");
return error_mark_node;
}
else
PTRMEM_OK_P (xarg) = ptrmem;
}
}
- else if (TREE_CODE (xarg) == TARGET_EXPR)
+ else if (TREE_CODE (xarg) == TARGET_EXPR && (complain & tf_warning))
warning (0, "taking address of temporary");
- exp = build_unary_op (ADDR_EXPR, xarg, 0);
+ exp = cp_build_unary_op (ADDR_EXPR, xarg, 0, complain);
}
if (processing_template_decl && exp != error_mark_node)
tree t;
if (processing_template_decl)
return expr;
- t = perform_implicit_conversion (boolean_type_node, expr);
+ t = perform_implicit_conversion (boolean_type_node, expr,
+ tf_warning_or_error);
t = fold_build_cleanup_point_expr (boolean_type_node, t);
return t;
}
(such as from short to int). */
tree
-build_unary_op (enum tree_code code, tree xarg, int noconvert)
+cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
+ tsubst_flags_t complain)
{
/* No default_conversion here. It causes trouble for ADDR_EXPR. */
tree arg = xarg;
break;
case TRUTH_NOT_EXPR:
- arg = perform_implicit_conversion (boolean_type_node, arg);
+ arg = perform_implicit_conversion (boolean_type_node, arg,
+ complain);
val = invert_truthvalue (arg);
if (arg != error_mark_node)
return val;
tree real, imag;
arg = stabilize_reference (arg);
- real = build_unary_op (REALPART_EXPR, arg, 1);
- imag = build_unary_op (IMAGPART_EXPR, arg, 1);
- real = build_unary_op (code, real, 1);
+ real = cp_build_unary_op (REALPART_EXPR, arg, 1, complain);
+ imag = cp_build_unary_op (IMAGPART_EXPR, arg, 1, complain);
+ real = cp_build_unary_op (code, real, 1, complain);
if (real == error_mark_node || imag == error_mark_node)
return error_mark_node;
return build2 (COMPLEX_EXPR, TREE_TYPE (arg),
/* Report something read-only. */
if (CP_TYPE_CONST_P (TREE_TYPE (arg))
- || TREE_READONLY (arg))
- readonly_error (arg, ((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? "increment" : "decrement"));
+ || TREE_READONLY (arg))
+ {
+ if (complain & tf_error)
+ readonly_error (arg, ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? "increment" : "decrement"));
+ else
+ return error_mark_node;
+ }
{
tree inc;
/* ARM $5.2.5 last annotation says this should be forbidden. */
if (TREE_CODE (argtype) == ENUMERAL_TYPE)
- pedwarn ((code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
- ? G_("ISO C++ forbids incrementing an enum")
- : G_("ISO C++ forbids decrementing an enum"));
+ {
+ if (complain & tf_error)
+ pedwarn ((code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+ ? G_("ISO C++ forbids incrementing an enum")
+ : G_("ISO C++ forbids decrementing an enum"));
+ else
+ return error_mark_node;
+ }
/* Compute the increment. */
tree type = complete_type (TREE_TYPE (argtype));
if (!COMPLETE_OR_VOID_TYPE_P (type))
- error (((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR))
- ? G_("cannot increment a pointer to incomplete type %qT")
- : G_("cannot decrement a pointer to incomplete type %qT"),
- TREE_TYPE (argtype));
+ {
+ if (complain & tf_error)
+ error (((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR))
+ ? G_("cannot increment a pointer to incomplete type %qT")
+ : G_("cannot decrement a pointer to incomplete type %qT"),
+ TREE_TYPE (argtype));
+ else
+ return error_mark_node;
+ }
else if ((pedantic || warn_pointer_arith)
- && !TYPE_PTROB_P (argtype))
- pedwarn ((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? G_("ISO C++ forbids incrementing a pointer of type %qT")
- : G_("ISO C++ forbids decrementing a pointer of type %qT"),
- argtype);
+ && !TYPE_PTROB_P (argtype))
+ {
+ if (complain & tf_error)
+ pedwarn ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? G_("ISO C++ forbids incrementing a pointer of type %qT")
+ : G_("ISO C++ forbids decrementing a pointer of type %qT"),
+ argtype);
+ else
+ return error_mark_node;
+ }
+
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)
- ? lv_increment : lv_decrement)))
+ ? lv_increment : lv_decrement),
+ complain))
return error_mark_node;
/* Forbid using -- on `bool'. */
{
if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
{
- error ("invalid use of %<--%> on bool variable %qD", arg);
+ if (complain & tf_error)
+ error ("invalid use of Boolean expression as operand "
+ "to %<operator--%>");
return error_mark_node;
}
val = boolean_increment (code, arg);
return arg;
}
else if (pedantic && DECL_MAIN_P (arg))
- /* ARM $3.4 */
- pedwarn ("ISO C++ forbids taking address of function %<::main%>");
+ {
+ /* ARM $3.4 */
+ if (complain & tf_error)
+ pedwarn ("ISO C++ forbids taking address of function %<::main%>");
+ else
+ return error_mark_node;
+ }
/* Let &* cancel out to simplify resulting code. */
if (TREE_CODE (arg) == INDIRECT_REF)
if (! flag_ms_extensions)
{
tree name = DECL_NAME (fn);
- if (current_class_type
- && TREE_OPERAND (arg, 0) == current_class_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%>",
- base, name);
+ if (!(complain & tf_error))
+ return error_mark_node;
+ else if (current_class_type
+ && TREE_OPERAND (arg, 0) == current_class_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%>",
+ base, name);
else
pedwarn ("ISO C++ forbids taking the address of a bound member"
" function to form a pointer to member function."
switch (TREE_CODE (arg))
{
- case NOP_EXPR:
- case CONVERT_EXPR:
+ CASE_CONVERT:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
- if (! lvalue_p (arg) && pedantic)
- pedwarn ("ISO C++ forbids taking the address of a cast to a non-lvalue expression");
+ /* Even if we're not being pedantic, we cannot allow this
+ extension when we're instantiating in a SFINAE
+ context. */
+ if (! lvalue_p (arg) && (pedantic || complain == tf_none))
+ {
+ if (complain & tf_error)
+ pedwarn ("ISO C++ forbids taking the address of a cast to a non-lvalue expression");
+ else
+ return error_mark_node;
+ }
break;
case BASELINK:
tree t;
if (!PTRMEM_OK_P (arg))
- return build_unary_op (code, arg, 0);
+ return cp_build_unary_op (code, arg, 0, complain);
t = TREE_OPERAND (arg, 1);
if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
{
- error ("cannot create pointer to reference member %qD", t);
+ if (complain & tf_error)
+ error ("cannot create pointer to reference member %qD", t);
return error_mark_node;
}
if (TREE_CODE (argtype) != FUNCTION_TYPE
&& TREE_CODE (argtype) != METHOD_TYPE
&& TREE_CODE (arg) != OFFSET_REF
- && !lvalue_or_else (arg, lv_addressof))
+ && !lvalue_or_else (arg, lv_addressof, complain))
return error_mark_node;
if (argtype != error_mark_node)
}
else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
{
- error ("attempt to take address of bit-field structure member %qD",
- TREE_OPERAND (arg, 1));
+ if (complain & tf_error)
+ error ("attempt to take address of bit-field structure member %qD",
+ TREE_OPERAND (arg, 1));
return error_mark_node;
}
else
return fold_if_not_in_template (build1 (code, argtype, arg));
}
- error ("%s", errstring);
+ if (complain & tf_error)
+ error ("%s", errstring);
return error_mark_node;
}
+/* Hook for the c-common bits that build a unary op. */
+tree
+build_unary_op (enum tree_code code, tree xarg, int noconvert)
+{
+ return cp_build_unary_op (code, xarg, noconvert, tf_warning_or_error);
+}
+
/* Apply unary lvalue-demanding operator CODE to the expression ARG
for certain kinds of expressions which are not really lvalues
but which we can accept as lvalues.
/* Handle (a, b) used as an "lvalue". */
if (TREE_CODE (arg) == COMPOUND_EXPR)
{
- tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0);
+ tree real_result = cp_build_unary_op (code, TREE_OPERAND (arg, 1), 0,
+ tf_warning_or_error);
return build2 (COMPOUND_EXPR, TREE_TYPE (real_result),
TREE_OPERAND (arg, 0), real_result);
}
/* Handle (a ? b : c) used as an "lvalue". */
if (TREE_CODE (arg) == COND_EXPR
|| TREE_CODE (arg) == MIN_EXPR || TREE_CODE (arg) == MAX_EXPR)
- return rationalize_conditional_expr (code, arg);
+ return rationalize_conditional_expr (code, arg, tf_warning_or_error);
/* Handle (a = b), (++a), and (--a) used as an "lvalue". */
if (TREE_CODE (arg) == MODIFY_EXPR
if (TREE_CODE (arg) == MODIFY_EXPR
|| TREE_CODE (arg) == INIT_EXPR)
{
- tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
+ tree real_result = cp_build_unary_op (code, TREE_OPERAND (arg, 0), 0,
+ tf_warning_or_error);
arg = build2 (COMPOUND_EXPR, TREE_TYPE (real_result),
arg, real_result);
TREE_NO_WARNING (arg) = 1;
if (TREE_CODE (targ) == SAVE_EXPR)
targ = TREE_OPERAND (targ, 0);
- if (TREE_CODE (targ) == CALL_EXPR && IS_AGGR_TYPE (TREE_TYPE (targ)))
+ if (TREE_CODE (targ) == CALL_EXPR && MAYBE_CLASS_TYPE_P (TREE_TYPE (targ)))
{
if (TREE_CODE (arg) == SAVE_EXPR)
targ = arg;
/* Build and return a conditional expression IFEXP ? OP1 : OP2. */
tree
-build_x_conditional_expr (tree ifexp, tree op1, tree op2)
+build_x_conditional_expr (tree ifexp, tree op1, tree op2,
+ tsubst_flags_t complain)
{
tree orig_ifexp = ifexp;
tree orig_op1 = op1;
op2 = build_non_dependent_expr (op2);
}
- expr = build_conditional_expr (ifexp, op1, op2);
+ expr = build_conditional_expr (ifexp, op1, op2, complain);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (COND_EXPR, expr,
orig_ifexp, orig_op1, orig_op2);
pedwarn ("%s expression list treated as compound expression", msg);
for (list = TREE_CHAIN (list); list; list = TREE_CHAIN (list))
- expr = build_x_compound_expr (expr, TREE_VALUE (list));
+ expr = build_x_compound_expr (expr, TREE_VALUE (list),
+ tf_warning_or_error);
}
return expr;
/* Handle overloading of the ',' operator when needed. */
tree
-build_x_compound_expr (tree op1, tree op2)
+build_x_compound_expr (tree op1, tree op2, tsubst_flags_t complain)
{
tree result;
tree orig_op1 = op1;
}
result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
- /*overloaded_p=*/NULL);
+ /*overloaded_p=*/NULL, complain);
if (!result)
- result = build_compound_expr (op1, op2);
+ result = cp_build_compound_expr (op1, op2, complain);
if (processing_template_decl && result != error_mark_node)
return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2);
return result;
}
-/* Build a compound expression. */
+/* Like cp_build_compound_expr, but for the c-common bits. */
tree
build_compound_expr (tree lhs, tree rhs)
{
- lhs = convert_to_void (lhs, "left-hand operand of comma");
+ return cp_build_compound_expr (lhs, rhs, tf_warning_or_error);
+}
+
+/* Build a compound expression. */
+
+tree
+cp_build_compound_expr (tree lhs, tree rhs, tsubst_flags_t complain)
+{
+ lhs = convert_to_void (lhs, "left-hand operand of comma", complain);
if (lhs == error_mark_node || rhs == error_mark_node)
return error_mark_node;
}
/* 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. */
+ casts away constness. CAST gives the type of cast. */
static void
check_for_casting_away_constness (tree src_type, tree dest_type,
- void (*diag_fn)(const char *, ...) ATTRIBUTE_GCC_CXXDIAG(1,2),
- const char *description)
+ enum tree_code cast)
{
- if (diag_fn && casts_away_constness (src_type, dest_type))
- diag_fn ("%s from type %qT to type %qT casts away constness",
- description, src_type, dest_type);
+ /* C-style casts are allowed to cast away constness. With
+ WARN_CAST_QUAL, we still want to issue a warning. */
+ if (cast == CAST_EXPR && !warn_cast_qual)
+ return;
+
+ if (casts_away_constness (src_type, dest_type))
+ switch (cast)
+ {
+ case CAST_EXPR:
+ warning (OPT_Wcast_qual,
+ "cast from type %qT to type %qT casts away constness",
+ src_type, dest_type);
+ return;
+
+ case STATIC_CAST_EXPR:
+ error ("static_cast from type %qT to type %qT casts away constness",
+ src_type, dest_type);
+ return;
+
+ case REINTERPRET_CAST_EXPR:
+ error ("reinterpret_cast from type %qT to type %qT casts away constness",
+ src_type, dest_type);
+ return;
+ default:
+ gcc_unreachable();
+ }
}
/* Convert EXPR (an expression with pointer-to-member type) to 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);
+ {
+ tree cond, op1, op2;
+
+ cond = cp_build_binary_op (EQ_EXPR,
+ expr,
+ build_int_cst (TREE_TYPE (expr), -1),
+ tf_warning_or_error);
+ op1 = build_nop (ptrdiff_type_node, expr);
+ op2 = cp_build_binary_op (PLUS_EXPR, op1, delta,
+ tf_warning_or_error);
+
+ expr = fold_build3 (COND_EXPR, ptrdiff_type_node, cond, op1, op2);
+
+ }
+
return build_nop (type, expr);
}
else
static tree
build_static_cast_1 (tree type, tree expr, bool c_cast_p,
- bool *valid_p)
+ bool *valid_p, tsubst_flags_t complain)
{
tree intype;
tree result;
tree orig;
- void (*diag_fn)(const char*, ...) ATTRIBUTE_GCC_CXXDIAG(1,2);
- const char *desc;
/* Assume the cast is valid. */
*valid_p = true;
/* Save casted types in the function's used types hash table. */
used_types_insert (type);
- /* 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
t(e);" is well-formed, for some invented temporary variable
t. */
result = perform_direct_initialization_if_possible (type, expr,
- c_cast_p);
+ c_cast_p, complain);
if (result)
{
result = convert_from_reference (result);
Any expression can be explicitly converted to type cv void. */
if (TREE_CODE (type) == VOID_TYPE)
- return convert_to_void (expr, /*implicit=*/NULL);
+ return convert_to_void (expr, /*implicit=*/NULL, complain);
/* [expr.static.cast]
tree base;
if (!c_cast_p)
- check_for_casting_away_constness (intype, type, diag_fn, desc);
+ check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
c_cast_p ? ba_unique : ba_check,
NULL);
t1 = intype;
t2 = type;
}
- if (can_convert (t1, t2))
+ if (can_convert (t1, t2) || can_convert (t2, t1))
{
if (!c_cast_p)
- check_for_casting_away_constness (intype, type, diag_fn,
- desc);
+ check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
c_cast_p);
}
&& TYPE_PTROB_P (type))
{
if (!c_cast_p)
- check_for_casting_away_constness (intype, type, diag_fn, desc);
+ check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
return build_nop (type, expr);
}
/* Return an expression representing static_cast<TYPE>(EXPR). */
tree
-build_static_cast (tree type, tree expr)
+build_static_cast (tree type, tree expr, tsubst_flags_t complain)
{
tree result;
bool valid_p;
&& 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);
+ result = build_static_cast_1 (type, expr, /*c_cast_p=*/false, &valid_p,
+ complain);
if (valid_p)
return result;
- error ("invalid static_cast from type %qT to type %qT",
- TREE_TYPE (expr), type);
+ if (complain & tf_error)
+ error ("invalid static_cast from type %qT to type %qT",
+ TREE_TYPE (expr), type);
return error_mark_node;
}
static tree
build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
- bool *valid_p)
+ bool *valid_p, tsubst_flags_t complain)
{
tree intype;
{
if (! real_lvalue_p (expr))
{
- error ("invalid cast of an rvalue expression of type "
- "%qT to type %qT",
- intype, type);
+ if (complain & tf_error)
+ error ("invalid cast of an rvalue expression of type "
+ "%qT to type %qT",
+ intype, type);
return error_mark_node;
}
"B" are related class types; the reinterpret_cast does not
adjust the pointer. */
if (TYPE_PTR_P (intype)
+ && (complain & tf_warning)
&& (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);
+ expr = cp_build_unary_op (ADDR_EXPR, expr, 0, complain);
if (expr != error_mark_node)
expr = build_reinterpret_cast_1
(build_pointer_type (TREE_TYPE (type)), expr, c_cast_p,
- valid_p);
+ valid_p, complain);
if (expr != error_mark_node)
- expr = build_indirect_ref (expr, 0);
+ expr = cp_build_indirect_ref (expr, 0, complain);
return expr;
}
if (CP_INTEGRAL_TYPE_P (type) && TYPE_PTR_P (intype))
{
if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
- pedwarn ("cast from %qT to %qT loses precision",
- intype, type);
+ {
+ if (complain & tf_error)
+ pedwarn ("cast from %qT to %qT loses precision",
+ intype, type);
+ else
+ return error_mark_node;
+ }
}
/* [expr.reinterpret.cast]
A value of integral or enumeration type can be explicitly
tree sexpr = expr;
if (!c_cast_p)
- check_for_casting_away_constness (intype, type, error,
- "reinterpret_cast");
+ check_for_casting_away_constness (intype, type, REINTERPRET_CAST_EXPR);
/* Warn about possible alignment problems. */
if (STRICT_ALIGNMENT && warn_cast_align
+ && (complain & tf_warning)
&& !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);
+ warning (OPT_Wcast_align, "cast from %qT to %qT "
+ "increases required alignment of target type", intype, type);
/* We need to strip nops here, because the front end likes to
create (int *)&a for array-to-pointer decay, instead of &a[0]. */
else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
|| (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
{
- if (pedantic)
+ if (pedantic && (complain & tf_warning))
/* 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
{
if (valid_p)
*valid_p = false;
- error ("invalid cast from type %qT to type %qT", intype, type);
+ if (complain & tf_error)
+ error ("invalid cast from type %qT to type %qT", intype, type);
return error_mark_node;
}
}
tree
-build_reinterpret_cast (tree type, tree expr)
+build_reinterpret_cast (tree type, tree expr, tsubst_flags_t complain)
{
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
}
return build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false,
- /*valid_p=*/NULL);
+ /*valid_p=*/NULL, complain);
}
/* Perform a const_cast from EXPR to TYPE. If the cast is valid,
*valid_p = true;
/* This cast is actually a C-style cast. Issue a warning if
the user is making a potentially unsafe cast. */
- if (warn_cast_qual)
- check_for_casting_away_constness (src_type, dst_type,
- warning0,
- "cast");
+ check_for_casting_away_constness (src_type, dst_type, CAST_EXPR);
}
if (reference_type)
{
- expr = build_unary_op (ADDR_EXPR, expr, 0);
+ expr = cp_build_unary_op (ADDR_EXPR, expr, 0,
+ complain? tf_warning_or_error : tf_none);
expr = build_nop (reference_type, expr);
return convert_from_reference (expr);
}
}
tree
-build_const_cast (tree type, tree expr)
+build_const_cast (tree type, tree expr, tsubst_flags_t complain)
{
if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
return convert_from_reference (t);
}
- return build_const_cast_1 (type, expr, /*complain=*/true,
+ return build_const_cast_1 (type, expr, complain & tf_error,
/*valid_p=*/NULL);
}
+/* Like cp_build_c_cast, but for the c-common bits. */
+
+tree
+build_c_cast (tree type, tree expr)
+{
+ return cp_build_c_cast (type, expr, tf_warning_or_error);
+}
+
/* Build an expression representing an explicit C-style cast to type
TYPE of expression EXPR. */
tree
-build_c_cast (tree type, tree expr)
+cp_build_c_cast (tree type, tree expr, tsubst_flags_t complain)
{
tree value = expr;
tree result;
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 %qT", type);
+ if (complain & tf_error)
+ pedwarn ("ISO C++ forbids casting to an array type %qT", type);
+ else
+ return error_mark_node;
type = build_pointer_type (TREE_TYPE (type));
}
else
{
- error ("ISO C++ forbids casting to an array type %qT", type);
+ if (complain & tf_error)
+ error ("ISO C++ forbids casting to an array type %qT", type);
return error_mark_node;
}
}
if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
{
- error ("invalid cast to function type %qT", type);
+ if (complain & tf_error)
+ error ("invalid cast to function type %qT", type);
return error_mark_node;
}
/* Or a static cast. */
result = build_static_cast_1 (type, value, /*c_cast_p=*/true,
- &valid_p);
+ &valid_p, complain);
/* Or a reinterpret_cast. */
if (!valid_p)
result = build_reinterpret_cast_1 (type, value, /*c_cast_p=*/true,
- &valid_p);
+ &valid_p, complain);
/* The static_cast or reinterpret_cast may be followed by a
const_cast. */
if (valid_p
return error_mark_node;
}
\f
+/* For use from the C common bits. */
+tree
+build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
+{
+ return cp_build_modify_expr (lhs, modifycode, rhs, tf_warning_or_error);
+}
+
/* Build an assignment expression of lvalue LHS from value RHS.
MODIFYCODE is the code for a binary operator that we use
to combine the old value of LHS with RHS to get the new value.
C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed. */
tree
-build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
+cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
+ tsubst_flags_t complain)
{
tree result;
tree newrhs = rhs;
lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
stabilize_reference (TREE_OPERAND (lhs, 0)),
TREE_OPERAND (lhs, 1));
- return build2 (COMPOUND_EXPR, lhstype,
- lhs,
- build_modify_expr (TREE_OPERAND (lhs, 0),
- modifycode, rhs));
+ newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 0),
+ modifycode, rhs, complain);
+ if (newrhs == error_mark_node)
+ return error_mark_node;
+ return build2 (COMPOUND_EXPR, lhstype, lhs, newrhs);
/* Handle (a, b) used as an "lvalue". */
case COMPOUND_EXPR:
- newrhs = build_modify_expr (TREE_OPERAND (lhs, 1),
- modifycode, rhs);
+ newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 1),
+ modifycode, rhs, complain);
if (newrhs == error_mark_node)
return error_mark_node;
return build2 (COMPOUND_EXPR, lhstype,
lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
stabilize_reference (TREE_OPERAND (lhs, 0)),
TREE_OPERAND (lhs, 1));
- newrhs = build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs);
+ newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs,
+ complain);
if (newrhs == error_mark_node)
return error_mark_node;
return build2 (COMPOUND_EXPR, lhstype, lhs, newrhs);
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))
+ if (!lvalue_or_else (lhs, lv_assign, complain))
return error_mark_node;
gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))
if (VOID_TYPE_P (TREE_TYPE (rhs)))
{
- error ("void value not ignored as it ought to be");
+ if (complain & tf_error)
+ error ("void value not ignored as it ought to be");
return error_mark_node;
}
/* 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, lv_assign))
+ if (!lvalue_or_else (lhs, lv_assign, complain))
return error_mark_node;
cond = build_conditional_expr
(TREE_OPERAND (lhs, 0),
- build_modify_expr (TREE_OPERAND (lhs, 1),
- modifycode, rhs),
- build_modify_expr (TREE_OPERAND (lhs, 2),
- modifycode, rhs));
+ cp_build_modify_expr (TREE_OPERAND (lhs, 1),
+ modifycode, rhs, complain),
+ cp_build_modify_expr (TREE_OPERAND (lhs, 2),
+ modifycode, rhs, complain),
+ complain);
if (cond == error_mark_node)
return cond;
TREE_SIDE_EFFECTS (result) = 1;
return result;
}
- else if (! IS_AGGR_TYPE (lhstype))
+ else if (! MAYBE_CLASS_TYPE_P (lhstype))
/* Do the default thing. */;
else
{
result = build_special_member_call (lhs, complete_ctor_identifier,
build_tree_list (NULL_TREE, rhs),
- lhstype, LOOKUP_NORMAL);
+ lhstype, LOOKUP_NORMAL,
+ complain);
if (result == NULL_TREE)
return error_mark_node;
return result;
if (modifycode == NOP_EXPR)
{
/* `operator=' is not an inheritable operator. */
- if (! IS_AGGR_TYPE (lhstype))
+ if (! MAYBE_CLASS_TYPE_P (lhstype))
/* Do the default thing. */;
else
{
result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
lhs, rhs, make_node (NOP_EXPR),
- /*overloaded_p=*/NULL);
+ /*overloaded_p=*/NULL,
+ complain);
if (result == NULL_TREE)
return error_mark_node;
return result;
/* A binary op has been requested. Combine the old LHS
value with the RHS producing the value we should actually
store into the LHS. */
+ gcc_assert (!((TREE_CODE (lhstype) == REFERENCE_TYPE
+ && MAYBE_CLASS_TYPE_P (TREE_TYPE (lhstype)))
+ || MAYBE_CLASS_TYPE_P (lhstype)));
- gcc_assert (!PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE));
lhs = stabilize_reference (lhs);
- newrhs = cp_build_binary_op (modifycode, lhs, rhs);
+ newrhs = cp_build_binary_op (modifycode, lhs, rhs,
+ complain);
if (newrhs == error_mark_node)
{
- error (" in evaluation of %<%Q(%#T, %#T)%>", modifycode,
- TREE_TYPE (lhs), TREE_TYPE (rhs));
+ if (complain & tf_error)
+ 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, lv_assign))
+ if (!lvalue_or_else (lhs, lv_assign, complain))
return error_mark_node;
/* Warn about modifying something that is `const'. Don't warn if
effectively const. */
|| (CLASS_TYPE_P (lhstype)
&& C_TYPE_FIELDS_READONLY (lhstype))))
- readonly_error (lhs, "assignment");
+ {
+ if (complain & tf_error)
+ readonly_error (lhs, "assignment");
+ else
+ return error_mark_node;
+ }
/* If storing into a structure or union member, it has probably been
given type `int'. Compute the type that would go with the actual
if (!same_or_base_type_p (TYPE_MAIN_VARIANT (lhstype),
TYPE_MAIN_VARIANT (TREE_TYPE (rhs))))
{
- error ("incompatible types in assignment of %qT to %qT",
- TREE_TYPE (rhs), lhstype);
+ if (complain & tf_error)
+ error ("incompatible types in assignment of %qT to %qT",
+ TREE_TYPE (rhs), lhstype);
return error_mark_node;
}
{
/* This routine is used for both initialization and assignment.
Make sure the diagnostic message differentiates the context. */
- if (modifycode == INIT_EXPR)
- error ("array used as initializer");
- else
- error ("invalid array assignment");
+ if (complain & tf_error)
+ {
+ if (modifycode == INIT_EXPR)
+ error ("array used as initializer");
+ else
+ error ("invalid array assignment");
+ }
return error_mark_node;
}
? 1 + (modifycode != INIT_EXPR): 0;
return build_vec_init (lhs, NULL_TREE, newrhs,
/*explicit_default_init_p=*/false,
- from_array);
+ from_array, complain);
}
if (modifycode == INIT_EXPR)
newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
- "initialization", NULL_TREE, 0);
+ "initialization", NULL_TREE, 0,
+ complain);
else
{
/* Avoid warnings on enum bit fields. */
&& TREE_CODE (lhstype) == INTEGER_TYPE)
{
newrhs = convert_for_assignment (olhstype, newrhs, "assignment",
- NULL_TREE, 0);
+ NULL_TREE, 0, complain);
newrhs = convert_force (lhstype, newrhs, 0);
}
else
newrhs = convert_for_assignment (lhstype, newrhs, "assignment",
- NULL_TREE, 0);
+ NULL_TREE, 0, complain);
if (TREE_CODE (newrhs) == CALL_EXPR
&& TYPE_NEEDS_CONSTRUCTING (lhstype))
newrhs = build_cplus_new (lhstype, newrhs);
return result;
}
return convert_for_assignment (olhstype, result, "assignment",
- NULL_TREE, 0);
+ NULL_TREE, 0, complain);
}
tree
-build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
+build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
+ tsubst_flags_t complain)
{
if (processing_template_decl)
return build_min_nt (MODOP_EXPR, lhs,
{
tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
make_node (modifycode),
- /*overloaded_p=*/NULL);
+ /*overloaded_p=*/NULL,
+ complain);
if (rval)
{
TREE_NO_WARNING (rval) = 1;
return rval;
}
}
- return build_modify_expr (lhs, modifycode, rhs);
+ return cp_build_modify_expr (lhs, modifycode, rhs, complain);
+}
+
+/* Helper function for get_delta_difference which assumes FROM is a base
+ class of TO. Returns a delta for the conversion of pointer-to-member
+ of FROM to pointer-to-member of TO. If the conversion is invalid,
+ returns zero. If FROM is not a base class of TO, returns NULL_TREE.
+ If C_CAST_P is true, this conversion is taking place as part of a C-style
+ cast. */
+
+static tree
+get_delta_difference_1 (tree from, tree to, bool c_cast_p)
+{
+ tree binfo;
+ base_kind 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");
+ return size_zero_node;
+ }
+ else if (binfo)
+ {
+ if (kind != bk_via_virtual)
+ return BINFO_OFFSET (binfo);
+ else
+ /* FROM is a virtual base class of TO. Issue an error or warning
+ depending on whether or not this is a reinterpret cast. */
+ {
+ error ("pointer to member conversion via virtual base %qT",
+ BINFO_TYPE (binfo_from_vbase (binfo)));
+
+ return size_zero_node;
+ }
+ }
+ else
+ return NULL_TREE;
}
-\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
bool allow_inverse_p,
bool c_cast_p)
{
- tree binfo;
- base_kind kind;
tree result;
- /* Assume no conversion is required. */
- result = integer_zero_node;
- binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
- if (kind == bk_inaccessible || kind == bk_ambig)
- error (" in pointer to member function conversion");
- else if (binfo)
- {
- if (kind != bk_via_virtual)
- result = BINFO_OFFSET (binfo);
- else
- {
- tree virt_binfo = binfo_from_vbase (binfo);
-
- /* 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");
- }
+ if (same_type_ignoring_top_level_qualifiers_p (from, to))
+ /* Pointer to member of incomplete class is permitted*/
+ result = size_zero_node;
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);
+ result = get_delta_difference_1 (from, to, c_cast_p);
- warning (0, "pointer to member cast via virtual base %qT",
- BINFO_TYPE (virt_binfo));
- }
- }
- }
+ if (!result)
+ {
+ if (!allow_inverse_p)
+ {
+ error_not_base_type (from, to);
+ error (" in pointer to member conversion");
+ result = size_zero_node;
+ }
+ else
+ {
+ result = get_delta_difference_1 (to, from, c_cast_p);
+
+ if (result)
+ result = size_diffop (size_zero_node, result);
+ else
+ {
+ error_not_base_type (from, to);
+ error (" in pointer to member conversion");
+ result = size_zero_node;
+ }
+ }
+ }
return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node,
result));
CONSTRUCTOR_APPEND_ELT(v, delta_field, delta);
u = build_constructor (type, v);
TREE_CONSTANT (u) = TREE_CONSTANT (pfn) & TREE_CONSTANT (delta);
- TREE_INVARIANT (u) = TREE_INVARIANT (pfn) & TREE_INVARIANT (delta);
TREE_STATIC (u) = (TREE_CONSTANT (u)
&& (initializer_constant_valid_p (pfn, TREE_TYPE (pfn))
!= NULL_TREE)
if (same_type_p (to_type, pfn_type))
return pfn;
else if (integer_zerop (n))
- return build_reinterpret_cast (to_type, pfn);
+ return build_reinterpret_cast (to_type, pfn,
+ tf_warning_or_error);
}
if (TREE_SIDE_EFFECTS (pfn))
gcc_assert (same_type_ignoring_top_level_qualifiers_p
(TREE_TYPE (delta), ptrdiff_type_node));
if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_delta)
- n = cp_build_binary_op (LSHIFT_EXPR, n, integer_one_node);
- delta = cp_build_binary_op (PLUS_EXPR, delta, n);
+ n = cp_build_binary_op (LSHIFT_EXPR, n, integer_one_node,
+ tf_warning_or_error);
+ delta = cp_build_binary_op (PLUS_EXPR, delta, n, tf_warning_or_error);
return build_ptrmemfunc1 (to_type, delta, npfn);
}
return build_ptrmemfunc_access_expr (t, pfn_identifier);
}
+/* Return an expression for DELTA from the pointer-to-member function
+ given by T. */
+
+static tree
+delta_from_ptrmemfunc (tree t)
+{
+ if (TREE_CODE (t) == PTRMEM_CST)
+ {
+ tree delta;
+ tree pfn;
+
+ expand_ptrmemfunc_cst (t, &delta, &pfn);
+ if (delta)
+ return delta;
+ }
+
+ return build_ptrmemfunc_access_expr (t, delta_identifier);
+}
+
/* 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
static tree
convert_for_assignment (tree type, tree rhs,
- const char *errtype, tree fndecl, int parmnum)
+ const char *errtype, tree fndecl, int parmnum,
+ tsubst_flags_t complain)
{
tree rhstype;
enum tree_code coder;
/* The RHS of an assignment cannot have void type. */
if (coder == VOID_TYPE)
{
- error ("void value not ignored as it ought to be");
+ if (complain & tf_error)
+ error ("void value not ignored as it ought to be");
return error_mark_node;
}
rhs = cp_convert (strip_top_quals (type), rhs);
else
{
- /* If the right-hand side has unknown type, then it is an
- overloaded function. Call instantiate_type to get error
- messages. */
- if (rhstype == unknown_type_node)
- instantiate_type (type, rhs, tf_warning_or_error);
- else if (fndecl)
- error ("cannot convert %qT to %qT for argument %qP to %qD",
- rhstype, type, parmnum, fndecl);
- else
- error ("cannot convert %qT to %qT in %s", rhstype, type, errtype);
+ if (complain & tf_error)
+ {
+ /* If the right-hand side has unknown type, then it is an
+ overloaded function. Call instantiate_type to get error
+ messages. */
+ if (rhstype == unknown_type_node)
+ instantiate_type (type, rhs, tf_warning_or_error);
+ else if (fndecl)
+ error ("cannot convert %qT to %qT for argument %qP to %qD",
+ rhstype, type, parmnum, fndecl);
+ else
+ error ("cannot convert %qT to %qT in %s", rhstype, type,
+ errtype);
+ }
return error_mark_node;
}
}
const enum tree_code codel = TREE_CODE (type);
if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
&& coder == codel
- && check_missing_format_attribute (type, rhstype))
+ && check_missing_format_attribute (type, rhstype)
+ && (complain & tf_warning))
warning (OPT_Wmissing_format_attribute,
"%s might be a candidate for a format attribute",
errtype);
&& type == boolean_type_node
&& TREE_CODE (rhs) == MODIFY_EXPR
&& !TREE_NO_WARNING (rhs)
- && TREE_TYPE (rhs) != boolean_type_node)
+ && TREE_TYPE (rhs) != boolean_type_node
+ && (complain & tf_warning))
{
warning (OPT_Wparentheses,
"suggest parentheses around assignment used as truth value");
TREE_NO_WARNING (rhs) = 1;
}
- return perform_implicit_conversion (strip_top_quals (type), rhs);
+ return perform_implicit_conversion (strip_top_quals (type), rhs, complain);
}
/* Convert RHS to be of type TYPE.
tree
convert_for_initialization (tree exp, tree type, tree rhs, int flags,
- const char *errtype, tree fndecl, int parmnum)
+ const char *errtype, tree fndecl, int parmnum,
+ tsubst_flags_t complain)
{
enum tree_code codel = TREE_CODE (type);
tree rhstype;
type = complete_type (type);
- if (IS_AGGR_TYPE (type))
+ if (MAYBE_CLASS_TYPE_P (type))
return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
- return convert_for_assignment (type, rhs, errtype, fndecl, parmnum);
+ return convert_for_assignment (type, rhs, errtype, fndecl, parmnum,
+ complain);
}
\f
/* If RETVAL is the address of, or a reference to, a local variable or
{
if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
whats_returned = TREE_OPERAND (whats_returned, 1);
- else if (TREE_CODE (whats_returned) == CONVERT_EXPR
- || TREE_CODE (whats_returned) == NON_LVALUE_EXPR
- || TREE_CODE (whats_returned) == NOP_EXPR)
+ else if (CONVERT_EXPR_P (whats_returned)
+ || TREE_CODE (whats_returned) == NON_LVALUE_EXPR)
whats_returned = TREE_OPERAND (whats_returned, 0);
else
break;
if (processing_template_decl)
{
current_function_returns_value = 1;
- check_for_bare_parameter_packs (retval);
+ if (check_for_bare_parameter_packs (retval))
+ retval = error_mark_node;
return retval;
}
function. */
&& same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
(TYPE_MAIN_VARIANT
- (TREE_TYPE (TREE_TYPE (current_function_decl))))));
+ (TREE_TYPE (TREE_TYPE (current_function_decl)))))
+ /* And the returned value must be non-volatile. */
+ && ! TYPE_VOLATILE (TREE_TYPE (retval)));
if (fn_returns_value_p && flag_elide_constructors)
{
to the type of return value's location to handle the
case that functype is smaller than the valtype. */
retval = convert_for_initialization
- (NULL_TREE, functype, retval, flags, "return", NULL_TREE, 0);
+ (NULL_TREE, functype, retval, flags, "return", NULL_TREE, 0,
+ tf_warning_or_error);
retval = convert (valtype, retval);
/* If the conversion failed, treat this just like `return;'. */
if (retval == error_mark_node)
return retval;
/* We can't initialize a register from a AGGR_INIT_EXPR. */
- else if (! current_function_returns_struct
+ else if (! cfun->returns_struct
&& TREE_CODE (retval) == TARGET_EXPR
&& TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
int
cp_type_quals (const_tree type)
{
- type = const_strip_array_types (type);
+ /* This CONST_CAST is okay because strip_array_types returns it's
+ argument unmodified and we assign it to a const_tree. */
+ type = strip_array_types (CONST_CAST_TREE(type));
if (type == error_mark_node)
return TYPE_UNQUALIFIED;
return TYPE_QUALS (type);
bool
cp_type_readonly (const_tree type)
{
- type = const_strip_array_types (type);
+ /* This CONST_CAST is okay because strip_array_types returns it's
+ argument unmodified and we assign it to a const_tree. */
+ type = strip_array_types (CONST_CAST_TREE(type));
return TYPE_READONLY (type);
}
bool
cp_has_mutable_p (const_tree type)
{
- type = const_strip_array_types (type);
+ /* This CONST_CAST is okay because strip_array_types returns it's
+ argument unmodified and we assign it to a const_tree. */
+ type = strip_array_types (CONST_CAST_TREE(type));
return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
}
-/* Apply the TYPE_QUALS to the new DECL. */
+/* Set TREE_READONLY and TREE_VOLATILE on DECL as indicated by the
+ TYPE_QUALS. For a VAR_DECL, this may be an optimistic
+ approximation. In particular, consider:
+
+ int f();
+ struct S { int i; };
+ const S s = { f(); }
+
+ Here, we will make "s" as TREE_READONLY (because it is declared
+ "const") -- only to reverse ourselves upon seeing that the
+ initializer is non-constant. */
+
void
cp_apply_type_quals_to_decl (int type_quals, tree decl)
{
how the lvalue is being used and so selects the error message. */
int
-lvalue_or_else (const_tree ref, enum lvalue_use use)
+lvalue_or_else (const_tree ref, enum lvalue_use use, tsubst_flags_t complain)
{
int win = lvalue_p (ref);
- if (!win)
+ if (!win && (complain & tf_error))
lvalue_error (use);
return win;