On 8/12/21 11:16 AM, Jakub Jelinek wrote:
On Thu, Aug 12, 2021 at 10:33:20AM -0400, Jason Merrill wrote:
The following patch implements __is_layout_compatible trait and
__builtin_is_corresponding_member helper function for the
std::is_corresponding_member template function.
For now it implements the IMHO buggy but
standard definition of layout-compatible and std::is_layout_compatible
requirements (that Jonathan was discussing to change),
including ignoring of alignment differences, mishandling of bitfields in unions
and [[no_unique_address]] issues with empty classes.
Until we know what exactly is decided in a CWG that seems better to trying
to guess what the standard will say, but of course if you have different
ideas, the patch can change.
I think it's clear that if corresponding fields have different offsets or
sizes, their containing types can't plausibly be layout-compatible. And if
two types have different sizes or alignments, they can't be
layout-compatible.
That leaves open the question of whether the presence or absence of no-op
alignment specifiers makes a difference; Richard Smith's proposal would make
that incompatible, I lean the other way, but don't feel strongly about it.
Ok, so you prefer to change layout_compatible_type_p in anticipation of the
future DR.
Yes; if the standard says something nonsensical, I prefer to figure out
something more sensible to propose as a change.
Given the g++.dg/cpp2a/is-layout-compatible3.C cases, shall that include:
if (TYPE_ALIGN (type1) != TYPE_ALIGN (type2))
return false; /* Types with different alignment aren't layout-compatible.
*/
if (!tree_int_cst_equal (TYPE_SIZE_UNIT (type1), TYPE_SIZE_UNIT (type2)))
return false; /* Types with different sizes aren't layout-compatible. */
cases inside both the ENUMERAL_TYPE and CLASS_TYPE_P ifs (as e.g. the
enumeral types can have the same underlying type including alignment and
size, but the enumeral type itself could have different alignas)?
I think I can't compare TYPE_SIZE_UNIT for the fallthrough same_type_p case
because the type could be array with unspecified bounds and I expect
same_type_p fails if the sizes or alignments are different.
Sounds good.
And then also compare field offsets in struct and say members with different
offsets aren't part of the common initial sequence (that would cover the
struct S {};
struct T {};
struct U { [[no_unique_address]] S a1; [[no_unique_address]] S a2;
[[no_unique_address]] S a3; };
struct V { [[no_unique_address]] S b1; [[no_unique_address]] T b2;
[[no_unique_address]] S b3; };
case or alignas on the members as opposed to types)?
Yes.
What about DECL_ALIGN? Shall that be relevant even when it doesn't change
anything further (TYPE_ALIGN of the whole struct is already the same and
field with higher DECL_ALIGN has the same field offset as in another struct
where it has that offset because of the previous fields or is at start)?
I'm inclined to accept that.
And finally, what about the union case? Shall it check also bitfield vs.
non-bitfield, bitfield size if bitfields?
Yes.
What about [[no_unique_address]]
on the union members, shall that be relevant or not? And DECL_ALIGN?
E.g. the whole union can have the alignment,
union alignas (16) A { short a; alignas (8) int b; };
vs.
union alignas (16) B { int a; short b; };
All union fields have the same field offset of course (0), but above A::b
has different alignment requirement than B::a.
I'd allow these differences.
Jason