Skip to content

Commit 54b5068

Browse files
committed
Revert "[LifetimeSafety] Revamp test suite using unittests (#149158)"
This reverts commit 688ea04.
1 parent d544005 commit 54b5068

File tree

6 files changed

+139
-665
lines changed

6 files changed

+139
-665
lines changed

clang/include/clang/Analysis/Analyses/LifetimeSafety.h

Lines changed: 5 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -17,96 +17,14 @@
1717
//===----------------------------------------------------------------------===//
1818
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
1919
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
20+
#include "clang/AST/DeclBase.h"
2021
#include "clang/Analysis/AnalysisDeclContext.h"
2122
#include "clang/Analysis/CFG.h"
22-
#include "llvm/ADT/ImmutableSet.h"
23-
#include "llvm/ADT/StringMap.h"
24-
#include <memory>
23+
namespace clang {
2524

26-
namespace clang::lifetimes {
25+
void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg,
26+
AnalysisDeclContext &AC);
2727

28-
/// The main entry point for the analysis.
29-
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC);
30-
31-
namespace internal {
32-
// Forward declarations of internal types.
33-
class Fact;
34-
class FactManager;
35-
class LoanPropagationAnalysis;
36-
struct LifetimeFactory;
37-
38-
/// A generic, type-safe wrapper for an ID, distinguished by its `Tag` type.
39-
/// Used for giving ID to loans and origins.
40-
template <typename Tag> struct ID {
41-
uint32_t Value = 0;
42-
43-
bool operator==(const ID<Tag> &Other) const { return Value == Other.Value; }
44-
bool operator!=(const ID<Tag> &Other) const { return !(*this == Other); }
45-
bool operator<(const ID<Tag> &Other) const { return Value < Other.Value; }
46-
ID<Tag> operator++(int) {
47-
ID<Tag> Tmp = *this;
48-
++Value;
49-
return Tmp;
50-
}
51-
void Profile(llvm::FoldingSetNodeID &IDBuilder) const {
52-
IDBuilder.AddInteger(Value);
53-
}
54-
};
55-
56-
using LoanID = ID<struct LoanTag>;
57-
using OriginID = ID<struct OriginTag>;
58-
59-
// Using LLVM's immutable collections is efficient for dataflow analysis
60-
// as it avoids deep copies during state transitions.
61-
// TODO(opt): Consider using a bitset to represent the set of loans.
62-
using LoanSet = llvm::ImmutableSet<LoanID>;
63-
using OriginSet = llvm::ImmutableSet<OriginID>;
64-
65-
/// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
66-
/// `Fact`. identified by a lifetime-related event (`Fact`).
67-
///
68-
/// A `ProgramPoint` has "after" semantics: it represents the location
69-
/// immediately after its corresponding `Fact`.
70-
using ProgramPoint = const Fact *;
71-
72-
/// Running the lifetime safety analysis and querying its results. It
73-
/// encapsulates the various dataflow analyses.
74-
class LifetimeSafetyAnalysis {
75-
public:
76-
LifetimeSafetyAnalysis(AnalysisDeclContext &AC);
77-
~LifetimeSafetyAnalysis();
78-
79-
void run();
80-
81-
/// Returns the set of loans an origin holds at a specific program point.
82-
LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const;
83-
84-
/// Finds the OriginID for a given declaration.
85-
/// Returns a null optional if not found.
86-
std::optional<OriginID> getOriginIDForDecl(const ValueDecl *D) const;
87-
88-
/// Finds the LoanID's for the loan created with the specific variable as
89-
/// their Path.
90-
std::vector<LoanID> getLoanIDForVar(const VarDecl *VD) const;
91-
92-
/// Retrieves program points that were specially marked in the source code
93-
/// for testing.
94-
///
95-
/// The analysis recognizes special function calls of the form
96-
/// `void("__lifetime_test_point_<name>")` as test points. This method returns
97-
/// a map from the annotation string (<name>) to the corresponding
98-
/// `ProgramPoint`. This allows test harnesses to query the analysis state at
99-
/// user-defined locations in the code.
100-
/// \note This is intended for testing only.
101-
llvm::StringMap<ProgramPoint> getTestPoints() const;
102-
103-
private:
104-
AnalysisDeclContext &AC;
105-
std::unique_ptr<LifetimeFactory> Factory;
106-
std::unique_ptr<FactManager> FactMgr;
107-
std::unique_ptr<LoanPropagationAnalysis> LoanPropagation;
108-
};
109-
} // namespace internal
110-
} // namespace clang::lifetimes
28+
} // namespace clang
11129

