Commit 663dcefa by Ben Clayton

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: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarAntonio Maiorano <amaiorano@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent ad1f264a
...@@ -43,6 +43,12 @@ namespace rr ...@@ -43,6 +43,12 @@ namespace rr
template<class T> class LValue; template<class T> class LValue;
template<class T> class RValue; 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. // IsDefined<T>::value is true if T is a valid type, otherwise false.
template <typename T, typename Enable = void> template <typename T, typename Enable = void>
struct IsDefined struct IsDefined
...@@ -51,7 +57,7 @@ namespace rr ...@@ -51,7 +57,7 @@ namespace rr
}; };
template <typename T> 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; static constexpr bool value = true;
}; };
...@@ -81,6 +87,11 @@ namespace rr ...@@ -81,6 +87,11 @@ namespace rr
// TODO: Long has no constructor that takes a uint64_t // TODO: Long has no constructor that takes a uint64_t
template<> struct CToReactor<uint64_t> { using type = Long; /* static Long cast(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<> // CToReactorPtr<T>::type resolves to the corresponding Reactor Pointer<>
// type for T*. // type for T*.
// For T types that have a CToReactorT<> specialization, // For T types that have a CToReactorT<> specialization,
...@@ -94,7 +105,7 @@ namespace rr ...@@ -94,7 +105,7 @@ namespace rr
// CToReactorPtr specialization for T types that have a CToReactorT<> // CToReactorPtr specialization for T types that have a CToReactorT<>
// specialization. // 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> >; using type = Pointer< CToReactorT<T> >;
static inline type cast(const T* v); // implemented in Traits.inl static inline type cast(const T* v); // implemented in Traits.inl
...@@ -112,7 +123,7 @@ namespace rr ...@@ -112,7 +123,7 @@ namespace rr
// Maps to Pointer<Byte>. // Maps to Pointer<Byte>.
// Drops the 'const' qualifier from the cast() method to avoid warnings // Drops the 'const' qualifier from the cast() method to avoid warnings
// about const having no meaning for function types. // 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>; using type = Pointer<Byte>;
static inline type cast(T* v); // implemented in Traits.inl static inline type cast(T* v); // implemented in Traits.inl
...@@ -125,7 +136,7 @@ namespace rr ...@@ -125,7 +136,7 @@ namespace rr
// CToReactorT<T*>::type resolves to Pointer< CToReactorT<T> >, otherwise // CToReactorT<T*>::type resolves to Pointer< CToReactorT<T> >, otherwise
// CToReactorT<T*>::type resolves to Pointer<Byte>. // CToReactorT<T*>::type resolves to Pointer<Byte>.
template<typename T> 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 elem = typename std::remove_pointer<T>::type;
using type = CToReactorPtrT<elem>; using type = CToReactorPtrT<elem>;
...@@ -134,7 +145,7 @@ namespace rr ...@@ -134,7 +145,7 @@ namespace rr
// CToReactor specialization for enum types. // CToReactor specialization for enum types.
template<typename T> 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 underlying = typename std::underlying_type<T>::type;
using type = CToReactorT<underlying>; using type = CToReactorT<underlying>;
...@@ -143,35 +154,35 @@ namespace rr ...@@ -143,35 +154,35 @@ namespace rr
// IsRValue::value is true if T is of type RValue<X>, where X is any type. // 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, 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>. // 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; }; 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. // 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, 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. // ReactorTypeT<T> returns the LValue Reactor type for T.
// T can be a C-type, RValue or LValue. // T can be a C-type, RValue or LValue.
template<typename T, typename ENABLE = void> struct ReactorType; template<typename T, typename ENABLE = void> struct ReactorType;
template<typename T> using ReactorTypeT = typename ReactorType<T>::type; 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>; using type = CToReactorT<T>;
static type cast(T v) { return CToReactor<T>::cast(v); } 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; using type = typename T::rvalue_underlying_type;
static type cast(T v) { return type(v); } 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; using type = T;
static type cast(T v) { return type(v); } 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; using type = T;
static type cast(T v) { return type(v); } static type cast(T v) { return type(v); }
......
...@@ -29,7 +29,7 @@ namespace rr ...@@ -29,7 +29,7 @@ namespace rr
// specialization. // specialization.
template<typename T> template<typename T>
Pointer<CToReactorT<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); return type(v);
} }
...@@ -43,7 +43,7 @@ namespace rr ...@@ -43,7 +43,7 @@ namespace rr
// CToReactorPtrT specialization for function pointer types. // CToReactorPtrT specialization for function pointer types.
template<typename T> template<typename T>
Pointer<Byte> 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); return ConstantPointer(v);
} }
...@@ -51,7 +51,7 @@ namespace rr ...@@ -51,7 +51,7 @@ namespace rr
// CToReactor specialization for pointer types. // CToReactor specialization for pointer types.
template<typename T> template<typename T>
CToReactorPtrT<typename std::remove_pointer<T>::type> 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); return CToReactorPtr<elem>::cast(v);
} }
...@@ -59,7 +59,7 @@ namespace rr ...@@ -59,7 +59,7 @@ namespace rr
// CToReactor specialization for enum types. // CToReactor specialization for enum types.
template<typename T> template<typename T>
CToReactorT<typename std::underlying_type<T>::type> 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); return CToReactor<underlying>::cast(v);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment