Skip to content

Case 117: [[no_unique_address]] layout overlay (no new ChangeKind)

Field Value
Verdict ๐Ÿ”ด BREAKING
Category Breaking
Platforms Linux
Flags ABI break
Detected ChangeKinds type_size_changed, type_field_offset_changed
Source files examples/case117_no_unique_address/

Category: Binary ABI break / C++20 layout | Verdict: ๐Ÿ”ด BREAKING

What changed

v1 stores an empty stateless EmptyPolicy as an ordinary member of Widget, so it occupies at least one byte and forces padding. v2 marks the same member [[no_unique_address]], letting the compiler overlay it with the following value member. Widget therefore shrinks and the offset of value moves.

Why there is no dedicated ChangeKind

This is the point of the case: [[no_unique_address]] does not need a special detector. The overlay manifests as a plain layout change that abicheck already catches with its existing structural kinds:

  • type_size_changed / struct_size_changed โ€” sizeof(Widget) shrank
  • type_field_offset_changed / struct_field_offset_changed โ€” value moved
  • possibly type_alignment_changed โ€” depending on the members involved

A consumer compiled against the v1 layout reads value at the wrong offset against v2. See docs/development/adr/0001-deferred-modern-cpp-abi.md for why this (and not, say, C++20 modules) is in scope for the snapshot pipeline.

Files

  • v1.cpp / v2.cpp โ€” the two library builds, with the ordinary vs [[no_unique_address]] member inlined (no header: the snapshot is taken from the compiled library's DWARF). This case is Linux-only โ€” the layout change is only visible via the ELF/DWARF path.
  • app.cpp โ€” minimal consumer stub

Source files

  • CMakeLists.txt
  • app.cpp
  • v1.cpp
  • v2.cpp

See also: Examples overview ยท All BREAKING cases ยท Category: Breaking.