Skip to content

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 Covers the InstCombine, InstSimplify and AggressiveInstCombine passes 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.

@nikic nikic merged commit b492ec5 into llvm:main May 5, 2025
11 of 13 checks passed
@nikic nikic deleted the fatal-error-apis branch May 5, 2025 10:10
@optimisan
Copy link
Contributor

optimisan commented May 5, 2025

Perhaps the ProgrammersManual should also be updated? Currently it says this:

In situations where you absolutely must emit a non-programmatic error and the Error model isn’t workable you can call report_fatal_error ... The use of report_fatal_error in this case is discouraged.

nikic added a commit to nikic/llvm-project that referenced this pull request May 5, 2025
Update docs for llvm#138251.
Mention reportFatalInternalError and reportFatalUsageError in the
respective sections of the documentation.
@nikic
Copy link
Contributor Author

nikic commented May 5, 2025

@optimisan Good point. I've put up #138502 to update the docs.

nikic added a commit that referenced this pull request May 6, 2025
Update docs for #138251.
Mention reportFatalInternalError and reportFatalUsageError in the
respective sections of the documentation.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…(NFC) (llvm#138251)

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.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…(NFC) (llvm#138251)

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.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
…(NFC) (llvm#138251)

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.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 7, 2025
Update docs for llvm/llvm-project#138251.
Mention reportFatalInternalError and reportFatalUsageError in the
respective sections of the documentation.
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
…(NFC) (llvm#138251)

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.
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
Update docs for llvm#138251.
Mention reportFatalInternalError and reportFatalUsageError in the
respective sections of the documentation.
bd1976bris added a commit to bd1976bris/llvm-project that referenced this pull request May 22, 2025
On Windows, LLVM’s `reportFatalUsageError` (llvm#138251) may emit a
bug report prompt due to the `PrettyStackTrace` signal handler,
initialized via `InitLLVM`. This occurs when `RunInterruptHandlers()`
is called from `reportFatalUsageError`.

This behavior is misleading for usage errors. For example, one
of Sony’s customers filed a bug after specifying an invalid LTO
cache directory - a clear usage error - because the toolchain
output included instructions to report a bug.

This patch suppresses `PrettyStackTrace` output for usage errors by
adding a flag to `sys::RunInterruptHandlers()` to indicate whether
signal handlers should be executed.

To test this, I have modified the invalid LTO pipeline errors to call
`reportFatalUsageError`, and I have updated the existing LLD test to
additionally verify that no bug report message has been emitted.

LLVM Issue: llvm#140953
Internal Tracker: TOOLCHAIN-17744
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 Covers the InstCombine, InstSimplify and AggressiveInstCombine passes 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.

8 participants