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

Patrick Palka <ppalka at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
   Target Milestone|---                         |13.5
      Known to fail|                            |13.4.0
                 CC|                            |ppalka at gcc dot gnu.org
   Last reconfirmed|                            |2026-08-04
      Known to work|                            |12.5.0
            Summary|Wrong active union member   |[13/14/15/16/17 Regression]
                   |in constant evaluation of   |Wrong active union member
                   |variable template           |in constant evaluation of
                   |initializers                |variable template
                   |                            |initializers
     Ever confirmed|0                           |1
             Status|UNCONFIRMED                 |NEW

--- Comment #1 from Patrick Palka <ppalka at gcc dot gnu.org> ---
Started with r13-6422 "c++: more mce_false folding from cp_fully_fold_init
[PR108243]".

Initial reduction:

namespace boost {
namespace multiprecision {
enum expression_template_option { et_off };
template <class Backend, expression_template_option> struct number {
  using self_type = number;
  template <class V> constexpr number(V) : m_backend(0) {}
  constexpr void operator+=(self_type val) { do_add(val, int()); }
  template <class Exp> constexpr void do_add(Exp, int) {
    Backend __trans_tmp_2 = 0;
    eval_add(m_backend, __trans_tmp_2);
  }
  Backend m_backend;
};
enum cpp_integer_type { unsigned_magnitude };
enum cpp_int_check_type { unchecked };
namespace backends {
template <unsigned long, unsigned long, cpp_integer_type, cpp_int_check_type,
          class = int>
struct cpp_int_backend;
}
using backends::cpp_int_backend;
template <class Backend, expression_template_option ExpressionTemplates,
          class Arithmetic>
constexpr bool operator==(number<Backend, ExpressionTemplates>, Arithmetic) {
  Backend __trans_tmp_1 = 0;
  return eval_eq(__trans_tmp_1);
}
namespace backends {
template <unsigned long, unsigned long, bool> struct cpp_int_base;
template <class> struct max_precision;
template <unsigned long MinBits, unsigned long MaxBits,
          cpp_integer_type SignType, cpp_int_check_type Checked,
          class Allocator>
struct max_precision<
    cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>> {
  static constexpr long value = MaxBits;
};
template <class> struct min_precision;
template <unsigned long MinBits, unsigned long MaxBits,
          cpp_integer_type SignType, cpp_int_check_type Checked,
          class Allocator>
struct min_precision<
    cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>> {
  static constexpr long value = MinBits;
};
constexpr bool value = false;
constexpr long limb_bits = sizeof(long);
template <unsigned long MinBits> struct cpp_int_base<MinBits, MinBits, false> {
  union data_type {
    unsigned long long m_data[limb_bits];
    __int128 m_double_first_limb;
    constexpr data_type(long, long) : m_data{} {}
    constexpr data_type(__int128) : m_double_first_limb() {
      if (__builtin_is_constant_evaluated()) {
        data_type t(0, limb_bits);
        *this = t;
      }
    }
  } m_wrapper;
  long m_limbs;
  constexpr cpp_int_base(__int128 i) : m_wrapper(i), m_limbs() {}
  constexpr unsigned long long *limbs() { return m_wrapper.m_data; }
};
template <unsigned long MinBits, unsigned long MaxBits,
          cpp_integer_type SignType, cpp_int_check_type Checked, class>
struct cpp_int_backend
    : cpp_int_base<
          min_precision<cpp_int_backend<MinBits, 1, SignType, Checked>>::value,
          max_precision<cpp_int_backend<1, MaxBits, SignType, Checked>>::value,
          value> {
  using self_type = cpp_int_backend;
  template <class Arg>
  constexpr cpp_int_backend(Arg i)
      : cpp_int_base<min_precision<self_type>::value,
                     max_precision<self_type>::value, value>(i) {}
};
template <unsigned long MinBits, unsigned long MaxBits,
          cpp_int_check_type Checked, class Allocator>
constexpr bool eval_eq(
    cpp_int_backend<MinBits, MaxBits, unsigned_magnitude, Checked, Allocator>
        a) {
  return *a.limbs() == 0;
}
template <class CppInt1, class CppInt2, class CppInt3>
constexpr void add_unsigned_constexpr(CppInt1, CppInt2 a, CppInt3 b) {
  *a.limbs() > *b.limbs();
}
template <class CppInt1, class CppInt2, class CppInt3>
constexpr void add_unsigned(CppInt1 result, CppInt2 a, CppInt3 b) {
  add_unsigned_constexpr(result, a, b);
}
template <unsigned long MinBits1, unsigned long MaxBits1,
          cpp_integer_type SignType1, cpp_int_check_type Checked1,
          class Allocator1, unsigned long MinBits2, unsigned long MaxBits2,
          cpp_integer_type SignType2, cpp_int_check_type Checked2,
          class Allocator2>
constexpr void eval_add(
    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>
result,
    cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> o) {
  eval_add(result, result, o);
}
template <unsigned long MinBits1, unsigned long MaxBits1,
          cpp_integer_type SignType1, cpp_int_check_type Checked1,
          class Allocator1, unsigned long MinBits2, unsigned long MaxBits2,
          cpp_integer_type SignType2, cpp_int_check_type Checked2,
          class Allocator2, unsigned long MinBits3, unsigned long MaxBits3,
          cpp_integer_type SignType3, cpp_int_check_type Checked3,
          class Allocator3>
constexpr void eval_add(
    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>
result,
    cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> a,
    cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> b) {
  add_unsigned(result, a, b);
}
} // namespace backends
} // namespace multiprecision
} // namespace boost

namespace mp = boost::multiprecision;

using u129 = mp::number<
  mp::cpp_int_backend<129, 129, mp::unsigned_magnitude, mp::unchecked, void>,
  mp::et_off
>;

// FAILS: variable template initializer
template <int>
inline constexpr auto vt = [] (void) constexpr noexcept {
  u129 x = static_cast<unsigned __int128>(0);
  x += x;
  return x;
}();

static_assert(vt<0> == 0);

Reply via email to