c++/71675 - __atomic_compare_exchange_n returns wrong type for typed enum
__atomic_compare_exchange_n is documented to return bool but when its operands are of one of the character types or derived from it (such as a class enum in C++) it converts the bool result to that type. The attached patch corrects that to prevent this conversion, analogously to what's already being done for __sync_bool_compare_and_swap. Martin
PR c++/71675 - __atomic_compare_exchange_n returns wrong type for typed enum gcc/c-family/ChangeLog: 2016-06-28 Martin Sebor <mse...@redhat.com> PR c++/71675 * c-common.c (resolve_overloaded_builtin): Avoid converting __atomic_compare_exchange_n return type to that of what its first argument points to. gcc/testsuite/ChangeLog: 2016-06-28 Martin Sebor <mse...@redhat.com> PR c++/71675 * g++.dg/ext/atomic-3.C: New test. * gcc.dg/atomic/pr71675.c: New test. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 524fbc5..e4e6d5f 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -11503,7 +11503,8 @@ resolve_overloaded_builtin (location_t loc, tree function, return result; if (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N - && orig_code != BUILT_IN_ATOMIC_STORE_N) + && orig_code != BUILT_IN_ATOMIC_STORE_N + && orig_code != BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N) result = sync_resolve_return (first_param, result, orig_format); if (fetch_op) diff --git a/gcc/testsuite/g++.dg/ext/atomic-3.C b/gcc/testsuite/g++.dg/ext/atomic-3.C new file mode 100644 index 0000000..f9e102e --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/atomic-3.C @@ -0,0 +1,37 @@ +// PR c++/71675 - __atomic_compare_exchange_n returns wrong type for typed enum +// { dg-do compile { target c++11 } } + +template <class T> +void sink (T); + +bool sink (bool); + +template <class T> +bool test () +{ + enum class E: T { }; + static E e; + + return sink (__atomic_compare_exchange_n (&e, &e, e, false, 0, 0)); +} + +void tests () +{ + // __atomic_compare_exchange_n would fail to return bool when + // its arguments were one of the three character types. + 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>(); +} diff --git a/gcc/testsuite/gcc.dg/atomic/pr71675.c b/gcc/testsuite/gcc.dg/atomic/pr71675.c new file mode 100644 index 0000000..0e344ac --- /dev/null +++ b/gcc/testsuite/gcc.dg/atomic/pr71675.c @@ -0,0 +1,32 @@ +/* PR c++/71675 - __atomic_compare_exchange_n returns wrong type for typed enum + */ +/* { dg-do compile { target c11 } } */ + +#define Test(T) \ + do { \ + static T x; \ + int r [_Generic (__atomic_compare_exchange_n (&x, &x, x, 0, 0, 0), \ + _Bool: 1, default: -1)]; \ + (void)&r; \ + } while (0) + +void f (void) +{ + /* __atomic_compare_exchange_n would fail to return _Bool when + its arguments were one of the three character types. */ + Test (char); + Test (signed char); + Test (unsigned char); + + Test (int); + Test (unsigned int); + + Test (long); + Test (unsigned long); + + Test (long long); + Test (unsigned long long); + + typedef enum E { e } E; + Test (E); +}