From b7f0df71a9de2354fcb7fb991e2a7406405c612d Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 29 May 2019 09:44:50 +0200 Subject: [PATCH] P1091R3 - Extending structured bindings to be more like var decls P1381R1 - Reference capture of structured bindings P1091R3 - Extending structured bindings to be more like var decls P1381R1 - Reference capture of structured bindings * decl.c (cp_maybe_mangle_decomp): Handle TREE_STATIC decls even at function scope. (cp_finish_decomp): Copy over various decl properties from decl to v[i] in the tuple case. (grokdeclarator): Allow static, thread_local and __thread for C++2a and use pedwarn instead of error for older standard revisions. Make other structured binding diagnostic messages more i18n friendly. * g++.dg/cpp1z/decomp3.C (test): For static, expect only warning instead of error and only for c++17_down. Add a thread_local test. (z2): Add a __thread test. * g++.dg/cpp2a/decomp1.C: New test. * g++.dg/cpp2a/decomp1-aux.cc: New file. * g++.dg/cpp2a/decomp2.C: New test. * g++.dg/cpp2a/decomp3.C: New test. From-SVN: r271730 --- gcc/cp/decl.c | 72 ++++++++++++------ gcc/testsuite/g++.dg/cpp1z/decomp3.C | 7 +- gcc/testsuite/g++.dg/cpp2a/decomp1-aux.cc | 52 +++++++++++++ gcc/testsuite/g++.dg/cpp2a/decomp1.C | 92 +++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp2a/decomp2.C | 76 +++++++++++++++++++ gcc/testsuite/g++.dg/cpp2a/decomp3.C | 26 +++++++ 6 files changed, 299 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/decomp1-aux.cc create mode 100644 gcc/testsuite/g++.dg/cpp2a/decomp1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/decomp2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/decomp3.C diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 2bb50e47478..99d75574d51 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7626,7 +7626,7 @@ cp_maybe_mangle_decomp (tree decl, tree first, unsigned int count) { if (!processing_template_decl && !error_operand_p (decl) - && DECL_NAMESPACE_SCOPE_P (decl)) + && TREE_STATIC (decl)) { auto_vec v; v.safe_grow (count); @@ -7857,8 +7857,27 @@ cp_finish_decomp (tree decl, tree first, unsigned int count) DECL_HAS_VALUE_EXPR_P (v[i]) = 0; } if (!processing_template_decl) - cp_finish_decl (v[i], init, /*constexpr*/false, - /*asm*/NULL_TREE, LOOKUP_NORMAL); + { + TREE_PUBLIC (v[i]) = TREE_PUBLIC (decl); + TREE_STATIC (v[i]) = TREE_STATIC (decl); + DECL_COMMON (v[i]) = DECL_COMMON (decl); + DECL_COMDAT (v[i]) = DECL_COMDAT (decl); + if (TREE_STATIC (v[i])) + { + CP_DECL_THREAD_LOCAL_P (v[i]) + = CP_DECL_THREAD_LOCAL_P (decl); + set_decl_tls_model (v[i], DECL_TLS_MODEL (decl)); + if (DECL_ONE_ONLY (decl)) + make_decl_one_only (v[i], cxx_comdat_group (v[i])); + if (TREE_PUBLIC (decl)) + DECL_WEAK (v[i]) = DECL_WEAK (decl); + DECL_VISIBILITY (v[i]) = DECL_VISIBILITY (decl); + DECL_VISIBILITY_SPECIFIED (v[i]) + = DECL_VISIBILITY_SPECIFIED (decl); + } + cp_finish_decl (v[i], init, /*constexpr*/false, + /*asm*/NULL_TREE, LOOKUP_NORMAL); + } } /* Ignore reads from the underlying decl performed during initialization of the individual variables. If those will be read, we'll mark @@ -11067,40 +11086,43 @@ grokdeclarator (const cp_declarator *declarator, ? declarator->declarator->id_loc : declarator->id_loc); if (inlinep) error_at (declspecs->locations[ds_inline], - "structured binding declaration cannot be %"); + "structured binding declaration cannot be %qs", "inline"); if (typedef_p) error_at (declspecs->locations[ds_typedef], - "structured binding declaration cannot be %"); + "structured binding declaration cannot be %qs", "typedef"); if (constexpr_p) error_at (declspecs->locations[ds_constexpr], "structured " - "binding declaration cannot be %"); - if (thread_p) - error_at (declspecs->locations[ds_thread], - "structured binding declaration cannot be %qs", - declspecs->gnu_thread_keyword_p - ? "__thread" : "thread_local"); + "binding declaration cannot be %qs", "constexpr"); + if (thread_p && cxx_dialect < cxx2a) + pedwarn (declspecs->locations[ds_thread], 0, + "structured binding declaration can be %qs only in " + "%<-std=c++2a%> or %<-std=gnu++2a%>", + declspecs->gnu_thread_keyword_p + ? "__thread" : "thread_local"); if (concept_p) error_at (declspecs->locations[ds_concept], - "structured binding declaration cannot be %"); + "structured binding declaration cannot be %qs", "concept"); switch (storage_class) { case sc_none: break; case sc_register: - error_at (loc, "structured binding declaration cannot be " - "%"); + error_at (loc, "structured binding declaration cannot be %qs", + "register"); break; case sc_static: - error_at (loc, "structured binding declaration cannot be " - "%"); + if (cxx_dialect < cxx2a) + pedwarn (loc, 0, + "structured binding declaration can be %qs only in " + "%<-std=c++2a%> or %<-std=gnu++2a%>", "static"); break; case sc_extern: - error_at (loc, "structured binding declaration cannot be " - "%"); + error_at (loc, "structured binding declaration cannot be %qs", + "extern"); break; case sc_mutable: - error_at (loc, "structured binding declaration cannot be " - "%"); + error_at (loc, "structured binding declaration cannot be %qs", + "mutable"); break; case sc_auto: error_at (loc, "structured binding declaration cannot be " @@ -11126,12 +11148,12 @@ grokdeclarator (const cp_declarator *declarator, inlinep = 0; typedef_p = 0; constexpr_p = 0; - thread_p = 0; concept_p = 0; - storage_class = sc_none; - staticp = 0; - declspecs->storage_class = sc_none; - declspecs->locations[ds_thread] = UNKNOWN_LOCATION; + if (storage_class != sc_static) + { + storage_class = sc_none; + declspecs->storage_class = sc_none; + } } /* Static anonymous unions are dealt with here. */ diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp3.C b/gcc/testsuite/g++.dg/cpp1z/decomp3.C index 95e9f376dd2..a9b23b08d83 100644 --- a/gcc/testsuite/g++.dg/cpp1z/decomp3.C +++ b/gcc/testsuite/g++.dg/cpp1z/decomp3.C @@ -35,12 +35,17 @@ test (A &b, B c) // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 } explicit auto [ w ] = c; // { dg-error "'explicit' outside class declaration" } // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 } - static auto [ x ] = c; // { dg-error "structured binding declaration cannot be 'static'" } + static auto [ x ] = c; // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } } // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 } extern auto [ y ] { c }; // { dg-error "structured binding declaration cannot be 'extern'" } // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 } + thread_local auto [ z ] = c; // { dg-warning "structured binding declaration can be 'thread_local' only in" "" { target c++17_down } } + // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 } } +__thread auto [ z2 ] = B (); // { dg-warning "structured binding declaration can be '__thread' only in" "" { target c++17_down } } + // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 } + void test2 (auto & [ p ] = bar ()) // { dg-error "'p' was not declared in this scope" } { // { dg-warning "auto" "" { target { ! concepts } } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp1-aux.cc b/gcc/testsuite/g++.dg/cpp2a/decomp1-aux.cc new file mode 100644 index 00000000000..2aaa2dfc50b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/decomp1-aux.cc @@ -0,0 +1,52 @@ +// P1091R3 +// { dg-do compile { target { c++17 && c++14_down } } } + +namespace std { + template struct tuple_size; + template struct tuple_element; +} + +struct A { + int i; + A(int x) : i(x) {} + template int& get() { return i; } +}; +struct B { int a, b, c; }; + +template<> struct std::tuple_size { static const int value = 2; }; +template struct std::tuple_element { using type = int; }; + +B s = { 1, 2, 3 }; + +#line 1 +static auto [ d, e, f ] = s; +static auto [ g, h ] = A (42); + +int & +foo (int x) +{ + switch (x) + { + case 0: return d; + case 1: return e; + case 2: return f; + case 3: return g; + default: return h; + } +} + +int +bar (int x) +{ +#line 3 + static auto [ m, n, o ] = s; + static auto [ p, q ] = A (43); + switch (x) + { + case 0: return ++m; + case 1: return ++n; + case 2: return ++o; + case 3: return ++p; + default: return ++q; + } +} diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp1.C b/gcc/testsuite/g++.dg/cpp2a/decomp1.C new file mode 100644 index 00000000000..7f7dab534b9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/decomp1.C @@ -0,0 +1,92 @@ +// P1091R3 +// { dg-do run { target c++11 } } +// { dg-options "" } +// { dg-additional-sources decomp1-aux.cc } + +namespace std { + template struct tuple_size; + template struct tuple_element; +} + +struct A { + int i; + A(int x) : i(x) {} + template int& get() { return i; } +}; +struct B { int a, b, c; }; + +template<> struct std::tuple_size { static const int value = 2; }; +template struct std::tuple_element { using type = int; }; + +extern int &foo (int); +extern int bar (int); +extern B s; +extern "C" void abort (); +B t = { 4, 5, 6 }; + +static auto [ d, e, f ] = t; // { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } +static auto [ g, h ] = A (44); // { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } +// The following warnings are in decomp1-aux.cc with #line directive. +// { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } 1 } +// { dg-warning "structured bindings only available with" "" { target c++14_down } 1 } +// { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } 2 } +// { dg-warning "structured bindings only available with" "" { target c++14_down } 2 } +// { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } 3 } +// { dg-warning "structured bindings only available with" "" { target c++14_down } 3 } +// { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } 4 } +// { dg-warning "structured bindings only available with" "" { target c++14_down } 4 } + +int & +baz (int x) +{ + switch (x) + { + case 0: return d; + case 1: return e; + case 2: return f; + case 3: return g; + default: return h; + } +} + +int +qux (int x) +{ + static auto [ m, n, o ] = t; // { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + static auto [ p, q ] = A (45); // { dg-warning "structured binding declaration can be 'static' only" "" { target c++17_down } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + switch (x) + { + case 0: return ++m; + case 1: return ++n; + case 2: return ++o; + case 3: return ++p; + default: return ++q; + } +} + +int +main () +{ + int *a[10]; + for (int i = 0; i < 5; ++i) + { + a[i] = &foo (i); + a[i + 5] = &baz (i); + } + for (int i = 0; i < 10; ++i) + for (int j = i + 1; j < 10; ++j) + if (a[i] == a[j] && (j != i + 1 || (i % 5) != 3)) + abort (); + if (a[1] != a[0] + 1 || a[2] != a[0] + 2 || a[4] != a[3] + || a[6] != a[5] + 1 || a[7] != a[5] + 2 || a[9] != a[8]) + abort (); + int b[] = { 1, 2, 3, 43, 43 + 6, 4, 5, 6, 45, 45 + 11 }; + for (int i = 0; i < 10; ++i) + for (int j = 0; j < 3 + i; ++j) + if ((i < 5 ? bar (i) : qux (i - 5)) != b[i] + 1 + j) + abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp2.C b/gcc/testsuite/g++.dg/cpp2a/decomp2.C new file mode 100644 index 00000000000..9149d0253e9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/decomp2.C @@ -0,0 +1,76 @@ +// P1091R3 +// { dg-do run { target c++11 } } +// { dg-options "" } +// { dg-require-effective-target tls } + +namespace std { + template struct tuple_size; + template struct tuple_element; +} + +struct A { + int i; + A(int x) : i(x) {} + template int& get() { return i; } +}; +struct B { int a, b, c; }; + +template<> struct std::tuple_size { static const int value = 2; }; +template struct std::tuple_element { using type = int; }; + +extern "C" void abort (); +B t = { 4, 5, 6 }; + +thread_local auto [ d, e, f ] = t; // { dg-warning "structured binding declaration can be 'thread_local' only" "" { target c++17_down } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } +thread_local auto [ g, h ] = A (44); // { dg-warning "structured binding declaration can be 'thread_local' only" "" { target c++17_down } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + +int & +baz (int x) +{ + switch (x) + { + case 0: return d; + case 1: return e; + case 2: return f; + case 3: return g; + default: return h; + } +} + +int +qux (int x) +{ + thread_local auto [ m, n, o ] = t; // { dg-warning "structured binding declaration can be 'thread_local' only" "" { target c++17_down } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + thread_local auto [ p, q ] = A (45); // { dg-warning "structured binding declaration can be 'thread_local' only" "" { target c++17_down } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + switch (x) + { + case 0: return ++m; + case 1: return ++n; + case 2: return ++o; + case 3: return ++p; + default: return ++q; + } +} + +int +main () +{ + int *a[5]; + for (int i = 0; i < 5; ++i) + a[i] = &baz (i); + for (int i = 0; i < 5; ++i) + for (int j = i + 1; j < 5; ++j) + if (a[i] == a[j] && (j != i + 1 || i != 3)) + abort (); + if (a[1] != a[0] + 1 || a[2] != a[0] + 2 || a[4] != a[3]) + abort (); + int b[] = { 4, 5, 6, 45, 45 + 6 }; + for (int i = 0; i < 5; ++i) + for (int j = 0; j < 3 + i; ++j) + if (qux (i) != b[i] + 1 + j) + abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/decomp3.C b/gcc/testsuite/g++.dg/cpp2a/decomp3.C new file mode 100644 index 00000000000..1afaefd66b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/decomp3.C @@ -0,0 +1,26 @@ +// P1381R1 +// { dg-do compile { target c++11 } } +// { dg-options "" } + +struct Foo { int a : 1; int b; }; + +int main() { + auto[a, b] = Foo(); // { dg-warning "structured bindings only available with" "" { target c++14_down } } + + auto f1 = [&] { return a; }; // { dg-error "cannot bind bitfield" } + auto f2 = [&a = a] { return a; }; // { dg-error "cannot bind bitfield" } + // { dg-warning "lambda capture initializers only available with" "" { target c++11_only } .-1 } + auto f3 = [&a] { return a; }; // { dg-error "cannot bind bitfield" } + + auto g1 = [&] { return b; }; + auto g2 = [&b = b] { return b; }; // { dg-warning "lambda capture initializers only available with" "" { target c++11_only } } + auto g3 = [&b] { return b; }; + + auto h1 = [=] { return a; }; + auto h2 = [a = a] { return a; }; // { dg-warning "lambda capture initializers only available with" "" { target c++11_only } } + auto h3 = [a] { return a; }; + + auto i1 = [=] { return b; }; + auto i2 = [b = b] { return b; }; // { dg-warning "lambda capture initializers only available with" "" { target c++11_only } } + auto i3 = [b] { return b; }; +} -- 2.30.2