Commit 955da5e5 by Jason Merrill Committed by 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.

From-SVN: r260621
parent a6b29221
2018-05-23 Jason Merrill <jason@redhat.com>
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 <polacek@redhat.com> 2018-05-23 Marek Polacek <polacek@redhat.com>
Implement P0614R1, Range-based for statements with initializer. Implement P0614R1, Range-based for statements with initializer.
......
...@@ -87,6 +87,7 @@ lvalue_kind (const_tree ref) ...@@ -87,6 +87,7 @@ lvalue_kind (const_tree ref)
{ {
case SAVE_EXPR: case SAVE_EXPR:
return clk_none; return clk_none;
/* preincrements and predecrements are valid lvals, provided /* preincrements and predecrements are valid lvals, provided
what they refer to are valid lvals. */ what they refer to are valid lvals. */
case PREINCREMENT_EXPR: case PREINCREMENT_EXPR:
...@@ -94,7 +95,14 @@ lvalue_kind (const_tree ref) ...@@ -94,7 +95,14 @@ lvalue_kind (const_tree ref)
case TRY_CATCH_EXPR: case TRY_CATCH_EXPR:
case REALPART_EXPR: case REALPART_EXPR:
case IMAGPART_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 MEMBER_REF:
case DOTSTAR_EXPR: case DOTSTAR_EXPR:
...@@ -104,6 +112,11 @@ lvalue_kind (const_tree ref) ...@@ -104,6 +112,11 @@ lvalue_kind (const_tree ref)
op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0)); op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0));
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (ref, 1)))) if (TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (ref, 1))))
op1_lvalue_kind = clk_none; 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; return op1_lvalue_kind;
case COMPONENT_REF: case COMPONENT_REF:
...@@ -119,6 +132,11 @@ lvalue_kind (const_tree ref) ...@@ -119,6 +132,11 @@ lvalue_kind (const_tree ref)
return lvalue_kind (TREE_OPERAND (ref, 1)); return lvalue_kind (TREE_OPERAND (ref, 1));
} }
op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0)); 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. */ /* Look at the member designator. */
if (!op1_lvalue_kind) if (!op1_lvalue_kind)
; ;
...@@ -165,7 +183,6 @@ lvalue_kind (const_tree ref) ...@@ -165,7 +183,6 @@ lvalue_kind (const_tree ref)
/* FALLTHRU */ /* FALLTHRU */
case INDIRECT_REF: case INDIRECT_REF:
case ARROW_EXPR: case ARROW_EXPR:
case ARRAY_REF:
case PARM_DECL: case PARM_DECL:
case RESULT_DECL: case RESULT_DECL:
case PLACEHOLDER_EXPR: case PLACEHOLDER_EXPR:
...@@ -203,11 +220,7 @@ lvalue_kind (const_tree ref) ...@@ -203,11 +220,7 @@ lvalue_kind (const_tree ref)
type-dependent expr, that is, but we shouldn't be testing type-dependent expr, that is, but we shouldn't be testing
lvalueness if we can't even tell the types yet! */ lvalueness if we can't even tell the types yet! */
gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref))); gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref)));
if (CLASS_TYPE_P (TREE_TYPE (ref)) goto default_;
|| TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)
return clk_class;
else
return clk_none;
} }
op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1) op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1)
? TREE_OPERAND (ref, 1) ? TREE_OPERAND (ref, 1)
...@@ -257,18 +270,14 @@ lvalue_kind (const_tree ref) ...@@ -257,18 +270,14 @@ lvalue_kind (const_tree ref)
case PAREN_EXPR: case PAREN_EXPR:
return lvalue_kind (TREE_OPERAND (ref, 0)); 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:
default_:
if (!TREE_TYPE (ref)) if (!TREE_TYPE (ref))
return clk_none; return clk_none;
if (CLASS_TYPE_P (TREE_TYPE (ref)) if (CLASS_TYPE_P (TREE_TYPE (ref))
|| TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE) || TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)
return clk_class; return clk_class;
break; return clk_none;
} }
/* If one operand is not an lvalue at all, then this expression is /* If one operand is not an lvalue at all, then this expression is
......
...@@ -5860,11 +5860,8 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain) ...@@ -5860,11 +5860,8 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
{ {
if (!(complain & tf_error)) if (!(complain & tf_error))
return error_mark_node; return error_mark_node;
if (kind & clk_class) /* Make this a permerror because we used to accept it. */
/* Make this a permerror because we used to accept it. */ permerror (input_location, "taking address of rvalue");
permerror (input_location, "taking address of temporary");
else
error ("taking address of xvalue (rvalue reference)");
} }
} }
...@@ -9866,11 +9863,8 @@ lvalue_or_else (tree ref, enum lvalue_use use, tsubst_flags_t complain) ...@@ -9866,11 +9863,8 @@ lvalue_or_else (tree ref, enum lvalue_use use, tsubst_flags_t complain)
{ {
if (!(complain & tf_error)) if (!(complain & tf_error))
return 0; return 0;
if (kind & clk_class) /* Make this a permerror because we used to accept it. */
/* Make this a permerror because we used to accept it. */ permerror (input_location, "using rvalue as lvalue");
permerror (input_location, "using temporary as lvalue");
else
error ("using xvalue (rvalue reference) as lvalue");
} }
return 1; return 1;
} }
......
...@@ -1965,7 +1965,7 @@ build_m_component_ref (tree datum, tree component, tsubst_flags_t complain) ...@@ -1965,7 +1965,7 @@ build_m_component_ref (tree datum, tree component, tsubst_flags_t complain)
if (TYPE_PTRDATAMEM_P (ptrmem_type)) if (TYPE_PTRDATAMEM_P (ptrmem_type))
{ {
cp_lvalue_kind kind = lvalue_kind (datum); bool is_lval = real_lvalue_p (datum);
tree ptype; tree ptype;
/* Compute the type of the field, as described in [expr.ref]. /* 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) ...@@ -1995,9 +1995,7 @@ build_m_component_ref (tree datum, tree component, tsubst_flags_t complain)
return error_mark_node; return error_mark_node;
/* If the object expression was an rvalue, return an rvalue. */ /* If the object expression was an rvalue, return an rvalue. */
if (kind & clk_class) if (!is_lval)
datum = rvalue (datum);
else if (kind & clk_rvalueref)
datum = move (datum); datum = move (datum);
return datum; return datum;
} }
......
...@@ -17,7 +17,7 @@ auto c = __builtin_addressof (s); ...@@ -17,7 +17,7 @@ auto c = __builtin_addressof (s);
auto d = addressof (s); auto d = addressof (s);
auto e = __builtin_addressof (s.s); // { dg-error "attempt to take address of bit-field" } 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 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 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 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" } auto j = __builtin_addressof (S::foo); // { dg-error "invalid use of non-static member function" }
......
...@@ -7,4 +7,4 @@ int A::*ipm = &A::i; ...@@ -7,4 +7,4 @@ int A::*ipm = &A::i;
template <class T, class U> class assert_same_type; template <class T, class U> class assert_same_type;
template <class T> class assert_same_type<T,T> { }; template <class T> class assert_same_type<T,T> { };
assert_same_type<decltype(A().*ipm),int> x2; assert_same_type<decltype(A().*ipm),int&&> x2;
...@@ -4,9 +4,9 @@ template <class T> T&& declval(); ...@@ -4,9 +4,9 @@ template <class T> T&& declval();
int main() int main()
{ {
&declval<int>(); // { dg-error "xvalue" } &declval<int>(); // { dg-error "rvalue" }
declval<int>() = declval<int>(); // { dg-error "xvalue" } declval<int>() = declval<int>(); // { dg-error "rvalue" }
declval<int>()++; // { dg-error "xvalue" } declval<int>()++; // { dg-error "rvalue" }
--declval<int>(); // { dg-error "xvalue" } --declval<int>(); // { dg-error "rvalue" }
declval<int>() += 1; // { dg-error "xvalue" } declval<int>() += 1; // { dg-error "rvalue" }
} }
...@@ -6,7 +6,7 @@ struct s { int a[1]; }; ...@@ -6,7 +6,7 @@ struct s { int a[1]; };
void void
foo5 (void) foo5 (void)
{ {
((struct s) { { 0 } }).a[0] = 1; int i = ((struct s) { { 0 } }).a[0];
} }
...@@ -6,7 +6,7 @@ struct A { int i; }; ...@@ -6,7 +6,7 @@ struct A { int i; };
template<int t> template<int t>
void foo() void foo()
{ {
((struct A) { 0 }).i += 1; // { dg-error "temporary" } ((struct A) { 0 }).i += 1; // { dg-error "lvalue" }
} }
void g(void) void g(void)
......
...@@ -17,4 +17,4 @@ struct cookie ...@@ -17,4 +17,4 @@ struct cookie
}; };
cookie cat(&foo("apabepa"));// { dg-warning "deprecated conversion|forbids converting a string constant" "dep" } 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 }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment