diff mbox

[WIP,C++] P0217R3 - C++17 structured bindings

Message ID CADzB+2nsJATZr3ucCgqqRWOU3Li9NZex16yavwzfsFgABiphiA@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill Nov. 15, 2016, 5:43 a.m. UTC
Some fixes for bit-field and decltype handling, and address comparison
in constant expressions.

Tested x86_64-pc-linux-gnu, applied to trunk.

On Mon, Nov 14, 2016 at 10:16 AM, Jason Merrill <jason@redhat.com> wrote:
> On Mon, Nov 14, 2016 at 9:51 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>> On Sun, Nov 13, 2016 at 11:53:10PM -0500, Jason Merrill wrote:
>>> On Wed, Nov 9, 2016 at 8:05 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>>> > On Wed, Nov 09, 2016 at 01:24:22PM +0100, Jakub Jelinek wrote:
>>> >> The following patch is a WIP on P0217R3 - decomposition declarations.
>>> >> It contains various FIXMEs, Jason, do you think you could finish it up?
>>>
>>> Here's what I'm checking in, as a delta from from your patch.  More
>>> testcases would still be welcome.
>>
>> Do we want to check this in (tested on x86_64-linux)?
>
> Yes, thanks, I keep forgetting the macros.
>
>> Or are some further
>> changes needed before that (e.g. has inline, constexpr, extern, static
>> etc. been allowed for decompositions in Issaquah or not)?
>
> These haven't been considered yet.
>
>> Are you going to update https://gcc.gnu.org/projects/cxx-status.html ?
>> Seems during the C++ meeting clang added:
>>
>> Matching template template parameters to compatible arguments   P0522R0
>> Removing deprecated dynamic exception specifications    P0003R5
>> Pack expansions in using-declarations   P0195R2
>>
>> rows to their table too, are you going to add those as well (to the table
>> and/or GCC 7)?
>
> I will.
>
> Jason
commit 01702a64c7d8524d662dd4b5d07accdeddafb7f6
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Nov 15 00:08:19 2016 -0500

    Various C++17 decomposition fixes.
    
            * 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.
diff mbox

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8c2dbe1..edcd3b4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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, ...);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index f142c1f..2af95a7 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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,
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0164f2e..29f5233 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index c595437..d1dd7c4 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 2d8b7b1..6f9ad0e 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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);
diff --git a/gcc/testsuite/g++.dg/cpp0x/addressof2.C b/gcc/testsuite/g++.dg/cpp0x/addressof2.C
index 28b71d8..bf218cc 100644
--- a/gcc/testsuite/g++.dg/cpp0x/addressof2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/addressof2.C
@@ -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
index 0000000..73edc87
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp-bitfield1.C
@@ -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
index 0000000..722ff76
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp-constexpr1.C
@@ -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);
+  }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp10.C b/gcc/testsuite/g++.dg/cpp1z/decomp10.C
index 316cea9..2abbaae 100644
--- a/gcc/testsuite/g++.dg/cpp1z/decomp10.C
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp10.C
@@ -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
index 0000000..9c8aaa4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp11.C
@@ -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&>{};
+}