/* 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 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
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 contains the functions for converting C++ expressions
#include "decl.h"
#include "target.h"
-static tree cp_convert_to_pointer (tree, tree, bool);
+static tree cp_convert_to_pointer (tree, tree);
static tree convert_to_pointer_force (tree, tree);
static tree build_type_conversion (tree, tree);
static tree build_up_reference (tree, tree, int, tree);
else if dealing with method pointers, delegate
else convert blindly
else if converting class, pass off to build_type_conversion
- else try C-style pointer conversion. If FORCE is true then allow
- conversions via virtual bases (these are permitted by reinterpret_cast,
- but not static_cast). */
+ else try C-style pointer conversion. */
static tree
-cp_convert_to_pointer (tree type, tree expr, bool force)
+cp_convert_to_pointer (tree type, tree expr)
{
tree intype = TREE_TYPE (expr);
enum tree_code form;
if (intype == error_mark_node)
return error_mark_node;
- if (IS_AGGR_TYPE (intype))
+ if (MAYBE_CLASS_TYPE_P (intype))
{
intype = complete_type (intype);
if (!COMPLETE_TYPE_P (intype))
if (TYPE_MAIN_VARIANT (type) != intype
&& TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
- && IS_AGGR_TYPE (TREE_TYPE (type))
- && IS_AGGR_TYPE (TREE_TYPE (intype))
+ && MAYBE_CLASS_TYPE_P (TREE_TYPE (type))
+ && MAYBE_CLASS_TYPE_P (TREE_TYPE (intype))
&& TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
{
enum tree_code code = PLUS_EXPR;
return build_nop (type, expr);
}
- else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
- {
- tree b1;
- tree b2;
- tree binfo;
- enum tree_code code = PLUS_EXPR;
- base_kind bk;
-
- b1 = TYPE_PTRMEM_CLASS_TYPE (type);
- b2 = TYPE_PTRMEM_CLASS_TYPE (intype);
- binfo = lookup_base (b1, b2, ba_check, &bk);
- if (!binfo)
- {
- binfo = lookup_base (b2, b1, ba_check, &bk);
- code = MINUS_EXPR;
- }
- if (binfo == error_mark_node)
- return error_mark_node;
-
- if (bk == bk_via_virtual)
- {
- if (force)
- warning (0, "pointer to member cast from %qT to %qT is via"
- " virtual base", intype, type);
- else
- {
- error ("pointer to member cast from %qT to %qT is"
- " via virtual base", intype, type);
- return error_mark_node;
- }
- /* This is a reinterpret cast, whose result is unspecified.
- We choose to do nothing. */
- return build1 (NOP_EXPR, type, expr);
- }
-
- if (TREE_CODE (expr) == PTRMEM_CST)
- expr = cplus_expand_constant (expr);
-
- if (binfo && !integer_zerop (BINFO_OFFSET (binfo)))
- expr = size_binop (code,
- build_nop (sizetype, expr),
- BINFO_OFFSET (binfo));
- return build_nop (type, expr);
- }
- else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
- return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
- /*c_cast_p=*/false);
+ 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);
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),
- force);
+ PTRMEM_CST_MEMBER (expr));
else if (TREE_CODE (expr) == OFFSET_REF)
{
tree object = TREE_OPERAND (expr, 0);
{
/* A NULL pointer-to-member is represented by -1, not by
zero. */
- expr = build_int_cst (type, -1);
- /* Fix up the representation of -1 if appropriate. */
- expr = force_fit_type (expr, 0, false, false);
+ expr = build_int_cst_type (type, -1);
}
else
expr = build_int_cst (type, 0);
if (TYPE_MAIN_VARIANT (type) != intype
&& TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
- && IS_AGGR_TYPE (TREE_TYPE (type))
- && IS_AGGR_TYPE (TREE_TYPE (intype))
+ && MAYBE_CLASS_TYPE_P (TREE_TYPE (type))
+ && MAYBE_CLASS_TYPE_P (TREE_TYPE (intype))
&& TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
{
enum tree_code code = PLUS_EXPR;
}
}
- return cp_convert_to_pointer (type, expr, true);
+ return cp_convert_to_pointer (type, expr);
}
/* We are passing something to a function which requires a reference.
if ((flags & LOOKUP_PROTECT)
&& TYPE_MAIN_VARIANT (argtype) != TYPE_MAIN_VARIANT (target_type)
- && IS_AGGR_TYPE (argtype)
- && IS_AGGR_TYPE (target_type))
+ && MAYBE_CLASS_TYPE_P (argtype)
+ && 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);
msg = "conversion to non-const reference type %q#T from"
" rvalue of type %qT";
- pedwarn (msg, reftype, intype);
+ permerror (msg, reftype, intype);
}
}
can_convert_intype_to_type = can_convert (type, intype);
if (!can_convert_intype_to_type
- && (convtype & CONV_IMPLICIT) && IS_AGGR_TYPE (intype)
+ && (convtype & CONV_IMPLICIT) && MAYBE_CLASS_TYPE_P (intype)
&& ! (flags & LOOKUP_NO_CONVERSION))
{
/* Look for a user-defined conversion to lvalue that we can use. */
if (! (convtype & CONV_CONST)
&& !at_least_as_qualified_p (ttl, ttr))
- pedwarn ("conversion from %qT to %qT discards qualifiers",
- ttr, reftype);
+ permerror ("conversion from %qT to %qT discards qualifiers",
+ ttr, reftype);
}
return build_up_reference (reftype, expr, flags, decl);
tree
force_rvalue (tree expr)
{
- if (IS_AGGR_TYPE (TREE_TYPE (expr)) && TREE_CODE (expr) != TARGET_EXPR)
+ 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);
else
return ocp_convert (type, expr, CONV_OLD_CONVERT, LOOKUP_NORMAL);
}
+/* C++ equivalent of convert_and_check but using cp_convert as the
+ conversion function.
+
+ Convert EXPR to TYPE, warning about conversion problems with constants.
+ Invoke this function on every expression that is converted implicitly,
+ i.e. because of language rules and not because of an explicit cast. */
+
+tree
+cp_convert_and_check (tree type, tree expr)
+{
+ tree result;
+
+ if (TREE_TYPE (expr) == type)
+ return expr;
+
+ result = cp_convert (type, expr);
+
+ if (!skip_evaluation && !TREE_OVERFLOW_P (expr) && result != error_mark_node)
+ warnings_for_convert_and_check (type, expr, result);
+
+ return result;
+}
+
/* Conversion...
FLAGS indicates how we should behave. */
e = integral_constant_value (e);
- if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP)
- /* Some internal structures (vtable_entry_type, sigtbl_ptr_type)
- don't go through finish_struct, so they don't have the synthesized
- constructors. So don't force a temporary. */
- && TYPE_HAS_CONSTRUCTOR (type))
+ if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP))
/* We need a new temporary; don't take this shortcut. */;
- else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
+ else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
{
if (same_type_p (type, TREE_TYPE (e)))
/* The call to fold will not always remove the NOP_EXPR as
else if (TREE_CODE (e) == TARGET_EXPR)
{
/* Don't build a NOP_EXPR of class type. Instead, change the
- type of the temporary. Only allow this for cv-qual changes,
- though. */
- gcc_assert (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (e)),
- TYPE_MAIN_VARIANT (type)));
+ type of the temporary. */
TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
return e;
}
|| TREE_CODE (intype) == POINTER_TYPE))
{
if (flags & LOOKUP_COMPLAIN)
- pedwarn ("conversion from %q#T to %q#T", intype, type);
+ permerror ("conversion from %q#T to %q#T", intype, type);
- if (flag_pedantic_errors)
+ if (!flag_permissive)
return error_mark_node;
}
- if (IS_AGGR_TYPE (intype))
+ if (MAYBE_CLASS_TYPE_P (intype))
{
tree rval;
rval = build_type_conversion (type, e);
return fold_if_not_in_template (convert_to_integer (type, e));
}
if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type))
- return fold_if_not_in_template (cp_convert_to_pointer (type, e, false));
+ return fold_if_not_in_template (cp_convert_to_pointer (type, e));
if (code == VECTOR_TYPE)
{
tree in_vtype = TREE_TYPE (e);
- if (IS_AGGR_TYPE (in_vtype))
+ if (MAYBE_CLASS_TYPE_P (in_vtype))
{
tree ret_val;
ret_val = build_type_conversion (type, e);
}
if (code == REAL_TYPE || code == COMPLEX_TYPE)
{
- if (IS_AGGR_TYPE (TREE_TYPE (e)))
+ if (MAYBE_CLASS_TYPE_P (TREE_TYPE (e)))
{
tree rval;
rval = build_type_conversion (type, e);
/* New C++ semantics: since assignment is now based on
memberwise copying, if the rhs type is derived from the
lhs type, then we may still do a conversion. */
- if (IS_AGGR_TYPE_CODE (code))
+ if (RECORD_OR_UNION_CODE_P (code))
{
tree dtype = TREE_TYPE (e);
tree ctor = NULL_TREE;
return error_mark_node;
if ((flags & LOOKUP_ONLYCONVERTING)
- && ! (IS_AGGR_TYPE (dtype) && DERIVED_FROM_P (type, dtype)))
+ && ! (MAYBE_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]). */
int is_volatile = TYPE_VOLATILE (type);
int is_complete = COMPLETE_TYPE_P (complete_type (type));
+ /* Can't load the value if we don't know the type. */
if (is_volatile && !is_complete)
warning (0, "object of incomplete type %qT will not be accessed in %s",
type, implicit ? implicit : "void context");
- else if (is_reference && is_volatile)
+ /* 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)))
warning (0, "object of type %qT will not be accessed in %s",
TREE_TYPE (TREE_OPERAND (expr, 0)),
implicit ? implicit : "void context");
- if (is_reference || !is_volatile || !is_complete)
+ if (is_reference || !is_volatile || !is_complete || TREE_ADDRESSABLE (type))
expr = TREE_OPERAND (expr, 0);
break;
break;
}
+ case TARGET_EXPR:
+ /* Don't bother with the temporary object returned from a function if
+ we don't use it and don't need to destroy it. We'll still
+ allocate space for it in expand_call or declare_return_variable,
+ but we don't need to track it through all the tree phases. */
+ if (TARGET_EXPR_IMPLICIT_P (expr)
+ && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (expr)))
+ {
+ tree init = TARGET_EXPR_INITIAL (expr);
+ if (TREE_CODE (init) == AGGR_INIT_EXPR
+ && !AGGR_INIT_VIA_CTOR_P (init))
+ {
+ tree fn = AGGR_INIT_EXPR_FN (init);
+ expr = build_call_array (TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+ fn,
+ aggr_init_expr_nargs (init),
+ AGGR_INIT_EXPR_ARGP (init));
+ }
+ }
+ break;
+
default:;
}
{
{
/* [over.over] enumerates the places where we can take the address
of an overloaded function, and this is not one of them. */
- pedwarn ("%s cannot resolve address of overloaded function",
- implicit ? implicit : "void cast");
+ error ("%s cannot resolve address of overloaded function",
+ implicit ? implicit : "void cast");
expr = void_zero_node;
}
else if (implicit && probe == expr && is_overloaded_fn (probe))
- /* Only warn when there is no &. */
- warning (0, "%s is a reference, not call, to function %qE",
- implicit, expr);
+ {
+ /* Only warn when there is no &. */
+ warning (OPT_Waddress, "%s is a reference, not call, to function %qE",
+ implicit, expr);
+ if (TREE_CODE (expr) == COMPONENT_REF)
+ expr = TREE_OPERAND (expr, 0);
+ }
}
if (expr != error_mark_node && !VOID_TYPE_P (TREE_TYPE (expr)))
}
expr = build1 (CONVERT_EXPR, void_type_node, expr);
}
+ if (! TREE_SIDE_EFFECTS (expr))
+ expr = void_zero_node;
return expr;
}
Most of this routine is from build_reinterpret_cast.
- The backend cannot call cp_convert (what was convert) because
+ The back end cannot call cp_convert (what was convert) because
conversions to/from basetypes may involve memory references
(vbases) and adding or subtracting small values (multiple
inheritance), but it calls convert from the constant folding code
if (basetype == error_mark_node)
return error_mark_node;
- if (! IS_AGGR_TYPE (basetype))
+ if (! MAYBE_CLASS_TYPE_P (basetype))
switch (TREE_CODE (basetype))
{
case INTEGER_TYPE:
return expr;
/* else fall through... */
- case VECTOR_TYPE:
case BOOLEAN_TYPE:
return (desires & WANT_INT) ? expr : NULL_TREE;
case ENUMERAL_TYPE:
case ARRAY_TYPE:
return (desires & WANT_POINTER) ? decay_conversion (expr)
: NULL_TREE;
+
+ case VECTOR_TYPE:
+ if ((desires & WANT_VECTOR) == 0)
+ return NULL_TREE;
+ switch (TREE_CODE (TREE_TYPE (basetype)))
+ {
+ case INTEGER_TYPE:
+ case BOOLEAN_TYPE:
+ return (desires & WANT_INT) ? expr : NULL_TREE;
+ case ENUMERAL_TYPE:
+ return (desires & WANT_ENUM) ? expr : NULL_TREE;
+ case REAL_TYPE:
+ return (desires & WANT_FLOAT) ? expr : NULL_TREE;
+ default:
+ return NULL_TREE;
+ }
+
default:
return NULL_TREE;
}
case POINTER_TYPE:
win = (desires & WANT_POINTER); break;
+ case VECTOR_TYPE:
+ if ((desires & WANT_VECTOR) == 0)
+ break;
+ switch (TREE_CODE (TREE_TYPE (candidate)))
+ {
+ case BOOLEAN_TYPE:
+ case INTEGER_TYPE:
+ win = (desires & WANT_INT); break;
+ case ENUMERAL_TYPE:
+ win = (desires & WANT_ENUM); break;
+ case REAL_TYPE:
+ win = (desires & WANT_FLOAT); break;
+ default:
+ break;
+ }
+ break;
+
default:
break;
}