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>
Implement P0614R1, Range-based for statements with initializer.
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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" }
......
......@@ -7,4 +7,4 @@ int A::*ipm = &A::i;
template <class T, class U> class assert_same_type;
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();
int main()
{
&declval<int>(); // { dg-error "xvalue" }
declval<int>() = declval<int>(); // { dg-error "xvalue" }
declval<int>()++; // { dg-error "xvalue" }
--declval<int>(); // { dg-error "xvalue" }
declval<int>() += 1; // { dg-error "xvalue" }
&declval<int>(); // { dg-error "rvalue" }
declval<int>() = declval<int>(); // { dg-error "rvalue" }
declval<int>()++; // { dg-error "rvalue" }
--declval<int>(); // { dg-error "rvalue" }
declval<int>() += 1; // { dg-error "rvalue" }
}
......@@ -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];
}
......@@ -6,7 +6,7 @@ struct A { int i; };
template<int t>
void foo()
{
((struct A) { 0 }).i += 1; // { dg-error "temporary" }
((struct A) { 0 }).i += 1; // { dg-error "lvalue" }
}
void g(void)
......
......@@ -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 }
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