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 | |
19 | void Terminator::RegisterCrashHandler( |
20 | void (*handler)(const char *, int, const char *, va_list &)) { |
21 | crashHandler = handler; |
22 | } |
23 | |
24 | 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 | |
33 | [[noreturn]] void Terminator::CrashArgs( |
34 | const char *message, va_list &ap) const { |
35 | CrashHeader(); |
36 | std::vfprintf(stderr, format: message, arg: ap); |
37 | va_end(ap); |
38 | CrashFooter(); |
39 | } |
40 | #endif |
41 | |
42 | RT_OFFLOAD_API_GROUP_BEGIN |
43 | |
44 | RT_API_ATTRS void Terminator::() 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(s: "\nfatal Fortran runtime error" , stderr); |
57 | if (sourceFileName_) { |
58 | std::fprintf(stderr, format: "(%s" , sourceFileName_); |
59 | if (sourceLine_) { |
60 | std::fprintf(stderr, format: ":%d" , sourceLine_); |
61 | } |
62 | fputc(c: ')', stderr); |
63 | } |
64 | std::fputs(s: ": " , stderr); |
65 | #endif |
66 | } |
67 | |
68 | [[noreturn]] RT_API_ATTRS void Terminator::() const { |
69 | #if defined(RT_DEVICE_COMPILATION) |
70 | std::printf("\n" ); |
71 | #else |
72 | fputc(c: '\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 | |
92 | [[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 | |
98 | [[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 |
105 | RT_API_ATTRS void NotifyOtherImagesOfNormalEnd() {} |
106 | RT_API_ATTRS void NotifyOtherImagesOfFailImageStatement() {} |
107 | RT_API_ATTRS void NotifyOtherImagesOfErrorTermination() {} |
108 | |
109 | RT_OFFLOAD_API_GROUP_END |
110 | |
111 | } // namespace Fortran::runtime |
112 | |