[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