Add traits for Reactor arguments and return types

Provides a number of template trait types for Reactor primitive types:

CToReactorT<T> transforms the C-type (T) into a suitable Reactor equivalent. Pointer types are now generalized, allowing for translations of T** types.

IsRValue<T>::value and IsLValue<T>::value are true iff T is of the respective Reactor type.

ReactorType<T> resolves to the corresponding LValue Reactor type for T, where T can be a C-type, RValue or LValue.

ValueOf<T> returns a rr::Value* for a C-value, RValue or LValue. This is now used by a single definition of Return(), fixing bad type coercion which in turn produced illegal LLVM IR.

CanBeUsedAsReturn<T>::value is true iff T can be used as a function return type.
CanBeUsedAsParameter<T>::value is true iff T can be used as a function parameter type.
Function signatures are now statically checked that all parameter types and the return type are valid, providing a human readable error message if an invalid type is used (verified on gcc, clang and msvc).

Added a whole bunch of static asserts in ReactorUnitTests.cpp to sanity check the templates.

Bug: b/131914569
Change-Id: I3267354d6a3f68545079365a657757969ec0047d
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/30455
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Reactor/Reactor.cpp b/src/Reactor/Reactor.cpp
index f079f32..56ab1da 100644
--- a/src/Reactor/Reactor.cpp
+++ b/src/Reactor/Reactor.cpp
@@ -4200,13 +4200,6 @@
 		Nucleus::setInsertBlock(Nucleus::createBasicBlock());
 	}
 
-	void Return(RValue<Int> ret)
-	{
-		Nucleus::createRet(ret.value);
-		// Place any unreachable instructions in an unreferenced block.
-		Nucleus::setInsertBlock(Nucleus::createBasicBlock());
-	}
-
 	void branch(RValue<Bool> cmp, BasicBlock *bodyBB, BasicBlock *endBB)
 	{
 		Nucleus::createCondBr(cmp.value, bodyBB, endBB);
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index 82fa23a..d201904 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -17,6 +17,7 @@
 
 #include "Nucleus.hpp"
 #include "Routine.hpp"
+#include "Traits.hpp"
 
 #include <cassert>
 #include <cstddef>
@@ -230,6 +231,8 @@
 	class RValue
 	{
 	public:
+		using rvalue_underlying_type = T;
+
 		explicit RValue(Value *rvalue);
 
 #ifdef ENABLE_RR_DEBUG_INFO
@@ -2399,14 +2402,23 @@
 
 	void branch(RValue<Bool> cmp, BasicBlock *bodyBB, BasicBlock *endBB);
 
+	// ValueOf returns a rr::Value* for the given C-type, RValue<T>, or LValue<T>.
+	template <typename T>
+	inline Value* ValueOf(const T &v)
+	{
+		return ReactorType<T>(v).loadValue();
+	}
+
 	void Return();
-	void Return(RValue<Int> ret);
 
 	template<class T>
-	void Return(const Pointer<T> &ret);
-
-	template<class T>
-	void Return(RValue<Pointer<T>> ret);
+	void Return(const T &ret)
+	{
+		static_assert(CanBeUsedAsReturn< ReactorType<T> >::value, "Unsupported type for Return()");
+		Nucleus::createRet(ValueOf<T>(ret));
+		// Place any unreachable instructions in an unreferenced block.
+		Nucleus::setInsertBlock(Nucleus::createBasicBlock());
+	}
 
 	// Generic template, leave undefined!
 	template<typename FunctionType>
@@ -2416,6 +2428,9 @@
 	template<typename Return, typename... Arguments>
 	class Function<Return(Arguments...)>
 	{
+		// Static assert that the function signature is valid.
+		static_assert(sizeof(AssertFunctionSignatureIsValid<Return(Arguments...)>) >= 0, "Invalid function signature");
+
 	public:
 		Function();
 
@@ -2968,24 +2983,6 @@
 		return RValue<T>(Nucleus::createSelect(condition.value, trueValue, falseValue));
 	}
 
-	template<class T>
-	void Return(const Pointer<T> &ret)
-	{
-		RR_DEBUG_INFO_UPDATE_LOC();
-		Nucleus::createRet(Nucleus::createLoad(ret.address, Pointer<T>::getType()));
-		// Place any unreachable instructions in an unreferenced block.
-		Nucleus::setInsertBlock(Nucleus::createBasicBlock());
-	}
-
-	template<class T>
-	void Return(RValue<Pointer<T>> ret)
-	{
-		RR_DEBUG_INFO_UPDATE_LOC();
-		Nucleus::createRet(ret.value);
-		// Place any unreachable instructions in an unreferenced block.
-		Nucleus::setInsertBlock(Nucleus::createBasicBlock());
-	}
-
 	template<typename Return, typename... Arguments>
 	Function<Return(Arguments...)>::Function()
 	{
@@ -3069,26 +3066,6 @@
 		return ReinterpretCast<T>(val);
 	}
 
-	template <typename T>
-	inline Value* valueOf(RValue<T> v) { return v.value; }
-
-	template <typename T>
-	inline Value* valueOf(LValue<T> v) { return valueOf(RValue<T>(v.loadValue())); }
-
-	template<typename T>
-	struct CToReactor;
-
-	template<> struct CToReactor<void>         { using type = Void; };
-	template<> struct CToReactor<int>          { using type = Int; };
-	template<> struct CToReactor<unsigned int> { using type = UInt; };
-	template<> struct CToReactor<float>        { using type = Float; };
-	template<> struct CToReactor<int*>         { using type = Pointer<Int>; };
-	template<> struct CToReactor<float*>       { using type = Pointer<Float>; };
-
-	// Pointers to non-reactor types are treated as uint8_t*.
-	template<typename T>
-	struct CToReactor<T*> { using type = Pointer<Byte>; };
-
 	// Returns a reactor pointer to the fixed-address ptr.
 	RValue<Pointer<Byte>> ConstantPointer(void const * ptr);
 
@@ -3104,24 +3081,24 @@
 	class CallHelper<Return(Arguments...)>
 	{
 	public:
-		using RReturn = typename CToReactor<Return>::type;
+		using RReturn = CToReactor<Return>;
 
-		static inline RReturn Call(Return(fptr)(Arguments...), typename CToReactor<Arguments>::type... args)
+		static inline RReturn Call(Return(fptr)(Arguments...), CToReactor<Arguments>... args)
 		{
 			return RValue<RReturn>(rr::Call(
 				ConstantPointer(reinterpret_cast<void*>(fptr)),
 				RReturn::getType(),
-				{ valueOf(args) ... },
-				{ CToReactor<Arguments>::type::getType() ... }));
+				{ ValueOf(args) ... },
+				{ CToReactor<Arguments>::getType() ... }));
 		}
 
-		static inline RReturn Call(Pointer<Byte> fptr, typename CToReactor<Arguments>::type... args)
+		static inline RReturn Call(Pointer<Byte> fptr, CToReactor<Arguments>... args)
 		{
 			return RValue<RReturn>(rr::Call(
 				fptr,
 				RReturn::getType(),
-				{ valueOf(args) ... },
-				{ CToReactor<Arguments>::type::getType() ... }));
+				{ ValueOf(args) ... },
+				{ CToReactor<Arguments>::getType() ... }));
 		}
 	};
 
@@ -3129,26 +3106,26 @@
 	class CallHelper<void(Arguments...)>
 	{
 	public:
-		static inline void Call(void(fptr)(Arguments...), typename CToReactor<Arguments>::type... args)
+		static inline void Call(void(fptr)(Arguments...), CToReactor<Arguments>... args)
 		{
 			rr::Call(ConstantPointer(reinterpret_cast<void*>(fptr)),
 				Void::getType(),
-				{ valueOf(args) ... },
-				{ CToReactor<Arguments>::type::getType() ... });
+				{ ValueOf(args) ... },
+				{ CToReactor<Arguments>::getType() ... });
 		}
 
-		static inline void Call(Pointer<Byte> fptr, typename CToReactor<Arguments>::type... args)
+		static inline void Call(Pointer<Byte> fptr, CToReactor<Arguments>... args)
 		{
 			rr::Call(fptr,
 				Void::getType(),
-				{ valueOf(args) ... },
-				{ CToReactor<Arguments>::type::getType() ... });
+				{ ValueOf(args) ... },
+				{ CToReactor<Arguments>::getType() ... });
 		}
 	};
 
 	// Calls the function pointer fptr with the given arguments args.
 	template<typename Return, typename ... Arguments>
