1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14, c++17 10 11 // <atomic> 12 // 13 // template <class T> 14 // class atomic_ref; 15 // 16 // static constexpr bool is_always_lock_free; 17 // bool is_lock_free() const noexcept; 18 19 #include <atomic> 20 #include <cassert> 21 #include <concepts> 22 23 #include "test_macros.h" 24 #include "atomic_helpers.h" 25 26 template <typename T> 27 void check_always_lock_free(std::atomic_ref<T> const& a) { 28 using InfoT = LockFreeStatusInfo<T>; 29 30 constexpr std::same_as<const bool> decltype(auto) is_always_lock_free = std::atomic_ref<T>::is_always_lock_free; 31 32 // If we know the status of T for sure, validate the exact result of the function. 33 if constexpr (InfoT::status_known) { 34 constexpr LockFreeStatus known_status = InfoT::value; 35 if constexpr (known_status == LockFreeStatus::always) { 36 static_assert(is_always_lock_free, "is_always_lock_free is inconsistent with known lock-free status"); 37 assert(a.is_lock_free() && "is_lock_free() is inconsistent with known lock-free status"); 38 } else if constexpr (known_status == LockFreeStatus::never) { 39 static_assert(!is_always_lock_free, "is_always_lock_free is inconsistent with known lock-free status"); 40 assert(!a.is_lock_free() && "is_lock_free() is inconsistent with known lock-free status"); 41 } else { 42 assert(a.is_lock_free() || !a.is_lock_free()); // This is kinda dumb, but we might as well call the function once. 43 } 44 } 45 46 // In all cases, also sanity-check it based on the implication always-lock-free => lock-free. 47 if (is_always_lock_free) { 48 std::same_as<bool> decltype(auto) is_lock_free = a.is_lock_free(); 49 assert(is_lock_free); 50 } 51 ASSERT_NOEXCEPT(a.is_lock_free()); 52 } 53 54 #define CHECK_ALWAYS_LOCK_FREE(T) \ 55 do { \ 56 typedef T type; \ 57 alignas(std::atomic_ref<type>::required_alignment) type obj{}; \ 58 std::atomic_ref<type> a(obj); \ 59 check_always_lock_free(a); \ 60 } while (0) 61 62 void test() { 63 char c = 'x'; 64 check_always_lock_free(std::atomic_ref<char>(c)); 65 66 int i = 0; 67 check_always_lock_free(std::atomic_ref<int>(i)); 68 69 float f = 0.f; 70 check_always_lock_free(std::atomic_ref<float>(f)); 71 72 int* p = &i; 73 check_always_lock_free(std::atomic_ref<int*>(p)); 74 75 CHECK_ALWAYS_LOCK_FREE(struct Empty{}); 76 CHECK_ALWAYS_LOCK_FREE(struct OneInt { int i; }); 77 CHECK_ALWAYS_LOCK_FREE(struct IntArr2 { int i[2]; }); 78 CHECK_ALWAYS_LOCK_FREE(struct FloatArr3 { float i[3]; }); 79 CHECK_ALWAYS_LOCK_FREE(struct LLIArr2 { long long int i[2]; }); 80 CHECK_ALWAYS_LOCK_FREE(struct LLIArr4 { long long int i[4]; }); 81 CHECK_ALWAYS_LOCK_FREE(struct LLIArr8 { long long int i[8]; }); 82 CHECK_ALWAYS_LOCK_FREE(struct LLIArr16 { long long int i[16]; }); 83 CHECK_ALWAYS_LOCK_FREE(struct Padding { 84 char c; /* padding */ 85 long long int i; 86 }); 87 CHECK_ALWAYS_LOCK_FREE(union IntFloat { 88 int i; 89 float f; 90 }); 91 CHECK_ALWAYS_LOCK_FREE(enum class CharEnumClass : char{foo}); 92 } 93 94 int main(int, char**) { 95 test(); 96 return 0; 97 } 98