/* Language-level data type conversion for GNU C++.
- Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 1987-2013 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
+#include "stor-layout.h"
#include "flags.h"
#include "cp-tree.h"
#include "intl.h"
#include "convert.h"
-#include "toplev.h"
#include "decl.h"
#include "target.h"
+#include "wide-int.h"
-static tree cp_convert_to_pointer (tree, tree);
-static tree convert_to_pointer_force (tree, tree);
+static tree cp_convert_to_pointer (tree, tree, tsubst_flags_t);
+static tree convert_to_pointer_force (tree, tree, tsubst_flags_t);
static tree build_type_conversion (tree, tree);
-static tree build_up_reference (tree, tree, int, tree);
-static void warn_ref_binding (tree, tree, tree);
+static tree build_up_reference (tree, tree, int, tree, tsubst_flags_t);
+static void diagnose_ref_binding (location_t, tree, tree, tree);
/* Change of width--truncation and extension of integers or reals--
is represented with NOP_EXPR. Proper functioning of many things
else try C-style pointer conversion. */
static tree
-cp_convert_to_pointer (tree type, tree expr)
+cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
{
tree intype = TREE_TYPE (expr);
enum tree_code form;
tree rval;
+ location_t loc = EXPR_LOC_OR_HERE (expr);
+
if (intype == error_mark_node)
return error_mark_node;
intype = complete_type (intype);
if (!COMPLETE_TYPE_P (intype))
{
- error ("can't convert from incomplete type %qT to %qT",
- intype, type);
+ if (complain & tf_error)
+ error_at (loc, "can%'t convert from incomplete type %qT to %qT",
+ intype, type);
return error_mark_node;
}
rval = build_type_conversion (type, expr);
if (rval)
{
- if (rval == error_mark_node)
- error ("conversion of %qE from %qT to %qT is ambiguous",
- expr, intype, type);
+ if ((complain & tf_error)
+ && rval == error_mark_node)
+ error_at (loc, "conversion of %qE from %qT to %qT is ambiguous",
+ expr, intype, type);
return rval;
}
}
/* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */
- if (TREE_CODE (type) == POINTER_TYPE
+ if (TYPE_PTR_P (type)
&& (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
|| VOID_TYPE_P (TREE_TYPE (type))))
{
if (TYPE_PTRMEMFUNC_P (intype)
|| TREE_CODE (intype) == METHOD_TYPE)
- return convert_member_func_to_ptr (type, expr);
- if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
+ return convert_member_func_to_ptr (type, expr, complain);
+ if (TYPE_PTR_P (TREE_TYPE (expr)))
return build_nop (type, expr);
intype = TREE_TYPE (expr);
}
intype = TYPE_MAIN_VARIANT (intype);
if (TYPE_MAIN_VARIANT (type) != intype
- && TREE_CODE (type) == POINTER_TYPE
+ && TYPE_PTR_P (type)
&& TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
&& MAYBE_CLASS_TYPE_P (TREE_TYPE (type))
&& MAYBE_CLASS_TYPE_P (TREE_TYPE (intype))
binfo = NULL_TREE;
/* Try derived to base conversion. */
if (!same_p)
- binfo = lookup_base (intype_class, type_class, ba_check, NULL);
+ binfo = lookup_base (intype_class, type_class, ba_check,
+ NULL, complain);
if (!same_p && !binfo)
{
/* Try base to derived conversion. */
- binfo = lookup_base (type_class, intype_class, ba_check, NULL);
+ binfo = lookup_base (type_class, intype_class, ba_check,
+ NULL, complain);
code = MINUS_EXPR;
}
if (binfo == error_mark_node)
if (binfo || same_p)
{
if (binfo)
- expr = build_base_path (code, expr, binfo, 0);
+ expr = build_base_path (code, expr, binfo, 0, complain);
/* Add any qualifier conversions. */
return build_nop (type, expr);
}
if (TYPE_PTRMEMFUNC_P (type))
{
- error ("cannot convert %qE from type %qT to type %qT",
- expr, intype, type);
+ if (complain & tf_error)
+ error_at (loc, "cannot convert %qE from type %qT to type %qT",
+ expr, intype, type);
return error_mark_node;
}
return build_nop (type, expr);
}
- else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+ else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
return convert_ptrmem (type, expr, /*allow_inverse_p=*/false,
- /*c_cast_p=*/false);
+ /*c_cast_p=*/false, complain);
else if (TYPE_PTRMEMFUNC_P (intype))
{
if (!warn_pmf2ptr)
{
if (TREE_CODE (expr) == PTRMEM_CST)
- return cp_convert_to_pointer (type,
- PTRMEM_CST_MEMBER (expr));
+ return cp_convert_to_pointer (type, PTRMEM_CST_MEMBER (expr),
+ complain);
else if (TREE_CODE (expr) == OFFSET_REF)
{
tree object = TREE_OPERAND (expr, 0);
return get_member_function_from_ptrfunc (&object,
- TREE_OPERAND (expr, 1));
+ TREE_OPERAND (expr, 1),
+ complain);
}
}
- error ("cannot convert %qE from type %qT to type %qT",
- expr, intype, type);
+ error_at (loc, "cannot convert %qE from type %qT to type %qT",
+ expr, intype, type);
return error_mark_node;
}
- if (integer_zerop (expr))
+ if (null_ptr_cst_p (expr))
{
if (TYPE_PTRMEMFUNC_P (type))
return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
- /*c_cast_p=*/false);
+ /*c_cast_p=*/false, complain);
- if (TYPE_PTRMEM_P (type))
- {
- /* A NULL pointer-to-member is represented by -1, not by
- zero. */
- expr = build_int_cst_type (type, -1);
- }
- else
- expr = build_int_cst (type, 0);
+ if (complain & tf_warning)
+ maybe_warn_zero_as_null_pointer_constant (expr, loc);
+
+ /* A NULL pointer-to-data-member is represented by -1, not by
+ zero. */
+ tree val = (TYPE_PTRDATAMEM_P (type)
+ ? build_int_cst_type (type, -1)
+ : build_int_cst (type, 0));
- return expr;
+ return (TREE_SIDE_EFFECTS (expr)
+ ? build2 (COMPOUND_EXPR, type, expr, val) : val);
}
- else if (TYPE_PTR_TO_MEMBER_P (type) && INTEGRAL_CODE_P (form))
+ else if (TYPE_PTRMEM_P (type) && INTEGRAL_CODE_P (form))
{
- error ("invalid conversion from %qT to %qT", intype, type);
+ if (complain & tf_error)
+ error_at (loc, "invalid conversion from %qT to %qT", intype, type);
return error_mark_node;
}
{
if (TYPE_PRECISION (intype) == POINTER_SIZE)
return build1 (CONVERT_EXPR, type, expr);
- expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr);
+ expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr,
+ complain);
/* Modes may be different but sizes should be the same. There
is supposed to be some integral type that is the same width
as a pointer. */
}
if (type_unknown_p (expr))
- return instantiate_type (type, expr, tf_warning_or_error);
+ return instantiate_type (type, expr, complain);
- error ("cannot convert %qE from type %qT to type %qT",
- expr, intype, type);
+ if (complain & tf_error)
+ error_at (loc, "cannot convert %qE from type %qT to type %qT",
+ expr, intype, type);
return error_mark_node;
}
(such as conversion from sub-type to private super-type). */
static tree
-convert_to_pointer_force (tree type, tree expr)
+convert_to_pointer_force (tree type, tree expr, tsubst_flags_t complain)
{
tree intype = TREE_TYPE (expr);
enum tree_code form = TREE_CODE (intype);
tree binfo;
binfo = lookup_base (TREE_TYPE (intype), TREE_TYPE (type),
- ba_unique, NULL);
+ ba_unique, NULL, complain);
if (!binfo)
{
binfo = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
- ba_unique, NULL);
+ ba_unique, NULL, complain);
code = MINUS_EXPR;
}
if (binfo == error_mark_node)
return error_mark_node;
if (binfo)
{
- expr = build_base_path (code, expr, binfo, 0);
+ expr = build_base_path (code, expr, binfo, 0, complain);
if (expr == error_mark_node)
return error_mark_node;
/* Add any qualifier conversions. */
}
}
- return cp_convert_to_pointer (type, expr);
+ return cp_convert_to_pointer (type, expr, complain);
}
/* We are passing something to a function which requires a reference.
If DIRECT_BIND is set, DECL is the reference we're binding to. */
static tree
-build_up_reference (tree type, tree arg, int flags, tree decl)
+build_up_reference (tree type, tree arg, int flags, tree decl,
+ tsubst_flags_t complain)
{
tree rval;
tree argtype = TREE_TYPE (arg);
here because it needs to live as long as DECL. */
tree targ = arg;
- arg = make_temporary_var_for_ref_to_temp (decl, TREE_TYPE (arg));
+ arg = make_temporary_var_for_ref_to_temp (decl, target_type);
/* Process the initializer for the declaration. */
DECL_INITIAL (arg) = targ;
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
}
else if (!(flags & DIRECT_BIND) && ! lvalue_p (arg))
- return get_target_expr (arg);
+ return get_target_expr_sfinae (arg, complain);
/* If we had a way to wrap this up, and say, if we ever needed its
address, transform all occurrences of the register, into a memory
reference we could win better. */
- rval = cp_build_unary_op (ADDR_EXPR, arg, 1, tf_warning_or_error);
+ rval = cp_build_addr_expr (arg, complain);
if (rval == error_mark_node)
return error_mark_node;
&& MAYBE_CLASS_TYPE_P (target_type))
{
/* We go through lookup_base for the access control. */
- tree binfo = lookup_base (argtype, target_type, ba_check, NULL);
+ tree binfo = lookup_base (argtype, target_type, ba_check,
+ NULL, complain);
if (binfo == error_mark_node)
return error_mark_node;
if (binfo == NULL_TREE)
return error_not_base_type (target_type, argtype);
- rval = build_base_path (PLUS_EXPR, rval, binfo, 1);
+ rval = build_base_path (PLUS_EXPR, rval, binfo, 1, complain);
}
else
rval
- = convert_to_pointer_force (build_pointer_type (target_type), rval);
+ = convert_to_pointer_force (build_pointer_type (target_type),
+ rval, complain);
return build_nop (type, rval);
}
non-volatile const type. */
static void
-warn_ref_binding (tree reftype, tree intype, tree decl)
+diagnose_ref_binding (location_t loc, tree reftype, tree intype, tree decl)
{
tree ttl = TREE_TYPE (reftype);
msg = G_("conversion to non-const reference type %q#T from "
"rvalue of type %qT");
- permerror (input_location, msg, reftype, intype);
+ permerror (loc, msg, reftype, intype);
}
}
tree
convert_to_reference (tree reftype, tree expr, int convtype,
- int flags, tree decl)
+ int flags, tree decl, tsubst_flags_t complain)
{
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (reftype));
tree intype;
tree rval = NULL_TREE;
tree rval_as_conversion = NULL_TREE;
bool can_convert_intype_to_type;
+ location_t loc = EXPR_LOC_OR_HERE (expr);
if (TREE_CODE (type) == FUNCTION_TYPE
&& TREE_TYPE (expr) == unknown_type_node)
- expr = instantiate_type (type, expr,
- (flags & LOOKUP_COMPLAIN)
- ? tf_warning_or_error : tf_none);
+ expr = instantiate_type (type, expr, complain);
if (expr == error_mark_node)
return error_mark_node;
intype = TYPE_MAIN_VARIANT (intype);
- can_convert_intype_to_type = can_convert (type, intype);
+ can_convert_intype_to_type = can_convert_standard (type, intype, complain);
+
if (!can_convert_intype_to_type
&& (convtype & CONV_IMPLICIT) && MAYBE_CLASS_TYPE_P (intype)
&& ! (flags & LOOKUP_NO_CONVERSION))
}
}
- if (((convtype & CONV_STATIC) && can_convert (intype, type))
+ if (((convtype & CONV_STATIC)
+ && can_convert_standard (intype, type, complain))
|| ((convtype & CONV_IMPLICIT) && can_convert_intype_to_type))
{
- if (flags & LOOKUP_COMPLAIN)
- {
- tree ttl = TREE_TYPE (reftype);
- tree ttr = lvalue_type (expr);
+ {
+ tree ttl = TREE_TYPE (reftype);
+ tree ttr = lvalue_type (expr);
- if (! real_lvalue_p (expr))
- warn_ref_binding (reftype, intype, decl);
+ if ((complain & tf_error)
+ && ! real_lvalue_p (expr))
+ diagnose_ref_binding (loc, reftype, intype, decl);
- if (! (convtype & CONV_CONST)
- && !at_least_as_qualified_p (ttl, ttr))
- permerror (input_location, "conversion from %qT to %qT discards qualifiers",
- ttr, reftype);
- }
+ if (! (convtype & CONV_CONST)
+ && !at_least_as_qualified_p (ttl, ttr))
+ {
+ if (complain & tf_error)
+ permerror (loc, "conversion from %qT to %qT discards qualifiers",
+ ttr, reftype);
+ else
+ return error_mark_node;
+ }
+ }
- return build_up_reference (reftype, expr, flags, decl);
+ return build_up_reference (reftype, expr, flags, decl, complain);
}
else if ((convtype & CONV_REINTERPRET) && lvalue_p (expr))
{
/* B* bp; A& ar = (A&)bp; is valid, but it's probably not what they
meant. */
- if (TREE_CODE (intype) == POINTER_TYPE
+ if ((complain & tf_warning)
+ && TYPE_PTR_P (intype)
&& (comptypes (TREE_TYPE (intype), type,
COMPARE_BASE | COMPARE_DERIVED)))
- warning (0, "casting %qT to %qT does not dereference pointer",
- intype, reftype);
+ warning_at (loc, 0, "casting %qT to %qT does not dereference pointer",
+ intype, reftype);
- rval = cp_build_unary_op (ADDR_EXPR, expr, 0, tf_warning_or_error);
+ rval = cp_build_addr_expr (expr, complain);
if (rval != error_mark_node)
rval = convert_force (build_pointer_type (TREE_TYPE (reftype)),
- rval, 0);
+ rval, 0, complain);
if (rval != error_mark_node)
rval = build1 (NOP_EXPR, reftype, rval);
}
else
{
rval = convert_for_initialization (NULL_TREE, type, expr, flags,
- "converting", 0, 0,
- tf_warning_or_error);
+ ICR_CONVERTING, 0, 0, complain);
if (rval == NULL_TREE || rval == error_mark_node)
return rval;
- warn_ref_binding (reftype, intype, decl);
- rval = build_up_reference (reftype, rval, flags, decl);
+ if (complain & tf_error)
+ diagnose_ref_binding (loc, reftype, intype, decl);
+ rval = build_up_reference (reftype, rval, flags, decl, complain);
}
if (rval)
return rval;
}
- if (flags & LOOKUP_COMPLAIN)
- error ("cannot convert type %qT to type %qT", intype, reftype);
+ if (complain & tf_error)
+ error_at (loc, "cannot convert type %qT to type %qT", intype, reftype);
return error_mark_node;
}
tree t = TREE_TYPE (TREE_TYPE (val));
tree ref = build1 (INDIRECT_REF, t, val);
+ mark_exp_read (val);
/* We *must* set TREE_READONLY when dereferencing a pointer to const,
so that we get the proper error message if the result is used
to assign to. Also, &* is supposed to be a no-op. */
TREE_THIS_VOLATILE (ref) = CP_TYPE_VOLATILE_P (t);
TREE_SIDE_EFFECTS (ref)
= (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (val));
- REFERENCE_REF_P (ref) = 1;
val = ref;
}
argument of class type into a temporary. */
tree
-force_rvalue (tree expr)
+force_rvalue (tree expr, tsubst_flags_t complain)
{
- if (MAYBE_CLASS_TYPE_P (TREE_TYPE (expr)) && TREE_CODE (expr) != TARGET_EXPR)
- expr = ocp_convert (TREE_TYPE (expr), expr,
- CONV_IMPLICIT|CONV_FORCE_TEMP, LOOKUP_NORMAL);
+ tree type = TREE_TYPE (expr);
+ if (MAYBE_CLASS_TYPE_P (type) && TREE_CODE (expr) != TARGET_EXPR)
+ {
+ vec<tree, va_gc> *args = make_tree_vector_single (expr);
+ expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
+ &args, type, LOOKUP_NORMAL, complain);
+ release_tree_vector (args);
+ expr = build_cplus_new (type, expr, complain);
+ }
else
- expr = decay_conversion (expr);
+ expr = decay_conversion (expr, complain);
return expr;
}
\f
-/* Fold away simple conversions, but make sure the result is an rvalue. */
+/* If EXPR and ORIG are INTEGER_CSTs, return a version of EXPR that has
+ TREE_OVERFLOW set only if it is set in ORIG. Otherwise, return EXPR
+ unchanged. */
+
+static tree
+ignore_overflows (tree expr, tree orig)
+{
+ if (TREE_CODE (expr) == INTEGER_CST
+ && TREE_CODE (orig) == INTEGER_CST
+ && TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig))
+ {
+ gcc_assert (!TREE_OVERFLOW (orig));
+ /* Ensure constant sharing. */
+ expr = wide_int_to_tree (TREE_TYPE (expr), expr);
+ }
+ return expr;
+}
+
+/* Fold away simple conversions, but make sure TREE_OVERFLOW is set
+ properly. */
tree
cp_fold_convert (tree type, tree expr)
{
- return rvalue (fold_convert (type, expr));
+ tree conv = fold_convert (type, expr);
+ conv = ignore_overflows (conv, expr);
+ return conv;
}
/* C++ conversions, preference to static cast conversions. */
tree
-cp_convert (tree type, tree expr)
+cp_convert (tree type, tree expr, tsubst_flags_t complain)
{
- return ocp_convert (type, expr, CONV_OLD_CONVERT, LOOKUP_NORMAL);
+ return ocp_convert (type, expr, CONV_OLD_CONVERT, LOOKUP_NORMAL, complain);
}
/* C++ equivalent of convert_and_check but using cp_convert as the
i.e. because of language rules and not because of an explicit cast. */
tree
-cp_convert_and_check (tree type, tree expr)
+cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
{
tree result;
if (TREE_TYPE (expr) == type)
return expr;
- result = cp_convert (type, expr);
+ result = cp_convert (type, expr, complain);
- if (c_inhibit_evaluation_warnings == 0
- && !TREE_OVERFLOW_P (expr)
- && result != error_mark_node)
- warnings_for_convert_and_check (type, expr, result);
+ if ((complain & tf_warning)
+ && c_inhibit_evaluation_warnings == 0)
+ {
+ tree folded = maybe_constant_value (expr);
+ tree stripped = folded;
+ tree folded_result = cp_convert (type, folded, complain);
+
+ /* maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW in a
+ NOP_EXPR so that it isn't TREE_CONSTANT anymore. */
+ STRIP_NOPS (stripped);
+
+ if (!TREE_OVERFLOW_P (stripped)
+ && folded_result != error_mark_node)
+ warnings_for_convert_and_check (type, folded, folded_result);
+ }
return result;
}
FLAGS indicates how we should behave. */
tree
-ocp_convert (tree type, tree expr, int convtype, int flags)
+ocp_convert (tree type, tree expr, int convtype, int flags,
+ tsubst_flags_t complain)
{
tree e = expr;
enum tree_code code = TREE_CODE (type);
const char *invalid_conv_diag;
tree e1;
+ location_t loc = EXPR_LOC_OR_HERE (expr);
if (error_operand_p (e) || type == error_mark_node)
return error_mark_node;
if ((invalid_conv_diag
= targetm.invalid_conversion (TREE_TYPE (expr), type)))
{
- error (invalid_conv_diag);
+ if (complain & tf_error)
+ error (invalid_conv_diag);
return error_mark_node;
}
- e = integral_constant_value (e);
+ /* FIXME remove when moving to c_fully_fold model. */
+ /* FIXME do we still need this test? */
+ if (!CLASS_TYPE_P (type))
+ e = integral_constant_value (e);
if (error_operand_p (e))
return error_mark_node;
conversion. */
else if (TREE_CODE (type) == COMPLEX_TYPE)
return fold_if_not_in_template (convert_to_complex (type, e));
+ else if (TREE_CODE (type) == VECTOR_TYPE)
+ return fold_if_not_in_template (convert_to_vector (type, e));
else if (TREE_CODE (e) == TARGET_EXPR)
{
/* Don't build a NOP_EXPR of class type. Instead, change the
if (code == VOID_TYPE && (convtype & CONV_STATIC))
{
- e = convert_to_void (e, /*implicit=*/NULL, tf_warning_or_error);
+ e = convert_to_void (e, ICV_CAST, complain);
return e;
}
if (INTEGRAL_CODE_P (code))
{
tree intype = TREE_TYPE (e);
+ tree converted;
if (TREE_CODE (type) == ENUMERAL_TYPE)
{
if (((INTEGRAL_OR_ENUMERATION_TYPE_P (intype)
|| TREE_CODE (intype) == REAL_TYPE)
&& ! (convtype & CONV_STATIC))
- || TREE_CODE (intype) == POINTER_TYPE)
+ || TYPE_PTR_P (intype))
{
- if (flags & LOOKUP_COMPLAIN)
- permerror (input_location, "conversion from %q#T to %q#T", intype, type);
-
- if (!flag_permissive)
+ if (complain & tf_error)
+ permerror (loc, "conversion from %q#T to %q#T", intype, type);
+ else
return error_mark_node;
}
the original value is within the range of the enumeration
values. Otherwise, the resulting enumeration value is
unspecified. */
- if (TREE_CODE (expr) == INTEGER_CST
- && !int_fits_type_p (expr, ENUM_UNDERLYING_TYPE (type)))
- warning (OPT_Wconversion,
- "the result of the conversion is unspecified because "
- "%qE is outside the range of type %qT",
- expr, type);
+ if ((complain & tf_warning)
+ && TREE_CODE (e) == INTEGER_CST
+ && !int_fits_type_p (e, ENUM_UNDERLYING_TYPE (type)))
+ warning_at (loc, OPT_Wconversion,
+ "the result of the conversion is unspecified because "
+ "%qE is outside the range of type %qT",
+ expr, type);
}
if (MAYBE_CLASS_TYPE_P (intype))
{
rval = build_type_conversion (type, e);
if (rval)
return rval;
- if (flags & LOOKUP_COMPLAIN)
- error ("%q#T used where a %qT was expected", intype, type);
+ if (complain & tf_error)
+ error_at (loc, "%q#T used where a %qT was expected", intype, type);
return error_mark_node;
}
if (code == BOOLEAN_TYPE)
- return cp_truthvalue_conversion (e);
+ {
+ if (VOID_TYPE_P (intype))
+ {
+ if (complain & tf_error)
+ error_at (loc,
+ "could not convert %qE from %<void%> to %<bool%>",
+ expr);
+ return error_mark_node;
+ }
+
+ /* We can't implicitly convert a scoped enum to bool, so convert
+ to the underlying type first. */
+ if (SCOPED_ENUM_P (intype) && (convtype & CONV_STATIC))
+ e = build_nop (ENUM_UNDERLYING_TYPE (intype), e);
+ return cp_truthvalue_conversion (e);
+ }
+
+ converted = fold_if_not_in_template (convert_to_integer (type, e));
- return fold_if_not_in_template (convert_to_integer (type, e));
+ /* Ignore any integer overflow caused by the conversion. */
+ return ignore_overflows (converted, e);
}
- if (code == NULLPTR_TYPE && e && null_ptr_cst_p (e))
- return nullptr_node;
- if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type))
- return fold_if_not_in_template (cp_convert_to_pointer (type, e));
+ if (NULLPTR_TYPE_P (type) && e && null_ptr_cst_p (e))
+ {
+ if (complain & tf_warning)
+ maybe_warn_zero_as_null_pointer_constant (e, loc);
+ return nullptr_node;
+ }
+ if (POINTER_TYPE_P (type) || TYPE_PTRMEM_P (type))
+ return fold_if_not_in_template (cp_convert_to_pointer (type, e, complain));
if (code == VECTOR_TYPE)
{
tree in_vtype = TREE_TYPE (e);
ret_val = build_type_conversion (type, e);
if (ret_val)
return ret_val;
- if (flags & LOOKUP_COMPLAIN)
- error ("%q#T used where a %qT was expected", in_vtype, type);
+ if (complain & tf_error)
+ error_at (loc, "%q#T used where a %qT was expected",
+ in_vtype, type);
return error_mark_node;
}
return fold_if_not_in_template (convert_to_vector (type, e));
rval = build_type_conversion (type, e);
if (rval)
return rval;
- else
- if (flags & LOOKUP_COMPLAIN)
- error ("%q#T used where a floating point value was expected",
- TREE_TYPE (e));
+ else if (complain & tf_error)
+ error_at (loc,
+ "%q#T used where a floating point value was expected",
+ TREE_TYPE (e));
}
if (code == REAL_TYPE)
return fold_if_not_in_template (convert_to_real (type, e));
ctor = e;
- if (abstract_virtuals_error (NULL_TREE, type))
+ if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain))
return error_mark_node;
if (BRACE_ENCLOSED_INITIALIZER_P (ctor))
- ctor = perform_implicit_conversion (type, ctor, tf_warning_or_error);
+ ctor = perform_implicit_conversion (type, ctor, complain);
else if ((flags & LOOKUP_ONLYCONVERTING)
&& ! (CLASS_TYPE_P (dtype) && DERIVED_FROM_P (type, dtype)))
/* For copy-initialization, first we create a temp of the proper type
with a user-defined conversion sequence, then we direct-initialize
the target with the temp (see [dcl.init]). */
- ctor = build_user_type_conversion (type, ctor, flags);
+ ctor = build_user_type_conversion (type, ctor, flags, complain);
else
{
- VEC(tree,gc) *ctor_vec = make_tree_vector_single (ctor);
+ vec<tree, va_gc> *ctor_vec = make_tree_vector_single (ctor);
ctor = build_special_member_call (NULL_TREE,
complete_ctor_identifier,
&ctor_vec,
- type, flags,
- tf_warning_or_error);
+ type, flags, complain);
release_tree_vector (ctor_vec);
}
if (ctor)
- return build_cplus_new (type, ctor);
+ return build_cplus_new (type, ctor, complain);
}
- if (flags & LOOKUP_COMPLAIN)
+ if (complain & tf_error)
{
/* If the conversion failed and expr was an invalid use of pointer to
member function, try to report a meaningful error. */
- if (invalid_nonstatic_memfn_p (expr, tf_warning_or_error))
+ if (invalid_nonstatic_memfn_p (expr, complain))
/* We displayed the error message. */;
else
- error ("conversion from %qT to non-scalar type %qT requested",
- TREE_TYPE (expr), type);
+ error_at (loc, "conversion from %qT to non-scalar type %qT requested",
+ TREE_TYPE (expr), type);
}
return error_mark_node;
}
make it impossible to ignore the reference return value from functions. We
issue warnings in the confusing cases.
- IMPLICIT is non-NULL iff an expression is being implicitly converted; it
- is NULL when the user is explicitly converting an expression to void via
- a cast. When non-NULL, IMPLICIT is a string indicating the context of
- the implicit conversion. */
+ The IMPLICIT is ICV_CAST when the user is explicitly converting an expression
+ to void via a cast. If an expression is being implicitly converted, IMPLICIT
+ indicates the context of the implicit conversion. */
tree
-convert_to_void (tree expr, const char *implicit, tsubst_flags_t complain)
+convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
{
+ location_t loc = EXPR_LOC_OR_HERE (expr);
+
if (expr == error_mark_node
|| TREE_TYPE (expr) == error_mark_node)
return error_mark_node;
+
+ if (implicit == ICV_CAST)
+ mark_exp_read (expr);
+ else
+ {
+ tree exprv = expr;
+
+ while (TREE_CODE (exprv) == COMPOUND_EXPR)
+ exprv = TREE_OPERAND (exprv, 1);
+ if (DECL_P (exprv)
+ || handled_component_p (exprv)
+ || INDIRECT_REF_P (exprv))
+ /* Expr is not being 'used' here, otherwise we whould have
+ called mark_{rl}value_use use here, which would have in turn
+ called mark_exp_read. Rather, we call mark_exp_read directly
+ to avoid some warnings when
+ -Wunused-but-set-{variable,parameter} is in effect. */
+ mark_exp_read (exprv);
+ }
+
if (!TREE_TYPE (expr))
return expr;
if (invalid_nonstatic_memfn_p (expr, complain))
if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR)
{
if (complain & tf_error)
- error ("pseudo-destructor is not called");
+ error_at (loc, "pseudo-destructor is not called");
return error_mark_node;
}
if (VOID_TYPE_P (TREE_TYPE (expr)))
/* The two parts of a cond expr might be separate lvalues. */
tree op1 = TREE_OPERAND (expr,1);
tree op2 = TREE_OPERAND (expr,2);
- bool side_effects = TREE_SIDE_EFFECTS (op1) || TREE_SIDE_EFFECTS (op2);
- tree new_op1 = convert_to_void
- (op1, (implicit && !side_effects
- ? "second operand of conditional" : NULL), complain);
- tree new_op2 = convert_to_void
- (op2, (implicit && !side_effects
- ? "third operand of conditional" : NULL), complain);
-
- expr = build3 (COND_EXPR, TREE_TYPE (new_op1),
+ bool side_effects = ((op1 && TREE_SIDE_EFFECTS (op1))
+ || TREE_SIDE_EFFECTS (op2));
+ tree new_op1, new_op2;
+ new_op1 = NULL_TREE;
+ if (implicit != ICV_CAST && !side_effects)
+ {
+ if (op1)
+ new_op1 = convert_to_void (op1, ICV_SECOND_OF_COND, complain);
+ new_op2 = convert_to_void (op2, ICV_THIRD_OF_COND, complain);
+ }
+ else
+ {
+ if (op1)
+ new_op1 = convert_to_void (op1, ICV_CAST, complain);
+ new_op2 = convert_to_void (op2, ICV_CAST, complain);
+ }
+
+ expr = build3 (COND_EXPR, TREE_TYPE (new_op2),
TREE_OPERAND (expr, 0), new_op1, new_op2);
break;
}
{
/* The second part of a compound expr contains the value. */
tree op1 = TREE_OPERAND (expr,1);
- tree new_op1 = convert_to_void
- (op1, (implicit && !TREE_NO_WARNING (expr)
- ? "right-hand operand of comma" : NULL), complain);
+ tree new_op1;
+ if (implicit != ICV_CAST && !TREE_NO_WARNING (expr))
+ new_op1 = convert_to_void (op1, ICV_RIGHT_OF_COMMA, complain);
+ else
+ new_op1 = convert_to_void (op1, ICV_CAST, complain);
if (new_op1 != op1)
{
if (is_volatile && !is_complete)
{
if (complain & tf_warning)
- warning (0, "object of incomplete type %qT will not be accessed in %s",
- type, implicit ? implicit : "void context");
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0, "conversion to void will not access "
+ "object of incomplete type %qT", type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in second operand "
+ "of conditional expression", type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in third operand "
+ "of conditional expression", type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in right operand of "
+ "comma operator", type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in left operand of "
+ "comma operator", type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in statement", type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0, "indirection will not access object of "
+ "incomplete type %qT in for increment "
+ "expression", type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
}
/* Don't load the value if this is an implicit dereference, or if
the type needs to be handled by ctors/dtors. */
- else if (is_volatile && (is_reference || TREE_ADDRESSABLE (type)))
+ else if (is_volatile && is_reference)
{
if (complain & tf_warning)
- warning (0, "object of type %qT will not be accessed in %s",
- TREE_TYPE (TREE_OPERAND (expr, 0)),
- implicit ? implicit : "void context");
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0, "conversion to void will not access "
+ "object of type %qT", type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in second operand of "
+ "conditional expression", type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in third operand of "
+ "conditional expression", type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in right operand of "
+ "comma operator", type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in left operand of comma "
+ "operator", type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in statement", type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0, "implicit dereference will not access "
+ "object of type %qT in for increment expression",
+ type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
}
+ else if (is_volatile && TREE_ADDRESSABLE (type))
+ {
+ if (complain & tf_warning)
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0, "conversion to void will not access "
+ "object of non-trivially-copyable type %qT",
+ type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0, "indirection will not access object of "
+ "non-trivially-copyable type %qT in second "
+ "operand of conditional expression", type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0, "indirection will not access object of "
+ "non-trivially-copyable type %qT in third "
+ "operand of conditional expression", type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0, "indirection will not access object of "
+ "non-trivially-copyable type %qT in right "
+ "operand of comma operator", type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0, "indirection will not access object of "
+ "non-trivially-copyable type %qT in left "
+ "operand of comma operator", type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0, "indirection will not access object of "
+ "non-trivially-copyable type %qT in statement",
+ type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0, "indirection will not access object of "
+ "non-trivially-copyable type %qT in for "
+ "increment expression", type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE (type))
{
/* Emit a warning (if enabled) when the "effect-less" INDIRECT_REF
- an expression with TREE_NO_WARNING set. (For an example of
such expressions, see build_over_call in call.c.)
- automatic dereferencing of references, since the user cannot
- control it. (See also warn_if_unused_value() in stmt.c.) */
+ control it. (See also warn_if_unused_value() in c-common.c.) */
if (warn_unused_value
- && implicit
+ && implicit != ICV_CAST
&& (complain & tf_warning)
&& !TREE_NO_WARNING (expr)
&& !is_reference)
- warning (OPT_Wunused_value, "value computed is not used");
+ warning_at (loc, OPT_Wunused_value, "value computed is not used");
expr = TREE_OPERAND (expr, 0);
}
int is_complete = COMPLETE_TYPE_P (complete_type (type));
if (TYPE_VOLATILE (type) && !is_complete && (complain & tf_warning))
- warning (0, "object %qE of incomplete type %qT will not be accessed in %s",
- expr, type, implicit ? implicit : "void context");
+ switch (implicit)
+ {
+ case ICV_CAST:
+ warning_at (loc, 0, "conversion to void will not access "
+ "object %qE of incomplete type %qT", expr, type);
+ break;
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, 0, "variable %qE of incomplete type %qT will "
+ "not be accessed in second operand of "
+ "conditional expression", expr, type);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, 0, "variable %qE of incomplete type %qT will "
+ "not be accessed in third operand of "
+ "conditional expression", expr, type);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, 0, "variable %qE of incomplete type %qT will "
+ "not be accessed in right operand of comma operator",
+ expr, type);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, 0, "variable %qE of incomplete type %qT will "
+ "not be accessed in left operand of comma operator",
+ expr, type);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, 0, "variable %qE of incomplete type %qT will "
+ "not be accessed in statement", expr, type);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, 0, "variable %qE of incomplete type %qT will "
+ "not be accessed in for increment expression",
+ expr, type);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
break;
}
/* [over.over] enumerates the places where we can take the address
of an overloaded function, and this is not one of them. */
if (complain & tf_error)
- error ("%s cannot resolve address of overloaded function",
- implicit ? implicit : "void cast");
+ switch (implicit)
+ {
+ case ICV_CAST:
+ error_at (loc, "conversion to void "
+ "cannot resolve address of overloaded function");
+ break;
+ case ICV_SECOND_OF_COND:
+ error_at (loc, "second operand of conditional expression "
+ "cannot resolve address of overloaded function");
+ break;
+ case ICV_THIRD_OF_COND:
+ error_at (loc, "third operand of conditional expression "
+ "cannot resolve address of overloaded function");
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ error_at (loc, "right operand of comma operator "
+ "cannot resolve address of overloaded function");
+ break;
+ case ICV_LEFT_OF_COMMA:
+ error_at (loc, "left operand of comma operator "
+ "cannot resolve address of overloaded function");
+ break;
+ case ICV_STATEMENT:
+ error_at (loc, "statement "
+ "cannot resolve address of overloaded function");
+ break;
+ case ICV_THIRD_IN_FOR:
+ error_at (loc, "for increment expression "
+ "cannot resolve address of overloaded function");
+ break;
+ }
else
return error_mark_node;
expr = void_zero_node;
}
- else if (implicit && probe == expr && is_overloaded_fn (probe))
+ else if (implicit != ICV_CAST && probe == expr && is_overloaded_fn (probe))
{
/* Only warn when there is no &. */
if (complain & tf_warning)
- warning (OPT_Waddress, "%s is a reference, not call, to function %qE",
- implicit, expr);
+ switch (implicit)
+ {
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, OPT_Waddress,
+ "second operand of conditional expression "
+ "is a reference, not call, to function %qE", expr);
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, OPT_Waddress,
+ "third operand of conditional expression "
+ "is a reference, not call, to function %qE", expr);
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, OPT_Waddress,
+ "right operand of comma operator "
+ "is a reference, not call, to function %qE", expr);
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, OPT_Waddress,
+ "left operand of comma operator "
+ "is a reference, not call, to function %qE", expr);
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, OPT_Waddress,
+ "statement is a reference, not call, to function %qE",
+ expr);
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, OPT_Waddress,
+ "for increment expression "
+ "is a reference, not call, to function %qE", expr);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
if (TREE_CODE (expr) == COMPONENT_REF)
expr = TREE_OPERAND (expr, 0);
}
if (expr != error_mark_node && !VOID_TYPE_P (TREE_TYPE (expr)))
{
- if (implicit
+ if (implicit != ICV_CAST
&& warn_unused_value
&& !TREE_NO_WARNING (expr)
&& !processing_template_decl)
been explicitly cast to void, so we must do so here. */
if (!TREE_SIDE_EFFECTS (expr)) {
if (complain & tf_warning)
- warning (OPT_Wunused_value, "%s has no effect", implicit);
+ switch (implicit)
+ {
+ case ICV_SECOND_OF_COND:
+ warning_at (loc, OPT_Wunused_value,
+ "second operand of conditional expression "
+ "has no effect");
+ break;
+ case ICV_THIRD_OF_COND:
+ warning_at (loc, OPT_Wunused_value,
+ "third operand of conditional expression "
+ "has no effect");
+ break;
+ case ICV_RIGHT_OF_COMMA:
+ warning_at (loc, OPT_Wunused_value,
+ "right operand of comma operator has no effect");
+ break;
+ case ICV_LEFT_OF_COMMA:
+ warning_at (loc, OPT_Wunused_value,
+ "left operand of comma operator has no effect");
+ break;
+ case ICV_STATEMENT:
+ warning_at (loc, OPT_Wunused_value,
+ "statement has no effect");
+ break;
+ case ICV_THIRD_IN_FOR:
+ warning_at (loc, OPT_Wunused_value,
+ "for increment expression has no effect");
+ break;
+ default:
+ gcc_unreachable ();
+ }
}
else
{
|| code == POSTDECREMENT_EXPR
|| code == POSTINCREMENT_EXPR)))
&& (complain & tf_warning))
- warning (OPT_Wunused_value, "value computed is not used");
+ warning_at (loc, OPT_Wunused_value, "value computed is not used");
}
}
expr = build1 (CONVERT_EXPR, void_type_node, expr);
return fold_if_not_in_template (build_nop (type, expr));
return ocp_convert (type, expr, CONV_OLD_CONVERT,
- LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
+ LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
+ tf_warning_or_error);
}
/* Like cp_convert, except permit conversions to take place which
(such as conversion from sub-type to private super-type). */
tree
-convert_force (tree type, tree expr, int convtype)
+convert_force (tree type, tree expr, int convtype, tsubst_flags_t complain)
{
tree e = expr;
enum tree_code code = TREE_CODE (type);
if (code == REFERENCE_TYPE)
return (fold_if_not_in_template
- (convert_to_reference (type, e, CONV_C_CAST, LOOKUP_COMPLAIN,
- NULL_TREE)));
+ (convert_to_reference (type, e, CONV_C_CAST, 0,
+ NULL_TREE, complain)));
if (code == POINTER_TYPE)
- return fold_if_not_in_template (convert_to_pointer_force (type, e));
+ return fold_if_not_in_template (convert_to_pointer_force (type, e,
+ complain));
/* From typeck.c convert_for_assignment */
- if (((TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE && TREE_CODE (e) == ADDR_EXPR
- && TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE
+ if (((TYPE_PTR_P (TREE_TYPE (e)) && TREE_CODE (e) == ADDR_EXPR
&& TREE_CODE (TREE_TYPE (TREE_TYPE (e))) == METHOD_TYPE)
|| integer_zerop (e)
|| TYPE_PTRMEMFUNC_P (TREE_TYPE (e)))
&& TYPE_PTRMEMFUNC_P (type))
/* compatible pointer to member functions. */
return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1,
- /*c_cast_p=*/1);
+ /*c_cast_p=*/1, complain);
- return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
+ return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL, complain);
}
/* Convert an aggregate EXPR to type XTYPE. If a conversion
{
/* C++: check to see if we can convert this aggregate type
into the required type. */
- return build_user_type_conversion (xtype, expr, LOOKUP_NORMAL);
+ return build_user_type_conversion (xtype, expr, LOOKUP_NORMAL,
+ tf_warning_or_error);
}
/* Convert the given EXPR to one of a group of types suitable for use in an
if (expr == null_node
&& (desires & WANT_INT)
&& !(desires & WANT_NULL))
- warning_at (input_location, OPT_Wconversion_null,
- "converting NULL to non-pointer type");
+ {
+ source_location loc =
+ expansion_point_location_if_in_system_header (input_location);
- basetype = TREE_TYPE (expr);
+ warning_at (loc, OPT_Wconversion_null,
+ "converting NULL to non-pointer type");
+ }
if (basetype == error_mark_node)
return error_mark_node;
case FUNCTION_TYPE:
case ARRAY_TYPE:
- return (desires & WANT_POINTER) ? decay_conversion (expr)
+ return (desires & WANT_POINTER) ? decay_conversion (expr,
+ tf_warning_or_error)
: NULL_TREE;
case COMPLEX_TYPE:
/* The code for conversions from class type is currently only used for
delete expressions. Other expressions are handled by build_new_op. */
- if (!complete_type_or_else (basetype, expr))
+ if (!complete_type_or_maybe_complain (basetype, expr, complain))
return error_mark_node;
if (!TYPE_HAS_CONVERSION (basetype))
return NULL_TREE;
- for (conv = lookup_conversions (basetype, /*lookup_template_convs_p=*/true);
- conv;
- conv = TREE_CHAIN (conv))
+ for (conv = lookup_conversions (basetype); conv; conv = TREE_CHAIN (conv))
{
int win = 0;
tree candidate;
break;
default:
+ /* A wildcard could be instantiated to match any desired
+ type, but we can't deduce the template argument. */
+ if (WILDCARD_TYPE_P (candidate))
+ win = true;
break;
}
if (win)
{
- if (winner)
+ if (TREE_CODE (cand) == TEMPLATE_DECL)
{
if (complain)
+ error ("default type conversion can't deduce template"
+ " argument for %qD", cand);
+ return error_mark_node;
+ }
+
+ if (winner)
+ {
+ tree winner_type
+ = non_reference (TREE_TYPE (TREE_TYPE (winner)));
+
+ if (!same_type_ignoring_top_level_qualifiers_p (winner_type,
+ candidate))
{
- error ("ambiguous default type conversion from %qT",
- basetype);
- error (" candidate conversions include %qD and %qD",
- winner, cand);
+ if (complain)
+ {
+ error ("ambiguous default type conversion from %qT",
+ basetype);
+ error (" candidate conversions include %qD and %qD",
+ winner, cand);
+ }
+ return error_mark_node;
}
- return error_mark_node;
}
- else
- winner = cand;
+
+ winner = cand;
}
}
if (winner)
{
tree type = non_reference (TREE_TYPE (TREE_TYPE (winner)));
- return build_user_type_conversion (type, expr, LOOKUP_NORMAL);
+ return build_user_type_conversion (type, expr, LOOKUP_NORMAL,
+ tf_warning_or_error);
}
return NULL_TREE;
if (TREE_CODE (type) == BOOLEAN_TYPE)
type = integer_type_node;
+ /* Scoped enums don't promote, but pretend they do for backward ABI bug
+ compatibility wrt varargs. */
+ else if (SCOPED_ENUM_P (type) && abi_version_at_least (6))
+ ;
+
/* Normally convert enums to int, but convert wide enums to something
wider. */
else if (TREE_CODE (type) == ENUMERAL_TYPE
int precision = MAX (TYPE_PRECISION (type),
TYPE_PRECISION (integer_type_node));
tree totype = c_common_type_for_size (precision, 0);
+ if (SCOPED_ENUM_P (type))
+ warning (OPT_Wabi, "scoped enum %qT will not promote to an integral "
+ "type in a future version of GCC", type);
if (TREE_CODE (type) == ENUMERAL_TYPE)
type = ENUM_UNDERLYING_TYPE (type);
if (TYPE_UNSIGNED (type)
else if (TYPE_PTR_P (type) && TYPE_PTR_P (expr_type)
&& comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (expr_type)))
return build_nop (type, expr);
- else if (TYPE_PTR_TO_MEMBER_P (type)
- && TYPE_PTR_TO_MEMBER_P (expr_type)
+ else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (expr_type)
&& same_type_p (TYPE_PTRMEM_CLASS_TYPE (type),
TYPE_PTRMEM_CLASS_TYPE (expr_type))
&& comp_ptr_ttypes (TYPE_PTRMEM_POINTED_TO_TYPE (type),