Remove PROTOBUF_MAYBE_CONSTEXPR and make the constructor constexpr even in MSVC
This solves a conflict when using Clang for Windows.
This is just a cherry-pick of the internal change cl/341698875.
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
index 9fbd06a..19be23a 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -329,7 +329,7 @@
// It uses a linker initialized mutex, so it is not compatible with regular
// runtime instances.
// Except in MSVC, where we can't have a constinit mutex.
- explicit PROTOBUF_MAYBE_CONSTEXPR MapFieldBase(ConstantInitialized)
+ explicit constexpr MapFieldBase(ConstantInitialized)
: arena_(nullptr),
repeated_field_(nullptr),
mutex_(GOOGLE_PROTOBUF_LINKER_INITIALIZED),
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index 320e888..01b3ce3 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -148,9 +148,6 @@
#ifdef PROTOBUF_CONSTINIT
#error PROTOBUF_CONSTINIT was previously defined
#endif
-#ifdef PROTOBUF_MAYBE_CONSTEXPR
-#error PROTOBUF_MAYBE_CONSTEXPR was previously defined
-#endif
#ifdef PROTOBUF_ATTRIBUTE_NO_DESTROY
#error PROTOBUF_ATTRIBUTE_NO_DESTROY was previously defined
#endif
@@ -560,15 +557,6 @@
#define PROTOBUF_CONSTINIT
#endif
-// Some constructors can't be constexpr under MSVC, but given that MSVC will not
-// do constant initialization of globals anyway we can omit `constexpr` from
-// them. These constructors are marked with PROTOBUF_MAYBE_CONSTEXPR
-#if defined(_MSC_VER)
-#define PROTOBUF_MAYBE_CONSTEXPR
-#else
-#define PROTOBUF_MAYBE_CONSTEXPR constexpr
-#endif
-
#if _MSC_VER
#define PROTOBUF_DISABLE_MSVC_UNION_WARNING \
__pragma(warning(push)) \
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
index d141428..99c05fb 100644
--- a/src/google/protobuf/port_undef.inc
+++ b/src/google/protobuf/port_undef.inc
@@ -75,7 +75,6 @@
#undef PROTOBUF_DISABLE_MSVC_UNION_WARNING
#undef PROTOBUF_ENABLE_MSVC_UNION_WARNING
#undef PROTOBUF_CONSTINIT
-#undef PROTOBUF_MAYBE_CONSTEXPR
#undef PROTOBUF_ATTRIBUTE_NO_DESTROY
// Restore macro that may have been #undef'd in port_def.inc.
diff --git a/src/google/protobuf/stubs/mutex.h b/src/google/protobuf/stubs/mutex.h
index b222ff7..64c4d6a 100644
--- a/src/google/protobuf/stubs/mutex.h
+++ b/src/google/protobuf/stubs/mutex.h
@@ -90,12 +90,33 @@
#endif
+// In MSVC std::mutex does not have a constexpr constructor.
+// This wrapper makes the constructor constexpr.
+template <typename T>
+class CallOnceInitializedMutex {
+ public:
+ constexpr CallOnceInitializedMutex() : flag_{}, buf_{} {}
+ ~CallOnceInitializedMutex() { get().~T(); }
+
+ void lock() { get().lock(); }
+ void unlock() { get().unlock(); }
+
+ private:
+ T& get() {
+ std::call_once(flag_, [&] { ::new (static_cast<void*>(&buf_)) T(); });
+ return reinterpret_cast<T&>(buf_);
+ }
+
+ std::once_flag flag_;
+ alignas(T) char buf_[sizeof(T)];
+};
+
// Mutex is a natural type to wrap. As both google and other organization have
// specialized mutexes. gRPC also provides an injection mechanism for custom
// mutexes.
class GOOGLE_PROTOBUF_CAPABILITY("mutex") PROTOBUF_EXPORT WrappedMutex {
public:
- WrappedMutex() = default;
+ constexpr WrappedMutex() = default;
void Lock() GOOGLE_PROTOBUF_ACQUIRE() { mu_.lock(); }
void Unlock() GOOGLE_PROTOBUF_RELEASE() { mu_.unlock(); }
// Crash if this Mutex is not held exclusively by this thread.
@@ -103,11 +124,13 @@
void AssertHeld() const {}
private:
-#ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
+#if defined(_MSC_VER)
+ CallOnceInitializedMutex<std::mutex> mu_;
+#elif defined(GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP)
+ CallOnceInitializedMutex<CriticalSectionLock> mu_;
+#else
std::mutex mu_;
-#else // ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
- CriticalSectionLock mu_;
-#endif // #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
+#endif
};
using Mutex = WrappedMutex;