Skip to content

Commit 221b2a0

Browse files
Change how we decide which empty string implementation to use. (#20708)
The feature macro seems to be lying on some toolchains. Instead, ask the compiler to try to run the default constructor in constexpr context which should fail if the implementation doesn't actually support it and fallback to the dynamic one. This should fix #20645 PiperOrigin-RevId: 737603382 Co-authored-by: Protobuf Team Bot <[email protected]>
1 parent a4beda2 commit 221b2a0

File tree

2 files changed

+17
-11
lines changed

2 files changed

+17
-11
lines changed

src/google/protobuf/port.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,9 @@ void RealDebugCounter::Register(absl::string_view name) {
9797
}
9898
}
9999

100-
#if defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L
101-
PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT const GlobalEmptyString
102-
fixed_address_empty_string{};
103-
#else
104100
PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
105101
PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 GlobalEmptyString
106102
fixed_address_empty_string{};
107-
#endif
108103

109104
} // namespace internal
110105
} // namespace protobuf

src/google/protobuf/port.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -494,20 +494,27 @@ class NoopDebugCounter {
494494
// Default empty string object. Don't use this directly. Instead, call
495495
// GetEmptyString() to get the reference. This empty string is aligned with a
496496
// minimum alignment of 8 bytes to match the requirement of ArenaStringPtr.
497-
#if defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L
497+
498498
// Take advantage of C++20 constexpr support in std::string.
499-
class alignas(8) GlobalEmptyString {
499+
class alignas(8) GlobalEmptyStringConstexpr {
500500
public:
501501
const std::string& get() const { return value_; }
502502
// Nothing to init, or destroy.
503503
std::string* Init() const { return nullptr; }
504504

505+
template <typename T = std::string, bool = (T(), true)>
506+
static constexpr std::true_type HasConstexprDefaultConstructor(int) {
507+
return {};
508+
}
509+
static constexpr std::false_type HasConstexprDefaultConstructor(char) {
510+
return {};
511+
}
512+
505513
private:
506514
std::string value_;
507515
};
508-
PROTOBUF_EXPORT extern const GlobalEmptyString fixed_address_empty_string;
509-
#else
510-
class alignas(8) GlobalEmptyString {
516+
517+
class alignas(8) GlobalEmptyStringDynamicInit {
511518
public:
512519
const std::string& get() const {
513520
return *reinterpret_cast<const std::string*>(internal::Launder(buffer_));
@@ -519,8 +526,12 @@ class alignas(8) GlobalEmptyString {
519526
private:
520527
alignas(std::string) char buffer_[sizeof(std::string)];
521528
};
529+
530+
using GlobalEmptyString = std::conditional_t<
531+
GlobalEmptyStringConstexpr::HasConstexprDefaultConstructor(0),
532+
const GlobalEmptyStringConstexpr, GlobalEmptyStringDynamicInit>;
533+
522534
PROTOBUF_EXPORT extern GlobalEmptyString fixed_address_empty_string;
523-
#endif
524535

525536
} // namespace internal
526537
} // namespace protobuf

0 commit comments

Comments
 (0)