Various C++17 decomposition fixes.
authorJason Merrill <jason@redhat.com>
Tue, 15 Nov 2016 05:22:28 +0000 (00:22 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 15 Nov 2016 05:22:28 +0000 (00:22 -0500)
* tree.c (bitfield_p): New.
* cp-tree.h: Declare it.
* typeck.c (cxx_sizeof_expr, cxx_alignof_expr)
(cp_build_addr_expr_1): Use it instead of DECL_C_BIT_FIELD.
* decl.c (cp_finish_decomp): Look through reference.  Always
SET_DECL_DECOMPOSITION_P.
* semantics.c (finish_decltype_type): Adjust decomposition handling.

From-SVN: r242408

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/g++.dg/cpp0x/addressof2.C
gcc/testsuite/g++.dg/cpp1z/decomp-bitfield1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp-constexpr1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/decomp10.C
gcc/testsuite/g++.dg/cpp1z/decomp11.C [new file with mode: 0644]

index 1a92ffa0e4ba13b5719a5859874ba7758f40f347..e9dd17c5d36ac4dbfb0d2221e45b900be9ea4c3d 100644 (file)
@@ -1,3 +1,13 @@
+2016-11-14  Jason Merrill  <jason@redhat.com>
+
+       * tree.c (bitfield_p): New.
+       * cp-tree.h: Declare it.
+       * typeck.c (cxx_sizeof_expr, cxx_alignof_expr)
+       (cp_build_addr_expr_1): Use it instead of DECL_C_BIT_FIELD.
+       * decl.c (cp_finish_decomp): Look through reference.  Always
+       SET_DECL_DECOMPOSITION_P.
+       * semantics.c (finish_decltype_type): Adjust decomposition handling.
+
 2016-11-13  Jakub Jelinek  <jakub@redhat.com>
            Jason Merrill  <jason@redhat.com>
 
index 8c2dbe1fba6f0ab1008552d1fbe0508c17bbab16..edcd3b47fa87966441c8da723f73c9c11234db9a 100644 (file)
@@ -6572,6 +6572,7 @@ extern cp_lvalue_kind lvalue_kind         (const_tree);
 extern bool glvalue_p                          (const_tree);
 extern bool obvalue_p                          (const_tree);
 extern bool xvalue_p                           (const_tree);
+extern bool bitfield_p                         (const_tree);
 extern tree cp_stabilize_reference             (tree);
 extern bool builtin_valid_in_constant_expr_p    (const_tree);
 extern tree build_min                          (enum tree_code, tree, ...);
index f142c1fb9313b60bf70a47d36855e06306c2e8fd..2af95a7568d1591727b7ae80b44a2ffe4413e652 100644 (file)
@@ -7350,18 +7350,23 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
   for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d))
     {
       v[count - i - 1] = d;
-      if (processing_template_decl)
-       {
-         retrofit_lang_decl (d);
-         SET_DECL_DECOMPOSITION_P (d);
-       }
+      retrofit_lang_decl (d);
+      SET_DECL_DECOMPOSITION_P (d);
     }
 
   tree type = TREE_TYPE (decl);
-  tree eltype = NULL_TREE;
+  tree dexp = decl;
+
   if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+    {
+      /* If e is a constant reference, use the referent directly.  */
+      if (DECL_INITIAL (decl))
+       dexp = DECL_INITIAL (decl);
+      dexp = convert_from_reference (dexp);
+      type = TREE_TYPE (type);
+    }
 
+  tree eltype = NULL_TREE;
   unsigned HOST_WIDE_INT eltscnt = 0;
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
@@ -7391,7 +7396,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
        {
          TREE_TYPE (v[i]) = eltype;
          layout_decl (v[i], 0);
-         tree t = convert_from_reference (decl);
+         tree t = dexp;
          t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF,
                          eltype, t, size_int (i), NULL_TREE,
                          NULL_TREE);
