From a347241b939399be041672fa6dfbc6c8c1853e28 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 23 May 2018 13:21:39 -0400 Subject: [PATCH] Fix cast to rvalue reference from prvalue. * cvt.c (diagnose_ref_binding): Handle rvalue reference. * rtti.c (build_dynamic_cast_1): Don't try to build a reference to non-class type. Handle xvalue argument. * typeck.c (build_reinterpret_cast_1): Allow cast from prvalue to rvalue reference. * semantics.c (finish_compound_literal): Do direct-initialization, not cast, to initialize a reference. From-SVN: r260622 --- gcc/cp/ChangeLog | 9 +++++++++ gcc/cp/cvt.c | 3 ++- gcc/cp/rtti.c | 10 +++++----- gcc/cp/semantics.c | 5 ++++- gcc/cp/typeck.c | 10 ++++++++-- gcc/testsuite/g++.dg/cpp0x/rv-cast6.C | 11 +++++++++++ 6 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/rv-cast6.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3adb570a0cb..f38d385e3be 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,14 @@ 2018-05-23 Jason Merrill + Fix cast to rvalue reference from prvalue. + * cvt.c (diagnose_ref_binding): Handle rvalue reference. + * rtti.c (build_dynamic_cast_1): Don't try to build a reference to + non-class type. Handle xvalue argument. + * typeck.c (build_reinterpret_cast_1): Allow cast from prvalue to + rvalue reference. + * semantics.c (finish_compound_literal): Do direct-initialization, + not cast, to initialize a reference. + CWG 616, 1213 - value category of subobject references. * tree.c (lvalue_kind): A reference to a subobject of a prvalue is an xvalue. diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 30b44b7d7ea..3f87317a47d 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -381,7 +381,8 @@ diagnose_ref_binding (location_t loc, tree reftype, tree intype, tree decl) { tree ttl = TREE_TYPE (reftype); - if (!CP_TYPE_CONST_NON_VOLATILE_P (ttl)) + if (!TYPE_REF_IS_RVALUE (reftype) + && !CP_TYPE_CONST_NON_VOLATILE_P (ttl)) { const char *msg; diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 426a23276e0..6692fb7ff86 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -616,22 +616,22 @@ build_dynamic_cast_1 (tree type, tree expr, tsubst_flags_t complain) else { expr = mark_lvalue_use (expr); - - exprtype = build_reference_type (TREE_TYPE (expr)); + exprtype = TREE_TYPE (expr); /* T is a reference type, v shall be an lvalue of a complete class type, and the result is an lvalue of the type referred to by T. */ - - if (! MAYBE_CLASS_TYPE_P (TREE_TYPE (exprtype))) + if (! MAYBE_CLASS_TYPE_P (exprtype)) { errstr = _("source is not of class type"); goto fail; } - if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (exprtype)))) + if (!COMPLETE_TYPE_P (complete_type (exprtype))) { errstr = _("source is of incomplete class type"); goto fail; } + + exprtype = cp_build_reference_type (exprtype, !lvalue_p (expr)); } /* The dynamic_cast operator shall not cast away constness. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 94e8f54254d..46251deaa6c 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2734,7 +2734,10 @@ finish_compound_literal (tree type, tree compound_literal, compound_literal = finish_compound_literal (TREE_TYPE (type), compound_literal, complain, fcl_context); - return cp_build_c_cast (type, compound_literal, complain); + /* The prvalue is then used to direct-initialize the reference. */ + tree r = (perform_implicit_conversion_flags + (type, compound_literal, complain, LOOKUP_NORMAL)); + return convert_from_reference (r); } if (!TYPE_OBJ_P (type)) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 82089c45105..a694499190f 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -7315,13 +7315,19 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, type = cv_unqualified (type); /* [expr.reinterpret.cast] - An lvalue expression of type T1 can be cast to the type + A glvalue expression of type T1 can be cast to the type "reference to T2" if an expression of type "pointer to T1" can be explicitly converted to the type "pointer to T2" using a reinterpret_cast. */ if (TYPE_REF_P (type)) { - if (! lvalue_p (expr)) + if (TYPE_REF_IS_RVALUE (type)) + { + if (!obvalue_p (expr)) + /* Perform the temporary materialization conversion. */ + expr = get_target_expr_sfinae (expr, complain); + } + else if (!lvalue_p (expr)) { if (complain & tf_error) error ("invalid cast of an rvalue expression of type " diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-cast6.C b/gcc/testsuite/g++.dg/cpp0x/rv-cast6.C new file mode 100644 index 00000000000..3ae5691c5fd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/rv-cast6.C @@ -0,0 +1,11 @@ +// Test that a prvalue can be used where a glvalue is expected. +// { dg-do compile { target c++11 } } + +struct A { virtual void f(); }; +struct B : A {}; + +auto && a = static_cast(B()); +auto && b = reinterpret_cast(B()); +auto && c = dynamic_cast(B()); +auto && d = dynamic_cast(static_cast(B())); +auto && e = const_cast(B()); -- 2.30.2