llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.68k stars 11.86k forks source link

`__is_standard_layout` is wrong when a base class is the type of first non-static data member #47741

Open a62a2cf6-873b-4f58-ae25-048414c98fc7 opened 3 years ago

a62a2cf6-873b-4f58-ae25-048414c98fc7 commented 3 years ago
Bugzilla Link 48397
Version trunk
OS Windows NT
CC @zygoloid

Extended Description

The static_assert in the following code fails on clang HEAD 12.0.0 (https://github.com/llvm/llvm-project.git 1c19900f9417bd0b832c1cb70863b2439a18647f) but should succeed as D is not a standard-layout class.

  struct B1 {};
  struct B2 { B1 b1; };
  struct D : B1, B2 {};
  static_assert(!__is_standard_layout(D), "D is not a standard-layout class");

Tested at: https://wandbox.org/permlink/ha8cStNKHEKl2BaJ

The standard says: https://timsong-cpp.github.io/cppwp/n4659/class#7

A class S is a standard-layout class if it:

  • ...
  • has no element of the set M(S) of types (defined below) as a base class. M(X) is defined as follows:
    • ...
    • If X is a non-union class type whose first non-static data member has type X0 (where said member may be an anonymous union), the set M(X) consists of X0 and the elements of M(X0).

The setM(D) consists of just B1 because D is a non-union class type whose first non-static data member has type B1. Then, because D has B1 as a base class, D is not a standard-layout class.

(If D is a standard-layout class, it must be layout compatible with B2. But sizeof(D) is 2 while sizeof(B2) is 1, which means they can't be layout compatible.)

ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 3 years ago

Confirmed. We check for repeated base classes, but we don't check for a base class duplicating the first field of another base class.