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 ();
}

Reply via email to