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 <ja...@redhat.com> wrote: > On Mon, Nov 14, 2016 at 9:51 AM, Jakub Jelinek <ja...@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 <ja...@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 <ja...@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 --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&>{}; +}