/* 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)
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This file is part of the C++ front end.
#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 (tree, tree, bool);
+static bool comp_array_types (const_tree, const_tree, bool);
static tree pointer_diff (tree, tree, tree);
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);
-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.)
/* Return truthvalue of whether type of EXP is instantiated. */
int
-type_unknown_p (tree exp)
+type_unknown_p (const_tree exp)
{
return (TREE_CODE (exp) == TREE_LIST
|| TREE_TYPE (exp) == unknown_type_node);
/* FIXME: Attributes. */
gcc_assert (ARITHMETIC_TYPE_P (t1)
- || TREE_CODE (t1) == COMPLEX_TYPE
|| TREE_CODE (t1) == VECTOR_TYPE
|| TREE_CODE (t1) == ENUMERAL_TYPE);
gcc_assert (ARITHMETIC_TYPE_P (t2)
- || TREE_CODE (t2) == COMPLEX_TYPE
|| TREE_CODE (t2) == VECTOR_TYPE
|| TREE_CODE (t2) == ENUMERAL_TYPE);
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);
code2 = TREE_CODE (t2);
if ((ARITHMETIC_TYPE_P (t1) || code1 == ENUMERAL_TYPE
- || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
+ || code1 == VECTOR_TYPE)
&& (ARITHMETIC_TYPE_P (t2) || code2 == ENUMERAL_TYPE
- || code2 == COMPLEX_TYPE || code2 == VECTOR_TYPE))
+ || code2 == VECTOR_TYPE))
return type_after_usual_arithmetic_conversions (t1, t2);
else if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
|| (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 ();
}
we should try to make use of that. */
bool
-comp_except_specs (tree t1, tree t2, bool exact)
+comp_except_specs (const_tree t1, const_tree t2, bool exact)
{
- tree probe;
- tree base;
+ const_tree probe;
+ const_tree base;
int length = 0;
if (t1 == t2)
[] can match [size]. */
static bool
-comp_array_types (tree t1, tree t2, bool allow_redeclaration)
+comp_array_types (const_tree t1, const_tree t2, bool allow_redeclaration)
{
tree d1;
tree d2;
/* TYPENAME_TYPEs should be resolved if the qualifying scope is the
current instantiation. */
if (TREE_CODE (t1) == TYPENAME_TYPE)
- {
- tree resolved = resolve_typename_type (t1, /*only_current_p=*/true);
-
- if (resolved != error_mark_node)
- t1 = resolved;
- }
+ t1 = resolve_typename_type (t1, /*only_current_p=*/true);
if (TREE_CODE (t2) == TYPENAME_TYPE)
- {
- tree resolved = resolve_typename_type (t2, /*only_current_p=*/true);
-
- if (resolved != error_mark_node)
- t2 = resolved;
- }
+ t2 = resolve_typename_type (t2, /*only_current_p=*/true);
if (TYPE_PTRMEMFUNC_P (t1))
t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
/* 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)
return false;
break;
- case POINTER_TYPE:
case REFERENCE_TYPE:
+ if (TYPE_REF_IS_RVALUE (t1) != TYPE_REF_IS_RVALUE (t2))
+ return false;
+ /* fall through to checks for pointer types */
+
+ case POINTER_TYPE:
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 same_type_p (PACK_EXPANSION_PATTERN (t1),
PACK_EXPANSION_PATTERN (t2));
+ case DECLTYPE_TYPE:
+ if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
+ != DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2)
+ || !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1),
+ DECLTYPE_TYPE_EXPR (t2)))
+ return false;
+ break;
+
default:
return false;
}
{
if (strict == COMPARE_STRICT)
{
- bool result;
-
if (t1 == t2)
return true;
perform a deep check. */
return structural_comptypes (t1, t2, strict);
- if (VERIFY_CANONICAL_TYPES)
+#ifdef ENABLE_CHECKING
+ if (USE_CANONICAL_TYPES)
{
- result = structural_comptypes (t1, t2, strict);
-
+ bool result = structural_comptypes (t1, t2, strict);
+
if (result && TYPE_CANONICAL (t1) != TYPE_CANONICAL (t2))
- {
- /* The two types are structurally equivalent, but their
- canonical types were different. This is a failure of the
- canonical type propagation code.*/
- warning(0,
- "canonical types differ for identical types %T and %T",
- t1, t2);
- debug_tree (t1);
- debug_tree (t2);
- }
+ /* The two types are structurally equivalent, but their
+ canonical types were different. This is a failure of the
+ canonical type propagation code.*/
+ internal_error
+ ("canonical types differ for identical types %T and %T",
+ t1, t2);
else if (!result && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2))
- {
- /* Two types are structurally different, but the canonical
- types are the same. This means we were over-eager in
- assigning canonical types. */
- warning (0,
- "same canonical type node for different types %T and %T",
- t1, t2);
- debug_tree (t1);
- debug_tree (t2);
- }
+ /* Two types are structurally different, but the canonical
+ types are the same. This means we were over-eager in
+ assigning canonical types. */
+ internal_error
+ ("same canonical type node for different types %T and %T",
+ t1, t2);
return result;
}
- else
+#else
+ if (USE_CANONICAL_TYPES)
return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
+#endif
+ else
+ return structural_comptypes (t1, t2, strict);
}
else if (strict == COMPARE_STRUCTURAL)
return structural_comptypes (t1, t2, COMPARE_STRICT);
/* Returns 1 if TYPE1 is at least as qualified as TYPE2. */
bool
-at_least_as_qualified_p (tree type1, tree type2)
+at_least_as_qualified_p (const_tree type1, const_tree type2)
{
int q1 = cp_type_quals (type1);
int q2 = cp_type_quals (type2);
more cv-qualified that TYPE1, and 0 otherwise. */
int
-comp_cv_qualification (tree type1, tree type2)
+comp_cv_qualification (const_tree type1, const_tree type2)
{
int q1 = cp_type_quals (type1);
int q2 = cp_type_quals (type2);
element by element. */
bool
-compparms (tree parms1, tree parms2)
+compparms (const_tree parms1, const_tree parms2)
{
- tree t1, t2;
+ const_tree t1, t2;
/* An unspecified parmlist matches any specified parmlist
whose argument types don't need default promotions. */
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");
- t = size_one_node;
+ 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
+ t = size_one_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;
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 (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;
of the bitfield. Otherwise, return NULL_TREE. */
tree
-is_bitfield_expr_with_lowered_type (tree exp)
+is_bitfield_expr_with_lowered_type (const_tree exp)
{
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;
}
than NULL_TREE. */
tree
-unlowered_expr_type (tree exp)
+unlowered_expr_type (const_tree exp)
{
tree type;
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);
}
decay_conversion to one. */
int
-string_conv_p (tree totype, tree exp, int warn)
+string_conv_p (const_tree totype, const_tree exp, int warn)
{
tree t;
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 (CONVERT_EXPR_P (ptr)
+ || TREE_CODE (ptr) == VIEW_CONVERT_EXPR)
+ {
+ /* If a warning is issued, mark it to avoid duplicates from
+ the backend. This only needs to be done at
+ warn_strict_aliasing > 2. */
+ if (warn_strict_aliasing > 2)
+ if (strict_aliasing_warning (TREE_TYPE (TREE_OPERAND (ptr, 0)),
+ type, TREE_OPERAND (ptr, 0)))
+ TREE_NO_WARNING (ptr) = 1;
+ }
+
if (VOID_TYPE_P (t))
{
/* 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:
return error_mark_node;
}
/* ...and then the delta in the PMF. */
- instance_ptr = build2 (PLUS_EXPR, TREE_TYPE (instance_ptr),
- instance_ptr, delta);
+ instance_ptr = build2 (POINTER_PLUS_EXPR, TREE_TYPE (instance_ptr),
+ instance_ptr, fold_convert (sizetype, delta));
/* Hand back the adjusted 'this' argument to our caller. */
*instance_ptrptr = instance_ptr;
/* 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 (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx);
- e2 = build_indirect_ref (e2, NULL);
+ e2 = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
+ fold_convert (sizetype, idx));
+ 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));
- TREE_TYPE (e2) = TREE_TYPE (e3);
- e1 = build_conditional_expr (e1, e2, e3);
+ e2 = fold_convert (TREE_TYPE (e3), e2);
+ 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);
}
if (typetail != 0 && typetail != void_list_node)
{
- /* See if there are default arguments that can be used. */
- if (TREE_PURPOSE (typetail)
+ /* See if there are default arguments that can be used. Because
+ we hold default arguments in the FUNCTION_TYPE (which is so
+ wrong), we can see default parameters here from deduced
+ contexts (and via typeof) for indirect function calls.
+ Fortunately we know whether we have a function decl to
+ provide default arguments in a language conformant
+ manner. */
+ if (fndecl && TREE_PURPOSE (typetail)
&& TREE_CODE (TREE_PURPOSE (typetail)) != DEFAULT_ARG)
{
for (; typetail != void_list_node; ++i)
}
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;
}
}
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
if ((code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
- || (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE))
+ || (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+ && !VECTOR_FLOAT_TYPE_P (type0)
+ && !VECTOR_FLOAT_TYPE_P (type1)))
shorten = -1;
break;
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;
|| !same_scalar_type_ignoring_signedness (TREE_TYPE (type0),
TREE_TYPE (type1)))
{
- binary_op_error (code);
+ binary_op_error (code, type0, type1);
return error_mark_node;
}
arithmetic_types_p = 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;
}
/* 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);
+ {
+ /* Since the middle-end checks the type when doing a build2, we
+ need to build the tree in pieces. This built tree will never
+ get out of the front-end as we replace it when instantiating
+ the template. */
+ tree tmp = build2 (resultcode,
+ build_type ? build_type : result_type,
+ NULL_TREE, op1);
+ TREE_OPERAND (tmp, 0) = op0;
+ return tmp;
+ }
if (arithmetic_types_p)
{
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 = 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),
- build_unary_op (code, real, 1), imag);
+ real, imag);
}
/* Report invalid types. */
errstring ="no post-decrement operator for type";
break;
}
+ else if (arg == error_mark_node)
+ return error_mark_node;
/* 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
inc = cp_convert (argtype, inc);
- /* Handle incrementing a cast-expression. */
-
- switch (TREE_CODE (arg))
- {
- case NOP_EXPR:
- case CONVERT_EXPR:
- case FLOAT_EXPR:
- case FIX_TRUNC_EXPR:
- {
- tree incremented, modify, value, compound;
- if (! lvalue_p (arg) && pedantic)
- pedwarn ("cast to non-reference type used as lvalue");
- arg = stabilize_reference (arg);
- if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
- value = arg;
- else
- value = save_expr (arg);
- incremented = build2 (((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? PLUS_EXPR : MINUS_EXPR),
- argtype, value, inc);
-
- modify = build_modify_expr (arg, NOP_EXPR, incremented);
- compound = build2 (COMPOUND_EXPR, TREE_TYPE (arg),
- modify, value);
-
- /* Eliminate warning about unused result of + or -. */
- TREE_NO_WARNING (compound) = 1;
- return compound;
- }
-
- default:
- break;
- }
-
/* 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]. */
STRIP_NOPS (sexpr);
- strict_aliasing_warning (intype, type, sexpr);
+ if (warn_strict_aliasing <= 2)
+ strict_aliasing_warning (intype, type, sexpr);
return fold_if_not_in_template (build_nop (type, expr));
}
else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
|| (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
{
- if (pedantic)
+ 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
}
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)
+ else if (TREE_CODE (intype) == VECTOR_TYPE && INTEGRAL_TYPE_P (type))
return fold_if_not_in_template (convert_to_integer (type, expr));
else
{
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))
tree cond;
tree preeval = NULL_TREE;
+ if (VOID_TYPE_P (TREE_TYPE (rhs)))
+ {
+ if (complain & tf_error)
+ error ("void value not ignored as it ought to be");
+ return error_mark_node;
+ }
+
rhs = stabilize_expr (rhs, &preeval);
/* 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));
/* Make sure DELTA has the type we want. */
delta = convert_and_check (delta_type_node, delta);
+ /* Convert to the correct target type if necessary. */
+ pfn = fold_convert (TREE_TYPE (pfn_field), pfn);
+
/* Finish creating the initializer. */
v = VEC_alloc(constructor_elt, gc, 2);
CONSTRUCTOR_APPEND_ELT(v, pfn_field, pfn);
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;
promotions. */
tree valtype;
int fn_returns_value_p;
+ bool named_return_value_okay_p;
*no_warning = false;
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;
}
|| 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))
+ && retval && null_ptr_cst_p (retval))
warning (0, "%<operator new%> must not return NULL unless it is "
"declared %<throw()%> (or -fcheck-new is in effect)");
See finish_function and finalize_nrv for the rest of this optimization. */
+ named_return_value_okay_p =
+ (retval != NULL_TREE
+ /* Must be a local, automatic variable. */
+ && TREE_CODE (retval) == VAR_DECL
+ && DECL_CONTEXT (retval) == current_function_decl
+ && ! TREE_STATIC (retval)
+ && ! DECL_ANON_UNION_VAR_P (retval)
+ && (DECL_ALIGN (retval)
+ >= DECL_ALIGN (DECL_RESULT (current_function_decl)))
+ /* The cv-unqualified type of the returned value must be the
+ same as the cv-unqualified return type of the
+ function. */
+ && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
+ (TYPE_MAIN_VARIANT
+ (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)
{
- if (retval != NULL_TREE
- && (current_function_return_value == NULL_TREE
- || current_function_return_value == retval)
- && TREE_CODE (retval) == VAR_DECL
- && DECL_CONTEXT (retval) == current_function_decl
- && ! TREE_STATIC (retval)
- && (DECL_ALIGN (retval)
- >= DECL_ALIGN (DECL_RESULT (current_function_decl)))
- && same_type_p ((TYPE_MAIN_VARIANT
- (TREE_TYPE (retval))),
- (TYPE_MAIN_VARIANT
- (TREE_TYPE (TREE_TYPE (current_function_decl))))))
+ if (named_return_value_okay_p
+ && (current_function_return_value == NULL_TREE
+ || current_function_return_value == retval))
current_function_return_value = retval;
else
current_function_return_value = error_mark_node;
{
/* The type the function is declared to return. */
tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
+ int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
/* The functype's return type will have been set to void, if it
was an incomplete type. Just treat this as 'return;' */
if (VOID_TYPE_P (functype))
return error_mark_node;
+ /* Under C++0x [12.8/16 class.copy], a returned lvalue is sometimes
+ treated as an rvalue for the purposes of overload resolution to
+ favor move constructors over copy constructors. */
+ if ((cxx_dialect != cxx98)
+ && named_return_value_okay_p
+ /* The variable must not have the `volatile' qualifier. */
+ && !(cp_type_quals (TREE_TYPE (retval)) & TYPE_QUAL_VOLATILE)
+ /* The return type must be a class type. */
+ && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
+ flags = flags | LOOKUP_PREFER_RVALUE;
+
/* First convert the value to the function's return type, then
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, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
- "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,
type or inheritance-related types, regardless of cv-quals. */
int
-ptr_reasonably_similar (tree to, tree from)
+ptr_reasonably_similar (const_tree to, const_tree from)
{
for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
{
elements for an array type. */
int
-cp_type_quals (tree type)
+cp_type_quals (const_tree type)
{
- type = 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);
}
+/* Returns nonzero if the TYPE is const from a C++ perspective: look inside
+ arrays. */
+
+bool
+cp_type_readonly (const_tree 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);
+}
+
/* Returns nonzero if the TYPE contains a mutable member. */
bool
-cp_has_mutable_p (tree type)
+cp_has_mutable_p (const_tree type)
{
- type = 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 (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;