Implement `testing::Rethrow` to throw exceptions more easily via `std::exception_ptr`

We avoid overloading or specializing `testing::Throw` as this is fundamentally a different operation than throwing the object.
However, we disable the corresponding overload of `testing::Throw` to prevent likely mistakes in the usage.

Fixes: #4412
PiperOrigin-RevId: 585745469
Change-Id: I03bb585427ce51983d914e88f2bf65a13545c920
diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h
index f20258b..fab9993 100644
--- a/googlemock/include/gmock/gmock-actions.h
+++ b/googlemock/include/gmock/gmock-actions.h
@@ -135,6 +135,7 @@
 #endif
 
 #include <algorithm>
+#include <exception>
 #include <functional>
 #include <memory>
 #include <string>
@@ -1746,6 +1747,13 @@
     return [copy](Args...) -> R { throw copy; };
   }
 };
+struct RethrowAction {
+  std::exception_ptr exception;
+  template <typename R, typename... Args>
+  operator Action<R(Args...)>() const {  // NOLINT
+    return [ex = exception](Args...) -> R { std::rethrow_exception(ex); };
+  }
+};
 #endif  // GTEST_HAS_EXCEPTIONS
 
 }  // namespace internal
@@ -2062,13 +2070,23 @@
   return {pointer};
 }
 
-// Action Throw(exception) can be used in a mock function of any type
-// to throw the given exception.  Any copyable value can be thrown.
 #if GTEST_HAS_EXCEPTIONS
+// Action Throw(exception) can be used in a mock function of any type
+// to throw the given exception.  Any copyable value can be thrown,
+// except for std::exception_ptr, which is likely a mistake if
+// thrown directly.
 template <typename T>
-internal::ThrowAction<typename std::decay<T>::type> Throw(T&& exception) {
+typename std::enable_if<
+    !std::is_base_of<std::exception_ptr, typename std::decay<T>::type>::value,
+    internal::ThrowAction<typename std::decay<T>::type>>::type
+Throw(T&& exception) {
   return {std::forward<T>(exception)};
 }
+// Action Rethrow(exception_ptr) can be used in a mock function of any type
+// to rethrow any exception_ptr. Note that the same object is thrown each time.
+inline internal::RethrowAction Rethrow(std::exception_ptr exception) {
+  return {std::move(exception)};
+}
 #endif  // GTEST_HAS_EXCEPTIONS
 
 namespace internal {
diff --git a/googlemock/test/gmock_link_test.h b/googlemock/test/gmock_link_test.h
index db11c2d..cf0a985 100644
--- a/googlemock/test/gmock_link_test.h
+++ b/googlemock/test/gmock_link_test.h
@@ -187,6 +187,7 @@
 
 #if GTEST_HAS_EXCEPTIONS
 using testing::Throw;
+using testing::Rethrow;
 #endif
 
 using testing::ContainsRegex;
@@ -416,6 +417,14 @@
   EXPECT_CALL(mock, VoidFromString(_)).WillOnce(Throw(42));
   EXPECT_THROW(mock.VoidFromString(nullptr), int);
 }
+// Tests the linkage of the Rethrow action.
+TEST(LinkTest, TestRethrow) {
+  Mock mock;
+
+  EXPECT_CALL(mock, VoidFromString(_))
+      .WillOnce(Rethrow(std::make_exception_ptr(42)));
+  EXPECT_THROW(mock.VoidFromString(nullptr), int);
+}
 #endif  // GTEST_HAS_EXCEPTIONS
 
 // The ACTION*() macros trigger warning C4100 (unreferenced formal