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

            Bug ID: 89481
           Summary: constexpr function allows writing one active union
                    member and reading another
           Product: gcc
           Version: 8.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: mickey.veksler at gmail dot com
  Target Milestone: ---

The following code should not compile, not when passed as a template argument
to std::intergral_constant<bool, all_zeros()> :

constexpr bool all_zeros()
{
    union mix {
        double numeric;
        char bytes[sizeof(double)+1];
    };
    mix zero{-0.0}; // active is 'numeric'

    // setting a different active member(?):
    zero.bytes[sizeof(double)] = '\0';
    for (unsigned i=0 ; i != sizeof(double) ; ++i)
    {
        // or this is illegal (since it was never initialized through 'bytes')
        if (zero.bytes[i])
           return false;
    }
    return true;
}

The puzzling thing is that the following two give different results:

int main()
{
  //  return all_zeros();
    return std::integral_constant<bool, all_zeros()>::value;
}

Unlike gcc, clang-7.0.0 emits diagnostics:
  <source>:3:16: error: constexpr function never produces a constant expression
[-Winvalid-constexpr]
  constexpr bool all_zeros()
                 ^
  <source>:10:32: note: assignment to member 'bytes' of union with active
member 'numeric' is not allowed in a constant expression
      zero.bytes[sizeof(double)] = '\0';
                               ^

Reply via email to