/* 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, 2010
- Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
#include "cp-tree.h"
#include "intl.h"
#include "convert.h"
-#include "toplev.h"
#include "decl.h"
#include "target.h"
intype = complete_type (intype);
if (!COMPLETE_TYPE_P (intype))
{
- error ("can't convert from incomplete type %qT to %qT",
+ error ("can%'t convert from incomplete type %qT to %qT",
intype, type);
return 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,
+ tf_warning_or_error);
/* Add any qualifier conversions. */
return build_nop (type, expr);
}
else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_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, tf_warning_or_error);
else if (TYPE_PTRMEMFUNC_P (intype))
{
if (!warn_pmf2ptr)
if (null_ptr_cst_p (expr))
{
+ tree val;
+
+ if (c_inhibit_evaluation_warnings == 0
+ && !NULLPTR_TYPE_P (TREE_TYPE (expr)))
+ warning (OPT_Wzero_as_null_pointer_constant,
+ "zero as null pointer constant");
+
if (TYPE_PTRMEMFUNC_P (type))
return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
- /*c_cast_p=*/false);
+ /*c_cast_p=*/false, tf_warning_or_error);
- 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);
+ /* A NULL pointer-to-data-member is represented by -1, not by
+ zero. */
+ val = (TYPE_PTRMEM_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))
{
return error_mark_node;
if (binfo)
{
- expr = build_base_path (code, expr, binfo, 0);
+ expr = build_base_path (code, expr, binfo, 0,
+ tf_warning_or_error);
if (expr == error_mark_node)
return error_mark_node;
/* Add any qualifier conversions. */
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;
/* 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, tf_warning_or_error);
if (rval == error_mark_node)
return 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,
+ tf_warning_or_error);
}
else
rval
warning (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, tf_warning_or_error);
if (rval != error_mark_node)
rval = convert_force (build_pointer_type (TREE_TYPE (reftype)),
rval, 0);
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,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);
}
\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 = build_int_cst_wide (TREE_TYPE (expr),
+ TREE_INT_CST_LOW (expr),
+ TREE_INT_CST_HIGH (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. */
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;
if (INTEGRAL_CODE_P (code))
{
tree intype = TREE_TYPE (e);
+ tree converted;
if (TREE_CODE (type) == ENUMERAL_TYPE)
{
return error_mark_node;
}
if (code == BOOLEAN_TYPE)
- return cp_truthvalue_conversion (e);
+ {
+ /* 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 (NULLPTR_TYPE_P (type) && e && null_ptr_cst_p (e))
return nullptr_node;
release_tree_vector (ctor_vec);
}
if (ctor)
- return build_cplus_new (type, ctor);
+ return build_cplus_new (type, ctor, tf_warning_or_error);
}
if (flags & LOOKUP_COMPLAIN)
/* 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);
+ 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)
{
- new_op1 = convert_to_void (op1, ICV_SECOND_OF_COND, complain);
+ 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
{
- new_op1 = convert_to_void (op1, ICV_CAST, complain);
+ 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_op1),
+ expr = build3 (COND_EXPR, TREE_TYPE (new_op2),
TREE_OPERAND (expr, 0), new_op1, new_op2);
break;
}
&& 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, tf_warning_or_error);
return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
}
/* 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 (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)
{
if (complain)
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)