diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 02ef3b30..8ef69c43 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -58,6 +58,7 @@ #include #include #include +#include #include #include "gtest/gtest-message.h" @@ -108,16 +109,29 @@ GTEST_API_ extern const char kStackTraceMarker[]; // An IgnoredValue object can be implicitly constructed from ANY value. class IgnoredValue { + struct Sink {}; public: // This constructor template allows any value to be implicitly // converted to IgnoredValue. The object has no data member and // doesn't try to remember anything about the argument. We // deliberately omit the 'explicit' keyword in order to allow the // conversion to be implicit. - template + // Disable the conversion if T already has a magical conversion operator. + // Otherwise we get ambiguity. + template ::value, + int>::type = 0> IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit) }; +// The only type that should be convertible to Secret* is nullptr. +// The other null pointer constants are not of a type that is convertible to +// Secret*. Only the literal with the right value is. +template +using TypeIsValidNullptrConstant = std::integral_constant< + bool, std::is_same::type, std::nullptr_t>::value || + !std::is_convertible::value>; + // Two overloaded helpers for checking at compile time whether an // expression is a null pointer literal (i.e. NULL or any 0-valued // compile-time integral constant). These helpers have no @@ -130,13 +144,16 @@ class IgnoredValue { // a null pointer literal. Therefore, we know that x is a null // pointer literal if and only if the first version is picked by the // compiler. -std::true_type IsNullLiteralHelper(Secret*); -std::false_type IsNullLiteralHelper(IgnoredValue); +std::true_type IsNullLiteralHelper(Secret*, std::true_type); +std::false_type IsNullLiteralHelper(IgnoredValue, std::false_type); +std::false_type IsNullLiteralHelper(IgnoredValue, std::true_type); // A compile-time bool constant that is true if and only if x is a null pointer // literal (i.e. nullptr, NULL or any 0-valued compile-time integral constant). -#define GTEST_IS_NULL_LITERAL_(x) \ - decltype(::testing::internal::IsNullLiteralHelper(x))::value +#define GTEST_IS_NULL_LITERAL_(x) \ + decltype(::testing::internal::IsNullLiteralHelper( \ + x, \ + ::testing::internal::TypeIsValidNullptrConstant()))::value // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ std::string AppendUserMessage( diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index 5e0e43a4..147f0f5c 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -519,9 +519,9 @@ TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsEpochStart) { // Tests that GTEST_IS_NULL_LITERAL_(x) is true when x is a null // pointer literal. TEST(NullLiteralTest, IsTrueForNullLiterals) { - EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(nullptr)); - EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(nullptr)); - EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(nullptr)); + EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(NULL)); // NOLINT + EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0)); // NOLINT + EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0u)); // NOLINT EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(nullptr)); } @@ -534,6 +534,26 @@ TEST(NullLiteralTest, IsFalseForNonNullLiterals) { EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(static_cast(nullptr))); } +struct ConvertToAll { + template + operator T() const { // NOLINT + return T(); + } +}; + +struct ConvertToAllButNoPointers { + template ::value, int>::type = 0> + operator T() const { // NOLINT + return T(); + } +}; + +TEST(NullLiteralTest, ImplicitConversion) { + EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(ConvertToAll{})); + EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(ConvertToAllButNoPointers{})); +} + # ifdef __BORLANDC__ // Restores warnings after previous "#pragma option push" suppressed them. # pragma option pop