[clang] Add fine-grained `__has_feature()` cutout (PR #170822)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 12 20:00:54 PST 2026
https://github.com/j39m updated https://github.com/llvm/llvm-project/pull/170822
>From 30462f19f6ba2bf53eb6440dff018c40282bf3fd Mon Sep 17 00:00:00 2001
From: Kalvin Lee <kdlee at chromium.org>
Date: Fri, 5 Dec 2025 17:37:29 +0900
Subject: [PATCH 1/6] Add fine-grained `__has_feature()` cutout
This is a follow-up to pull 148323. It mints
`-fsanitize-ignore-for-ubsan-feature=...`, accepting a list of (UBSan)
sanitizers that should not cause
`__has_feature(undefined_behavior_sanitizer)` to evaluate true.
---
.../clang/Basic/DiagnosticDriverKinds.td | 1 +
clang/include/clang/Basic/Features.def | 2 +-
clang/include/clang/Basic/LangOptions.h | 3 ++
clang/include/clang/Driver/SanitizerArgs.h | 1 +
clang/include/clang/Options/Options.td | 8 +++++
clang/lib/Driver/SanitizerArgs.cpp | 29 ++++++++++++++++++
clang/lib/Frontend/CompilerInvocation.cpp | 15 ++++++++++
...s_feature_undefined_behavior_sanitizer.cpp | 30 +++++++++++++++++++
8 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index aeffe96e806bd..9e5ca9f76397b 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -277,6 +277,7 @@ def err_drv_malformed_sanitizer_metadata_ignorelist : Error<
"malformed sanitizer metadata ignorelist: '%0'">;
def err_drv_unsupported_static_sanitizer_darwin : Error<
"static %0 runtime is not supported on darwin">;
+def err_drv_not_a_ubsan_sanitizer : Error<"not a UBSan sanitizer: '%0'">;
def err_drv_duplicate_config : Error<
"no more than one option '--config' is allowed">;
def err_drv_cannot_open_config_file : Error<
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 0e91b42a132c1..52dd3a72392ee 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -53,7 +53,7 @@ FEATURE(memtag_globals,
LangOpts.Sanitize.has(SanitizerKind::MemtagGlobals))
FEATURE(xray_instrument, LangOpts.XRayInstrument)
FEATURE(undefined_behavior_sanitizer,
- LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined))
+ LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined & ~LangOpts.UBSanFeatureSuppressedSanitize.Mask))
FEATURE(undefined_behavior_sanitizer_finegrained_feature_checks, true)
// These are all part of undefined_behavior_sanitizer:
FEATURE(alignment_sanitizer,
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 3f042f8ddb5a1..66fe01e877cb1 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -441,6 +441,9 @@ class LangOptions : public LangOptionsBase {
SanitizerSet Sanitize;
/// Is at least one coverage instrumentation type enabled.
bool SanitizeCoverage = false;
+ /// Set of enabled (undefined behavior) sanitizers that do not cause
+ /// `__has_feature(undefined_behavior_sanitizer)` to evaluate true.
+ SanitizerSet UBSanFeatureSuppressedSanitize;
/// Paths to files specifying which objects
/// (files, functions, variables) should not be instrumented.
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 84fb66e16bee3..aa8aa9be287c6 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -28,6 +28,7 @@ class SanitizerArgs {
SanitizerSet MergeHandlers;
SanitizerMaskCutoffs SkipHotCutoffs;
SanitizerSet AnnotateDebugInfo;
+ SanitizerSet SuppressUBSanFeature;
std::vector<std::string> UserIgnorelistFiles;
std::vector<std::string> SystemIgnorelistFiles;
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index c6841937c8d39..84243ad80f2a1 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2404,6 +2404,14 @@ def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
"or suspicious behavior. See user manual for available checks">;
def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>,
Visibility<[ClangOption, CLOption]>;
+def fsanitize_ignore_for_ubsan_feature_EQ
+ : CommaJoined<["-"], "fsanitize-ignore-for-ubsan-feature=">,
+ Group<f_clang_Group>,
+ MetaVarName<"<check>">,
+ HelpText<
+ "Prevents `__has_feature(undefined_behavior_sanitizer)` from "
+ "evaluating true for "
+ "these UBSan checks. See user manual for available UBSan checks">;
def fsanitize_ignorelist_EQ : Joined<["-"], "fsanitize-ignorelist=">,
Group<f_clang_Group>, HelpText<"Path to ignorelist file for sanitizers">;
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index be068b2381d06..08db579626437 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -408,6 +408,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// unused-argument diagnostics.
SanitizerMask DiagnosedKinds; // All Kinds we have diagnosed up to now.
// Used to deduplicate diagnostics.
+ SanitizerMask IgnoreForUbsanFeature; // Accumulated set of values passed to
+ // `-fsanitize-ignore-for-ubsan-feature`.
SanitizerMask Kinds;
const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers());
@@ -612,6 +614,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
Arg->claim();
SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
AllRemove |= expandSanitizerGroups(Remove);
+ } else if (Arg->getOption().matches(
+ options::OPT_fsanitize_ignore_for_ubsan_feature_EQ)) {
+ Arg->claim();
+ SanitizerMask Suppress = parseArgValues(D, Arg, DiagnoseErrors);
+ IgnoreForUbsanFeature |= expandSanitizerGroups(Suppress);
}
}
@@ -736,6 +743,22 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// -f(-no)sanitize=leak should change whether leak detection is enabled by
// default in ASan?
+ // Error if a non-UBSan sanitizer is passed to
+ // `-fsanitize-ignore-for-ubsan-feature=`.
+ //
+ // `shift` is a `SANITIZER_GROUP()`, and so is expanded into its constituents
+ // by `expandSanitizerGroups()` above, though the physical bit is not included
+ // in `SanitizerKind::Undefined`.
+ const SanitizerMask not_ubsan_mask =
+ IgnoreForUbsanFeature &
+ ~(SanitizerKind::Undefined | SanitizerKind::ShiftGroup);
+ if (not_ubsan_mask && DiagnoseErrors) {
+ SanitizerSet not_ubsan;
+ not_ubsan.set(not_ubsan_mask);
+ D.Diag(clang::diag::err_drv_not_a_ubsan_sanitizer) << toString(not_ubsan);
+ }
+ IgnoreForUbsanFeature &= SanitizerKind::Undefined;
+
// Parse -f(no-)?sanitize-recover flags.
SanitizerMask RecoverableKinds = parseSanitizeArgs(
D, Args, DiagnoseErrors, RecoverableByDefault, AlwaysRecoverable,
@@ -1212,6 +1235,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
MergeHandlers.Mask |= MergeKinds;
AnnotateDebugInfo.Mask |= AnnotateDebugInfoKinds;
+ SuppressUBSanFeature.Mask |= IgnoreForUbsanFeature;
// Zero out SkipHotCutoffs for unused sanitizers
SkipHotCutoffs.clear(~Sanitizers.Mask);
@@ -1392,6 +1416,11 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
return;
CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers)));
+ if (!SuppressUBSanFeature.empty())
+ CmdArgs.push_back(
+ Args.MakeArgString("-fsanitize-ignore-for-ubsan-feature=" +
+ toString(SuppressUBSanFeature)));
+
if (!RecoverableSanitizers.empty())
CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" +
toString(RecoverableSanitizers)));
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index b42c263abd2c7..66dd3bc458efe 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3693,6 +3693,10 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_pic_is_pie);
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
+ for (StringRef Sanitizer :
+ serializeSanitizerKinds(Opts.UBSanFeatureSuppressedSanitize))
+ GenerateArg(Consumer, OPT_fsanitize_ignore_for_ubsan_feature_EQ,
+ Sanitizer);
return;
}
@@ -3892,6 +3896,9 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
+ for (StringRef Sanitizer :
+ serializeSanitizerKinds(Opts.UBSanFeatureSuppressedSanitize))
+ GenerateArg(Consumer, OPT_fsanitize_ignore_for_ubsan_feature_EQ, Sanitizer);
// Conflating '-fsanitize-system-ignorelist' and '-fsanitize-ignorelist'.
for (const std::string &F : Opts.NoSanitizeFiles)
@@ -3973,6 +3980,10 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.PIE = Args.hasArg(OPT_pic_is_pie);
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
Diags, Opts.Sanitize);
+ parseSanitizerKinds(
+ "-fsanitize-ignore-for-ubsan-feature=",
+ Args.getAllArgValues(OPT_fsanitize_ignore_for_ubsan_feature_EQ), Diags,
+ Opts.UBSanFeatureSuppressedSanitize);
return Diags.getNumErrors() == NumErrorsBefore;
}
@@ -4390,6 +4401,10 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
// Parse -fsanitize= arguments.
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
Diags, Opts.Sanitize);
+ parseSanitizerKinds(
+ "-fsanitize-ignore-for-ubsan-feature=",
+ Args.getAllArgValues(OPT_fsanitize_ignore_for_ubsan_feature_EQ), Diags,
+ Opts.UBSanFeatureSuppressedSanitize);
Opts.NoSanitizeFiles = Args.getAllArgValues(OPT_fsanitize_ignorelist_EQ);
std::vector<std::string> systemIgnorelists =
Args.getAllArgValues(OPT_fsanitize_system_ignorelist_EQ);
diff --git a/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp b/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
index e1a07d215b549..de4dd1f1cfebc 100644
--- a/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
+++ b/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
@@ -23,6 +23,36 @@
// RUN: %clang -E %s -o - | FileCheck --check-prefix=CHECK-NO-UBSAN %s
+// Specifying a specific sanitizer under UBSan and immediately suppressing
+// `__has_feature(undefined_behavior_sanitizer)` for the same should result in
+// "no-UBSan."
+// BUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=undefined -fsanitize-ignore-for-ubsan-feature=undefined %s -o - | FileCheck --check-prefix=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=alignment -fsanitize-ignore-for-ubsan-feature=alignment %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=bool -fsanitize-ignore-for-ubsan-feature=bool %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=builtin -fsanitize-ignore-for-ubsan-feature=builtin %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=array-bounds -fsanitize-ignore-for-ubsan-feature=array-bounds %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=enum -fsanitize-ignore-for-ubsan-feature=enum %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=float-cast-overflow -fsanitize-ignore-for-ubsan-feature=float-cast-overflow %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=integer-divide-by-zero -fsanitize-ignore-for-ubsan-feature=integer-divide-by-zero %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=nonnull-attribute -fsanitize-ignore-for-ubsan-feature=nonnull-attribute %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=null -fsanitize-ignore-for-ubsan-feature=null %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// object-size is a no-op at O0.
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -O2 -fsanitize=object-size -fsanitize-ignore-for-ubsan-feature=object-size %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=pointer-overflow -fsanitize-ignore-for-ubsan-feature=pointer-overflow %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=return -fsanitize-ignore-for-ubsan-feature=return %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=returns-nonnull-attribute -fsanitize-ignore-for-ubsan-feature=returns-nonnull-attribute %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=shift-base -fsanitize-ignore-for-ubsan-feature=shift-base %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=shift-exponent -fsanitize-ignore-for-ubsan-feature=shift-exponent %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=shift -fsanitize-ignore-for-ubsan-feature=shift %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow -fsanitize-ignore-for-ubsan-feature=signed-integer-overflow %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=unreachable -fsanitize-ignore-for-ubsan-feature=unreachable %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=vla-bound -fsanitize-ignore-for-ubsan-feature=vla-bound %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=function -fsanitize-ignore-for-ubsan-feature=function %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
+
+// Spot check: suppressing an unrelated sanitizer should still result in a "has
+// UBSan" configuration.
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=function -fsanitize-ignore-for-ubsan-feature=alignment %s -o - | FileCheck --check-prefixes=CHECK-UBSAN,CHECK-FUNCTION %s
+
// REQUIRES: x86-registered-target
#if !__has_feature(undefined_behavior_sanitizer_finegrained_feature_checks)
>From 71b5d838035fbcd7a347725261163c66bce5824e Mon Sep 17 00:00:00 2001
From: Kalvin Lee <kdlee at chromium.org>
Date: Tue, 9 Dec 2025 11:57:36 +0900
Subject: [PATCH 2/6] fixup! Add fine-grained `__has_feature()` cutout
* Uniformly use "ignore" rather than "suppress" in describing how we
_ignore_ `-fsanitize=...` when evaluating `__has_feature()`.
* Remove diagnostic emission when a sanitizer not belonging to UBSan
is passed to `-fsanitize-ignore...`
---
clang/include/clang/Basic/Features.def | 2 +-
clang/include/clang/Basic/LangOptions.h | 2 +-
clang/lib/Driver/SanitizerArgs.cpp | 20 ++------------------
clang/lib/Frontend/CompilerInvocation.cpp | 8 ++++----
4 files changed, 8 insertions(+), 24 deletions(-)
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 52dd3a72392ee..ea99a1d5dbbbf 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -53,7 +53,7 @@ FEATURE(memtag_globals,
LangOpts.Sanitize.has(SanitizerKind::MemtagGlobals))
FEATURE(xray_instrument, LangOpts.XRayInstrument)
FEATURE(undefined_behavior_sanitizer,
- LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined & ~LangOpts.UBSanFeatureSuppressedSanitize.Mask))
+ LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined & ~LangOpts.UBSanFeatureIgnoredSanitize.Mask))
FEATURE(undefined_behavior_sanitizer_finegrained_feature_checks, true)
// These are all part of undefined_behavior_sanitizer:
FEATURE(alignment_sanitizer,
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 66fe01e877cb1..568ea5c4f336a 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -443,7 +443,7 @@ class LangOptions : public LangOptionsBase {
bool SanitizeCoverage = false;
/// Set of enabled (undefined behavior) sanitizers that do not cause
/// `__has_feature(undefined_behavior_sanitizer)` to evaluate true.
- SanitizerSet UBSanFeatureSuppressedSanitize;
+ SanitizerSet UBSanFeatureIgnoredSanitize;
/// Paths to files specifying which objects
/// (files, functions, variables) should not be instrumented.
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 08db579626437..68e151f89b251 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -617,8 +617,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
} else if (Arg->getOption().matches(
options::OPT_fsanitize_ignore_for_ubsan_feature_EQ)) {
Arg->claim();
- SanitizerMask Suppress = parseArgValues(D, Arg, DiagnoseErrors);
- IgnoreForUbsanFeature |= expandSanitizerGroups(Suppress);
+ IgnoreForUbsanFeature |=
+ expandSanitizerGroups(parseArgValues(D, Arg, DiagnoseErrors));
}
}
@@ -743,22 +743,6 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// -f(-no)sanitize=leak should change whether leak detection is enabled by
// default in ASan?
- // Error if a non-UBSan sanitizer is passed to
- // `-fsanitize-ignore-for-ubsan-feature=`.
- //
- // `shift` is a `SANITIZER_GROUP()`, and so is expanded into its constituents
- // by `expandSanitizerGroups()` above, though the physical bit is not included
- // in `SanitizerKind::Undefined`.
- const SanitizerMask not_ubsan_mask =
- IgnoreForUbsanFeature &
- ~(SanitizerKind::Undefined | SanitizerKind::ShiftGroup);
- if (not_ubsan_mask && DiagnoseErrors) {
- SanitizerSet not_ubsan;
- not_ubsan.set(not_ubsan_mask);
- D.Diag(clang::diag::err_drv_not_a_ubsan_sanitizer) << toString(not_ubsan);
- }
- IgnoreForUbsanFeature &= SanitizerKind::Undefined;
-
// Parse -f(no-)?sanitize-recover flags.
SanitizerMask RecoverableKinds = parseSanitizeArgs(
D, Args, DiagnoseErrors, RecoverableByDefault, AlwaysRecoverable,
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 66dd3bc458efe..a06dd64df1c1b 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3694,7 +3694,7 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
for (StringRef Sanitizer :
- serializeSanitizerKinds(Opts.UBSanFeatureSuppressedSanitize))
+ serializeSanitizerKinds(Opts.UBSanFeatureIgnoredSanitize))
GenerateArg(Consumer, OPT_fsanitize_ignore_for_ubsan_feature_EQ,
Sanitizer);
@@ -3897,7 +3897,7 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
for (StringRef Sanitizer :
- serializeSanitizerKinds(Opts.UBSanFeatureSuppressedSanitize))
+ serializeSanitizerKinds(Opts.UBSanFeatureIgnoredSanitize))
GenerateArg(Consumer, OPT_fsanitize_ignore_for_ubsan_feature_EQ, Sanitizer);
// Conflating '-fsanitize-system-ignorelist' and '-fsanitize-ignorelist'.
@@ -3983,7 +3983,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
parseSanitizerKinds(
"-fsanitize-ignore-for-ubsan-feature=",
Args.getAllArgValues(OPT_fsanitize_ignore_for_ubsan_feature_EQ), Diags,
- Opts.UBSanFeatureSuppressedSanitize);
+ Opts.UBSanFeatureIgnoredSanitize);
return Diags.getNumErrors() == NumErrorsBefore;
}
@@ -4404,7 +4404,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
parseSanitizerKinds(
"-fsanitize-ignore-for-ubsan-feature=",
Args.getAllArgValues(OPT_fsanitize_ignore_for_ubsan_feature_EQ), Diags,
- Opts.UBSanFeatureSuppressedSanitize);
+ Opts.UBSanFeatureIgnoredSanitize);
Opts.NoSanitizeFiles = Args.getAllArgValues(OPT_fsanitize_ignorelist_EQ);
std::vector<std::string> systemIgnorelists =
Args.getAllArgValues(OPT_fsanitize_system_ignorelist_EQ);
>From d7ddc45e75a973cfec9a8762ea86345405e02de3 Mon Sep 17 00:00:00 2001
From: Kalvin Lee <kdlee at chromium.org>
Date: Thu, 11 Dec 2025 16:02:48 +0900
Subject: [PATCH 3/6] fixup! Add fine-grained `__has_feature()` cutout
Speculative fix for crash in
`Clang.Lexer/has_feature_undefined_behavior_sanitizer.cpp`. I can't
reproduce in my tree (am I building the right check target?), so this is
a guess.
---
clang/lib/Driver/SanitizerArgs.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 68e151f89b251..7c51d66645198 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -1628,7 +1628,9 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
A->getOption().matches(options::OPT_fno_sanitize_merge_handlers_EQ) ||
A->getOption().matches(options::OPT_fsanitize_annotate_debug_info_EQ) ||
A->getOption().matches(
- options::OPT_fno_sanitize_annotate_debug_info_EQ)) &&
+ options::OPT_fno_sanitize_annotate_debug_info_EQ) ||
+ A->getOption().matches(
+ options::OPT_fsanitize_ignore_for_ubsan_feature_EQ)) &&
"Invalid argument in parseArgValues!");
SanitizerMask Kinds;
for (int i = 0, n = A->getNumValues(); i != n; ++i) {
>From 34fb92d67ead092704842ea02e1f0cd917085f0d Mon Sep 17 00:00:00 2001
From: Kalvin Lee <kdlee at chromium.org>
Date: Tue, 16 Dec 2025 17:34:31 +0900
Subject: [PATCH 4/6] fixup! Add fine-grained `__has_feature()` cutout
Correct a typo: `RUN`, not `BUN`
---
clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp b/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
index de4dd1f1cfebc..8e668745a5844 100644
--- a/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
+++ b/clang/test/Lexer/has_feature_undefined_behavior_sanitizer.cpp
@@ -26,7 +26,7 @@
// Specifying a specific sanitizer under UBSan and immediately suppressing
// `__has_feature(undefined_behavior_sanitizer)` for the same should result in
// "no-UBSan."
-// BUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=undefined -fsanitize-ignore-for-ubsan-feature=undefined %s -o - | FileCheck --check-prefix=CHECK-NO-UBSAN %s
+// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=undefined -fsanitize-ignore-for-ubsan-feature=undefined %s -o - | FileCheck --check-prefix=CHECK-NO-UBSAN %s
// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=alignment -fsanitize-ignore-for-ubsan-feature=alignment %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=bool -fsanitize-ignore-for-ubsan-feature=bool %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
// RUN: %clang -E -target x86_64-unknown-linux-gnu -fsanitize=builtin -fsanitize-ignore-for-ubsan-feature=builtin %s -o - | FileCheck --check-prefixes=CHECK-NO-UBSAN %s
>From d77a203e085f738e5907a390cc7f301a43fdd66a Mon Sep 17 00:00:00 2001
From: Kalvin Lee <kdlee at chromium.org>
Date: Thu, 18 Dec 2025 16:48:58 +0900
Subject: [PATCH 5/6] fixup! Add fine-grained `__has_feature()` cutout
Remove unused diagnostic.
---
clang/include/clang/Basic/DiagnosticDriverKinds.td | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 9e5ca9f76397b..aeffe96e806bd 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -277,7 +277,6 @@ def err_drv_malformed_sanitizer_metadata_ignorelist : Error<
"malformed sanitizer metadata ignorelist: '%0'">;
def err_drv_unsupported_static_sanitizer_darwin : Error<
"static %0 runtime is not supported on darwin">;
-def err_drv_not_a_ubsan_sanitizer : Error<"not a UBSan sanitizer: '%0'">;
def err_drv_duplicate_config : Error<
"no more than one option '--config' is allowed">;
def err_drv_cannot_open_config_file : Error<
>From 2b644b694da1beca58fcb969996be57ea04803f8 Mon Sep 17 00:00:00 2001
From: Kalvin Lee <kdlee at chromium.org>
Date: Tue, 13 Jan 2026 12:59:22 +0900
Subject: [PATCH 6/6] fixup! Add fine-grained `__has_feature()` cutout
Reword comment for `LangOptions::UBSanFeatureIgnoredSanitize`.
---
clang/include/clang/Basic/LangOptions.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 568ea5c4f336a..01b3906a75673 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -441,7 +441,7 @@ class LangOptions : public LangOptionsBase {
SanitizerSet Sanitize;
/// Is at least one coverage instrumentation type enabled.
bool SanitizeCoverage = false;
- /// Set of enabled (undefined behavior) sanitizers that do not cause
+ /// Set of (UBSan) sanitizers that when enabled do not cause
/// `__has_feature(undefined_behavior_sanitizer)` to evaluate true.
SanitizerSet UBSanFeatureIgnoredSanitize;
More information about the cfe-commits
mailing list