diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index fbc841c88ba..656cc96ef29 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,10 @@ +2012-02-03 Benjamin Kosnik + + PR libstdc++/51811 + * include/bits/atomic_base.h (atomic<_Tp*>): Fix offsets. + * testsuite/29_atomics/atomic/operators/51811.cc: New. + * testsuite/29_atomics/atomic/operators/pointer_partial_void.cc: New. + 2012-02-03 Jakub Jelinek * config/abi/post/i386-linux-gnu/baseline_symbols.txt: Update. diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h index aa43bccd1bf..9d5f4eb6ff0 100644 --- a/libstdc++-v3/include/bits/atomic_base.h +++ b/libstdc++-v3/include/bits/atomic_base.h @@ -1,6 +1,6 @@ // -*- C++ -*- header. -// Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -621,6 +621,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __pointer_type _M_p; + // Factored out to facilitate explicit specialization. + constexpr ptrdiff_t + _M_type_size(ptrdiff_t __d) { return __d * sizeof(_PTp); } + + constexpr ptrdiff_t + _M_type_size(ptrdiff_t __d) volatile { return __d * sizeof(_PTp); } + public: __atomic_base() noexcept = default; ~__atomic_base() noexcept = default; @@ -669,43 +676,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __pointer_type operator++() noexcept - { return __atomic_add_fetch(&_M_p, 1, memory_order_seq_cst); } + { return __atomic_add_fetch(&_M_p, _M_type_size(1), + memory_order_seq_cst); } __pointer_type operator++() volatile noexcept - { return __atomic_add_fetch(&_M_p, 1, memory_order_seq_cst); } + { return __atomic_add_fetch(&_M_p, _M_type_size(1), + memory_order_seq_cst); } __pointer_type operator--() noexcept - { return __atomic_sub_fetch(&_M_p, 1, memory_order_seq_cst); } + { return __atomic_sub_fetch(&_M_p, _M_type_size(1), + memory_order_seq_cst); } __pointer_type operator--() volatile noexcept - { return __atomic_sub_fetch(&_M_p, 1, memory_order_seq_cst); } + { return __atomic_sub_fetch(&_M_p, _M_type_size(1), + memory_order_seq_cst); } __pointer_type operator+=(ptrdiff_t __d) noexcept - { return __atomic_add_fetch(&_M_p, __d, memory_order_seq_cst); } + { return __atomic_add_fetch(&_M_p, _M_type_size(__d), + memory_order_seq_cst); } __pointer_type operator+=(ptrdiff_t __d) volatile noexcept - { return __atomic_add_fetch(&_M_p, __d, memory_order_seq_cst); } + { return __atomic_add_fetch(&_M_p, _M_type_size(__d), + memory_order_seq_cst); } __pointer_type operator-=(ptrdiff_t __d) noexcept - { return __atomic_sub_fetch(&_M_p, __d, memory_order_seq_cst); } + { return __atomic_sub_fetch(&_M_p, _M_type_size(__d), + memory_order_seq_cst); } __pointer_type operator-=(ptrdiff_t __d) volatile noexcept - { return __atomic_sub_fetch(&_M_p, __d, memory_order_seq_cst); } + { return __atomic_sub_fetch(&_M_p, _M_type_size(__d), + memory_order_seq_cst); } bool is_lock_free() const noexcept - { return __atomic_is_lock_free (sizeof (_M_p), &_M_p); } + { return __atomic_is_lock_free(_M_type_size(1), &_M_p); } bool is_lock_free() const volatile noexcept - { return __atomic_is_lock_free (sizeof (_M_p), &_M_p); } + { return __atomic_is_lock_free(_M_type_size(1), &_M_p); } void store(__pointer_type __p, @@ -789,22 +804,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __pointer_type fetch_add(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) noexcept - { return __atomic_fetch_add(&_M_p, __d, __m); } + { return __atomic_fetch_add(&_M_p, _M_type_size(__d), __m); } __pointer_type fetch_add(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) volatile noexcept - { return __atomic_fetch_add(&_M_p, __d, __m); } + { return __atomic_fetch_add(&_M_p, _M_type_size(__d), __m); } __pointer_type fetch_sub(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) noexcept - { return __atomic_fetch_sub(&_M_p, __d, __m); } + { return __atomic_fetch_sub(&_M_p, _M_type_size(__d), __m); } __pointer_type fetch_sub(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) volatile noexcept - { return __atomic_fetch_sub(&_M_p, __d, __m); } + { return __atomic_fetch_sub(&_M_p, _M_type_size(__d), __m); } }; // @} group atomics diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/operators/51811.cc b/libstdc++-v3/testsuite/29_atomics/atomic/operators/51811.cc new file mode 100644 index 00000000000..7c234f2ff02 --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic/operators/51811.cc @@ -0,0 +1,90 @@ +// { dg-options "-std=gnu++0x" } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include //std::abs +#include + +// libstdc++/51811 +// pointer arithimetic vs. atomic<_Tp*> specialization +int main(void) +{ + bool test __attribute__((unused)) = true; + + using namespace std; + + typedef int value_type; + const size_t n = 2; + value_type value = 42; + atomic p, p2, p3; + + // operator++ + { + p = &value; + p2 = p++; + VERIFY (p != p2); + + value_type* vp(p); + value_type* vp2(p2); + ptrdiff_t dist = reinterpret_cast(vp) - reinterpret_cast(vp2); + VERIFY ( std::abs(dist) == sizeof(value_type)); + + p = &value; + p3 = ++p; + VERIFY (p == p3); + } + + // operator-- + { + p = &value; + p2 = p--; + VERIFY (p != p2); + + value_type* vp(p); + value_type* vp2(p2); + ptrdiff_t dist = reinterpret_cast(vp) - reinterpret_cast(vp2); + VERIFY ( std::abs(dist) == sizeof(value_type)); + + p = &value; + p3 = --p; + VERIFY (p == p3); + } + + // operator+= + { + p = &value; + value_type* vp(p); + p+=n; + value_type* vp2(p); + ptrdiff_t dist = reinterpret_cast(vp) - reinterpret_cast(vp2); + VERIFY ( std::abs(dist) == sizeof(value_type) * n); + } + + // operator-= + { + p = &value; + value_type* vp(p); + p-=n; + value_type* vp2(p); + ptrdiff_t dist = reinterpret_cast(vp) - reinterpret_cast(vp2); + VERIFY ( std::abs(dist) == sizeof(value_type) * n); + } + + return 0; +} diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc b/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc new file mode 100644 index 00000000000..09a4d44db8e --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc @@ -0,0 +1,70 @@ +// { dg-options "-std=gnu++0x" } + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include //std::abs +#include + +// pointer arithimetic vs. atomic. +// atomic vs. explicitly specialized w/o operators, like atomic_bool? +int main(void) +{ + // bool test __attribute__((unused)) = true; + + using namespace std; + + typedef int value_type; + const size_t n = 2; + value_type value = 42; + value_type* p = &value; + void* vp = p; + ptrdiff_t dist(0); + + atomic a(vp); + + // operator++ + void* vp2(a); + a++; + void* vp3(a); + dist = reinterpret_cast(vp2) - reinterpret_cast(vp3); + // VERIFY ( std::abs(dist) == sizeof(void*)); + + // operator-- + void* vp4(a); + a--; + void* vp5(a); + dist = reinterpret_cast(vp4) - reinterpret_cast(vp5); + // VERIFY ( std::abs(dist) == sizeof(void*)); + + // operator+= + void* vp6(a); + a+=n; + void* vp7(a); + dist = reinterpret_cast(vp6) - reinterpret_cast(vp7); + // VERIFY ( std::abs(dist) == sizeof(void*) * n); + + // operator-= + void* vp8(a); + a-=n; + void* vp9(a); + dist = reinterpret_cast(vp8) - reinterpret_cast(vp9); + //VERIFY ( std::abs(dist) == sizeof(void*) * n); + + return 0; +}