Skip to content

Commit cdc9849

Browse files
committed
[LifetimeSafety] Track view types/gsl::Pointer.
1 parent 894fa21 commit cdc9849

File tree

2 files changed

+39
-21
lines changed

2 files changed

+39
-21
lines changed

clang/lib/Analysis/LifetimeSafety.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
396396
// initializations and destructions are processed in the correct sequence.
397397
for (const CFGBlock *Block : *AC.getAnalysis<PostOrderCFGView>()) {
398398
CurrentBlockFacts.clear();
399+
VisitedStmts.clear();
399400
for (unsigned I = 0; I < Block->size(); ++I) {
400401
const CFGElement &Element = Block->Elements[I];
401402
if (std::optional<CFGStmt> CS = Element.getAs<CFGStmt>())
@@ -408,6 +409,12 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
408409
}
409410
}
410411

412+
void Visit(const Stmt *S) {
413+
if (!S || !VisitedStmts.insert(S).second)
414+
return;
415+
Base::Visit(S);
416+
}
417+
411418
void VisitDeclStmt(const DeclStmt *DS) {
412419
for (const Decl *D : DS->decls())
413420
if (const auto *VD = dyn_cast<VarDecl>(D))
@@ -551,6 +558,7 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
551558
FactManager &FactMgr;
552559
AnalysisDeclContext &AC;
553560
llvm::SmallVector<Fact *> CurrentBlockFacts;
561+
llvm::DenseSet<const Stmt *> VisitedStmts;
554562
};
555563

556564
// ========================================================================= //

clang/unittests/Analysis/LifetimeSafetyTest.cpp

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "clang/ASTMatchers/ASTMatchers.h"
1212
#include "clang/Testing/TestAST.h"
1313
#include "llvm/ADT/StringMap.h"
14+
#include "llvm/Testing/Support/Error.h"
1415
#include "gmock/gmock.h"
1516
#include "gtest/gtest.h"
1617
#include <optional>
@@ -96,21 +97,18 @@ class LifetimeTestHelper {
9697
return OID;
9798
}
9899

99-
std::optional<LoanID> getLoanForVar(llvm::StringRef VarName) {
100+
std::vector<LoanID> getLoansForVar(llvm::StringRef VarName) {
100101
auto *VD = findDecl<VarDecl>(VarName);
101-
if (!VD)
102-
return std::nullopt;
102+
if (!VD) {
103+
ADD_FAILURE() << "No VarDecl found for '" << VarName << "'";
104+
return {};
105+
}
103106
std::vector<LoanID> LID = Analysis.getLoanIDForVar(VD);
104107
if (LID.empty()) {
105108
ADD_FAILURE() << "Loan for '" << VarName << "' not found.";
106-
return std::nullopt;
107-
}
108-
// TODO: Support retrieving more than one loans to a var.
109-
if (LID.size() > 1) {
110-
ADD_FAILURE() << "More than 1 loans found for '" << VarName;
111-
return std::nullopt;
109+
return {};
112110
}
113-
return LID[0];
111+
return LID;
114112
}
115113

116114
std::optional<LoanSet> getLoansAtPoint(OriginID OID,
@@ -121,13 +119,12 @@ class LifetimeTestHelper {
121119
return Analysis.getLoansAtPoint(OID, PP);
122120
}
123121

124-
std::optional<llvm::DenseSet<LoanID>>
122+
std::optional<std::vector<LoanID>>
125123
getExpiredLoansAtPoint(llvm::StringRef Annotation) {
126124
ProgramPoint PP = Runner.getProgramPoint(Annotation);
127125
if (!PP)
128126
return std::nullopt;
129-
auto Expired = Analysis.getExpiredLoansAtPoint(PP);
130-
return llvm::DenseSet<LoanID>{Expired.begin(), Expired.end()};
127+
return Analysis.getExpiredLoansAtPoint(PP);
131128
}
132129

133130
private:
@@ -197,12 +194,13 @@ MATCHER_P2(HasLoansToImpl, LoanVars, Annotation, "") {
197194

198195
std::vector<LoanID> ExpectedLoans;
199196
for (const auto &LoanVar : LoanVars) {
200-
std::optional<LoanID> ExpectedLIDOpt = Info.Helper.getLoanForVar(LoanVar);
201-
if (!ExpectedLIDOpt) {
197+
std::vector<LoanID> ExpectedLIDs = Info.Helper.getLoansForVar(LoanVar);
198+
if (ExpectedLIDs.empty()) {
202199
*result_listener << "could not find loan for var '" << LoanVar << "'";
203200
return false;
204201
}
205-
ExpectedLoans.push_back(*ExpectedLIDOpt);
202+
ExpectedLoans.insert(ExpectedLoans.end(), ExpectedLIDs.begin(),
203+
ExpectedLIDs.end());
206204
}
207205

208206
return ExplainMatchResult(UnorderedElementsAreArray(ExpectedLoans),
@@ -221,17 +219,17 @@ MATCHER_P(AreExpiredAt, Annotation, "") {
221219
<< Annotation << "'";
222220
return false;
223221
}
224-
std::vector<LoanID> ActualExpiredLoans(ActualExpiredSetOpt->begin(),
225-
ActualExpiredSetOpt->end());
222+
std::vector<LoanID> ActualExpiredLoans = *ActualExpiredSetOpt;
226223
std::vector<LoanID> ExpectedExpiredLoans;
227224
for (const auto &VarName : Info.LoanVars) {
228-
auto LoanIDOpt = Helper.getLoanForVar(VarName);
229-
if (!LoanIDOpt) {
225+
auto LoanIDs = Helper.getLoansForVar(VarName);
226+
if (LoanIDs.empty()) {
230227
*result_listener << "could not find a loan for variable '" << VarName
231228
<< "'";
232229
return false;
233230
}
234-
ExpectedExpiredLoans.push_back(*LoanIDOpt);
231+
ExpectedExpiredLoans.insert(ExpectedExpiredLoans.end(), LoanIDs.begin(),
232+
LoanIDs.end());
235233
}
236234
return ExplainMatchResult(UnorderedElementsAreArray(ExpectedExpiredLoans),
237235
ActualExpiredLoans, result_listener);
@@ -730,5 +728,17 @@ TEST_F(LifetimeAnalysisTest, ReassignedPointerThenOriginalExpires) {
730728
EXPECT_THAT(LoansTo({"s1", "s2"}), AreExpiredAt("p_after_s1_expires"));
731729
}
732730

731+
TEST_F(LifetimeAnalysisTest, NoDuplicateLoansForImplicitCastToConst) {
732+
SetupTest(R"(
733+
void target() {
734+
MyObj a;
735+
const MyObj* p = &a;
736+
const MyObj* q = p;
737+
POINT(at_end);
738+
}
739+
)");
740+
EXPECT_THAT(Helper->getLoansForVar("a"), testing::SizeIs(1));
741+
}
742+
733743
} // anonymous namespace
734744
} // namespace clang::lifetimes::internal

0 commit comments

Comments
 (0)