On Thu, May 4, 2023 at 1:29 PM Marcin Jaczewski <marcinjaczewski86@gmail.com> wrote:
czw., 4 maj 2023 o 16:39 Arthur O'Dwyer napisał(a):
> Marcin Jaczewski wrote:
>>
>> But attributes "failure" should be preferably "invisible" and "undetectable"?
[...]
I personally would prefer that you could disable attributes in one TU
and still could link with the rest of the program that had enabled
them.
And I call this "ignorable" (same as `-O3` could be integrable but
critical for any program).
But of course currently standard do not work this way, and
`[[no_unique_address]]` or `[[trivially_relocatable]]` would break if
you link two TU that have diffrent interpretation of them.

Actually, [[trivially_relocatable]] has no direct effect on ABI at all; that's one of its design principles.
Now, in some sense, everything in the entire world — as long as it's observable — is ABI. Consider:

// https://godbolt.org/z/foxvdEsfP
struct [[trivially_relocatable]] S {
  [[no_unique_address]] int i;
  boost::container::vector<int> v;
};
inline int f() { return sizeof(S); }
inline bool g() { return std::is_trivially_relocatable_v<S>; }

If you ignore the attributes in one TU, then `f` and `g` start returning 32 and 0 instead of 24 and 1; and since they're `inline` and need to have the same behavior in all TUs, that's an ODR violation.

But [[trivially_relocatable]] deliberately doesn't affect ABI in any sense other than being observable via the type trait. It doesn't affect the calling convention, or size or alignment or mangling or anything like that. This makes [[trivially_relocatable]] one big step less ABI-ful than [[no_unique_address]], which directly affects struct layout and thus calling convention.  (But it remains more ABI-ful than [[nodiscard]] or [[deprecated]], neither of which can even be used to create an ODR violation, as far as I know.)


This means to have "portable" programs for both these attributes your
headers need to have:
```
#if !__atturibte_supported(no_unique_address) ||
!__atturibte_supported(trivially_relocatable)
#error "please install new compiler"
#endif
```

Yes, but that's true of literally everything in the language. You can't use structured bindings unless the compiler supports them. You can't use concepts unless the compiler supports them. You can't use `std::flat_map` unless the library supports it. And so on, and so on, forever. We deal with this "dialectization" of C++ in at least a couple of ways:
- Feature-test macros, so you can portably tell whether your code will be accepted by the compiler with the semantics you expect. As you notice, we already have feature-test macros even for attributes, because in general their semantics do matter to working programmers.
- A general fear, in WG21, of "splitting the language" into dialects (e.g. `-fno-exceptions` or Embedded C++), which manifests as a resistance to "epochs"-type proposals and also as relentless pressure on vendors to implement everything in the current standard (and as close to "nothing else" as possible), so that code that uses exactly what's in the standard will be more-or-less "portable" across all vendors. This includes supporting the standard attributes.

In other words, attributes aren't any more special than keywords in these respects. You can't use any of C++ without compiler support for it.

–Arthur