aboutsummaryrefslogtreecommitdiffstats
path: root/googlemock
diff options
context:
space:
mode:
authorvslashg <gfalcon@google.com>2019-10-29 16:51:12 -0400
committervslashg <gfalcon@google.com>2019-10-29 16:51:12 -0400
commitb5fb5ba05cb6144f17be58b9dba8a35ba022876a (patch)
tree20bfbd56efb93852cd5fccc102f6bc7ddaa2f7e5 /googlemock
parenta1f71dd56df487ed755cdf6a6a2908a64207285a (diff)
parent208c2f6b6076c7386faed78ee570cca87c6d3964 (diff)
downloadgoogletest-b5fb5ba05cb6144f17be58b9dba8a35ba022876a.tar.gz
googletest-b5fb5ba05cb6144f17be58b9dba8a35ba022876a.tar.bz2
googletest-b5fb5ba05cb6144f17be58b9dba8a35ba022876a.zip
Merge pull request #2527 from PiotrNycz:gmock_prevent_return_ref_to_store_temporaries_2
PiperOrigin-RevId: 277061341
Diffstat (limited to 'googlemock')
-rw-r--r--googlemock/include/gmock/gmock-actions.h4
-rw-r--r--googlemock/test/gmock-actions_test.cc36
2 files changed, 40 insertions, 0 deletions
diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h
index 91abcd35..2fe7574a 100644
--- a/googlemock/include/gmock/gmock-actions.h
+++ b/googlemock/include/gmock/gmock-actions.h
@@ -1052,6 +1052,10 @@ inline internal::ReturnRefAction<R> ReturnRef(R& x) { // NOLINT
return internal::ReturnRefAction<R>(x);
}
+// Prevent using ReturnRef on reference to temporary.
+template <typename R, R* = nullptr>
+internal::ReturnRefAction<R> ReturnRef(R&&) = delete;
+
// Creates an action that returns the reference to a copy of the
// argument. The copy is created when the action is constructed and
// lives as long as the action.
diff --git a/googlemock/test/gmock-actions_test.cc b/googlemock/test/gmock-actions_test.cc
index dcce111a..ae4fa20e 100644
--- a/googlemock/test/gmock-actions_test.cc
+++ b/googlemock/test/gmock-actions_test.cc
@@ -46,6 +46,7 @@
#include <iterator>
#include <memory>
#include <string>
+#include <type_traits>
#include "gmock/gmock.h"
#include "gmock/internal/gmock-port.h"
#include "gtest/gtest.h"
@@ -647,6 +648,41 @@ TEST(ReturnRefTest, IsCovariant) {
EXPECT_EQ(&derived, &a.Perform(std::make_tuple()));
}
+template <typename T, typename = decltype(ReturnRef(std::declval<T&&>()))>
+bool CanCallReturnRef(T&&) { return true; }
+bool CanCallReturnRef(Unused) { return false; }
+
+// Tests that ReturnRef(v) is working with non-temporaries (T&)
+TEST(ReturnRefTest, WorksForNonTemporary) {
+ int scalar_value = 123;
+ EXPECT_TRUE(CanCallReturnRef(scalar_value));
+
+ std::string non_scalar_value("ABC");
+ EXPECT_TRUE(CanCallReturnRef(non_scalar_value));
+
+ const int const_scalar_value{321};
+ EXPECT_TRUE(CanCallReturnRef(const_scalar_value));
+
+ const std::string const_non_scalar_value("CBA");
+ EXPECT_TRUE(CanCallReturnRef(const_non_scalar_value));
+}
+
+// Tests that ReturnRef(v) is not working with temporaries (T&&)
+TEST(ReturnRefTest, DoesNotWorkForTemporary) {
+ auto scalar_value = []() -> int { return 123; };
+ EXPECT_FALSE(CanCallReturnRef(scalar_value()));
+
+ auto non_scalar_value = []() -> std::string { return "ABC"; };
+ EXPECT_FALSE(CanCallReturnRef(non_scalar_value()));
+
+ // cannot use here callable returning "const scalar type",
+ // because such const for scalar return type is ignored
+ EXPECT_FALSE(CanCallReturnRef(static_cast<const int>(321)));
+
+ auto const_non_scalar_value = []() -> const std::string { return "CBA"; };
+ EXPECT_FALSE(CanCallReturnRef(const_non_scalar_value()));
+}
+
// Tests that ReturnRefOfCopy(v) works for reference types.
TEST(ReturnRefOfCopyTest, WorksForReference) {
int n = 42;