This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: [PATCH] Fix ODR violations in code using <ext/atomicity.h>
- From: Jonathan Wakely <jwakely at redhat dot com>
- To: Nathan Sidwell <nathan at acm dot org>
- Cc: libstdc++ at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Date: Fri, 5 Jul 2019 17:13:25 +0100
- Subject: Re: [PATCH] Fix ODR violations in code using <ext/atomicity.h>
- References: <20190621160152.GN7627@redhat.com> <eae02d9b-e5aa-3198-cb71-6dc8a5de1e04@acm.org> <20190621170816.GO7627@redhat.com> <20190621171304.GP7627@redhat.com>
On 21/06/19 18:13 +0100, Jonathan Wakely wrote:
On 21/06/19 18:08 +0100, Jonathan Wakely wrote:
On 21/06/19 13:01 -0400, Nathan Sidwell wrote:
On 6/21/19 12:01 PM, Jonathan Wakely wrote:
Nathan noticed that the 'static inline' functions in <ext/atomicity.h>
cause ODR violations when used from inline functions or templates (see
[basic.def.odr] p12 bullet (12.2)). His modules branch now diagnoses
those violations, so we need a fix.
Looking at the history (r114044 by Paolo) I believe the idea was indeed
to allow different definitions to be used in different TUs. I think
__attribute__((__always_inline__)) is a better match for that than
'static inline', and doesn't violate the ODR (at least, not if all TUs
have the same values for __GTHREADS and _GLIBCXX_ATOMIC_BUILTINS).
These functions still violate this rule in [dcl.inline]:
C++17: "If a function with external linkage is declared inline in one
translation unit, it shall be declared inline in all translation units
in which it appears; no diagnostic is required."
C++2a WP: "If a function or variable with external or module linkage
is declared inline in one translation unit, there shall be a reachable
inline declaration in all translation units in which it is declared;
no diagnostic is required."
But that doesn't seem to be diagnosable by today's implementations.
Does this change seem reasonable?
yes, thanks!
Actually, I think I prefer this version. This produces identical code
to the always_inline version, but without the indirection to
additional inline functions, i.e. just inline the relevant code into
the _dispatch functions.
Tests are still running but no failures so far, as expected.
Oops, I spoke too soon:
FAIL: tr1/2_general_utilities/shared_ptr/thread/default_weaktoshared.cc (test for excess errors)
UNRESOLVED: tr1/2_general_utilities/shared_ptr/thread/default_weaktoshared.cc compilation failed to produce executable
FAIL: tr1/2_general_utilities/shared_ptr/thread/mutex_weaktoshared.cc (test for excess errors)
UNRESOLVED: tr1/2_general_utilities/shared_ptr/thread/mutex_weaktoshared.cc compilation failed to produce executable
Those tests explicitly use the __atomic_add function that the patch
removes. But those would be easy to adjust.
I decided against the simplification in the second patch, and
committed the attached one which is closer to the first patch I sent
(preserving the __atomic_add and __exchange_and_add functions even
when they just call the built-ins).
Tested x86_64-linux, powerpc64-linux, powerpc-aix. Committed to trunk.
commit 0d26b6506f20dcb1c956338baba0c26f623e25f2
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Fri Jul 5 15:15:46 2019 +0100
Fix ODR violations in code using <ext/atomicity.h>
Because the inline versions of __exchange_and_add and __atomic_add are
also marked static, they cannot be used from templates or other inline
functions without ODR violations. This change gives them external
linkage, but adds the always_inline attribute.
* include/ext/atomicity.h [_GLIBCXX_ATOMIC_BUILTINS] (__atomic_add)
(__exchange_and_add): Replace static specifier with always_inline
attribute.
(__exchange_and_add_single, __atomic_add_single): Likewise.
(__exchange_and_add_dispatch, __atomic_add_dispatch): Likewise. Also
combine !__gthread_active_p() and !__GTHREADS branches.
diff --git a/libstdc++-v3/include/ext/atomicity.h b/libstdc++-v3/include/ext/atomicity.h
index 0783a58e01a..73225b3de20 100644
--- a/libstdc++-v3/include/ext/atomicity.h
+++ b/libstdc++-v3/include/ext/atomicity.h
@@ -44,24 +44,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// __exchange_and_add_dispatch
// __atomic_add_dispatch
#ifdef _GLIBCXX_ATOMIC_BUILTINS
- static inline _Atomic_word
+ inline _Atomic_word
+ __attribute__((__always_inline__))
__exchange_and_add(volatile _Atomic_word* __mem, int __val)
{ return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }
- static inline void
+ inline void
+ __attribute__((__always_inline__))
__atomic_add(volatile _Atomic_word* __mem, int __val)
{ __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }
#else
_Atomic_word
- __attribute__ ((__unused__))
__exchange_and_add(volatile _Atomic_word*, int) throw ();
void
- __attribute__ ((__unused__))
__atomic_add(volatile _Atomic_word*, int) throw ();
#endif
- static inline _Atomic_word
+ inline _Atomic_word
+ __attribute__((__always_inline__))
__exchange_and_add_single(_Atomic_word* __mem, int __val)
{
_Atomic_word __result = *__mem;
@@ -69,36 +70,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __result;
}
- static inline void
+ inline void
+ __attribute__((__always_inline__))
__atomic_add_single(_Atomic_word* __mem, int __val)
{ *__mem += __val; }
- static inline _Atomic_word
- __attribute__ ((__unused__))
+ inline _Atomic_word
+ __attribute__ ((__always_inline__))
__exchange_and_add_dispatch(_Atomic_word* __mem, int __val)
{
#ifdef __GTHREADS
if (__gthread_active_p())
return __exchange_and_add(__mem, __val);
- else
- return __exchange_and_add_single(__mem, __val);
-#else
- return __exchange_and_add_single(__mem, __val);
#endif
+ return __exchange_and_add_single(__mem, __val);
}
- static inline void
- __attribute__ ((__unused__))
+ inline void
+ __attribute__ ((__always_inline__))
__atomic_add_dispatch(_Atomic_word* __mem, int __val)
{
#ifdef __GTHREADS
if (__gthread_active_p())
__atomic_add(__mem, __val);
- else
- __atomic_add_single(__mem, __val);
-#else
- __atomic_add_single(__mem, __val);
#endif
+ __atomic_add_single(__mem, __val);
}
_GLIBCXX_END_NAMESPACE_VERSION