Skip to content

Union's trivial copy constructor fails during constant evaluation #49

@Quuxplusone

Description

@Quuxplusone

https://godbolt.org/z/73oM1j1v8

struct T {};

struct Op {
  constexpr Op() : t() {}
  union {
    char c;
    T t;
  };
};

constexpr bool f() {
  Op op;
  op.t.~T();
  // op.c = 0;
  auto op2 = op; // wrongly fails to be constexpr-friendly
  (void)op2;
  return true;
}

static_assert(f());  // wrongly fails

Clang trunk (ever since constexpr destructors were added in Clang 10) complains:

<source>:21:15: error: static assertion expression is not an integral constant expression
   21 | static_assert(f());
      |               ^~~
<source>:16:14: note: subobject 't' is not initialized
   16 |   auto op2 = op; // trivial?
      |              ^
<source>:16:14: note: in call to 'Op(op)'
   16 |   auto op2 = op; // trivial?
      |              ^~
<source>:21:15: note: in call to 'f()'
   21 | static_assert(f());
      |               ^~~
<source>:8:7: note: subobject declared here
    8 |     T t;
      |       ^

Uncommenting the line op.c = 0; makes Clang happy. But that line shouldn't be necessary — not physically, because op's copy constructor is trivial i.e. bytewise; nor on paper, because op.c is a char — an implicit-lifetime type — which can "pop into existence" without our needing to explicitly "activate" it here.

GCC, MSVC, and EDG happily accept this code; only Clang rejects.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions