[flang-commits] [flang] [llvm] [flang-rt] Add fatal diagnostics with integer values (PR #231241)
via flang-commits
flang-commits at lists.llvm.org
Tue Oct 13 04:11:40 PDT 2026
https://github.com/jeanPerier updated https://github.com/llvm/llvm-project/pull/231241
>From 188058ef47c872f2b3975bbfca6d054eca7de7ae Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Mon, 12 Oct 2026 09:58:31 -0700
Subject: [PATCH 1/2] [flang-rt] Add fatal diagnostics with integer values
Add noreturn runtime entries for messages with integer diagnostic values.
Use a fixed four-value signature for small messages and a count-and-array
signature for larger payloads, keeping both callable from device code.
The array entry accepts the restricted %lld/%% format, checks argument
counts and allocation sizes, and preserves the existing source location,
crash handler, and termination behavior. Document the runtime interfaces
in the inline-check design and cover formatting and failures in unit tests.
---
flang-rt/lib/runtime/stop.cpp | 72 +++++++++++++++++++++++++
flang-rt/unittests/Runtime/Stop.cpp | 82 +++++++++++++++++++++++++++++
flang/docs/InlineRuntimeChecks.md | 26 +++++----
flang/include/flang/Runtime/stop.h | 17 ++++++
4 files changed, 187 insertions(+), 10 deletions(-)
diff --git a/flang-rt/lib/runtime/stop.cpp b/flang-rt/lib/runtime/stop.cpp
index b4508e0b7d0bc..b4179c38bd275 100644
--- a/flang-rt/lib/runtime/stop.cpp
+++ b/flang-rt/lib/runtime/stop.cpp
@@ -11,11 +11,15 @@
#include "flang-rt/runtime/environment.h"
#include "flang-rt/runtime/file.h"
#include "flang-rt/runtime/io-error.h"
+#include "flang-rt/runtime/memory.h"
#include "flang-rt/runtime/terminator.h"
#include "flang-rt/runtime/unit.h"
+#include "flang/Runtime/freestanding-tools.h"
#include <cfenv>
#include <cstdio>
#include <cstdlib>
+#include <cstring>
+#include <limits>
#ifdef HAVE_BACKTRACE
#include BACKTRACE_HEADER
@@ -249,4 +253,72 @@ RT_OPTNONE_ATTR void FORTRAN_PROCEDURE_NAME(backtrace)() { PrintBacktrace(); }
const char *message, const char *source, int line) {
Fortran::runtime::Terminator{source, line}.Crash(message);
}
+
+RT_OFFLOAD_API_GROUP_BEGIN
+[[noreturn]] RT_API_ATTRS void RTNAME(ReportFatalUserErrorValues)(
+ const char *message, const char *source, int line, long long v0,
+ long long v1, long long v2, long long v3) {
+ Fortran::runtime::Terminator{source, line}.Crash(message, v0, v1, v2, v3);
+}
+
+[[noreturn]] RT_API_ATTRS void RTNAME(ReportFatalUserErrorValueArray)(
+ const char *message, const char *source, int line, std::size_t count,
+ const long long *values) {
+ Fortran::runtime::Terminator terminator{source, line};
+ RUNTIME_CHECK(terminator, message && (count == 0 || values));
+
+ // Reserve enough space for every value, its sign, and the unchanged format.
+ // Allocation is confined to this fatal path, and no diagnostic is truncated.
+ constexpr std::size_t maxValueChars{
+ std::numeric_limits<unsigned long long>::digits10 + 2};
+ std::size_t messageLength{Fortran::runtime::strlen(message)};
+ if (messageLength == std::numeric_limits<std::size_t>::max() ||
+ count > (std::numeric_limits<std::size_t>::max() - messageLength - 1) /
+ maxValueChars) {
+ terminator.Crash("Fatal error message size overflow");
+ }
+ char *buffer{static_cast<char *>(Fortran::runtime::AllocateMemoryOrCrash(
+ terminator, messageLength + count * maxValueChars + 1))};
+ char *out{buffer};
+ std::size_t nextValue{0};
+ for (const char *p{message}; *p; ++p) {
+ if (*p != '%') {
+ *out++ = *p;
+ } else if (p[1] == '%') {
+ *out++ = '%';
+ ++p;
+ } else if (p[1] == 'l' && p[2] == 'l' && p[3] == 'd') {
+ if (nextValue == count) {
+ terminator.Crash("Fatal error message value count mismatch");
+ }
+ long long value{values[nextValue++]};
+ unsigned long long magnitude{static_cast<unsigned long long>(value)};
+ if (value < 0) {
+ *out++ = '-';
+ // Negate in unsigned arithmetic, including for the most negative value.
+ magnitude = -magnitude;
+ }
+ char digits[maxValueChars];
+ char *end{digits + sizeof digits}, *begin{end};
+ do {
+ *--begin = '0' + magnitude % 10;
+ magnitude /= 10;
+ } while (magnitude != 0);
+ std::size_t length{static_cast<std::size_t>(end - begin)};
+ Fortran::runtime::memcpy(out, begin, length);
+ out += length;
+ p += 3;
+ } else {
+ terminator.Crash("Invalid fatal error message format");
+ }
+ }
+ if (nextValue != count) {
+ terminator.Crash("Fatal error message value count mismatch");
+ }
+ *out = '\0';
+ // Keep both the standard diagnostic and the host crash-handler hook. The
+ // rendered percent signs are data, not additional format conversions.
+ terminator.Crash("%s", buffer);
+}
+RT_OFFLOAD_API_GROUP_END
}
diff --git a/flang-rt/unittests/Runtime/Stop.cpp b/flang-rt/unittests/Runtime/Stop.cpp
index 5c30f6c301cd3..c74b44aa4d68f 100644
--- a/flang-rt/unittests/Runtime/Stop.cpp
+++ b/flang-rt/unittests/Runtime/Stop.cpp
@@ -13,9 +13,11 @@
#include "flang/Runtime/stop.h"
#include "CrashHandlerFixture.h"
#include "flang-rt/runtime/environment.h"
+#include "flang-rt/runtime/terminator.h"
#include <cstdlib>
#include <cstring>
#include <gtest/gtest.h>
+#include <limits>
using namespace Fortran::runtime;
@@ -128,3 +130,83 @@ TEST_F(TestProgramEnd, CrashTest) {
RTNAME(ReportFatalUserError)(crashMessage.c_str(), fileName.c_str(), 343),
fullMessage.c_str());
}
+
+TEST_F(TestProgramEnd, CrashValuesTest) {
+ EXPECT_DEATH(
+ RTNAME(ReportFatalUserErrorValues)("sizes %lld, %lld, %lld, %lld %%",
+ "check.f90", 42, -17, 4294967296LL, 0, 9),
+ "check.f90\\(42\\): sizes -17, 4294967296, 0, 9 %");
+}
+
+TEST_F(TestProgramEnd, CrashValuesWithoutValuesTest) {
+ EXPECT_DEATH(RTNAME(ReportFatalUserErrorValues)(
+ "bad argument: 100%%", "check.f90", 7, 0, 0, 0, 0),
+ "check.f90\\(7\\): bad argument: 100%");
+}
+
+TEST_F(TestProgramEnd, CrashValueArrayTest) {
+ const long long values[]{std::numeric_limits<long long>::min(),
+ std::numeric_limits<long long>::max(), 0, -1, 4294967296LL, 17};
+ EXPECT_DEATH(
+ RTNAME(ReportFatalUserErrorValueArray)(
+ "%lld %lld %lld %lld %lld %%%lld %%lld", "check.f90", 43, 6, values),
+ "check.f90\\(43\\): -9223372036854775808 9223372036854775807 0 -1 "
+ "4294967296 %17 %lld");
+}
+
+TEST_F(TestProgramEnd, CrashValueArrayWithoutValuesTest) {
+ EXPECT_DEATH(RTNAME(ReportFatalUserErrorValueArray)(
+ "bad argument: 100%%", "check.f90", 7, 0, nullptr),
+ "check.f90\\(7\\): bad argument: 100%");
+ EXPECT_DEATH(
+ RTNAME(ReportFatalUserErrorValueArray)("", "check.f90", 7, 0, nullptr),
+ "check.f90\\(7\\): ");
+}
+
+TEST_F(TestProgramEnd, CrashValueArrayInvalidFormatTest) {
+ for (const char *message : {"%", "%l", "%ll", "%d", "%n", "%1$lld"}) {
+ EXPECT_DEATH(RTNAME(ReportFatalUserErrorValueArray)(
+ message, "check.f90", 7, 0, nullptr),
+ "Invalid fatal error message format");
+ }
+}
+
+TEST_F(TestProgramEnd, CrashValueArrayCountMismatchTest) {
+ const long long values[]{1, 2};
+ EXPECT_DEATH(RTNAME(ReportFatalUserErrorValueArray)(
+ "%lld %lld", "check.f90", 7, 1, values),
+ "Fatal error message value count mismatch");
+ EXPECT_DEATH(
+ RTNAME(ReportFatalUserErrorValueArray)("%lld", "check.f90", 7, 2, values),
+ "Fatal error message value count mismatch");
+ EXPECT_DEATH(RTNAME(ReportFatalUserErrorValueArray)(
+ "%lld", "check.f90", 7, 0, nullptr),
+ "Fatal error message value count mismatch");
+ EXPECT_DEATH(RTNAME(ReportFatalUserErrorValueArray)(
+ "%lld", "check.f90", 7, 1, nullptr),
+ "RUNTIME_CHECK");
+}
+
+TEST_F(TestProgramEnd, CrashValueArraySizeOverflowTest) {
+ const long long value{0};
+ EXPECT_DEATH(RTNAME(ReportFatalUserErrorValueArray)("%lld", "check.f90", 7,
+ std::numeric_limits<std::size_t>::max(), &value),
+ "Fatal error message size overflow");
+}
+
+TEST_F(TestProgramEnd, CrashValueArrayStandardDiagnosticTest) {
+ // The test crash handler truncates messages to 1000 characters. Exercise the
+ // actual runtime diagnostic, including its header and a much longer message.
+ std::string message(4096, 'x');
+ message += " %lld %lld %lld %lld %lld %%";
+ const long long values[]{-1, 0, 1, 2, 3};
+ EXPECT_DEATH(
+ {
+ Terminator::RegisterCrashHandler(nullptr);
+ RTNAME(ReportFatalUserErrorValueArray)(
+ message.c_str(), "check.f90", 99, 5, values);
+ },
+ ("fatal Fortran runtime error\\(check.f90:99\\): " +
+ std::string(4096, 'x') + " -1 0 1 2 3 %")
+ .c_str());
+}
diff --git a/flang/docs/InlineRuntimeChecks.md b/flang/docs/InlineRuntimeChecks.md
index 7a7e2892036cf..fa24ebc0f16ea 100644
--- a/flang/docs/InlineRuntimeChecks.md
+++ b/flang/docs/InlineRuntimeChecks.md
@@ -255,12 +255,17 @@ llvm.cond_br %ok weights([2000, 1]), ^cont, ^fail
- **Runtime entry.** `_FortranAReportFatalUserError(msg, source, line)`
(`flang/include/flang/Runtime/stop.h`) is `[[noreturn]]` and device-callable
- (`RT_API_ATTRS`). It takes no values. Proposed addition:
- `ReportFatalUserErrorValues(msg, source, line, v0..v3)` with a fixed
- number of `long long` arguments. That keeps the ABI simple on devices, and
- messages use `%lld` only (CUDA's device `printf` only documents the `h`,
- `l`, and `ll` length modifiers). The message is passed to `printf`, so a
- literal `%` in a message must be escaped.
+ (`RT_API_ATTRS`). It takes no values. Assertions with up to four values use
+ `ReportFatalUserErrorValues(msg, source, line, v0..v3)` with fixed
+ `long long` arguments, padding unused arguments with zeros. Assertions with
+ more values use `ReportFatalUserErrorValueArray(msg, source, line, count,
+ values)`, where `count` is a `size_t` and `values` points to an array of
+ `long long`. Code generation packs that array on the failure path; the
+ assertion's diagnostic operands remain SSA values until then. Both entries
+ have fixed signatures to keep the ABI simple on devices. Messages use only
+ `%lld` and `%%` (for a literal percent sign). The array entry formats these
+ directives before passing the completed message to the existing runtime
+ termination machinery.
- **Declaration.** The runtime function declaration must carry `noreturn`,
so LLVM can use the checked condition on the continuation path.
- **Source location.** Take it from the assert's own location. Resolve
@@ -778,10 +783,11 @@ elimination do not. The code generation pattern must work on unoptimized IR.
## 9. Open questions
-1. Message formatting: a fixed number of `long long` values, or a variadic
- runtime entry? Inline messages keep the runtime's text as closely as
- possible, and only differ where the inline check is stricter (per-dimension
- conformance, section 5.1).
+1. Diagnostic detail: report only the failing dimension, or include complete
+ shapes and subscript tuples? The fixed and count-and-array entries support
+ both. Inline messages keep the runtime's text as closely as possible, and
+ only differ where the inline check is stricter (per-dimension conformance,
+ section 5.1).
2. When a default-on kind (`conformance`, `argument`) is disabled by an
option, should its checks be emitted as assumptions (`llvm.intr.assume` at
code generation) instead of not at all? An assumption gives more
diff --git a/flang/include/flang/Runtime/stop.h b/flang/include/flang/Runtime/stop.h
index 710d75494c875..f310872778285 100644
--- a/flang/include/flang/Runtime/stop.h
+++ b/flang/include/flang/Runtime/stop.h
@@ -44,6 +44,23 @@ void FORTRAN_PROCEDURE_NAME(backtrace)(NO_ARGUMENTS);
NORETURN RT_API_ATTRS void RTNAME(ReportFatalUserError)(
const char *message, const char *source, int line);
+// The NUL-terminated message contains only %lld conversions and %% escapes.
+// A fixed argument list also permits calls from device code; unused values
+// are ignored.
+RT_OFFLOAD_API_GROUP_BEGIN
+NORETURN RT_API_ATTRS void RTNAME(ReportFatalUserErrorValues)(
+ const char *message, const char *source, int line, long long v0,
+ long long v1, long long v2, long long v3);
+
+// The same NUL-terminated restricted format with an arbitrary number of values.
+// The number of %lld conversions must equal count; values may be null when
+// count is zero. This fallback allocates its formatted message only on the
+// fatal path.
+NORETURN RT_API_ATTRS void RTNAME(ReportFatalUserErrorValueArray)(
+ const char *message, const char *source, int line, size_t count,
+ const long long *values);
+RT_OFFLOAD_API_GROUP_END
+
FORTRAN_EXTERN_C_END
#endif // FORTRAN_RUNTIME_STOP_H_
>From 9e47009cec87a333616a053b0a9624864a21af94 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Tue, 13 Oct 2026 01:53:49 -0700
Subject: [PATCH 2/2] [flang-rt] Preserve fatal diagnostics when allocation
fails
Validate the array-entry format and value count before printing error message.
Print the validated message in bounded pieces through the existing
termination helpers, avoiding allocation of a formatted message and the
custom decimal conversion. Concurrent failures may interleave their output.
Document the fixed-entry caller contract and mark all three fatal-error
entries for device compilation. Test large mismatched counts,
including long text and integer limits.
Check the real runtime diagnostic in the array-entry tests and remove the
allocation-failure regression and its static-runtime lit feature.
---
flang-rt/lib/runtime/stop.cpp | 87 ++++++++++++-----------------
flang-rt/unittests/Runtime/Stop.cpp | 29 +++++-----
flang/docs/InlineRuntimeChecks.md | 7 ++-
flang/include/flang/Runtime/stop.h | 15 ++---
4 files changed, 62 insertions(+), 76 deletions(-)
diff --git a/flang-rt/lib/runtime/stop.cpp b/flang-rt/lib/runtime/stop.cpp
index b4179c38bd275..561ea41642aaf 100644
--- a/flang-rt/lib/runtime/stop.cpp
+++ b/flang-rt/lib/runtime/stop.cpp
@@ -11,15 +11,11 @@
#include "flang-rt/runtime/environment.h"
#include "flang-rt/runtime/file.h"
#include "flang-rt/runtime/io-error.h"
-#include "flang-rt/runtime/memory.h"
#include "flang-rt/runtime/terminator.h"
#include "flang-rt/runtime/unit.h"
-#include "flang/Runtime/freestanding-tools.h"
#include <cfenv>
#include <cstdio>
#include <cstdlib>
-#include <cstring>
-#include <limits>
#ifdef HAVE_BACKTRACE
#include BACKTRACE_HEADER
@@ -249,12 +245,12 @@ static RT_NOINLINE_ATTR void PrintBacktrace() {
RT_OPTNONE_ATTR void FORTRAN_PROCEDURE_NAME(backtrace)() { PrintBacktrace(); }
+RT_EXT_API_GROUP_BEGIN
[[noreturn]] RT_API_ATTRS void RTNAME(ReportFatalUserError)(
const char *message, const char *source, int line) {
Fortran::runtime::Terminator{source, line}.Crash(message);
}
-RT_OFFLOAD_API_GROUP_BEGIN
[[noreturn]] RT_API_ATTRS void RTNAME(ReportFatalUserErrorValues)(
const char *message, const char *source, int line, long long v0,
long long v1, long long v2, long long v3) {
@@ -267,58 +263,47 @@ RT_OFFLOAD_API_GROUP_BEGIN
Fortran::runtime::Terminator terminator{source, line};
RUNTIME_CHECK(terminator, message && (count == 0 || values));
- // Reserve enough space for every value, its sign, and the unchanged format.
- // Allocation is confined to this fatal path, and no diagnostic is truncated.
- constexpr std::size_t maxValueChars{
- std::numeric_limits<unsigned long long>::digits10 + 2};
- std::size_t messageLength{Fortran::runtime::strlen(message)};
- if (messageLength == std::numeric_limits<std::size_t>::max() ||
- count > (std::numeric_limits<std::size_t>::max() - messageLength - 1) /
- maxValueChars) {
- terminator.Crash("Fatal error message size overflow");
+ // Validate the format and count before printing the diagnostic or reading
+ // values.
+ std::size_t conversions{0};
+ for (const char *p{message}; *p; ++p) {
+ if (*p == '%') {
+ if (p[1] == '%') {
+ ++p;
+ } else if (p[1] == 'l' && p[2] == 'l' && p[3] == 'd') {
+ ++conversions;
+ p += 3;
+ } else {
+ terminator.Crash("Invalid fatal error message format");
+ }
+ }
}
- char *buffer{static_cast<char *>(Fortran::runtime::AllocateMemoryOrCrash(
- terminator, messageLength + count * maxValueChars + 1))};
- char *out{buffer};
+ if (conversions != count) {
+ terminator.Crash("Fatal error message value count mismatch");
+ }
+
+ // Print in pieces so reporting the error does not require allocating a
+ // formatted message. Concurrent failures may interleave their output.
+ terminator.CrashHeader();
std::size_t nextValue{0};
- for (const char *p{message}; *p; ++p) {
+ for (const char *p{message}; *p;) {
if (*p != '%') {
- *out++ = *p;
- } else if (p[1] == '%') {
- *out++ = '%';
- ++p;
- } else if (p[1] == 'l' && p[2] == 'l' && p[3] == 'd') {
- if (nextValue == count) {
- terminator.Crash("Fatal error message value count mismatch");
- }
- long long value{values[nextValue++]};
- unsigned long long magnitude{static_cast<unsigned long long>(value)};
- if (value < 0) {
- *out++ = '-';
- // Negate in unsigned arithmetic, including for the most negative value.
- magnitude = -magnitude;
+ char chunk[256];
+ std::size_t length{0};
+ while (*p && *p != '%' && length < sizeof chunk - 1) {
+ chunk[length++] = *p++;
}
- char digits[maxValueChars];
- char *end{digits + sizeof digits}, *begin{end};
- do {
- *--begin = '0' + magnitude % 10;
- magnitude /= 10;
- } while (magnitude != 0);
- std::size_t length{static_cast<std::size_t>(end - begin)};
- Fortran::runtime::memcpy(out, begin, length);
- out += length;
- p += 3;
+ chunk[length] = '\0';
+ terminator.PrintCrashArgs("%s", chunk);
+ } else if (p[1] == '%') {
+ terminator.PrintCrashArgs("%%");
+ p += 2;
} else {
- terminator.Crash("Invalid fatal error message format");
+ terminator.PrintCrashArgs("%lld", values[nextValue++]);
+ p += 4;
}
}
- if (nextValue != count) {
- terminator.Crash("Fatal error message value count mismatch");
- }
- *out = '\0';
- // Keep both the standard diagnostic and the host crash-handler hook. The
- // rendered percent signs are data, not additional format conversions.
- terminator.Crash("%s", buffer);
+ terminator.CrashFooter();
}
-RT_OFFLOAD_API_GROUP_END
+RT_EXT_API_GROUP_END
}
diff --git a/flang-rt/unittests/Runtime/Stop.cpp b/flang-rt/unittests/Runtime/Stop.cpp
index c74b44aa4d68f..0facf6c8345a6 100644
--- a/flang-rt/unittests/Runtime/Stop.cpp
+++ b/flang-rt/unittests/Runtime/Stop.cpp
@@ -150,17 +150,18 @@ TEST_F(TestProgramEnd, CrashValueArrayTest) {
EXPECT_DEATH(
RTNAME(ReportFatalUserErrorValueArray)(
"%lld %lld %lld %lld %lld %%%lld %%lld", "check.f90", 43, 6, values),
- "check.f90\\(43\\): -9223372036854775808 9223372036854775807 0 -1 "
+ "fatal Fortran runtime error\\(check.f90:43\\): "
+ "-9223372036854775808 9223372036854775807 0 -1 "
"4294967296 %17 %lld");
}
TEST_F(TestProgramEnd, CrashValueArrayWithoutValuesTest) {
EXPECT_DEATH(RTNAME(ReportFatalUserErrorValueArray)(
"bad argument: 100%%", "check.f90", 7, 0, nullptr),
- "check.f90\\(7\\): bad argument: 100%");
+ "fatal Fortran runtime error\\(check.f90:7\\): bad argument: 100%");
EXPECT_DEATH(
RTNAME(ReportFatalUserErrorValueArray)("", "check.f90", 7, 0, nullptr),
- "check.f90\\(7\\): ");
+ "fatal Fortran runtime error\\(check.f90:7\\): ");
}
TEST_F(TestProgramEnd, CrashValueArrayInvalidFormatTest) {
@@ -187,25 +188,23 @@ TEST_F(TestProgramEnd, CrashValueArrayCountMismatchTest) {
"RUNTIME_CHECK");
}
-TEST_F(TestProgramEnd, CrashValueArraySizeOverflowTest) {
+TEST_F(TestProgramEnd, CrashValueArrayLargeCountMismatchTest) {
const long long value{0};
- EXPECT_DEATH(RTNAME(ReportFatalUserErrorValueArray)("%lld", "check.f90", 7,
- std::numeric_limits<std::size_t>::max(), &value),
- "Fatal error message size overflow");
+ for (std::size_t count : {std::numeric_limits<std::size_t>::max(),
+ std::numeric_limits<std::size_t>::max() / 64}) {
+ EXPECT_DEATH(RTNAME(ReportFatalUserErrorValueArray)(
+ "%lld", "check.f90", 7, count, &value),
+ "Fatal error message value count mismatch");
+ }
}
TEST_F(TestProgramEnd, CrashValueArrayStandardDiagnosticTest) {
- // The test crash handler truncates messages to 1000 characters. Exercise the
- // actual runtime diagnostic, including its header and a much longer message.
+ // A long literal must span several chunks without truncation.
std::string message(4096, 'x');
message += " %lld %lld %lld %lld %lld %%";
const long long values[]{-1, 0, 1, 2, 3};
- EXPECT_DEATH(
- {
- Terminator::RegisterCrashHandler(nullptr);
- RTNAME(ReportFatalUserErrorValueArray)(
- message.c_str(), "check.f90", 99, 5, values);
- },
+ EXPECT_DEATH(RTNAME(ReportFatalUserErrorValueArray)(
+ message.c_str(), "check.f90", 99, 5, values),
("fatal Fortran runtime error\\(check.f90:99\\): " +
std::string(4096, 'x') + " -1 0 1 2 3 %")
.c_str());
diff --git a/flang/docs/InlineRuntimeChecks.md b/flang/docs/InlineRuntimeChecks.md
index fa24ebc0f16ea..1d1d77bf924f4 100644
--- a/flang/docs/InlineRuntimeChecks.md
+++ b/flang/docs/InlineRuntimeChecks.md
@@ -263,9 +263,10 @@ llvm.cond_br %ok weights([2000, 1]), ^cont, ^fail
`long long`. Code generation packs that array on the failure path; the
assertion's diagnostic operands remain SSA values until then. Both entries
have fixed signatures to keep the ABI simple on devices. Messages use only
- `%lld` and `%%` (for a literal percent sign). The array entry formats these
- directives before passing the completed message to the existing runtime
- termination machinery.
+ `%lld` and `%%` (for a literal percent sign). The array entry prints the
+ diagnostic in pieces through the existing runtime termination machinery,
+ without allocating a formatted message. Concurrent failures may interleave
+ their output.
- **Declaration.** The runtime function declaration must carry `noreturn`,
so LLVM can use the checked condition on the continuation path.
- **Source location.** Take it from the assert's own location. Resolve
diff --git a/flang/include/flang/Runtime/stop.h b/flang/include/flang/Runtime/stop.h
index f310872778285..495dad06c4266 100644
--- a/flang/include/flang/Runtime/stop.h
+++ b/flang/include/flang/Runtime/stop.h
@@ -41,25 +41,26 @@ void FORTRAN_PROCEDURE_NAME(backtrace)(NO_ARGUMENTS);
// Crash with an error message when the program dynamically violates a Fortran
// constraint.
+RT_EXT_API_GROUP_BEGIN
NORETURN RT_API_ATTRS void RTNAME(ReportFatalUserError)(
const char *message, const char *source, int line);
-// The NUL-terminated message contains only %lld conversions and %% escapes.
-// A fixed argument list also permits calls from device code; unused values
-// are ignored.
-RT_OFFLOAD_API_GROUP_BEGIN
+// The caller must provide a NUL-terminated message containing at most four
+// %lld conversions, with any other percent signs escaped as %%. This contract
+// is not checked. A fixed argument list also permits calls from device code;
+// unused values are ignored.
NORETURN RT_API_ATTRS void RTNAME(ReportFatalUserErrorValues)(
const char *message, const char *source, int line, long long v0,
long long v1, long long v2, long long v3);
// The same NUL-terminated restricted format with an arbitrary number of values.
// The number of %lld conversions must equal count; values may be null when
-// count is zero. This fallback allocates its formatted message only on the
-// fatal path.
+// count is zero. The diagnostic is printed in pieces without allocating a
+// formatted message, so concurrent failures may interleave their output.
NORETURN RT_API_ATTRS void RTNAME(ReportFatalUserErrorValueArray)(
const char *message, const char *source, int line, size_t count,
const long long *values);
-RT_OFFLOAD_API_GROUP_END
+RT_EXT_API_GROUP_END
FORTRAN_EXTERN_C_END
More information about the flang-commits
mailing list