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