11230
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H

clang/lib/Analysis/LifetimeSafety.cpp

Lines changed: 46 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,8 @@
2424
#include "llvm/Support/TimeProfiler.h"
2525
#include <cstdint>
2626

27-
namespace clang::lifetimes {
28-
namespace internal {
27+
namespace clang {
2928
namespace {
30-
template <typename Tag>
31-
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID<Tag> ID) {
32-
return OS << ID.Value;
33-
}
34-
} // namespace
3529

3630
/// Represents the storage location being borrowed, e.g., a specific stack
3731
/// variable.
@@ -42,6 +36,32 @@ struct AccessPath {
4236
AccessPath(const clang::ValueDecl *D) : D(D) {}
4337
};
4438

39+
/// A generic, type-safe wrapper for an ID, distinguished by its `Tag` type.
40+
/// Used for giving ID to loans and origins.
41+
template <typename Tag> struct ID {
42+
uint32_t Value = 0;
43+
44+
bool operator==(const ID<Tag> &Other) const { return Value == Other.Value; }
45+
bool operator!=(const ID<Tag> &Other) const { return !(*this == Other); }
46+
bool operator<(const ID<Tag> &Other) const { return Value < Other.Value; }
47+
ID<Tag> operator++(int) {
48+
ID<Tag> Tmp = *this;
49+
++Value;
50+
return Tmp;
51+
}
52+
void Profile(llvm::FoldingSetNodeID &IDBuilder) const {
53+
IDBuilder.AddInteger(Value);
54+
}
55+
};
56+
57+
template <typename Tag>
58+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID<Tag> ID) {
59+
return OS << ID.Value;
60+
}
61+
62+
using LoanID = ID<struct LoanTag>;
63+
using OriginID = ID<struct OriginTag>;
64+
4565
/// Information about a single borrow, or "Loan". A loan is created when a
4666
/// reference or pointer is created.
4767
struct Loan {
@@ -203,9 +223,7 @@ class Fact {
203223
/// An origin is propagated from a source to a destination (e.g., p = q).
204224
AssignOrigin,
205225
/// An origin escapes the function by flowing into the return value.
206-
ReturnOfOrigin,
207-
/// A marker for a specific point in the code, for testing.
208-
TestPoint,
226+
ReturnOfOrigin
209227
};
210228

211229
private:
@@ -292,24 +310,6 @@ class ReturnOfOriginFact : public Fact {
292310
}
293311
};
294312

295-
/// A dummy-fact used to mark a specific point in the code for testing.
296-
/// It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
297-
class TestPointFact : public Fact {
298-
StringRef Annotation;
299-
300-
public:
301-
static bool classof(const Fact *F) { return F->getKind() == Kind::TestPoint; }
302-
303-
explicit TestPointFact(StringRef Annotation)
304-
: Fact(Kind::TestPoint), Annotation(Annotation) {}
305-
306-
StringRef getAnnotation() const { return Annotation; }
307-
308-
void dump(llvm::raw_ostream &OS) const override {
309-
OS << "TestPoint (Annotation: \"" << getAnnotation() << "\")\n";
310-
}
311-
};
312-
313313
class FactManager {
314314
public:
315315
llvm::ArrayRef<const Fact *> getFacts(const CFGBlock *B) const {
@@ -363,7 +363,6 @@ class FactManager {
363363
};
364364

365365
class FactGenerator : public ConstStmtVisitor<FactGenerator> {
366-
using Base = ConstStmtVisitor<FactGenerator>;
367366

368367
public:
369368
FactGenerator(FactManager &FactMgr, AnalysisDeclContext &AC)
@@ -459,15 +458,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
459458
}
460459
}
461460

462-
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *FCE) {
463-
// Check if this is a test point marker. If so, we are done with this
464-
// expression.
465-
if (VisitTestPoint(FCE))
466-
return;
467-
// Visit as normal otherwise.
468-
Base::VisitCXXFunctionalCastExpr(FCE);
469-
}
470-
471461
private:
472462
// Check if a type has an origin.
473463
bool hasOrigin(QualType QT) { return QT->isPointerOrReferenceType(); }
@@ -501,27 +491,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
501491
}
502492
}
503493

