1 /* Test fegetexceptflag and fesetexceptflag.
2    Copyright (C) 2016-2022 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
feraiseexcept_exact(int exc)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 (exc);
44   int ret = feraiseexcept (exc);
45   feclearexcept (FE_INEXACT);
46   return ret;
47 #else
48   return feraiseexcept (exc);
49 #endif
50 }
51 
52 static int
test_set(int initial,const fexcept_t * saved,int mask,int expected)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 ("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 (initial);
61   if (ret != 0)
62     {
63       puts ("feraiseexcept failed");
64       if (initial == 0 || EXCEPTION_TESTS (float))
65 	{
66 	  puts ("failure of feraiseexcept was unexpected");
67 	  result = 1;
68 	}
69       else
70 	puts ("failure of feraiseexcept OK, skipping further tests");
71       return result;
72     }
73   ret = fesetexceptflag (saved, mask);
74   if (ret != 0)
75     {
76       puts ("fesetexceptflag failed");
77       result = 1;
78     }
79   else
80     puts ("fesetexceptflag succeeded");
81   ret = fetestexcept (FE_ALL_EXCEPT);
82   if (ret != expected)
83     {
84       printf ("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
test_except(int exc,const char * exc_name)92 test_except (int exc, const char *exc_name)
93 {
94   int result = 0;
95 
96   printf ("Testing %s\n", exc_name);
97   feclearexcept (FE_ALL_EXCEPT);
98 
99   fexcept_t clear_saved_exc, clear_saved_all;
100   int ret = fegetexceptflag (&clear_saved_exc, exc);
101   if (ret == 0)
102     printf ("fegetexceptflag (%s) succeeded\n", exc_name);
103   else
104     {
105       printf ("fegetexceptflag (%s) failed\n", exc_name);
106       result = 1;
107       return result;
108     }
109   ret = fegetexceptflag (&clear_saved_all, FE_ALL_EXCEPT);
110   if (ret == 0)
111     puts ("fegetexceptflag (FE_ALL_EXCEPT) succeeded");
112   else
113     {
114       puts ("fegetexceptflag (FE_ALL_EXCEPT) failed");
115       result = 1;
116       return result;
117     }
118 
119   ret = feraiseexcept_exact (exc);
120   if (ret == 0)
121     printf ("feraiseexcept (%s) succeeded\n", exc_name);
122   else
123     {
124       printf ("feraiseexcept (%s) failed\n", exc_name);
125       if (exc == 0 || EXCEPTION_TESTS (float))
126 	{
127 	  puts ("failure of feraiseexcept was unexpected");
128 	  result = 1;
129 	}
130       else
131 	puts ("failure of feraiseexcept OK, skipping further tests");
132       return result;
133     }
134 
135   fexcept_t set_saved_exc, set_saved_all;
136   ret = fegetexceptflag (&set_saved_exc, exc);
137   if (ret == 0)
138     printf ("fegetexceptflag (%s) succeeded\n", exc_name);
139   else
140     {
141       printf ("fegetexceptflag (%s) failed\n", exc_name);
142       result = 1;
143       return result;
144     }
145   ret = fegetexceptflag (&set_saved_all, FE_ALL_EXCEPT);
146   if (ret == 0)
147     puts ("fegetexceptflag (FE_ALL_EXCEPT) succeeded");
148   else
149     {
150       puts ("fegetexceptflag (FE_ALL_EXCEPT) failed");
151       result = 1;
152       return result;
153     }
154 
155   result |= test_set (0, &set_saved_exc, exc, exc);
156   result |= test_set (0, &set_saved_all, exc, exc);
157   result |= test_set (0, &set_saved_all, FE_ALL_EXCEPT, exc);
158   result |= test_set (0, &clear_saved_exc, exc, 0);
159   result |= test_set (0, &clear_saved_all, exc, 0);
160   result |= test_set (0, &clear_saved_all, FE_ALL_EXCEPT, 0);
161   result |= test_set (exc, &set_saved_exc, exc, exc);
162   result |= test_set (exc, &set_saved_all, exc, exc);
163   result |= test_set (exc, &set_saved_all, FE_ALL_EXCEPT, exc);
164   result |= test_set (exc, &clear_saved_exc, exc, 0);
165   result |= test_set (exc, &clear_saved_all, exc, 0);
166   result |= test_set (exc, &clear_saved_all, FE_ALL_EXCEPT, 0);
167   result |= test_set (FE_ALL_EXCEPT, &set_saved_exc, exc, FE_ALL_EXCEPT);
168   result |= test_set (FE_ALL_EXCEPT, &set_saved_all, exc, FE_ALL_EXCEPT);
169   result |= test_set (FE_ALL_EXCEPT, &set_saved_all, FE_ALL_EXCEPT, exc);
170   result |= test_set (FE_ALL_EXCEPT, &clear_saved_exc, exc,
171 		      FE_ALL_EXCEPT & ~exc);
172   result |= test_set (FE_ALL_EXCEPT, &clear_saved_all, exc,
173 		      FE_ALL_EXCEPT & ~exc);
174   result |= test_set (FE_ALL_EXCEPT, &clear_saved_all, FE_ALL_EXCEPT, 0);
175 
176   return result;
177 }
178 
179 static int
do_test(void)180 do_test (void)
181 {
182   int result = 0;
183 
184   result |= test_except (0, "0");
185   result |= test_except (FE_ALL_EXCEPT, "FE_ALL_EXCEPT");
186 #ifdef FE_DIVBYZERO
187   result |= test_except (FE_DIVBYZERO, "FE_DIVBYZERO");
188 #endif
189 #ifdef FE_INEXACT
190   result |= test_except (FE_INEXACT, "FE_INEXACT");
191 #endif
192 #ifdef FE_INVALID
193   result |= test_except (FE_INVALID, "FE_INVALID");
194 #endif
195 #ifdef FE_OVERFLOW
196   result |= test_except (FE_OVERFLOW, "FE_OVERFLOW");
197 #endif
198 #ifdef FE_UNDERFLOW
199   result |= test_except (FE_UNDERFLOW, "FE_UNDERFLOW");
200 #endif
201 
202   return result;
203 }
204 
205 #define TEST_FUNCTION do_test ()
206 #include "../test-skeleton.c"
207