Line data Source code
1 1 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : /// \file 5 : /// Functions to enable/disable termination on floating point exceptions 6 : 7 : #pragma once 8 : 9 : #include <optional> 10 : 11 : /// \cond 12 : #ifdef __APPLE__ 13 : #ifndef __arm64__ 14 : #define SPECTRE_FPE_CSR 1 15 : #endif 16 : #elif not defined(__aarch64__) 17 : #define SPECTRE_FPE_FENV 1 18 : #endif 19 : /// \endcond 20 : 21 : /// \ingroup ErrorHandlingGroup 22 : /// After a call to this function, the code will terminate with a floating 23 : /// point exception on overflow, divide-by-zero, and invalid operations. 24 1 : void enable_floating_point_exceptions(); 25 : 26 : /// \ingroup ErrorHandlingGroup 27 : /// After a call to this function, the code will NOT terminate with a floating 28 : /// point exception on overflow, divide-by-zero, and invalid operations. 29 : /// 30 : /// \warning Do not use this function to temporarily disable FPEs, 31 : /// because it will not interact correctly with C++ exceptions. Use 32 : /// `ScopedFpeState` instead. 33 1 : void disable_floating_point_exceptions(); 34 : 35 : /// \ingroup ErrorHandlingGroup 36 : /// An RAII object to temporarily modify the handling of floating 37 : /// point exceptions. 38 1 : class ScopedFpeState { 39 : public: 40 0 : ScopedFpeState(const ScopedFpeState&) = delete; 41 0 : ScopedFpeState(ScopedFpeState&&) = delete; 42 0 : ScopedFpeState& operator=(const ScopedFpeState&) = delete; 43 0 : ScopedFpeState& operator=(ScopedFpeState&&) = delete; 44 0 : ~ScopedFpeState(); 45 : 46 : /// Start a scope that will be restored, without changing the 47 : /// current state. 48 1 : ScopedFpeState(); 49 : /// Start a scope with the specified exception state. This is 50 : /// equivalent to calling the default constructor followed by 51 : /// `set_exceptions`. 52 1 : explicit ScopedFpeState(bool exceptions_enabled); 53 : 54 0 : struct DoNotSave {}; 55 : /// Start a scope without saving the current state. The only valid 56 : /// method call from this state is `save_exceptions`. 57 1 : explicit ScopedFpeState(DoNotSave /*meta*/); 58 : 59 : /// Enable or disable floating point exceptions. It is an error if 60 : /// the exception state is not currently saved. 61 1 : void set_exceptions(bool exceptions_enabled) const; 62 : 63 : /// Save the current exception handling state after it has been 64 : /// cleared by `restore_exceptions`. It will be restored by a later 65 : /// call to `restore_exceptions`. It is an error to call this if 66 : /// a state is already saved. 67 1 : void save_exceptions(); 68 : 69 : /// Restore the FPE handling to the internally saved state if 70 : /// present and clear that state. This is called automatically by 71 : /// the destructor if it is not called manually. 72 1 : void restore_exceptions(); 73 : 74 : private: 75 : #if SPECTRE_FPE_CSR 76 : std::optional<unsigned int> original_state_; 77 : #elif SPECTRE_FPE_FENV 78 : std::optional<int> original_state_; 79 : #else 80 : // FPEs not supported, but this is still used to check method calls 81 : // are valid. 82 0 : struct DummyState {}; 83 0 : std::optional<DummyState> original_state_; 84 : #endif 85 : };