504-
/// Checks if the expression is a `void("__lifetime_test_point_...")` cast.
505-
/// If so, creates a `TestPointFact` and returns true.
506-
bool VisitTestPoint(const CXXFunctionalCastExpr *FCE) {
507-
if (!FCE->getType()->isVoidType())
508-
return false;
509-
510-
const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
511-
if (const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
512-
llvm::StringRef LiteralValue = SL->getString();
513-
const std::string Prefix = "__lifetime_test_point_";
514-
515-
if (LiteralValue.starts_with(Prefix)) {
516-
StringRef Annotation = LiteralValue.drop_front(Prefix.length());
517-
CurrentBlockFacts.push_back(
518-
FactMgr.createFact<TestPointFact>(Annotation));
519-
return true;
520-
}
521-
}
522-
return false;
523-
}
524-
525494
FactManager &FactMgr;
526495
AnalysisDeclContext &AC;
527496
llvm::SmallVector<Fact *> CurrentBlockFacts;
@@ -668,8 +637,6 @@ class DataflowAnalysis {
668637
return D->transfer(In, *F->getAs<AssignOriginFact>());
669638
case Fact::Kind::ReturnOfOrigin:
670639
return D->transfer(In, *F->getAs<ReturnOfOriginFact>());
671-
case Fact::Kind::TestPoint:
672-
return D->transfer(In, *F->getAs<TestPointFact>());
673640
}
674641
llvm_unreachable("Unknown fact kind");
675642
}
@@ -679,16 +646,14 @@ class DataflowAnalysis {
679646
Lattice transfer(Lattice In, const ExpireFact &) { return In; }
680647
Lattice transfer(Lattice In, const AssignOriginFact &) { return In; }
681648
Lattice transfer(Lattice In, const ReturnOfOriginFact &) { return In; }
682-
Lattice transfer(Lattice In, const TestPointFact &) { return In; }
683649
};
684650

