https://github.com/matrix updated 
https://github.com/llvm/llvm-project/pull/229781

>From 110fe0af4d0fd463e7d82202bc95980602598fd3 Mon Sep 17 00:00:00 2001
From: Gabriele Gristina <[email protected]>
Date: Wed, 7 Oct 2026 16:37:45 +0200
Subject: [PATCH] [clang] Report an invalid -mllvm or -mmlir argument instead
 of exiting

An option passed through -mllvm reaches llvm::cl::ParseCommandLineOptions,
which prints to llvm::errs() and calls exit() when it is not given a stream
to report to. clang passes nullptr, so an invalid option ends the process
from inside the option parser.

That is fatal for anything that embeds clang as a library, hiprtc among
others: one invalid -mllvm option ends the host process rather than failing
the compilation it belongs to, and a caller cannot test whether an option
exists, because asking is what kills it.

Pass llvm::errs(), the stream the parser falls back to when it is given
none, so the text it writes for an unknown argument is unchanged, and report
the failure it returns as a diagnostic. ExecuteCompilerInvocation already
returns false once the error count has grown, and cc1as already skips the
assembler once a diagnostic has been reported, so the invocation fails the
ordinary way and the caller keeps control.

Three call sites forward options to a cl:: parser this way and all three
pass nullptr, so all three are changed: -mllvm and -mmlir in
ExecuteCompilerInvocation, and -mllvm in cc1as_main.cpp. The diagnostic
names the flag the option came from. The -mmlir one is compiled only when
CLANG_ENABLE_CIR is on, so clang/test/CIR/mlirargs.c covers it only in that
configuration.
---
 clang/docs/ReleaseNotes.md                    |  2 ++
 .../clang/Basic/DiagnosticFrontendKinds.td    |  2 ++
 .../ExecuteCompilerInvocation.cpp             | 21 +++++++++++++------
 clang/test/CIR/mlirargs.c                     |  1 +
 clang/test/Driver/unknown-arg.c               |  4 ++++
 clang/test/Frontend/unknown-arg.c             |  7 +++++++
 clang/tools/driver/cc1as_main.cpp             |  8 +++++--
 7 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index efbcc198a28e3..dd64034413cf1 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -882,6 +882,8 @@ features cannot lower the translation-unit ABI level;
 
 #### Miscellaneous Bug Fixes
 
+- Fixed clang terminating the process from inside the LLVM or MLIR option 
parser, instead of reporting a diagnostic, when an invalid option was passed 
through `-mllvm` or `-mmlir`.
+
 #### Miscellaneous Clang Crashes Fixed
 
 - Fixed a crash in CTAD for type alias templates when the aggregate deduction 
guide could not be resolved. (#GH206994)
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td 
b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 232475b6fb5a7..0ab712b4e9374 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -153,6 +153,8 @@ def err_cir_input_missing_triple : Error<
     "missing target triple in ClangIR input">;
 def err_cir_input_triple_mismatch : Error<
     "target triple '%0' of ClangIR input does not match the target '%1'">;
+def err_fe_invalid_forwarded_option : Error<
+    "invalid argument in '%select{-mllvm|-mmlir}0'">;
 def err_fe_invalid_multiple_actions : Error<
     "'%0' action ignored; '%1' action specified previously">;
 def err_fe_invalid_alignment : Error<
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp 
b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index e872f0823f23e..5077115c2e878 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -34,6 +34,7 @@
 #include "llvm/Support/BuryPointer.h"
 #include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
 
 #if CLANG_ENABLE_CIR
 #include "mlir/IR/AsmState.h"
@@ -264,9 +265,13 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
     for (unsigned i = 0; i != NumArgs; ++i)
       Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
     Args[NumArgs + 1] = nullptr;
-    llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get(), /*Overview=*/"",
-                                      /*Errs=*/nullptr,
-                                      /*VFS=*/&Clang->getVirtualFileSystem());
+    // With no stream to report to, the parser calls exit(), which ends the
+    // process that embeds clang. Keep its output where it already went.
+    if (!llvm::cl::ParseCommandLineOptions(
+            NumArgs + 1, Args.get(), /*Overview=*/"", /*Errs=*/&llvm::errs(),
+            /*VFS=*/&Clang->getVirtualFileSystem()))
+      Clang->getDiagnostics().Report(diag::err_fe_invalid_forwarded_option)
+          << 0;
   }
 
 #if CLANG_ENABLE_STATIC_ANALYZER
@@ -313,9 +318,13 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
     for (unsigned i = 0; i != NumArgs; ++i)
       Args[i + 1] = Clang->getFrontendOpts().MLIRArgs[i].c_str();
     Args[NumArgs + 1] = nullptr;
-    llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get(),
-                                      /*Description=*/"", /*Errs=*/nullptr,
-                                      &Clang->getVirtualFileSystem());
+    // With no stream to report to, the parser calls exit(), which ends the
+    // process that embeds clang. Keep its output where it already went.
+    if (!llvm::cl::ParseCommandLineOptions(
+            NumArgs + 1, Args.get(), /*Overview=*/"", /*Errs=*/&llvm::errs(),
+            /*VFS=*/&Clang->getVirtualFileSystem()))
+      Clang->getDiagnostics().Report(diag::err_fe_invalid_forwarded_option)
+          << 1;
   }
 #endif
 
