Skip to content

Commit 16f6ded

Browse files
authored
Merge pull request #3441 from roystgnr/quiet_throw
Only print *uncaught* errors automatically
2 parents 63ad414 + daad825 commit 16f6ded

4 files changed

Lines changed: 68 additions & 131 deletions

File tree

include/base/libmesh_common.h

Lines changed: 34 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
// compatibility, although we no longer use it in the library.
7272
#include "libmesh/libmesh_nullptr.h"
7373

74+
// C++ headers
75+
#include <iomanip> // setprecision, in assertion macros
76+
7477
namespace libMesh
7578
{
7679
namespace Threads
@@ -80,16 +83,26 @@ void lock_singleton_spin_mutex();
8083
void unlock_singleton_spin_mutex();
8184
}
8285

86+
// Let's define a couple output streams - these will default
87+
// to cout/cerr, but LibMeshInit (or the user) can also set them to
88+
// something more sophisticated.
89+
//
90+
// We use a proxy class rather than references so they can be
91+
// reseated at runtime.
92+
93+
extern OStreamProxy out;
94+
extern OStreamProxy err;
95+
8396
// A namespace for functions used in the bodies of the macros below.
8497
// The macros generally call these functions with __FILE__, __LINE__,
8598
// __DATE__, and __TIME__ in the appropriate order. These should not
8699
// be called by users directly! The implementations can be found in
87100
// libmesh_common.C.
88101
namespace MacroFunctions
89102
{
90-
void here(const char * file, int line, const char * date, const char * time);
103+
void here(const char * file, int line, const char * date, const char * time, std::ostream & os = libMesh::err);
91104
void stop(const char * file, int line, const char * date, const char * time);
92-
void report_error(const char * file, int line, const char * date, const char * time);
105+
void report_error(const char * file, int line, const char * date, const char * time, std::ostream & os = libMesh::err);
93106
}
94107

95108
// Undefine any existing macros
@@ -221,16 +234,6 @@ extern MPI_Comm GLOBAL_COMM_WORLD;
221234
extern int GLOBAL_COMM_WORLD;
222235
#endif
223236

