https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115769
Bug ID: 115769 Summary: Implement CWG 2867 - Order of initialization for structured bindings Product: gcc Version: 15.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: jakub at gcc dot gnu.org Target Milestone: --- I've tried to come up with a testcase for DR 2867 https://wg21.link/CWG2867 Both GCC and Clang currently pass this with -DCURRENT which is the ordering of e, a, b initialization, but invoke T::~T () before the get methods are called rather than after them. This is because cp_finish_decl on the structured binding base (aka e) calls initialize_local_var, which temporarily sets stmts_are_full_exprs_p = 1 and finish_expr_stmt will wrap it into a CLEANUP_POINT_EXPR. If that is not what we want, not really sure what we need to do; change initialize_local_var, so that for DECL_DECOMPOSITION_P && DECL_DECOMP_IS_BASE vars to set stmts_are_full_exprs_p to 0 instead of 1 and somewhere in the callers wrap the statements from cp_finish_decl and cp_finish_decomp into a statement list wrapped inside of CLEANUP_POINT_EXPR, something else? // DR 2867 - Order of initialization for structured bindings // { dg-do run { target c++11 } } // { dg-options "" } namespace std { template<typename T> struct tuple_size; template<int, typename> struct tuple_element; } struct S { int a, b, c; static int d; template <int I> int &get () { if (d != I + 2) __builtin_abort (); ++d; return I ? a : b; } }; int S::d = 0; template<> struct std::tuple_size<S> { static const int value = 2; }; template<int I> struct std::tuple_element<I,S> { using type = int; }; struct T { T () { if (S::d != 0) __builtin_abort (); ++S::d; } #ifndef CURRENT ~T () { if (S::d != 4) __builtin_abort (); ++S::d; } #else ~T () {} #endif }; S foo (T) { S s { 1, 2, 3 }; if (S::d != 1) __builtin_abort (); ++S::d; return s; } int main () { auto [a, b] = foo (T {}); // { dg-warning "structured bindings only available with" "" { target c++14_down } } #ifndef CURRENT if (S::d != 5 || a != 2 || b != 1) #else if (S::d != 4 || a != 2 || b != 1) #endif __builtin_abort (); }