-	inline typename CToReactor<Return>::type Call(Return(fptr)(Arguments...), typename CToReactor<Arguments>::type... args)
+	inline CToReactor<Return> Call(Return(fptr)(Arguments...), CToReactor<Arguments>... args)
 	{
 		return CallHelper<Return(Arguments...)>::Call(fptr, args...);
 	}
diff --git a/src/Reactor/ReactorUnitTests.cpp b/src/Reactor/ReactorUnitTests.cpp
index b52b722..81c3700 100644
--- a/src/Reactor/ReactorUnitTests.cpp
+++ b/src/Reactor/ReactorUnitTests.cpp
@@ -1374,3 +1374,149 @@
 	::testing::InitGoogleTest(&argc, argv);
 	return RUN_ALL_TESTS();
 }
+
+////////////////////////////////
+// Trait compile time checks. //
+////////////////////////////////
+
+// Assert CToReactor resolves to expected types.
+static_assert(std::is_same<CToReactor<void>,     Void>::value, "");
+static_assert(std::is_same<CToReactor<bool>,     Bool>::value, "");
+static_assert(std::is_same<CToReactor<uint8_t>,  Byte>::value, "");
+static_assert(std::is_same<CToReactor<int8_t>,   SByte>::value, "");
+static_assert(std::is_same<CToReactor<int16_t>,  Short>::value, "");
+static_assert(std::is_same<CToReactor<uint16_t>, UShort>::value, "");
+static_assert(std::is_same<CToReactor<int32_t>,  Int>::value, "");
+static_assert(std::is_same<CToReactor<uint64_t>, Long>::value, "");
+static_assert(std::is_same<CToReactor<uint32_t>, UInt>::value, "");
+static_assert(std::is_same<CToReactor<float>,    Float>::value, "");
+
+// Assert CToReactor for known pointer types resolves to expected types.
+static_assert(std::is_same<CToReactor<void*>,     Pointer<Byte>>::value, "");
+static_assert(std::is_same<CToReactor<bool*>,     Pointer<Bool>>::value, "");
+static_assert(std::is_same<CToReactor<uint8_t*>,  Pointer<Byte>>::value, "");
+static_assert(std::is_same<CToReactor<int8_t*>,   Pointer<SByte>>::value, "");
+static_assert(std::is_same<CToReactor<int16_t*>,  Pointer<Short>>::value, "");
+static_assert(std::is_same<CToReactor<uint16_t*>, Pointer<UShort>>::value, "");
+static_assert(std::is_same<CToReactor<int32_t*>,  Pointer<Int>>::value, "");
+static_assert(std::is_same<CToReactor<uint64_t*>, Pointer<Long>>::value, "");
+static_assert(std::is_same<CToReactor<uint32_t*>, Pointer<UInt>>::value, "");
+static_assert(std::is_same<CToReactor<float*>,    Pointer<Float>>::value, "");
+static_assert(std::is_same<CToReactor<uint16_t**>, Pointer<Pointer<UShort>>>::value, "");
+static_assert(std::is_same<CToReactor<uint16_t***>, Pointer<Pointer<Pointer<UShort>>>>::value, "");
+
+// Assert CToReactor for unknown pointer types resolves to Pointer<Byte>.
+struct S{};
+static_assert(std::is_same<CToReactor<S*>, Pointer<Byte>>::value, "");
+static_assert(std::is_same<CToReactor<S**>, Pointer<Pointer<Byte>>>::value, "");
+static_assert(std::is_same<CToReactor<S***>, Pointer<Pointer<Pointer<Byte>>>>::value, "");
+
+// Assert IsRValue<> resolves true for RValue<> types.
+static_assert(IsRValue<RValue<Void>>::value, "");
+static_assert(IsRValue<RValue<Bool>>::value, "");
+static_assert(IsRValue<RValue<Byte>>::value, "");
+static_assert(IsRValue<RValue<SByte>>::value, "");
+static_assert(IsRValue<RValue<Short>>::value, "");
+static_assert(IsRValue<RValue<UShort>>::value, "");
+static_assert(IsRValue<RValue<Int>>::value, "");
+static_assert(IsRValue<RValue<Long>>::value, "");
+static_assert(IsRValue<RValue<UInt>>::value, "");
+static_assert(IsRValue<RValue<Float>>::value, "");
+
+// Assert IsLValue<> resolves true for LValue types.
+static_assert(IsLValue<Bool>::value, "");
+static_assert(IsLValue<Byte>::value, "");
+static_assert(IsLValue<SByte>::value, "");
+static_assert(IsLValue<Short>::value, "");
+static_assert(IsLValue<UShort>::value, "");
+static_assert(IsLValue<Int>::value, "");
+static_assert(IsLValue<Long>::value, "");
+static_assert(IsLValue<UInt>::value, "");
+static_assert(IsLValue<Float>::value, "");
+
+// Assert IsRValue<> resolves false for LValue types.
+static_assert(!IsRValue<Void>::value, "");
+static_assert(!IsRValue<Bool>::value, "");
+static_assert(!IsRValue<Byte>::value, "");
+static_assert(!IsRValue<SByte>::value, "");
+static_assert(!IsRValue<Short>::value, "");
+static_assert(!IsRValue<UShort>::value, "");
+static_assert(!IsRValue<Int>::value, "");
+static_assert(!IsRValue<Long>::value, "");
+static_assert(!IsRValue<UInt>::value, "");
+static_assert(!IsRValue<Float>::value, "");
+
+// Assert IsRValue<> resolves false for C types.
+static_assert(!IsRValue<void>::value, "");
+static_assert(!IsRValue<bool>::value, "");
+static_assert(!IsRValue<uint8_t>::value, "");
+static_assert(!IsRValue<int8_t>::value, "");
+static_assert(!IsRValue<int16_t>::value, "");
+static_assert(!IsRValue<uint16_t>::value, "");
+static_assert(!IsRValue<int32_t>::value, "");
+static_assert(!IsRValue<uint64_t>::value, "");
+static_assert(!IsRValue<uint32_t>::value, "");
+static_assert(!IsRValue<float>::value, "");
+
+// Assert IsLValue<> resolves false for RValue<> types.
+static_assert(!IsLValue<RValue<Void>>::value, "");
+static_assert(!IsLValue<RValue<Bool>>::value, "");
+static_assert(!IsLValue<RValue<Byte>>::value, "");
+static_assert(!IsLValue<RValue<SByte>>::value, "");
+static_assert(!IsLValue<RValue<Short>>::value, "");
+static_assert(!IsLValue<RValue<UShort>>::value, "");
+static_assert(!IsLValue<RValue<Int>>::value, "");
+static_assert(!IsLValue<RValue<Long>>::value, "");
+static_assert(!IsLValue<RValue<UInt>>::value, "");
+static_assert(!IsLValue<RValue<Float>>::value, "");
+
+// Assert IsLValue<> resolves false for Void type.
+static_assert(!IsLValue<Void>::value, "");
+
+// Assert IsLValue<> resolves false for C types.
+static_assert(!IsLValue<void>::value, "");
+static_assert(!IsLValue<bool>::value, "");
+static_assert(!IsLValue<uint8_t>::value, "");
+static_assert(!IsLValue<int8_t>::value, "");
+static_assert(!IsLValue<int16_t>::value, "");
+static_assert(!IsLValue<uint16_t>::value, "");
+static_assert(!IsLValue<int32_t>::value, "");
+static_assert(!IsLValue<uint64_t>::value, "");
+static_assert(!IsLValue<uint32_t>::value, "");
+static_assert(!IsLValue<float>::value, "");
+
+// Assert IsDefined<> resolves true for RValue<> types.
+static_assert(IsDefined<RValue<Void>>::value, "");
+static_assert(IsDefined<RValue<Bool>>::value, "");
+static_assert(IsDefined<RValue<Byte>>::value, "");
+static_assert(IsDefined<RValue<SByte>>::value, "");
+static_assert(IsDefined<RValue<Short>>::value, "");
+static_assert(IsDefined<RValue<UShort>>::value, "");
+static_assert(IsDefined<RValue<Int>>::value, "");
+static_assert(IsDefined<RValue<Long>>::value, "");
+static_assert(IsDefined<RValue<UInt>>::value, "");
+static_assert(IsDefined<RValue<Float>>::value, "");
+
+// Assert IsDefined<> resolves true for LValue types.
+static_assert(IsDefined<Void>::value, "");
+static_assert(IsDefined<Bool>::value, "");
+static_assert(IsDefined<Byte>::value, "");
+static_assert(IsDefined<SByte>::value, "");
+static_assert(IsDefined<Short>::value, "");
+static_assert(IsDefined<UShort>::value, "");
+static_assert(IsDefined<Int>::value, "");
+static_assert(IsDefined<Long>::value, "");
+static_assert(IsDefined<UInt>::value, "");
+static_assert(IsDefined<Float>::value, "");
+
+// Assert IsDefined<> resolves true for C types.
+static_assert(IsDefined<void>::value, "");
+static_assert(IsDefined<bool>::value, "");
+static_assert(IsDefined<uint8_t>::value, "");
+static_assert(IsDefined<int8_t>::value, "");
+static_assert(IsDefined<int16_t>::value, "");
+static_assert(IsDefined<uint16_t>::value, "");
+static_assert(IsDefined<int32_t>::value, "");
+static_assert(IsDefined<uint64_t>::value, "");
+static_assert(IsDefined<uint32_t>::value, "");
+static_assert(IsDefined<float>::value, "");
diff --git a/src/Reactor/Traits.hpp b/src/Reactor/Traits.hpp
new file mode 100644
index 0000000..ce6ac34
--- /dev/null
+++ b/src/Reactor/Traits.hpp
@@ -0,0 +1,175 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef rr_Traits_hpp
+#define rr_Traits_hpp
+
+#include <stdint.h>
+#include <type_traits>
+
+#ifdef Bool
+#undef Bool // b/127920555
+#endif
+
+namespace rr
+{
+	// Forward declarations
+	class Value;
+
+	class Void;
+	class Bool;
+	class Byte;
+	class SByte;
+	class Short;
+	class UShort;
+	class Int;
+	class UInt;
+	class Long;
+	class Half;
+	class Float;
+
+	template<class T> class Pointer;
+	template<class T> class LValue;
+	template<class T> class RValue;
+
+	// IsDefined<T>::value is true if T is a valid type, otherwise false.
+	template <typename T, typename Enable = void>
+	struct IsDefined
+	{
+		static constexpr bool value = false;
+	};
+
+	template <typename T>
+	struct IsDefined<T, typename std::enable_if<(sizeof(T)>0)>::type>
+	{
+		static constexpr bool value = true;
+	};
+
+	template <>
+	struct IsDefined<void>
+	{
+		static constexpr bool value = true;
+	};
+
+	// CToReactor<T> resolves to the corresponding Reactor type for the given C
+	// template type T.
+	template<typename T, typename ENABLE = void> struct CToReactorT;
+	template<typename T> using CToReactor = typename CToReactorT<T>::type;
+
+	// CToReactorT specializations for POD types.
+	template<> struct CToReactorT<void>    	{ using type = Void; };
+	template<> struct CToReactorT<bool>    	{ using type = Bool; };
+	template<> struct CToReactorT<uint8_t> 	{ using type = Byte; };
+	template<> struct CToReactorT<int8_t>  	{ using type = SByte; };
+	template<> struct CToReactorT<int16_t> 	{ using type = Short; };
+	template<> struct CToReactorT<uint16_t>	{ using type = UShort; };
+	template<> struct CToReactorT<int32_t> 	{ using type = Int; };
+	template<> struct CToReactorT<uint64_t>	{ using type = Long; };
+	template<> struct CToReactorT<uint32_t>	{ using type = UInt; };
+	template<> struct CToReactorT<float>   	{ using type = Float; };
+
+	// CToReactorPtrT<T>::type resolves to the corresponding Reactor Pointer<>
+	// type for T*.
+	// For T types that have a CToReactorT<> specialization,
+	// CToReactorPtrT<T>::type resolves to Pointer< CToReactorT<T> >, otherwise
+	// CToReactorPtrT<T>::type resolves to Pointer<Byte>.
+	template<typename T, typename ENABLE = void> struct CToReactorPtrT { using type = Pointer<Byte>; };
+	template<typename T> using CToReactorPtr = typename CToReactorPtrT<T>::type;
+	template<typename T> struct CToReactorPtrT<T, typename std::enable_if< IsDefined< typename CToReactorT<T>::type >::value>::type >
+	{
+		using type = Pointer< typename CToReactorT<T>::type >;
+	};
+
+	// CToReactorT specialization for pointer types.
+	// For T types that have a CToReactorT<> specialization,
+	// CToReactorT<T*>::type resolves to Pointer< CToReactorT<T> >, otherwise
+	// CToReactorT<T*>::type resolves to Pointer<Byte>.
+	template<typename T>
+	struct CToReactorT<T, typename std::enable_if<std::is_pointer<T>::value>::type>
+	{
+		using elem = typename std::remove_pointer<T>::type;
+		using type = CToReactorPtr<elem>;
+	};
+
+	// CToReactorT specialization for void*.
+	// Maps to Pointer<Byte> instead of Pointer<Void>.
+	template<> struct CToReactorT<void*> { using type = Pointer<Byte>; };
+
+	// CToReactorT specialization for enum types.
+	template<typename T>
+	struct CToReactorT<T, typename std::enable_if<std::is_enum<T>::value>::type>
+	{
+		using underlying = typename std::underlying_type<T>::type;
+		using type = typename CToReactorT<underlying>::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> struct IsRValue<T, typename std::enable_if<IsDefined<typename T::rvalue_underlying_type>::value>::type> { 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; };
+
+	// ReactorType<T> returns the LValue Reactor type for T.
+	// T can be a C-type, RValue or LValue.
+	template<typename T, typename ENABLE = void> struct ReactorTypeT;
+	template<typename T> using ReactorType = typename ReactorTypeT<T>::type;
+	template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsDefined<CToReactor<T>>::value>::type> { using type = CToReactor<T>; };
+	template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsRValue<T>::value>::type> { using type = typename T::rvalue_underlying_type; };
+	template<typename T> struct ReactorTypeT<T, typename std::enable_if<IsLValue<T>::value>::type> { using type = T; };
+
+	// Reactor types that can be used as a return type for a function.
+	template <typename T> struct CanBeUsedAsReturn { static constexpr bool value = false; };
+	template <> struct CanBeUsedAsReturn<Void>     { static constexpr bool value = true; };
+	template <> struct CanBeUsedAsReturn<Int>      { static constexpr bool value = true; };
+	template <> struct CanBeUsedAsReturn<UInt>     { static constexpr bool value = true; };
+	template <> struct CanBeUsedAsReturn<Float>    { static constexpr bool value = true; };
+	template <typename T> struct CanBeUsedAsReturn<Pointer<T>> { static constexpr bool value = true; };
+
+	// Reactor types that can be used as a parameter types for a function.
+	template <typename T> struct CanBeUsedAsParameter { static constexpr bool value = false; };
+	template <> struct CanBeUsedAsParameter<Int>      { static constexpr bool value = true; };
+	template <> struct CanBeUsedAsParameter<UInt>     { static constexpr bool value = true; };
+	template <> struct CanBeUsedAsParameter<Float>    { static constexpr bool value = true; };
+	template <typename T> struct CanBeUsedAsParameter<Pointer<T>> { static constexpr bool value = true; };
+
+	// AssertParameterTypeIsValid statically asserts that all template parameter
+	// types can be used as a Reactor function parameter.
+	template<typename T, typename ... other>
+	struct AssertParameterTypeIsValid : AssertParameterTypeIsValid<other...>
+	{
+		static_assert(CanBeUsedAsParameter<T>::value, "Invalid parameter type");
+	};
+	template<typename T>
+	struct AssertParameterTypeIsValid<T>
+	{
+		static_assert(CanBeUsedAsParameter<T>::value, "Invalid parameter type");
+	};
+
+	// AssertFunctionSignatureIsValid statically asserts that the Reactor
+	// function signature is valid.
+	template<typename Return, typename... Arguments>
+	class AssertFunctionSignatureIsValid;
+	template<typename Return>
+	class AssertFunctionSignatureIsValid<Return(Void)> {};
+	template<typename Return, typename... Arguments>
+	class AssertFunctionSignatureIsValid<Return(Arguments...)>
+	{
+		static_assert(CanBeUsedAsReturn<Return>::value, "Invalid return type");
+		static_assert(sizeof(AssertParameterTypeIsValid<Arguments...>) >= 0, "");
+	};
+
+} // namespace rr
+
+#endif // rr_Traits_hpp