[flang] Accept polymorphic component element in storage_size
[llvm-project.git] / flang / runtime / io-error.cpp
blob790c579e1c43c07364458780dc622a266cdc4b2b
1 //===-- runtime/io-error.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 //===----------------------------------------------------------------------===//
9 #include "io-error.h"
10 #include "config.h"
11 #include "tools.h"
12 #include "flang/Runtime/magic-numbers.h"
13 #include <cerrno>
14 #include <cstdarg>
15 #include <cstdio>
16 #include <cstring>
18 namespace Fortran::runtime::io {
20 void IoErrorHandler::SignalError(int iostatOrErrno, const char *msg, ...) {
21 if (iostatOrErrno == IostatEnd && (flags_ & hasEnd)) {
22 if (ioStat_ == IostatOk || ioStat_ < IostatEnd) {
23 ioStat_ = IostatEnd;
25 } else if (iostatOrErrno == IostatEor && (flags_ & hasEor)) {
26 if (ioStat_ == IostatOk || ioStat_ < IostatEor) {
27 ioStat_ = IostatEor; // least priority
29 } else if (iostatOrErrno != IostatOk) {
30 if (flags_ & (hasIoStat | hasIoMsg | hasErr)) {
31 if (ioStat_ <= 0) {
32 ioStat_ = iostatOrErrno; // priority over END=/EOR=
33 if (msg && (flags_ & hasIoMsg)) {
34 char buffer[256];
35 va_list ap;
36 va_start(ap, msg);
37 std::vsnprintf(buffer, sizeof buffer, msg, ap);
38 ioMsg_ = SaveDefaultCharacter(buffer, std::strlen(buffer) + 1, *this);
39 va_end(ap);
42 } else if (msg) {
43 va_list ap;
44 va_start(ap, msg);
45 CrashArgs(msg, ap);
46 va_end(ap);
47 } else if (const char *errstr{IostatErrorString(iostatOrErrno)}) {
48 Crash(errstr);
49 } else {
50 Crash("I/O error (errno=%d): %s", iostatOrErrno,
51 std::strerror(iostatOrErrno));
56 void IoErrorHandler::SignalError(int iostatOrErrno) {
57 SignalError(iostatOrErrno, nullptr);
60 void IoErrorHandler::Forward(
61 int ioStatOrErrno, const char *msg, std::size_t length) {
62 if (ioStat_ != IostatOk && msg && (flags_ & hasIoMsg)) {
63 ioMsg_ = SaveDefaultCharacter(msg, length, *this);
65 if (ioStatOrErrno != IostatOk && msg) {
66 SignalError(ioStatOrErrno, "%.*s", static_cast<int>(length), msg);
67 } else {
68 SignalError(ioStatOrErrno);
72 void IoErrorHandler::SignalErrno() { SignalError(errno); }
74 void IoErrorHandler::SignalEnd() { SignalError(IostatEnd); }
76 void IoErrorHandler::SignalEor() { SignalError(IostatEor); }
78 void IoErrorHandler::SignalPendingError() {
79 int error{pendingError_};
80 pendingError_ = IostatOk;
81 SignalError(error);
84 bool IoErrorHandler::GetIoMsg(char *buffer, std::size_t bufferLength) {
85 const char *msg{ioMsg_.get()};
86 if (!msg) {
87 msg = IostatErrorString(ioStat_ == IostatOk ? pendingError_ : ioStat_);
89 if (msg) {
90 ToFortranDefaultCharacter(buffer, bufferLength, msg);
91 return true;
94 // Following code is taken from llvm/lib/Support/Errno.cpp
95 // in LLVM v9.0.1 with inadequate modification for Fortran,
96 // since rectified.
97 bool ok{false};
98 #if HAVE_STRERROR_R
99 // strerror_r is thread-safe.
100 #if defined(__GLIBC__) && defined(_GNU_SOURCE)
101 // glibc defines its own incompatible version of strerror_r
102 // which may not use the buffer supplied.
103 msg = ::strerror_r(ioStat_, buffer, bufferLength);
104 #else
105 ok = ::strerror_r(ioStat_, buffer, bufferLength) == 0;
106 #endif
107 #elif HAVE_DECL_STRERROR_S // "Windows Secure API"
108 ok = ::strerror_s(buffer, bufferLength, ioStat_) == 0;
109 #elif HAVE_STRERROR
110 // Copy the thread un-safe result of strerror into
111 // the buffer as fast as possible to minimize impact
112 // of collision of strerror in multiple threads.
113 msg = strerror(ioStat_);
114 #else
115 // Strange that this system doesn't even have strerror
116 return false;
117 #endif
118 if (msg) {
119 ToFortranDefaultCharacter(buffer, bufferLength, msg);
120 return true;
121 } else if (ok) {
122 std::size_t copied{std::strlen(buffer)};
123 if (copied < bufferLength) {
124 std::memset(buffer + copied, ' ', bufferLength - copied);
126 return true;
127 } else {
128 return false;
131 } // namespace Fortran::runtime::io