1 //===-- runtime/terminator.h ------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // Termination of the image 10 11 #ifndef FORTRAN_RUNTIME_TERMINATOR_H_ 12 #define FORTRAN_RUNTIME_TERMINATOR_H_ 13 14 #include "flang/Common/api-attrs.h" 15 #include <cstdarg> 16 #include <cstdio> 17 #include <cstdlib> 18 19 namespace Fortran::runtime { 20 21 // A mixin class for statement-specific image error termination 22 // for errors detected in the runtime library 23 class Terminator { 24 public: Terminator()25 RT_API_ATTRS Terminator() {} 26 Terminator(const Terminator &) = default; 27 explicit RT_API_ATTRS Terminator( 28 const char *sourceFileName, int sourceLine = 0) 29 : sourceFileName_{sourceFileName}, sourceLine_{sourceLine} {} 30 sourceFileName()31 RT_API_ATTRS const char *sourceFileName() const { return sourceFileName_; } sourceLine()32 RT_API_ATTRS int sourceLine() const { return sourceLine_; } 33 34 RT_API_ATTRS void SetLocation( 35 const char *sourceFileName = nullptr, int sourceLine = 0) { 36 sourceFileName_ = sourceFileName; 37 sourceLine_ = sourceLine; 38 } 39 40 // Silence compiler warnings about the format string being 41 // non-literal. A more precise control would be 42 // __attribute__((format_arg(2))), but it requires the function 43 // to return 'char *', which does not work well with noreturn. 44 #if defined(__clang__) 45 #pragma clang diagnostic push 46 #pragma clang diagnostic ignored "-Wformat-security" 47 #elif defined(__GNUC__) 48 #pragma GCC diagnostic push 49 #pragma GCC diagnostic ignored "-Wformat-security" 50 #endif 51 52 // Device offload compilers do not normally support varargs and va_list, 53 // so use C++ variadic templates to forward the crash arguments 54 // to regular printf for the device compilation. 55 // Try to keep the inline implementations as small as possible. 56 template <typename... Args> Crash(const char * message,Args...args)57 [[noreturn]] RT_DEVICE_NOINLINE RT_API_ATTRS const char *Crash( 58 const char *message, Args... args) const { 59 #if !defined(RT_DEVICE_COMPILATION) 60 // Invoke handler set up by the test harness. 61 InvokeCrashHandler(message, args...); 62 #endif 63 CrashHeader(); 64 PrintCrashArgs(message, args...); 65 CrashFooter(); 66 } 67 68 template <typename... Args> PrintCrashArgs(const char * message,Args...args)69 RT_API_ATTRS void PrintCrashArgs(const char *message, Args... args) const { 70 #if defined(RT_DEVICE_COMPILATION) 71 std::printf(message, args...); 72 #else 73 std::fprintf(stderr, message, args...); 74 #endif 75 } 76 77 #if defined(__clang__) 78 #pragma clang diagnostic pop 79 #elif defined(__GNUC__) 80 #pragma GCC diagnostic pop 81 #endif 82 83 RT_API_ATTRS void CrashHeader() const; 84 [[noreturn]] RT_API_ATTRS void CrashFooter() const; 85 #if !defined(RT_DEVICE_COMPILATION) 86 void InvokeCrashHandler(const char *message, ...) const; 87 [[noreturn]] void CrashArgs(const char *message, va_list &) const; 88 #endif 89 [[noreturn]] RT_API_ATTRS void CheckFailed( 90 const char *predicate, const char *file, int line) const; 91 [[noreturn]] RT_API_ATTRS void CheckFailed(const char *predicate) const; 92 93 // For test harnessing - overrides CrashArgs(). 94 static void RegisterCrashHandler(void (*)(const char *sourceFile, 95 int sourceLine, const char *message, va_list &ap)); 96 97 private: 98 const char *sourceFileName_{nullptr}; 99 int sourceLine_{0}; 100 }; 101 102 // RUNTIME_CHECK() guarantees evaluation of its predicate. 103 #define RUNTIME_CHECK(terminator, pred) \ 104 if (pred) \ 105 ; \ 106 else \ 107 (terminator).CheckFailed(#pred, __FILE__, __LINE__) 108 109 #define INTERNAL_CHECK(pred) \ 110 if (pred) \ 111 ; \ 112 else \ 113 Terminator{__FILE__, __LINE__}.CheckFailed(#pred) 114 115 RT_API_ATTRS void NotifyOtherImagesOfNormalEnd(); 116 RT_API_ATTRS void NotifyOtherImagesOfFailImageStatement(); 117 RT_API_ATTRS void NotifyOtherImagesOfErrorTermination(); 118 } // namespace Fortran::runtime 119 120 namespace Fortran::runtime::io { 121 RT_API_ATTRS void FlushOutputOnCrash(const Terminator &); 122 } 123 124 #endif // FORTRAN_RUNTIME_TERMINATOR_H_ 125