1 | /* Test fegetexceptflag and fesetexceptflag. |
2 | Copyright (C) 2016-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <fenv.h> |
20 | #include <stdio.h> |
21 | #include <math-tests.h> |
22 | |
23 | /* Like feraiseexcept, but raise exactly the specified exceptions EXC, |
24 | without possibly raising "inexact" together with "overflow" or |
25 | "underflow" as permitted by ISO C. (This is not used with traps |
26 | enabled, so side-effects from raising and then clearing "inexact" |
27 | are irrelevant.) */ |
28 | |
29 | static int |
30 | feraiseexcept_exact (int exc) |
31 | { |
32 | #ifdef FE_INEXACT |
33 | int mask = 0; |
34 | #ifdef FE_OVERFLOW |
35 | mask |= FE_OVERFLOW; |
36 | #endif |
37 | #ifdef FE_UNDERFLOW |
38 | mask |= FE_UNDERFLOW; |
39 | #endif |
40 | if ((exc & FE_INEXACT) != 0 |
41 | || (exc & mask) == 0 |
42 | || fetestexcept (FE_INEXACT) != 0) |
43 | return feraiseexcept (excepts: exc); |
44 | int ret = feraiseexcept (excepts: exc); |
45 | feclearexcept (FE_INEXACT); |
46 | return ret; |
47 | #else |
48 | return feraiseexcept (exc); |
49 | #endif |
50 | } |
51 | |
52 | static int |
53 | test_set (int initial, const fexcept_t *saved, int mask, int expected) |
54 | { |
55 | int result = 0; |
56 | feclearexcept (FE_ALL_EXCEPT); |
57 | printf (format: "Testing set: initial exceptions %x, mask %x, expected %x\n" , |
58 | (unsigned int) initial, (unsigned int) mask, |
59 | (unsigned int) expected); |
60 | int ret = feraiseexcept_exact (exc: initial); |
61 | if (ret != 0) |
62 | { |
63 | puts (s: "feraiseexcept failed" ); |
64 | if (initial == 0 || EXCEPTION_TESTS (float)) |
65 | { |
66 | puts (s: "failure of feraiseexcept was unexpected" ); |
67 | result = 1; |
68 | } |
69 | else |
70 | puts (s: "failure of feraiseexcept OK, skipping further tests" ); |
71 | return result; |
72 | } |
73 | ret = fesetexceptflag (flagp: saved, excepts: mask); |
74 | if (ret != 0) |
75 | { |
76 | puts (s: "fesetexceptflag failed" ); |
77 | result = 1; |
78 | } |
79 | else |
80 | puts (s: "fesetexceptflag succeeded" ); |
81 | ret = fetestexcept (FE_ALL_EXCEPT); |
82 | if (ret != expected) |
83 | { |
84 | printf (format: "raised exceptions %x, expected %x\n" , |
85 | (unsigned int) ret, (unsigned int) expected); |
86 | result = 1; |
87 | } |
88 | return result; |
89 | } |
90 | |
91 | static int |
92 | test_except (int exc, const char *exc_name) |
93 | { |
94 | int result = 0; |
95 | |
96 | printf (format: "Testing %s\n" , exc_name); |
97 | feclearexcept (FE_ALL_EXCEPT); |
98 | |
99 | fexcept_t clear_saved_exc, clear_saved_all; |
100 | int ret = fegetexceptflag (flagp: &clear_saved_exc, excepts: exc); |
101 | if (ret == 0) |
102 | printf (format: "fegetexceptflag (%s) succeeded\n" , exc_name); |
103 | else |
104 | { |
105 | printf (format: "fegetexceptflag (%s) failed\n" , exc_name); |
106 | result = 1; |
107 | return result; |
108 | } |
109 | ret = fegetexceptflag (flagp: &clear_saved_all, FE_ALL_EXCEPT); |
110 | if (ret == 0) |
111 | puts (s: "fegetexceptflag (FE_ALL_EXCEPT) succeeded" ); |
112 | else |
113 | { |
114 | puts (s: "fegetexceptflag (FE_ALL_EXCEPT) failed" ); |
115 | result = 1; |
116 | return result; |
117 | } |
118 | |
119 | ret = feraiseexcept_exact (exc); |
120 | if (ret == 0) |
121 | printf (format: "feraiseexcept (%s) succeeded\n" , exc_name); |
122 | else |
123 | { |
124 | printf (format: "feraiseexcept (%s) failed\n" , exc_name); |
125 | if (exc == 0 || EXCEPTION_TESTS (float)) |
126 | { |
127 | puts (s: "failure of feraiseexcept was unexpected" ); |
128 | result = 1; |
129 | } |
130 | else |
131 | puts (s: "failure of feraiseexcept OK, skipping further tests" ); |
132 | return result; |
133 | } |
134 | |
135 | fexcept_t set_saved_exc, set_saved_all; |
136 | ret = fegetexceptflag (flagp: &set_saved_exc, excepts: exc); |
137 | if (ret == 0) |
138 | printf (format: "fegetexceptflag (%s) succeeded\n" , exc_name); |
139 | else |
140 | { |
141 | printf (format: "fegetexceptflag (%s) failed\n" , exc_name); |
142 | result = 1; |
143 | return result; |
144 | } |
145 | ret = fegetexceptflag (flagp: &set_saved_all, FE_ALL_EXCEPT); |
146 | if (ret == 0) |
147 | puts (s: "fegetexceptflag (FE_ALL_EXCEPT) succeeded" ); |
148 | else |
149 | { |
150 | puts (s: "fegetexceptflag (FE_ALL_EXCEPT) failed" ); |
151 | result = 1; |
152 | return result; |
153 | } |
154 | |
155 | result |= test_set (initial: 0, saved: &set_saved_exc, mask: exc, expected: exc); |
156 | result |= test_set (initial: 0, saved: &set_saved_all, mask: exc, expected: exc); |
157 | result |= test_set (initial: 0, saved: &set_saved_all, FE_ALL_EXCEPT, expected: exc); |
158 | result |= test_set (initial: 0, saved: &clear_saved_exc, mask: exc, expected: 0); |
159 | result |= test_set (initial: 0, saved: &clear_saved_all, mask: exc, expected: 0); |
160 | result |= test_set (initial: 0, saved: &clear_saved_all, FE_ALL_EXCEPT, expected: 0); |
161 | result |= test_set (initial: exc, saved: &set_saved_exc, mask: exc, expected: exc); |
162 | result |= test_set (initial: exc, saved: &set_saved_all, mask: exc, expected: exc); |
163 | result |= test_set (initial: exc, saved: &set_saved_all, FE_ALL_EXCEPT, expected: exc); |
164 | result |= test_set (initial: exc, saved: &clear_saved_exc, mask: exc, expected: 0); |
165 | result |= test_set (initial: exc, saved: &clear_saved_all, mask: exc, expected: 0); |
166 | result |= test_set (initial: exc, saved: &clear_saved_all, FE_ALL_EXCEPT, expected: 0); |
167 | result |= test_set (FE_ALL_EXCEPT, saved: &set_saved_exc, mask: exc, FE_ALL_EXCEPT); |
168 | result |= test_set (FE_ALL_EXCEPT, saved: &set_saved_all, mask: exc, FE_ALL_EXCEPT); |
169 | result |= test_set (FE_ALL_EXCEPT, saved: &set_saved_all, FE_ALL_EXCEPT, expected: exc); |
170 | result |= test_set (FE_ALL_EXCEPT, saved: &clear_saved_exc, mask: exc, |
171 | FE_ALL_EXCEPT & ~exc); |
172 | result |= test_set (FE_ALL_EXCEPT, saved: &clear_saved_all, mask: exc, |
173 | FE_ALL_EXCEPT & ~exc); |
174 | result |= test_set (FE_ALL_EXCEPT, saved: &clear_saved_all, FE_ALL_EXCEPT, expected: 0); |
175 | |
176 | return result; |
177 | } |
178 | |
179 | static int |
180 | do_test (void) |
181 | { |
182 | int result = 0; |
183 | |
184 | result |= test_except (exc: 0, exc_name: "0" ); |
185 | result |= test_except (FE_ALL_EXCEPT, exc_name: "FE_ALL_EXCEPT" ); |
186 | #ifdef FE_DIVBYZERO |
187 | result |= test_except (FE_DIVBYZERO, exc_name: "FE_DIVBYZERO" ); |
188 | #endif |
189 | #ifdef FE_INEXACT |
190 | result |= test_except (FE_INEXACT, exc_name: "FE_INEXACT" ); |
191 | #endif |
192 | #ifdef FE_INVALID |
193 | result |= test_except (FE_INVALID, exc_name: "FE_INVALID" ); |
194 | #endif |
195 | #ifdef FE_OVERFLOW |
196 | result |= test_except (FE_OVERFLOW, exc_name: "FE_OVERFLOW" ); |
197 | #endif |
198 | #ifdef FE_UNDERFLOW |
199 | result |= test_except (FE_UNDERFLOW, exc_name: "FE_UNDERFLOW" ); |
200 | #endif |
201 | |
202 | return result; |
203 | } |
204 | |
205 | #define TEST_FUNCTION do_test () |
206 | #include "../test-skeleton.c" |
207 | |