+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.
{
case SAVE_EXPR:
return clk_none;
+
/* preincrements and predecrements are valid lvals, provided
what they refer to are valid lvals. */
case PREINCREMENT_EXPR:
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:
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:
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)
;
/* FALLTHRU */
case INDIRECT_REF:
case ARROW_EXPR:
- case ARRAY_REF:
case PARM_DECL:
case RESULT_DECL:
case PLACEHOLDER_EXPR:
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)
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
{
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");
}
}
{
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;
}
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].
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;
}
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" }
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;
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" }
}
void
foo5 (void)
{
- ((struct s) { { 0 } }).a[0] = 1;
+ int i = ((struct s) { { 0 } }).a[0];
}
template<int t>
void foo()
{
- ((struct A) { 0 }).i += 1; // { dg-error "temporary" }
+ ((struct A) { 0 }).i += 1; // { dg-error "lvalue" }
}
void g(void)
};
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 }