Reactor: Work around new MSVC brokenness. Complex SFINAE expressions appear to be broken on the latest release of MSVC 2017. MSVC++ 14.15 (Visual Studio 2017 version 15.8): The parent change compiles fine. MSVC++ 14.16 (Visual Studio 2017 version 15.9): `error C2039: 'type': is not a member of 'std'` for some CToReactorPtr specializations that use `std::enable_if`. Replacing these `typename std::enable_if<T>::type` with `enable_if_t<T>` works around the issue (while also making the template expressions easier to read). I was unable to find an existing MSVC bug report for this problem, and so I will create one. Bug: swiftshader:141 Change-Id: I7e953dbc719d7cb656aa7f16656c3f86ffad5522 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38688 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: Alexis Hétu <sugoi@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com> Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Reactor/Traits.hpp b/src/Reactor/Traits.hpp index 722b9a4..ccef628 100644 --- a/src/Reactor/Traits.hpp +++ b/src/Reactor/Traits.hpp
@@ -43,6 +43,12 @@ template<class T> class LValue; template<class T> class RValue; + // enabled_if_t is identical to C++14's std::enable_if_t. + // std::enable_if_t was introduced in C++14, but Reactor must support + // C++11. + template<bool Condition, class TrueType = void> + using enable_if_t = typename std::enable_if<Condition, TrueType>::type; + // IsDefined<T>::value is true if T is a valid type, otherwise false. template <typename T, typename Enable = void> struct IsDefined @@ -51,7 +57,7 @@ }; template <typename T> - struct IsDefined<T, typename std::enable_if<(sizeof(T)>0)>::type> + struct IsDefined<T, enable_if_t<(sizeof(T)>0)> > { static constexpr bool value = true; }; @@ -81,6 +87,11 @@ // TODO: Long has no constructor that takes a uint64_t template<> struct CToReactor<uint64_t> { using type = Long; /* static Long cast(uint64_t); */ }; + // HasReactorType<T>::value resolves to true iff there exists a + // CToReactorT specialization for type T. + template<typename T> + using HasReactorType = IsDefined< CToReactorT<T> >; + // CToReactorPtr<T>::type resolves to the corresponding Reactor Pointer<> // type for T*. // For T types that have a CToReactorT<> specialization, @@ -94,7 +105,7 @@ // CToReactorPtr specialization for T types that have a CToReactorT<> // specialization. - template<typename T> struct CToReactorPtr<T, typename std::enable_if< IsDefined< CToReactorT<T> >::value>::type > + template<typename T> struct CToReactorPtr<T, enable_if_t< HasReactorType<T>::value > > { using type = Pointer< CToReactorT<T> >; static inline type cast(const T* v); // implemented in Traits.inl @@ -112,7 +123,7 @@ // Maps to Pointer<Byte>. // Drops the 'const' qualifier from the cast() method to avoid warnings // about const having no meaning for function types. - template<typename T> struct CToReactorPtr<T, typename std::enable_if< std::is_function<T>::value >::type > + template<typename T> struct CToReactorPtr<T, enable_if_t< std::is_function<T>::value > > { using type = Pointer<Byte>; static inline type cast(T* v); // implemented in Traits.inl @@ -125,7 +136,7 @@ // CToReactorT<T*>::type resolves to Pointer< CToReactorT<T> >, otherwise // CToReactorT<T*>::type resolves to Pointer<Byte>. template<typename T> - struct CToReactor<T, typename std::enable_if<std::is_pointer<T>::value>::type> + struct CToReactor<T, enable_if_t<std::is_pointer<T>::value> > { using elem = typename std::remove_pointer<T>::type; using type = CToReactorPtrT<elem>; @@ -134,7 +145,7 @@ // CToReactor specialization for enum types. template<typename T> - struct CToReactor<T, typename std::enable_if<std::is_enum<T>::value>::type> + struct CToReactor<T, enable_if_t<std::is_enum<T>::value> > { using underlying = typename std::underlying_type<T>::type; using type = CToReactorT<underlying>; @@ -143,35 +154,35 @@ // IsRValue::value is true if T is of type RValue<X>, where X is any type. template <typename T, typename Enable = void> struct IsRValue { static constexpr bool value = false; }; - template <typename T> struct IsRValue<T, typename std::enable_if<IsDefined<typename T::rvalue_underlying_type>::value>::type> { static constexpr bool value = true; }; + template <typename T> struct IsRValue<T, enable_if_t<IsDefined<typename T::rvalue_underlying_type>::value> > { static constexpr bool value = true; }; // IsLValue::value is true if T is of, or derives from type LValue<T>. template <typename T> struct IsLValue { static constexpr bool value = std::is_base_of<LValue<T>, T>::value; }; // IsReference::value is true if T is of type Reference<X>, where X is any type. template <typename T, typename Enable = void> struct IsReference { static constexpr bool value = false; }; - template <typename T> struct IsReference<T, typename std::enable_if<IsDefined<typename T::reference_underlying_type>::value>::type> { static constexpr bool value = true; }; + template <typename T> struct IsReference<T, enable_if_t<IsDefined<typename T::reference_underlying_type>::value> > { static constexpr bool value = true; }; // ReactorTypeT<T> returns the LValue Reactor type for T. // T can be a C-type, RValue or LValue. template<typename T, typename ENABLE = void> struct ReactorType; template<typename T> using ReactorTypeT = typename ReactorType<T>::type; - template<typename T> struct ReactorType<T, typename std::enable_if<IsDefined<CToReactorT<T>>::value>::type> + template<typename T> struct ReactorType<T, enable_if_t<IsDefined<CToReactorT<T>>::value> > { using type = CToReactorT<T>; static type cast(T v) { return CToReactor<T>::cast(v); } }; - template<typename T> struct ReactorType<T, typename std::enable_if<IsRValue<T>::value>::type> + template<typename T> struct ReactorType<T, enable_if_t<IsRValue<T>::value> > { using type = typename T::rvalue_underlying_type; static type cast(T v) { return type(v); } }; - template<typename T> struct ReactorType<T, typename std::enable_if<IsLValue<T>::value>::type> + template<typename T> struct ReactorType<T, enable_if_t<IsLValue<T>::value> > { using type = T; static type cast(T v) { return type(v); } }; - template<typename T> struct ReactorType<T, typename std::enable_if<IsReference<T>::value>::type> + template<typename T> struct ReactorType<T, enable_if_t<IsReference<T>::value> > { using type = T; static type cast(T v) { return type(v); }
diff --git a/src/Reactor/Traits.inl b/src/Reactor/Traits.inl index fd40f5b..2e10568 100644 --- a/src/Reactor/Traits.inl +++ b/src/Reactor/Traits.inl
@@ -29,7 +29,7 @@ // specialization. template<typename T> Pointer<CToReactorT<T>> - CToReactorPtr<T, typename std::enable_if< IsDefined< CToReactorT<T> >::value>::type >::cast(const T* v) + CToReactorPtr<T, enable_if_t< HasReactorType<T>::value > >::cast(const T* v) { return type(v); } @@ -43,7 +43,7 @@ // CToReactorPtrT specialization for function pointer types. template<typename T> Pointer<Byte> - CToReactorPtr<T, typename std::enable_if< std::is_function<T>::value >::type>::cast(T* v) + CToReactorPtr<T, enable_if_t< std::is_function<T>::value > >::cast(T* v) { return ConstantPointer(v); } @@ -51,7 +51,7 @@ // CToReactor specialization for pointer types. template<typename T> CToReactorPtrT<typename std::remove_pointer<T>::type> - CToReactor<T, typename std::enable_if<std::is_pointer<T>::value>::type>::cast(T v) + CToReactor<T, enable_if_t<std::is_pointer<T>::value> >::cast(T v) { return CToReactorPtr<elem>::cast(v); } @@ -59,7 +59,7 @@ // CToReactor specialization for enum types. template<typename T> CToReactorT<typename std::underlying_type<T>::type> - CToReactor<T, typename std::enable_if<std::is_enum<T>::value>::type>::cast(T v) + CToReactor<T, enable_if_t<std::is_enum<T>::value> >::cast(T v) { return CToReactor<underlying>::cast(v); }