[llvm-branch-commits] [clang] remove-confidence (PR #182709)
Utkarsh Saxena via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Feb 21 14:51:25 PST 2026
https://github.com/usx95 created https://github.com/llvm/llvm-project/pull/182709
None
>From 8396e8c3ef7beb070c261e450d2593496c9c3b66 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Sat, 21 Feb 2026 22:43:23 +0000
Subject: [PATCH] remove-confidence
---
.../Analyses/LifetimeSafety/LifetimeSafety.h | 18 +---
.../Analyses/LifetimeSafety/LiveOrigins.h | 24 +----
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 80 +++++++-------
.../Analysis/LifetimeSafety/LiveOrigins.cpp | 53 +++-------
clang/lib/Sema/AnalysisBasedWarnings.cpp | 6 +-
clang/test/Sema/warn-lifetime-safety.cpp | 62 +++++------
.../unittests/Analysis/LifetimeSafetyTest.cpp | 100 ++++++------------
7 files changed, 115 insertions(+), 228 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index d7aadf4cf04ca..095b8409d753d 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -28,20 +28,11 @@
#include "clang/Analysis/Analyses/LifetimeSafety/MovedLoans.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
#include "clang/Analysis/AnalysisDeclContext.h"
-#include <cstdint>
+#include <cstddef>
#include <memory>
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,
- Maybe, // Reported as a potential error (-Wlifetime-safety-strict)
- Definite // Reported as a definite error (-Wlifetime-safety-permissive)
-};
-
struct LifetimeSafetyOpts {
/// Maximum number of CFG blocks to analyze. Functions with larger CFGs will
/// be skipped.
@@ -70,14 +61,13 @@ class LifetimeSafetySemaHelper {
virtual ~LifetimeSafetySemaHelper() = default;
virtual void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
- const Expr *MovedExpr, SourceLocation FreeLoc,
- Confidence Confidence) {}
+ const Expr *MovedExpr,
+ SourceLocation FreeLoc) {}
virtual void reportUseAfterReturn(const Expr *IssueExpr,
const Expr *ReturnExpr,
const Expr *MovedExpr,
- SourceLocation ExpiryLoc,
- Confidence Confidence) {}
+ SourceLocation ExpiryLoc) {}
virtual void reportDanglingField(const Expr *IssueExpr,
const FieldDecl *Field,
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h
index 35b4224883cce..fa9deed9f3423 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h
@@ -34,12 +34,6 @@ namespace clang::lifetimes::internal {
using CausingFactType =
::llvm::PointerUnion<const UseFact *, const OriginEscapesFact *>;
-enum class LivenessKind : uint8_t {
- Dead, // Not alive
- Maybe, // Live on some path but not all paths (may-be-live)
- Must // Live on all paths (must-be-live)
-};
-
/// Information about why an origin is live at a program point.
struct LivenessInfo {
/// The use that makes the origin live. If liveness is propagated from
@@ -48,28 +42,16 @@ struct LivenessInfo {
/// This is 'null' when the origin is not live.
CausingFactType CausingFact;
- /// The kind of liveness of the origin.
- /// `Must`: The origin is live on all control-flow paths from the current
- /// point to the function's exit (i.e. the current point is dominated by a set
- /// of uses).
- /// `Maybe`: indicates it is live on some but not all paths.
- ///
- /// This determines the diagnostic's confidence level.
- /// `Must`-be-alive at expiration implies a definite use-after-free,
- /// while `Maybe`-be-alive suggests a potential one on some paths.
- LivenessKind Kind;
-
- LivenessInfo() : CausingFact(nullptr), Kind(LivenessKind::Dead) {}
- LivenessInfo(CausingFactType CF, LivenessKind K) : CausingFact(CF), Kind(K) {}
+ LivenessInfo() : CausingFact(nullptr) {}
+ LivenessInfo(CausingFactType CF) : CausingFact(CF) {}
bool operator==(const LivenessInfo &Other) const {
- return CausingFact == Other.CausingFact && Kind == Other.Kind;
+ return CausingFact == Other.CausingFact;
}
bool operator!=(const LivenessInfo &Other) const { return !(*this == Other); }
void Profile(llvm::FoldingSetNodeID &IDBuilder) const {
IDBuilder.AddPointer(CausingFact.getOpaqueValue());
- IDBuilder.Add(Kind);
}
};
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 78c2a6dba3eb6..efecd9363d481 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -24,24 +24,11 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TimeProfiler.h"
namespace clang::lifetimes::internal {
-static Confidence livenessKindToConfidence(LivenessKind K) {
- switch (K) {
- case LivenessKind::Must:
- return Confidence::Definite;
- case LivenessKind::Maybe:
- return Confidence::Maybe;
- case LivenessKind::Dead:
- return Confidence::None;
- }
- llvm_unreachable("unknown liveness kind");
-}
-
namespace {
/// Struct to store the complete context for a potential lifetime violation.
@@ -50,7 +37,6 @@ struct PendingWarning {
llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> CausingFact;
const Expr *MovedExpr;
const Expr *InvalidatedByExpr;
- Confidence ConfidenceLevel;
};
using AnnotationTarget =
@@ -69,6 +55,19 @@ class LifetimeChecker {
LifetimeSafetySemaHelper *SemaHelper;
ASTContext &AST;
+ static SourceLocation GetFactLoc(
+ llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> F) {
+ if (const auto *UF = F.dyn_cast<const UseFact *>())
+ return UF->getUseExpr()->getExprLoc();
+ if (const auto *OEF = F.dyn_cast<const OriginEscapesFact *>()) {
+ if (auto *ReturnEsc = dyn_cast<ReturnEscapeFact>(OEF))
+ return ReturnEsc->getReturnExpr()->getExprLoc();
+ if (auto *FieldEsc = dyn_cast<FieldEscapeFact>(OEF))
+ return FieldEsc->getFieldDecl()->getLocation();
+ }
+ llvm_unreachable("unhandled causing fact in PointerUnion");
+ }
+
public:
LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const MovedLoansAnalysis &MovedLoans,
@@ -139,9 +138,7 @@ class LifetimeChecker {
///
/// This method examines all live origins at the expiry point and determines
/// if any of them hold the expiring loan. If so, it creates a pending
- /// warning with the appropriate confidence level based on the liveness
- /// information. The confidence reflects whether the origin is definitely
- /// or maybe live at this point.
+ /// warning.
///
/// Note: This implementation considers only the confidence of origin
/// liveness. Future enhancements could also consider the confidence of loan
@@ -153,34 +150,31 @@ class LifetimeChecker {
MovedExpr = *ME;
LivenessMap Origins = LiveOrigins.getLiveOriginsAt(EF);
- Confidence CurConfidence = Confidence::None;
// The UseFact or OriginEscapesFact most indicative of a lifetime error,
// prioritized by earlier source location.
llvm::PointerUnion<const UseFact *, const OriginEscapesFact *>
- BestCausingFact = nullptr;
+ CausingFact = nullptr;
for (auto &[OID, LiveInfo] : Origins) {
LoanSet HeldLoans = LoanPropagation.getLoans(OID, EF);
if (!HeldLoans.contains(ExpiredLoan))
continue;
- // Loan is defaulted.
- Confidence NewConfidence = livenessKindToConfidence(LiveInfo.Kind);
- if (CurConfidence < NewConfidence) {
- CurConfidence = NewConfidence;
- BestCausingFact = LiveInfo.CausingFact;
- }
+
+ if (!CausingFact ||
+ GetFactLoc(LiveInfo.CausingFact) < GetFactLoc(CausingFact))
+ CausingFact = LiveInfo.CausingFact;
}
- if (!BestCausingFact)
- return;
- // We have a use-after-free.
- Confidence LastConf = FinalWarningsMap.lookup(ExpiredLoan).ConfidenceLevel;
- if (LastConf >= CurConfidence)
+ if (!CausingFact)
return;
- FinalWarningsMap[ExpiredLoan] = {/*ExpiryLoc=*/EF->getExpiryLoc(),
- /*BestCausingFact=*/BestCausingFact,
- /*MovedExpr=*/MovedExpr,
- /*InvalidatedByExpr=*/nullptr,
- /*ConfidenceLevel=*/CurConfidence};
+
+ auto It = FinalWarningsMap.find(ExpiredLoan);
+ if (It == FinalWarningsMap.end() ||
+ GetFactLoc(CausingFact) < GetFactLoc(It->second.CausingFact)) {
+ FinalWarningsMap[ExpiredLoan] = {/*ExpiryLoc=*/EF->getExpiryLoc(),
+ CausingFact,
+ /*MovedExpr=*/MovedExpr,
+ /*InvalidatedByExpr=*/nullptr};
+ }
}
/// Checks for use-after-invalidation errors when a container is modified.
@@ -216,16 +210,15 @@ class LifetimeChecker {
LoanSet HeldLoans = LoanPropagation.getLoans(OID, IOF);
for (LoanID LiveLoanID : HeldLoans)
if (IsInvalidated(FactMgr.getLoanMgr().getLoan(LiveLoanID))) {
- Confidence CurConfidence = livenessKindToConfidence(LiveInfo.Kind);
- Confidence LastConf =
- FinalWarningsMap.lookup(LiveLoanID).ConfidenceLevel;
- if (LastConf < CurConfidence) {
+ auto It = FinalWarningsMap.find(LiveLoanID);
+ if (It == FinalWarningsMap.end() ||
+ GetFactLoc(LiveInfo.CausingFact) <
+ GetFactLoc(It->second.CausingFact)) {
FinalWarningsMap[LiveLoanID] = {
/*ExpiryLoc=*/{},
/*CausingFact=*/LiveInfo.CausingFact,
/*MovedExpr=*/nullptr,
- /*InvalidatedByExpr=*/IOF->getInvalidationExpr(),
- /*ConfidenceLevel=*/CurConfidence};
+ /*InvalidatedByExpr=*/IOF->getInvalidationExpr()};
}
}
}
@@ -245,7 +238,6 @@ class LifetimeChecker {
InvalidatedPVD = PL->getParmVarDecl();
llvm::PointerUnion<const UseFact *, const OriginEscapesFact *>
CausingFact = Warning.CausingFact;
- Confidence Confidence = Warning.ConfidenceLevel;
const Expr *MovedExpr = Warning.MovedExpr;
SourceLocation ExpiryLoc = Warning.ExpiryLoc;
@@ -260,13 +252,13 @@ class LifetimeChecker {
} else
SemaHelper->reportUseAfterFree(IssueExpr, UF->getUseExpr(), MovedExpr,
- ExpiryLoc, Confidence);
+ ExpiryLoc);
} else if (const auto *OEF =
CausingFact.dyn_cast<const OriginEscapesFact *>()) {
if (const auto *RetEscape = dyn_cast<ReturnEscapeFact>(OEF))
SemaHelper->reportUseAfterReturn(IssueExpr,
RetEscape->getReturnExpr(),
- MovedExpr, ExpiryLoc, Confidence);
+ MovedExpr, ExpiryLoc);
else if (const auto *FieldEscape = dyn_cast<FieldEscapeFact>(OEF))
SemaHelper->reportDanglingField(
IssueExpr, FieldEscape->getFieldDecl(), MovedExpr, ExpiryLoc);
diff --git a/clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp b/clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp
index f210fb4d752d4..b18999fbbbef4 100644
--- a/clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp
@@ -35,21 +35,9 @@ struct Lattice {
OS << " <empty>\n";
for (const auto &Entry : LiveOrigins) {
OriginID OID = Entry.first;
- const LivenessInfo &Info = Entry.second;
OS << " ";
OM.dump(OID, OS);
- OS << " is ";
- switch (Info.Kind) {
- case LivenessKind::Must:
- OS << "definitely";
- break;
- case LivenessKind::Maybe:
- OS << "maybe";
- break;
- case LivenessKind::Dead:
- llvm_unreachable("liveness kind of live origins should not be dead.");
- }
- OS << " live at this point\n";
+ OS << " is live at this point\n";
}
}
};
@@ -67,8 +55,7 @@ static SourceLocation GetFactLoc(CausingFactType F) {
}
/// The analysis that tracks which origins are live, with granular information
-/// about the causing use fact and confidence level. This is a backward
-/// analysis.
+/// about the causing use fact. This is a backward analysis.
class AnalysisImpl
: public DataflowAnalysis<AnalysisImpl, Lattice, Direction::Backward> {
@@ -83,8 +70,6 @@ class AnalysisImpl
Lattice getInitialState() { return Lattice(Factory.getEmptyMap()); }
/// Merges two lattices by combining liveness information.
- /// When the same origin has different confidence levels, we take the lower
- /// one.
Lattice join(Lattice L1, Lattice L2) const {
LivenessMap Merged = L1.LiveOrigins;
// Take the earliest Fact to make the join hermetic and commutative.
@@ -96,34 +81,24 @@ class AnalysisImpl
return A;
return GetFactLoc(A) < GetFactLoc(B) ? A : B;
};
- auto CombineLivenessKind = [](LivenessKind K1,
- LivenessKind K2) -> LivenessKind {
- assert(K1 != LivenessKind::Dead && "LivenessKind should not be dead.");
- assert(K2 != LivenessKind::Dead && "LivenessKind should not be dead.");
- // Only return "Must" if both paths are "Must", otherwise Maybe.
- if (K1 == LivenessKind::Must && K2 == LivenessKind::Must)
- return LivenessKind::Must;
- return LivenessKind::Maybe;
- };
auto CombineLivenessInfo = [&](const LivenessInfo *L1,
const LivenessInfo *L2) -> LivenessInfo {
assert((L1 || L2) && "unexpectedly merging 2 empty sets");
if (!L1)
- return LivenessInfo(L2->CausingFact, LivenessKind::Maybe);
+ return LivenessInfo(L2->CausingFact);
if (!L2)
- return LivenessInfo(L1->CausingFact, LivenessKind::Maybe);
- return LivenessInfo(CombineCausingFact(L1->CausingFact, L2->CausingFact),
- CombineLivenessKind(L1->Kind, L2->Kind));
+ return LivenessInfo(L1->CausingFact);
+ return LivenessInfo(CombineCausingFact(L1->CausingFact, L2->CausingFact));
};
return Lattice(utils::join(
L1.LiveOrigins, L2.LiveOrigins, Factory, CombineLivenessInfo,
// A symmetric join is required here. If an origin is live on one
- // branch but not the other, its confidence must be demoted to `Maybe`.
+ // branch but not the other, it is live in the joined state.
utils::JoinKind::Symmetric));
}
- /// A read operation makes the origin live with definite confidence, as it
- /// dominates this program point. A write operation kills the liveness of
+ /// A read operation makes the origin live, as it dominates this program
+ /// point. A write operation kills the liveness of
/// the origin since it overwrites the value.
Lattice transfer(Lattice In, const UseFact &UF) {
Lattice Out = In;
@@ -134,21 +109,17 @@ class AnalysisImpl
if (UF.isWritten()) {
Out = Lattice(Factory.remove(Out.LiveOrigins, OID));
} else {
- // Read makes origin live with definite confidence (dominates this
- // point).
- Out = Lattice(Factory.add(Out.LiveOrigins, OID,
- LivenessInfo(&UF, LivenessKind::Must)));
+ // Read makes origin live.
+ Out = Lattice(Factory.add(Out.LiveOrigins, OID, LivenessInfo(&UF)));
}
}
return Out;
}
- /// An escaping origin (e.g., via return) makes the origin live with definite
- /// confidence, as it dominates this program point.
+ /// An escaping origin (e.g., via return) makes the origin live.
Lattice transfer(Lattice In, const OriginEscapesFact &OEF) {
OriginID OID = OEF.getEscapedOriginID();
- return Lattice(Factory.add(In.LiveOrigins, OID,
- LivenessInfo(&OEF, LivenessKind::Must)));
+ return Lattice(Factory.add(In.LiveOrigins, OID, LivenessInfo(&OEF)));
}
/// Issuing a new loan to an origin kills its liveness.
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 20c41096501fb..6cab356f7f4e2 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2861,8 +2861,7 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
LifetimeSafetySemaHelperImpl(Sema &S) : S(S) {}
void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
- const Expr *MovedExpr, SourceLocation FreeLoc,
- Confidence) override {
+ const Expr *MovedExpr, SourceLocation FreeLoc) override {
S.Diag(IssueExpr->getExprLoc(),
MovedExpr ? diag::warn_lifetime_safety_use_after_scope_moved
: diag::warn_lifetime_safety_use_after_scope)
@@ -2876,8 +2875,7 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
}
void reportUseAfterReturn(const Expr *IssueExpr, const Expr *ReturnExpr,
- const Expr *MovedExpr, SourceLocation ExpiryLoc,
- Confidence) override {
+ const Expr *MovedExpr, SourceLocation ExpiryLoc) override {
S.Diag(IssueExpr->getExprLoc(),
MovedExpr ? diag::warn_lifetime_safety_return_stack_addr_moved
: diag::warn_lifetime_safety_return_stack_addr)
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 097f3279d8e54..f5d1871ec36a1 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -46,11 +46,10 @@ View construct_view(const MyObj &obj [[clang::lifetimebound]]) {
void use(View);
//===----------------------------------------------------------------------===//
-// Basic Definite Use-After-Free (-W...permissive)
-// These are cases where the pointer is guaranteed to be dangling at the use site.
+// Basic Use-After-Free
//===----------------------------------------------------------------------===//
-void definite_simple_case() {
+void simple_case() {
MyObj* p;
{
MyObj s;
@@ -59,7 +58,7 @@ void definite_simple_case() {
(void)*p; // expected-note {{later used here}}
}
-void definite_simple_case_gsl() {
+void simple_case_gsl() {
View v;
{
MyObj s;
@@ -86,7 +85,7 @@ void no_use_no_error_gsl() {
// 'v' is dangling here, but since it is never used, no warning is issued.
}
-void definite_pointer_chain() {
+void pointer_chain() {
MyObj* p;
MyObj* q;
{
@@ -97,7 +96,7 @@ void definite_pointer_chain() {
(void)*q; // expected-note {{later used here}}
}
-void definite_propagation_gsl() {
+void propagation_gsl() {
View v1, v2;
{
MyObj s;
@@ -107,7 +106,7 @@ void definite_propagation_gsl() {
v2.use(); // expected-note {{later used here}}
}
-void definite_multiple_uses_one_warning() {
+void multiple_uses_one_warning() {
MyObj* p;
{
MyObj s;
@@ -120,7 +119,7 @@ void definite_multiple_uses_one_warning() {
(void)*q;
}
-void definite_multiple_pointers() {
+void multiple_pointers() {
MyObj *p, *q, *r;
{
MyObj s;
@@ -133,7 +132,7 @@ void definite_multiple_pointers() {
(void)*r; // expected-note {{later used here}}
}
-void definite_single_pointer_multiple_loans(bool cond) {
+void single_pointer_multiple_loans(bool cond) {
MyObj *p;
if (cond){
MyObj s;
@@ -146,7 +145,7 @@ void definite_single_pointer_multiple_loans(bool cond) {
(void)*p; // expected-note 2 {{later used here}}
}
-void definite_single_pointer_multiple_loans_gsl(bool cond) {
+void single_pointer_multiple_loans_gsl(bool cond) {
View v;
if (cond){
MyObj s;
@@ -159,7 +158,7 @@ void definite_single_pointer_multiple_loans_gsl(bool cond) {
v.use(); // expected-note 2 {{later used here}}
}
-void definite_if_branch(bool cond) {
+void if_branch(bool cond) {
MyObj safe;
MyObj* p = &safe;
if (cond) {
@@ -169,7 +168,7 @@ void definite_if_branch(bool cond) {
(void)*p; // expected-note {{later used here}}
}
-void potential_if_branch(bool cond) {
+void if_branch_potential(bool cond) {
MyObj safe;
MyObj* p = &safe;
if (cond) {
@@ -182,7 +181,7 @@ void potential_if_branch(bool cond) {
p = &safe;
}
-void definite_if_branch_gsl(bool cond) {
+void if_branch_gsl(bool cond) {
MyObj safe;
View v = safe;
if (cond) {
@@ -192,7 +191,7 @@ void definite_if_branch_gsl(bool cond) {
v.use(); // expected-note {{later used here}}
}
-void definite_potential_together(bool cond) {
+void potential_together(bool cond) {
MyObj safe;
MyObj* p_maybe = &safe;
MyObj* p_definite = nullptr;
@@ -209,7 +208,7 @@ void definite_potential_together(bool cond) {
(void)*p_maybe; // expected-note {{later used here}}
}
-void definite_overrides_potential(bool cond) {
+void overrides_potential(bool cond) {
MyObj safe;
MyObj* p;
MyObj* q;
@@ -224,13 +223,12 @@ void definite_overrides_potential(bool cond) {
q = &safe;
}
- // The use of 'p' is a definite error because it was never rescued.
- (void)*q;
- (void)*p; // expected-note {{later used here}}
+ (void)*q; // expected-note {{later used here}}
+ (void)*p;
(void)*q;
}
-void potential_due_to_conditional_killing(bool cond) {
+void due_to_conditional_killing(bool cond) {
MyObj safe;
MyObj* q;
{
@@ -244,7 +242,7 @@ void potential_due_to_conditional_killing(bool cond) {
(void)*q; // expected-note {{later used here}}
}
-void potential_for_loop_use_after_loop_body(MyObj safe) {
+void for_loop_use_after_loop_body(MyObj safe) {
MyObj* p = &safe;
for (int i = 0; i < 1; ++i) {
MyObj s;
@@ -263,7 +261,7 @@ void safe_for_loop_gsl() {
}
}
-void potential_for_loop_gsl() {
+void for_loop_gsl() {
MyObj safe;
View v = safe;
for (int i = 0; i < 1; ++i) {
@@ -273,7 +271,7 @@ void potential_for_loop_gsl() {
v.use(); // expected-note {{later used here}}
}
-void potential_for_loop_use_before_loop_body(MyObj safe) {
+void for_loop_use_before_loop_body(MyObj safe) {
MyObj* p = &safe;
// Prefer the earlier use for diagnsotics.
for (int i = 0; i < 1; ++i) {
@@ -284,7 +282,7 @@ void potential_for_loop_use_before_loop_body(MyObj safe) {
(void)*p;
}
-void definite_loop_with_break(bool cond) {
+void loop_with_break(bool cond) {
MyObj safe;
MyObj* p = &safe;
for (int i = 0; i < 10; ++i) {
@@ -297,7 +295,7 @@ void definite_loop_with_break(bool cond) {
(void)*p; // expected-note {{later used here}}
}
-void definite_loop_with_break_gsl(bool cond) {
+void loop_with_break_gsl(bool cond) {
MyObj safe;
View v = safe;
for (int i = 0; i < 10; ++i) {
@@ -310,7 +308,7 @@ void definite_loop_with_break_gsl(bool cond) {
v.use(); // expected-note {{later used here}}
}
-void potential_multiple_expiry_of_same_loan(bool cond) {
+void multiple_expiry_of_same_loan(bool cond) {
// Choose the last expiry location for the loan (e.g., through scope-ends and break statements).
MyObj safe;
MyObj* p = &safe;
@@ -342,11 +340,6 @@ void potential_multiple_expiry_of_same_loan(bool cond) {
break; // expected-note {{destroyed here}}
}
}
-
- // TODO: This can be argued to be a "maybe" warning. This is because
- // we only check for confidence of liveness and not the confidence of
- // the loan contained in an origin. To deal with this, we can introduce
- // a confidence in loan propagation analysis as well like liveness.
(void)*p; // expected-note {{later used here}}
p = &safe;
@@ -360,7 +353,7 @@ void potential_multiple_expiry_of_same_loan(bool cond) {
(void)*p; // expected-note {{later used here}}
}
-void potential_switch(int mode) {
+void switch_potential(int mode) {
MyObj safe;
MyObj* p = &safe;
switch (mode) {
@@ -378,7 +371,7 @@ void potential_switch(int mode) {
(void)*p; // expected-note {{later used here}}
}
-void definite_switch(int mode) {
+void switch_uaf(int mode) {
MyObj safe;
MyObj* p = &safe;
// A use domintates all the loan expires --> all definite error.
@@ -402,7 +395,7 @@ void definite_switch(int mode) {
(void)*p; // expected-note 3 {{later used here}}
}
-void definite_switch_gsl(int mode) {
+void switch_gsl(int mode) {
View v;
switch (mode) {
case 1: {
@@ -468,8 +461,7 @@ void small_scope_reference_var_no_error() {
}
//===----------------------------------------------------------------------===//
-// Basic Definite Use-After-Return (Return-Stack-Address) (-W...permissive)
-// These are cases where the pointer is guaranteed to be dangling at the use site.
+// Basic Use-After-Return (Return-Stack-Address)
//===----------------------------------------------------------------------===//
MyObj* simple_return_stack_address() {
diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
index a27f746fffb60..437ef9d4aae83 100644
--- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp
+++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
@@ -178,21 +178,21 @@ class LifetimeTestHelper {
}
std::optional<LoanSet> getLoansAtPoint(OriginID OID,
- llvm::StringRef Annotation) {
+ llvm::StringRef Annotation) const {
ProgramPoint PP = Runner.getProgramPoint(Annotation);
if (!PP)
return std::nullopt;
return Analysis.getLoanPropagation().getLoans(OID, PP);
}
- std::optional<std::vector<std::pair<OriginID, LivenessKind>>>
- getLiveOriginsAtPoint(llvm::StringRef Annotation) {
+ std::optional<std::vector<OriginID>>
+ getLiveOriginsAtPoint(llvm::StringRef Annotation) const {
ProgramPoint PP = Runner.getProgramPoint(Annotation);
if (!PP)
return std::nullopt;
- std::vector<std::pair<OriginID, LivenessKind>> Result;
+ std::vector<OriginID> Result;
for (auto &[OID, Info] : Analysis.getLiveOrigins().getLiveOriginsAt(PP))
- Result.push_back({OID, Info.Kind});
+ Result.push_back(OID);
return Result;
}
@@ -316,10 +316,8 @@ MATCHER_P2(HasLoansToImpl, LoanVars, Annotation, "") {
ActualLoans, result_listener);
}
-enum class LivenessKindFilter { Maybe, Must, All };
-
/// Matcher to verify the complete set of live origins at a program point.
-MATCHER_P2(AreLiveAtImpl, Annotation, ConfFilter, "") {
+MATCHER_P(AreLiveAtImpl, Annotation, "") {
const OriginsInfo &Info = arg;
auto &Helper = Info.Helper;
auto ActualLiveSetOpt = Helper.getLiveOriginsAtPoint(Annotation);
@@ -328,17 +326,7 @@ MATCHER_P2(AreLiveAtImpl, Annotation, ConfFilter, "") {
<< Annotation << "'";
return false;
}
- std::vector<OriginID> ActualLiveOrigins;
- for (const auto [OID, ActualConfidence] : ActualLiveSetOpt.value()) {
- if (ConfFilter == LivenessKindFilter::All)
- ActualLiveOrigins.push_back(OID);
- if (ActualConfidence == LivenessKind::Maybe &&
- ConfFilter == LivenessKindFilter::Maybe)
- ActualLiveOrigins.push_back(OID);
- if (ActualConfidence == LivenessKind::Must &&
- ConfFilter == LivenessKindFilter::Must)
- ActualLiveOrigins.push_back(OID);
- }
+ std::vector<OriginID> ActualLiveOrigins = ActualLiveSetOpt.value();
std::vector<OriginID> ExpectedLiveOrigins;
for (const auto &VarName : Info.OriginVars) {
@@ -404,20 +392,8 @@ MATCHER_P2(HasLiveLoanAtExpiryImpl, HelperPtr, Annotation, "") {
return false;
}
-MATCHER_P(MustBeLiveAt, Annotation, "") {
- return ExplainMatchResult(AreLiveAtImpl(Annotation, LivenessKindFilter::Must),
- arg, result_listener);
-}
-
-MATCHER_P(MaybeLiveAt, Annotation, "") {
- return ExplainMatchResult(
- AreLiveAtImpl(Annotation, LivenessKindFilter::Maybe), arg,
- result_listener);
-}
-
MATCHER_P(AreLiveAt, Annotation, "") {
- return ExplainMatchResult(AreLiveAtImpl(Annotation, LivenessKindFilter::All),
- arg, result_listener);
+ return ExplainMatchResult(AreLiveAtImpl(Annotation), arg, result_listener);
}
MATCHER_P(HasLoanToATemporary, Annotation, "") {
@@ -1216,7 +1192,7 @@ TEST_F(LifetimeAnalysisTest, LivenessSimpleReturn) {
return p;
}
)");
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p1"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p1"));
}
TEST_F(LifetimeAnalysisTest, LivenessKilledByReassignment) {
@@ -1230,7 +1206,7 @@ TEST_F(LifetimeAnalysisTest, LivenessKilledByReassignment) {
return p;
}
)");
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p2"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p2"));
EXPECT_THAT(NoOrigins(), AreLiveAt("p1"));
}
@@ -1250,8 +1226,8 @@ TEST_F(LifetimeAnalysisTest, LivenessAcrossBranches) {
return p;
}
)");
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p2"));
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p3"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p2"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p3"));
// Before the `if`, the value of `p` (`nullptr`) is always overwritten before.
EXPECT_THAT(NoOrigins(), AreLiveAt("p1"));
}
@@ -1274,15 +1250,10 @@ TEST_F(LifetimeAnalysisTest, LivenessInLoop) {
}
)");
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p4"));
- EXPECT_THAT(NoOrigins(), MaybeLiveAt("p4"));
-
- EXPECT_THAT(Origins({"p", "q"}), MaybeLiveAt("p3"));
-
- EXPECT_THAT(Origins({"q"}), MustBeLiveAt("p2"));
- EXPECT_THAT(NoOrigins(), MaybeLiveAt("p2"));
-
- EXPECT_THAT(Origins({"p", "q"}), MaybeLiveAt("p1"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p4"));
+ EXPECT_THAT(Origins({"p", "q"}), AreLiveAt("p3"));
+ EXPECT_THAT(Origins({"q"}), AreLiveAt("p2"));
+ EXPECT_THAT(Origins({"p", "q"}), AreLiveAt("p1"));
}
TEST_F(LifetimeAnalysisTest, LivenessInLoopAndIf) {
@@ -1309,9 +1280,9 @@ TEST_F(LifetimeAnalysisTest, LivenessInLoopAndIf) {
}
)");
EXPECT_THAT(NoOrigins(), AreLiveAt("p5"));
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p4"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p4"));
EXPECT_THAT(NoOrigins(), AreLiveAt("p3"));
- EXPECT_THAT(Origins({"p"}), MaybeLiveAt("p2"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p2"));
EXPECT_THAT(NoOrigins(), AreLiveAt("p1"));
}
@@ -1341,21 +1312,12 @@ TEST_F(LifetimeAnalysisTest, LivenessInLoopAndIf2) {
}
}
)");
- EXPECT_THAT(Origins({"q"}), MaybeLiveAt("p6"));
- EXPECT_THAT(NoOrigins(), MustBeLiveAt("p6"));
-
- EXPECT_THAT(Origins({"p", "q"}), MustBeLiveAt("p5"));
-
- EXPECT_THAT(Origins({"p", "q"}), MustBeLiveAt("p4"));
-
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p3"));
- EXPECT_THAT(Origins({"q"}), MaybeLiveAt("p3"));
-
- EXPECT_THAT(Origins({"q"}), MaybeLiveAt("p2"));
- EXPECT_THAT(NoOrigins(), MustBeLiveAt("p2"));
-
- EXPECT_THAT(Origins({"q"}), MaybeLiveAt("p1"));
- EXPECT_THAT(NoOrigins(), MustBeLiveAt("p1"));
+ EXPECT_THAT(Origins({"q"}), AreLiveAt("p6"));
+ EXPECT_THAT(Origins({"p", "q"}), AreLiveAt("p5"));
+ EXPECT_THAT(Origins({"p", "q"}), AreLiveAt("p4"));
+ EXPECT_THAT(Origins({"p", "q"}), AreLiveAt("p3"));
+ EXPECT_THAT(Origins({"q"}), AreLiveAt("p2"));
+ EXPECT_THAT(Origins({"q"}), AreLiveAt("p1"));
}
TEST_F(LifetimeAnalysisTest, LivenessOutsideLoop) {
@@ -1371,8 +1333,8 @@ TEST_F(LifetimeAnalysisTest, LivenessOutsideLoop) {
(void)*p;
}
)");
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p2"));
- EXPECT_THAT(Origins({"p"}), MaybeLiveAt("p1"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p2"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p1"));
}
TEST_F(LifetimeAnalysisTest, TrivialDestructorsUAF) {
@@ -1388,7 +1350,7 @@ TEST_F(LifetimeAnalysisTest, TrivialDestructorsUAF) {
}
)");
EXPECT_THAT(Origin("ptr"), HasLoansTo({"s"}, "p1"));
- EXPECT_THAT(Origins({"ptr"}), MustBeLiveAt("p1"));
+ EXPECT_THAT(Origins({"ptr"}), AreLiveAt("p1"));
}
TEST_F(LifetimeAnalysisTest, TrivialClassDestructorsUAF) {
@@ -1408,7 +1370,7 @@ TEST_F(LifetimeAnalysisTest, TrivialClassDestructorsUAF) {
}
)");
EXPECT_THAT(Origin("ptr"), HasLoansTo({"s"}, "p1"));
- EXPECT_THAT(Origins({"ptr"}), MustBeLiveAt("p1"));
+ EXPECT_THAT(Origins({"ptr"}), AreLiveAt("p1"));
}
TEST_F(LifetimeAnalysisTest, SimpleReturnStackAddress) {
@@ -1577,10 +1539,10 @@ TEST_F(LifetimeAnalysisTest, UseAfterScopeThenReturn) {
}
)");
EXPECT_THAT(Origin("p"), HasLoansTo({"local_obj"}, "p2"));
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p2"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p2"));
EXPECT_THAT(Origin("p"), HasLoansTo({"local_obj"}, "p1"));
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p1"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p1"));
EXPECT_THAT("local_obj", HasLiveLoanAtExpiry("p2"));
}
@@ -1607,7 +1569,7 @@ TEST_F(LifetimeAnalysisTest, ReturnBeforeUseAfterScope) {
EXPECT_THAT(NoOrigins(), AreLiveAt("p2"));
EXPECT_THAT(Origin("p"), HasLoansTo({"local_obj"}, "p1"));
- EXPECT_THAT(Origins({"p"}), MustBeLiveAt("p1"));
+ EXPECT_THAT(Origins({"p"}), AreLiveAt("p1"));
}
TEST_F(LifetimeAnalysisTest, TrivialDestructorsUAR) {
More information about the llvm-branch-commits
mailing list