#ifndef FORTRAN_RUNTIME_TERMINATOR_H_
#define FORTRAN_RUNTIME_TERMINATOR_H_
#include "flang/Common/api-attrs.h"
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
namespace Fortran::runtime {
class Terminator {
public:
RT_API_ATTRS Terminator() {}
Terminator(const Terminator &) = default;
explicit RT_API_ATTRS Terminator(
const char *sourceFileName, int sourceLine = 0)
: sourceFileName_{sourceFileName}, sourceLine_{sourceLine} {}
RT_API_ATTRS const char *sourceFileName() const { return sourceFileName_; }
RT_API_ATTRS int sourceLine() const { return sourceLine_; }
RT_API_ATTRS void SetLocation(
const char *sourceFileName = nullptr, int sourceLine = 0) {
sourceFileName_ = sourceFileName;
sourceLine_ = sourceLine;
}
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-security"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-security"
#endif
template <typename... Args>
[[noreturn]] RT_DEVICE_NOINLINE RT_API_ATTRS const char *Crash(
const char *message, Args... args) const {
#if !defined(RT_DEVICE_COMPILATION)
InvokeCrashHandler(message, args...);
#endif
CrashHeader();
PrintCrashArgs(message, args...);
CrashFooter();
}
template <typename... Args>
RT_API_ATTRS void PrintCrashArgs(const char *message, Args... args) const {
#if defined(RT_DEVICE_COMPILATION)
std::printf(message, args...);
#else
std::fprintf(stderr, message, args...);
#endif
}
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
RT_API_ATTRS void CrashHeader() const;
[[noreturn]] RT_API_ATTRS void CrashFooter() const;
#if !defined(RT_DEVICE_COMPILATION)
void InvokeCrashHandler(const char *message, ...) const;
[[noreturn]] void CrashArgs(const char *message, va_list &) const;
#endif
[[noreturn]] RT_API_ATTRS void CheckFailed(
const char *predicate, const char *file, int line) const;
[[noreturn]] RT_API_ATTRS void CheckFailed(const char *predicate) const;
static void RegisterCrashHandler(void (*)(const char *sourceFile,
int sourceLine, const char *message, va_list &ap));
private:
const char *sourceFileName_{nullptr};
int sourceLine_{0};
};
#define RUNTIME_CHECK(terminator, pred) \
if (pred) \
; \
else \
(terminator).CheckFailed(#pred, __FILE__, __LINE__)
#define INTERNAL_CHECK(pred) \
if (pred) \
; \
else \
Terminator{__FILE__, __LINE__}.CheckFailed(#pred)
RT_API_ATTRS void NotifyOtherImagesOfNormalEnd();
RT_API_ATTRS void NotifyOtherImagesOfFailImageStatement();
RT_API_ATTRS void NotifyOtherImagesOfErrorTermination();
}
namespace Fortran::runtime::io {
RT_API_ATTRS void FlushOutputOnCrash(const Terminator &);
}
#endif