I believe this is the proposal that added them:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p04...
The "references" section has links to GCC and Clang builtins:
https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
http://llvm.org/docs/BranchWeightMetadata.html#built-in-expe...
Except the standard’s likely and unlikely attributes invented new syntax that is not drop-in compatible with clang’s and gcc’s attributes.
Where clang and gcc would use:
if (__builtin_expect(x > 0, 1)) { … }
the standard uses: if (x > 0) [[likely]] { … }"Standard Attributes in C and C++"
Anyway, while it is possible that some attributes can cause UB if misused, I very much doubt that's possible with [[likely]] and [[unlikely]], as they are just hints for the optimizer, and the optimizer is supposed to preserve semantical guarantees.
They can agree at ISO level but even then it isn't enough, as proven by the whole set of issues that are currently being ignored on platforms where breaking the ABI is tabu.
These are useful when there’s static knowledge about control flow that could assist the optimizer, e.g. with inlining decisions.
For example: It’s not uncommon to have “bi-modal” functions, where simple checks guard simple actions, followed by much more complex logic to handle everything else.
Are those checks for exceptional cases like an invariant violation? Think of an I/O write function confirming the device is open.
Or are they the “fast path” for the most common invocations? Think of std::vector::push_back() checking for available capacity.
The answer helps the optimizer immensely in deciding whether to “partially inline” the simple code into callers or not.
In general the profiler is a better tool, but there are rare exceptions and if those apply to you c++ gives you the control you need.
[[likely]] return 2;
or @!l return 2;
? Which one is more understandable if you're reading and not familiar to the syntax?