Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
19.std.exceptions.cpp
Go to the documentation of this file.
1
29#include <stdexcept>
30
31
34template <class Exception>
35int test_ex_spec (Exception*, const char *str)
36{
37#ifndef _RWSTD_NO_EXCEPTIONS
38
39 try {
40 // also tests that exception objects can be constructed
41 // from a const char* argument w/o <string> having been
42 // explicitly #included first
43 Exception e (str);
44 (void)&e;
45 }
46 catch (...) {
47 return 1;
48 }
49
50#else // if defined (_RWSTD_NO_EXCEPTIONS);
51
53
54#endif // _RWSTD_NO_EXCEPTIONS
55
56 return 0;
57}
58
59
61#include <string>
62
63
66// helpers to verify that each exception's ctor is explicit
67// not defined since they must not be referenced if test is successful
68void is_explicit (const std::logic_error&);
69void is_explicit (const std::domain_error&);
70void is_explicit (const std::invalid_argument&);
71void is_explicit (const std::length_error&);
72void is_explicit (const std::out_of_range&);
73void is_explicit (const std::runtime_error&);
74void is_explicit (const std::range_error&);
75void is_explicit (const std::overflow_error&);
76void is_explicit (const std::underflow_error&);
77
79{
80 // also verifies that std::string is declared
81 bogus_exception (const std::string&) { }
82 bogus_exception (const char*) { }
83};
84
85// calls to the overoaded is_explicit (std::string ()) must resolve
86// to this function since there must be no implicit conversion from
87// std::string to any of the exception classes
89
90// exercise the ability to construct exception objects w/o
91// explicitly #including <string> first; std::string must still
92// be declared (but not necessarily defined)
93
94#if !defined (_RWSTD_NO_NAMESPACE) && !defined (_RWSTD_NO_HONOR_STD)
95 // declare a global function with the same name as exception
96# define TEST_NAMESPACE_DEF(T) void T ()
97#else
98# define TEST_NAMESPACE_DEF(ignore) (void)0
99#endif // !_RWSTD_NO_NAMESPACE && !_RWSTD_NO_HONOR_STD
100
101
102#ifndef _RWSTD_NO_PTR_EXCEPTION_SPEC
103# define _PTR_THROWS(spec) _THROWS (spec)
104#else // if defined (_RWSTD_NO_PTR_EXCEPTION_SPEC)
105 // throw specs on pointers to functions not implemented...
106# define _PTR_THROWS(ignore)
107#endif // _RWSTD_NO_PTR_EXCEPTION_SPEC
108
109
110// verify that each name is declared in namespace std
111// w/o polluting the global namespace
112#define TEST_DEF(T) \
113 typedef std::T T ## _type; \
114 TEST_NAMESPACE_DEF (T); \
115 /* construct an object */ \
116 std::T obj_ ## T ("std::" _RWSTD_STR (T)); \
117 /* assign the address of object to std::exception* */ \
118 e = &obj_ ## T; \
119 /* verify that assignment can't throw */ \
120 std::T& (std::T::*p_assign_ ## T)(const std::T&) \
121 _PTR_THROWS(()) = &std::T::operator=; \
122 _RWSTD_UNUSED (p_assign_ ## T); \
123 /* verify that what() can't throw */ \
124 const char* (std::T::*p_what_ ## T)() const \
125 _PTR_THROWS(()) = &std::T::what; \
126 _RWSTD_UNUSED (p_what_ ## T); \
127 /* verify ctor postcondition */ \
128 result = result << 1 | cmp (obj_ ## T.what (), \
129 "std::" _RWSTD_STR (T))
130
131
132int cmp (const char *s1, const char *s2)
133{
134 for (; *s1 && *s1 == *s2; ++s1, ++s2);
135 return *s2 - *s1;
136}
137
138
139// returns 0 on success; on failure returns a bitmap with one bit set
140// for every exception that failed its ctor postcondition
141static int test_exception_defs ()
142{
143 int result = 0;
144
145 // used below to verify public inheritance from std::exception
146 std::exception *e = 0;
147
148 TEST_DEF (logic_error);
149 TEST_DEF (domain_error);
150 TEST_DEF (invalid_argument);
151 TEST_DEF (length_error);
152 TEST_DEF (out_of_range);
153 TEST_DEF (runtime_error);
154 TEST_DEF (range_error);
155 TEST_DEF (overflow_error);
156 TEST_DEF (underflow_error);
157
159
160 // verify that each exceptions converting ctor is explicit
161 // use a pointer since std::string need not be a complete class
162 const char s[40] = "";
163 const std::string *ps = _RWSTD_REINTERPRET_CAST (const std::string*, s);
164 is_explicit (*ps);
165
166 // verify that each exceptions converting ctor from const char*
167 // (if one exists) is also explicit
168 is_explicit (s);
169
170 return result;
171}
172
173#undef _PTR_THROWS
174
175
177#include <rw_new.h>
178#include <rw_driver.h>
179
180#include <cstddef>
181
182
185template <class Exception>
186int test_throw (Exception*, const char *str)
187{
188#ifndef _RWSTD_NO_EXCEPTIONS
189
191
192 try {
193 throw Exception (str);
194 }
195 catch (const Exception &e) {
196 // caught by const reference
197 rw_assert (e.what () && !cmp (e.what (), str),
198 0, __LINE__,
199 "caught by const reference; %s::what() == %#s",
200 str, str);
201 }
202 catch (...) {
203 rw_assert (false, 0, __LINE__,
204 "threw %s, caught an unknown exception", str);
205 }
206
208
209 try {
210 throw Exception (str);
211 }
212 catch (Exception e) {
213 // caught by value
214 rw_assert (e.what () && !cmp (e.what (), str),
215 0, __LINE__,
216 "caught by value; %s::what() == %#s",
217 str, str);
218 }
219 catch (...) {
220 rw_assert (false, 0, __LINE__,
221 "threw %s, caught an unknown exception", str);
222 }
223
225
226 const Exception ex (str);
227
228 try {
229 throw ex;
230 }
231 catch (Exception e) {
232 // caught copy by value
233 rw_assert (e.what () && !cmp (e.what (), str),
234 0, __LINE__,
235 "caught copy by value; %s::what() == %#s",
236 str, str);
237 }
238 catch (...) {
239 rw_assert (false, 0, __LINE__,
240 "threw %s, caught an unknown exception", str);
241 }
242
244
245 try {
246 throw ex;
247 }
248 catch (std::exception &e) {
249 // caught by non-const reference to a base class
250 rw_assert (e.what () && !cmp (e.what (), str),
251 0, __LINE__,
252 "caught by non-const reference to base; %s::what() == %#s",
253 str, str);
254 }
255 catch (...) {
256 rw_assert (false, 0, __LINE__,
257 "threw %s, caught an unknown exception", str);
258 }
259
261
262 try {
263 try {
264 throw Exception (str);
265 }
266 catch (...) {
267 // rethrown
268 throw;
269 }
270 }
271 catch (Exception e) {
272 // rethrown object caught by value
273 rw_assert (e.what () && !cmp (e.what (), str),
274 0, __LINE__,
275 "caught rethrown by value; %s::what() == %#s", str, str);
276 }
277 catch (...) {
278 rw_assert (false, 0, __LINE__,
279 "threw %s, caught an unknown exception", str);
280 }
281
283
284 try {
285 try {
286 throw Exception (str);
287 }
288 catch (Exception e) {
289 rw_assert (e.what () && !cmp (e.what (), str),
290 0, __LINE__,
291 "caught by value; %s::what() == %#s",
292 str, str);
293
294 // rethrown by value
295 throw e;
296 }
297 }
298 catch (Exception e) {
299 // rethrown object caught by value
300 rw_assert (e.what () && !cmp (e.what (), str),
301 0, __LINE__,
302 "caught rethrown copy by value; %s::what() == %#s",
303 str, str);
304 }
305 catch (...) {
306 rw_assert (false, 0, __LINE__,
307 "threw %s, caught an unknown exception", str);
308 }
309
310#else // if defined (_RWSTD_NO_EXCEPTIONS);
311
314
315#endif // _RWSTD_NO_EXCEPTIONS
316
317 return 0;
318}
319
320
323static int
324run_test (int, char* [])
325{
326 // verify that exception's (and its derivatives') ctor is explicit
327 is_explicit (std::string ());
328
329 const char* const names[] = {
330 "logic_error", "domain_error", "invalid_argument", "length_error",
331 "out_of_range", "runtime_error", "range_error", "overflow_error",
332 "underflow_error"
333 };
334
335 // if set, each bit corresponds to a failed exception assertion
336 const int failures = test_exception_defs ();
337
338 for (unsigned i = 0; i != sizeof names / sizeof *names; ++i) {
339 rw_assert (!(failures & (1 << i)), 0, __LINE__,
340 "std::%s::%s (const std::string&) postcondition",
341 names [i]);
342 }
343
344
345 // have replacement operator new throw an exception
346 rwt_free_store* const pst = rwt_get_free_store (0);
347 *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + 1;
348
349 // create a very long string to guarantee that exception ctors
350 // try to dynamically allocate storage even if it otherwise
351 // use some clever scheme to avoid doing so
352 char long_str [0x10000];
353 for (unsigned i = 0; i != sizeof long_str - 1; ++i)
354 long_str [i] = '*';
355
356 long_str [sizeof long_str - 1] = '\0';
357
358 int new_throws = 0;
359
360 _TRY {
361 // see if replacement operator new throws an exception
362 // when called directly from the program
363 void *p = ::operator new (sizeof long_str);
364 ::operator delete (p);
365 new_throws = 0;
366
367#ifdef _RWSTD_NO_REPLACEABLE_NEW_DELETE
368
369 // MSVC and VAC++ don't reliably replace operators
370 // new and delete across shared librray boundaries
371
372 rw_warn (false, 0, __LINE__,
373 "replacement ::operator new(std::size_t = %u) failed "
374 "to throw when called directly from a program: this "
375 "is an expected failure on this platform",
376 sizeof long_str);
377
378#else // if !defined (_RWSTD_NO_REPLACEABLE_NEW_DELETE)
379
380 rw_assert (false, 0, __LINE__,
381 "replacement ::operator new(std::size_t = %u) "
382 "unexpectdly failed to throw when called directly "
383 "from a program",
384 sizeof long_str);
385
386#endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE
387
388 }
389 _CATCH (...) {
390 new_throws = 1;
391 }
392
393 *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + 1;
394
395 _TRY {
396 // see if replacement operator new throws an exception
397 // when called indirectly, i.e., from the library binary
398 void* const p = _RW::__rw_allocate (sizeof long_str, 0);
399 _RW::__rw_deallocate (p, 0);
400 new_throws = 0;
401
402#ifdef _RWSTD_NO_REPLACEABLE_NEW_DELETE
403
404 // MSVC and VAC++ don't reliably replace operators
405 // new and delete across shared librray boundaries
406
407 rw_warn (false, 0, __LINE__,
408 "replacement ::operator new(std::size_t = %u) failed "
409 "to throw when called from the library: this is an "
410 "expected failure on this platform",
411 sizeof long_str);
412
413#else // if !defined (_RWSTD_NO_REPLACEABLE_NEW_DELETE)
414
415 rw_assert (false, 0, __LINE__,
416 "replacement ::operator new(std::size_t = %u) "
417 "unexpectdly failed to throw when called from "
418 "the library",
419 sizeof long_str);
420
421#endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE
422
423 }
424 _CATCH (...) {
425 new_throws = 1;
426 }
427
428// exercise exception specification on class ctors
429// and the ability to throw and catch exception objects
430#define TEST_EX_SPEC(T) do { \
431 /* do not induce an exception from replacement operator new */ \
432 *pst->throw_at_calls_ [0] = std::size_t (-1); \
433 *pst->throw_at_calls_ [1] = std::size_t (-1); \
434 /* verify that exception objects can be thrown, caught, and rethrown */\
435 test_throw ((std:: T*)0, "std::" #T); \
436 /* induce an exception from replacement operator new */ \
437 *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + 1; \
438 *pst->throw_at_calls_ [1] = pst->new_calls_ [1] + 1; \
439 /* verify that each exception ctor propagates the exception thrown */ \
440 /* from operator new(); failure wil cause a call to terminate() */ \
441 /* tests are expected to silently fail if (0 == new_throws) holds */ \
442 const int threw = test_ex_spec ((std::T*)0, long_str); \
443 rw_assert (threw == new_throws, 0, __LINE__, \
444 "attempthing to construct a std::" #T " %s an exception", \
445 new_throws ? "failed to rethrow" : "unexpectedly threw"); \
446 } while (0)
447
448 TEST_EX_SPEC (logic_error);
449 TEST_EX_SPEC (domain_error);
450 TEST_EX_SPEC (invalid_argument);
451 TEST_EX_SPEC (length_error);
452 TEST_EX_SPEC (out_of_range);
453 TEST_EX_SPEC (runtime_error);
454 TEST_EX_SPEC (range_error);
455 TEST_EX_SPEC (overflow_error);
456 TEST_EX_SPEC (underflow_error);
457
458 return 0;
459}
460
461
464int main (int argc, char* argv [])
465{
466 return rw_test (argc, argv, __FILE__,
467 "lib.std.exceptions",
468 0 /* no comment */,
469 run_test,
470 "",
471 (void*)0);
472}
#define i
Definition 17.names.cpp:126
#define s1
Definition 17.names.cpp:242
#define t
Definition 17.names.cpp:136
#define e
Definition 17.names.cpp:118
#define cmp
Definition 17.names.cpp:458
#define s2
Definition 17.names.cpp:268
#define s
#define p
Definition 17.names.cpp:132
volatile int result
int test_ex_spec(Exception *, const char *str)
#define TEST_EX_SPEC(T)
void is_explicit(const std::logic_error &)
int test_throw(Exception *, const char *str)
#define TEST_DEF(T)
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
#define main
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _TRY
Definition _defs.h:850
#define _CATCH(ex)
Definition _defs.h:851
const char * str
Definition exec.cpp:170
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT int rw_warn(int, const char *, int, const char *,...)
Definition driver.cpp:1647
_TEST_EXPORT rwt_free_store * rwt_get_free_store(rwt_free_store *)
Definition new.cpp:597
bogus_exception(const std::string &)
bogus_exception(const char *)
_RWSTD_SIZE_T * throw_at_calls_[2]
Definition rw_new.h:83
_RWSTD_SIZE_T new_calls_[2]
Definition rw_new.h:47