From 955da5e5443724cb59f8fbd854c13e78c68bf000 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 23 May 2018 13:21:22 -0400 Subject: [PATCH] CWG 616, 1213 - value category of subobject references. * tree.c (lvalue_kind): A reference to a subobject of a prvalue is an xvalue. * typeck2.c (build_m_component_ref): Likewise. * typeck.c (cp_build_addr_expr_1, lvalue_or_else): Remove diagnostic distinction between temporary and xvalue. From-SVN: r260621 --- gcc/cp/ChangeLog | 9 ++++++ gcc/cp/tree.c | 35 +++++++++++++-------- gcc/cp/typeck.c | 14 +++------ gcc/cp/typeck2.c | 6 ++-- gcc/testsuite/g++.dg/cpp0x/addressof2.C | 2 +- gcc/testsuite/g++.dg/cpp0x/decltype49.C | 2 +- gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C | 10 +++--- gcc/testsuite/g++.dg/ext/c99struct1.C | 2 +- gcc/testsuite/g++.dg/ext/complit11.C | 2 +- gcc/testsuite/g++.old-deja/g++.law/temps1.C | 2 +- 10 files changed, 47 insertions(+), 37 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1e0854fc2a1..3adb570a0cb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2018-05-23 Jason Merrill + + CWG 616, 1213 - value category of subobject references. + * tree.c (lvalue_kind): A reference to a subobject of a prvalue is + an xvalue. + * typeck2.c (build_m_component_ref): Likewise. + * typeck.c (cp_build_addr_expr_1, lvalue_or_else): Remove diagnostic + distinction between temporary and xvalue. + 2018-05-23 Marek Polacek Implement P0614R1, Range-based for statements with initializer. diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 15b9697a63b..efb8c2bf926 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -87,6 +87,7 @@ lvalue_kind (const_tree ref) { case SAVE_EXPR: return clk_none; + /* preincrements and predecrements are valid lvals, provided what they refer to are valid lvals. */ case PREINCREMENT_EXPR: @@ -94,7 +95,14 @@ lvalue_kind (const_tree ref) case TRY_CATCH_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: - return lvalue_kind (TREE_OPERAND (ref, 0)); + case ARRAY_REF: + case VIEW_CONVERT_EXPR: + op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0)); + if (op1_lvalue_kind == clk_class) + /* in the case of an array operand, the result is an lvalue if that + operand is an lvalue and an xvalue otherwise */ + op1_lvalue_kind = clk_rvalueref; + return op1_lvalue_kind; case MEMBER_REF: case DOTSTAR_EXPR: @@ -104,6 +112,11 @@ lvalue_kind (const_tree ref) op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0)); if (TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (ref, 1)))) op1_lvalue_kind = clk_none; + else if (op1_lvalue_kind == clk_class) + /* The result of a .* expression whose second operand is a pointer to a + data member is an lvalue if the first operand is an lvalue and an + xvalue otherwise. */ + op1_lvalue_kind = clk_rvalueref; return op1_lvalue_kind; case COMPONENT_REF: @@ -119,6 +132,11 @@ lvalue_kind (const_tree ref) return lvalue_kind (TREE_OPERAND (ref, 1)); } op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0)); + if (op1_lvalue_kind == clk_class) + /* If E1 is an lvalue, then E1.E2 is an lvalue; + otherwise E1.E2 is an xvalue. */ + op1_lvalue_kind = clk_rvalueref; + /* Look at the member designator. */ if (!op1_lvalue_kind) ; @@ -165,7 +183,6 @@ lvalue_kind (const_tree ref) /* FALLTHRU */ case INDIRECT_REF: case ARROW_EXPR: - case ARRAY_REF: case PARM_DECL: case RESULT_DECL: case PLACEHOLDER_EXPR: @@ -203,11 +220,7 @@ lvalue_kind (const_tree ref) type-dependent expr, that is, but we shouldn't be testing lvalueness if we can't even tell the types yet! */ gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref))); - if (CLASS_TYPE_P (TREE_TYPE (ref)) - || TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE) - return clk_class; - else - return clk_none; + goto default_; } op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1) ? TREE_OPERAND (ref, 1) @@ -257,18 +270,14 @@ lvalue_kind (const_tree ref) case PAREN_EXPR: return lvalue_kind (TREE_OPERAND (ref, 0)); - case VIEW_CONVERT_EXPR: - if (location_wrapper_p (ref)) - return lvalue_kind (TREE_OPERAND (ref, 0)); - /* Fallthrough. */ - default: + default_: if (!TREE_TYPE (ref)) return clk_none; if (CLASS_TYPE_P (TREE_TYPE (ref)) || TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE) return clk_class; - break; + return clk_none; } /* If one operand is not an lvalue at all, then this expression is diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index ecb334d19d2..82089c45105 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5860,11 +5860,8 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain) { if (!(complain & tf_error)) return error_mark_node; - if (kind & clk_class) - /* Make this a permerror because we used to accept it. */ - permerror (input_location, "taking address of temporary"); - else - error ("taking address of xvalue (rvalue reference)"); + /* Make this a permerror because we used to accept it. */ + permerror (input_location, "taking address of rvalue"); } } @@ -9866,11 +9863,8 @@ lvalue_or_else (tree ref, enum lvalue_use use, tsubst_flags_t complain) { if (!(complain & tf_error)) return 0; - if (kind & clk_class) - /* Make this a permerror because we used to accept it. */ - permerror (input_location, "using temporary as lvalue"); - else - error ("using xvalue (rvalue reference) as lvalue"); + /* Make this a permerror because we used to accept it. */ + permerror (input_location, "using rvalue as lvalue"); } return 1; } diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index ad0774c6731..40233e68716 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1965,7 +1965,7 @@ build_m_component_ref (tree datum, tree component, tsubst_flags_t complain) if (TYPE_PTRDATAMEM_P (ptrmem_type)) { - cp_lvalue_kind kind = lvalue_kind (datum); + bool is_lval = real_lvalue_p (datum); tree ptype; /* Compute the type of the field, as described in [expr.ref]. @@ -1995,9 +1995,7 @@ build_m_component_ref (tree datum, tree component, tsubst_flags_t complain) return error_mark_node; /* If the object expression was an rvalue, return an rvalue. */ - if (kind & clk_class) - datum = rvalue (datum); - else if (kind & clk_rvalueref) + if (!is_lval) datum = move (datum); return datum; } diff --git a/gcc/testsuite/g++.dg/cpp0x/addressof2.C b/gcc/testsuite/g++.dg/cpp0x/addressof2.C index bf218cca481..a38dce003a7 100644 --- a/gcc/testsuite/g++.dg/cpp0x/addressof2.C +++ b/gcc/testsuite/g++.dg/cpp0x/addressof2.C @@ -17,7 +17,7 @@ auto c = __builtin_addressof (s); auto d = addressof (s); auto e = __builtin_addressof (s.s); // { dg-error "attempt to take address of bit-field" } auto f = addressof (s.s); // { dg-error "cannot bind bitfield" } -auto g = __builtin_addressof (S{}); // { dg-error "taking address of temporary" } +auto g = __builtin_addressof (S{}); // { dg-error "taking address of rvalue" } auto h = addressof (S{}); // { dg-error "cannot bind non-const lvalue reference of type" } auto i = __builtin_addressof (S::t); // { dg-error "invalid use of non-static data member" } auto j = __builtin_addressof (S::foo); // { dg-error "invalid use of non-static member function" } diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype49.C b/gcc/testsuite/g++.dg/cpp0x/decltype49.C index c3174982f82..d0a37823d4b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/decltype49.C +++ b/gcc/testsuite/g++.dg/cpp0x/decltype49.C @@ -7,4 +7,4 @@ int A::*ipm = &A::i; template class assert_same_type; template class assert_same_type { }; -assert_same_type x2; +assert_same_type x2; diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C b/gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C index 1ca3c415475..10a655dc1e5 100644 --- a/gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C +++ b/gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C @@ -4,9 +4,9 @@ template T&& declval(); int main() { - &declval(); // { dg-error "xvalue" } - declval() = declval(); // { dg-error "xvalue" } - declval()++; // { dg-error "xvalue" } - --declval(); // { dg-error "xvalue" } - declval() += 1; // { dg-error "xvalue" } + &declval(); // { dg-error "rvalue" } + declval() = declval(); // { dg-error "rvalue" } + declval()++; // { dg-error "rvalue" } + --declval(); // { dg-error "rvalue" } + declval() += 1; // { dg-error "rvalue" } } diff --git a/gcc/testsuite/g++.dg/ext/c99struct1.C b/gcc/testsuite/g++.dg/ext/c99struct1.C index 93e84b46039..bd5be2dbbf5 100644 --- a/gcc/testsuite/g++.dg/ext/c99struct1.C +++ b/gcc/testsuite/g++.dg/ext/c99struct1.C @@ -6,7 +6,7 @@ struct s { int a[1]; }; void foo5 (void) { - ((struct s) { { 0 } }).a[0] = 1; + int i = ((struct s) { { 0 } }).a[0]; } diff --git a/gcc/testsuite/g++.dg/ext/complit11.C b/gcc/testsuite/g++.dg/ext/complit11.C index 0662543d941..07418aba985 100644 --- a/gcc/testsuite/g++.dg/ext/complit11.C +++ b/gcc/testsuite/g++.dg/ext/complit11.C @@ -6,7 +6,7 @@ struct A { int i; }; template void foo() { - ((struct A) { 0 }).i += 1; // { dg-error "temporary" } + ((struct A) { 0 }).i += 1; // { dg-error "lvalue" } } void g(void) diff --git a/gcc/testsuite/g++.old-deja/g++.law/temps1.C b/gcc/testsuite/g++.old-deja/g++.law/temps1.C index ad42f425751..d1ac15d6e90 100644 --- a/gcc/testsuite/g++.old-deja/g++.law/temps1.C +++ b/gcc/testsuite/g++.old-deja/g++.law/temps1.C @@ -17,4 +17,4 @@ struct cookie }; cookie cat(&foo("apabepa"));// { dg-warning "deprecated conversion|forbids converting a string constant" "dep" } -// { dg-warning "taking address of temporary" "add" { target *-*-* } .-1 } +// { dg-warning "taking address of rvalue" "add" { target *-*-* } .-1 } -- 2.30.2