1 /* 2 * This file is part of the GROMACS molecular simulation package. 3 * 4 * Copyright (c) 2011,2012,2013,2014,2015 by the GROMACS development team. 5 * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by 6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, 7 * and including many others, as listed in the AUTHORS file in the 8 * top-level source directory and at http://www.gromacs.org. 9 * 10 * GROMACS is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public License 12 * as published by the Free Software Foundation; either version 2.1 13 * of the License, or (at your option) any later version. 14 * 15 * GROMACS is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with GROMACS; if not, see 22 * http://www.gnu.org/licenses, or write to the Free Software Foundation, 23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 * 25 * If you want to redistribute modifications to GROMACS, please 26 * consider that scientific software is very special. Version 27 * control is crucial - bugs must be traceable. We will be happy to 28 * consider code for inclusion in the official distribution, but 29 * derived work must not be called official GROMACS. Details are found 30 * in the README & COPYING files - if they are missing, get the 31 * official version at http://www.gromacs.org. 32 * 33 * To help us fund GROMACS development, we humbly ask that you cite 34 * the research papers on the package. Check out http://www.gromacs.org. 35 */ 36 /*! \file 37 * \brief 38 * Declares common exception classes and macros for fatal error handling. 39 * 40 * The basic approach is the same as in boost::exception for storing additional 41 * context information to exceptions, but since that functionality is a very 42 * small and simple part of boost::exception, the code is duplicated here. 43 * 44 * \author Teemu Murtola <teemu.murtola@gmail.com> 45 * \inpublicapi 46 * \ingroup module_utility 47 */ 48 #ifndef GMX_UTILITY_EXCEPTIONS_H 49 #define GMX_UTILITY_EXCEPTIONS_H 50 51 #include <cstdio> 52 #include <cstdlib> 53 54 #include <exception> 55 #include <memory> 56 #include <string> 57 #include <type_traits> 58 #include <typeindex> 59 #include <vector> 60 61 #include "gromacs/utility/basedefinitions.h" 62 #include "gromacs/utility/gmxassert.h" 63 64 namespace gmx 65 { 66 67 class TextWriter; 68 69 namespace internal 70 { 71 //! Internal container type for storing a list of nested exceptions. 72 typedef std::vector<std::exception_ptr> NestedExceptionList; 73 74 /*! \internal 75 * \brief 76 * Base class for ExceptionInfo. 77 * 78 * This class only provides a way to store different ExceptionInfo objects in 79 * the same container. Actual access to the ExceptionInfo items is handled by 80 * downcasting, after looking up the correct item based on its type. 81 * 82 * \ingroup module_utility 83 */ 84 class IExceptionInfo 85 { 86 public: 87 virtual ~IExceptionInfo(); 88 IExceptionInfo() = default; 89 IExceptionInfo(const IExceptionInfo&) = default; 90 IExceptionInfo(IExceptionInfo&&) noexcept = default; 91 IExceptionInfo& operator=(const IExceptionInfo&) = default; 92 IExceptionInfo& operator=(IExceptionInfo&&) noexcept = default; 93 }; 94 95 //! Smart pointer to manage IExceptionInfo ownership. 96 typedef std::unique_ptr<IExceptionInfo> ExceptionInfoPointer; 97 98 class ExceptionData; 99 100 } // namespace internal 101 102 //! \addtogroup module_utility 103 //! \{ 104 105 /*! \brief 106 * Stores additional context information for exceptions. 107 * 108 * \tparam Tag Tag type (typically, a forward-declared struct that is not 109 * defined anywhere) that makes all ExceptionInfo types unique, even if 110 * they have the same value type. 111 * \tparam T Type of value this object stores. 112 * Needs to be copy-constructible. 113 * 114 * Example of declaring a new info type that stores an integer: 115 * \code 116 typedef ExceptionInfo<struct ExceptionInfoMyInfo_, int> ExceptionInfoMyInfo; 117 \endcode 118 * 119 * \inpublicapi 120 */ 121 template<class Tag, typename T> 122 class ExceptionInfo : public internal::IExceptionInfo 123 { 124 public: 125 //! The type of value stored in this object. 126 typedef T value_type; 127 128 //! Creates an info object from given value. ExceptionInfo(const T & value)129 explicit ExceptionInfo(const T& value) : value_(value) {} 130 131 //! Returns the stored value. value()132 const T& value() const { return value_; } 133 134 private: 135 T value_; 136 }; 137 138 /*! \internal 139 * \brief 140 * Stores the location from which an exception was thrown. 141 */ 142 struct ThrowLocation 143 { 144 //! Creates an object for storing the throw location. ThrowLocationThrowLocation145 ThrowLocation(const char* func, const char* file, int line) : func(func), file(file), line(line) 146 { 147 } 148 149 //! Function where the throw occurred. 150 const char* func; 151 //! File where the throw occurred. 152 const char* file; 153 //! Line number where the throw occurred. 154 int line; 155 }; 156 157 //! Stores `errno` value that triggered the exception. 158 typedef ExceptionInfo<struct ExceptionInfoErrno_, int> ExceptionInfoErrno; 159 //! Stores the function name that returned the `errno` in ExceptionInfoErrno. 160 typedef ExceptionInfo<struct ExceptionInfoApiFunc_, const char*> ExceptionInfoApiFunction; 161 //! Stores the location where the exception was thrown. 162 typedef ExceptionInfo<struct ExceptionInfoLocation_, ThrowLocation> ExceptionInfoLocation; 163 164 /*! \brief 165 * Provides information for Gromacs exception constructors. 166 * 167 * This class exists to implement common functionality for initializing all 168 * Gromacs exceptions without having extra code in each exception class. 169 * In simple cases, it can be implicitly constructed by passing a simple string 170 * to an exception constructor. 171 * If more complex initialization is necessary, it is possible to explicitly 172 * construct an object of this type and then call other methods to add 173 * information before actually creating the exception object. 174 * 175 * \todo 176 * With the exception of the reason string, information added with this class 177 * is not currently accessible through any public API, except for calling 178 * printFatalErrorMessage(), formatExceptionMessageToString() or 179 * formatExceptionMessageToFile(). This is not implemented as there is not yet 180 * need for it, and it is not clear what would be the best alternative for the 181 * access. It should be possible to refactor the internal implementation to 182 * suit the needs of such external access without requiring changes in code 183 * that throws these exceptions. 184 * 185 * \ingroup module_utility 186 */ 187 class ExceptionInitializer 188 { 189 public: 190 /*! \brief 191 * Creates an initialized with the given string as the reason. 192 * 193 * \param[in] reason Detailed reason for the exception. 194 * \throw std::bad_alloc if out of memory. 195 * 196 * This constructor is not explicit to allow constructing exceptions 197 * with a plain string argument given to the constructor without adding 198 * extra code to each exception class. 199 */ ExceptionInitializer(const char * reason)200 ExceptionInitializer(const char* reason) : reason_(reason) {} 201 //! \copydoc ExceptionInitializer(const char *) ExceptionInitializer(const std::string & reason)202 ExceptionInitializer(const std::string& reason) : reason_(reason) {} 203 204 /*! \brief 205 * Returns true if addCurrentExceptionAsNested() has been called. 206 * 207 * Provided for convenience for cases where exceptions will be added 208 * conditionally, and the caller wants to check whether any excetions 209 * were actually added. 210 */ hasNestedExceptions()211 bool hasNestedExceptions() const { return !nested_.empty(); } 212 /*! \brief 213 * Adds the currently caught exception as a nested exception. 214 * 215 * May be called multiple times; all provided exceptions will be added 216 * in a list of nested exceptions. 217 * 218 * Must not be called outside a catch block. 219 */ addCurrentExceptionAsNested()220 void addCurrentExceptionAsNested() { nested_.push_back(std::current_exception()); } 221 /*! \brief 222 * Adds the specified exception as a nested exception. 223 * 224 * May be called multiple times; all provided exceptions will be added 225 * in a list of nested exceptions. 226 * 227 * This is equivalent to throwing \p ex and calling 228 * addCurrentExceptionAsNested() in the catch block, but potentially 229 * more efficient. 230 */ 231 template<class Exception> addNested(const Exception & ex)232 void addNested(const Exception& ex) 233 { 234 nested_.push_back(std::make_exception_ptr(ex)); 235 } 236 237 private: 238 std::string reason_; 239 internal::NestedExceptionList nested_; 240 241 friend class GromacsException; 242 }; 243 244 /*! \brief 245 * Base class for all exception objects in Gromacs. 246 * 247 * \inpublicapi 248 */ 249 class GromacsException : public std::exception 250 { 251 public: 252 // Explicitly declared because some compiler/library combinations warn 253 // about missing noexcept otherwise. ~GromacsException()254 ~GromacsException() noexcept override {} 255 256 GromacsException() = default; 257 GromacsException(const GromacsException&) = default; 258 GromacsException(GromacsException&&) noexcept = default; 259 GromacsException& operator=(const GromacsException&) = default; 260 GromacsException& operator=(GromacsException&&) noexcept = default; 261 262 /*! \brief 263 * Returns the reason string for the exception. 264 * 265 * The return value is the string that was passed to the constructor. 266 */ 267 const char* what() const noexcept override; 268 /*! \brief 269 * Returns the error code corresponding to the exception type. 270 */ 271 virtual int errorCode() const = 0; 272 273 /*! \brief 274 * Returns the value associated with given ExceptionInfo. 275 * 276 * \tparam InfoType ExceptionInfo type to get the value for. 277 * \returns Value set for `InfoType`, or `nullptr` if such info has not 278 * been set. 279 * 280 * Does not throw. 281 */ 282 template<class InfoType> getInfo()283 const typename InfoType::value_type* getInfo() const 284 { 285 const internal::IExceptionInfo* item = getInfo(typeid(InfoType)); 286 if (item != nullptr) 287 { 288 GMX_ASSERT(dynamic_cast<const InfoType*>(item) != nullptr, 289 "Invalid exception info item found"); 290 return &static_cast<const InfoType*>(item)->value(); 291 } 292 return nullptr; 293 } 294 295 /*! \brief 296 * Associates extra information with the exception. 297 * 298 * \tparam Tag ExceptionInfo tag type. 299 * \tparam T ExceptionInfo value type. 300 * \param[in] item ExceptionInfo to associate. 301 * \throws std::bad_alloc if out of memory. 302 * \throws unspecified any exception thrown by `T` copy construction. 303 * 304 * If an item of this type is already associated, it is overwritten. 305 */ 306 template<class Tag, typename T> setInfo(const ExceptionInfo<Tag,T> & item)307 void setInfo(const ExceptionInfo<Tag, T>& item) 308 { 309 typedef ExceptionInfo<Tag, T> ItemType; 310 internal::ExceptionInfoPointer itemPtr(new ItemType(item)); 311 setInfo(typeid(ItemType), std::move(itemPtr)); 312 } 313 314 /*! \brief 315 * Adds context information to this exception. 316 * 317 * \param[in] context Context string to add. 318 * \throws std::bad_alloc if out of memory. 319 * 320 * Typical use is to add additional information higher up in the call 321 * stack using this function in a catch block and the rethrow the 322 * exception. 323 * 324 * \todo 325 * The added information is currently not accessible through what(), 326 * nor through any other means except for calling 327 * printFatalErrorMessage(), formatExceptionMessageToString() or 328 * formatExceptionMessageToFile(). See ExceptionInitializer for more 329 * discussion. 330 */ 331 void prependContext(const std::string& context); 332 333 protected: 334 /*! \brief 335 * Creates an exception object with the provided initializer/reason. 336 * 337 * \param[in] details Initializer for the exception. 338 * \throws std::bad_alloc if out of memory. 339 */ 340 explicit GromacsException(const ExceptionInitializer& details); 341 342 private: 343 const internal::IExceptionInfo* getInfo(const std::type_index& index) const; 344 void setInfo(const std::type_index& index, internal::ExceptionInfoPointer&& item); 345 346 std::shared_ptr<internal::ExceptionData> data_; 347 }; 348 349 /*! \brief 350 * Associates extra information with an exception. 351 * 352 * \tparam Exception Exception type (must be derived from GromacsException). 353 * \tparam Tag ExceptionInfo tag. 354 * \tparam T ExceptionInfo value type. 355 * \param[in,out] ex Exception to associate the information to. 356 * \param[in] item Information to associate. 357 * 358 * \internal 359 * The association is done with a templated non-member operator of exactly this 360 * form to make the simple syntax of GMX_THROW() possible. To support this, 361 * this operation needs to: 362 * - Allow setting information in a temporary to support 363 * `GMX_THROW(InvalidInputError(ex))`. 364 * - Return a copy of the same class it takes in. The compiler needs 365 * this information to throw the correct type of exception. This 366 * would be tedious to achieve with a member function (without a 367 * lot of code duplication). Generally, \c ex will be a temporary, 368 * copied twice and returned by value, which the compiler will 369 * typically elide away (and anyway performance is not important 370 * when throwing). We are not using the typical 371 * return-by-const-reference idiom for this operator so that 372 * tooling can reliably see that we are throwing by value. 373 * - Provide convenient syntax for adding multiple items. A non-member 374 * function that would require nested calls would look ugly for such cases. 375 * 376 * The reason for the enable_if is that this way, it does not conflict with 377 * other overloads of `operator<<` for ExceptionInfo objects, in case someone 378 * would like to declare those. But currently we do not have such overloads, so 379 * if the enable_if causes problems with some compilers, it can be removed. 380 * 381 * \todo Use std::is_base_of_v when CUDA 11 is a requirement. 382 */ 383 template<class Exception, class Tag, class T> 384 inline std::enable_if_t<std::is_base_of<GromacsException, Exception>::value, Exception> 385 operator<<(Exception ex, const ExceptionInfo<Tag, T>& item) 386 { 387 ex.setInfo(item); 388 return ex; 389 } 390 391 /*! \brief 392 * Exception class for file I/O errors. 393 * 394 * \inpublicapi 395 */ 396 class FileIOError : public GromacsException 397 { 398 public: 399 /*! \brief 400 * Creates an exception object with the provided initializer/reason. 401 * 402 * \param[in] details Initializer for the exception. 403 * \throws std::bad_alloc if out of memory. 404 * 405 * It is possible to call this constructor either with an explicit 406 * ExceptionInitializer object (useful for more complex cases), or 407 * a simple string if only a reason string needs to be provided. 408 */ FileIOError(const ExceptionInitializer & details)409 explicit FileIOError(const ExceptionInitializer& details) : GromacsException(details) {} 410 411 int errorCode() const override; 412 }; 413 414 /*! \brief 415 * Exception class for user input errors. 416 * 417 * Derived classes should be used to indicate the nature of the error instead 418 * of throwing this class directly. 419 * 420 * \inpublicapi 421 */ 422 class UserInputError : public GromacsException 423 { 424 protected: 425 //! \copydoc FileIOError::FileIOError() UserInputError(const ExceptionInitializer & details)426 explicit UserInputError(const ExceptionInitializer& details) : GromacsException(details) {} 427 }; 428 429 /*! \brief 430 * Exception class for situations where user input cannot be parsed/understood. 431 * 432 * \inpublicapi 433 */ 434 class InvalidInputError : public UserInputError 435 { 436 public: 437 //! \copydoc FileIOError::FileIOError() InvalidInputError(const ExceptionInitializer & details)438 explicit InvalidInputError(const ExceptionInitializer& details) : UserInputError(details) {} 439 440 int errorCode() const override; 441 }; 442 443 /*! \brief 444 * Exception class for situations where user input is inconsistent. 445 * 446 * \inpublicapi 447 */ 448 class InconsistentInputError : public UserInputError 449 { 450 public: 451 //! \copydoc FileIOError::FileIOError() InconsistentInputError(const ExceptionInitializer & details)452 explicit InconsistentInputError(const ExceptionInitializer& details) : UserInputError(details) 453 { 454 } 455 456 int errorCode() const override; 457 }; 458 459 /*! \brief 460 * Exception class when a specified tolerance cannot be achieved. 461 * 462 * \inpublicapi 463 */ 464 class ToleranceError : public GromacsException 465 { 466 public: 467 /*! \brief 468 * Creates an exception object with the provided initializer/reason. 469 * 470 * \param[in] details Initializer for the exception. 471 * \throws std::bad_alloc if out of memory. 472 * 473 * It is possible to call this constructor either with an explicit 474 * ExceptionInitializer object (useful for more complex cases), or 475 * a simple string if only a reason string needs to be provided. 476 */ ToleranceError(const ExceptionInitializer & details)477 explicit ToleranceError(const ExceptionInitializer& details) : GromacsException(details) {} 478 479 int errorCode() const override; 480 }; 481 482 /*! \brief 483 * Exception class for simulation instabilities. 484 * 485 * \inpublicapi 486 */ 487 class SimulationInstabilityError : public GromacsException 488 { 489 public: 490 //! \copydoc FileIOError::FileIOError() SimulationInstabilityError(const ExceptionInitializer & details)491 explicit SimulationInstabilityError(const ExceptionInitializer& details) : 492 GromacsException(details) 493 { 494 } 495 496 int errorCode() const override; 497 }; 498 499 /*! \brief 500 * Exception class for internal errors. 501 * 502 * \inpublicapi 503 */ 504 class InternalError : public GromacsException 505 { 506 public: 507 //! \copydoc FileIOError::FileIOError() InternalError(const ExceptionInitializer & details)508 explicit InternalError(const ExceptionInitializer& details) : GromacsException(details) {} 509 510 int errorCode() const override; 511 }; 512 513 /*! \brief 514 * Exception class for incorrect use of an API. 515 * 516 * \inpublicapi 517 */ 518 class APIError : public GromacsException 519 { 520 public: 521 //! \copydoc FileIOError::FileIOError() APIError(const ExceptionInitializer & details)522 explicit APIError(const ExceptionInitializer& details) : GromacsException(details) {} 523 524 int errorCode() const override; 525 }; 526 527 /*! \brief 528 * Exception class for out-of-range values or indices 529 * 530 * \inpublicapi 531 */ 532 class RangeError : public GromacsException 533 { 534 public: 535 //! \copydoc FileIOError::FileIOError() RangeError(const ExceptionInitializer & details)536 explicit RangeError(const ExceptionInitializer& details) : GromacsException(details) {} 537 538 int errorCode() const override; 539 }; 540 541 /*! \brief 542 * Exception class for use of an unimplemented feature. 543 * 544 * \inpublicapi 545 */ 546 class NotImplementedError : public APIError 547 { 548 public: 549 //! \copydoc FileIOError::FileIOError() NotImplementedError(const ExceptionInitializer & details)550 explicit NotImplementedError(const ExceptionInitializer& details) : APIError(details) {} 551 552 int errorCode() const override; 553 }; 554 555 /*! \brief Exception class for use when ensuring that MPI ranks to throw 556 * in a coordinated fashion. 557 * 558 * Generally all ranks that can throw would need to check for whether 559 * an exception has been caught, communicate whether any rank caught, 560 * then all throw one of these, with either a string that describes 561 * any exception caught on that rank, or a generic string. 562 * 563 * \inpublicapi 564 */ 565 class ParallelConsistencyError : public APIError 566 { 567 public: 568 //! \copydoc FileIOError::FileIOError() ParallelConsistencyError(const ExceptionInitializer & details)569 explicit ParallelConsistencyError(const ExceptionInitializer& details) : APIError(details) {} 570 571 int errorCode() const override; 572 }; 573 574 /*! \brief 575 * Exception class for modular simulator. 576 * 577 * \inpublicapi 578 */ 579 class ModularSimulatorError : public GromacsException 580 { 581 public: 582 //! \copydoc FileIOError::FileIOError() ModularSimulatorError(const ExceptionInitializer & details)583 explicit ModularSimulatorError(const ExceptionInitializer& details) : GromacsException(details) 584 { 585 } 586 587 [[nodiscard]] int errorCode() const override; 588 }; 589 590 /*! \brief 591 * Macro for throwing an exception. 592 * 593 * \param[in] e Exception object to throw. 594 * 595 * Using this macro instead of \c throw directly makes it possible to uniformly 596 * attach information into the exception objects. 597 * \p e should evaluate to an instance of an object derived from 598 * GromacsException. 599 * 600 * Basic usage: 601 * \code 602 if (value < 0) 603 { 604 GMX_THROW(InconsistentUserInput("Negative values not allowed for value")); 605 } 606 \endcode 607 */ 608 #define GMX_THROW(e) \ 609 throw(e) << gmx::ExceptionInfoLocation(gmx::ThrowLocation(GMX_CURRENT_FUNCTION, __FILE__, __LINE__)) 610 611 /*! \brief 612 * Macro for throwing an exception based on errno. 613 * 614 * \param[in] e Exception object to throw. 615 * \param[in] syscall Name of the syscall that returned the error. 616 * \param[in] err errno value returned by the syscall. 617 * 618 * This macro provides a convenience interface for throwing an exception to 619 * report an error based on a errno value. In addition to adding the necessary 620 * information to the exception object, the macro also ensures that \p errno is 621 * evaluated before, e.g., the constructor of \p e may call other functions 622 * that could overwrite the errno value. 623 * \p e should evaluate to an instance of an object derived from 624 * GromacsException. 625 * 626 * Typical usage (note that gmx::File wraps this particular case): 627 * \code 628 FILE *fp = fopen("filename.txt", "r"); 629 if (fp == NULL) 630 { 631 GMX_THROW(FileIOError("Could not open file"), "fopen", errno); 632 } 633 \endcode 634 */ 635 #define GMX_THROW_WITH_ERRNO(e, syscall, err) \ 636 do \ 637 { \ 638 int stored_errno_ = (err); \ 639 GMX_THROW((e) << gmx::ExceptionInfoErrno(stored_errno_) \ 640 << gmx::ExceptionInfoApiFunction(syscall)); \ 641 } while (0) 642 // TODO: Add an equivalent macro for Windows GetLastError 643 644 /*! \brief 645 * Formats a standard fatal error message for reporting an exception. 646 * 647 * \param[in] fp %File to format the message to. 648 * \param[in] ex Exception to format. 649 * 650 * Does not throw. If memory allocation fails or some other error occurs 651 * while formatting the error, tries to print a reasonable alternative message. 652 * 653 * Normal usage in Gromacs command-line programs is like this: 654 * \code 655 int main(int argc, char *argv[]) 656 { 657 gmx::init(&argc, &argv); 658 try 659 { 660 // The actual code for the program 661 return 0; 662 } 663 catch (const std::exception &ex) 664 { 665 gmx::printFatalErrorMessage(stderr, ex); 666 return gmx::processExceptionAtExit(ex); 667 } 668 } 669 \endcode 670 */ 671 void printFatalErrorMessage(FILE* fp, const std::exception& ex); 672 /*! \brief 673 * Formats an error message for reporting an exception. 674 * 675 * \param[in] ex Exception to format. 676 * \returns Formatted string containing details of \p ex. 677 * \throws std::bad_alloc if out of memory. 678 */ 679 std::string formatExceptionMessageToString(const std::exception& ex); 680 /*! \brief 681 * Formats an error message for reporting an exception. 682 * 683 * \param fp %File to write the message to. 684 * \param[in] ex Exception to format. 685 * \throws std::bad_alloc if out of memory. 686 */ 687 void formatExceptionMessageToFile(FILE* fp, const std::exception& ex); 688 /*! \brief 689 * Formats an error message for reporting an exception. 690 * 691 * \param writer Writer to use for writing the message. 692 * \param[in] ex Exception to format. 693 * \throws std::bad_alloc if out of memory. 694 */ 695 void formatExceptionMessageToWriter(TextWriter* writer, const std::exception& ex); 696 /*! \brief 697 * Handles an exception that is causing the program to terminate. 698 * 699 * \param[in] ex Exception that is the cause for terminating the program. 700 * \returns Return code to return from main(). 701 * 702 * This method should be called as the last thing before terminating the 703 * program because of an exception. It exists to terminate the program as 704 * gracefully as possible in the case of MPI processing (but the current 705 * implementation always calls MPI_Abort()). 706 * 707 * See printFatalErrorMessage() for example usage. 708 * 709 * Does not throw. 710 */ 711 int processExceptionAtExit(const std::exception& ex); 712 713 /*! \brief 714 * Helper function for terminating the program on an exception. 715 * 716 * \param[in] ex Exception that is the cause for terminating the program. 717 * 718 * Does not throw, and does not return. 719 */ 720 [[noreturn]] void processExceptionAsFatalError(const std::exception& ex); 721 722 /*! \brief 723 * Macro for catching exceptions at C++ -> C boundary. 724 * 725 * This macro is intended for uniform handling of exceptions when C++ code is 726 * called from C code within Gromacs. Since most existing code is written 727 * using the assumption that fatal errors terminate the program, this macro 728 * implements this behavior for exceptions. It should only be used in cases 729 * where the error cannot be propagated upwards using return values or such. 730 * 731 * Having this as a macro instead of having the same code in each place makes 732 * it easy to 1) find all such locations in the code, and 2) change the exact 733 * behavior if needed. 734 * 735 * Usage: 736 \code 737 try 738 { 739 // C++ code 740 } 741 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR; 742 \endcode 743 */ 744 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \ 745 catch (const std::exception& ex) { ::gmx::processExceptionAsFatalError(ex); } 746 747 //! \} 748 749 } // namespace gmx 750 751 #endif 752