Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
[libcxx] Allow use of <atomic> in C++03. Try 3.
Browse files Browse the repository at this point in the history
Summary:
After putting this question up on cfe-dev I have decided that it would be best to allow the use of `<atomic>` in C++03. Although static initialization is a concern the syntax required to get it is C++11 only. Meaning that C++11 constant static initialization cannot silently break in C++03, it will always cause a syntax error. Furthermore `ATOMIC_VAR_INIT` and `ATOMIC_FLAG_INIT` remain defined in C++03 even though they cannot be used because C++03 usages will cause better error messages.

The main change in this patch is to replace `__has_feature(cxx_atomic)`, which only returns true when C++ >= 11, to `__has_extension(c_atomic)` which returns true whenever clang supports the required atomic builtins.


This patch adds the following macros:
* `_LIBCPP_HAS_C_ATOMIC_IMP`      - Defined on clang versions which provide the C `_Atomic` keyword.
* `_LIBCPP_HAS_GCC_ATOMIC_IMP` - Defined on GCC > 4.7. We must use the fallback atomic implementation.
* `_LIBCPP_HAS_NO_ATOMIC_HEADER` - Defined when it is not safe to include `<atomic>`.

`_LIBCPP_HAS_C_ATOMIC_IMP` and `_LIBCPP_HAS_GCC_ATOMIC_IMP` are mutually exclusive, only one should be defined. If neither is defined then `<atomic>` is not implemented and including `<atomic>` will issue an error.

