diff options
author | Nico Weber <thakis@chromium.org> | 2017-05-15 21:21:25 (GMT) |
---|---|---|
committer | Nico Weber <thakis@chromium.org> | 2017-05-15 21:21:25 (GMT) |
commit | b2cbbec04c141801dc9f648dc92b26bac5bad0da (patch) | |
tree | ae7c03161abb3cb7c84bee822693a3ebf9ea6c18 /googletest | |
parent | 294f72bc773c92410aa3c5ecdd6cd4a757c3fbf4 (diff) | |
download | googletest-b2cbbec04c141801dc9f648dc92b26bac5bad0da.zip googletest-b2cbbec04c141801dc9f648dc92b26bac5bad0da.tar.gz googletest-b2cbbec04c141801dc9f648dc92b26bac5bad0da.tar.bz2 |
Fix -Wmicrosoft-cast warnings when using gtest with clang on Windows.refs/pull/1091/head
This upstreams a Google-internal change.
Original CL description:
The C++ standard says that function pointers are not implicitly
convertible to object pointers. Visual Studio disregards that and allows
implicit conversion between function pointers and object points, and
enough code relies on this that clang follows suit in
Microsoft-compatibility mode.
However, clang emits a -Wmicrosoft-cast warning when such a conversion
is done:
E:\b\c\b\win_clang\src\sandbox\win\src\sync_dispatcher.cc(42,7):
warning: implicit conversion between pointer-to-function and
pointer-to-object is a Microsoft extension [-Wmicrosoft-cast]
This change fixes this warning in gtest, while hopefully not changing
any behavior. The change does two things:
1. It replaces the if in DefaultPrintTo with SFINAE
2. In C++11 mode, it uses enable_if<is_function<>> instead of
ImplicitlyConvertible<T*, const void*> to check if the
explicit cast is needed.
With this change, functions will use the branch with the reintpret_casts
with Visual Studio and clang/win, and clang no longer needs to warn
that it implicitly converts a function pointer to a void pointer.
Diffstat (limited to 'googletest')
-rw-r--r-- | googletest/include/gtest/gtest-printers.h | 89 |
1 files changed, 51 insertions, 38 deletions
diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index 8a33164..2c36a90 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -364,11 +364,18 @@ class UniversalPrinter; template <typename T> void UniversalPrint(const T& value, ::std::ostream* os); +enum DefaultPrinterType { + kPrintContainer, + kPrintPointer, + kPrintFunctionPointer, + kPrintOther, +}; +template <DefaultPrinterType type> struct WrapPrinterType {}; + // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template <typename C> -void DefaultPrintTo(IsContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType<kPrintContainer> /* dummy */, const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; @@ -401,40 +408,38 @@ void DefaultPrintTo(IsContainer /* dummy */, // implementation-defined. Therefore they will be printed as raw // bytes.) template <typename T> -void DefaultPrintTo(IsNotContainer /* dummy */, - true_type /* is a pointer */, +void DefaultPrintTo(WrapPrinterType<kPrintPointer> /* dummy */, T* p, ::std::ostream* os) { if (p == NULL) { *os << "NULL"; } else { - // C++ doesn't allow casting from a function pointer to any object - // pointer. - // - // IsTrue() silences warnings: "Condition is always true", - // "unreachable code". - if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) { - // T is not a function type. We just call << to print p, - // relying on ADL to pick up user-defined << for their pointer - // types, if any. - *os << p; - } else { - // T is a function type, so '*os << p' doesn't do what we want - // (it just prints p as bool). We want to print p as a const - // void*. However, we cannot cast it to const void* directly, - // even using reinterpret_cast, as earlier versions of gcc - // (e.g. 3.4.5) cannot compile the cast when p is a function - // pointer. Casting to UInt64 first solves the problem. - *os << reinterpret_cast<const void*>( - reinterpret_cast<internal::UInt64>(p)); - } + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } +} +template <typename T> +void DefaultPrintTo(WrapPrinterType<kPrintFunctionPointer> /* dummy */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. However, we cannot cast it to const void* directly, + // even using reinterpret_cast, as earlier versions of gcc + // (e.g. 3.4.5) cannot compile the cast when p is a function + // pointer. Casting to UInt64 first solves the problem. + *os << reinterpret_cast<const void*>( + reinterpret_cast<internal::UInt64>(p)); } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template <typename T> -void DefaultPrintTo(IsNotContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType<kPrintOther> /* dummy */, const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } @@ -452,11 +457,8 @@ void DefaultPrintTo(IsNotContainer /* dummy */, // wants). template <typename T> void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first two - // arguments determine which version will be picked. If T is an - // STL-style container, the version for container will be called; if - // T is a pointer, the pointer version will be called; otherwise the - // generic version will be called. + // DefaultPrintTo() is overloaded. The type of its first argument + // determines which version will be picked. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: @@ -468,13 +470,24 @@ void PrintTo(const T& value, ::std::ostream* os) { // elements; therefore we check for container types here to ensure // that our format is used. // - // The second argument of DefaultPrintTo() is needed to bypass a bug - // in Symbian's C++ compiler that prevents it from picking the right - // overload between: - // - // PrintTo(const T& x, ...); - // PrintTo(T* x, ...); - DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os); + // Note that MSVC and clang-cl do allow an implicit conversion from + // pointer-to-function to pointer-to-object, but clang-cl warns on it. + // So don't use ImplicitlyConvertible if it can be helped since it will + // cause this warning, and use a separate overload of DefaultPrintTo for + // function pointers so that the `*os << p` in the object pointer overload + // doesn't cause that warning either. + DefaultPrintTo( + WrapPrinterType<sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer) + ? kPrintContainer : !is_pointer<T>::value + ? kPrintOther +#if GTEST_LANG_CXX11 + : std::is_function<typename std::remove_pointer<T>::type>::value +#else + : !internal::ImplicitlyConvertible<T, const void*>::value +#endif + ? kPrintFunctionPointer + : kPrintPointer>(), + value, os); } // The following list of PrintTo() overloads tells |