https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/179309
>From f414c7276075bbe5c592a77c3830aee92425d913 Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Mon, 2 Feb 2026 19:16:30 +0000 Subject: [PATCH] Reorganise permissive and strict diagnostic groups --- .../Analyses/LifetimeSafety/LifetimeSafety.h | 2 + clang/include/clang/Basic/DiagnosticGroups.td | 69 ++++++++++++++++--- .../clang/Basic/DiagnosticSemaKinds.td | 21 +++--- clang/lib/Sema/AnalysisBasedWarnings.cpp | 25 +++---- clang/test/Sema/warn-lifetime-safety.cpp | 18 ++--- 5 files changed, 88 insertions(+), 47 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index 7761a5c24c606..d7aadf4cf04ca 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -33,6 +33,8 @@ namespace clang::lifetimes { +// TODO: Deprecate and remove Confidence as this is no more used as a +// differentiator between strict and permissive warnings. /// Enum to track the confidence level of a potential error. enum class Confidence : uint8_t { None, diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index aaf8275a78707..7df83d2a4011f 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -556,36 +556,65 @@ def Dangling : DiagGroup<"dangling", [DanglingAssignment, DanglingGsl, ReturnStackAddress]>; -def LifetimeSafetyDanglingField : DiagGroup<"lifetime-safety-dangling-field"> { +// Use-After-Scope +def LifetimeSafetyUseAfterScope : DiagGroup<"lifetime-safety-use-after-scope"> { + code Documentation = [{ +Warning to detect dangling references introduced by use-after-scope. + }]; +} +def LifetimeSafetyUseAfterScopeMoved : DiagGroup<"lifetime-safety-use-after-scope-moved"> { code Documentation = [{ - Warning to detect dangling field references. +Warning to detect dangling references introduced by use-after-scope. +This may contain false-positives, e.g. when the borrowed storage is potentially moved and is not destroyed at scope exit. }]; } -def LifetimeSafetyDanglingFieldStrict : DiagGroup<"lifetime-safety-dangling-field-strict"> { +// Return-Stack-Address (aka Use-After-Return) +def LifetimeSafetyReturnStackAddr : DiagGroup<"lifetime-safety-return-stack-addr"> { + code Documentation = [{ +Warning to detect use-after-return introduced by returning stack address. + }]; +} +def LifetimeSafetyReturnStackAddrMoved : DiagGroup<"lifetime-safety-return-stack-addr-moved"> { code Documentation = [{ - Warning to detect dangling field references. - This may contain false-positives, e.g. when the borrowed storage is potentially moved and is not destroyed at function exit. +Warning to detect use-after-return introduced by returning stack address. +This may contain false-positives, e.g. when the borrowed storage is potentially moved and is not destroyed at function exit. }]; } +// Dangling-Field (aka Escape-To-Field) +def LifetimeSafetyDanglingField : DiagGroup<"lifetime-safety-dangling-field"> { + code Documentation = [{ +Warning to detect dangling field references. + }]; +} +def LifetimeSafetyDanglingFieldMoved : DiagGroup<"lifetime-safety-dangling-field-moved"> { + code Documentation = [{ +Warning to detect dangling field references. +This may contain false-positives, e.g. when the borrowed storage is potentially moved and is not destroyed at function exit. + }]; +} def LifetimeSafetyInvalidation : DiagGroup<"lifetime-safety-invalidation"> { code Documentation = [{ - Warning to detect invalidation of references. +Warning to detect invalidation of references. }]; } def LifetimeSafetyPermissive : DiagGroup<"lifetime-safety-permissive", - [LifetimeSafetyDanglingField]>; + [LifetimeSafetyUseAfterScope, + LifetimeSafetyReturnStackAddr, + LifetimeSafetyDanglingField]>; def LifetimeSafetyStrict : DiagGroup<"lifetime-safety-strict", - [LifetimeSafetyDanglingFieldStrict, + [LifetimeSafetyUseAfterScopeMoved, + LifetimeSafetyReturnStackAddrMoved, + LifetimeSafetyDanglingFieldMoved, LifetimeSafetyInvalidation]>; def LifetimeSafety : DiagGroup<"lifetime-safety", [LifetimeSafetyPermissive, LifetimeSafetyStrict]> { code Documentation = [{ - Warnings to detect use-after-free and related temporal safety bugs based on lifetime safety analysis. +Warnings to detect use-after-free and related temporal safety bugs based on lifetime safety analysis. }]; } @@ -598,13 +627,31 @@ def LifetimeSafetySuggestions [LifetimeSafetyCrossTUSuggestions, LifetimeSafetyIntraTUSuggestions]> { code Documentation = [{ - Lifetime annotation suggestions for function parameters that should be marked [[clang::lifetimebound]] based on lifetime analysis. +Lifetime annotation suggestions for function parameters that should be marked [[clang::lifetimebound]] based on lifetime analysis. }]; } + def LifetimeSafetyNoescape : DiagGroup<"lifetime-safety-noescape"> { code Documentation = [{ - Detects misuse of [[clang::noescape]] annotation where the parameter escapes (for example, through return). +Detects misuse of [[clang::noescape]] annotation where the parameter escapes (for example, through return). + }]; +} + +def LifetimeSafetyValidations : DiagGroup<"lifetime-safety-validations", + [LifetimeSafetyNoescape]> { + code Documentation = [{ +Verify function implementations adhere to the annotated lifetime contracts through lifetime safety +like verifying [[clang::noescape]] and [[clang::lifetimebound]] (upcoming). + }]; +} + +def LifetimeSafetyAll : DiagGroup<"lifetime-safety-all", + [LifetimeSafety, + LifetimeSafetySuggestions, + LifetimeSafetyValidations]> { + code Documentation = [{ +Turns on all the warnings in the lifetime-safety umbrella. }]; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5254003f0c21e..68016ec4d58a3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10897,26 +10897,23 @@ def warn_dangling_reference_captured_by_unknown : Warning< "the full-expression">, InGroup<DanglingCapture>; // Diagnostics based on the Lifetime safety analysis. -def warn_lifetime_safety_loan_expires_permissive : Warning< +def warn_lifetime_safety_use_after_scope : Warning< "object whose reference is captured does not live long enough">, - InGroup<LifetimeSafetyPermissive>, DefaultIgnore; -def warn_lifetime_safety_loan_expires_strict : Warning< - "object whose reference is captured may not live long enough">, - InGroup<LifetimeSafetyStrict>, DefaultIgnore; -def warn_lifetime_safety_loan_expires_moved_strict : Warning< + InGroup<LifetimeSafetyUseAfterScope>, DefaultIgnore; +def warn_lifetime_safety_use_after_scope_moved : Warning< "object whose reference is captured may not live long enough. " "This could be false positive as the storage may have been moved later">, - InGroup<LifetimeSafetyStrict>, DefaultIgnore; + InGroup<LifetimeSafetyUseAfterScopeMoved>, DefaultIgnore; -def warn_lifetime_safety_return_stack_addr_permissive +def warn_lifetime_safety_return_stack_addr : Warning<"address of stack memory is returned later">, - InGroup<LifetimeSafetyPermissive>, + InGroup<LifetimeSafetyReturnStackAddr>, DefaultIgnore; -def warn_lifetime_safety_return_stack_addr_moved_strict +def warn_lifetime_safety_return_stack_addr_moved : Warning<"address of stack memory may be returned later. " "This could be false positive as the storage may have been moved. " "Consider moving first and then aliasing later to resolve the issue">, - InGroup<LifetimeSafetyStrict>, + InGroup<LifetimeSafetyReturnStackAddrMoved>, DefaultIgnore; def warn_lifetime_safety_invalidation @@ -10932,7 +10929,7 @@ def warn_lifetime_safety_dangling_field_moved : Warning<"address of stack memory escapes to a field. " "This could be a false positive as the storage may have been moved. " "Consider moving first and then aliasing later to resolve the issue">, - InGroup<LifetimeSafetyDanglingFieldStrict>, + InGroup<LifetimeSafetyDanglingFieldMoved>, DefaultIgnore; def note_lifetime_safety_used_here : Note<"later used here">; diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 5c49e601840cf..76dd00ee96e35 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2862,12 +2862,10 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr, const Expr *MovedExpr, SourceLocation FreeLoc, - Confidence C) override { + Confidence) override { S.Diag(IssueExpr->getExprLoc(), - MovedExpr ? diag::warn_lifetime_safety_loan_expires_moved_strict - : C == Confidence::Definite - ? diag::warn_lifetime_safety_loan_expires_permissive - : diag::warn_lifetime_safety_loan_expires_strict) + MovedExpr ? diag::warn_lifetime_safety_use_after_scope_moved + : diag::warn_lifetime_safety_use_after_scope) << IssueExpr->getSourceRange(); if (MovedExpr) S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here) @@ -2879,10 +2877,10 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { void reportUseAfterReturn(const Expr *IssueExpr, const Expr *ReturnExpr, const Expr *MovedExpr, SourceLocation ExpiryLoc, - Confidence C) override { + Confidence) override { S.Diag(IssueExpr->getExprLoc(), - MovedExpr ? diag::warn_lifetime_safety_return_stack_addr_moved_strict - : diag::warn_lifetime_safety_return_stack_addr_permissive) + MovedExpr ? diag::warn_lifetime_safety_return_stack_addr_moved + : diag::warn_lifetime_safety_return_stack_addr) << IssueExpr->getSourceRange(); if (MovedExpr) S.Diag(MovedExpr->getExprLoc(), diag::note_lifetime_safety_moved_here) @@ -3150,17 +3148,14 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true; bool IsLifetimeSafetyDiagnosticEnabled = - !Diags.isIgnored(diag::warn_lifetime_safety_loan_expires_permissive, + !Diags.isIgnored(diag::warn_lifetime_safety_use_after_scope, D->getBeginLoc()) || - !Diags.isIgnored(diag::warn_lifetime_safety_loan_expires_strict, + !Diags.isIgnored(diag::warn_lifetime_safety_use_after_scope_moved, D->getBeginLoc()) || - !Diags.isIgnored(diag::warn_lifetime_safety_loan_expires_moved_strict, + !Diags.isIgnored(diag::warn_lifetime_safety_return_stack_addr, D->getBeginLoc()) || - !Diags.isIgnored(diag::warn_lifetime_safety_return_stack_addr_permissive, + !Diags.isIgnored(diag::warn_lifetime_safety_return_stack_addr_moved, D->getBeginLoc()) || - !Diags.isIgnored( - diag::warn_lifetime_safety_return_stack_addr_moved_strict, - D->getBeginLoc()) || !Diags.isIgnored(diag::warn_lifetime_safety_invalidation, D->getBeginLoc()) || !Diags.isIgnored(diag::warn_lifetime_safety_noescape_escapes, diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 8f52ff27bc6fd..3516ab14d925a 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -174,7 +174,7 @@ void potential_if_branch(bool cond) { MyObj* p = &safe; if (cond) { MyObj temp; - p = &temp; // expected-warning {{object whose reference is captured may not live long enough}} + p = &temp; // expected-warning {{object whose reference is captured does not live long enough}} } // expected-note {{destroyed here}} if (!cond) (void)*p; // expected-note {{later used here}} @@ -202,7 +202,7 @@ void definite_potential_together(bool cond) { if (cond) p_definite = &s; // expected-warning {{does not live long enough}} if (cond) - p_maybe = &s; // expected-warning {{may not live long enough}} + p_maybe = &s; // expected-warning {{does not live long enough}} } // expected-note 2 {{destroyed here}} (void)*p_definite; // expected-note {{later used here}} if (!cond) @@ -235,7 +235,7 @@ void potential_due_to_conditional_killing(bool cond) { MyObj* q; { MyObj s; - q = &s; // expected-warning {{may not live long enough}} + q = &s; // expected-warning {{does not live long enough}} } // expected-note {{destroyed here}} if (cond) { // 'q' is conditionally "rescued". 'p' is not. @@ -248,7 +248,7 @@ void potential_for_loop_use_after_loop_body(MyObj safe) { MyObj* p = &safe; for (int i = 0; i < 1; ++i) { MyObj s; - p = &s; // expected-warning {{may not live long enough}} + p = &s; // expected-warning {{does not live long enough}} } // expected-note {{destroyed here}} (void)*p; // expected-note {{later used here}} } @@ -268,7 +268,7 @@ void potential_for_loop_gsl() { View v = safe; for (int i = 0; i < 1; ++i) { MyObj s; - v = s; // expected-warning {{object whose reference is captured may not live long enough}} + v = s; // expected-warning {{object whose reference is captured does not live long enough}} } // expected-note {{destroyed here}} v.use(); // expected-note {{later used here}} } @@ -366,7 +366,7 @@ void potential_switch(int mode) { switch (mode) { case 1: { MyObj temp; - p = &temp; // expected-warning {{object whose reference is captured may not live long enough}} + p = &temp; // expected-warning {{object whose reference is captured does not live long enough}} break; // expected-note {{destroyed here}} } case 2: { @@ -430,7 +430,7 @@ void loan_from_previous_iteration(MyObj safe, bool condition) { while (condition) { MyObj x; - p = &x; // expected-warning {{may not live long enough}} + p = &x; // expected-warning {{does not live long enough}} if (condition) q = p; @@ -994,7 +994,7 @@ void conditional_operator_one_unsafe_branch(bool cond) { MyObj* p = &safe; { MyObj temp; - p = cond ? &temp // expected-warning {{object whose reference is captured may not live long enough}} + p = cond ? &temp // expected-warning {{object whose reference is captured does not live long enough}} : &safe; } // expected-note {{destroyed here}} @@ -1191,7 +1191,7 @@ void range_based_for_not_reference() { { MyObjStorage s; for (MyObj o : s) { // expected-note {{destroyed here}} - v = o; // expected-warning {{object whose reference is captured may not live long enough}} + v = o; // expected-warning {{object whose reference is captured does not live long enough}} } } v.use(); // expected-note {{later used here}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