Reviewers: chandlerc, jroelofs, mclow.lists

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D11555

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@245463 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
EricWF committed Aug 19, 2015
1 parent 8966350 commit 00f4a49
Show file tree
Hide file tree
Showing 37 changed files with 304 additions and 698 deletions.
16 changes: 15 additions & 1 deletion include/__config
Expand Up @@ -37,6 +37,9 @@
#ifndef __has_builtin
#define __has_builtin(__x) 0
#endif
#ifndef __has_extension
#define __has_extension(__x) 0
#endif
#ifndef __has_feature
#define __has_feature(__x) 0
#endif
Expand Down Expand Up @@ -773,4 +776,15 @@ extern "C" void __sanitizer_annotate_contiguous_container(
#define _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS
#endif

#endif // _LIBCPP_CONFIG
#if __has_extension(c_atomic)
#define _LIBCPP_HAS_C_ATOMIC_IMP
#elif _GNUC_VER > 407
#define _LIBCPP_HAS_GCC_ATOMIC_IMP
#endif

#if (!defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_GCC_ATOMIC_IMP)) \
|| defined(_LIBCPP_HAS_NO_THREADS)
#define _LIBCPP_HAS_NO_ATOMIC_HEADER
#endif

#endif // _LIBCPP_CONFIG
21 changes: 7 additions & 14 deletions include/atomic
Expand Up @@ -535,21 +535,20 @@ void atomic_signal_fence(memory_order m) noexcept;

#ifdef _LIBCPP_HAS_NO_THREADS
#error <atomic> is not supported on this single threaded system
#else // !_LIBCPP_HAS_NO_THREADS
#endif
#if !defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_GCC_ATOMIC_IMP)
#error <atomic> is not implemented
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

#if !__has_feature(cxx_atomic) && _GNUC_VER < 407
#error <atomic> is not implemented
#else

typedef enum memory_order
{
memory_order_relaxed, memory_order_consume, memory_order_acquire,
memory_order_release, memory_order_acq_rel, memory_order_seq_cst
} memory_order;

#if _GNUC_VER >= 407
#if defined(_LIBCPP_HAS_GCC_ATOMIC_IMP)
namespace __gcc_atomic {
template <typename _Tp>
struct __gcc_atomic_t {
Expand Down Expand Up @@ -805,7 +804,7 @@ static inline _Tp __c11_atomic_fetch_xor(_Atomic(_Tp)* __a, _Tp __pattern,
return __atomic_fetch_xor(&__a->__a_value, __pattern,
__gcc_atomic::__to_gcc_order(__order));
}
#endif // _GNUC_VER >= 407
#endif // _LIBCPP_HAS_GCC_ATOMIC_IMP

template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
Expand All @@ -825,7 +824,7 @@ struct __atomic_base // false
_LIBCPP_INLINE_VISIBILITY
bool is_lock_free() const volatile _NOEXCEPT
{
#if __has_feature(cxx_atomic)
#if defined(_LIBCPP_HAS_C_ATOMIC_IMP)
return __c11_atomic_is_lock_free(sizeof(_Tp));
#else
return __atomic_is_lock_free(sizeof(_Tp), 0);
Expand Down Expand Up @@ -1779,8 +1778,6 @@ typedef atomic<uintmax_t> atomic_uintmax_t;
#define ATOMIC_FLAG_INIT {false}
#define ATOMIC_VAR_INIT(__v) {__v}

// lock-free property

#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
Expand All @@ -1792,10 +1789,6 @@ typedef atomic<uintmax_t> atomic_uintmax_t;
#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE

#endif // !__has_feature(cxx_atomic)

_LIBCPP_END_NAMESPACE_STD

#endif // !_LIBCPP_HAS_NO_THREADS

#endif // _LIBCPP_ATOMIC
6 changes: 4 additions & 2 deletions include/ios
Expand Up @@ -216,7 +216,7 @@ storage-class-specifier const error_category& iostream_category() noexcept;
#include <__locale>
#include <system_error>

#if __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS)
#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
#include <atomic> // for __xindex_
#endif

Expand Down Expand Up @@ -367,7 +367,9 @@ private:
int* __index_;
size_t __event_size_;
size_t __event_cap_;
#if __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS)
// TODO(EricWF): Enable this for both Clang and GCC. Currently it is only
// enabled with clang.
#if defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS)
static atomic<int> __xindex_;
#else
static int __xindex_;
Expand Down
8 changes: 5 additions & 3 deletions include/memory
Expand Up @@ -612,7 +612,7 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
#include <cassert>
#endif

#if __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS)
#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
# include <atomic>
#endif

Expand Down Expand Up @@ -5381,7 +5381,9 @@ inline _LIBCPP_INLINE_VISIBILITY
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, shared_ptr<_Yp> const& __p);

#if __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS)
// TODO(EricWF): Enable this for both Clang and GCC. Currently it is only
// enabled with clang.
#if defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS)

class _LIBCPP_TYPE_VIS __sp_mut
{
Expand Down Expand Up @@ -5507,7 +5509,7 @@ atomic_compare_exchange_weak_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v
return atomic_compare_exchange_weak(__p, __v, __w);
}

#endif // __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS)
#endif // defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS)

//enum class
struct _LIBCPP_TYPE_VIS pointer_safety
Expand Down
2 changes: 1 addition & 1 deletion src/ios.cpp
Expand Up @@ -152,7 +152,7 @@ ios_base::getloc() const
}

// xalloc
#if __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS)
#if defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS)
atomic<int> ios_base::__xindex_ = ATOMIC_VAR_INIT(0);
#else
int ios_base::__xindex_ = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/memory.cpp
Expand Up @@ -124,7 +124,7 @@ __shared_weak_count::__get_deleter(const type_info&) const _NOEXCEPT

#endif // _LIBCPP_NO_RTTI

#if __has_feature(cxx_atomic) && !defined(_LIBCPP_HAS_NO_THREADS)
#if defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS)

static const std::size_t __sp_mut_count = 16;
static pthread_mutex_t mut_back_imp[__sp_mut_count] =
Expand Down Expand Up @@ -177,7 +177,7 @@ __get_sp_mut(const void* p)
return muts[hash<const void*>()(p) & (__sp_mut_count-1)];
}

#endif // __has_feature(cxx_atomic) && !_LIBCPP_HAS_NO_THREADS
#endif // defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_NO_THREADS)

void
declare_reachable(void*)
Expand Down
4 changes: 2 additions & 2 deletions test/std/atomics/atomics.flag/atomic_flag_clear.pass.cpp
Expand Up @@ -22,13 +22,13 @@
int main()
{
{
std::atomic_flag f = ATOMIC_FLAG_INIT;
std::atomic_flag f(false);
f.test_and_set();
atomic_flag_clear(&f);
assert(f.test_and_set() == 0);
}
{
volatile std::atomic_flag f = ATOMIC_FLAG_INIT;
volatile std::atomic_flag f(false);
f.test_and_set();
atomic_flag_clear(&f);
assert(f.test_and_set() == 0);
Expand Down
Expand Up @@ -22,37 +22,37 @@
int main()
{
{
std::atomic_flag f = ATOMIC_FLAG_INIT;
std::atomic_flag f(false);
f.test_and_set();
atomic_flag_clear_explicit(&f, std::memory_order_relaxed);
assert(f.test_and_set() == 0);
}
{
std::atomic_flag f = ATOMIC_FLAG_INIT;
std::atomic_flag f(false);
f.test_and_set();
atomic_flag_clear_explicit(&f, std::memory_order_release);
assert(f.test_and_set() == 0);
}
{
std::atomic_flag f = ATOMIC_FLAG_INIT;
std::atomic_flag f(false);
f.test_and_set();
atomic_flag_clear_explicit(&f, std::memory_order_seq_cst);
assert(f.test_and_set() == 0);
}
{
volatile std::atomic_flag f = ATOMIC_FLAG_INIT;
volatile std::atomic_flag f(false);
f.test_and_set();
atomic_flag_clear_explicit(&f, std::memory_order_relaxed);
assert(f.test_and_set() == 0);
}
{
volatile std::atomic_flag f = ATOMIC_FLAG_INIT;
volatile std::atomic_flag f(false);
f.test_and_set();
atomic_flag_clear_explicit(&f, std::memory_order_release);
assert(f.test_and_set() == 0);
}
{
volatile std::atomic_flag f = ATOMIC_FLAG_INIT;
volatile std::atomic_flag f(false);
f.test_and_set();
atomic_flag_clear_explicit(&f, std::memory_order_seq_cst);
assert(f.test_and_set() == 0);
Expand Down
16 changes: 8 additions & 8 deletions test/std/atomics/atomics.flag/clear.pass.cpp
Expand Up @@ -22,49 +22,49 @@
int main()
{
{
std::atomic_flag f = ATOMIC_FLAG_INIT;
std::atomic_flag f(false);
f.test_and_set();
f.clear();
assert(f.test_and_set() == 0);
}
{
std::atomic_flag f = ATOMIC_FLAG_INIT;
std::atomic_flag f(false);
f.test_and_set();
f.clear(std::memory_order_relaxed);
assert(f.test_and_set() == 0);
}
{
std::atomic_flag f = ATOMIC_FLAG_INIT;
std::atomic_flag f(false);
f.test_and_set();
f.clear(std::memory_order_release);
assert(f.test_and_set() == 0);
}
{
std::atomic_flag f = ATOMIC_FLAG_INIT;
std::atomic_flag f(false);
f.test_and_set();
f.clear(std::memory_order_seq_cst);
assert(f.test_and_set() == 0);
}
{
volatile std::atomic_flag f = ATOMIC_FLAG_INIT;
volatile std::atomic_flag f(false);
f.test_and_set();
f.clear();
assert(f.test_and_set() == 0);
}
{
volatile std::atomic_flag f = ATOMIC_FLAG_INIT;
volatile std::atomic_flag f(false);
f.test_and_set();
f.clear(std::memory_order_relaxed);
assert(f.test_and_set() == 0);
}
{
volatile std::atomic_flag f = ATOMIC_FLAG_INIT;
volatile std::atomic_flag f(false);
f.test_and_set();
f.clear(std::memory_order_release);
assert(f.test_and_set() == 0);
}
{
volatile std::atomic_flag f = ATOMIC_FLAG_INIT;
volatile std::atomic_flag f(false);
f.test_and_set();
f.clear(std::memory_order_seq_cst);
assert(f.test_and_set() == 0);
Expand Down
1 change: 1 addition & 0 deletions test/std/atomics/atomics.flag/init.pass.cpp
Expand Up @@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads
// XFAIL: c++98, c++03

// <atomic>

Expand Down
25 changes: 25 additions & 0 deletions test/std/atomics/atomics.flag/init03.pass.cpp
@@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: libcpp-has-no-threads

// <atomic>

// struct atomic_flag

// TESTING EXTENSION atomic_flag(bool)

#include <atomic>
#include <cassert>

int main()
{
std::atomic_flag f(false);
assert(f.test_and_set() == 0);
}
Expand Up @@ -24,10 +24,11 @@
#include <type_traits>
#include <cassert>

#include "atomic_helpers.h"

template <class T>
void
test()
{
struct TestFn {
void operator()() const {
{
typedef std::atomic<T> A;
A a;
Expand All @@ -52,37 +53,10 @@ test()
assert(a == T(2));
assert(t == T(2));
}
}

struct A
{
int i;

explicit A(int d = 0) noexcept {i=d;}

friend bool operator==(const A& x, const A& y)
{return x.i == y.i;}
}
};

int main()
{
test<A>();
test<char>();
test<signed char>();
test<unsigned char>();
test<short>();
test<unsigned short>();
test<int>();
test<unsigned int>();
test<long>();
test<unsigned long>();
test<long long>();
test<unsigned long long>();
test<wchar_t>();
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
test<char16_t>();
test<char32_t>();
#endif // _LIBCPP_HAS_NO_UNICODE_CHARS
test<int*>();
test<const int*>();
TestEachAtomicType<TestFn>()();
}

0 comments on commit 00f4a49

Please sign in to comment.