llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Utkarsh Saxena (usx95)
<details>
<summary>Changes</summary>
Reorganized lifetime safety diagnostic groups to be more granular and renamed
diagnostic messages for better clarity.
- **Diagnostic Group Restructuring**: Split lifetime safety warnings into more
specific categories:
- `lifetime-safety-use-after-scope` and
`lifetime-safety-use-after-scope-moved` for scope-related issues
- `lifetime-safety-return-stack-addr` and
`lifetime-safety-return-stack-addr-moved` for return address issues
- `lifetime-safety-dangling-field` and
`lifetime-safety-dangling-field-moved` for field reference issues
- Added new umbrella groups `lifetime-safety-validations` and
`lifetime-safety-all`
- **Diagnostic Message Updates**: Renamed warning diagnostics from generic
"loan expires" terminology to more specific messages like "use after scope" and
"return stack addr"
- **Code Cleanup**: Removed `Confidence` logic (based on possible vs guaranteed
control-flow) from diagnostic reporting functions. Added TODO comment to
deprecate the `Confidence` enum
The new diagnostic group tree is:
```
lifetime-safety-all
├── lifetime-safety
│ ├── lifetime-safety-permissive
│ │ ├── lifetime-safety-use-after-scope
│ │ ├── lifetime-safety-return-stack-addr
│ │ └── lifetime-safety-dangling-field
│ └── lifetime-safety-strict
│ ├── lifetime-safety-use-after-scope-moved
│ ├── lifetime-safety-return-stack-addr-moved
│ ├── lifetime-safety-dangling-field-moved
│ └── lifetime-safety-invalidation
├── lifetime-safety-suggestions
│ ├── lifetime-safety-cross-tu-suggestions
│ └── lifetime-safety-intra-tu-suggestions
└── lifetime-safety-validations
└── lifetime-safety-noescape
```
---
Full diff: https://github.com/llvm/llvm-project/pull/179309.diff
5 Files Affected:
- (modified)
clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h (+2)
- (modified) clang/include/clang/Basic/DiagnosticGroups.td (+58-11)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+9-12)
- (modified) clang/lib/Sema/AnalysisBasedWarnings.cpp (+10-15)
- (modified) clang/test/Sema/warn-lifetime-safety.cpp (+9-9)
``````````diff
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}}
``````````
</details>
https://github.com/llvm/llvm-project/pull/179309
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits