https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118960
Bug ID: 118960 Summary: Define std::mutex unconditionally Product: gcc Version: 15.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: redi at gcc dot gnu.org Target Milestone: --- We have a few cases of code like this in src/c++20/format.cc #ifndef _GLIBCXX_HAS_GTHREADS // Dummy mutex struct mutex { void lock() const { } void unlock() const { } }; #endif This is actually incorrect, as it means we'll use a dummy mutex on a target that supports parallelism but doesn't support all the gthreads features needed for full C++11 support (e.g. nvptx). It should be something like: #ifndef __GTHREADS // Dummy mutex struct mutex { void lock() const { } void unlock() const { } }; #elif ! defined _GLIBCXX_HAS_GTHREADS // Use __gnu_cxx::__mutex if std::mutex isn't available. using mutex = __gnu_cxx::__mutex; #endif But a better solution would be to just make <bits/std_mutex.h> define std::mutex unconditionally (at least for C++11 and later). std::mutex doesn't actually need any of the features included in the __GTHREAD_CXX0X set, only the basic ones from the __GTHREADS API. This means we can define a fully functional std::mutex for any target that defines __GTHREADS (including nvptx) and we can define a dummy no-op std::mutex otherwise: --- a/libstdc++-v3/include/bits/std_mutex.h +++ b/libstdc++-v3/include/bits/std_mutex.h @@ -54,7 +54,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @{ */ -#ifdef _GLIBCXX_HAS_GTHREADS +#ifdef __GTHREADS // std::mutex only needs __GTHREADS, not __GTHREADS_CXX0X /// @cond undocumented // Common base class for std::mutex and std::timed_mutex @@ -138,7 +138,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION native_handle() noexcept { return &_M_mutex; } }; +#else // ! __GTHREADS + // No-op mutex type for single-threaded targets. + struct mutex + { + constexpr mutex() noexcept { } + mutex(const mutex&) = delete; + mutex& operator=(const mutex&) = delete; + void lock() { } + void unlock() { } + bool try_lock() noexcept { return true; } + }; +#endif // __GTHREADS +#ifdef _GLIBCXX_HAS_GTHREADS /// @cond undocumented // Implementation details for std::condition_variable By providing the dummy std:::mutex here, we don't need to keep redefining equivalents in src/c++20/format.cc and src/c++20/tzdb.cc and elsewhere. The downside of this is that it would break any user code which provides its own polyfill mutex defined in namespace std. Such code is not allowed and so undefined, but it's the kind of thing people do, e.g. namespace std { using mutex = ::acme::alternative_mutex; } So we could do: +#elif ! defined _GLIBCXX_NO_SINGLE_THREADED_MUTEX + // No-op mutex type for single-threaded targets. + struct mutex So that the library can rely on that being defined for src/c++20/format.cc etc. but user code can suppress that definition if it's not wanted.