[clang] a509a4e - [LifetimeSafety] Enable C support by default under -Wlifetime-safety (#224028)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 25 06:07:01 PDT 2026
Author: Benedek Kaibas
Date: 2026-09-25T15:06:54+02:00
New Revision: a509a4e98a50a2acc172a5f6eba77b8df020e3cd
URL: https://github.com/llvm/llvm-project/commit/a509a4e98a50a2acc172a5f6eba77b8df020e3cd
DIFF: https://github.com/llvm/llvm-project/commit/a509a4e98a50a2acc172a5f6eba77b8df020e3cd.diff
LOG: [LifetimeSafety] Enable C support by default under -Wlifetime-safety (#224028)
This PR extends the lifetime safety analysis to C. When the analysis is
enabled with `-Wlifetime-safety`, it now also runs on C code without the
extra `-fexperimental-lifetime-safety-c` flag.
I have renamed `-fexperimental-lifetime-safety-c` to
`-flifetime-safety-c` since it is on by default from now on. The
`-fno-lifetime-safety-c` flag disables the analysis for C. I have
updated the documentation and the release notes and rewrote the RUN
lines of the test cases that used the old flag.
Added:
clang/test/Driver/flifetime-safety-c.c
Modified:
clang/docs/LifetimeSafety.md
clang/docs/ReleaseNotes.md
clang/include/clang/Basic/LangOptions.def
clang/include/clang/Options/Options.td
clang/lib/Driver/ToolChains/Clang.cpp
clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c
clang/test/Sema/LifetimeSafety/safety-c.c
Removed:
################################################################################
diff --git a/clang/docs/LifetimeSafety.md b/clang/docs/LifetimeSafety.md
index dcf206547643d..dbf67cfb2ce77 100644
--- a/clang/docs/LifetimeSafety.md
+++ b/clang/docs/LifetimeSafety.md
@@ -3,7 +3,7 @@
## Introduction
-Clang Lifetime Safety Analysis is a C++ language extension which warns about
+Clang Lifetime Safety Analysis is a C and C++ language extension which warns about
potential dangling pointer defects in code. The analysis aims to detect
when a pointer, reference or view type (such as `std::string_view`) refers to an object
that is no longer alive, a condition that leads to use-after-free bugs and
@@ -57,6 +57,24 @@ The analysis flags the assignment `v = s` as defective because `s` is
destroyed while `v` is still alive and points to `s`, and adds a note
to where `v` is used after `s` has been destroyed.
+```c
+#include <stdio.h>
+void simple_dangle() {
+ int *ptr = NULL;
+ {
+ int i = 5;
+ ptr = &i; // warning: local variable 'i' does not live long enough
+ } // note: local variable 'i' is destroyed here
+ *ptr = 6; // note: later used here
+}
+```
+
+This example demonstrates a simples use-after-scope bug in C. The `ptr` pointer
+is set to `NULL` in the outer scope. In the inner scope ptr points to `i`, but
+its lifetime ends at the end of the inner block which causes `ptr` to dangle
+when it is set to 6.
+
+
### Running The Analysis
To run the analysis, compile with the `-Wlifetime-safety-permissive` flag, e.g.
@@ -66,7 +84,9 @@ clang -c -Wlifetime-safety-permissive example.cpp
```
This flag enables a core set of lifetime safety checks. For more fine-grained
-control over warnings, see {ref}`warning_flags`.
+control over warnings, see {ref}`warning_flags`. The analysis runs for both
+C and C++ by default. Use `-fno-lifetime-safety-c` to disable the analysis
+for C code.
## Lifetime Annotations
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 702ff4a17d5c0..48d9b05597868 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -382,6 +382,9 @@ features cannot lower the translation-unit ABI level;
};
```
+- Lifetime safety analysis is now enabled for C by default. The `-fexperimental-lifetime-safety-c`
+ flag is renamed to `-flifetime-safety-c`. Use `-fno-lifetime-safety-c` to disable it.
+
- Improved `-Wassign-enum` performance by caching enum enumerator values. (#GH176454)
- Fixed a false negative in `-Warray-bounds` where the warning was suppressed
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index d7637f2dfd507..c4ae12cd44bed 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -525,7 +525,7 @@ LANGOPT(BoundsSafety, 1, 0, NotCompatible, "Bounds safety extension for C")
LANGOPT(DebugRunLifetimeSafety, 1, 0, Benign, "Run lifetime safety analysis for C++. Does not enable warnings.")
-LANGOPT(EnableLifetimeSafetyInC, 1, 0, Benign, "Lifetime safety analysis for C")
+LANGOPT(EnableLifetimeSafetyInC, 1, 1, Benign, "Lifetime safety analysis for C")
LANGOPT(LifetimeSafetyMaxCFGBlocks, 32, 0, Benign, "Skip LifetimeSafety analysis for functions with CFG block count exceeding this threshold. Specify 0 for no limit")
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 15b2196b68e76..1b1a00de20040 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2121,12 +2121,11 @@ defm debug_run_lifetime_safety : BoolFOption<
NegFlag<SetFalse, [], [CC1Option], "Disable">,
BothFlags<[], [CC1Option], " lifetime safety analysis for C++. Warnings are still controlled by -Wlifetime-safety. Primarily used to surface crashes or compile-time regressions without showing analysis findings.">>;
-defm experimental_lifetime_safety_c : BoolFOption<
- "experimental-lifetime-safety-c",
- LangOpts<"EnableLifetimeSafetyInC">, DefaultFalse,
- PosFlag<SetTrue, [], [CC1Option], "Enable">,
- NegFlag<SetFalse, [], [CC1Option], "Disable">,
- BothFlags<[], [CC1Option], " experimental lifetime safety analysis for C">>;
+defm lifetime_safety_c : BoolFOption<
+ "lifetime-safety-c",
+ LangOpts<"EnableLifetimeSafetyInC">, DefaultTrue,
+ NegFlag<SetFalse, [], [ClangOption, CC1Option]>,
+ PosFlag<SetTrue, [], [ClangOption], "Enable lifetime safety analysis for C">>;
def lifetime_safety_max_cfg_blocks
: Joined<["-"], "lifetime-safety-max-cfg-blocks=">,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 6636a5fd6e655..d42af0b16a1eb 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4554,6 +4554,9 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
Args.addOptInFlag(CmdArgs, options::OPT_fdiagnostics_show_hotness,
options::OPT_fno_diagnostics_show_hotness);
+ Args.addOptOutFlag(CmdArgs, options::OPT_flifetime_safety_c,
+ options::OPT_fno_lifetime_safety_c);
+
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) {
std::string Opt =
diff --git a/clang/test/Driver/flifetime-safety-c.c b/clang/test/Driver/flifetime-safety-c.c
new file mode 100644
index 0000000000000..28579add0f04d
--- /dev/null
+++ b/clang/test/Driver/flifetime-safety-c.c
@@ -0,0 +1,7 @@
+/// -flifetime-safety-c is the default
+// RUN: %clang -### -c %s 2>&1 | FileCheck --check-prefix=ENABLED %s
+// ENABLED-NOT: "-fno-lifetime-safety-c"
+
+// RUN: %clang -### -c %s -flifetime-safety-c -fno-lifetime-safety-c 2>&1 | \
+// RUN: FileCheck --check-prefix=DISABLED %s
+// DISABLED: "-fno-lifetime-safety-c"
diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c
index 0ad009fa0c559..58ffea304d7b9 100644
--- a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c
+++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.c
@@ -1,18 +1,18 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \
+// RUN: %clang_cc1 -fsyntax-only -std=c17 \
// RUN: -Wlifetime-safety-suggestions -Wno-dangling \
// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -fsyntax-only -std=c23 -fexperimental-lifetime-safety-c \
+// RUN: %clang_cc1 -fsyntax-only -std=c23 \
// RUN: -Wlifetime-safety-suggestions -Wno-dangling \
// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s --check-prefix=CHECK-C23
-// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \
+// RUN: %clang_cc1 -fsyntax-only -std=c17 \
// RUN: -Wlifetime-safety-suggestions -Wno-dangling \
// RUN: '-DLIFETIMEBOUND_MACRO=__attribute__((lifetimebound))' \
// RUN: -lifetime-safety-lifetimebound-macro=LIFETIMEBOUND_MACRO \
// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s --check-prefix=CHECK-MACRO
// RUN: cp %s %t.c
-// RUN: %clang_cc1 -std=c17 -fexperimental-lifetime-safety-c \
+// RUN: %clang_cc1 -std=c17 \
// RUN: -Wlifetime-safety-suggestions -Wno-dangling -fixit %t.c
-// RUN: %clang_cc1 -fsyntax-only -std=c17 -fexperimental-lifetime-safety-c \
+// RUN: %clang_cc1 -fsyntax-only -std=c17 \
// RUN: -Werror=lifetime-safety-suggestions -Wno-dangling %t.c
int *return_pointer(int *p) {
diff --git a/clang/test/Sema/LifetimeSafety/safety-c.c b/clang/test/Sema/LifetimeSafety/safety-c.c
index 171ac15341efe..8e6ca521c1804 100644
--- a/clang/test/Sema/LifetimeSafety/safety-c.c
+++ b/clang/test/Sema/LifetimeSafety/safety-c.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -Wno-varargs -Wno-non-pod-varargs -verify -fexperimental-lifetime-safety-c %s
-// RUN: %clang_cc1 -fsyntax-only -Werror=lifetime-safety -Wno-dangling -Wno-varargs -Wno-non-pod-varargs %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -Wno-varargs -Wno-non-pod-varargs -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Werror=lifetime-safety -Wno-dangling -Wno-varargs -Wno-non-pod-varargs -fno-lifetime-safety-c %s
int *identity(int *p __attribute__((lifetimebound))) { return p; }
More information about the cfe-commits
mailing list