https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116345

            Bug ID: 116345
           Summary: (cwg2867) - [DR2867] 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: ---

https://wg21.link/cwg2867

We already do implement the right ordering, e initializer is evaluated first,
then the get calls in increasing index order, but destruct temporaries from the
e initializer before the get calls rather than after that.

Here is a testcase how I believe stuff should be constructed and destructed, so
far just in a test for automatic non-template structured binding:

// CWG2867 - Order of initialization for structured bindings.
// { dg-do run { target c++17 } }

#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 c;
int i;

struct A {
  A () { assert (c == 3); ++c; }
  ~A () { assert (c == 12); ++c; }
  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; }
};

A
foo (const B &, const B &)
{
  A a;
  assert (c == 4);
  ++c;
  return a;
}

int
main ()
{
  {
    c = 1;
    const auto &[x, y, z, w] = foo (B {}, B {});
    assert (c == 11);
    ++c;
  }
  assert (c == 13);
}

Reply via email to