Stephan Tolksdorf: fixes the issue in the <atomic> header and adds corresponding tests. I've used macros to fall back to a user-provided default constructor if _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS (though I suspect that there won't be many users defining that macro).
The tests use placement new to check that atomic values get properly zero-initialized. I had to modify the atomic_is_lock_free test, because default initialization of an object of const type 'const A' (aka 'const atomic<int>') requires a user-provided default constructor. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@180945 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e58bc12f2a
commit
74f4da7219
12
CREDITS.TXT
12
CREDITS.TXT
@ -48,6 +48,10 @@ N: Argyrios Kyrtzidis
|
|||||||
E: kyrtzidis@apple.com
|
E: kyrtzidis@apple.com
|
||||||
D: Bug fixes.
|
D: Bug fixes.
|
||||||
|
|
||||||
|
N: Bruce Mitchener, Jr.
|
||||||
|
E: bruce.mitchener@gmail.com
|
||||||
|
D: Emscripten-related changes.
|
||||||
|
|
||||||
N: Michel Morin
|
N: Michel Morin
|
||||||
E: mimomorin@gmail.com
|
E: mimomorin@gmail.com
|
||||||
D: Minor patches to is_convertible.
|
D: Minor patches to is_convertible.
|
||||||
@ -78,6 +82,10 @@ N: Joerg Sonnenberger
|
|||||||
E: joerg@NetBSD.org
|
E: joerg@NetBSD.org
|
||||||
D: NetBSD port.
|
D: NetBSD port.
|
||||||
|
|
||||||
|
N: Stephan Tolksdorf
|
||||||
|
E: st@quanttec.com
|
||||||
|
D: Minor <atomic> fix
|
||||||
|
|
||||||
N: Michael van der Westhuizen
|
N: Michael van der Westhuizen
|
||||||
E: r1mikey at gmail dot com
|
E: r1mikey at gmail dot com
|
||||||
|
|
||||||
@ -93,7 +101,3 @@ N: Jeffrey Yasskin
|
|||||||
E: jyasskin@gmail.com
|
E: jyasskin@gmail.com
|
||||||
E: jyasskin@google.com
|
E: jyasskin@google.com
|
||||||
D: Linux fixes.
|
D: Linux fixes.
|
||||||
|
|
||||||
N: Bruce Mitchener, Jr.
|
|
||||||
E: bruce.mitchener@gmail.com
|
|
||||||
D: Emscripten-related changes.
|
|
||||||
|
@ -216,7 +216,9 @@ typedef __char32_t char32_t;
|
|||||||
# define _LIBCPP_NORETURN __attribute__ ((noreturn))
|
# define _LIBCPP_NORETURN __attribute__ ((noreturn))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !(__has_feature(cxx_defaulted_functions))
|
||||||
#define _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
|
#define _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
|
||||||
|
#endif // !(__has_feature(cxx_defaulted_functions))
|
||||||
|
|
||||||
#if !(__has_feature(cxx_deleted_functions))
|
#if !(__has_feature(cxx_deleted_functions))
|
||||||
#define _LIBCPP_HAS_NO_DELETED_FUNCTIONS
|
#define _LIBCPP_HAS_NO_DELETED_FUNCTIONS
|
||||||
@ -422,6 +424,12 @@ template <unsigned> struct __static_assert_check {};
|
|||||||
#define _LIBCPP_CONSTEXPR constexpr
|
#define _LIBCPP_CONSTEXPR constexpr
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
|
||||||
|
#define _LIBCPP_DEFAULT {}
|
||||||
|
#else
|
||||||
|
#define _LIBCPP_DEFAULT = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#define _NOALIAS __attribute__((__malloc__))
|
#define _NOALIAS __attribute__((__malloc__))
|
||||||
#else
|
#else
|
||||||
|
@ -622,7 +622,12 @@ struct __atomic_base // false
|
|||||||
{return __c11_atomic_compare_exchange_strong(&__a_, &__e, __d, __m, __m);}
|
{return __c11_atomic_compare_exchange_strong(&__a_, &__e, __d, __m, __m);}
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
__atomic_base() _NOEXCEPT {} // = default;
|
#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
|
||||||
|
__atomic_base() _NOEXCEPT = default;
|
||||||
|
#else
|
||||||
|
__atomic_base() _NOEXCEPT : __a_() {}
|
||||||
|
#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
_LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __a_(__d) {}
|
_LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __a_(__d) {}
|
||||||
#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
|
#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
|
||||||
@ -645,7 +650,7 @@ struct __atomic_base<_Tp, true>
|
|||||||
{
|
{
|
||||||
typedef __atomic_base<_Tp, false> __base;
|
typedef __atomic_base<_Tp, false> __base;
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
__atomic_base() _NOEXCEPT {} // = default;
|
__atomic_base() _NOEXCEPT _LIBCPP_DEFAULT
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
_LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __base(__d) {}
|
_LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __base(__d) {}
|
||||||
|
|
||||||
@ -726,7 +731,7 @@ struct atomic
|
|||||||
{
|
{
|
||||||
typedef __atomic_base<_Tp> __base;
|
typedef __atomic_base<_Tp> __base;
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
atomic() _NOEXCEPT {} // = default;
|
atomic() _NOEXCEPT _LIBCPP_DEFAULT
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
_LIBCPP_CONSTEXPR atomic(_Tp __d) _NOEXCEPT : __base(__d) {}
|
_LIBCPP_CONSTEXPR atomic(_Tp __d) _NOEXCEPT : __base(__d) {}
|
||||||
|
|
||||||
@ -746,7 +751,7 @@ struct atomic<_Tp*>
|
|||||||
{
|
{
|
||||||
typedef __atomic_base<_Tp*> __base;
|
typedef __atomic_base<_Tp*> __base;
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
atomic() _NOEXCEPT {} // = default;
|
atomic() _NOEXCEPT _LIBCPP_DEFAULT
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
_LIBCPP_CONSTEXPR atomic(_Tp* __d) _NOEXCEPT : __base(__d) {}
|
_LIBCPP_CONSTEXPR atomic(_Tp* __d) _NOEXCEPT : __base(__d) {}
|
||||||
|
|
||||||
@ -1367,7 +1372,12 @@ typedef struct atomic_flag
|
|||||||
{__c11_atomic_store(&__a_, false, __m);}
|
{__c11_atomic_store(&__a_, false, __m);}
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
atomic_flag() _NOEXCEPT {} // = default;
|
#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
|
||||||
|
atomic_flag() _NOEXCEPT = default;
|
||||||
|
#else
|
||||||
|
atomic_flag() _NOEXCEPT : __a_() {}
|
||||||
|
#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
atomic_flag(bool __b) _NOEXCEPT : __a_(__b) {}
|
atomic_flag(bool __b) _NOEXCEPT : __a_(__b) {}
|
||||||
|
|
||||||
|
@ -14,9 +14,18 @@
|
|||||||
// atomic_flag() = default;
|
// atomic_flag() = default;
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <new>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
std::atomic_flag f;
|
std::atomic_flag f;
|
||||||
|
|
||||||
|
{
|
||||||
|
typedef std::atomic_flag A;
|
||||||
|
_ALIGNAS_TYPE(A) char storage[sizeof(A)] = {1};
|
||||||
|
A& zero = *new (storage) A();
|
||||||
|
assert(!zero.test_and_set());
|
||||||
|
zero.~A();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <new>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
@ -112,6 +113,13 @@ do_test()
|
|||||||
assert(obj == T(5*sizeof(X)));
|
assert(obj == T(5*sizeof(X)));
|
||||||
assert((obj -= std::ptrdiff_t(3)) == T(2*sizeof(X)));
|
assert((obj -= std::ptrdiff_t(3)) == T(2*sizeof(X)));
|
||||||
assert(obj == T(2*sizeof(X)));
|
assert(obj == T(2*sizeof(X)));
|
||||||
|
|
||||||
|
{
|
||||||
|
_ALIGNAS_TYPE(A) char storage[sizeof(A)] = {23};
|
||||||
|
A& zero = *new (storage) A();
|
||||||
|
assert(zero == 0);
|
||||||
|
zero.~A();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class A, class T>
|
template <class A, class T>
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
// typedef atomic<bool> atomic_bool;
|
// typedef atomic<bool> atomic_bool;
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <new>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@ -219,4 +220,11 @@ int main()
|
|||||||
assert((obj = true) == true);
|
assert((obj = true) == true);
|
||||||
assert(obj == true);
|
assert(obj == true);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
typedef std::atomic<bool> A;
|
||||||
|
_ALIGNAS_TYPE(A) char storage[sizeof(A)] = {1};
|
||||||
|
A& zero = *new (storage) A();
|
||||||
|
assert(zero == false);
|
||||||
|
zero.~A();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,7 @@
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <new>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
template <class A, class T>
|
template <class A, class T>
|
||||||
@ -143,6 +144,13 @@ do_test()
|
|||||||
assert(obj == T(7));
|
assert(obj == T(7));
|
||||||
assert((obj ^= T(0xF)) == T(8));
|
assert((obj ^= T(0xF)) == T(8));
|
||||||
assert(obj == T(8));
|
assert(obj == T(8));
|
||||||
|
|
||||||
|
{
|
||||||
|
_ALIGNAS_TYPE(A) char storage[sizeof(A)] = {23};
|
||||||
|
A& zero = *new (storage) A();
|
||||||
|
assert(zero == 0);
|
||||||
|
zero.~A();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class A, class T>
|
template <class A, class T>
|
||||||
|
@ -24,10 +24,10 @@ void
|
|||||||
test()
|
test()
|
||||||
{
|
{
|
||||||
typedef std::atomic<T> A;
|
typedef std::atomic<T> A;
|
||||||
const A ct;
|
A t;
|
||||||
bool b1 = std::atomic_is_lock_free(&ct);
|
bool b1 = std::atomic_is_lock_free(static_cast<const A*>(&t));
|
||||||
const volatile A cvt;
|
volatile A vt;
|
||||||
bool b2 = std::atomic_is_lock_free(&cvt);
|
bool b2 = std::atomic_is_lock_free(static_cast<const volatile A*>(&vt));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct A
|
struct A
|
||||||
|
Loading…
x
Reference in New Issue
Block a user