xref: /llvm-project/flang/runtime/terminator.cpp (revision 4bdec5830bc398cecf6e775cc54d9dd511e6e237)
1 //===-- runtime/terminate.cpp ---------------------------------------------===//
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 #include "terminator.h"
10 #include <cstdio>
11 #include <cstdlib>
12 
13 namespace Fortran::runtime {
14 
15 #if !defined(RT_DEVICE_COMPILATION)
16 [[maybe_unused]] static void (*crashHandler)(
17     const char *, int, const char *, va_list &){nullptr};
18 
RegisterCrashHandler(void (* handler)(const char *,int,const char *,va_list &))19 void Terminator::RegisterCrashHandler(
20     void (*handler)(const char *, int, const char *, va_list &)) {
21   crashHandler = handler;
22 }
23 
InvokeCrashHandler(const char * message,...) const24 void Terminator::InvokeCrashHandler(const char *message, ...) const {
25   if (crashHandler) {
26     va_list ap;
27     va_start(ap, message);
28     crashHandler(sourceFileName_, sourceLine_, message, ap);
29     va_end(ap);
30   }
31 }
32 
CrashArgs(const char * message,va_list & ap) const33 [[noreturn]] void Terminator::CrashArgs(
34     const char *message, va_list &ap) const {
35   CrashHeader();
36   std::vfprintf(stderr, message, ap);
37   va_end(ap);
38   CrashFooter();
39 }
40 #endif
41 
42 RT_OFFLOAD_API_GROUP_BEGIN
43 
CrashHeader() const44 RT_API_ATTRS void Terminator::CrashHeader() const {
45 #if defined(RT_DEVICE_COMPILATION)
46   std::printf("\nfatal Fortran runtime error");
47   if (sourceFileName_) {
48     std::printf("(%s", sourceFileName_);
49     if (sourceLine_) {
50       std::printf(":%d", sourceLine_);
51     }
52     std::printf(")");
53   }
54   std::printf(": ");
55 #else
56   std::fputs("\nfatal Fortran runtime error", stderr);
57   if (sourceFileName_) {
58     std::fprintf(stderr, "(%s", sourceFileName_);
59     if (sourceLine_) {
60       std::fprintf(stderr, ":%d", sourceLine_);
61     }
62     fputc(')', stderr);
63   }
64   std::fputs(": ", stderr);
65 #endif
66 }
67 
CrashFooter() const68 [[noreturn]] RT_API_ATTRS void Terminator::CrashFooter() const {
69 #if defined(RT_DEVICE_COMPILATION)
70   std::printf("\n");
71 #else
72   fputc('\n', stderr);
73   // FIXME: re-enable the flush along with the IO enabling.
74   io::FlushOutputOnCrash(*this);
75 #endif
76   NotifyOtherImagesOfErrorTermination();
77 #if defined(RT_DEVICE_COMPILATION)
78 #if defined(__CUDACC__)
79   // NVCC supports __trap().
80   __trap();
81 #elif defined(__clang__)
82   // Clang supports __builtin_trap().
83   __builtin_trap();
84 #else
85 #error "unsupported compiler"
86 #endif
87 #else
88   std::abort();
89 #endif
90 }
91 
CheckFailed(const char * predicate,const char * file,int line) const92 [[noreturn]] RT_API_ATTRS void Terminator::CheckFailed(
93     const char *predicate, const char *file, int line) const {
94   Crash("Internal error: RUNTIME_CHECK(%s) failed at %s(%d)", predicate, file,
95       line);
96 }
97 
CheckFailed(const char * predicate) const98 [[noreturn]] RT_API_ATTRS void Terminator::CheckFailed(
99     const char *predicate) const {
100   Crash("Internal error: RUNTIME_CHECK(%s) failed at %s(%d)", predicate,
101       sourceFileName_, sourceLine_);
102 }
103 
104 // TODO: These will be defined in the coarray runtime library
NotifyOtherImagesOfNormalEnd()105 RT_API_ATTRS void NotifyOtherImagesOfNormalEnd() {}
NotifyOtherImagesOfFailImageStatement()106 RT_API_ATTRS void NotifyOtherImagesOfFailImageStatement() {}
NotifyOtherImagesOfErrorTermination()107 RT_API_ATTRS void NotifyOtherImagesOfErrorTermination() {}
108 
109 RT_OFFLOAD_API_GROUP_END
110 
111 } // namespace Fortran::runtime
112