summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/cp/call.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/cp/call.c')
-rw-r--r--contrib/gcc/cp/call.c110
1 files changed, 83 insertions, 27 deletions
diff --git a/contrib/gcc/cp/call.c b/contrib/gcc/cp/call.c
index 24b5d1f..576790c 100644
--- a/contrib/gcc/cp/call.c
+++ b/contrib/gcc/cp/call.c
@@ -95,6 +95,10 @@ struct conversion {
/* If KIND is ck_ptr or ck_pmem, true to indicate that a conversion
from a pointer-to-derived to pointer-to-base is being performed. */
BOOL_BITFIELD base_p : 1;
+ /* If KIND is ck_ref_bind, true when either an lvalue reference is
+ being bound to an lvalue expression or an rvalue reference is
+ being bound to an rvalue expression. */
+ BOOL_BITFIELD rvaluedness_matches_p: 1;
/* The type of the expression resulting from the conversion. */
tree type;
union {
@@ -174,7 +178,7 @@ static conversion *standard_conversion (tree, tree, tree, bool, int);
static conversion *reference_binding (tree, tree, tree, bool, int);
static conversion *build_conv (conversion_kind, tree, conversion *);
static bool is_subseq (conversion *, conversion *);
-static tree maybe_handle_ref_bind (conversion **);
+static conversion *maybe_handle_ref_bind (conversion **);
static void maybe_handle_implicit_object (conversion **);
static struct z_candidate *add_candidate
(struct z_candidate **, tree, tree, size_t,
@@ -895,12 +899,12 @@ reference_compatible_p (tree t1, tree t2)
converted to T as in [over.match.ref]. */
static conversion *
-convert_class_to_reference (tree t, tree s, tree expr)
+convert_class_to_reference (tree reference_type, tree s, tree expr)
{
tree conversions;
tree arglist;
conversion *conv;
- tree reference_type;
+ tree t;
struct z_candidate *candidates;
struct z_candidate *cand;
bool any_viable_p;
@@ -934,7 +938,7 @@ convert_class_to_reference (tree t, tree s, tree expr)
arglist = build_int_cst (build_pointer_type (s), 0);
arglist = build_tree_list (NULL_TREE, arglist);
- reference_type = build_reference_type (t);
+ t = TREE_TYPE (reference_type);
while (conversions)
{
@@ -997,6 +1001,9 @@ convert_class_to_reference (tree t, tree s, tree expr)
cand->second_conv
= (direct_reference_binding
(reference_type, identity_conv));
+ cand->second_conv->rvaluedness_matches_p
+ = TYPE_REF_IS_RVALUE (TREE_TYPE (TREE_TYPE (cand->fn)))
+ == TYPE_REF_IS_RVALUE (reference_type);
cand->second_conv->bad_p |= cand->convs[0]->bad_p;
}
}
@@ -1123,7 +1130,16 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
to = build_qualified_type (to, cp_type_quals (from));
compatible_p = reference_compatible_p (to, from);
- if (lvalue_p && compatible_p)
+ /* Directly bind reference when target expression's type is compatible with
+ the reference and expression is an lvalue. In C++0x, the wording in
+ [8.5.3/5 dcl.init.ref] is changed to also allow direct bindings for const
+ and rvalue references to rvalues of compatible class type, as part of
+ DR391. */
+ if (compatible_p
+ && (lvalue_p
+ || (flag_cpp0x
+ && (CP_TYPE_CONST_NON_VOLATILE_P(to) || TYPE_REF_IS_RVALUE (rto))
+ && CLASS_TYPE_P (from))))
{
/* [dcl.init.ref]
@@ -1136,6 +1152,15 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
lvalue. */
conv = build_identity_conv (from, expr);
conv = direct_reference_binding (rto, conv);
+
+ if (flags & LOOKUP_PREFER_RVALUE)
+ /* The top-level caller requested that we pretend that the lvalue
+ be treated as an rvalue. */
+ conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
+ else
+ conv->rvaluedness_matches_p
+ = (TYPE_REF_IS_RVALUE (rto) == !lvalue_p);
+
if ((lvalue_p & clk_bitfield) != 0
|| ((lvalue_p & clk_packed) != 0 && !TYPE_PACKED (to)))
/* For the purposes of overload resolution, we ignore the fact
@@ -1168,7 +1193,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
the reference is bound to the lvalue result of the conversion
in the second case. */
- conv = convert_class_to_reference (to, from, expr);
+ conv = convert_class_to_reference (rto, from, expr);
if (conv)
return conv;
}
@@ -1191,8 +1216,10 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
/* [dcl.init.ref]
- Otherwise, the reference shall be to a non-volatile const type. */
- if (!CP_TYPE_CONST_NON_VOLATILE_P (to))
+ Otherwise, the reference shall be to a non-volatile const type.
+
+ Under C++0x, [8.5.3/5 dcl.init.ref] it may also be an rvalue reference */
+ if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
return NULL;
/* [dcl.init.ref]
@@ -1215,6 +1242,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
{
conv = build_identity_conv (from, expr);
conv = direct_reference_binding (rto, conv);
+ conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
if (!(flags & LOOKUP_CONSTRUCTOR_CALLABLE))
conv->u.next->check_copy_constructor_p = true;
return conv;
@@ -1239,6 +1267,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
/* This reference binding, unlike those above, requires the
creation of a temporary. */
conv->need_temporary_p = true;
+ conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
return conv;
}
@@ -1280,7 +1309,7 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
conv = cand->second_conv;
/* We used to try to bind a reference to a temporary here, but that
- is now handled by the recursive call to this function at the end
+ is now handled after the recursive call to this function at the end
of reference_binding. */
return conv;
}
@@ -4409,13 +4438,22 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
{
tree ref_type = totype;
- /* If necessary, create a temporary. */
- if (convs->need_temporary_p || !lvalue_p (expr))
+ /* If necessary, create a temporary.
+
+ VA_ARG_EXPR and CONSTRUCTOR expressions are special cases
+ that need temporaries, even when their types are reference
+ compatible with the type of reference being bound, so the
+ upcoming call to build_unary_op (ADDR_EXPR, expr, ...)
+ doesn't fail. */
+ if (convs->need_temporary_p
+ || TREE_CODE (expr) == CONSTRUCTOR
+ || TREE_CODE (expr) == VA_ARG_EXPR)
{
tree type = convs->u.next->type;
cp_lvalue_kind lvalue = real_lvalue_p (expr);
- if (!CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
+ if (!CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type))
+ && !TYPE_REF_IS_RVALUE (ref_type))
{
/* If the reference is volatile or non-const, we
cannot create a temporary. */
@@ -4938,7 +4976,9 @@ build_over_call (struct z_candidate *cand, int flags)
if (! flag_elide_constructors)
/* Do things the hard way. */;
- else if (cand->num_convs == 1 && DECL_COPY_CONSTRUCTOR_P (fn))
+ else if (cand->num_convs == 1
+ && (DECL_COPY_CONSTRUCTOR_P (fn)
+ || DECL_MOVE_CONSTRUCTOR_P (fn)))
{
tree targ;
arg = skip_artificial_parms_for (fn, converted_args);
@@ -5676,28 +5716,28 @@ maybe_handle_implicit_object (conversion **ics)
t = t->u.next;
t = build_identity_conv (TREE_TYPE (t->type), NULL_TREE);
t = direct_reference_binding (reference_type, t);
+ t->rvaluedness_matches_p = 1;
*ics = t;
}
}
/* If *ICS is a REF_BIND set *ICS to the remainder of the conversion,
- and return the type to which the reference refers. Otherwise,
- leave *ICS unchanged and return NULL_TREE. */
+ and return the initial reference binding conversion. Otherwise,
+ leave *ICS unchanged and return NULL. */
-static tree
+static conversion *
maybe_handle_ref_bind (conversion **ics)
{
if ((*ics)->kind == ck_ref_bind)
{
conversion *old_ics = *ics;
- tree type = TREE_TYPE (old_ics->type);
*ics = old_ics->u.next;
(*ics)->user_conv_p = old_ics->user_conv_p;
(*ics)->bad_p = old_ics->bad_p;
- return type;
+ return old_ics;
}
- return NULL_TREE;
+ return NULL;
}
/* Compare two implicit conversion sequences according to the rules set out in
@@ -5721,18 +5761,18 @@ compare_ics (conversion *ics1, conversion *ics2)
conversion_rank rank1, rank2;
/* REF_BINDING is nonzero if the result of the conversion sequence
- is a reference type. In that case TARGET_TYPE is the
- type referred to by the reference. */
- tree target_type1;
- tree target_type2;
+ is a reference type. In that case REF_CONV is the reference
+ binding conversion. */
+ conversion *ref_conv1;
+ conversion *ref_conv2;
/* Handle implicit object parameters. */
maybe_handle_implicit_object (&ics1);
maybe_handle_implicit_object (&ics2);
/* Handle reference parameters. */
- target_type1 = maybe_handle_ref_bind (&ics1);
- target_type2 = maybe_handle_ref_bind (&ics2);
+ ref_conv1 = maybe_handle_ref_bind (&ics1);
+ ref_conv2 = maybe_handle_ref_bind (&ics2);
/* [over.ics.rank]
@@ -6023,15 +6063,31 @@ compare_ics (conversion *ics1, conversion *ics2)
/* [over.ics.rank]
+ --S1 and S2 are reference bindings (_dcl.init.ref_) and neither refers
+ to an implicit object parameter, and either S1 binds an lvalue reference
+ to an lvalue and S2 binds an rvalue reference or S1 binds an rvalue
+ reference to an rvalue and S2 binds an lvalue reference
+ (C++0x draft standard, 13.3.3.2)
+
--S1 and S2 are reference bindings (_dcl.init.ref_), and the
types to which the references refer are the same type except for
top-level cv-qualifiers, and the type to which the reference
initialized by S2 refers is more cv-qualified than the type to
which the reference initialized by S1 refers */
- if (target_type1 && target_type2
+ if (ref_conv1 && ref_conv2
&& same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
- return comp_cv_qualification (target_type2, target_type1);
+ {
+ if (ref_conv1->rvaluedness_matches_p
+ && !ref_conv2->rvaluedness_matches_p)
+ return 1;
+ else if (!ref_conv1->rvaluedness_matches_p
+ && ref_conv2->rvaluedness_matches_p)
+ return -1;
+
+ return comp_cv_qualification (TREE_TYPE (ref_conv2->type),
+ TREE_TYPE (ref_conv1->type));
+ }
/* Neither conversion sequence is better than the other. */
return 0;
OpenPOWER on IntegriCloud