mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 19:16:05 +00:00

std::atomic is implemented with the following (confusing!) hierarchy of types: std::atomic<T> : std::__atomic_base<T> { ... }; std::__atomic_base<T> { std::__cxx_atomic_impl<T> __impl; }; std::__cxx_atomic_impl<T> { _Atomic(T) __val; }; Inside std::__atomic_base, we implement the is_lock_free() and is_always_lock_free() functions. However, we used to implement them inconsistently: - is_always_lock_free() is based on whether __cxx_atomic_impl<T> is always lock free (using the builtin), which means that we include any potential padding added by _Atomic(T) into the determination. - is_lock_free() was based on whether T is lock free (using the builtin), which meant that we did not take into account any potential padding added by _Atomic(T). It is important to note that the padding added by _Atomic(T) can turn a type that wouldn't be lock free into a lock free type, for example by making its size become a power of two. The inconsistency of how the two functions were implemented could lead to cases where is_always_lock_free() would return true, but is_lock_free() would then return false. This is the case for example of the following type, which is always lock free on arm64 but was incorrectly reported as !is_lock_free() before this patch: struct Foo { float x[3]; }; This patch switches the determination of is_lock_free() to be based on __cxx_atomic_impl<T> instead to match how we determine is_always_lock_free(). rdar://115324353