685651
namespace utils {
686652

687653
/// Computes the union of two ImmutableSets.
688654
template <typename T>
689-
static llvm::ImmutableSet<T> join(llvm::ImmutableSet<T> A,
690-
llvm::ImmutableSet<T> B,
691-
typename llvm::ImmutableSet<T>::Factory &F) {
655+
llvm::ImmutableSet<T> join(llvm::ImmutableSet<T> A, llvm::ImmutableSet<T> B,
656+
typename llvm::ImmutableSet<T>::Factory &F) {
692657
if (A.getHeight() < B.getHeight())
693658
std::swap(A, B);
694659
for (const T &E : B)
@@ -701,7 +666,7 @@ static llvm::ImmutableSet<T> join(llvm::ImmutableSet<T> A,
701666
// efficient merge could be implemented using a Patricia Trie or HAMT
702667
// instead of the current AVL-tree-based ImmutableMap.
703668
template <typename K, typename V, typename Joiner>
704-
static llvm::ImmutableMap<K, V>
669+
llvm::ImmutableMap<K, V>
705670
join(llvm::ImmutableMap<K, V> A, llvm::ImmutableMap<K, V> B,
706671
typename llvm::ImmutableMap<K, V>::Factory &F, Joiner joinValues) {
707672
if (A.getHeight() < B.getHeight())
@@ -725,6 +690,10 @@ join(llvm::ImmutableMap<K, V> A, llvm::ImmutableMap<K, V> B,
725690
// Loan Propagation Analysis
726691
// ========================================================================= //
727692

693+
// Using LLVM's immutable collections is efficient for dataflow analysis
694+
// as it avoids deep copies during state transitions.
695+
// TODO(opt): Consider using a bitset to represent the set of loans.
696+
using LoanSet = llvm::ImmutableSet<LoanID>;
728697
using OriginLoanMap = llvm::ImmutableMap<OriginID, LoanSet>;
729698

730699
/// An object to hold the factories for immutable collections, ensuring
@@ -838,28 +807,17 @@ class LoanPropagationAnalysis
838807
// - Modify origin liveness analysis to answer `bool isLive(Origin O, Point P)`
839808
// - Using the above three to perform the final error reporting.
840809
// ========================================================================= //
810+
} // anonymous namespace
841811

842-
// ========================================================================= //
843-
// LifetimeSafetyAnalysis Class Implementation
844-
// ========================================================================= //
845-
846-
// We need this here for unique_ptr with forward declared class.
847-
LifetimeSafetyAnalysis::~LifetimeSafetyAnalysis() = default;
848-
849-
LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC)
850-
: AC(AC), Factory(std::make_unique<LifetimeFactory>()),
851-
FactMgr(std::make_unique<FactManager>()) {}
852-
853-
void LifetimeSafetyAnalysis::run() {
812+
void runLifetimeSafetyAnalysis(const DeclContext &DC, const CFG &Cfg,
813+
AnalysisDeclContext &AC) {
854814
llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis");
855-
856-
const CFG &Cfg = *AC.getCFG();
857815
DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(),
858816
/*ShowColors=*/true));
859-
860-
FactGenerator FactGen(*FactMgr, AC);
817+
FactManager FactMgr;
818+
FactGenerator FactGen(FactMgr, AC);
861819
FactGen.run();
862-
DEBUG_WITH_TYPE("LifetimeFacts", FactMgr->dump(Cfg, AC));
820+
DEBUG_WITH_TYPE("LifetimeFacts", FactMgr.dump(Cfg, AC));
863821

864822
/// TODO(opt): Consider optimizing individual blocks before running the
865823
/// dataflow analysis.
@@ -870,56 +828,9 @@ void LifetimeSafetyAnalysis::run() {
870828
/// blocks; only Decls are visible. Therefore, loans in a block that
871829
/// never reach an Origin associated with a Decl can be safely dropped by
872830
/// the analysis.
873-
LoanPropagation =
874-
std::make_unique<LoanPropagationAnalysis>(Cfg, AC, *FactMgr, *Factory);
875-
LoanPropagation->run();
876-
}
877-
878-
LoanSet LifetimeSafetyAnalysis::getLoansAtPoint(OriginID OID,
879-
ProgramPoint PP) const {
880-
assert(LoanPropagation && "Analysis has not been run.");
881-
return LoanPropagation->getLoans(OID, PP);
882-
}
883-
884-
std::optional<OriginID>
885-
LifetimeSafetyAnalysis::getOriginIDForDecl(const ValueDecl *D) const {
886-
assert(FactMgr && "FactManager not initialized");
887-
// This assumes the OriginManager's `get` can find an existing origin.
888-
// We might need a `find` method on OriginManager to avoid `getOrCreate` logic
889-
// in a const-query context if that becomes an issue.
890-
return FactMgr->getOriginMgr().get(*D);
891-
}
892-
893-
std::vector<LoanID>
894-
LifetimeSafetyAnalysis::getLoanIDForVar(const VarDecl *VD) const {
895-
assert(FactMgr && "FactManager not initialized");
896-
std::vector<LoanID> Result;
897-
for (const Loan &L : FactMgr->getLoanMgr().getLoans())
898-
if (L.Path.D == VD)
899-
Result.push_back(L.ID);
900-
return Result;
901-
}
902-
903-
llvm::StringMap<ProgramPoint> LifetimeSafetyAnalysis::getTestPoints() const {
904-
assert(FactMgr && "FactManager not initialized");
905-
llvm::StringMap<ProgramPoint> AnnotationToPointMap;
906-
for (const CFGBlock *Block : *AC.getCFG()) {
907-
for (const Fact *F : FactMgr->getFacts(Block)) {
908-
if (const auto *TPF = F->getAs<TestPointFact>()) {
909-
StringRef PointName = TPF->getAnnotation();
910-
assert(AnnotationToPointMap.find(PointName) ==
911-
AnnotationToPointMap.end() &&
912-
"more than one test points with the same name");
913-
AnnotationToPointMap[PointName] = F;
914-
}
915-
}
916-
}
917-
return AnnotationToPointMap;
918-
}
919-
} // namespace internal
920-
921-
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC) {
922-
internal::LifetimeSafetyAnalysis Analysis(AC);
923-
Analysis.run();
831+
LifetimeFactory Factory;
832+
LoanPropagationAnalysis LoanPropagation(Cfg, AC, FactMgr, Factory);
833+
LoanPropagation.run();
834+
DEBUG_WITH_TYPE("LifetimeLoanPropagation", LoanPropagation.dump());
924835
}
925-
} // namespace clang::lifetimes
836+
} // namespace clang

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3029,8 +3029,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
30293029
// TODO: Enable lifetime safety analysis for other languages once it is
30303030
// stable.
30313031
if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
3032-
if (AC.getCFG())
3033-
lifetimes::runLifetimeSafetyAnalysis(AC);
3032+
if (CFG *cfg = AC.getCFG())
3033+
runLifetimeSafetyAnalysis(*cast<DeclContext>(D), *cfg, AC);
30343034
}
30353035
// Check for violations of "called once" parameter properties.
30363036
if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus &&

0 commit comments

Comments
 (0)