diff --git a/libc/test/src/fenv/enabled_exceptions_test.cpp b/libc/test/src/fenv/enabled_exceptions_test.cpp --- a/libc/test/src/fenv/enabled_exceptions_test.cpp +++ b/libc/test/src/fenv/enabled_exceptions_test.cpp @@ -11,7 +11,7 @@ #include "src/fenv/fetestexcept.h" #include "utils/FPUtil/FEnvUtils.h" -#include "utils/FPUtil/TestHelpers.h" +#include "utils/FPUtil/FPExceptMatcher.h" #include "utils/UnitTest/Test.h" #include diff --git a/libc/test/src/fenv/feholdexcept_test.cpp b/libc/test/src/fenv/feholdexcept_test.cpp --- a/libc/test/src/fenv/feholdexcept_test.cpp +++ b/libc/test/src/fenv/feholdexcept_test.cpp @@ -9,7 +9,7 @@ #include "src/fenv/feholdexcept.h" #include "utils/FPUtil/FEnvUtils.h" -#include "utils/FPUtil/TestHelpers.h" +#include "utils/FPUtil/FPExceptMatcher.h" #include "utils/UnitTest/Test.h" #include diff --git a/libc/utils/FPUtil/CMakeLists.txt b/libc/utils/FPUtil/CMakeLists.txt --- a/libc/utils/FPUtil/CMakeLists.txt +++ b/libc/utils/FPUtil/CMakeLists.txt @@ -36,6 +36,8 @@ add_library( LibcFPTestHelpers + FPExceptMatcher.cpp + FPExceptMatcher.h TestHelpers.cpp TestHelpers.h ) diff --git a/libc/utils/FPUtil/FPExceptMatcher.h b/libc/utils/FPUtil/FPExceptMatcher.h new file mode 100644 --- /dev/null +++ b/libc/utils/FPUtil/FPExceptMatcher.h @@ -0,0 +1,67 @@ +//===-- FPExceptMatcher.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_UTILS_FPUTIL_FP_EXCEPT_MATCHER_H +#define LLVM_LIBC_UTILS_FPUTIL_FP_EXCEPT_MATCHER_H + +#ifndef LLVM_LIBC_TEST_USE_FUCHSIA + +#include "utils/UnitTest/Test.h" + +namespace __llvm_libc { +namespace fputil { +namespace testing { + +// TODO: Make the matcher match specific exceptions instead of just identifying +// that an exception was raised. +class FPExceptMatcher : public __llvm_libc::testing::Matcher { + bool exceptionRaised; + +public: + class FunctionCaller { + public: + virtual ~FunctionCaller(){}; + virtual void call() = 0; + }; + + template static FunctionCaller *getFunctionCaller(Func func) { + struct Callable : public FunctionCaller { + Func f; + explicit Callable(Func theFunc) : f(theFunc) {} + void call() override { f(); } + }; + + return new Callable(func); + } + + // Takes ownership of func. + explicit FPExceptMatcher(FunctionCaller *func); + + bool match(bool unused) { return exceptionRaised; } + + void explainError(testutils::StreamWrapper &stream) override { + stream << "A floating point exception should have been raised but it " + << "wasn't\n"; + } +}; + +} // namespace testing +} // namespace fputil +} // namespace __llvm_libc + +#define ASSERT_RAISES_FP_EXCEPT(func) \ + ASSERT_THAT( \ + true, \ + __llvm_libc::fputil::testing::FPExceptMatcher( \ + __llvm_libc::fputil::testing::FPExceptMatcher::getFunctionCaller( \ + func))) +#else +#define ASSERT_RAISES_FP_EXCEPT(func) ASSERT_DEATH(func, WITH_SIGNAL(SIGFPE)) +#endif // LLVM_LIBC_TEST_USE_FUCHSIA + +#endif // LLVM_LIBC_UTILS_FPUTIL_FP_EXCEPT_MATCHER_H diff --git a/libc/utils/FPUtil/FPExceptMatcher.cpp b/libc/utils/FPUtil/FPExceptMatcher.cpp new file mode 100644 --- /dev/null +++ b/libc/utils/FPUtil/FPExceptMatcher.cpp @@ -0,0 +1,52 @@ +//===-- FPExceptMatchers.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "FPExceptMatcher.h" + +#include +#include +#include +#include + +namespace __llvm_libc { +namespace fputil { +namespace testing { + +#if defined(_WIN32) +#define sigjmp_buf jmp_buf +#define sigsetjmp(buf, save) setjmp(buf) +#define siglongjmp(buf, val) longjmp(buf, val) +#endif + +static thread_local sigjmp_buf jumpBuffer; +static thread_local bool caughtExcept; + +static void sigfpeHandler(int sig) { + caughtExcept = true; + siglongjmp(jumpBuffer, -1); +} + +FPExceptMatcher::FPExceptMatcher(FunctionCaller *func) { + auto oldSIGFPEHandler = signal(SIGFPE, &sigfpeHandler); + std::unique_ptr funcUP(func); + + caughtExcept = false; + fenv_t oldEnv; + fegetenv(&oldEnv); + if (sigsetjmp(jumpBuffer, 1) == 0) + funcUP->call(); + // We restore the previous floating point environment after + // the call to the function which can potentially raise SIGFPE. + fesetenv(&oldEnv); + signal(SIGFPE, oldSIGFPEHandler); + exceptionRaised = caughtExcept; +} + +} // namespace testing +} // namespace fputil +} // namespace __llvm_libc diff --git a/libc/utils/FPUtil/TestHelpers.h b/libc/utils/FPUtil/TestHelpers.h --- a/libc/utils/FPUtil/TestHelpers.h +++ b/libc/utils/FPUtil/TestHelpers.h @@ -61,39 +61,6 @@ return FPMatcher(expectedValue); } -// TODO: Make the matcher match specific exceptions instead of just identifying -// that an exception was raised. -class FPExceptMatcher : public __llvm_libc::testing::Matcher { - bool exceptionRaised; - -public: - class FunctionCaller { - public: - virtual ~FunctionCaller(){}; - virtual void call() = 0; - }; - - template static FunctionCaller *getFunctionCaller(Func func) { - struct Callable : public FunctionCaller { - Func f; - explicit Callable(Func theFunc) : f(theFunc) {} - void call() override { f(); } - }; - - return new Callable(func); - } - - // Takes ownership of func. - explicit FPExceptMatcher(FunctionCaller *func); - - bool match(bool unused) { return exceptionRaised; } - - void explainError(testutils::StreamWrapper &stream) override { - stream << "A floating point exception should have been raised but it " - << "wasn't\n"; - } -}; - } // namespace testing } // namespace fputil } // namespace __llvm_libc @@ -131,15 +98,4 @@ __llvm_libc::fputil::testing::getMatcher<__llvm_libc::testing::Cond_NE>( \ expected)) -#ifdef LLVM_LIBC_TEST_USE_FUCHSIA -#define ASSERT_RAISES_FP_EXCEPT(func) ASSERT_DEATH(func, WITH_SIGNAL(SIGFPE)) -#else -#define ASSERT_RAISES_FP_EXCEPT(func) \ - ASSERT_THAT( \ - true, \ - __llvm_libc::fputil::testing::FPExceptMatcher( \ - __llvm_libc::fputil::testing::FPExceptMatcher::getFunctionCaller( \ - func))) -#endif // LLVM_LIBC_TEST_USE_FUCHSIA - #endif // LLVM_LIBC_UTILS_FPUTIL_TEST_HELPERS_H diff --git a/libc/utils/FPUtil/TestHelpers.cpp b/libc/utils/FPUtil/TestHelpers.cpp --- a/libc/utils/FPUtil/TestHelpers.cpp +++ b/libc/utils/FPUtil/TestHelpers.cpp @@ -10,10 +10,6 @@ #include "FPBits.h" -#include -#include -#include -#include #include namespace __llvm_libc { @@ -74,36 +70,6 @@ template void describeValue(const char *, long double, testutils::StreamWrapper &); -#if defined(_WIN32) -#define sigjmp_buf jmp_buf -#define sigsetjmp(buf, save) setjmp(buf) -#define siglongjmp(buf, val) longjmp(buf, val) -#endif - -static thread_local sigjmp_buf jumpBuffer; -static thread_local bool caughtExcept; - -static void sigfpeHandler(int sig) { - caughtExcept = true; - siglongjmp(jumpBuffer, -1); -} - -FPExceptMatcher::FPExceptMatcher(FunctionCaller *func) { - auto oldSIGFPEHandler = signal(SIGFPE, &sigfpeHandler); - std::unique_ptr funcUP(func); - - caughtExcept = false; - fenv_t oldEnv; - fegetenv(&oldEnv); - if (sigsetjmp(jumpBuffer, 1) == 0) - funcUP->call(); - // We restore the previous floating point environment after - // the call to the function which can potentially raise SIGFPE. - fesetenv(&oldEnv); - signal(SIGFPE, oldSIGFPEHandler); - exceptionRaised = caughtExcept; -} - } // namespace testing } // namespace fputil } // namespace __llvm_libc