diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 5cfa0b71c..7407e119e 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -284,6 +284,44 @@ #define GMOCK_MAYBE_5046_ #endif +#if GTEST_HAS_RTTI +namespace proto2 { +namespace internal { + +// A type trait to essentially determine if `DynamicCastMessage` is available, +// since older versions of protobuf don't have this function. +template +static constexpr bool kHasDynamicCastMessage = false; +template +static constexpr bool kHasDynamicCastMessage< + T, std::void_t( + std::declval()))>> = true; + +// A helper function to call `DynamicCastMessage` if available, otherwise +// falling back to `dynamic_cast`. Note that we must declare this function in +// the `proto2` namespace because we need ADL to find the right +// `DynamicCastMessage`, and ADL only applies to unqualified function calls. +template +const T* DynamicCastMessageForGtest(const proto2::MessageLite* msg) { + if constexpr (kHasDynamicCastMessage) { + return DynamicCastMessage(msg); + } else { + return dynamic_cast(msg); + } +} +template +T* DynamicCastMessageForGtest(proto2::MessageLite* msg) { + if constexpr (kHasDynamicCastMessage) { + return DynamicCastMessage(msg); + } else { + return dynamic_cast(msg); + } +} + +} // namespace internal +} // namespace proto2 +#endif // GTEST_HAS_RTTI + GTEST_DISABLE_MSC_WARNINGS_PUSH_( 4251 GMOCK_MAYBE_5046_ /* class A needs to have dll-interface to be used by clients of class B */ @@ -2060,15 +2098,6 @@ class [[nodiscard]] PointerMatcher { }; #if GTEST_HAS_RTTI -// A type trait to essentially determine if `DynamicCastMessage` is available, -// since older versions of protobuf don't have this function. -template -static constexpr bool kHasDynamicCastMessage = false; -template -static constexpr bool kHasDynamicCastMessage< - T, std::void_t( - std::declval()))>> = true; - // Implements the WhenDynamicCastTo(m) matcher that matches a pointer or // reference that matches inner_matcher when dynamic_cast is applied. // The result of dynamic_cast is forwarded to the inner matcher. @@ -2101,13 +2130,12 @@ class [[nodiscard]] WhenDynamicCastToMatcherBase { using ToType = std::remove_const_t>>; - if constexpr (std::is_base_of_v && - kHasDynamicCastMessage) { - if constexpr (std::is_pointer_v) { - return proto2::DynamicCastMessage(from); + if constexpr (std::is_base_of_v) { + if constexpr (std::is_pointer_v) { + return proto2::internal::DynamicCastMessageForGtest(from); } else { // We don't want an std::bad_cast here, so do the cast with pointers. - return proto2::DynamicCastMessage(&from); + return proto2::internal::DynamicCastMessageForGtest(&from); } } else if constexpr (std::is_pointer_v) { return dynamic_cast(from);