@@ -9121,7 +9121,24 @@ cp_finish_decl (tree decl, tree init, bo
initializer. It is not legal to redeclare a static data
member, so this issue does not arise in that case. */
else if (var_definition_p && TREE_STATIC (decl))
- expand_static_init (decl, init);
+ {
+ if (need_decomp_init && DECL_FUNCTION_SCOPE_P (decl))
+ {
+ tree sl = push_stmt_list ();
+ auto saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
+ current_stmt_tree ()->stmts_are_full_exprs_p = 0;
+ expand_static_init (decl, init);
+ current_stmt_tree ()->stmts_are_full_exprs_p
+ = saved_stmts_are_full_exprs_p;
+ cp_finish_decomp (decl, decomp);
+ sl = pop_stmt_list (sl);
+ sl = maybe_cleanup_point_expr_void (sl);
+ add_stmt (sl);
+ need_decomp_init = false;
+ }
+ else
+ expand_static_init (decl, init);
+ }
}
/* If a CLEANUP_STMT was created to destroy a temporary bound to a
@@ -0,0 +1,159 @@
+// CWG2867 - Order of initialization for structured bindings.
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
+
+namespace std {
+ template<typename T> struct tuple_size;
+ template<int, typename> struct tuple_element;
+}
+
+int a, c, d, i;
+
+struct A {
+ A () { assert (c == 3); ++c; }
+ ~A () { ++a; }
+ template <int I> int &get () const { assert (c == 5 + I); ++c; return i; }
+};
+
+template <> struct std::tuple_size <A> { static const int value = 4; };
+template <int I> struct std::tuple_element <I, A> { using type = int; };
+template <> struct std::tuple_size <const A> { static const int value = 4; };
+template <int I> struct std::tuple_element <I, const A> { using type = int; };
+
+struct B {
+ B () { assert (c >= 1 && c <= 2); ++c; }
+ ~B () { assert (c >= 9 && c <= 10); ++c; }
+};
+
+struct C {
+ constexpr C () {}
+ constexpr C (const C &) {}
+ template <int I> int &get () const { assert (d == 1 + I); ++d; return i; }
+};
+
+template <> struct std::tuple_size <C> { static const int value = 3; };
+template <int I> struct std::tuple_element <I, C> { using type = int; };
+template <> struct std::tuple_size <const C> { static const int value = 3; };
+template <int I> struct std::tuple_element <I, const C> { using type = int; };
+
+A
+foo (const B &, const B &)
+{
+ A a;
+ assert (c == 4);
+ ++c;
+ return a;
+}
+
+constexpr C
+foo (const C &, const C &)
+{
+ return C {};
+}
+
+int
+foo (const int &, const int &)
+{
+ assert (false);
+}
+
+inline void
+bar ()
+{
+ c = 1;
+ static const auto &[x, y, z, w] = foo (B {}, B {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (c == 11); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ ++c;
+ d = 1;
+ static const auto &[s, t, u] = foo (C {}, C {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (d == 4); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+}
+
+template <int N>
+inline void
+baz ()
+{
+ c = 1;
+ static const auto &[x, y, z, w] = foo (B {}, B {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (c == 11); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ ++c;
+ d = 1;
+ static const auto &[s, t, u] = foo (C {}, C {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (d == 4); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+}
+
+template <typename T, typename U>
+inline void
+qux ()
+{
+ c = 1;
+ static const auto &[x, y, z, w] = foo (T {}, T {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (c == 11); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ ++c;
+ d = 1;
+ static const auto &[s, t, u] = foo (U {}, U {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (d == 4); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+}
+
+inline void
+corge ()
+{
+ c = 1;
+ static auto [x, y, z, w] = foo (B {}, B {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (c == 11); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ ++c;
+ d = 1;
+ static auto [s, t, u] = foo (C {}, C {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (d == 4); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+}
+
+template <int N>
+inline void
+garply ()
+{
+ c = 1;
+ static auto [x, y, z, w] = foo (B {}, B {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (c == 11); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ ++c;
+ d = 1;
+ static auto [s, t, u] = foo (C {}, C {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (d == 4); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+}
+
+template <typename T, typename U>
+inline void
+freddy ()
+{
+ c = 1;
+ static auto [x, y, z, w] = foo (T {}, T {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (c == 11); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ ++c;
+ d = 1;
+ static auto [s, t, u] = foo (U {}, U {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (d == 4); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+}
+
+struct E {
+ ~E () { assert (a == 6); }
+};
+
+int
+main ()
+{
+ static E e;
+ bar ();
+ assert (c == 12);
+ baz <0> ();
+ assert (c == 12);
+ qux <B, C> ();
+ assert (c == 12);
+ corge ();
+ assert (c == 12);
+ garply <42> ();
+ assert (c == 12);
+ freddy <B, C> ();
+ assert (c == 12);
+ assert (a == 0);
+}
@@ -0,0 +1,108 @@
+// CWG2867 - Order of initialization for structured bindings.
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+#define assert(X) do { if (!(X)) __builtin_abort(); } while (0)
+
+namespace std {
+ template<typename T> struct tuple_size;
+ template<int, typename> struct tuple_element;
+}
+
+int a, c;
+
+struct C {
+ C () { assert (c >= 5 && c <= 17 && (c - 5) % 4 == 0); ++c; }
+ ~C () { assert (c >= 8 && c <= 20 && c % 4 == 0); ++c; }
+};
+
+struct D {
+ D () { assert (c >= 7 && c <= 19 && (c - 7) % 4 == 0); ++c; }
+ ~D () { assert (a % 5 != 4); ++a; }
+};
+
+struct A {
+ A () { assert (c == 3); ++c; }
+ ~A () { assert (a % 5 == 4); ++a; }
+ template <int I> D get (const C & = C{}) const { assert (c == 6 + 4 * I); ++c; return D {}; }
+};
+
+template <> struct std::tuple_size <A> { static const int value = 4; };
+template <int I> struct std::tuple_element <I, A> { using type = D; };
+template <> struct std::tuple_size <const A> { static const int value = 4; };
+template <int I> struct std::tuple_element <I, const A> { using type = D; };
+
+struct B {
+ B () { assert (c >= 1 && c <= 2); ++c; }
+ ~B () { assert (c >= 21 && c <= 22); ++c; }
+};
+
+A
+foo (const B &, const B &)
+{
+ A a;
+ assert (c == 4);
+ ++c;
+ return a;
+}
+
+int
+foo (const int &, const int &)
+{
+ assert (false);
+}
+
+inline void
+bar ()
+{
+ c = 1;
+ // First B::B () is invoked twice, then foo called, which invokes A::A ().
+ // e is reference bound to the A::A () constructed temporary.
+ // Then 4 times (in increasing I):
+ // C::C () is invoked, get is called, D::D () is invoked, C::~C () is
+ // invoked.
+ // After that B::~B () is invoked twice, then the following 2 user
+ // statements.
+ // At exit time D::~D () is invoked 4 times, then A::~A (), repeated 3
+ // times.
+ static const auto &[x, y, z, w] = foo (B {}, B {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (c == 23); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ ++c;
+}
+
+template <int N>
+inline void
+baz ()
+{
+ c = 1;
+ static const auto &[x, y, z, w] = foo (B {}, B {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (c == 23); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ ++c;
+}
+
+template <typename T>
+inline void
+qux ()
+{
+ c = 1;
+ static const auto &[x, y, z, w] = foo (T {}, T {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ assert (c == 23); // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-1 }
+ ++c;
+}
+
+struct E {
+ ~E () { assert (a == 15); }
+};
+
+int
+main ()
+{
+ static E e;
+ bar ();
+ assert (c == 24);
+ baz <42> ();
+ assert (c == 24);
+ qux <B> ();
+ assert (c == 24);
+ assert (a == 0);
+}