[clang] [CIR] Honor -fno-clangir (PR #214904)
Bruno Cardoso Lopes via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 11 11:03:23 PDT 2026
https://github.com/bcardosolopes updated https://github.com/llvm/llvm-project/pull/214904
>From 5d776418dd01b380e854a8e78eff62ce9d828f89 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Fri, 7 Aug 2026 17:44:25 -0700
Subject: [PATCH 1/2] [CIR] Honor -fno-clangir
-fno-clangir was a no-op whenever -fclangir also appeared on the command
line, in either order: the CIR pipeline ran regardless. Options.td already
declares clangir as a BoolFOption with a NegFlag, so last-wins semantics
were intended and the generated marshalling implements them correctly.
Two consumers bypassed it:
- The driver tested Args.hasArg(OPT_fclangir), a presence check that never
looks at the negation, and forwarded -fclangir to -cc1 unconditionally.
- ParseFrontendArgs then set Opts.UseClangIRPipeline = true under the same
presence check, clobbering the value the marshalling had already computed
from both flags a few lines earlier.
Use hasFlag() in the driver, and drop the redundant frontend override.
-emit-cir still forces the pipeline on, since it is an action that requires
it.
Beyond the stated flag semantics, this matters for A/B testing: appending
-fno-clangir to a -fclangir build to produce a "CIR off" arm silently
produced a second CIR build instead.
---
clang/lib/Driver/ToolChains/Clang.cpp | 2 +-
clang/lib/Frontend/CompilerInvocation.cpp | 5 ++++-
clang/test/CIR/Driver/clangir.c | 23 +++++++++++++++++++++++
3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 85fe99dbf8b69..ec1ad05497751 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5332,7 +5332,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- if (Args.hasArg(options::OPT_fclangir))
+ if (Args.hasFlag(options::OPT_fclangir, options::OPT_fno_clangir, false))
CmdArgs.push_back("-fclangir");
if (IsOpenMPDevice) {
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 6562cb3a9b135..4f319f11e7cb6 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3172,7 +3172,10 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
if (Opts.ProgramAction != frontend::GenerateModule && Opts.IsSystemModule)
Diags.Report(diag::err_drv_argument_only_allowed_with) << "-fsystem-module"
<< "-emit-module";
- if (Args.hasArg(OPT_fclangir) || Args.hasArg(OPT_emit_cir))
+ // -fclangir/-fno-clangir are marshalled into Opts.UseClangIRPipeline above,
+ // which already gives them last-wins semantics; don't clobber that here.
+ // -emit-cir is an action that implies the pipeline regardless.
+ if (Args.hasArg(OPT_emit_cir))
Opts.UseClangIRPipeline = true;
#if CLANG_ENABLE_CIR
diff --git a/clang/test/CIR/Driver/clangir.c b/clang/test/CIR/Driver/clangir.c
index afbe6c6d2388f..d8419d8812f62 100644
--- a/clang/test/CIR/Driver/clangir.c
+++ b/clang/test/CIR/Driver/clangir.c
@@ -15,4 +15,27 @@
// LLVMIR: "-cc1"
// LLVMIR-SAME: "-fclangir"
+// -fclangir and -fno-clangir are last-wins, in either order.
+
+// RUN: %clang -### -fclangir -fno-clangir -S %s 2>&1 | FileCheck %s --check-prefix=NEG
+// RUN: %clang -### -fno-clangir -S %s 2>&1 | FileCheck %s --check-prefix=NEG
+// NEG: "-cc1"
+// NEG-NOT: "-fclangir"
+
+// RUN: %clang -### -fno-clangir -fclangir -S %s 2>&1 | FileCheck %s --check-prefix=POS
+// POS: "-cc1"
+// POS-SAME: "-fclangir"
+
+// The frontend must honor the negation too, not just the driver. -fopenacc
+// warns only when the CIR pipeline is off, which makes UseClangIRPipeline
+// observable at -cc1.
+
+// RUN: %clang_cc1 -fopenacc -fclangir -fno-clangir -emit-llvm-only %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CC1-OFF
+// CC1-OFF: use -fclangir to enable runtime effect
+
+// RUN: %clang_cc1 -fopenacc -fno-clangir -fclangir -emit-llvm-only %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CC1-ON --allow-empty
+// CC1-ON-NOT: use -fclangir to enable runtime effect
+
void foo() {}
>From 872fcfa58d449dee32757c4abb8997750b0d99b5 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Mon, 10 Aug 2026 10:39:57 -0700
Subject: [PATCH 2/2] [CIR] Drop the -fno-clangir marshalling comment
Addresses review feedback on the -fno-clangir fix: the comment restated
what the BoolFOption marshalling already does, so it was noise.
---
clang/lib/Frontend/CompilerInvocation.cpp | 3 ---
1 file changed, 3 deletions(-)
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 4f319f11e7cb6..8b6b64be38709 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3172,9 +3172,6 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
if (Opts.ProgramAction != frontend::GenerateModule && Opts.IsSystemModule)
Diags.Report(diag::err_drv_argument_only_allowed_with) << "-fsystem-module"
<< "-emit-module";
- // -fclangir/-fno-clangir are marshalled into Opts.UseClangIRPipeline above,
- // which already gives them last-wins semantics; don't clobber that here.
- // -emit-cir is an action that implies the pipeline regardless.
if (Args.hasArg(OPT_emit_cir))
Opts.UseClangIRPipeline = true;
More information about the cfe-commits
mailing list