On Fri, Oct 9, 2026 at 3:37 PM Jakub Jelinek <[email protected]> wrote:

> On Thu, Oct 08, 2026 at 06:50:03PM +0200, Jakub Jelinek wrote:
> > On Thu, Oct 08, 2026 at 05:56:58PM +0200, Tomasz Kaminski wrote:
> > > These error are produced from value initialization of aggregate member
> in
> > > ctor initializer:
> > >     constexpr
> > >       __formatter_ptr() noexcept
> > >       : _M_spec()
> > >       {}
> > >
> > > So these are bugs, there is no reads or lvalue-to-rvalue conversions.
> >
> > Reduced:
> > struct A { int a; int b = ' '; };
> > struct B { constexpr B () noexcept : c () {} A c; };
> > constexpr B a;
> > This is similar to the problematic constexpr-dtor17.C testcase I've
> talked
> > about.
>
> Ok, here is an updated patch.
> It has the incremental patch incorporated, plus for INIT_EXPR checks
> whether
> the copy will be elided or not and if it will be, doesn't diagnose it.
> This fixes both constexpr-dtor17.C and the remaining libstdc++-v3 FAILs,
> so this version has no regressions.
>
> 2026-10-09  Jakub Jelinek  <[email protected]>
>
>         PR c++/127235
>         * cp-tree.h (INIT_EXPR_UNION_LIFETIME_START_P): Define.
>         * constexpr.cc (any_scalar_subobject, find_uninit_subobject,
>         check_uninit_subobjects): New functions.
>         (cxx_bind_parameters_in_call): Use check_uninit_subobjects.
>         (cxx_eval_call_expression): Mark INIT_EXPR with
>         INIT_EXPR_UNION_LIFETIME_START_P flag.
>         (cxx_eval_store_expression, cxx_eval_constant_expression): Use
>         check_uninit_subobjects.
>
>         * g++.dg/cpp0x/constexpr-92443.C: Expect diagnostics for C++20.
>         * g++.dg/cpp26/trivial-union6.C: Remove xfailed dg-error, add
>         dg-error with different diagnostics on a line before that.
>         * g++.dg/cpp26/trivial-union7.C: New test.
>         * g++.dg/cpp26/within-lifetime1.C (std::bit_cast): Remove.
>         (foo): Remove tests with std::bit_cast.
>         * g++.dg/cpp2a/constexpr-init24.C: New test.
>         * g++.dg/cpp2a/bit-cast11.C: Expect different diagnostics for
> C++20.
>         * g++.dg/cpp2a/bit-cast12.C: Likewise.
>         * g++.dg/cpp2a/bit-cast14.C: Likewise.
>         * g++.dg/reflect/bases_of5.C (_Vector_impl): Initialize _M_start
>         to nullptr in the ctor.
>
> --- a/gcc/cp/cp-tree.h  2026-10-09 10:03:50.499185090 +0200
> +++ b/gcc/cp/cp-tree.h  2026-10-09 12:25:48.337582273 +0200
> @@ -509,6 +509,7 @@ extern GTY(()) tree cp_global_trees[CPTI
>        MUST_NOT_THROW_CATCH_P (in MUST_NOT_THROW_EXPR)
>        MULTIPLE_NAMES_PARM_P (in PARM_DECL)
>        SPLICE_EXPR_ADDRESS_P (in SPLICE_EXPR)
> +      INIT_EXPR_UNION_LIFETIME_START_P (in INIT_EXPR)
>     3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR)
>        ICS_BAD_FLAG (in _CONV)
>        FN_TRY_BLOCK_P (in TRY_BLOCK)
> @@ -4517,6 +4518,12 @@ struct GTY(()) lang_decl {
>  #define INIT_EXPR_NRV_P(NODE) \
>    TREE_LANG_FLAG_0 (INIT_EXPR_CHECK (NODE))
>
> +/* True iff this represents starting of lifetime of a union member.
> +   In such case we shouldn't check for indeterminate subobjects on the
> +   rhs.  */
> +#define INIT_EXPR_UNION_LIFETIME_START_P(NODE) \
> +  TREE_LANG_FLAG_2 (INIT_EXPR_CHECK (NODE))
> +
>  #define CALL_OR_AGGR_INIT_CHECK(NODE) \
>    TREE_CHECK2 ((NODE), CALL_EXPR, AGGR_INIT_EXPR)
>
> --- a/gcc/cp/constexpr.cc       2026-10-09 10:03:42.070300255 +0200
> +++ b/gcc/cp/constexpr.cc       2026-10-09 12:43:37.686135716 +0200
> @@ -3291,6 +3291,188 @@ addr_of_non_const_var (tree *tp, int *wa
>    return NULL_TREE;
>  }
>
> +/* Helper function of find_uninit_subobject.  Return true if TYPE contains
> +   any scalar subobject except for subobjects of unions.  This is called
> on
> +   types of subobjects of CONSTRUCTOR_NO_PADDING elements which are
> missing
> +   in the CONSTRUCTOR.  For union it means no union member is considered
> +   active.  */
> +static bool
> +any_scalar_subobject (tree type)
> +{
> +  type = strip_array_types (type);
> +  if (type == error_mark_node || TREE_CODE (type) == UNION_TYPE)
> +    return false;
> +  if (TREE_CODE (type) == RECORD_TYPE)
> +    {
> +      for (tree field = next_subobject_field (TYPE_FIELDS (type));
> +          field; field = next_subobject_field (DECL_CHAIN (field)))
> +       if (any_scalar_subobject (TREE_TYPE (field)))
> +         return true;
> +      return false;
> +    }
> +  return true;
> +}
> +
> +/* Return true if T contains an uninitialized member and leave in
> +   COMPONENTS a vector of the indices.
> +   If called recursively on a FIELD_DECL's CONSTRUCTOR, SZ
> +   is DECL_SIZE of the FIELD_DECL, otherwise NULL.  */
> +
> +static bool
> +find_uninit_subobject (tree t, tree sz, vec<tree> *components)
> +{
> +  if (t == void_node)
> +    return true;
> +  if (TREE_CODE (t) != CONSTRUCTOR)
> +    return false;
> +  if (!AGGREGATE_TYPE_P (TREE_TYPE (t)))
> +    return true;
> +  if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
> +    {
> +      tree min = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
> +      tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t)));
> +      tree cursor = CONSTRUCTOR_NO_CLEARING (t) ? min : NULL_TREE;
> +      int any_scalar_subobject_p = -1;
> +      for (auto &e: CONSTRUCTOR_ELTS (t))
> +       {
> +         if (cursor && array_index_cmp (cursor, e.index))
> +           {
> +             if (any_scalar_subobject_p == -1)
> +               any_scalar_subobject_p
> +                 = any_scalar_subobject (TREE_TYPE (TREE_TYPE (t)));
> +             if (any_scalar_subobject_p)
> +               {
> +                 components->safe_push (cursor);
> +                 return true;
> +               }
> +             else
> +               cursor = e.index;
> +           }
> +         components->safe_push (e.index);
> +         if (find_uninit_subobject (e.value, NULL_TREE, components))
> +           return true;
> +         components->pop ();
> +         if (!cursor)
> +           continue;
> +         if (TREE_CODE (e.index) == RANGE_EXPR)
> +           cursor = TREE_OPERAND (e.index, 1);
> +         if (TREE_CODE (e.value) == RAW_DATA_CST)
> +           cursor
> +             = int_const_binop (PLUS_EXPR, cursor,
> +                                size_int (RAW_DATA_LENGTH (e.value)));
> +         else
> +           cursor = int_const_binop (PLUS_EXPR, cursor,
> +                                     size_one_node);
> +       }
> +      if (cursor)
> +       {
> +         max = int_const_binop (PLUS_EXPR, max, size_one_node);
> +         if (array_index_cmp (cursor, max))
> +           {
> +             if (any_scalar_subobject_p == -1)
> +               any_scalar_subobject_p
> +                 = any_scalar_subobject (TREE_TYPE (TREE_TYPE (t)));
> +             if (any_scalar_subobject_p)
> +               {
> +                 components->safe_push (cursor);
> +                 return true;
> +               }
> +           }
> +       }
> +      return false;
> +    }
> +  if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
> +    /* Union copying is done by copying object representation.  */
> +    return false;
> +  tree field = NULL_TREE;
> +  if (CONSTRUCTOR_NO_CLEARING (t))
> +    field = next_subobject_field (TYPE_FIELDS (TREE_TYPE (t)));
> +  for (auto &e: CONSTRUCTOR_ELTS (t))
> +    {
> +      for (; field && e.index != field;
> +          field = next_subobject_field (DECL_CHAIN (field)))
> +       if (any_scalar_subobject (TREE_TYPE (field)))
> +         {
> +           components->safe_push (field);
> +           return true;
> +         }
> +      components->safe_push (e.index);
> +      if (find_uninit_subobject (e.value, DECL_SIZE (e.index),
> +                                components))
> +       return true;
> +      components->pop ();
> +      if (field)
> +       field = next_subobject_field (DECL_CHAIN (field));
> +    }
> +  for (; field; field = next_subobject_field (DECL_CHAIN (field)))
> +    if (any_scalar_subobject (TREE_TYPE (field)))
> +      {
> +       /* Ignore FIELD_DECLs with bit positions beyond DECL_SIZE of
> +          the parent FIELD_DECL (if any) for classes with virtual bases.
> */
> +       if (cxx_dialect >= cxx26
> +           && sz
> +           && tree_int_cst_le (sz, bit_position (field)))
> +         break;
> +       components->safe_push (field);
> +       return true;
> +      }
> +  return false;
> +}
> +
> +/* Return true if INIT contains any uninitialized subobjects and
> +   if !CTX->quiet, diagnose it as well.  */
> +
> +static bool
> +check_uninit_subobjects (const constexpr_ctx *ctx,
> +                        location_t init_loc, tree init)
> +{
> +  auto_vec <tree, 8> components;
> +  if (!find_uninit_subobject (init, NULL_TREE, &components))
> +    return false;
> +  if (!ctx->quiet)
> +    {
> +      if (AGGREGATE_TYPE_P (TREE_TYPE (init)))
> +       {
> +         pretty_printer pp;
> +         pretty_printer *refpp = global_dc->get_reference_printer ();
> +         pp_format_decoder (&pp) = pp_format_decoder (refpp);
> +         pp.set_format_postprocessor
> +           (pp_format_postprocessor (refpp)->clone ());
> +#if __GNUC__ >= 10
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wformat"
> +#pragma GCC diagnostic ignored "-Wformat-diag"
> +#endif
> +         unsigned int i;
> +         tree c;
> +         FOR_EACH_VEC_ELT (components, i, c)
> +           {
> +             if (TREE_CODE (c) == INTEGER_CST)
> +               {
> +                 pp_character (&pp, '[');
> +                 pp_printf (&pp, "%E", c);
> +                 pp_character (&pp, ']');
> +               }
> +             else
> +               {
> +                 if (i)
> +                   pp_character (&pp, '.');
> +                 pp_printf (&pp, "%D", c);
> +               }
> +           }
> +#if __GNUC__ >= 10
> +#pragma GCC diagnostic pop
> +#endif
> +         error_at (init_loc, "accessing uninitialized subobject %qs",
> +                   pp_formatted_text (&pp));
> +       }
> +      else
> +       error_at (init_loc, "reading indeterminate value of type %qT",
> +                 TREE_TYPE (init));
> +    }
> +  return true;
> +}
> +
>  /* Subroutine of cxx_eval_call_expression.
>     We are processing a call expression (either CALL_EXPR or
>     AGGR_INIT_EXPR) in the context of CTX.  Evaluate
> @@ -3406,6 +3588,16 @@ cxx_bind_parameters_in_call (const const
>        /* Don't VERIFY_CONSTANT here.  */
>        if (*non_constant_p && ctx->quiet)
>         break;
> +
> +      if (cxx_dialect >= cxx20
> +         && TREE_CODE (arg) == CONSTRUCTOR
> +         && !*non_constant_p)
> +       {
> +         location_t arg_loc = cp_expr_loc_or_input_loc (x);
> +         if (check_uninit_subobjects (ctx, arg_loc, arg))
> +           *non_constant_p = true;
> +       }
> +
>        /* Just discard ellipsis args after checking their constantitude.
> */
>        if (!parms)
>         continue;
> @@ -5041,6 +5233,7 @@ cxx_eval_call_expression (const constexp
>               CONSTRUCTOR_NO_CLEARING (ctor) = true;
>               tree activate = build2 (INIT_EXPR, TREE_TYPE (new_obj),
>                                       new_obj, ctor);
> +             INIT_EXPR_UNION_LIFETIME_START_P (activate) = true;
>               cxx_eval_constant_expression (ctx, activate,
>                                             lval, non_constant_p,
> overflow_p,
>                                             jump_target);
> @@ -8985,6 +9178,43 @@ cxx_eval_store_expression (const constex
>    if (*non_constant_p)
>      return t;
>
> +  /* For C++20 and above check if aggregate assignment or default
> construction
> +     doesn't copy uninitialized subobjects, because that violates
> +     [expr.const]/(2.12): an lvalue-to-rvalue conversion that is applied
> to
> +     an object with an indeterminate value.  */
> +  if (cxx_dialect >= cxx20
> +      && TREE_CODE (init) == CONSTRUCTOR
> +      && !TREE_CLOBBER_P (init)
> +      && TREE_CODE (t) != MODOP_EXPR
> +      && (TREE_CODE (t) != INIT_EXPR
> +         || !INIT_EXPR_UNION_LIFETIME_START_P (t)))
> +    {
> +      location_t init_loc = cp_expr_loc_or_input_loc (TREE_OPERAND (t,
> 1));
> +      bool check = true;
> +      if (TREE_CODE (t) == INIT_EXPR)
> +       {
> +         /* For INIT_EXPR, don't diagnose copying of aggregates with
> +            indeterminate subobjects if the copying will be elided
> +            in cp_gimplify_init_expr.  */
> +         tree from = TREE_OPERAND (t, 1);
> +         if (TREE_CODE (from) == TARGET_EXPR
> +             && TARGET_EXPR_INITIAL (from)
> +             && (TARGET_EXPR_ELIDING_P (from)
> +                 || !TREE_ADDRESSABLE (TREE_TYPE (from))))
> +           from = TARGET_EXPR_INITIAL (from);
> +         while (TREE_CODE (from) == COMPOUND_EXPR)
> +           from = TREE_OPERAND (from, 1);
> +         if (TREE_CODE (from) == AGGR_INIT_EXPR
> +             || TREE_CODE (from) == VEC_INIT_EXPR)
> +           check = false;
> +       }
> +      if (check && check_uninit_subobjects (ctx, init_loc, init))
> +       {
> +         *non_constant_p = true;
> +         return t;
> +       }
> +    }
> +
>    /* Don't share a CONSTRUCTOR that might be changed later.  */
>    init = unshare_constructor (init);
>
> @@ -10084,6 +10314,15 @@ cxx_eval_constant_expression (const cons
>                                                  jump_target);
>             if (*jump_target)
>               return NULL_TREE;
> +           if (cxx_dialect >= cxx20
> +               && TREE_CODE (init) == CONSTRUCTOR
> +               && !*non_constant_p)
> +             {
> +               location_t init_loc
> +                 = cp_expr_loc_or_input_loc (DECL_INITIAL (r));
> +               if (check_uninit_subobjects (ctx, init_loc, init))
> +                 *non_constant_p = true;
> +             }
>             /* Don't share a CONSTRUCTOR that might be changed.  */
>             init = unshare_constructor (init);
>             /* Remember that a constant object's constructor has already
> --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-92443.C      2026-10-09
> 10:03:42.091299968 +0200
> +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-92443.C      2026-10-09
> 12:25:48.340812101 +0200
> @@ -9,4 +9,4 @@ struct a {
>    long b;
>  };
>  using d = a;
> -constexpr d e = 6, f = f | e;
> +constexpr d e = 6, f = f | e;  // { dg-error "accessing uninitialized
> subobject 'a::b'" "" { target c++20 } }
> --- a/gcc/testsuite/g++.dg/cpp26/trivial-union6.C       2026-10-09
> 10:03:42.093299941 +0200
> +++ b/gcc/testsuite/g++.dg/cpp26/trivial-union6.C       2026-10-09
> 12:25:48.341005726 +0200
> @@ -10,8 +10,8 @@ struct E { C a; };
>  union F { int a; A b; };
>  union G { int a; A b[2]; };
>
> -constexpr A fA () { A a; a.a[0] = 1; return a; }
> -constexpr A a = fA ();         // { dg-error "is not a constant
> expression" "" { xfail *-*-* } }
> +constexpr A fA () { A a; a.a[0] = 1; return a; }       // { dg-error
> "accessing uninitialized subobject 'A::a\\\[1\\\]'" }
> +constexpr A a = fA ();
>  constexpr B fB () { B a; a.b[0] = 1; return a; }
>  constexpr B b = fB ();         // { dg-error "is not a constant
> expression" }
>  constexpr C fC () { C a; a.b[0][0] = 1; a.b[1][0] = 2; a.b[1][1] = 3;
> return a; }
> --- a/gcc/testsuite/g++.dg/cpp26/trivial-union7.C       2026-10-09
> 12:25:48.341116719 +0200
> +++ b/gcc/testsuite/g++.dg/cpp26/trivial-union7.C       2026-10-09
> 12:25:48.341116719 +0200
> @@ -0,0 +1,61 @@
> +// P3074R7 - trivial unions (was std::uninitialized<T>)
> +// P3726R2 - Adjustments to Union Lifetime Rules
> +// { dg-do compile { target c++20 } }
> +
> +struct A { int a[2]; };
> +union B { int a; int b[2]; };
> +union C { int a; int b[2][2]; };
> +struct D { B a; };
> +struct E { C a; };
> +union F { int a; A b; };
> +union G { int a; A b[2]; };
> +
> +struct H { constexpr H () { a.a[0] = 1; } A a; };
> +constexpr H h; // { dg-error "is not a constant expression" }
> +struct I { constexpr I () { a.b[0] = 1; } B a; };
> +constexpr I i; // { dg-error "is not a constant expression" }
> +struct J { constexpr J () { a.b[0][0] = 1; a.b[1][0] = 2; a.b[1][1] = 3;
> } C a; };
> +constexpr J j; // { dg-error "is not a constant expression" }
> +struct K { constexpr K () { a.a.b[0] = 1; } D a; };
> +constexpr K k; // { dg-error "is not a constant expression" }
> +struct L { constexpr L () { a.a.b[0][0] = 1; a.a.b[1][0] = 2; a.a.b[1][1]
> = 3; } E a; };
> +constexpr L l; // { dg-error "is not a constant expression" }
> +struct M { constexpr M () { a.b.a[0] = 1; } F a; };
> +constexpr M m; // { dg-error "is not a constant expression" }
> +struct N { constexpr N () { a.b[0].a[0] = 1; } G a; };
> +constexpr N n; // { dg-error "is not a constant expression" }
> +struct O { constexpr O () { __builtin_start_lifetime (&a.b); a.b[0] = 1;
> } B a; };
> +constexpr O o; // { dg-error "is not a constant expression" "" { target
> c++23_down } }
> +struct P { constexpr P (bool x) {
> +  __builtin_start_lifetime (&a.b);
> +  __builtin_start_lifetime (&a.b[0]);
> +  if (x)
> +    __builtin_start_lifetime (&a.b[1]);
> +  a.b[0][0] = 1;
> +  a.b[1][0] = 2;
> +  a.b[1][1] = 3;
> +} C a; };
> +constexpr P pf (false);        // { dg-error "is not a constant
> expression" "" { target c++23_down } }
> +constexpr P pt (true); // { dg-error "is not a constant expression" "" {
> target c++23_down } }
> +struct Q { constexpr Q () { __builtin_start_lifetime (&a.a.b); a.a.b[0] =
> 1; } D a; };
> +constexpr Q q; // { dg-error "is not a constant expression" "" { target
> c++23_down } }
> +struct R { constexpr R (bool x) {
> +  __builtin_start_lifetime (&a.a.b);
> +  __builtin_start_lifetime (&a.a.b[0]);
> +  if (x)
> +    __builtin_start_lifetime (&a.a.b[1]);
> +  a.a.b[0][0] = 1;
> +  a.a.b[1][0] = 2;
> +  a.a.b[1][1] = 3;
> +} E a; };
> +constexpr R rf (false);        // { dg-error "is not a constant
> expression" "" { target c++23_down } }
> +constexpr R rt (true); // { dg-error "is not a constant expression" "" {
> target c++23_down } }
> +struct S { constexpr S (bool x) {
> +  __builtin_start_lifetime (&a.a.b[0]);        // { dg-error
> "'__builtin_start_lifetime' with containing object not within lifetime" }
> +  if (x)
> +    __builtin_start_lifetime (&a.a.b[1]);
> +  a.a.b[0][0] = 1;
> +  a.a.b[1][1] = 3;
> +} E a; };
> +constexpr S sf (false);
> +constexpr S st (true);
> --- a/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C     2026-10-09
> 10:03:42.093299941 +0200
> +++ b/gcc/testsuite/g++.dg/cpp26/within-lifetime1.C     2026-10-09
> 12:25:48.341250777 +0200
> @@ -12,15 +12,6 @@ namespace std {
>  }
>  #endif
>
> -namespace std {
> -  template <typename T, typename F>
> -  constexpr T
> -  bit_cast (const F &f) noexcept
> -  {
> -    return __builtin_bit_cast (T, f);
> -  }
> -}
> -
>  constexpr char d = 0;
>  struct E { char a; union F { int b; long c; short d; struct G { int e; }
> f[2]; } g; };
>  constexpr E e = {};
> @@ -149,15 +140,9 @@ foo ()
>      return __LINE__;
>    if (!std::is_within_lifetime (&k))
>      return __LINE__;
> -  unsigned char l = std::bit_cast <unsigned char> (k);
> -  if (!std::is_within_lifetime (&l))
> -    return __LINE__;
>    struct {} m;
>    if (!std::is_within_lifetime (&m))
>      return __LINE__;
> -  unsigned char n = std::bit_cast <unsigned char> (m);
> -  if (!std::is_within_lifetime (&n))
> -    return __LINE__;
>    int o;
>    if (!std::is_within_lifetime (static_cast <volatile int *> (&o)))
>      return __LINE__;
> --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-init24.C     2026-10-09
> 12:25:48.341425730 +0200
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init24.C     2026-10-09
> 13:03:28.935164460 +0200
> @@ -0,0 +1,218 @@
> +// PR c++/127235
> +// { dg-do compile { target c++20 } }
> +
> +struct A { int a, b; };
> +struct B { int c; A d; int e; };
> +union C { int f; long g; A h; };
> +struct D { A i[3]; C j; };
>
Could you add some guaranteed copy elision cases. To be able to crete
uninitialized prvalue we need some cosntructor doing so
struct X { constexpr X(int p) : x(p) {}; int x; int y };
X create() { return X(10); }
void pass(X);

void test() {
  X x = X(10); // OK, no copy
  pass(X(10)); // OK, no copy
  X x2 = create(); // OK, no copy
  pass(create()); // OK, no copy

  X x3 = x; // FAIL, copy
  pass(x); // FAIL, copy
}

constexpr X gx = create(); // FAILs,
// due constexpr variable with uninitialized consitiutent value,
// but initialization should be OK



> +
> +template <typename T>
> +constexpr bool
> +baz (T x)
> +{
> +  return true;
> +}
> +
> +constexpr bool
> +qux (bool x, ...)
> +{
> +  return x;
> +}
> +
> +constexpr bool
> +foo (int x)
> +{
> +  B b, c;
> +  b.c = 1;
> +  b.d.a = 2;
> +  b.e = 3;
> +  D d, e;
> +  d.i[0] = {};
> +  d.i[1] = {};
> +  d.i[2].b = 4;
> +  if (x == 1)
> +    c.d.b = b.d.b;             // { dg-error "accessing uninitialized
> member 'A::b'" }
> +  else if (x == 2)
> +    c.d = b.d;                 // { dg-error "accessing uninitialized
> subobject 'A::b'" }
> +  else if (x == 3)
> +    c = b;                     // { dg-error "accessing uninitialized
> subobject 'B::d.A::b'" }
> +  else if (x == 4)
> +    e.i[2].a = d.i[2].a;       // { dg-error "accessing uninitialized
> member 'A::a'" }
> +  else if (x == 5)
> +    e.i[2] = d.i[2];           // { dg-error "accessing uninitialized
> subobject 'A::a'" }
> +  else if (x == 6)
> +    e.i[1] = d.i[1];
> +  else if (x == 7)
> +    e = d;                     // { dg-error "accessing uninitialized
> subobject 'D::i\\\[2\\\].A::a'" }
> +  d.i[2].a = 5;
> +  if (x == 8)
> +    e = d;
> +  d.j.f = 6;
> +  if (x == 9)
> +    e = d;
> +  d.j.g = 7;
> +  if (x == 10)
> +    e = d;
> +  d.j.h.a = 8;
> +  if (x == 11)
> +    e = d;
> +  d.j.h.b = 9;
> +  if (x == 12)
> +    e = d;
> +  d = {};
> +  if (x == 13)
> +    e = d;
> +  d.j.h.b = 10;
> +  if (x == 14)
> +    e = d;
> +  C f, g;
> +  f = {};
> +  if (x == 15)
> +    g = f;
> +  f.h = {};
> +  if (x == 16)
> +    g = f;
> +  f.g = {};
> +  if (x == 17)
> +    g = f;
> +  f.h.a = {};
> +  if (x == 18)
> +    g = f;
> +  if (x == 19)
> +    C h = f;
> +  else if (x == 20)
> +    D i = d;
> +  else if (x == 21)
> +    B j = b;                   // { dg-error "accessing uninitialized
> subobject 'B::d.A::b'" }
> +  else if (x == 22)
> +    baz (f);
> +  else if (x == 23)
> +    baz (d);
> +  else if (x == 24)
> +    baz (b);                   // { dg-error "accessing uninitialized
> subobject 'B::d.A::b'" }
> +  else if (x == 25)
> +    baz <C &> (f);
> +  else if (x == 26)
> +    baz <D &> (d);
> +  else if (x == 27)
> +    baz <B &> (b);
> +  else if (x == 28)
> +    qux (true, f);
> +  else if (x == 29)
> +    qux (true, d);
> +  else if (x == 30)
> +    qux (true, b);             // { dg-error "accessing uninitialized
> subobject 'B::d.A::b'" }
> +  return true;
> +}
> +
> +constexpr A
> +bar (int x)
> +{
> +  A a;
> +  if (x == 1 || x == 3)
> +    a.a = 1;
> +  if (x == 2 || x == 3)
> +    a.b = 2;
> +  return a;                    // { dg-error "accessing uninitialized
> subobject 'A::a'" }
> +}                              // { dg-error "accessing uninitialized
> subobject 'A::b'" "" { target *-*-* } .-1 }
> +
> +constexpr B
> +fred (int x)
> +{
> +  if (x == 1)
> +    {
> +      B a;
> +      a.c = 1;
> +      a.d.a = 2;
> +      a.e = 3;
> +      return a;                        // { dg-error "accessing
> uninitialized subobject 'B::d.A::b'" }
> +    }
> +  else if (x == 2)
> +    {
> +      B b;
> +      b.c = 4;
> +      b.d.b = 5;
> +      b.e = 6;
> +      return b;                        // { dg-error "accessing
> uninitialized subobject 'B::d.A::a'" }
> +    }
> +  return {};
> +}
> +
> +constexpr C
> +corge (int x)
> +{
> +  if (x == 1)
> +    {
> +      C a;
> +      return a;
> +    }
> +  else if (x == 2)
> +    {
> +      C b;
> +      b.h.a = 1;
> +      return b;
> +    }
> +  else if (x == 3)
> +    {
> +      C c;
> +      c.g = 42;
> +      return c;
> +    }
> +  C d;
> +  if (x == 5)
> +    d.f = 1;
> +  else if (x == 6)
> +    d.g = 2;
> +  else if (x == 7)
> +    d.h.b = 3;
> +  else if (x == 8)
> +    d.h.a = 4;
> +  else if (x == 9)
> +    d.h.a = d.h.b = 5;
> +  return d;
> +}
> +
> +constexpr bool a = foo (1);
> +constexpr bool b = foo (2);
> +constexpr bool c = foo (3);
> +constexpr bool d = foo (4);
> +constexpr bool e = foo (5);
> +static_assert (foo (6));
> +constexpr bool f = foo (7);
> +static_assert (foo (8));
> +static_assert (foo (9));
> +static_assert (foo (10));
> +static_assert (foo (11));
> +static_assert (foo (12));
> +static_assert (foo (13));
> +static_assert (foo (14));
> +static_assert (foo (15));
> +static_assert (foo (16));
> +static_assert (foo (17));
> +static_assert (foo (18));
> +static_assert (foo (19));
> +static_assert (foo (20));
> +constexpr bool l = foo (21);
> +static_assert (foo (22));
> +static_assert (foo (23));
> +constexpr bool o = foo (24);
> +static_assert (foo (25));
> +static_assert (foo (26));
> +static_assert (foo (27));
> +static_assert (foo (28));
> +static_assert (foo (29));
> +constexpr bool r = foo (30);
> +constexpr int s = bar (1).a;
> +constexpr int t = bar (2).b;
> +static_assert (bar (3).a == 1);
> +constexpr int u = fred (1).d.a;
> +constexpr int v = fred (2).d.b;
> +static_assert ((corge (1), true));
> +constexpr int w = corge (2).h.a;
> +static_assert (corge (3).g == 42);
> +static_assert ((corge (4), true));
> +static_assert (corge (5).f == 1);
> +static_assert (corge (6).g == 2);
> +constexpr int x = corge (7).h.b;
> +constexpr int y = corge (8).h.a;
> +static_assert (corge (9).h.a == 5);
> --- a/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C   2026-10-09
> 10:03:42.093299941 +0200
> +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C   2026-10-09
> 12:25:48.341574360 +0200
> @@ -11,7 +11,7 @@ constexpr bool
>  f1 ()
>  {
>    T t = { 1, 2 };
> -  S s = __builtin_bit_cast (S, t);
> +  S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized
> subobject 'S::a\\\[1\\\]'" "" { target c++20 } }
>    return s.a[0] == 1;
>  }
>
> @@ -19,7 +19,7 @@ constexpr bool
>  f2 ()
>  {
>    U u = { 0, 0 };
> -  unsigned char a = __builtin_bit_cast (unsigned char, u);
> +  unsigned char a = __builtin_bit_cast (unsigned char, u); // { dg-error
> "reading indeterminate value of type 'unsigned char'" "" { target c++20 } }
>    return true;
>  }
>
> @@ -27,23 +27,23 @@ constexpr bool
>  f3 ()
>  {
>    T t = { 1, 2 };
> -  S s = __builtin_bit_cast (S, t);
> -  return s.a[1] == 0;          // { dg-error "accessing uninitialized
> array element" }
> +  S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized
> subobject 'S::a\\\[1\\\]'" "" { target c++20 } }
> +  return s.a[1] == 0;          // { dg-error "accessing uninitialized
> array element" "" { target c++17_down } }
>  }
>
>  constexpr bool
>  f4 ()
>  {
>    U u = { 0, 0 };
> -  unsigned char a = __builtin_bit_cast (unsigned char, u);
> -  return a == 0;               // { dg-error "is not a constant
> expression" }
> +  unsigned char a = __builtin_bit_cast (unsigned char, u); // { dg-error
> "reading indeterminate value of type 'unsigned char'" "" { target c++20 } }
> +  return a == 0;               // { dg-error "is not a constant
> expression" "" { target c++17_down } }
>  }
>
>  constexpr bool
>  f5 ()
>  {
>    W t = { 1, 2 };
> -  V s = __builtin_bit_cast (V, t);
> +  V s = __builtin_bit_cast (V, t); // { dg-error "accessing uninitialized
> subobject 'V::b.S::a\\\[1\\\]'" "" { target c++20 } }
>    return s.b.a[0] == 1;
>  }
>
> @@ -51,13 +51,13 @@ constexpr bool
>  f6 ()
>  {
>    W t = { 1, 2 };
> -  V s = __builtin_bit_cast (V, t);
> -  return s.b.a[1] == 1;                // { dg-error "accessing
> uninitialized array element" }
> +  V s = __builtin_bit_cast (V, t); // { dg-error "accessing uninitialized
> subobject 'V::b.S::a\\\[1\\\]'" "" { target c++20 } }
> +  return s.b.a[1] == 1;                // { dg-error "accessing
> uninitialized array element" "" { target c++17_down } }
>  }
>
> -constexpr bool a = f1 ();
> -constexpr bool b = f2 ();
> +constexpr bool a = f1 ();      // { dg-message "in .constexpr. expansion"
> "" { target c++20 } }
> +constexpr bool b = f2 ();      // { dg-message "in .constexpr. expansion"
> "" { target c++20 } }
>  constexpr bool c = f3 ();      // { dg-message "in .constexpr. expansion"
> }
>  constexpr bool d = f4 ();      // { dg-message "in .constexpr. expansion"
> }
> -constexpr bool e = f5 ();
> +constexpr bool e = f5 ();      // { dg-message "in .constexpr. expansion"
> "" { target c++20 } }
>  constexpr bool f = f6 ();      // { dg-message "in .constexpr. expansion"
> }
> --- a/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C   2026-10-09
> 10:03:42.093299941 +0200
> +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C   2026-10-09
> 12:25:48.341735065 +0200
> @@ -6,7 +6,7 @@ namespace std
>    enum class byte : unsigned char {};
>  }
>
> -struct S { unsigned char a[2]; alignas(sizeof 0) int b; };
> +struct S { std::byte a[2]; alignas(sizeof 0) int b; };
>  struct T { char a; alignas(sizeof 0) int b; };
>  struct U { char a : 1; char : 6; char b : 1; };
>  struct V { int a; S b; };
> @@ -16,15 +16,15 @@ constexpr bool
>  f1 ()
>  {
>    T t = { 1, 2 };
> -  S s = __builtin_bit_cast (S, t);
> -  return s.a[0] == 1;
> +  S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized
> subobject 'S::a\\\[1\\\]'" "" { target c++20 } }
> +  return s.a[0] == std::byte (1);
>  }
>
>  constexpr bool
>  f2 ()
>  {
>    U u = { 0, 0 };
> -  unsigned char a = __builtin_bit_cast (unsigned char, u);
> +  std::byte a = __builtin_bit_cast (std::byte, u); // { dg-error "reading
> indeterminate value of type 'std::byte'" "" { target c++20 } }
>    return true;
>  }
>
> @@ -32,37 +32,37 @@ constexpr bool
>  f3 ()
>  {
>    T t = { 1, 2 };
> -  S s = __builtin_bit_cast (S, t);
> -  return s.a[1] == 0;          // { dg-error "accessing uninitialized
> array element" }
> +  S s = __builtin_bit_cast (S, t); // { dg-error "accessing uninitialized
> subobject 'S::a\\\[1\\\]'" "" { target c++20 } }
> +  return s.a[1] == std::byte (0); // { dg-error "accessing uninitialized
> array element" "" { target c++17_down } }
>  }
>
>  constexpr bool
>  f4 ()
>  {
>    U u = { 0, 0 };
> -  unsigned char a = __builtin_bit_cast (unsigned char, u);
> -  return a == 0;               // { dg-error "is not a constant
> expression" }
> +  std::byte a = __builtin_bit_cast (std::byte, u); // { dg-error "reading
> indeterminate value of type 'std::byte'" "" { target c++20 } }
> +  return a == std::byte (0);   // { dg-error "is not a constant
> expression" "" { target c++17_down } }
>  }
>
>  constexpr bool
>  f5 ()
>  {
>    W t = { 1, 2 };
> -  V s = __builtin_bit_cast (V, t);
> -  return s.b.a[0] == 1;
> +  V s = __builtin_bit_cast (V, t); // { dg-error "accessing uninitialized
> subobject 'V::b.S::a\\\[1\\\]'" "" { target c++20 } }
> +  return s.b.a[0] == std::byte (1);
>  }
>
>  constexpr bool
>  f6 ()
>  {
>    W t = { 1, 2 };
> -  V s = __builtin_bit_cast (V, t);
> -  return s.b.a[1] == 1;                // { dg-error "accessing
> uninitialized array element" }
> +  V s = __builtin_bit_cast (V, t); // { dg-error "accessing uninitialized
> subobject 'V::b.S::a\\\[1\\\]'" "" { target c++20 } }
> +  return s.b.a[1] == std::byte (1); // { dg-error "accessing
> uninitialized array element" "" { target c++17_down } }
>  }
>
> -constexpr bool a = f1 ();
> -constexpr bool b = f2 ();
> +constexpr bool a = f1 ();      // { dg-message "in .constexpr. expansion"
> "" { target c++20 } }
> +constexpr bool b = f2 ();      // { dg-message "in .constexpr. expansion"
> "" { target c++20 } }
>  constexpr bool c = f3 ();      // { dg-message "in .constexpr. expansion"
> }
>  constexpr bool d = f4 ();      // { dg-message "in .constexpr. expansion"
> }
> -constexpr bool e = f5 ();
> +constexpr bool e = f5 ();      // { dg-message "in .constexpr. expansion"
> "" { target c++20 } }
>  constexpr bool f = f6 ();      // { dg-message "in .constexpr. expansion"
> }
> --- a/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C   2026-10-09
> 10:03:42.094299927 +0200
> +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C   2026-10-09
> 12:25:48.341882020 +0200
> @@ -11,7 +11,7 @@ constexpr bool
>  f1 ()
>  {
>    T1 t = { 0, 0, 0, 0, 0, 0, 0 };
> -  S s = __builtin_bit_cast (S, t);
> +  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing
> uninitialized subobject 'S::a'" "" { target c++20 } }
>    return true;
>  }
>
> @@ -19,7 +19,7 @@ constexpr bool
>  f2 ()
>  {
>    T2 t = { 0, 0, 0, 0, 0, 0, 0 };
> -  S s = __builtin_bit_cast (S, t);
> +  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing
> uninitialized subobject 'S::b'" "" { target c++20 } }
>    return true;
>  }
>
> @@ -27,7 +27,7 @@ constexpr bool
>  f3 ()
>  {
>    T3 t = { 0, 0, 0, 0, 0, 0, 0 };
> -  S s = __builtin_bit_cast (S, t);
> +  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing
> uninitialized subobject 'S::c'" "" { target c++20 } }
>    return true;
>  }
>
> @@ -43,8 +43,8 @@ constexpr bool
>  f5 ()
>  {
>    T1 t = { 0, 0, 0, 0, 0, 0, 0 };
> -  S s = __builtin_bit_cast (S, t);
> -  unsigned char a = s.a;               // { dg-error "accessing
> uninitialized member" }
> +  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing
> uninitialized subobject 'S::a'" "" { target c++20 } }
> +  unsigned char a = s.a;               // { dg-error "accessing
> uninitialized member" "" { target c++17_down } }
>    return true;
>  }
>
> @@ -52,8 +52,8 @@ constexpr bool
>  f6 ()
>  {
>    T2 t = { 0, 0, 0, 0, 0, 0, 0 };
> -  S s = __builtin_bit_cast (S, t);
> -  unsigned char b = s.b;               // { dg-error "accessing
> uninitialized member" }
> +  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing
> uninitialized subobject 'S::b'" "" { target c++20 } }
> +  unsigned char b = s.b;               // { dg-error "accessing
> uninitialized member" "" { target c++17_down } }
>    return true;
>  }
>
> @@ -61,14 +61,14 @@ constexpr bool
>  f7 ()
>  {
>    T3 t = { 0, 0, 0, 0, 0, 0, 0 };
> -  S s = __builtin_bit_cast (S, t);
> -  unsigned char c = s.c;               // { dg-error "accessing
> uninitialized member" }
> +  S s = __builtin_bit_cast (S, t);     // { dg-error "accessing
> uninitialized subobject 'S::c'" "" { target c++20 } }
> +  unsigned char c = s.c;               // { dg-error "accessing
> uninitialized member" "" { target c++17_down } }
>    return true;
>  }
>
> -constexpr bool a = f1 ();
> -constexpr bool b = f2 ();
> -constexpr bool c = f3 ();
> +constexpr bool a = f1 ();      // { dg-message "in .constexpr. expansion"
> "" { target c++20 } }
> +constexpr bool b = f2 ();      // { dg-message "in .constexpr. expansion"
> "" { target c++20 } }
> +constexpr bool c = f3 ();      // { dg-message "in .constexpr. expansion"
> "" { target c++20 } }
>  constexpr bool d = f4 ();      // { dg-message "in .constexpr. expansion"
> }
>  constexpr bool e = f5 ();      // { dg-message "in .constexpr. expansion"
> }
>  constexpr bool f = f6 ();      // { dg-message "in .constexpr. expansion"
> }
> --- a/gcc/testsuite/g++.dg/reflect/bases_of5.C  2026-10-09
> 10:03:42.096299900 +0200
> +++ b/gcc/testsuite/g++.dg/reflect/bases_of5.C  2026-10-09
> 12:25:48.342054145 +0200
> @@ -69,7 +69,7 @@ template <typename _Tp, typename _Alloc>
>    typedef __alloc_traits<_Alloc>::template rebind<_Tp>::other
> _Tp_alloc_type;
>    typedef __alloc_traits<_Tp_alloc_type>::pointer pointer;
>    struct _Vector_impl : _Tp_alloc_type {
> -    constexpr _Vector_impl(_Tp_alloc_type) {}
> +    constexpr _Vector_impl(_Tp_alloc_type) : _M_start(nullptr) {}
>      pointer _M_start;
>    };
>    constexpr ~_Vector_base() { _M_deallocate(_M_impl._M_start); }
>
>         Jakub
>
>

Reply via email to