@@ -7410,7 +7415,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
        {
          TREE_TYPE (v[i]) = eltype;
          layout_decl (v[i], 0);
-         tree t = convert_from_reference (decl);
+         tree t = dexp;
          t = build1_loc (DECL_SOURCE_LOCATION (v[i]),
                          i ? IMAGPART_EXPR : REALPART_EXPR, eltype,
                          t);
@@ -7428,7 +7433,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
        {
          TREE_TYPE (v[i]) = eltype;
          layout_decl (v[i], 0);
-         tree t = convert_from_reference (decl);
+         tree t = dexp;
          convert_vector_to_array_for_subscript (DECL_SOURCE_LOCATION (v[i]),
                                                 &t, size_int (i));
          t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF,
@@ -7501,7 +7506,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
          eltscnt++;
       if (count != eltscnt)
        goto cnt_mismatch;
-      tree t = convert_from_reference (decl);
+      tree t = dexp;
       if (type != btype)
        {
          t = convert_to_base (t, btype, /*check_access*/true,
index 0164f2e5c7478a658410d5c9eedab19b12a2fe7d..29f52333a94cf743256b8eed209215c17b64c172 100644 (file)
@@ -8873,8 +8873,13 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
       if (identifier_p (expr))
         expr = lookup_name (expr);
 
-      if (VAR_P (expr) && DECL_HAS_VALUE_EXPR_P (expr))
-       expr = DECL_VALUE_EXPR (expr);
+      /* The decltype rules for decomposition are different from the rules for
+        member access; in particular, the decomposition decl gets
+        cv-qualifiers from the aggregate object, whereas decltype of a member
+        access expr ignores the object.  */
+      if (VAR_P (expr) && DECL_DECOMPOSITION_P (expr)
+         && DECL_HAS_VALUE_EXPR_P (expr))
+       return unlowered_expr_type (DECL_VALUE_EXPR (expr));
 
       if (INDIRECT_REF_P (expr))
         /* This can happen when the expression is, e.g., "a.b". Just
index c59543768a80e28640c7339b163a34d885fd42d7..d1dd7c40680f27eff76e4a105acdcc71b0c5d19f 100644 (file)
@@ -305,6 +305,14 @@ xvalue_p (const_tree ref)
   return (lvalue_kind (ref) == clk_rvalueref);
 }
 
+/* True if REF is a bit-field.  */
+
+bool
+bitfield_p (const_tree ref)
+{
+  return (lvalue_kind (ref) & clk_bitfield);
+}
+
 /* C++-specific version of stabilize_reference.  */
 
 tree
index 2d8b7b104406ec53e84319c283d2270283671f24..6f9ad0ed3cb66e7301e6b727c47d4dba1d416efb 100644 (file)
@@ -1650,9 +1650,7 @@ cxx_sizeof_expr (tree e, tsubst_flags_t complain)
 
   e = mark_type_use (e);
 
-  if (TREE_CODE (e) == COMPONENT_REF
-      && TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL
-      && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
+  if (bitfield_p (e))
     {
       if (complain & tf_error)
         error ("invalid application of %<sizeof%> to a bit-field");
@@ -1709,9 +1707,7 @@ cxx_alignof_expr (tree e, tsubst_flags_t complain)
 
   if (VAR_P (e))
     t = size_int (DECL_ALIGN_UNIT (e));
-  else if (TREE_CODE (e) == COMPONENT_REF
-          && TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL
-          && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
+  else if (bitfield_p (e))
     {
       if (complain & tf_error)
         error ("invalid application of %<__alignof%> to a bit-field");
@@ -5751,6 +5747,13 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
   if (argtype != error_mark_node)
     argtype = build_pointer_type (argtype);
 
+  if (bitfield_p (arg))
+    {
+      if (complain & tf_error)
+       error ("attempt to take address of bit-field");
+      return error_mark_node;
+    }
+
   /* In a template, we are processing a non-dependent expression
      so we can just form an ADDR_EXPR with the correct type.  */
   if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF)
@@ -5775,13 +5778,6 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
        val = build2 (COMPOUND_EXPR, TREE_TYPE (val),
                      TREE_OPERAND (arg, 0), val);
     }
-  else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
-    {
-      if (complain & tf_error)
-       error ("attempt to take address of bit-field structure member %qD",
-              TREE_OPERAND (arg, 1));
-      return error_mark_node;
-    }
   else
     {
       tree object = TREE_OPERAND (arg, 0);
index 28b71d83b3cb57c81028d83db355083c1131100c..bf218cca481b0d4377b750e8fc0face5a0e6a809 100644 (file)
@@ -15,7 +15,7 @@ struct S { int s : 5; int t; void foo (); } s;
 
 auto c = __builtin_addressof (s);
 auto d = addressof (s);
-auto e = __builtin_addressof (s.s);            // { dg-error "attempt to take address of bit-field structure member" }
+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 h = addressof (S{});                      // { dg-error "cannot bind non-const lvalue reference of type" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp-bitfield1.C b/gcc/testsuite/g++.dg/cpp1z/decomp-bitfield1.C
new file mode 100644 (file)
index 0000000..73edc87
--- /dev/null
@@ -0,0 +1,19 @@
+// Test of bit-fields.
+// { dg-options -std=c++1z }
+
+struct A { long i: 2; } a;
+
+template <class,class> struct same_type;
+template <class T> struct same_type<T,T> {};
+
+void f()
+{
+  auto [ x ] = a;
+
+  same_type<decltype(x),long>{};
+  same_type<decltype(x+x),int>{};
+
+  long &r = x;                 // { dg-error "bit" }
+  &x;                          // { dg-error "bit" }
+  sizeof(x);                   // { dg-error "bit" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp-constexpr1.C b/gcc/testsuite/g++.dg/cpp1z/decomp-constexpr1.C
new file mode 100644 (file)
index 0000000..722ff76
--- /dev/null
@@ -0,0 +1,18 @@
+// Test for reference address comparison in constant expression.
+// { dg-options -std=c++1z }
+
+int i[2];
+struct A { int i, j; } a;
+
+void f()
+{
+  {
+    auto& [ x, y ] = i;
+    static_assert (&x == &i[0]);
+  }
+
+  {
+    auto& [ x, y ] = a;
+    static_assert (&x == &a.i && &y != &a.i);
+  }
+}
index 316cea988118474fbf15f43ce5f95acc7b4df899..2abbaaebe9a7ec4cdb6909ce0523ba59d0a81c5b 100644 (file)
@@ -31,18 +31,15 @@ struct A4 {
   template <int I> int& get() { return ar[I]; }
 } a4;
 template<> struct std::tuple_size<A4> { enum { value = 3 }; };
-template <int I> 
 void f4() { auto [ x, y, z ] = a4; }   // { dg-error "tuple_element" }
 
 struct A5 { } a5;
 template <int I> int& get(A5&& a);
 template<> struct std::tuple_size<A5> { enum { value = 3 }; };
-template <int I> 
 void f5() { auto [ x, y, z ] = a5; }   // { dg-error "tuple_element" }
 
 struct A6 { } a6;
 template <int I> int& get(A6&& a);
 template<> struct std::tuple_size<A6> { enum { value = 3 }; };
 template<> struct std::tuple_element<0, A6> { };
-template <int I> 
 void f6() { auto [ x, y, z ] = a6; }   // { dg-error "no type named .type" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp11.C b/gcc/testsuite/g++.dg/cpp1z/decomp11.C
new file mode 100644 (file)
index 0000000..9c8aaa4
--- /dev/null
@@ -0,0 +1,51 @@
+// Test for decltype of direct decomposition.
+// { dg-options -std=c++1z }
+
+template <class,class> struct same_type;
+template <class T> struct same_type<T,T> {};
+
+struct A {
+  int i;
+  const int ci = 42;
+  mutable int mi;
+  int& r = i;
+  const int& cr = ci;
+} a;
+
+void f() {
+  auto [i,ci,mi,r,cr] = a;
+
+  same_type<decltype(i),int>{};
+  same_type<decltype(ci),const int>{};
+  same_type<decltype(mi),int>{};
+  same_type<decltype(r),int&>{};
+  same_type<decltype(cr),const int&>{};
+}
+void frr() {
+  auto &&[i,ci,mi,r,cr] = a;
+
+  same_type<decltype(i),int>{};
+  same_type<decltype(ci),const int>{};
+  same_type<decltype(mi),int>{};
+  same_type<decltype(r),int&>{};
+  same_type<decltype(cr),const int&>{};
+}
+void fc() {
+  const auto [i,ci,mi,r,cr] = a;
+
+  same_type<decltype(i),const int>{};
+  same_type<decltype(ci),const int>{};
+  same_type<decltype(mi),int>{};
+  same_type<decltype(r),int&>{};
+  same_type<decltype(cr),const int&>{};
+}
+void frc() {
+  const A ca{};
+  auto &[i,ci,mi,r,cr] = ca;
+
+  same_type<decltype(i),const int>{};
+  same_type<decltype(ci),const int>{};
+  same_type<decltype(mi),int>{};
+  same_type<decltype(r),int&>{};
+  same_type<decltype(cr),const int&>{};
+}