CWG 616, 1213 - value category of subobject references.
authorJason Merrill <jason@redhat.com>
Wed, 23 May 2018 17:21:22 +0000 (13:21 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 23 May 2018 17:21:22 +0000 (13:21 -0400)
* 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
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/cpp0x/addressof2.C
gcc/testsuite/g++.dg/cpp0x/decltype49.C
gcc/testsuite/g++.dg/cpp0x/rv-lvalue-req.C
gcc/testsuite/g++.dg/ext/c99struct1.C
gcc/testsuite/g++.dg/ext/complit11.C
gcc/testsuite/g++.old-deja/g++.law/temps1.C

index 1e0854fc2a1ce1cdb1bf72415869a1d15a6035a8..3adb570a0cbeb4c4181ad00702d5023b88b99ddf 100644 (file)
@@ -1,3 +1,12 @@
+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.
index 15b9697a63ba9814463ed90ac28dc6d9091a7a5c..efb8c2bf926f9a0ebdb4dd321a5ff823fba8abd1 100644 (file)
@@ -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
index ecb334d19d2030c1199769744be9528f8b87a263..82089c451056d6097fd5ee749c33d7f11ae1f634 100644 (file)
@@ -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;
 }
index ad0774c6731f042bdb43876e0db3af1f0f7846b9..40233e68716736f1a72261955d39b692cb5734c7 100644 (file)
@@ -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;
     }
index bf218cca481b0d4377b750e8fc0face5a0e6a809..a38dce003a745d0758536ce145df48982b8aae7f 100644 (file)
@@ -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" }
index c3174982f82ca8748ad7e91f99f7566d269da230..d0a37823d4b2dd8aa90ccf222cc56491fa2d697a 100644 (file)
@@ -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;
index 1ca3c4154750995b7a18a310e75feca88ebd304d..10a655dc1e59dcc1467f3490f4a24bbaad6ad8ad 100644 (file)
@@ -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" }
 }
index 93e84b460393171b03b449ae2b5ad8a1adaa674a..bd5be2dbbf54605afa05b3cdee9d5fe3b7d4c55e 100644 (file)
@@ -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];
 }
 
 
index 0662543d941b8659e5c2316a572e6afdb8c037af..07418aba985f9d916acaba6175bcddbdd06349f0 100644 (file)
@@ -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)
index ad42f4257511ef3f94848716fec26cd5c51e1ecb..d1ac15d6e90f201788e147c23b5e604508de0508 100644 (file)
@@ -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 }