// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #if !defined __GNUC__ // relative include path contains '..', specific to this file #pragma warning( disable: 4464 ) #else #pragma GCC diagnostic ignored "-Wunused-variable" #endif #if !defined __clang__ && defined __GNUC__ && __cplusplus >= 201402L // The gcc compiler isn't smart enough to sort out that the constexpr exception functions // are never hit, so create a null exception handler. Nothing in this file is tested at runtime in any case. class SafeIntGccCompileOnly { public: constexpr static void SafeIntOnOverflow() { } constexpr static void SafeIntOnDivZero() { } }; #define SafeIntDefaultExceptionHandler SafeIntGccCompileOnly #endif #include "../SafeInt.hpp" namespace TestConstExpr { template SAFEINT_CONSTEXPR11 bool LessThanTest() { return (U)2 < SafeInt(3) && SafeInt(4) < (U)5 && SafeInt(6) < SafeInt(7); } template SAFEINT_CONSTEXPR11 bool GreaterThanTest() { return (U)2 > SafeInt(3) && SafeInt(4) > (U)5 && SafeInt(6) > SafeInt(7); } template SAFEINT_CONSTEXPR11 bool LessThanEqualTest() { return (U)2 <= SafeInt(3) && SafeInt(4) <= (U)5 && SafeInt(6) <= SafeInt(7); } template SAFEINT_CONSTEXPR11 bool GreaterThanEqualTest() { return (U)2 >= SafeInt(3) && SafeInt(4) >= (U)5 && SafeInt(6) >= SafeInt(7); } template SAFEINT_CONSTEXPR11 bool EqualTest() { return (U)2 == SafeInt(3) && SafeInt(4) == (U)5 && SafeInt(6) == SafeInt(7) && true == SafeInt(1) && false == SafeInt(0); } template SAFEINT_CONSTEXPR11 bool NotEqualTest() { return (U)2 != SafeInt(3) && SafeInt(4) != (U)5 && SafeInt(6) != SafeInt(7) && true != SafeInt(1) && false != SafeInt(0); } template void ComparisonTestTU() { static bool b1 = LessThanTest(); static bool b2 = LessThanEqualTest(); static bool b3 = GreaterThanTest(); static bool b4 = GreaterThanEqualTest(); static bool b5 = EqualTest(); static bool b6 = NotEqualTest(); } template void ComparisonTestT() { ComparisonTestTU(); ComparisonTestTU(); ComparisonTestTU(); ComparisonTestTU(); ComparisonTestTU(); ComparisonTestTU(); ComparisonTestTU(); ComparisonTestTU(); ComparisonTestTU(); ComparisonTestTU(); ComparisonTestTU(); } template SAFEINT_CONSTEXPR11 T ConstConstructor() { // Constructors, also add in the useless unary + operator return SafeInt() + SafeInt(1) + SafeInt(false) + (+SafeInt(3)); } template SAFEINT_CONSTEXPR11 bool ConstBool() { return (bool)SafeInt(2) && !SafeInt(0); } template void ConstTestT() { static const T t = ConstConstructor(); static const bool b = ConstBool(); } template SAFEINT_CONSTEXPR11 SafeInt ConstSafeInt() { return SafeInt(1); } template void ConstCastTestT() { static const bool b = ConstSafeInt(); static const wchar_t w = ConstSafeInt(); static const char c = ConstSafeInt(); static const signed char sc = ConstSafeInt(); static const unsigned char uc = ConstSafeInt(); static const signed short s = ConstSafeInt(); static const unsigned short us = ConstSafeInt(); static const signed int i = ConstSafeInt(); static const unsigned int ui = ConstSafeInt(); static const signed long l = ConstSafeInt(); static const unsigned long ul = ConstSafeInt(); static const signed long long ll = ConstSafeInt(); static const unsigned long long ull = ConstSafeInt(); static const size_t st = ConstSafeInt(); static const ptrdiff_t pt = ConstSafeInt(); // Also catch the useless unary + operator static const int pl = +ConstSafeInt(); } #if CPLUSPLUS_STD == CPLUSPLUS_14 template SAFEINT_CONSTEXPR14 T DivOperator() { // Have to explicitly force this operator // to be used T lhs = 3; SafeInt s(2); T& r = operator /=(lhs, s); return r; } template SAFEINT_CONSTEXPR14 T AddOperator() { // Have to explicitly force this operator // to be used T lhs = 3; SafeInt s(2); T& r = operator +=(lhs, s); return r; } template SAFEINT_CONSTEXPR14 T SubOperator() { // Have to explicitly force this operator // to be used T lhs = 3; SafeInt s(2); T& r = operator -=(lhs, s); return r; } template SAFEINT_CONSTEXPR14 T LShiftOperator() { // Have to explicitly force this operator // to be used // T& operator <<=(T& lhs, SafeInt< U, E > rhs) T lhs = 3; SafeInt s(2); T& r = operator <<=(lhs, s); return r; } template SAFEINT_CONSTEXPR14 U LShiftOperator2() { // Have to explicitly force this operator // to be used U lhs = 3; SafeInt s(2); SafeInt r = operator <<(lhs, s); return r; } template SAFEINT_CONSTEXPR14 T RShiftOperator() { // Have to explicitly force this operator // to be used T lhs = 3; SafeInt s(1); T& r = operator >>=(lhs, s); return r; } template SAFEINT_CONSTEXPR14 U RShiftOperator2() { // Have to explicitly force this operator // to be used U lhs = 3; SafeInt s(1); SafeInt r = operator >>(lhs, s); return r; } template SAFEINT_CONSTEXPR14 T AndOperator() { // Have to explicitly force this operator // to be used T lhs = 3; SafeInt s(1); T& r = operator &=(lhs, s); return r; } template SAFEINT_CONSTEXPR14 U AndOperator2() { // Have to explicitly force this operator // to be used U lhs = 3; SafeInt s(1); SafeInt r = operator &(lhs, s); return r; } template SAFEINT_CONSTEXPR14 T XorOperator() { // Have to explicitly force this operator // to be used T lhs = 3; SafeInt s(1); T& r = operator ^=(lhs, s); return r; } template SAFEINT_CONSTEXPR14 U XorOperator2() { // Have to explicitly force this operator // to be used U lhs = 3; SafeInt s(1); SafeInt r = operator ^(lhs, s); return r; } template SAFEINT_CONSTEXPR14 T OrOperator() { // Have to explicitly force this operator // to be used T lhs = 3; SafeInt s(1); T& r = operator |=(lhs, s); return r; } template SAFEINT_CONSTEXPR14 U OrOperator2() { // Have to explicitly force this operator // to be used U lhs = 3; SafeInt s(1); SafeInt r = operator |(lhs, s); return r; } template SAFEINT_CONSTEXPR14 bool SafeCastTest() { U to = 0; return SafeCast((T)3, to); } template SAFEINT_CONSTEXPR14 bool SafeModulusTest() { U u = 2; T result = 0; return SafeModulus((T)3, u, result); } template SAFEINT_CONSTEXPR14 bool SafeMultiplyTest() { U u = 2; T result = 0; return SafeMultiply((T)3, u, result); } template SAFEINT_CONSTEXPR14 bool SafeDivideTest() { U u = 2; T result = 0; return SafeDivide((T)3, u, result); } template SAFEINT_CONSTEXPR14 bool SafeAddTest() { U u = 2; T result = 0; return SafeAdd((T)3, u, result); } template void StaticAssertTU() { // Constructors static_assert(SafeInt(SafeInt(1)), "SafeInt U constr"); static_assert(SafeInt((U)1), "U constr"); // Assignment operators static_assert((SafeInt() = (U)1), "Assignment U"); static_assert((SafeInt() = (T)1), "Assignment T"); static_assert((SafeInt() = SafeInt(1)), "Assignment SafeInt U"); // Next one happens when T == U, so already included // static_assert((SafeInt() = SafeInt(1)), "Assignment SafeInt T"); // Test the casting operators static_assert((U)(SafeInt((T)1)), "Casting"); // Modulus static_assert(SafeInt((T)3) % (U)2, "Modulus"); static_assert(SafeInt((T)3) % SafeInt(2), "Modulus"); static_assert((SafeInt((T)3) %= (U)2), "Modulus"); static_assert((SafeInt((T)3) %= SafeInt(2)), "Modulus"); static_assert((U)3 % SafeInt(2), "Modulus"); static_assert((T)3 % SafeInt(2), "Modulus"); // Multiplication // Multiplication must either use intrinsics OR constexpr, but not both because the intrinsics aren't marked constexpr #if !SAFEINT_USE_INTRINSICS static_assert(SafeInt((T)3) * (U)2, "Multiplication"); static_assert(SafeInt((T)3) * SafeInt(2), "Multiplication"); static_assert((SafeInt((T)3) *= (U)2), "Multiplication"); static_assert((SafeInt((T)3) *= SafeInt(2)), "Multiplication"); static_assert((U)3 * SafeInt(2), "Multiplication"); static_assert(((T)3 * SafeInt(2)), "Multiplication"); #endif // Division static_assert(SafeInt((T)3) / (U)2, "Division"); static_assert(SafeInt((T)3) / SafeInt(2), "Division"); static_assert((SafeInt((T)3) /= (U)2), "Division"); #if SAFEINT_COMPILER != GCC_COMPILER // gcc is not happy with this one static_assert((SafeInt((T)3) /= SafeInt(2)), "Division"); static_assert((U)3 / SafeInt(2), "Division"); #endif static_assert(DivOperator(), "Division"); // Addition static_assert(SafeInt((T)3) + (U)2, "Addition"); static_assert(SafeInt((T)3) + SafeInt(2), "Addition"); static_assert((SafeInt((T)3) += (U)2), "Addition"); static_assert((SafeInt((T)3) += SafeInt(2)), "Addition"); static_assert((U)3 + SafeInt(2), "Addition"); static_assert(AddOperator(), "Addition"); // Subtraction static_assert(SafeInt((T)3) - (U)2, "Subtraction"); static_assert(SafeInt((T)3) - SafeInt(2), "Subtraction"); static_assert((SafeInt((T)3) -= (U)2), "Subtraction"); static_assert((SafeInt((T)3) -= SafeInt(2)), "Subtraction"); static_assert((U)3 - SafeInt(2), "Subtraction"); static_assert(SubOperator(), "Subtraction"); // Shift // Left static_assert(SafeInt((T)3) << (U)2, "Shift"); static_assert(SafeInt((T)3) << SafeInt(2), "Shift"); static_assert((SafeInt((T)3) <<= (U)2), "Shift"); static_assert((SafeInt((T)3) <<= SafeInt(2)), "Shift"); static_assert(LShiftOperator(), "Shift"); static_assert(LShiftOperator2(), "Shift"); // Right static_assert(SafeInt((T)3) >> (U)1, "Shift"); static_assert(SafeInt((T)3) >> SafeInt(1), "Shift"); static_assert((SafeInt((T)3) >>= (U)1), "Shift"); static_assert((SafeInt((T)3) >>= SafeInt(1)), "Shift"); static_assert(RShiftOperator(), "Shift"); static_assert(RShiftOperator2(), "Shift"); // Binary And static_assert(SafeInt((T)3) & SafeInt(1), "And"); static_assert(SafeInt((T)3) & (U)1, "And"); static_assert((SafeInt((T)3) &= (U)(1)), "And"); static_assert((SafeInt((T)3) &= SafeInt(1)), "And"); static_assert(AndOperator(), "And"); static_assert(AndOperator2(), "And"); // Binary Xor static_assert(SafeInt((T)3) ^ SafeInt(1), "Xor"); static_assert(SafeInt((T)3) ^ (U)1, "Xor"); static_assert((SafeInt((T)3) ^= (U)(1)), "Xor"); static_assert((SafeInt((T)3) ^= SafeInt(1)), "Xor"); static_assert(XorOperator(), "Xor"); static_assert(XorOperator2(), "Xor"); // Binary Or static_assert(SafeInt((T)3) | SafeInt(1), "Or"); static_assert(SafeInt((T)3) | (U)1, "Or"); static_assert((SafeInt((T)3) |= (U)(1)), "Or"); static_assert((SafeInt((T)3) |= SafeInt(1)), "Or"); static_assert(OrOperator(), "Or"); static_assert(OrOperator2(), "Or"); // Comparisons // Less than static_assert(SafeInt((T)2) < (U)3, "LT"); static_assert((T)2 < SafeInt((U)3), "LT"); static_assert(SafeInt((T)2) < SafeInt((U)3), "LT"); // Less than or equal static_assert(SafeInt((T)2) <= (U)3, "LTE"); static_assert((T)2 <= SafeInt((U)3), "LTE"); static_assert(SafeInt((T)2) <= SafeInt((U)3), "LTE"); // Greater than static_assert(SafeInt((T)4) > (U)3, "GT"); static_assert((T)4 > SafeInt((U)3), "GT"); static_assert(SafeInt((T)4) > SafeInt((U)3), "GT"); // Less than or equal static_assert(SafeInt((T)4) >= (U)3, "GTE"); static_assert((T)4 >= SafeInt((U)3), "GTE"); static_assert((SafeInt((T)4) >= SafeInt((U)3)), "GTE"); // Equals static_assert(SafeInt((T)3) == (U)3, "EQ"); static_assert((T)3 == SafeInt((U)3), "EQ"); static_assert(SafeInt((T)3) == SafeInt((U)3), "EQ"); // Not equal static_assert(SafeInt((T)4) != (U)3, "NEQ"); static_assert((T)4 != SafeInt((U)3), "NEQ"); static_assert(SafeInt((T)4) != SafeInt((U)3), "NEQ"); // Now need coverage for these: static_assert(SafeCastTest(), "SafeCast"); static_assert(SafeEquals((T)2, (U)2), "SafeEquals"); static_assert(SafeNotEquals((T)3, (U)2), "SafeNotEquals"); static_assert(SafeGreaterThan((T)3, (U)2), "SafeGreaterThan"); static_assert(SafeGreaterThanEquals((T)3, (U)2), "SafeGreaterThanEquals"); static_assert(SafeLessThan((T)1, (U)2), "SafeLessThan"); static_assert(SafeLessThanEquals((T)1, (U)2), "SafeLessThanEquals"); static_assert(SafeModulusTest(), "SafeModulus"); #if !SAFEINT_USE_INTRINSICS static_assert(SafeMultiplyTest(), "SafeMultiply"); #endif static_assert(SafeDivideTest(), "SafeDivide"); static_assert(SafeAddTest(), "SafeAdd"); } template void StaticAssertTest() { static_assert(SafeInt() == 0, "Default constr"); static_assert(SafeInt((T)1), "T constr"); static_assert(SafeInt(true), "bool constr"); // Floating point will not work due to presence of fpclassify // static_assert(SafeInt((float)1.0), "float constr"); StaticAssertTU(); StaticAssertTU(); StaticAssertTU(); StaticAssertTU(); StaticAssertTU(); StaticAssertTU(); StaticAssertTU(); StaticAssertTU(); StaticAssertTU(); StaticAssertTU(); StaticAssertTU(); // Special case casting static_assert((bool)(SafeInt((T)1)), "Casting"); static_assert((wchar_t)(SafeInt((T)1)), "Casting"); static_assert((float)(SafeInt((T)1)), "Casting"); static_assert((double)(SafeInt((T)1)), "Casting"); static_assert((long double)(SafeInt((T)1)), "Casting"); // Unary operations static_assert(!SafeInt((T)0), "operator !"); static_assert(++SafeInt((T)1), "operator ++"); static_assert(SafeInt((T)1)++, "operator ++"); static_assert(--SafeInt((T)2), "operator --"); static_assert(SafeInt((T)2)--, "operator --"); static_assert(~SafeInt((T)0), "operator ~"); } template SAFEINT_CONSTEXPR14 T ConstMultiplyTU() { return (SafeInt(2) * (U)1) + (U(4) * SafeInt(3)) + (SafeInt(6) * SafeInt(5)); } template void ConstMultiplyT() { static const T c = ConstMultiplyTU< T, char >(); static const T sc = ConstMultiplyTU< T, signed char >(); static const T uc = ConstMultiplyTU< T, unsigned char >(); static const T ss = ConstMultiplyTU< T, signed short >(); static const T us = ConstMultiplyTU< T, unsigned short >(); static const T si = ConstMultiplyTU< T, signed int >(); static const T ui = ConstMultiplyTU< T, unsigned int >(); static const T sl = ConstMultiplyTU< T, signed long >(); static const T ul = ConstMultiplyTU< T, unsigned long >(); static const T sll = ConstMultiplyTU< T, signed long long >(); static const T ull = ConstMultiplyTU< T, unsigned long long >(); } template SAFEINT_CONSTEXPR14 T ConstSubtractTU() { return (SafeInt(2) - (U)1) + (U(4) - SafeInt(3)) + (SafeInt(6) - SafeInt(5)); } template void ConstSubtractT() { static const T c = ConstSubtractTU< T, char >(); static const T sc = ConstSubtractTU< T, signed char >(); static const T uc = ConstSubtractTU< T, unsigned char >(); static const T ss = ConstSubtractTU< T, signed short >(); static const T us = ConstSubtractTU< T, unsigned short >(); static const T si = ConstSubtractTU< T, signed int >(); static const T ui = ConstSubtractTU< T, unsigned int >(); static const T sl = ConstSubtractTU< T, signed long >(); static const T ul = ConstSubtractTU< T, unsigned long >(); static const T sll = ConstSubtractTU< T, signed long long >(); static const T ull = ConstSubtractTU< T, unsigned long long >(); } template SAFEINT_CONSTEXPR14 T ConstAddTU() { return (SafeInt(1) + (U)2) + (U(3) + SafeInt(4)) + (SafeInt(5) + SafeInt(6)); } template void ConstAddT() { static const T c = ConstAddTU< T, char >(); static const T sc = ConstAddTU< T, signed char >(); static const T uc = ConstAddTU< T, unsigned char >(); static const T ss = ConstAddTU< T, signed short >(); static const T us = ConstAddTU< T, unsigned short >(); static const T si = ConstAddTU< T, signed int >(); static const T ui = ConstAddTU< T, unsigned int >(); static const T sl = ConstAddTU< T, signed long >(); static const T ul = ConstAddTU< T, unsigned long >(); static const T sll = ConstAddTU< T, signed long long >(); static const T ull = ConstAddTU< T, unsigned long long >(); } template SAFEINT_CONSTEXPR14 T PrefixInc(T i) { return ++SafeInt(i); } template SAFEINT_CONSTEXPR14 T PostfixInc(T i) { return SafeInt(i)++; } template SAFEINT_CONSTEXPR14 void SignedOnly() { static_assert(-SafeInt((T)1), "operator -"); } void TestSignedOnly() { SignedOnly(); SignedOnly(); SignedOnly(); SignedOnly(); SignedOnly(); } #endif // CPLUSPLUS_14 template void ConstExprTestT() { ConstTestT(); ComparisonTestT(); ConstCastTestT(); #if CPLUSPLUS_STD == CPLUSPLUS_14 StaticAssertTest(); TestSignedOnly(); ConstAddT(); ConstSubtractT(); ConstMultiplyT(); #endif } void ConstExprTest() { ConstExprTestT(); ConstExprTestT(); ConstExprTestT(); ConstExprTestT(); ConstExprTestT(); ConstExprTestT(); ConstExprTestT(); ConstExprTestT(); ConstExprTestT(); ConstExprTestT(); ConstExprTestT(); // Catch the SafePtrDiff function, since it is marked. Can't think of a scenario for this being constexpr, though. const char* p1 = (char*)1; const char* p2 = nullptr; static const SafeInt pt = SafePtrDiff(p1, p2); if (pt > 0) return; } } void ConstExpr() { TestConstExpr::ConstExprTest(); }