224-
// Let's define a couple output streams - these will default
225-
// to cout/cerr, but LibMeshInit (or the user) can also set them to
226-
// something more sophisticated.
227-
//
228-
// We use a proxy class rather than references so they can be
229-
// reseated at runtime.
230-
231-
extern OStreamProxy out;
232-
extern OStreamProxy err;
233-
234237
// This global variable is to help us deprecate AutoPtr. We can't
235238
// just use libmesh_deprecated() because then you get one print out
236239
// per template instantiation, instead of one total print out.
@@ -308,76 +311,15 @@ extern bool warned_about_auto_ptr;
308311
#define libmesh_assert_equal_to_msg(expr1,expr2, msg) \
309312
do { \
310313
if (!((expr1) == (expr2))) { \
311-
libMesh::Threads::lock_singleton_spin_mutex(); \
312-
std::streamsize oldp = libMesh::err.precision(17); \
313-
libMesh::err << "Assertion `" #expr1 " == " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
314-
libMesh::err.precision(oldp); \
315-
libMesh::Threads::unlock_singleton_spin_mutex(); \
316-
libmesh_error(); \
314+
libmesh_error_msg(std::setprecision(17) << "Assertion `" #expr1 " == " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl); \
317315
} } while (0)
318316

319317
#define libmesh_assert_not_equal_to_msg(expr1,expr2, msg) \
320318
do { \
321319
if (!((expr1) != (expr2))) { \
322-
libMesh::Threads::lock_singleton_spin_mutex(); \
323-
std::streamsize oldp = libMesh::err.precision(17); \
324-
libMesh::err << "Assertion `" #expr1 " != " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
325-
libMesh::err.precision(oldp); \
326-
libMesh::Threads::unlock_singleton_spin_mutex(); \
327-
libmesh_error(); \
320+
libmesh_error_msg(std::setprecision(17) << "Assertion `" #expr1 " != " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl); \
328321
} } while (0)
329322

330-
// Older Clang has a parsing bug that can't seem to handle the handle the decay statement when
331-
// expanding these macros. We'll just fall back to the previous behavior with those older compilers
332-
#if defined(__clang__) && (__clang_major__ <= 3)
333-
334-
#define libmesh_assert_less_msg(expr1,expr2, msg) \
335-
do { \
336-
if (!((expr1) < (expr2))) { \
337-
libMesh::Threads::lock_singleton_spin_mutex(); \
338-
std::streamsize oldp = libMesh::err.precision(17); \
339-
libMesh::err << "Assertion `" #expr1 " < " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
340-
libMesh::err.precision(oldp); \
341-
libMesh::Threads::unlock_singleton_spin_mutex(); \
342-
libmesh_error(); \
343-
} } while (0)
344-
345-
#define libmesh_assert_greater_msg(expr1,expr2, msg) \
346-
do { \
347-
if (!((expr1) > (expr2))) { \
348-
libMesh::Threads::lock_singleton_spin_mutex(); \
349-
std::streamsize oldp = libMesh::err.precision(17); \
350-
libMesh::err << "Assertion `" #expr1 " > " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
351-
libMesh::err.precision(oldp); \
352-
libMesh::Threads::unlock_singleton_spin_mutex(); \
353-
libmesh_error(); \
354-
} } while (0)
355-
356-
#define libmesh_assert_less_equal_msg(expr1,expr2, msg) \
357-
do { \
358-
if (!((expr1) <= (expr2))) { \
359-
libMesh::Threads::lock_singleton_spin_mutex(); \
360-
std::streamsize oldp = libMesh::err.precision(17); \
361-
libMesh::err << "Assertion `" #expr1 " <= " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
362-
libMesh::err.precision(oldp); \
363-
libMesh::Threads::unlock_singleton_spin_mutex(); \
364-
libmesh_error(); \
365-
} } while (0)
366-
367-
#define libmesh_assert_greater_equal_msg(expr1,expr2, msg) \
368-
do { \
369-
if (!((expr1) >= (expr2))) { \
370-
libMesh::Threads::lock_singleton_spin_mutex(); \
371-
std::streamsize oldp = libMesh::err.precision(17); \
372-
libMesh::err << "Assertion `" #expr1 " >= " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
373-
libMesh::err.precision(oldp); \
374-
libMesh::Threads::unlock_singleton_spin_mutex(); \
375-
libmesh_error(); \
376-
} } while (0)
377-
378-
// Newer clangs and all other supported compilers
379-
#else
380-
381323
template <template <class> class Comp>
382324
struct casting_compare {
383325

@@ -400,49 +342,27 @@ struct casting_compare {
400342
#define libmesh_assert_less_msg(expr1,expr2, msg) \
401343
do { \
402344
if (!libMesh::casting_compare<std::less>()(expr1, expr2)) { \
403-
libMesh::Threads::lock_singleton_spin_mutex(); \
404-
std::streamsize oldp = libMesh::err.precision(17); \
405-
libMesh::err << "Assertion `" #expr1 " < " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
406-
libMesh::err.precision(oldp); \
407-
libMesh::Threads::unlock_singleton_spin_mutex(); \
408-
libmesh_error(); \
345+
libmesh_error_msg(std::setprecision(17) << "Assertion `" #expr1 " < " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl); \
409346
} } while (0)
410347

411348
#define libmesh_assert_greater_msg(expr1,expr2, msg) \
412349
do { \
413350
if (!libMesh::casting_compare<std::greater>()(expr1, expr2)) { \
414-
libMesh::Threads::lock_singleton_spin_mutex(); \
415-
std::streamsize oldp = libMesh::err.precision(17); \
416-
libMesh::err << "Assertion `" #expr1 " > " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
417-
libMesh::err.precision(oldp); \
418-
libMesh::Threads::unlock_singleton_spin_mutex(); \
419-
libmesh_error(); \
351+
libmesh_error_msg(std::setprecision(17) << "Assertion `" #expr1 " > " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl); \
420352
} } while (0)
421353

422354
#define libmesh_assert_less_equal_msg(expr1,expr2, msg) \
423355
do { \
424356
if (!libMesh::casting_compare<std::less_equal>()(expr1, expr2)) { \
425-
libMesh::Threads::lock_singleton_spin_mutex(); \
426-
std::streamsize oldp = libMesh::err.precision(17); \
427-
libMesh::err << "Assertion `" #expr1 " <= " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
428-
libMesh::err.precision(oldp); \
429-
libMesh::Threads::unlock_singleton_spin_mutex(); \
430-
libmesh_error(); \
357+
libmesh_error_msg(std::setprecision(17) << "Assertion `" #expr1 " <= " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl); \
431358
} } while (0)
432359

433360
#define libmesh_assert_greater_equal_msg(expr1,expr2, msg) \
434361
do { \
435362
if (!libMesh::casting_compare<std::greater_equal>()(expr1, expr2)) { \
436-
libMesh::Threads::lock_singleton_spin_mutex(); \
437-
std::streamsize oldp = libMesh::err.precision(17); \
438-
libMesh::err << "Assertion `" #expr1 " >= " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl; \
439-
libMesh::err.precision(oldp); \
440-
libMesh::Threads::unlock_singleton_spin_mutex(); \
441-
libmesh_error(); \
363+
libmesh_error_msg(std::setprecision(17) << "Assertion `" #expr1 " >= " #expr2 "' failed.\n" #expr1 " = " << (expr1) << "\n" #expr2 " = " << (expr2) << '\n' << msg << std::endl); \
442364
} } while (0)
443365

444-
#endif // clang <4.0
445-
446366
#endif
447367

448368

@@ -468,13 +388,12 @@ struct casting_compare {
468388
// throws a ConvergenceFailure exception
469389
#define libmesh_error_msg(msg) \
470390
do { \
391+
std::stringstream message_stream; \
392+
message_stream << msg << '\n'; \
471393
libMesh::Threads::lock_singleton_spin_mutex(); \
472-
libMesh::err << msg << std::endl; \
473-
std::stringstream msg_stream; \
474-
msg_stream << msg; \
475-
libMesh::MacroFunctions::report_error(__FILE__, __LINE__, LIBMESH_DATE, LIBMESH_TIME); \
394+
libMesh::MacroFunctions::report_error(__FILE__, __LINE__, LIBMESH_DATE, LIBMESH_TIME, message_stream); \
476395
libMesh::Threads::unlock_singleton_spin_mutex(); \
477-
LIBMESH_THROW(libMesh::LogicError(msg_stream.str())); \
396+
LIBMESH_THROW(libMesh::LogicError(message_stream.str())); \
478397
} while (0)
479398

480399
#define libmesh_error() libmesh_error_msg("")
@@ -488,7 +407,7 @@ struct casting_compare {
488407
#define libmesh_exceptionless_error_msg(msg) \
489408
do { \
490409
libMesh::Threads::lock_singleton_spin_mutex(); \
491-
libMesh::err << msg << std::endl; \
410+
libMesh::err << msg << '\n'; \
492411
libmesh_try { libMesh::MacroFunctions::report_error(__FILE__, __LINE__, LIBMESH_DATE, LIBMESH_TIME); } \
493412
libmesh_catch (...) {} \
494413
libMesh::Threads::unlock_singleton_spin_mutex(); \
@@ -499,23 +418,24 @@ struct casting_compare {
499418

500419
#define libmesh_not_implemented_msg(msg) \
501420
do { \
421+
std::stringstream message_stream; \
422+
message_stream << msg << '\n'; \
502423
libMesh::Threads::lock_singleton_spin_mutex(); \
503-
libMesh::err << msg << std::endl; \
504-
libMesh::MacroFunctions::report_error(__FILE__, __LINE__, LIBMESH_DATE, LIBMESH_TIME); \
424+
libMesh::MacroFunctions::report_error(__FILE__, __LINE__, LIBMESH_DATE, LIBMESH_TIME, message_stream); \
505425
libMesh::Threads::unlock_singleton_spin_mutex(); \
506-
LIBMESH_THROW(libMesh::NotImplemented()); \
426+
LIBMESH_THROW(libMesh::NotImplemented(message_stream.str())); \
507427
} while (0)
508428

509429
#define libmesh_not_implemented() libmesh_not_implemented_msg("")
510430

511431
#define libmesh_file_error_msg(filename, msg) \
512432
do { \
433+
std::stringstream message_stream; \
434+
message_stream << msg << '\n'; \
513435
libMesh::Threads::lock_singleton_spin_mutex(); \
514-
libMesh::err << "Error with file `" << filename << "'" << std::endl; \
515-
libMesh::MacroFunctions::report_error(__FILE__, __LINE__, LIBMESH_DATE, LIBMESH_TIME); \
516-
libMesh::err << msg << std::endl; \
436+
libMesh::MacroFunctions::report_error(__FILE__, __LINE__, LIBMESH_DATE, LIBMESH_TIME, message_stream); \
517437
libMesh::Threads::unlock_singleton_spin_mutex(); \
518-
LIBMESH_THROW(libMesh::FileError(filename)); \
438+
LIBMESH_THROW(libMesh::FileError(filename, message_stream.str())); \
519439
} while (0)
520440

521441
#define libmesh_file_error(filename) libmesh_file_error_msg(filename,"")

include/base/libmesh_exceptions.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class LogicError : public std::logic_error
5151
class NotImplemented : public std::logic_error
5252
{
5353
public:
54-
NotImplemented() : std::logic_error( "Error: not implemented!" ) {}
54+
NotImplemented(std::string msg="") : std::logic_error( "Error: feature not implemented!\n" + msg ) {}
5555
};
5656

5757

@@ -65,7 +65,8 @@ class NotImplemented : public std::logic_error
6565
class FileError : public std::runtime_error
6666
{
6767
public:
68-
FileError(const std::string & filename) : std::runtime_error( "Error accessing file: " + filename ) {}
68+
FileError(const std::string & filename, const std::string msg="") :
69+
std::runtime_error("Error with file `" + filename + "'\n" + std::move(msg)) {}
6970
};
7071

7172

@@ -150,7 +151,7 @@ class SolverException: public std::exception
150151

151152
#else
152153

153-
#define LIBMESH_THROW(e) do { std::abort(); } while (0)
154+
#define LIBMESH_THROW(e) do { libMesh::err << e.what(); std::abort(); } while (0)
154155
#define libmesh_try
155156
#define libmesh_catch(e) if (0)
156157

src/base/libmesh.C

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,23 @@ std::terminate_handler old_terminate_handler;
276276

277277
void libmesh_terminate_handler()
278278
{
279+
// If we have an active exception, it may have an error message that
280+
// we should print.
281+
libMesh::err << "libMesh terminating";
282+
std::exception_ptr ex = std::current_exception();
283+
if (ex)
284+
{
285+
try
286+
{
287+
std::rethrow_exception(ex);
288+
}
289+
catch (const std::exception & std_ex)
290+
{
291+
libMesh::err << ":\n" << std_ex.what();
292+
}
293+
}
294+
libMesh::err << std::endl;
295+
279296
// If this got called then we're probably crashing; let's print a
280297
// stack trace. The trace files that are ultimately written depend on:
281298
// 1.) Who throws the exception.
@@ -319,9 +336,8 @@ void libmesh_terminate_handler()
319336
MPI_Abort(libMesh::GLOBAL_COMM_WORLD, 1);
320337
else
321338
#endif
322-
// The system terminate_handler may do useful things like printing
323-
// uncaught exception information, or the user may have created
324-
// their own terminate handler that we want to call.
339+
// The system terminate_handler may do useful things, or the user
340+
// may have set their own terminate handler that we want to call.
325341
old_terminate_handler();
326342
}
327343
#endif

src/base/libmesh_common.C

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ namespace libMesh
3838

3939
namespace MacroFunctions
4040
{
41-
void here(const char * file, int line, const char * date, const char * time)
41+
void here(const char * file, int line, const char * date, const char * time, std::ostream & os)
4242
{
43-
libMesh::err << "[" << static_cast<std::size_t>(libMesh::global_processor_id()) << "] "
44-
<< file
45-
<< ", line " << line
46-
<< ", compiled " << date
47-
<< " at " << time
48-
<< std::endl;
43+
os << "[" << static_cast<std::size_t>(libMesh::global_processor_id()) << "] "
44+
<< file
45+
<< ", line " << line
46+
<< ", compiled " << date
47+
<< " at " << time
48+
<< std::endl;
4949
}
5050

5151

@@ -66,7 +66,7 @@ void stop(const char * file, int line, const char * date, const char * time)
6666
}
6767

6868

69-
void report_error(const char * file, int line, const char * date, const char * time)
69+
void report_error(const char * file, int line, const char * date, const char * time, std::ostream & os)
7070
{
7171
// It is possible to have an error *inside* report_error; e.g. from
7272
// print_trace. We don't want to infinitely recurse.
@@ -75,17 +75,17 @@ void report_error(const char * file, int line, const char * date, const char * t
7575
{
7676
// I heard you like error reporting, so we put an error report
7777
// in report_error() so you can report errors from the report.
78-
libMesh::err << "libMesh encountered an error while attempting to report_error." << std::endl;
78+
os << "libMesh encountered an error while attempting to report_error." << std::endl;
7979
return;
8080
}
8181
reporting_error = true;
8282

8383
if (libMesh::global_n_processors() == 1 ||
8484
libMesh::on_command_line("--print-trace"))
85-
libMesh::print_trace();
85+
libMesh::print_trace(os);
8686
else
8787
libMesh::write_traceout();
88-
libMesh::MacroFunctions::here(file, line, date, time);
88+
libMesh::MacroFunctions::here(file, line, date, time, os);
8989

9090
reporting_error = false;
9191
}

0 commit comments

Comments
 (0)