In the libc++ implementation of std::expected
, there is this helper variable template:
// This function returns whether the type `_Second` can be stuffed into the tail padding
// of the `_First` type if both of them are given `[[no_unique_address]]`.
template <class _First, class _Second>
inline constexpr bool __fits_in_tail_padding = []() {
struct __x {
_LIBCPP_NO_UNIQUE_ADDRESS _First __first;
_LIBCPP_NO_UNIQUE_ADDRESS _Second __second;
};
return sizeof(__x) == sizeof(_First);
}();
_LIBCPP_NO_UNIQUE_ADDRESS
is defined as:
# if __has_cpp_attribute(msvc::no_unique_address)
// MSVC implements [[no_unique_address]] as a silent no-op currently.
// (If/when MSVC breaks its C++ ABI, it will be changed to work as intended.)
// However, MSVC implements [[msvc::no_unique_address]] which does what
// [[no_unique_address]] is supposed to do, in general.
# define _LIBCPP_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
# else
# define _LIBCPP_NO_UNIQUE_ADDRESS [[__no_unique_address__]]
# endif
In my understanding, it is the __second
that can be inserted into tail padding of __first
, not the other way around. In that case, is _LIBCPP_NO_UNIQUE_ADDRESS
applied to __second
redundant?
The Itanium ABI defines a concept called "POD for the purpose of layout", which prevents compilers from utilizing tail padding of POD structs. However, since __x
would already have potentially overlapping members with only __first
being marked as _LIBCPP_NO_UNIQUE_ADDRESS
, it wouldn't be considered "POD for the purpose of layout" even without _LIBCPP_NO_UNIQUE_ADDRESS
applied to __second
.
It is not redundant, as the behavior differs depending on whether or not the attribute is applied to __second
.
In particular, when both __first
and __second
are annotated with _LIBCPP_NO_UNIQUE_ADDRESS
, __fits_in_tail_padding<int, Empty>
evaluates to true
(Empty
here being struct Empty {};
), whereas if only __first
is annotated, it evaluates to false
.
The reason is that [[no_unique_address]]
allows both reuse of tail padding and elision of empty classes. In the case of empty class elision, the attribute must be applied to a member whose type is a potentially empty class - in this case, __second
.