diff --git a/clang/test/CIR/mlirargs.c b/clang/test/CIR/mlirargs.c
index cfb07197ef185..b28c7c59e3797 100644
--- a/clang/test/CIR/mlirargs.c
+++ b/clang/test/CIR/mlirargs.c
@@ -8,5 +8,6 @@
 // WRONG: clang (MLIR option parsing): Did you mean '--mlir-disable-threading'?
 // WRONG: clang (MLIR option parsing): Unknown command line argument 
'-mlir-print-op-genericd'.  Try: 'clang (MLIR option parsing) --help'
 // WRONG: clang (MLIR option parsing): Did you mean '--mlir-print-op-generic'?
+// WRONG: error: invalid argument in '-mmlir'
 
 // CC1: "-mmlir" "-mlir-disable-threading"
diff --git a/clang/test/Driver/unknown-arg.c b/clang/test/Driver/unknown-arg.c
index 26032a407f413..9bddef95d5fa0 100644
--- a/clang/test/Driver/unknown-arg.c
+++ b/clang/test/Driver/unknown-arg.c
@@ -20,6 +20,8 @@
 // RUN:     FileCheck %s --check-prefix=SILENT
 // RUN: not %clang -cc1as -hell --version 2>&1 | \
 // RUN:     FileCheck %s --check-prefix=CC1AS-DID-YOU-MEAN
+// RUN: not %clang -cc1as -mllvm -helium 2>&1 | \
+// RUN:     FileCheck %s --check-prefix=CC1AS-MLLVM
 // RUN: not %clang -cc1asphalt -help 2>&1 | \
 // RUN:     FileCheck %s --check-prefix=UNKNOWN-INTEGRATED
 
@@ -59,6 +61,8 @@
 // SILENT-NOT: warning:
 // CC1AS-DID-YOU-MEAN: error: unknown argument '-hell'; did you mean '-help'?
 // CC1AS-DID-YOU-MEAN: error: unknown argument '--version'; did you mean 
'-version'?
+// CC1AS-MLLVM: clang (LLVM option parsing): Unknown command line argument 
'-helium'
+// CC1AS-MLLVM: error: invalid argument in '-mllvm'
 // UNKNOWN-INTEGRATED: error: unknown integrated tool '-cc1asphalt'. Valid 
tools include '-cc1', '-cc1as' and '-cc1gen-reproducer'.
 
 // RUN: %clang -S %s -o %t.s  -Wunknown-to-clang-option 2>&1 | FileCheck 
--check-prefix=IGNORED %s
diff --git a/clang/test/Frontend/unknown-arg.c 
b/clang/test/Frontend/unknown-arg.c
index 74a6c842da908..9cebe195c2413 100644
--- a/clang/test/Frontend/unknown-arg.c
+++ b/clang/test/Frontend/unknown-arg.c
@@ -6,7 +6,14 @@
 // RUN: FileCheck %s --check-prefix=DID-YOU-MEAN
 // RUN: not %clang_cc1 --version 2>&1 | \
 // RUN: FileCheck %s --check-prefix=DID-YOU-MEAN-VER
+// RUN: not %clang_cc1 %s -E -mllvm -helium 2>&1 | \
+// RUN: FileCheck %s --check-prefix=MLLVM
 
 // CHECK: error: unknown argument: '--helium'
 // DID-YOU-MEAN: error: unknown argument '--hel['; did you mean '--help'?
 // DID-YOU-MEAN-VER: error: unknown argument '--version'; did you mean 
'-version'?
+
+// An unknown option behind -mllvm is reported, and the text LLVM's own parser
+// writes is unchanged, because it still goes to the stream it used before.
+// MLLVM: clang (LLVM option parsing): Unknown command line argument '-helium'
+// MLLVM: error: invalid argument in '-mllvm'
diff --git a/clang/tools/driver/cc1as_main.cpp 
b/clang/tools/driver/cc1as_main.cpp
index 077cd69ce4e2c..41f1562208a5d 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -731,8 +731,12 @@ int cc1as_main(ArrayRef<const char *> Argv, const char 
*Argv0, void *MainAddr) {
     for (unsigned i = 0; i != NumArgs; ++i)
       Args[i + 1] = Asm.LLVMArgs[i].c_str();
     Args[NumArgs + 1] = nullptr;
-    llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get(), /*Overview=*/"",
-                                      /*Errs=*/nullptr, /*VFS=*/VFS.get());
+    // With no stream to report to, the parser calls exit(), which ends the
+    // process that embeds clang. Keep its output where it already went.
+    if (!llvm::cl::ParseCommandLineOptions(
+            NumArgs + 1, Args.get(), /*Overview=*/"", /*Errs=*/&llvm::errs(),
+            /*VFS=*/VFS.get()))
+      Diags.Report(diag::err_fe_invalid_forwarded_option) << 0;
   }
 
   // Execute the invocation, unless there were parsing errors.

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to