From 47a2b1ba9e276a9a2f3f314f4e6b9f6688311820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?= Date: Mon, 6 Oct 2025 19:21:12 -0400 Subject: [PATCH] [Clang][Driver] New parameter allow-unrecognized-arguments This parameter is used to suppress the ``Unknown argument '...'`` error that clang will emit whenever it encounters an unknown argument. This is probably an error to make sure the user fixes it's mistake by either removing the argument or renaming it, but there are some cases where it's not possible to fix the issue. For instance, CMake now injects gcc-specific arguments in the clang-tidy command that breaks static-analysis (https://gitlab.kitware.com/cmake/cmake/-/issues/26283) This will also allow users to run clang-tidy / clangd on a gcc-based project without the need to maintain two separate build commands to run llvm-based tools. By enabling this parameter, the user is able to downgrade the error to a warning (unknown-argument) that he can further silence using the ``-Qunused-arguments`` flag if needed. Fixes: #108455 --- clang/include/clang/Driver/Options.td | 3 ++ clang/lib/Driver/Driver.cpp | 42 ++++++++++++----------- clang/lib/Frontend/CompilerInvocation.cpp | 20 ++++++----- clang/test/Driver/unsupported-option.c | 4 +++ 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 2ef609831637e..de0d32f68253a 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1011,6 +1011,9 @@ def : Flag<["-"], "Xcompiler">, IgnoredGCCCompat; def Z_Flag : Flag<["-"], "Z">, Group; def all__load : Flag<["-"], "all_load">; def allowable__client : Separate<["-"], "allowable_client">; +def allow_unrecognized_arguments : Flag<["--"], "allow-unrecognized-arguments">, + Visibility<[ClangOption, CLOption]>, + HelpText<"Ignore unrecognized command-line arguments instead of reporting an error.">; def ansi : Flag<["-", "--"], "ansi">, Group; def arch__errors__fatal : Flag<["-"], "arch_errors_fatal">; def arch : Separate<["-"], "arch">, Flags<[NoXarchOption,TargetSpecific]>; diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 85a1335785542..4f2ac9ba8271c 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -303,29 +303,31 @@ InputArgList Driver::ParseArgStrings(ArrayRef ArgStrings, } } - for (const Arg *A : Args.filtered(options::OPT_UNKNOWN)) { - unsigned DiagID; - auto ArgString = A->getAsString(Args); - std::string Nearest; - if (getOpts().findNearest(ArgString, Nearest, VisibilityMask) > 1) { - if (!IsCLMode() && - getOpts().findExact(ArgString, Nearest, - llvm::opt::Visibility(options::CC1Option))) { - DiagID = diag::err_drv_unknown_argument_with_suggestion; - Diags.Report(DiagID) << ArgString << "-Xclang " + Nearest; + if (!Args.hasArg(options::OPT_allow_unrecognized_arguments)) { + for (const Arg *A : Args.filtered(options::OPT_UNKNOWN)) { + unsigned DiagID; + auto ArgString = A->getAsString(Args); + std::string Nearest; + if (getOpts().findNearest(ArgString, Nearest, VisibilityMask) > 1) { + if (!IsCLMode() && + getOpts().findExact(ArgString, Nearest, + llvm::opt::Visibility(options::CC1Option))) { + DiagID = diag::err_drv_unknown_argument_with_suggestion; + Diags.Report(DiagID) << ArgString << "-Xclang " + Nearest; + } else { + DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl + : diag::err_drv_unknown_argument; + Diags.Report(DiagID) << ArgString; + } } else { - DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl - : diag::err_drv_unknown_argument; - Diags.Report(DiagID) << ArgString; + DiagID = IsCLMode() + ? diag::warn_drv_unknown_argument_clang_cl_with_suggestion + : diag::err_drv_unknown_argument_with_suggestion; + Diags.Report(DiagID) << ArgString << Nearest; } - } else { - DiagID = IsCLMode() - ? diag::warn_drv_unknown_argument_clang_cl_with_suggestion - : diag::err_drv_unknown_argument_with_suggestion; - Diags.Report(DiagID) << ArgString << Nearest; + ContainsError |= Diags.getDiagnosticLevel(DiagID, SourceLocation()) > + DiagnosticsEngine::Warning; } - ContainsError |= Diags.getDiagnosticLevel(DiagID, SourceLocation()) > - DiagnosticsEngine::Warning; } for (const Arg *A : Args.filtered(options::OPT_o)) { diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 422375240bab6..0ba29db471617 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4991,15 +4991,17 @@ bool CompilerInvocation::CreateFromArgsImpl( Diags.Report(diag::err_drv_missing_argument) << Args.getArgString(MissingArgIndex) << MissingArgCount; - // Issue errors on unknown arguments. - for (const auto *A : Args.filtered(OPT_UNKNOWN)) { - auto ArgString = A->getAsString(Args); - std::string Nearest; - if (Opts.findNearest(ArgString, Nearest, VisibilityMask) > 1) - Diags.Report(diag::err_drv_unknown_argument) << ArgString; - else - Diags.Report(diag::err_drv_unknown_argument_with_suggestion) - << ArgString << Nearest; + if (!Args.hasArg(options::OPT_allow_unrecognized_arguments)) { + // Issue errors on unknown arguments. + for (const auto *A : Args.filtered(OPT_UNKNOWN)) { + auto ArgString = A->getAsString(Args); + std::string Nearest; + if (Opts.findNearest(ArgString, Nearest, VisibilityMask) > 1) + Diags.Report(diag::err_drv_unknown_argument) << ArgString; + else + Diags.Report(diag::err_drv_unknown_argument_with_suggestion) + << ArgString << Nearest; + } } ParseFileSystemArgs(Res.getFileSystemOpts(), Args, Diags); diff --git a/clang/test/Driver/unsupported-option.c b/clang/test/Driver/unsupported-option.c index 7234e52571582..465f1879b31c8 100644 --- a/clang/test/Driver/unsupported-option.c +++ b/clang/test/Driver/unsupported-option.c @@ -32,3 +32,7 @@ // RUN: not %clang -c -Qunused-arguments --target=aarch64-- -mfpu=crypto-neon-fp-armv8 %s 2>&1 \ // RUN: | FileCheck %s --check-prefix=QUNUSED_ARGUMENTS // QUNUSED_ARGUMENTS: error: unsupported option '-mfpu=' for target 'aarch64--' + +// RUN: %clang %s -invalid --allow-unrecognized-arguments -### 2>&1 | \ +// RUN: FileCheck %s --check-prefix=UNKNOWN_ARGUMENT +// UNKNOWN_ARGUMENT: warning: argument unused during compilation: '-invalid'