}
}
conv = build_conv (ck_rvalue, from, conv);
- if (flags & LOOKUP_PREFER_RVALUE)
- /* Tell convert_like to set LOOKUP_PREFER_RVALUE. */
- conv->rvaluedness_matches_p = true;
/* If we're performing copy-initialization, remember to skip
explicit constructors. */
if (flags & LOOKUP_ONLYCONVERTING)
type. A temporary object is created to hold the result of
the conversion unless we're binding directly to a reference. */
conv->need_temporary_p = !(flags & LOOKUP_NO_TEMP_BIND);
- if (flags & LOOKUP_PREFER_RVALUE)
- /* Tell convert_like to set LOOKUP_PREFER_RVALUE. */
- conv->rvaluedness_matches_p = true;
/* If we're performing copy-initialization, remember to skip
explicit constructors. */
if (flags & LOOKUP_ONLYCONVERTING)
/* Unless it's really a C++20 lvalue being treated as an xvalue.
But in C++23, such an expression is just an xvalue, not a special
lvalue, so the binding is once again ill-formed. */
- && !(cxx_dialect == cxx20
+ && !(cxx_dialect <= cxx20
&& (gl_kind & clk_implicit_rval))
&& (!CP_TYPE_CONST_NON_VOLATILE_P (to)
|| (flags & LOOKUP_NO_RVAL_BIND))
/* Other flags only apply to the primary function in overload
resolution, or after we've chosen one. */
flags &= (LOOKUP_ONLYCONVERTING|LOOKUP_NO_CONVERSION|LOOKUP_COPY_PARM
- |LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_PREFER_RVALUE
- |LOOKUP_NO_NARROWING|LOOKUP_PROTECT|LOOKUP_NO_NON_INTEGRAL
- |LOOKUP_SHORTCUT_BAD_CONVS);
+ |LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_NO_NARROWING
+ |LOOKUP_PROTECT|LOOKUP_NO_NON_INTEGRAL|LOOKUP_SHORTCUT_BAD_CONVS);
/* FIXME: actually we don't want warnings either, but we can't just
have 'complain &= ~(tf_warning|tf_error)' because it would cause
if (cand->viable == -1)
conv->bad_p = true;
- /* We're performing the maybe-rvalue overload resolution and
- a conversion function is in play. Reject converting the return
- value of the conversion function to a base class. */
- if ((flags & LOOKUP_PREFER_RVALUE) && !DECL_CONSTRUCTOR_P (cand->fn))
- for (conversion *t = cand->second_conv; t; t = next_conversion (t))
- if (t->kind == ck_base)
- return NULL;
-
/* Remember that this was a list-initialization. */
if (flags & LOOKUP_NO_NARROWING)
conv->check_narrowing = true;
explicit constructors. */
if (convs->copy_init_p)
flags |= LOOKUP_ONLYCONVERTING;
- if (convs->rvaluedness_matches_p)
- /* standard_conversion got LOOKUP_PREFER_RVALUE. */
- flags |= LOOKUP_PREFER_RVALUE;
expr = build_temp (expr, totype, flags, &diag_kind, complain);
if (diag_kind && complain)
{
++arg_index;
parm = TREE_CHAIN (parm);
}
-
- if (cxx_dialect < cxx20
- && (cand->flags & LOOKUP_PREFER_RVALUE))
- {
- /* The implicit move specified in 15.8.3/3 fails "...if the type of
- the first parameter of the selected constructor is not an rvalue
- reference to the object's type (possibly cv-qualified)...." */
- gcc_assert (!(complain & tf_error));
- tree ptype = convs[0]->type;
- /* Allow calling a by-value converting constructor even though it
- isn't permitted by the above, because we've allowed it since GCC 5
- (PR58051) and it's allowed in C++20. But don't call a copy
- constructor. */
- if ((TYPE_REF_P (ptype) && !TYPE_REF_IS_RVALUE (ptype))
- || CONVERSION_RANK (convs[0]) > cr_exact)
- return error_mark_node;
- }
}
/* Bypass access control for 'this' parameter. */
else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
#define LOOKUP_DESTRUCTOR (1 << 5)
/* Do not permit references to bind to temporaries. */
#define LOOKUP_NO_TEMP_BIND (1 << 6)
-/* We're trying to treat an lvalue as an rvalue. */
-/* FIXME remove when we extend the P1825 semantics to all standard modes, the
- C++20 approach uses IMPLICIT_RVALUE_P instead. */
-#define LOOKUP_PREFER_RVALUE (LOOKUP_NO_TEMP_BIND << 1)
/* We're inside an init-list, so narrowing conversions are ill-formed. */
-#define LOOKUP_NO_NARROWING (LOOKUP_PREFER_RVALUE << 1)
+#define LOOKUP_NO_NARROWING (LOOKUP_NO_TEMP_BIND << 1)
/* We're looking up a constructor for list-initialization. */
#define LOOKUP_LIST_INIT_CTOR (LOOKUP_NO_NARROWING << 1)
/* This is the first parameter of a copy constructor. */
treated as an rvalue for the purposes of overload resolution
to favor move constructors over copy constructors. */
if (tree moved = treat_lvalue_as_rvalue_p (exp, /*return*/false))
- {
- if (cxx_dialect < cxx20)
- {
- releasing_vec exp_vec (make_tree_vector_single (moved));
- moved = (build_special_member_call
- (object, complete_ctor_identifier, &exp_vec,
- TREE_TYPE (object), flags|LOOKUP_PREFER_RVALUE,
- tf_none));
- if (moved != error_mark_node)
- {
- exp = moved;
- converted = true;
- }
- }
- else
- /* In C++20 we just treat the return value as an rvalue that
- can bind to lvalue refs. */
- exp = moved;
- }
+ /* In C++20 we treat the return value as an rvalue that
+ can bind to lvalue refs. In C++23, such an expression is just
+ an xvalue. */
+ exp = moved;
/* Call the copy constructor. */
if (!converted)
tree t = convert_for_initialization (NULL_TREE, type,
moved,
(LOOKUP_NORMAL
- | LOOKUP_ONLYCONVERTING
- | LOOKUP_PREFER_RVALUE),
+ | LOOKUP_ONLYCONVERTING),
ICR_RETURN, NULL_TREE, 0,
tf_none);
/* If this worked, implicit rvalue would work, so the call to
std::move is redundant. */
- if (t != error_mark_node
- /* Trying to move something const will never succeed unless
- there's T(const T&&), which it almost never is, and if
- so, T wouldn't be error_mark_node now: the above convert_
- call with LOOKUP_PREFER_RVALUE returns an error if a const T&
- overload is selected. */
- || (CP_TYPE_CONST_P (TREE_TYPE (arg))
- && same_type_ignoring_top_level_qualifiers_p
- (TREE_TYPE (arg), type)))
+ if (t != error_mark_node)
{
auto_diagnostic_group d;
if (warning_at (loc, OPT_Wredundant_move,
? CLASS_TYPE_P (functype)
: !SCALAR_TYPE_P (functype) || !SCALAR_TYPE_P (TREE_TYPE (retval)))
&& (moved = treat_lvalue_as_rvalue_p (retval, /*return*/true)))
- {
- if (cxx_dialect < cxx20)
- {
- moved = convert_for_initialization
- (NULL_TREE, functype, moved, flags|LOOKUP_PREFER_RVALUE,
- ICR_RETURN, NULL_TREE, 0, tf_none);
- if (moved != error_mark_node)
- {
- retval = moved;
- converted = true;
- }
- }
- else
- /* In C++20 we just treat the return value as an rvalue that
- can bind to lvalue refs. */
- retval = moved;
- }
+ /* In C++20 and earlier we treat the return value as an rvalue
+ that can bind to lvalue refs. In C++23, such an expression is just
+ an xvalue (see reference_binding). */
+ retval = moved;
/* The call in a (lambda) thunk needs no conversions. */
if (TREE_CODE (retval) == CALL_EXPR
S1 f3(const S2 s)
{
- return std::move(s); // { dg-warning "redundant move" "" { target c++20 } }
+ return std::move(s); // { dg-warning "redundant move" }
}
S1
f (S2 s)
{
- return std::move(s); // { dg-warning "redundant move in return statement" "" { target c++20 } }
+ return std::move(s); // { dg-warning "redundant move in return statement" }
}
struct R1 {
R1
f2 (const R2 s)
{
- return std::move(s); // { dg-warning "redundant move in return statement" "" { target c++20 } }
+ return std::move(s); // { dg-warning "redundant move in return statement" }
}
struct T1 {
{
// Without std::move: const T1 &
// With std::move: const T1 &&
- return std::move(s); // { dg-warning "redundant move in return statement" "" { target c++20 } }
+ return std::move(s); // { dg-warning "redundant move in return statement" }
}
S1
f (S2 s)
{
- return s; // { dg-error "use of deleted function" "" { target c++17_down } }
+ return s;
}
A<int> foo()
{
A<double> v;
- return v; // { dg-error "cannot bind rvalue reference" "" { target c++17_down } }
+ return v;
}
--- /dev/null
+// { dg-do compile { target c++11 } }
+// This used to compile in C++11...17 because we performed two
+// separate overload resolutions: one treating the operand as
+// an rvalue, and then (if that resolution fails) another one
+// treating the operand as an lvalue.
+
+struct W {
+ W();
+};
+
+struct F {
+ F(W&);
+ F(W&&) = delete;
+};
+
+F fn ()
+{
+ W w;
+ return w; // { dg-error "use of deleted function" }
+}
int
main ()
{
- int return_lval = __cplusplus > 201703L ? -1 : 2;
+ int return_lval = -1;
Y y1 = f (A());
if (y1.y != return_lval)
__builtin_abort ();