Skip to content

[ErrorHandling] Add reportFatalInternalError + reportFatalUsageError (NFC) #138251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

nikic
Copy link
Contributor

@nikic nikic commented May 2, 2025

This implements the result of the discussion at:
https://discourse.llvm.org/t/rfc-report-fatal-error-and-the-default-value-of-gencrashdialog/73587

There are two different use cases for report_fatal_error, so replace it with two functions reportFatalInternalError() and reportFatalUsageError(). The former indicates a bug in LLVM and generates a crash dialog. The latter does not. The names have been suggested by rnk and people seemed to like them.

This replaces a lot of the usages that passed an explicit value for GenCrashDiag. I did not bulk replace remaining report_fatal_error usage -- they probably require case by case review for which function to use.

…(NFC)

This implements the result of the discussion at:
https://discourse.llvm.org/t/rfc-report-fatal-error-and-the-default-value-of-gencrashdialog/73587

There are two different use cases for report_fatal_error, so
replace it with two functions reportFatalInternalError() and
reportFatalUsageError(). The former indicates a bug in LLVM and
generates a crash dialog. The latter does not. The names have been
suggested by rnk and people seemed to like them.

This replaces a lot of the usages that passed an explicit value
for GenCrashDiag. I did not bulk replace remaining report_fatal_error
usage.
@nikic nikic requested review from asb, rnk and arsenm May 2, 2025 11:09
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:AMDGPU backend:RISC-V clang:frontend Language frontend issues, e.g. anything involving "Sema" mlir llvm:instcombine backend:DirectX backend:SPIR-V LTO Link time optimization (regular/full LTO or ThinLTO) llvm:support backend:loongarch llvm:transforms labels May 2, 2025
@llvmbot
Copy link
Member

llvmbot commented May 2, 2025

@llvm/pr-subscribers-llvm-support
@llvm/pr-subscribers-mlir

@llvm/pr-subscribers-backend-amdgpu

Author: Nikita Popov (nikic)

Changes

This implements the result of the discussion at:
https://discourse.llvm.org/t/rfc-report-fatal-error-and-the-default-value-of-gencrashdialog/73587

There are two different use cases for report_fatal_error, so replace it with two functions reportFatalInternalError() and reportFatalUsageError(). The former indicates a bug in LLVM and generates a crash dialog. The latter does not. The names have been suggested by rnk and people seemed to like them.

This replaces a lot of the usages that passed an explicit value for GenCrashDiag. I did not bulk replace remaining report_fatal_error usage -- they probably require case by case review for which function to use.


Patch is 26.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138251.diff

27 Files Affected:

  • (modified) clang/lib/AST/ExternalASTSource.cpp (+1-1)
  • (modified) clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp (+1-1)
  • (modified) llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h (+2-2)
  • (modified) llvm/include/llvm/Passes/CodeGenPassBuilder.h (+1-1)
  • (modified) llvm/include/llvm/Support/Error.h (+9-2)
  • (modified) llvm/include/llvm/Support/ErrorHandling.h (+28-9)
  • (modified) llvm/lib/LTO/LTOBackend.cpp (+1-1)
  • (modified) llvm/lib/Support/Error.cpp (+7)
  • (modified) llvm/lib/Support/ErrorHandling.cpp (+19)
  • (modified) llvm/lib/Support/raw_ostream.cpp (+2-3)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp (+2-3)
  • (modified) llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp (+5-9)
  • (modified) llvm/lib/Target/DirectX/DXILOpBuilder.cpp (+2-3)
  • (modified) llvm/lib/Target/DirectX/DXILResourceAccess.cpp (+1-2)
  • (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+2-3)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp (+3-2)
  • (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+4-6)
  • (modified) llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp (+1-1)
  • (modified) llvm/lib/Transforms/IPO/BlockExtractor.cpp (+6-7)
  • (modified) llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp (+3-5)
  • (modified) llvm/lib/Transforms/InstCombine/InstructionCombining.cpp (+5-6)
  • (modified) llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp (+2-2)
  • (modified) llvm/lib/Transforms/Scalar/LICM.cpp (+2-4)
  • (modified) llvm/lib/Transforms/Scalar/LoopPassManager.cpp (+2-3)
  • (modified) llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp (+2-2)
  • (modified) llvm/tools/opt/optdriver.cpp (+1-1)
  • (modified) mlir/lib/TableGen/AttrOrTypeDef.cpp (+2-3)
diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp
index 3e865cb7679b5..e8c1004089713 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -129,7 +129,7 @@ uint32_t ExternalASTSource::incrementGeneration(ASTContext &C) {
     // FIXME: Only bump the generation counter if the current generation number
     // has been observed?
     if (!++CurrentGeneration)
-      llvm::report_fatal_error("generation counter overflowed", false);
+      llvm::reportFatalUsageError("generation counter overflowed");
   }
 
   return OldGeneration;
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index bdeaa2031d184..105b656c9dfad 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -1404,7 +1404,7 @@ int main(int Argc, char **Argv) {
   PassPlugins.setCallback([&](const std::string &PluginPath) {
     auto Plugin = PassPlugin::Load(PluginPath);
     if (!Plugin)
-      report_fatal_error(Plugin.takeError(), /*gen_crash_diag=*/false);
+      reportFatalUsageError(Plugin.takeError());
     PluginList.emplace_back(Plugin.get());
   });
   cl::ParseCommandLineOptions(NewArgv.size(), &NewArgv[0]);
diff --git a/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h b/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
index 7bb4420e555fb..ad399cd0b2f10 100644
--- a/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
+++ b/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
@@ -82,9 +82,9 @@ getEffectiveCodeModel(std::optional<CodeModel::Model> CM,
   if (CM) {
     // By default, targets do not support the tiny and kernel models.
     if (*CM == CodeModel::Tiny)
-      report_fatal_error("Target does not support the tiny CodeModel", false);
+      reportFatalUsageError("Target does not support the tiny CodeModel");
     if (*CM == CodeModel::Kernel)
-      report_fatal_error("Target does not support the kernel CodeModel", false);
+      reportFatalUsageError("Target does not support the kernel CodeModel");
     return *CM;
   }
   return Default;
diff --git a/llvm/include/llvm/Passes/CodeGenPassBuilder.h b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
index 80b74785473f7..6ed9ac47405d3 100644
--- a/llvm/include/llvm/Passes/CodeGenPassBuilder.h
+++ b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
@@ -1117,7 +1117,7 @@ void CodeGenPassBuilder<Derived, TargetMachineT>::addRegAllocPass(
       addPass(RAGreedyPass());
       break;
     default:
-      report_fatal_error("register allocator not supported yet", false);
+      reportFatalUsageError("register allocator not supported yet");
     }
     return;
   }
diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h
index f0580bdd50ee6..43deccb825347 100644
--- a/llvm/include/llvm/Support/Error.h
+++ b/llvm/include/llvm/Support/Error.h
@@ -735,10 +735,17 @@ template <class T> class [[nodiscard]] Expected {
 #endif
 };
 
-/// Report a serious error, calling any installed error handler. See
-/// ErrorHandling.h.
+/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
+/// instead.
 [[noreturn]] void report_fatal_error(Error Err, bool gen_crash_diag = true);
 
+/// Report a fatal error that indicates a bug in LLVM.
+/// See ErrorHandling.h for details.
+[[noreturn]] void reportFatalInternalError(Error Err);
+/// Report a fatal error that does not indicate a bug in LLVM.
+/// See ErrorHandling.h for details.
+[[noreturn]] void reportFatalUsageError(Error Err);
+
 /// Report a fatal error if Err is a failure value.
 ///
 /// This function can be used to wrap calls to fallible functions ONLY when it
diff --git a/llvm/include/llvm/Support/ErrorHandling.h b/llvm/include/llvm/Support/ErrorHandling.h
index 9c8e3448f3a03..16a5fc8ad4092 100644
--- a/llvm/include/llvm/Support/ErrorHandling.h
+++ b/llvm/include/llvm/Support/ErrorHandling.h
@@ -59,15 +59,8 @@ namespace llvm {
     ~ScopedFatalErrorHandler() { remove_fatal_error_handler(); }
   };
 
-/// Reports a serious error, calling any installed error handler. These
-/// functions are intended to be used for error conditions which are outside
-/// the control of the compiler (I/O errors, invalid user input, etc.)
-///
-/// If no error handler is installed the default is to print the message to
-/// standard error, followed by a newline.
-/// After the error handler is called this function will call abort(), it
-/// does not return.
-/// NOTE: The std::string variant was removed to avoid a <string> dependency.
+/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
+/// instead.
 [[noreturn]] void report_fatal_error(const char *reason,
                                      bool gen_crash_diag = true);
 [[noreturn]] void report_fatal_error(StringRef reason,
@@ -75,6 +68,32 @@ namespace llvm {
 [[noreturn]] void report_fatal_error(const Twine &reason,
                                      bool gen_crash_diag = true);
 
+/// Report a fatal error that likely indicates a bug in LLVM. It serves a
+/// similar purpose as an assertion, but is always enabled, regardless of the
+/// value of NDEBUG.
+///
+/// This will call installed error handlers (or print the message by default)
+/// and then abort. This will produce a crash trace and *will* ask users to
+/// report an LLVM bug.
+[[noreturn]] void reportFatalInternalError(const char *reason);
+[[noreturn]] void reportFatalInternalError(StringRef reason);
+[[noreturn]] void reportFatalInternalError(const Twine &reason);
+
+/// Report a fatal error that does not indicate a bug in LLVM, in contexts
+/// where a more sophisticated error reporting mechanism (such as Error/Expected
+/// or DiagnosticInfo) is not supported.
+///
+/// Examples where this function should be used include invalid inputs or
+/// options, but also environment error conditions outside LLVM's control.
+/// It should also be used for known unsupported/unimplemented functionality.
+///
+/// This will call installed error handlers (or print the message by default)
+/// and then exit with code 1. It will not produce a crash trace and will
+/// *not* ask users to report an LLVM bug.
+[[noreturn]] void reportFatalUsageError(const char *reason);
+[[noreturn]] void reportFatalUsageError(StringRef reason);
+[[noreturn]] void reportFatalUsageError(const Twine &reason);
+
 /// Installs a new bad alloc error handler that should be used whenever a
 /// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
 ///
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp
index dd9197efa7718..8a85ac835000a 100644
--- a/llvm/lib/LTO/LTOBackend.cpp
+++ b/llvm/lib/LTO/LTOBackend.cpp
@@ -195,7 +195,7 @@ static void RegisterPassPlugins(ArrayRef<std::string> PassPlugins,
   for (auto &PluginFN : PassPlugins) {
     auto PassPlugin = PassPlugin::Load(PluginFN);
     if (!PassPlugin)
-      report_fatal_error(PassPlugin.takeError(), /*gen_crash_diag=*/false);
+      reportFatalUsageError(PassPlugin.takeError());
     PassPlugin->registerPassBuilderCallbacks(PB);
   }
 }
diff --git a/llvm/lib/Support/Error.cpp b/llvm/lib/Support/Error.cpp
index baa3c322e9dae..d168b462a6eb2 100644
--- a/llvm/lib/Support/Error.cpp
+++ b/llvm/lib/Support/Error.cpp
@@ -174,6 +174,13 @@ void report_fatal_error(Error Err, bool GenCrashDiag) {
   report_fatal_error(Twine(ErrMsg), GenCrashDiag);
 }
 
+void reportFatalInternalError(Error Err) {
+  report_fatal_error(std::move(Err), /*GenCrashDiag=*/true);
+}
+void reportFatalUsageError(Error Err) {
+  report_fatal_error(std::move(Err), /*GenCrashDiag=*/false);
+}
+
 } // end namespace llvm
 
 LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err) {
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index afe3b37cc3431..cc16f2037ea58 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -126,6 +126,25 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
     exit(1);
 }
 
+void llvm::reportFatalInternalError(const char *reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/true);
+}
+void llvm::reportFatalInternalError(StringRef reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/true);
+}
+void llvm::reportFatalInternalError(const Twine &reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/true);
+}
+void llvm::reportFatalUsageError(const char *reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/false);
+}
+void llvm::reportFatalUsageError(StringRef reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/false);
+}
+void llvm::reportFatalUsageError(const Twine &reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/false);
+}
+
 void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler,
                                            void *user_data) {
 #if LLVM_ENABLE_THREADS == 1
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index e75ddc66b7d16..16631a63d1921 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -678,9 +678,8 @@ raw_fd_ostream::~raw_fd_ostream() {
   // has_error() and clear the error flag with clear_error() before
   // destructing raw_ostream objects which may have errors.
   if (has_error())
-    report_fatal_error(Twine("IO failure on output stream: ") +
-                           error().message(),
-                       /*gen_crash_diag=*/false);
+    reportFatalUsageError(Twine("IO failure on output stream: ") +
+                          error().message());
 }
 
 #if defined(_WIN32)
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
index 800e2b9c0e657..5e684a7c46568 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
@@ -163,9 +163,8 @@ void AMDGPUAsmPrinter::emitFunctionBodyStart() {
 
   // TODO: We're checking this late, would be nice to check it earlier.
   if (STM.requiresCodeObjectV6() && CodeObjectVersion < AMDGPU::AMDHSA_COV6) {
-    report_fatal_error(
-        STM.getCPU() + " is only available on code object version 6 or better",
-        /*gen_crash_diag*/ false);
+    reportFatalUsageError(
+        STM.getCPU() + " is only available on code object version 6 or better");
   }
 
   // TODO: Which one is called first, emitStartOfAsmFile or
diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
index 8ec5ed0e22974..6e8dc64643778 100644
--- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
+++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
@@ -138,8 +138,7 @@ static Value *expandCrossIntrinsic(CallInst *Orig) {
 
   VectorType *VT = cast<VectorType>(Orig->getType());
   if (cast<FixedVectorType>(VT)->getNumElements() != 3)
-    report_fatal_error(Twine("return vector must have exactly 3 elements"),
-                       /* gen_crash_diag=*/false);
+    reportFatalUsageError("return vector must have exactly 3 elements");
 
   Value *op0 = Orig->getOperand(0);
   Value *op1 = Orig->getOperand(1);
@@ -197,9 +196,8 @@ static Value *expandFloatDotIntrinsic(CallInst *Orig, Value *A, Value *B) {
     DotIntrinsic = Intrinsic::dx_dot4;
     break;
   default:
-    report_fatal_error(
-        Twine("Invalid dot product input vector: length is outside 2-4"),
-        /* gen_crash_diag=*/false);
+    reportFatalUsageError(
+        "Invalid dot product input vector: length is outside 2-4");
     return nullptr;
   }
 
@@ -359,8 +357,7 @@ static Value *expandNormalizeIntrinsic(CallInst *Orig) {
     if (auto *constantFP = dyn_cast<ConstantFP>(X)) {
       const APFloat &fpVal = constantFP->getValueAPF();
       if (fpVal.isZero())
-        report_fatal_error(Twine("Invalid input scalar: length is zero"),
-                           /* gen_crash_diag=*/false);
+        reportFatalUsageError"Invalid input scalar: length is zero");
     }
     return Builder.CreateFDiv(X, X);
   }
@@ -372,8 +369,7 @@ static Value *expandNormalizeIntrinsic(CallInst *Orig) {
   if (auto *constantFP = dyn_cast<ConstantFP>(DotProduct)) {
     const APFloat &fpVal = constantFP->getValueAPF();
     if (fpVal.isZero())
-      report_fatal_error(Twine("Invalid input vector: length is zero"),
-                         /* gen_crash_diag=*/false);
+      reportFatalUsageError("Invalid input vector: length is zero");
   }
 
   Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
index c92475fee2141..1aed8f9867231 100644
--- a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
@@ -478,10 +478,9 @@ DXILOpBuilder::DXILOpBuilder(Module &M) : M(M), IRB(M.getContext()) {
   ShaderStage = TT.getEnvironment();
   // Ensure Environment type is known
   if (ShaderStage == Triple::UnknownEnvironment) {
-    report_fatal_error(
+    reportFatalUsageError(
         Twine(DXILVersion.getAsString()) +
-            ": Unknown Compilation Target Shader Stage specified ",
-        /*gen_crash_diag*/ false);
+        ": Unknown Compilation Target Shader Stage specified ");
   }
 }
 
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index 16337f1237e00..566f3a98457a4 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -115,8 +115,7 @@ static void createStoreIntrinsic(IntrinsicInst *II, StoreInst *SI,
   case dxil::ResourceKind::TextureCubeArray:
   case dxil::ResourceKind::FeedbackTexture2D:
   case dxil::ResourceKind::FeedbackTexture2DArray:
-    report_fatal_error("DXIL Load not implemented yet",
-                       /*gen_crash_diag=*/false);
+    reportFatalUsageError("DXIL Load not implemented yet");
     return;
   case dxil::ResourceKind::CBuffer:
   case dxil::ResourceKind::Sampler:
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 1383302059910..1e2d752a02607 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -2486,8 +2486,7 @@ LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
   assert(N->getOffset() == 0 && "unexpected offset in global node");
 
   if (DAG.getTarget().useEmulatedTLS())
-    report_fatal_error("the emulated TLS is prohibited",
-                       /*GenCrashDiag=*/false);
+    reportFatalUsageError("the emulated TLS is prohibited");
 
   bool IsDesc = DAG.getTarget().useTLSDESC();
 
@@ -7122,4 +7121,4 @@ LoongArchTargetLowering::getPreferredVectorAction(MVT VT) const {
     return TypeWidenVector;
 
   return TargetLoweringBase::getPreferredVectorAction(VT);
-}
\ No newline at end of file
+}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
index 6d2659aa1236e..d407beffcd7d1 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
@@ -52,11 +52,12 @@ namespace RISCV {
 } // namespace RISCV
 
 // Report an error but don't ask the user to report a bug.
+// TODO: Remove these wrappers.
 [[noreturn]] static void reportError(const char *Reason) {
-  report_fatal_error(Reason, /*gen_crash_diag=*/false);
+  reportFatalUsageError(Reason);
 }
 [[noreturn]] static void reportError(Error Err) {
-  report_fatal_error(std::move(Err), /*gen_crash_diag=*/false);
+  reportFatalUsageError(std::move(Err));
 }
 
 namespace RISCVABI {
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 0d3003b59eeba..86f8873c135ef 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -21465,15 +21465,13 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
       report_fatal_error("'qci-*' interrupt kinds require Xqciint extension");
 
     if (Kind.starts_with("SiFive-CLIC-") && !Subtarget.hasVendorXSfmclic())
-      report_fatal_error(
-          "'SiFive-CLIC-*' interrupt kinds require XSfmclic extension",
-          /*gen_crash_diag=*/false);
+      reportFatalUsageError(
+          "'SiFive-CLIC-*' interrupt kinds require XSfmclic extension");
 
     const TargetFrameLowering *TFI = Subtarget.getFrameLowering();
     if (Kind.starts_with("SiFive-CLIC-preemptible") && TFI->hasFP(MF))
-      report_fatal_error("'SiFive-CLIC-preemptible' interrupt kinds cannot "
-                         "have a frame pointer",
-                         /*gen_crash_diag=*/false);
+      reportFatalUsageError("'SiFive-CLIC-preemptible' interrupt kinds cannot "
+                            "have a frame pointer");
   }
 
   EVT PtrVT = getPointerTy(DAG.getDataLayout());
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 31b8ffe4099a7..88b1e44d15af0 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -52,7 +52,7 @@ static unsigned typeToAddressSpace(const Type *Ty) {
   if (auto *ExtTy = dyn_cast<TargetExtType>(Ty);
       ExtTy && isTypedPointerWrapper(ExtTy))
     return ExtTy->getIntParameter(0);
-  report_fatal_error("Unable to convert LLVM type to SPIRVType", true);
+  reportFatalInternalError("Unable to convert LLVM type to SPIRVType");
 }
 
 #ifndef NDEBUG
diff --git a/llvm/lib/Transforms/IPO/BlockExtractor.cpp b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
index ec1be35a33164..44913533030e3 100644
--- a/llvm/lib/Transforms/IPO/BlockExtractor.cpp
+++ b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
@@ -80,8 +80,8 @@ void BlockExtractor::loadFile() {
     if (LineSplit.empty())
       continue;
     if (LineSplit.size()!=2)
-      report_fatal_error("Invalid line format, expecting lines like: 'funcname bb1[;bb2..]'",
-                         /*GenCrashDiag=*/false);
+      reportFatalUsageError(
+          "Invalid line format, expecting lines like: 'funcname bb1[;bb2..]'");
     SmallVector<StringRef, 4> BBNames;
     LineSplit[1].split(BBNames, ';', /*MaxSplit=*/-1,
                        /*KeepEmpty=*/false);
@@ -139,14 +139,13 @@ bool BlockExtractor::runOnModule(Module &M) {
   for (const auto &BInfo : BlocksByName) {
     Function *F = M.getFunction(BInfo.first);
     if (!F)
-      report_fatal_error("Invalid function name specified in the input file",
-                         /*GenCrashDiag=*/false);
+      reportFatalUsageError(
+          "Invalid function name specified in the input file");
     for (const auto &BBInfo : BInfo.second) {
       auto Res = llvm::find_if(
           *F, [&](const BasicBlock &BB) { return BB.getName() == BBInfo; });
       if (Res == F->end())
-        report_fatal_error("Invalid block name specified in the input file",
-                           /*GenCrashDiag=*/false);
+        reportFatalUsageError("Invalid block name specified in the input file");
       GroupsOfBlocks[NextGroupIdx].push_back(&*Res);
     }
     ++NextGroupIdx;
@@ -158,7 +157,7 @@ bool BlockExtractor::runOnModule(Module &M) {
     for (BasicBlock *BB : BBs) {
       // Check if the module contains BB.
       if (BB->getParent()->getParent() != &M)
-        report_fatal_error("Invalid basic block", /*GenCrashDiag=*/false);
+        reportFatalUsageError("Invalid basic block");
       LLVM_DEBUG(dbgs() << "BlockExtractor: Extracting "
                         << BB->getParent()->getName() << ":" << BB->getName()
                         << "\n");
diff --git a/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp b/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp
index 5950573173d74..73f567734a91b 100644
--- a/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp
+++ b/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp
@@ -24,14 +24,12 @@ using namespace llvm;
 
 PreservedAnalyses EmbedBitcodePass::run(Module &M, ModuleAnalysisManager &AM) {
   if (M.getGlobalVariable("llvm.embedded.module", /*AllowInternal=*/true))
-    report_fatal_error("Can only embed the module once",
-                       /*gen_crash_diag=*/false);
+    reportFatalUsageError("Can only embed the module once");
 
   Triple T(M.getTargetTriple());
   if (T.getObjectFormat() != Triple::ELF)
-    report_fatal_error(
-...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented May 2, 2025

@llvm/pr-subscribers-clang

Author: Nikita Popov (nikic)

Changes

This implements the result of the discussion at:
https://discourse.llvm.org/t/rfc-report-fatal-error-and-the-default-value-of-gencrashdialog/73587

There are two different use cases for report_fatal_error, so replace it with two functions reportFatalInternalError() and reportFatalUsageError(). The former indicates a bug in LLVM and generates a crash dialog. The latter does not. The names have been suggested by rnk and people seemed to like them.

This replaces a lot of the usages that passed an explicit value for GenCrashDiag. I did not bulk replace remaining report_fatal_error usage -- they probably require case by case review for which function to use.


Patch is 26.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138251.diff

27 Files Affected:

  • (modified) clang/lib/AST/ExternalASTSource.cpp (+1-1)
  • (modified) clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp (+1-1)
  • (modified) llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h (+2-2)
  • (modified) llvm/include/llvm/Passes/CodeGenPassBuilder.h (+1-1)
  • (modified) llvm/include/llvm/Support/Error.h (+9-2)
  • (modified) llvm/include/llvm/Support/ErrorHandling.h (+28-9)
  • (modified) llvm/lib/LTO/LTOBackend.cpp (+1-1)
  • (modified) llvm/lib/Support/Error.cpp (+7)
  • (modified) llvm/lib/Support/ErrorHandling.cpp (+19)
  • (modified) llvm/lib/Support/raw_ostream.cpp (+2-3)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp (+2-3)
  • (modified) llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp (+5-9)
  • (modified) llvm/lib/Target/DirectX/DXILOpBuilder.cpp (+2-3)
  • (modified) llvm/lib/Target/DirectX/DXILResourceAccess.cpp (+1-2)
  • (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+2-3)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp (+3-2)
  • (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+4-6)
  • (modified) llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp (+1-1)
  • (modified) llvm/lib/Transforms/IPO/BlockExtractor.cpp (+6-7)
  • (modified) llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp (+3-5)
  • (modified) llvm/lib/Transforms/InstCombine/InstructionCombining.cpp (+5-6)
  • (modified) llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp (+2-2)
  • (modified) llvm/lib/Transforms/Scalar/LICM.cpp (+2-4)
  • (modified) llvm/lib/Transforms/Scalar/LoopPassManager.cpp (+2-3)
  • (modified) llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp (+2-2)
  • (modified) llvm/tools/opt/optdriver.cpp (+1-1)
  • (modified) mlir/lib/TableGen/AttrOrTypeDef.cpp (+2-3)
diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp
index 3e865cb7679b5..e8c1004089713 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -129,7 +129,7 @@ uint32_t ExternalASTSource::incrementGeneration(ASTContext &C) {
     // FIXME: Only bump the generation counter if the current generation number
     // has been observed?
     if (!++CurrentGeneration)
-      llvm::report_fatal_error("generation counter overflowed", false);
+      llvm::reportFatalUsageError("generation counter overflowed");
   }
 
   return OldGeneration;
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index bdeaa2031d184..105b656c9dfad 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -1404,7 +1404,7 @@ int main(int Argc, char **Argv) {
   PassPlugins.setCallback([&](const std::string &PluginPath) {
     auto Plugin = PassPlugin::Load(PluginPath);
     if (!Plugin)
-      report_fatal_error(Plugin.takeError(), /*gen_crash_diag=*/false);
+      reportFatalUsageError(Plugin.takeError());
     PluginList.emplace_back(Plugin.get());
   });
   cl::ParseCommandLineOptions(NewArgv.size(), &NewArgv[0]);
diff --git a/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h b/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
index 7bb4420e555fb..ad399cd0b2f10 100644
--- a/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
+++ b/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
@@ -82,9 +82,9 @@ getEffectiveCodeModel(std::optional<CodeModel::Model> CM,
   if (CM) {
     // By default, targets do not support the tiny and kernel models.
     if (*CM == CodeModel::Tiny)
-      report_fatal_error("Target does not support the tiny CodeModel", false);
+      reportFatalUsageError("Target does not support the tiny CodeModel");
     if (*CM == CodeModel::Kernel)
-      report_fatal_error("Target does not support the kernel CodeModel", false);
+      reportFatalUsageError("Target does not support the kernel CodeModel");
     return *CM;
   }
   return Default;
diff --git a/llvm/include/llvm/Passes/CodeGenPassBuilder.h b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
index 80b74785473f7..6ed9ac47405d3 100644
--- a/llvm/include/llvm/Passes/CodeGenPassBuilder.h
+++ b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
@@ -1117,7 +1117,7 @@ void CodeGenPassBuilder<Derived, TargetMachineT>::addRegAllocPass(
       addPass(RAGreedyPass());
       break;
     default:
-      report_fatal_error("register allocator not supported yet", false);
+      reportFatalUsageError("register allocator not supported yet");
     }
     return;
   }
diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h
index f0580bdd50ee6..43deccb825347 100644
--- a/llvm/include/llvm/Support/Error.h
+++ b/llvm/include/llvm/Support/Error.h
@@ -735,10 +735,17 @@ template <class T> class [[nodiscard]] Expected {
 #endif
 };
 
-/// Report a serious error, calling any installed error handler. See
-/// ErrorHandling.h.
+/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
+/// instead.
 [[noreturn]] void report_fatal_error(Error Err, bool gen_crash_diag = true);
 
+/// Report a fatal error that indicates a bug in LLVM.
+/// See ErrorHandling.h for details.
+[[noreturn]] void reportFatalInternalError(Error Err);
+/// Report a fatal error that does not indicate a bug in LLVM.
+/// See ErrorHandling.h for details.
+[[noreturn]] void reportFatalUsageError(Error Err);
+
 /// Report a fatal error if Err is a failure value.
 ///
 /// This function can be used to wrap calls to fallible functions ONLY when it
diff --git a/llvm/include/llvm/Support/ErrorHandling.h b/llvm/include/llvm/Support/ErrorHandling.h
index 9c8e3448f3a03..16a5fc8ad4092 100644
--- a/llvm/include/llvm/Support/ErrorHandling.h
+++ b/llvm/include/llvm/Support/ErrorHandling.h
@@ -59,15 +59,8 @@ namespace llvm {
     ~ScopedFatalErrorHandler() { remove_fatal_error_handler(); }
   };
 
-/// Reports a serious error, calling any installed error handler. These
-/// functions are intended to be used for error conditions which are outside
-/// the control of the compiler (I/O errors, invalid user input, etc.)
-///
-/// If no error handler is installed the default is to print the message to
-/// standard error, followed by a newline.
-/// After the error handler is called this function will call abort(), it
-/// does not return.
-/// NOTE: The std::string variant was removed to avoid a <string> dependency.
+/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
+/// instead.
 [[noreturn]] void report_fatal_error(const char *reason,
                                      bool gen_crash_diag = true);
 [[noreturn]] void report_fatal_error(StringRef reason,
@@ -75,6 +68,32 @@ namespace llvm {
 [[noreturn]] void report_fatal_error(const Twine &reason,
                                      bool gen_crash_diag = true);
 
+/// Report a fatal error that likely indicates a bug in LLVM. It serves a
+/// similar purpose as an assertion, but is always enabled, regardless of the
+/// value of NDEBUG.
+///
+/// This will call installed error handlers (or print the message by default)
+/// and then abort. This will produce a crash trace and *will* ask users to
+/// report an LLVM bug.
+[[noreturn]] void reportFatalInternalError(const char *reason);
+[[noreturn]] void reportFatalInternalError(StringRef reason);
+[[noreturn]] void reportFatalInternalError(const Twine &reason);
+
+/// Report a fatal error that does not indicate a bug in LLVM, in contexts
+/// where a more sophisticated error reporting mechanism (such as Error/Expected
+/// or DiagnosticInfo) is not supported.
+///
+/// Examples where this function should be used include invalid inputs or
+/// options, but also environment error conditions outside LLVM's control.
+/// It should also be used for known unsupported/unimplemented functionality.
+///
+/// This will call installed error handlers (or print the message by default)
+/// and then exit with code 1. It will not produce a crash trace and will
+/// *not* ask users to report an LLVM bug.
+[[noreturn]] void reportFatalUsageError(const char *reason);
+[[noreturn]] void reportFatalUsageError(StringRef reason);
+[[noreturn]] void reportFatalUsageError(const Twine &reason);
+
 /// Installs a new bad alloc error handler that should be used whenever a
 /// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
 ///
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp
index dd9197efa7718..8a85ac835000a 100644
--- a/llvm/lib/LTO/LTOBackend.cpp
+++ b/llvm/lib/LTO/LTOBackend.cpp
@@ -195,7 +195,7 @@ static void RegisterPassPlugins(ArrayRef<std::string> PassPlugins,
   for (auto &PluginFN : PassPlugins) {
     auto PassPlugin = PassPlugin::Load(PluginFN);
     if (!PassPlugin)
-      report_fatal_error(PassPlugin.takeError(), /*gen_crash_diag=*/false);
+      reportFatalUsageError(PassPlugin.takeError());
     PassPlugin->registerPassBuilderCallbacks(PB);
   }
 }
diff --git a/llvm/lib/Support/Error.cpp b/llvm/lib/Support/Error.cpp
index baa3c322e9dae..d168b462a6eb2 100644
--- a/llvm/lib/Support/Error.cpp
+++ b/llvm/lib/Support/Error.cpp
@@ -174,6 +174,13 @@ void report_fatal_error(Error Err, bool GenCrashDiag) {
   report_fatal_error(Twine(ErrMsg), GenCrashDiag);
 }
 
+void reportFatalInternalError(Error Err) {
+  report_fatal_error(std::move(Err), /*GenCrashDiag=*/true);
+}
+void reportFatalUsageError(Error Err) {
+  report_fatal_error(std::move(Err), /*GenCrashDiag=*/false);
+}
+
 } // end namespace llvm
 
 LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err) {
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index afe3b37cc3431..cc16f2037ea58 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -126,6 +126,25 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
     exit(1);
 }
 
+void llvm::reportFatalInternalError(const char *reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/true);
+}
+void llvm::reportFatalInternalError(StringRef reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/true);
+}
+void llvm::reportFatalInternalError(const Twine &reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/true);
+}
+void llvm::reportFatalUsageError(const char *reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/false);
+}
+void llvm::reportFatalUsageError(StringRef reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/false);
+}
+void llvm::reportFatalUsageError(const Twine &reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/false);
+}
+
 void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler,
                                            void *user_data) {
 #if LLVM_ENABLE_THREADS == 1
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index e75ddc66b7d16..16631a63d1921 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -678,9 +678,8 @@ raw_fd_ostream::~raw_fd_ostream() {
   // has_error() and clear the error flag with clear_error() before
   // destructing raw_ostream objects which may have errors.
   if (has_error())
-    report_fatal_error(Twine("IO failure on output stream: ") +
-                           error().message(),
-                       /*gen_crash_diag=*/false);
+    reportFatalUsageError(Twine("IO failure on output stream: ") +
+                          error().message());
 }
 
 #if defined(_WIN32)
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
index 800e2b9c0e657..5e684a7c46568 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
@@ -163,9 +163,8 @@ void AMDGPUAsmPrinter::emitFunctionBodyStart() {
 
   // TODO: We're checking this late, would be nice to check it earlier.
   if (STM.requiresCodeObjectV6() && CodeObjectVersion < AMDGPU::AMDHSA_COV6) {
-    report_fatal_error(
-        STM.getCPU() + " is only available on code object version 6 or better",
-        /*gen_crash_diag*/ false);
+    reportFatalUsageError(
+        STM.getCPU() + " is only available on code object version 6 or better");
   }
 
   // TODO: Which one is called first, emitStartOfAsmFile or
diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
index 8ec5ed0e22974..6e8dc64643778 100644
--- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
+++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
@@ -138,8 +138,7 @@ static Value *expandCrossIntrinsic(CallInst *Orig) {
 
   VectorType *VT = cast<VectorType>(Orig->getType());
   if (cast<FixedVectorType>(VT)->getNumElements() != 3)
-    report_fatal_error(Twine("return vector must have exactly 3 elements"),
-                       /* gen_crash_diag=*/false);
+    reportFatalUsageError("return vector must have exactly 3 elements");
 
   Value *op0 = Orig->getOperand(0);
   Value *op1 = Orig->getOperand(1);
@@ -197,9 +196,8 @@ static Value *expandFloatDotIntrinsic(CallInst *Orig, Value *A, Value *B) {
     DotIntrinsic = Intrinsic::dx_dot4;
     break;
   default:
-    report_fatal_error(
-        Twine("Invalid dot product input vector: length is outside 2-4"),
-        /* gen_crash_diag=*/false);
+    reportFatalUsageError(
+        "Invalid dot product input vector: length is outside 2-4");
     return nullptr;
   }
 
@@ -359,8 +357,7 @@ static Value *expandNormalizeIntrinsic(CallInst *Orig) {
     if (auto *constantFP = dyn_cast<ConstantFP>(X)) {
       const APFloat &fpVal = constantFP->getValueAPF();
       if (fpVal.isZero())
-        report_fatal_error(Twine("Invalid input scalar: length is zero"),
-                           /* gen_crash_diag=*/false);
+        reportFatalUsageError"Invalid input scalar: length is zero");
     }
     return Builder.CreateFDiv(X, X);
   }
@@ -372,8 +369,7 @@ static Value *expandNormalizeIntrinsic(CallInst *Orig) {
   if (auto *constantFP = dyn_cast<ConstantFP>(DotProduct)) {
     const APFloat &fpVal = constantFP->getValueAPF();
     if (fpVal.isZero())
-      report_fatal_error(Twine("Invalid input vector: length is zero"),
-                         /* gen_crash_diag=*/false);
+      reportFatalUsageError("Invalid input vector: length is zero");
   }
 
   Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
index c92475fee2141..1aed8f9867231 100644
--- a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
@@ -478,10 +478,9 @@ DXILOpBuilder::DXILOpBuilder(Module &M) : M(M), IRB(M.getContext()) {
   ShaderStage = TT.getEnvironment();
   // Ensure Environment type is known
   if (ShaderStage == Triple::UnknownEnvironment) {
-    report_fatal_error(
+    reportFatalUsageError(
         Twine(DXILVersion.getAsString()) +
-            ": Unknown Compilation Target Shader Stage specified ",
-        /*gen_crash_diag*/ false);
+        ": Unknown Compilation Target Shader Stage specified ");
   }
 }
 
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index 16337f1237e00..566f3a98457a4 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -115,8 +115,7 @@ static void createStoreIntrinsic(IntrinsicInst *II, StoreInst *SI,
   case dxil::ResourceKind::TextureCubeArray:
   case dxil::ResourceKind::FeedbackTexture2D:
   case dxil::ResourceKind::FeedbackTexture2DArray:
-    report_fatal_error("DXIL Load not implemented yet",
-                       /*gen_crash_diag=*/false);
+    reportFatalUsageError("DXIL Load not implemented yet");
     return;
   case dxil::ResourceKind::CBuffer:
   case dxil::ResourceKind::Sampler:
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 1383302059910..1e2d752a02607 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -2486,8 +2486,7 @@ LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
   assert(N->getOffset() == 0 && "unexpected offset in global node");
 
   if (DAG.getTarget().useEmulatedTLS())
-    report_fatal_error("the emulated TLS is prohibited",
-                       /*GenCrashDiag=*/false);
+    reportFatalUsageError("the emulated TLS is prohibited");
 
   bool IsDesc = DAG.getTarget().useTLSDESC();
 
@@ -7122,4 +7121,4 @@ LoongArchTargetLowering::getPreferredVectorAction(MVT VT) const {
     return TypeWidenVector;
 
   return TargetLoweringBase::getPreferredVectorAction(VT);
-}
\ No newline at end of file
+}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
index 6d2659aa1236e..d407beffcd7d1 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
@@ -52,11 +52,12 @@ namespace RISCV {
 } // namespace RISCV
 
 // Report an error but don't ask the user to report a bug.
+// TODO: Remove these wrappers.
 [[noreturn]] static void reportError(const char *Reason) {
-  report_fatal_error(Reason, /*gen_crash_diag=*/false);
+  reportFatalUsageError(Reason);
 }
 [[noreturn]] static void reportError(Error Err) {
-  report_fatal_error(std::move(Err), /*gen_crash_diag=*/false);
+  reportFatalUsageError(std::move(Err));
 }
 
 namespace RISCVABI {
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 0d3003b59eeba..86f8873c135ef 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -21465,15 +21465,13 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
       report_fatal_error("'qci-*' interrupt kinds require Xqciint extension");
 
     if (Kind.starts_with("SiFive-CLIC-") && !Subtarget.hasVendorXSfmclic())
-      report_fatal_error(
-          "'SiFive-CLIC-*' interrupt kinds require XSfmclic extension",
-          /*gen_crash_diag=*/false);
+      reportFatalUsageError(
+          "'SiFive-CLIC-*' interrupt kinds require XSfmclic extension");
 
     const TargetFrameLowering *TFI = Subtarget.getFrameLowering();
     if (Kind.starts_with("SiFive-CLIC-preemptible") && TFI->hasFP(MF))
-      report_fatal_error("'SiFive-CLIC-preemptible' interrupt kinds cannot "
-                         "have a frame pointer",
-                         /*gen_crash_diag=*/false);
+      reportFatalUsageError("'SiFive-CLIC-preemptible' interrupt kinds cannot "
+                            "have a frame pointer");
   }
 
   EVT PtrVT = getPointerTy(DAG.getDataLayout());
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 31b8ffe4099a7..88b1e44d15af0 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -52,7 +52,7 @@ static unsigned typeToAddressSpace(const Type *Ty) {
   if (auto *ExtTy = dyn_cast<TargetExtType>(Ty);
       ExtTy && isTypedPointerWrapper(ExtTy))
     return ExtTy->getIntParameter(0);
-  report_fatal_error("Unable to convert LLVM type to SPIRVType", true);
+  reportFatalInternalError("Unable to convert LLVM type to SPIRVType");
 }
 
 #ifndef NDEBUG
diff --git a/llvm/lib/Transforms/IPO/BlockExtractor.cpp b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
index ec1be35a33164..44913533030e3 100644
--- a/llvm/lib/Transforms/IPO/BlockExtractor.cpp
+++ b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
@@ -80,8 +80,8 @@ void BlockExtractor::loadFile() {
     if (LineSplit.empty())
       continue;
     if (LineSplit.size()!=2)
-      report_fatal_error("Invalid line format, expecting lines like: 'funcname bb1[;bb2..]'",
-                         /*GenCrashDiag=*/false);
+      reportFatalUsageError(
+          "Invalid line format, expecting lines like: 'funcname bb1[;bb2..]'");
     SmallVector<StringRef, 4> BBNames;
     LineSplit[1].split(BBNames, ';', /*MaxSplit=*/-1,
                        /*KeepEmpty=*/false);
@@ -139,14 +139,13 @@ bool BlockExtractor::runOnModule(Module &M) {
   for (const auto &BInfo : BlocksByName) {
     Function *F = M.getFunction(BInfo.first);
     if (!F)
-      report_fatal_error("Invalid function name specified in the input file",
-                         /*GenCrashDiag=*/false);
+      reportFatalUsageError(
+          "Invalid function name specified in the input file");
     for (const auto &BBInfo : BInfo.second) {
       auto Res = llvm::find_if(
           *F, [&](const BasicBlock &BB) { return BB.getName() == BBInfo; });
       if (Res == F->end())
-        report_fatal_error("Invalid block name specified in the input file",
-                           /*GenCrashDiag=*/false);
+        reportFatalUsageError("Invalid block name specified in the input file");
       GroupsOfBlocks[NextGroupIdx].push_back(&*Res);
     }
     ++NextGroupIdx;
@@ -158,7 +157,7 @@ bool BlockExtractor::runOnModule(Module &M) {
     for (BasicBlock *BB : BBs) {
       // Check if the module contains BB.
       if (BB->getParent()->getParent() != &M)
-        report_fatal_error("Invalid basic block", /*GenCrashDiag=*/false);
+        reportFatalUsageError("Invalid basic block");
       LLVM_DEBUG(dbgs() << "BlockExtractor: Extracting "
                         << BB->getParent()->getName() << ":" << BB->getName()
                         << "\n");
diff --git a/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp b/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp
index 5950573173d74..73f567734a91b 100644
--- a/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp
+++ b/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp
@@ -24,14 +24,12 @@ using namespace llvm;
 
 PreservedAnalyses EmbedBitcodePass::run(Module &M, ModuleAnalysisManager &AM) {
   if (M.getGlobalVariable("llvm.embedded.module", /*AllowInternal=*/true))
-    report_fatal_error("Can only embed the module once",
-                       /*gen_crash_diag=*/false);
+    reportFatalUsageError("Can only embed the module once");
 
   Triple T(M.getTargetTriple());
   if (T.getObjectFormat() != Triple::ELF)
-    report_fatal_error(
-...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented May 2, 2025

@llvm/pr-subscribers-backend-risc-v

Author: Nikita Popov (nikic)

Changes

This implements the result of the discussion at:
https://discourse.llvm.org/t/rfc-report-fatal-error-and-the-default-value-of-gencrashdialog/73587

There are two different use cases for report_fatal_error, so replace it with two functions reportFatalInternalError() and reportFatalUsageError(). The former indicates a bug in LLVM and generates a crash dialog. The latter does not. The names have been suggested by rnk and people seemed to like them.

This replaces a lot of the usages that passed an explicit value for GenCrashDiag. I did not bulk replace remaining report_fatal_error usage -- they probably require case by case review for which function to use.


Patch is 26.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138251.diff

27 Files Affected:

  • (modified) clang/lib/AST/ExternalASTSource.cpp (+1-1)
  • (modified) clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp (+1-1)
  • (modified) llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h (+2-2)
  • (modified) llvm/include/llvm/Passes/CodeGenPassBuilder.h (+1-1)
  • (modified) llvm/include/llvm/Support/Error.h (+9-2)
  • (modified) llvm/include/llvm/Support/ErrorHandling.h (+28-9)
  • (modified) llvm/lib/LTO/LTOBackend.cpp (+1-1)
  • (modified) llvm/lib/Support/Error.cpp (+7)
  • (modified) llvm/lib/Support/ErrorHandling.cpp (+19)
  • (modified) llvm/lib/Support/raw_ostream.cpp (+2-3)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp (+2-3)
  • (modified) llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp (+5-9)
  • (modified) llvm/lib/Target/DirectX/DXILOpBuilder.cpp (+2-3)
  • (modified) llvm/lib/Target/DirectX/DXILResourceAccess.cpp (+1-2)
  • (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+2-3)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp (+3-2)
  • (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+4-6)
  • (modified) llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp (+1-1)
  • (modified) llvm/lib/Transforms/IPO/BlockExtractor.cpp (+6-7)
  • (modified) llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp (+3-5)
  • (modified) llvm/lib/Transforms/InstCombine/InstructionCombining.cpp (+5-6)
  • (modified) llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp (+2-2)
  • (modified) llvm/lib/Transforms/Scalar/LICM.cpp (+2-4)
  • (modified) llvm/lib/Transforms/Scalar/LoopPassManager.cpp (+2-3)
  • (modified) llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp (+2-2)
  • (modified) llvm/tools/opt/optdriver.cpp (+1-1)
  • (modified) mlir/lib/TableGen/AttrOrTypeDef.cpp (+2-3)
diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp
index 3e865cb7679b5..e8c1004089713 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -129,7 +129,7 @@ uint32_t ExternalASTSource::incrementGeneration(ASTContext &C) {
     // FIXME: Only bump the generation counter if the current generation number
     // has been observed?
     if (!++CurrentGeneration)
-      llvm::report_fatal_error("generation counter overflowed", false);
+      llvm::reportFatalUsageError("generation counter overflowed");
   }
 
   return OldGeneration;
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index bdeaa2031d184..105b656c9dfad 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -1404,7 +1404,7 @@ int main(int Argc, char **Argv) {
   PassPlugins.setCallback([&](const std::string &PluginPath) {
     auto Plugin = PassPlugin::Load(PluginPath);
     if (!Plugin)
-      report_fatal_error(Plugin.takeError(), /*gen_crash_diag=*/false);
+      reportFatalUsageError(Plugin.takeError());
     PluginList.emplace_back(Plugin.get());
   });
   cl::ParseCommandLineOptions(NewArgv.size(), &NewArgv[0]);
diff --git a/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h b/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
index 7bb4420e555fb..ad399cd0b2f10 100644
--- a/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
+++ b/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
@@ -82,9 +82,9 @@ getEffectiveCodeModel(std::optional<CodeModel::Model> CM,
   if (CM) {
     // By default, targets do not support the tiny and kernel models.
     if (*CM == CodeModel::Tiny)
-      report_fatal_error("Target does not support the tiny CodeModel", false);
+      reportFatalUsageError("Target does not support the tiny CodeModel");
     if (*CM == CodeModel::Kernel)
-      report_fatal_error("Target does not support the kernel CodeModel", false);
+      reportFatalUsageError("Target does not support the kernel CodeModel");
     return *CM;
   }
   return Default;
diff --git a/llvm/include/llvm/Passes/CodeGenPassBuilder.h b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
index 80b74785473f7..6ed9ac47405d3 100644
--- a/llvm/include/llvm/Passes/CodeGenPassBuilder.h
+++ b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
@@ -1117,7 +1117,7 @@ void CodeGenPassBuilder<Derived, TargetMachineT>::addRegAllocPass(
       addPass(RAGreedyPass());
       break;
     default:
-      report_fatal_error("register allocator not supported yet", false);
+      reportFatalUsageError("register allocator not supported yet");
     }
     return;
   }
diff --git a/llvm/include/llvm/Support/Error.h b/llvm/include/llvm/Support/Error.h
index f0580bdd50ee6..43deccb825347 100644
--- a/llvm/include/llvm/Support/Error.h
+++ b/llvm/include/llvm/Support/Error.h
@@ -735,10 +735,17 @@ template <class T> class [[nodiscard]] Expected {
 #endif
 };
 
-/// Report a serious error, calling any installed error handler. See
-/// ErrorHandling.h.
+/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
+/// instead.
 [[noreturn]] void report_fatal_error(Error Err, bool gen_crash_diag = true);
 
+/// Report a fatal error that indicates a bug in LLVM.
+/// See ErrorHandling.h for details.
+[[noreturn]] void reportFatalInternalError(Error Err);
+/// Report a fatal error that does not indicate a bug in LLVM.
+/// See ErrorHandling.h for details.
+[[noreturn]] void reportFatalUsageError(Error Err);
+
 /// Report a fatal error if Err is a failure value.
 ///
 /// This function can be used to wrap calls to fallible functions ONLY when it
diff --git a/llvm/include/llvm/Support/ErrorHandling.h b/llvm/include/llvm/Support/ErrorHandling.h
index 9c8e3448f3a03..16a5fc8ad4092 100644
--- a/llvm/include/llvm/Support/ErrorHandling.h
+++ b/llvm/include/llvm/Support/ErrorHandling.h
@@ -59,15 +59,8 @@ namespace llvm {
     ~ScopedFatalErrorHandler() { remove_fatal_error_handler(); }
   };
 
-/// Reports a serious error, calling any installed error handler. These
-/// functions are intended to be used for error conditions which are outside
-/// the control of the compiler (I/O errors, invalid user input, etc.)
-///
-/// If no error handler is installed the default is to print the message to
-/// standard error, followed by a newline.
-/// After the error handler is called this function will call abort(), it
-/// does not return.
-/// NOTE: The std::string variant was removed to avoid a <string> dependency.
+/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
+/// instead.
 [[noreturn]] void report_fatal_error(const char *reason,
                                      bool gen_crash_diag = true);
 [[noreturn]] void report_fatal_error(StringRef reason,
@@ -75,6 +68,32 @@ namespace llvm {
 [[noreturn]] void report_fatal_error(const Twine &reason,
                                      bool gen_crash_diag = true);
 
+/// Report a fatal error that likely indicates a bug in LLVM. It serves a
+/// similar purpose as an assertion, but is always enabled, regardless of the
+/// value of NDEBUG.
+///
+/// This will call installed error handlers (or print the message by default)
+/// and then abort. This will produce a crash trace and *will* ask users to
+/// report an LLVM bug.
+[[noreturn]] void reportFatalInternalError(const char *reason);
+[[noreturn]] void reportFatalInternalError(StringRef reason);
+[[noreturn]] void reportFatalInternalError(const Twine &reason);
+
+/// Report a fatal error that does not indicate a bug in LLVM, in contexts
+/// where a more sophisticated error reporting mechanism (such as Error/Expected
+/// or DiagnosticInfo) is not supported.
+///
+/// Examples where this function should be used include invalid inputs or
+/// options, but also environment error conditions outside LLVM's control.
+/// It should also be used for known unsupported/unimplemented functionality.
+///
+/// This will call installed error handlers (or print the message by default)
+/// and then exit with code 1. It will not produce a crash trace and will
+/// *not* ask users to report an LLVM bug.
+[[noreturn]] void reportFatalUsageError(const char *reason);
+[[noreturn]] void reportFatalUsageError(StringRef reason);
+[[noreturn]] void reportFatalUsageError(const Twine &reason);
+
 /// Installs a new bad alloc error handler that should be used whenever a
 /// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
 ///
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp
index dd9197efa7718..8a85ac835000a 100644
--- a/llvm/lib/LTO/LTOBackend.cpp
+++ b/llvm/lib/LTO/LTOBackend.cpp
@@ -195,7 +195,7 @@ static void RegisterPassPlugins(ArrayRef<std::string> PassPlugins,
   for (auto &PluginFN : PassPlugins) {
     auto PassPlugin = PassPlugin::Load(PluginFN);
     if (!PassPlugin)
-      report_fatal_error(PassPlugin.takeError(), /*gen_crash_diag=*/false);
+      reportFatalUsageError(PassPlugin.takeError());
     PassPlugin->registerPassBuilderCallbacks(PB);
   }
 }
diff --git a/llvm/lib/Support/Error.cpp b/llvm/lib/Support/Error.cpp
index baa3c322e9dae..d168b462a6eb2 100644
--- a/llvm/lib/Support/Error.cpp
+++ b/llvm/lib/Support/Error.cpp
@@ -174,6 +174,13 @@ void report_fatal_error(Error Err, bool GenCrashDiag) {
   report_fatal_error(Twine(ErrMsg), GenCrashDiag);
 }
 
+void reportFatalInternalError(Error Err) {
+  report_fatal_error(std::move(Err), /*GenCrashDiag=*/true);
+}
+void reportFatalUsageError(Error Err) {
+  report_fatal_error(std::move(Err), /*GenCrashDiag=*/false);
+}
+
 } // end namespace llvm
 
 LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err) {
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index afe3b37cc3431..cc16f2037ea58 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -126,6 +126,25 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
     exit(1);
 }
 
+void llvm::reportFatalInternalError(const char *reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/true);
+}
+void llvm::reportFatalInternalError(StringRef reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/true);
+}
+void llvm::reportFatalInternalError(const Twine &reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/true);
+}
+void llvm::reportFatalUsageError(const char *reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/false);
+}
+void llvm::reportFatalUsageError(StringRef reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/false);
+}
+void llvm::reportFatalUsageError(const Twine &reason) {
+  report_fatal_error(reason, /*GenCrashDiag=*/false);
+}
+
 void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler,
                                            void *user_data) {
 #if LLVM_ENABLE_THREADS == 1
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index e75ddc66b7d16..16631a63d1921 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -678,9 +678,8 @@ raw_fd_ostream::~raw_fd_ostream() {
   // has_error() and clear the error flag with clear_error() before
   // destructing raw_ostream objects which may have errors.
   if (has_error())
-    report_fatal_error(Twine("IO failure on output stream: ") +
-                           error().message(),
-                       /*gen_crash_diag=*/false);
+    reportFatalUsageError(Twine("IO failure on output stream: ") +
+                          error().message());
 }
 
 #if defined(_WIN32)
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
index 800e2b9c0e657..5e684a7c46568 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
@@ -163,9 +163,8 @@ void AMDGPUAsmPrinter::emitFunctionBodyStart() {
 
   // TODO: We're checking this late, would be nice to check it earlier.
   if (STM.requiresCodeObjectV6() && CodeObjectVersion < AMDGPU::AMDHSA_COV6) {
-    report_fatal_error(
-        STM.getCPU() + " is only available on code object version 6 or better",
-        /*gen_crash_diag*/ false);
+    reportFatalUsageError(
+        STM.getCPU() + " is only available on code object version 6 or better");
   }
 
   // TODO: Which one is called first, emitStartOfAsmFile or
diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
index 8ec5ed0e22974..6e8dc64643778 100644
--- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
+++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
@@ -138,8 +138,7 @@ static Value *expandCrossIntrinsic(CallInst *Orig) {
 
   VectorType *VT = cast<VectorType>(Orig->getType());
   if (cast<FixedVectorType>(VT)->getNumElements() != 3)
-    report_fatal_error(Twine("return vector must have exactly 3 elements"),
-                       /* gen_crash_diag=*/false);
+    reportFatalUsageError("return vector must have exactly 3 elements");
 
   Value *op0 = Orig->getOperand(0);
   Value *op1 = Orig->getOperand(1);
@@ -197,9 +196,8 @@ static Value *expandFloatDotIntrinsic(CallInst *Orig, Value *A, Value *B) {
     DotIntrinsic = Intrinsic::dx_dot4;
     break;
   default:
-    report_fatal_error(
-        Twine("Invalid dot product input vector: length is outside 2-4"),
-        /* gen_crash_diag=*/false);
+    reportFatalUsageError(
+        "Invalid dot product input vector: length is outside 2-4");
     return nullptr;
   }
 
@@ -359,8 +357,7 @@ static Value *expandNormalizeIntrinsic(CallInst *Orig) {
     if (auto *constantFP = dyn_cast<ConstantFP>(X)) {
       const APFloat &fpVal = constantFP->getValueAPF();
       if (fpVal.isZero())
-        report_fatal_error(Twine("Invalid input scalar: length is zero"),
-                           /* gen_crash_diag=*/false);
+        reportFatalUsageError"Invalid input scalar: length is zero");
     }
     return Builder.CreateFDiv(X, X);
   }
@@ -372,8 +369,7 @@ static Value *expandNormalizeIntrinsic(CallInst *Orig) {
   if (auto *constantFP = dyn_cast<ConstantFP>(DotProduct)) {
     const APFloat &fpVal = constantFP->getValueAPF();
     if (fpVal.isZero())
-      report_fatal_error(Twine("Invalid input vector: length is zero"),
-                         /* gen_crash_diag=*/false);
+      reportFatalUsageError("Invalid input vector: length is zero");
   }
 
   Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
index c92475fee2141..1aed8f9867231 100644
--- a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
@@ -478,10 +478,9 @@ DXILOpBuilder::DXILOpBuilder(Module &M) : M(M), IRB(M.getContext()) {
   ShaderStage = TT.getEnvironment();
   // Ensure Environment type is known
   if (ShaderStage == Triple::UnknownEnvironment) {
-    report_fatal_error(
+    reportFatalUsageError(
         Twine(DXILVersion.getAsString()) +
-            ": Unknown Compilation Target Shader Stage specified ",
-        /*gen_crash_diag*/ false);
+        ": Unknown Compilation Target Shader Stage specified ");
   }
 }
 
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index 16337f1237e00..566f3a98457a4 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -115,8 +115,7 @@ static void createStoreIntrinsic(IntrinsicInst *II, StoreInst *SI,
   case dxil::ResourceKind::TextureCubeArray:
   case dxil::ResourceKind::FeedbackTexture2D:
   case dxil::ResourceKind::FeedbackTexture2DArray:
-    report_fatal_error("DXIL Load not implemented yet",
-                       /*gen_crash_diag=*/false);
+    reportFatalUsageError("DXIL Load not implemented yet");
     return;
   case dxil::ResourceKind::CBuffer:
   case dxil::ResourceKind::Sampler:
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 1383302059910..1e2d752a02607 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -2486,8 +2486,7 @@ LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
   assert(N->getOffset() == 0 && "unexpected offset in global node");
 
   if (DAG.getTarget().useEmulatedTLS())
-    report_fatal_error("the emulated TLS is prohibited",
-                       /*GenCrashDiag=*/false);
+    reportFatalUsageError("the emulated TLS is prohibited");
 
   bool IsDesc = DAG.getTarget().useTLSDESC();
 
@@ -7122,4 +7121,4 @@ LoongArchTargetLowering::getPreferredVectorAction(MVT VT) const {
     return TypeWidenVector;
 
   return TargetLoweringBase::getPreferredVectorAction(VT);
-}
\ No newline at end of file
+}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
index 6d2659aa1236e..d407beffcd7d1 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
@@ -52,11 +52,12 @@ namespace RISCV {
 } // namespace RISCV
 
 // Report an error but don't ask the user to report a bug.
+// TODO: Remove these wrappers.
 [[noreturn]] static void reportError(const char *Reason) {
-  report_fatal_error(Reason, /*gen_crash_diag=*/false);
+  reportFatalUsageError(Reason);
 }
 [[noreturn]] static void reportError(Error Err) {
-  report_fatal_error(std::move(Err), /*gen_crash_diag=*/false);
+  reportFatalUsageError(std::move(Err));
 }
 
 namespace RISCVABI {
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 0d3003b59eeba..86f8873c135ef 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -21465,15 +21465,13 @@ SDValue RISCVTargetLowering::LowerFormalArguments(
       report_fatal_error("'qci-*' interrupt kinds require Xqciint extension");
 
     if (Kind.starts_with("SiFive-CLIC-") && !Subtarget.hasVendorXSfmclic())
-      report_fatal_error(
-          "'SiFive-CLIC-*' interrupt kinds require XSfmclic extension",
-          /*gen_crash_diag=*/false);
+      reportFatalUsageError(
+          "'SiFive-CLIC-*' interrupt kinds require XSfmclic extension");
 
     const TargetFrameLowering *TFI = Subtarget.getFrameLowering();
     if (Kind.starts_with("SiFive-CLIC-preemptible") && TFI->hasFP(MF))
-      report_fatal_error("'SiFive-CLIC-preemptible' interrupt kinds cannot "
-                         "have a frame pointer",
-                         /*gen_crash_diag=*/false);
+      reportFatalUsageError("'SiFive-CLIC-preemptible' interrupt kinds cannot "
+                            "have a frame pointer");
   }
 
   EVT PtrVT = getPointerTy(DAG.getDataLayout());
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 31b8ffe4099a7..88b1e44d15af0 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -52,7 +52,7 @@ static unsigned typeToAddressSpace(const Type *Ty) {
   if (auto *ExtTy = dyn_cast<TargetExtType>(Ty);
       ExtTy && isTypedPointerWrapper(ExtTy))
     return ExtTy->getIntParameter(0);
-  report_fatal_error("Unable to convert LLVM type to SPIRVType", true);
+  reportFatalInternalError("Unable to convert LLVM type to SPIRVType");
 }
 
 #ifndef NDEBUG
diff --git a/llvm/lib/Transforms/IPO/BlockExtractor.cpp b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
index ec1be35a33164..44913533030e3 100644
--- a/llvm/lib/Transforms/IPO/BlockExtractor.cpp
+++ b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
@@ -80,8 +80,8 @@ void BlockExtractor::loadFile() {
     if (LineSplit.empty())
       continue;
     if (LineSplit.size()!=2)
-      report_fatal_error("Invalid line format, expecting lines like: 'funcname bb1[;bb2..]'",
-                         /*GenCrashDiag=*/false);
+      reportFatalUsageError(
+          "Invalid line format, expecting lines like: 'funcname bb1[;bb2..]'");
     SmallVector<StringRef, 4> BBNames;
     LineSplit[1].split(BBNames, ';', /*MaxSplit=*/-1,
                        /*KeepEmpty=*/false);
@@ -139,14 +139,13 @@ bool BlockExtractor::runOnModule(Module &M) {
   for (const auto &BInfo : BlocksByName) {
     Function *F = M.getFunction(BInfo.first);
     if (!F)
-      report_fatal_error("Invalid function name specified in the input file",
-                         /*GenCrashDiag=*/false);
+      reportFatalUsageError(
+          "Invalid function name specified in the input file");
     for (const auto &BBInfo : BInfo.second) {
       auto Res = llvm::find_if(
           *F, [&](const BasicBlock &BB) { return BB.getName() == BBInfo; });
       if (Res == F->end())
-        report_fatal_error("Invalid block name specified in the input file",
-                           /*GenCrashDiag=*/false);
+        reportFatalUsageError("Invalid block name specified in the input file");
       GroupsOfBlocks[NextGroupIdx].push_back(&*Res);
     }
     ++NextGroupIdx;
@@ -158,7 +157,7 @@ bool BlockExtractor::runOnModule(Module &M) {
     for (BasicBlock *BB : BBs) {
       // Check if the module contains BB.
       if (BB->getParent()->getParent() != &M)
-        report_fatal_error("Invalid basic block", /*GenCrashDiag=*/false);
+        reportFatalUsageError("Invalid basic block");
       LLVM_DEBUG(dbgs() << "BlockExtractor: Extracting "
                         << BB->getParent()->getName() << ":" << BB->getName()
                         << "\n");
diff --git a/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp b/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp
index 5950573173d74..73f567734a91b 100644
--- a/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp
+++ b/llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp
@@ -24,14 +24,12 @@ using namespace llvm;
 
 PreservedAnalyses EmbedBitcodePass::run(Module &M, ModuleAnalysisManager &AM) {
   if (M.getGlobalVariable("llvm.embedded.module", /*AllowInternal=*/true))
-    report_fatal_error("Can only embed the module once",
-                       /*gen_crash_diag=*/false);
+    reportFatalUsageError("Can only embed the module once");
 
   Triple T(M.getTargetTriple());
   if (T.getObjectFormat() != Triple::ELF)
-    report_fatal_error(
-...
[truncated]

Copy link

github-actions bot commented May 2, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff HEAD~1 HEAD --extensions cpp,h -- clang/lib/AST/ExternalASTSource.cpp clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h llvm/include/llvm/Passes/CodeGenPassBuilder.h llvm/include/llvm/Support/Error.h llvm/include/llvm/Support/ErrorHandling.h llvm/lib/LTO/LTOBackend.cpp llvm/lib/Support/Error.cpp llvm/lib/Support/ErrorHandling.cpp llvm/lib/Support/raw_ostream.cpp llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp llvm/lib/Target/DirectX/DXILOpBuilder.cpp llvm/lib/Target/DirectX/DXILResourceAccess.cpp llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp llvm/lib/Target/RISCV/RISCVISelLowering.cpp llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp llvm/lib/Transforms/IPO/BlockExtractor.cpp llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp llvm/lib/Transforms/InstCombine/InstructionCombining.cpp llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp llvm/lib/Transforms/Scalar/LICM.cpp llvm/lib/Transforms/Scalar/LoopPassManager.cpp llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp llvm/tools/opt/optdriver.cpp mlir/lib/TableGen/AttrOrTypeDef.cpp
View the diff from clang-format here.
diff --git a/llvm/include/llvm/Support/ErrorHandling.h b/llvm/include/llvm/Support/ErrorHandling.h
index 85daaee10..d266da60a 100644
--- a/llvm/include/llvm/Support/ErrorHandling.h
+++ b/llvm/include/llvm/Support/ErrorHandling.h
@@ -59,89 +59,89 @@ namespace llvm {
     ~ScopedFatalErrorHandler() { remove_fatal_error_handler(); }
   };
 
-/// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
-/// instead.
-[[noreturn]] void report_fatal_error(const char *reason,
-                                     bool gen_crash_diag = true);
-[[noreturn]] void report_fatal_error(StringRef reason,
-                                     bool gen_crash_diag = true);
-[[noreturn]] void report_fatal_error(const Twine &reason,
-                                     bool gen_crash_diag = true);
-
-/// Report a fatal error that likely indicates a bug in LLVM. It serves a
-/// similar purpose as an assertion, but is always enabled, regardless of the
-/// value of NDEBUG.
-///
-/// This will call installed error handlers (or print the message by default)
-/// and then abort. This will produce a crash trace and *will* ask users to
-/// report an LLVM bug.
-[[noreturn]] void reportFatalInternalError(const char *reason);
-[[noreturn]] void reportFatalInternalError(StringRef reason);
-[[noreturn]] void reportFatalInternalError(const Twine &reason);
-
-/// Report a fatal error that does not indicate a bug in LLVM.
-///
-/// This can be used in contexts where a proper error reporting mechanism
-/// (such as Error/Expected or DiagnosticInfo) is currently not supported, and
-/// would be too involved to introduce at the moment.
-///
-/// Examples where this function should be used instead of
-/// reportFatalInternalError() include invalid inputs or options, but also
-/// environment error conditions outside LLVM's control. It should also be used
-/// for known unsupported/unimplemented functionality.
-///
-/// This will call installed error handlers (or print the message by default)
-/// and then exit with code 1. It will not produce a crash trace and will
-/// *not* ask users to report an LLVM bug.
-[[noreturn]] void reportFatalUsageError(const char *reason);
-[[noreturn]] void reportFatalUsageError(StringRef reason);
-[[noreturn]] void reportFatalUsageError(const Twine &reason);
-
-/// Installs a new bad alloc error handler that should be used whenever a
-/// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
-///
-/// The user can install a bad alloc handler, in order to define the behavior
-/// in case of failing allocations, e.g. throwing an exception. Note that this
-/// handler must not trigger any additional allocations itself.
-///
-/// If no error handler is installed the default is to print the error message
-/// to stderr, and call exit(1).  If an error handler is installed then it is
-/// the handler's responsibility to log the message, it will no longer be
-/// printed to stderr.  If the error handler returns, then exit(1) will be
-/// called.
-///
-///
-/// \param user_data - An argument which will be passed to the installed error
-/// handler.
-void install_bad_alloc_error_handler(fatal_error_handler_t handler,
-                                     void *user_data = nullptr);
+  /// @deprecated Use reportFatalInternalError() or reportFatalUsageError()
+  /// instead.
+  [[noreturn]] void report_fatal_error(const char *reason,
+                                       bool gen_crash_diag = true);
+  [[noreturn]] void report_fatal_error(StringRef reason,
+                                       bool gen_crash_diag = true);
+  [[noreturn]] void report_fatal_error(const Twine &reason,
+                                       bool gen_crash_diag = true);
+
+  /// Report a fatal error that likely indicates a bug in LLVM. It serves a
+  /// similar purpose as an assertion, but is always enabled, regardless of the
+  /// value of NDEBUG.
+  ///
+  /// This will call installed error handlers (or print the message by default)
+  /// and then abort. This will produce a crash trace and *will* ask users to
+  /// report an LLVM bug.
+  [[noreturn]] void reportFatalInternalError(const char *reason);
+  [[noreturn]] void reportFatalInternalError(StringRef reason);
+  [[noreturn]] void reportFatalInternalError(const Twine &reason);
+
+  /// Report a fatal error that does not indicate a bug in LLVM.
+  ///
+  /// This can be used in contexts where a proper error reporting mechanism
+  /// (such as Error/Expected or DiagnosticInfo) is currently not supported, and
+  /// would be too involved to introduce at the moment.
+  ///
+  /// Examples where this function should be used instead of
+  /// reportFatalInternalError() include invalid inputs or options, but also
+  /// environment error conditions outside LLVM's control. It should also be
+  /// used for known unsupported/unimplemented functionality.
+  ///
+  /// This will call installed error handlers (or print the message by default)
+  /// and then exit with code 1. It will not produce a crash trace and will
+  /// *not* ask users to report an LLVM bug.
+  [[noreturn]] void reportFatalUsageError(const char *reason);
+  [[noreturn]] void reportFatalUsageError(StringRef reason);
+  [[noreturn]] void reportFatalUsageError(const Twine &reason);
+
+  /// Installs a new bad alloc error handler that should be used whenever a
+  /// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
+  ///
+  /// The user can install a bad alloc handler, in order to define the behavior
+  /// in case of failing allocations, e.g. throwing an exception. Note that this
+  /// handler must not trigger any additional allocations itself.
+  ///
+  /// If no error handler is installed the default is to print the error message
+  /// to stderr, and call exit(1).  If an error handler is installed then it is
+  /// the handler's responsibility to log the message, it will no longer be
+  /// printed to stderr.  If the error handler returns, then exit(1) will be
+  /// called.
+  ///
+  ///
+  /// \param user_data - An argument which will be passed to the installed error
+  /// handler.
+  void install_bad_alloc_error_handler(fatal_error_handler_t handler,
+                                       void *user_data = nullptr);
 
-/// Restores default bad alloc error handling behavior.
-void remove_bad_alloc_error_handler();
+  /// Restores default bad alloc error handling behavior.
+  void remove_bad_alloc_error_handler();
 
-void install_out_of_memory_new_handler();
+  void install_out_of_memory_new_handler();
 
-/// Reports a bad alloc error, calling any user defined bad alloc
-/// error handler. In contrast to the generic 'report_fatal_error'
-/// functions, this function might not terminate, e.g. the user
-/// defined error handler throws an exception, but it won't return.
-///
-/// Note: When throwing an exception in the bad alloc handler, make sure that
-/// the following unwind succeeds, e.g. do not trigger additional allocations
-/// in the unwind chain.
-///
-/// If no error handler is installed (default), throws a bad_alloc exception
-/// if LLVM is compiled with exception support. Otherwise prints the error
-/// to standard error and calls abort().
-[[noreturn]] void report_bad_alloc_error(const char *Reason,
-                                         bool GenCrashDiag = true);
-
-/// This function calls abort(), and prints the optional message to stderr.
-/// Use the llvm_unreachable macro (that adds location info), instead of
-/// calling this function directly.
-[[noreturn]] void
-llvm_unreachable_internal(const char *msg = nullptr, const char *file = nullptr,
-                          unsigned line = 0);
+  /// Reports a bad alloc error, calling any user defined bad alloc
+  /// error handler. In contrast to the generic 'report_fatal_error'
+  /// functions, this function might not terminate, e.g. the user
+  /// defined error handler throws an exception, but it won't return.
+  ///
+  /// Note: When throwing an exception in the bad alloc handler, make sure that
+  /// the following unwind succeeds, e.g. do not trigger additional allocations
+  /// in the unwind chain.
+  ///
+  /// If no error handler is installed (default), throws a bad_alloc exception
+  /// if LLVM is compiled with exception support. Otherwise prints the error
+  /// to standard error and calls abort().
+  [[noreturn]] void report_bad_alloc_error(const char *Reason,
+                                           bool GenCrashDiag = true);
+
+  /// This function calls abort(), and prints the optional message to stderr.
+  /// Use the llvm_unreachable macro (that adds location info), instead of
+  /// calling this function directly.
+  [[noreturn]] void llvm_unreachable_internal(const char *msg = nullptr,
+                                              const char *file = nullptr,
+                                              unsigned line = 0);
 }
 
 /// Marks that the current location is not supposed to be reachable.

@jayfoad
Copy link
Contributor

jayfoad commented May 2, 2025

Thanks for doing this. I like it. Definitely an improvement on the status quo. I would be tempted to go further, and replace all uses of report_fatal_error.

@arsenm
Copy link
Contributor

arsenm commented May 2, 2025

Next step is to avoid all instances of "not --crash", which #128495 has a big chunk of

Copy link
Collaborator

@joker-eph joker-eph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG

Copy link
Contributor

@asb asb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you! I agree it would be good to migrate more report_fatal_error instances, but that's best handled in follow-up PRs IMHO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AMDGPU backend:DirectX backend:loongarch backend:RISC-V backend:SPIR-V clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category llvm:instcombine llvm:support llvm:transforms LTO Link time optimization (regular/full LTO or ThinLTO) mlir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants