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);
}