@@ -1008,7 +1008,7 @@ class ThreadSafetyAnalyzer {
1008
1008
threadSafety::SExprBuilder SxBuilder;
1009
1009
1010
1010
ThreadSafetyHandler &Handler;
1011
- const FunctionDecl *CurrentFunction ;
1011
+ const CXXMethodDecl *CurrentMethod = nullptr ;
1012
1012
LocalVariableMap LocalVarMap;
1013
1013
FactManager FactMan;
1014
1014
std::vector<CFGBlockInfo> BlockInfo;
@@ -1243,10 +1243,10 @@ bool ThreadSafetyAnalyzer::inCurrentScope(const CapabilityExpr &CapE) {
1243
1243
1244
1244
// Members are in scope from methods of the same class.
1245
1245
if (const auto *P = dyn_cast<til::Project>(SExp)) {
1246
- if (!isa_and_nonnull<CXXMethodDecl>(CurrentFunction) )
1246
+ if (!CurrentMethod )
1247
1247
return false ;
1248
1248
const ValueDecl *VD = P->clangDecl ();
1249
- return VD->getDeclContext () == CurrentFunction ->getDeclContext ();
1249
+ return VD->getDeclContext () == CurrentMethod ->getDeclContext ();
1250
1250
}
1251
1251
1252
1252
return false ;
@@ -1541,8 +1541,6 @@ class BuildLockset : public ConstStmtVisitor<BuildLockset> {
1541
1541
1542
1542
ThreadSafetyAnalyzer *Analyzer;
1543
1543
FactSet FSet;
1544
- // The fact set for the function on exit.
1545
- const FactSet &FunctionExitFSet;
1546
1544
// / Maps constructed objects to `this` placeholder prior to initialization.
1547
1545
llvm::SmallDenseMap<const Expr *, til::LiteralPtr *> ConstructedObjects;
1548
1546
LocalVariableMap::Context LVarCtx;
@@ -1568,11 +1566,9 @@ class BuildLockset : public ConstStmtVisitor<BuildLockset> {
1568
1566
bool SkipFirstParam = false );
1569
1567
1570
1568
public:
1571
- BuildLockset (ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info,
1572
- const FactSet &FunctionExitFSet)
1569
+ BuildLockset (ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
1573
1570
: ConstStmtVisitor<BuildLockset>(), Analyzer(Anlzr), FSet(Info.EntrySet),
1574
- FunctionExitFSet (FunctionExitFSet), LVarCtx(Info.EntryContext),
1575
- CtxIndex (Info.EntryIndex) {}
1571
+ LVarCtx (Info.EntryContext), CtxIndex(Info.EntryIndex) {}
1576
1572
1577
1573
void VisitUnaryOperator (const UnaryOperator *UO);
1578
1574
void VisitBinaryOperator (const BinaryOperator *BO);
@@ -1581,7 +1577,6 @@ class BuildLockset : public ConstStmtVisitor<BuildLockset> {
1581
1577
void VisitCXXConstructExpr (const CXXConstructExpr *Exp);
1582
1578
void VisitDeclStmt (const DeclStmt *S);
1583
1579
void VisitMaterializeTemporaryExpr (const MaterializeTemporaryExpr *Exp);
1584
- void VisitReturnStmt (const ReturnStmt *S);
1585
1580
};
1586
1581
1587
1582
} // namespace
@@ -1763,8 +1758,6 @@ void ThreadSafetyAnalyzer::checkPtAccess(const FactSet &FSet, const Expr *Exp,
1763
1758
// Pass by reference warnings are under a different flag.
1764
1759
ProtectedOperationKind PtPOK = POK_VarDereference;
1765
1760
if (POK == POK_PassByRef) PtPOK = POK_PtPassByRef;
1766
- if (POK == POK_ReturnByRef)
1767
- PtPOK = POK_PtReturnByRef;
1768
1761
1769
1762
const ValueDecl *D = getValueDecl (Exp);
1770
1763
if (!D || !D->hasAttrs ())
@@ -2149,25 +2142,6 @@ void BuildLockset::VisitMaterializeTemporaryExpr(
2149
2142
}
2150
2143
}
2151
2144
2152
- void BuildLockset::VisitReturnStmt (const ReturnStmt *S) {
2153
- if (Analyzer->CurrentFunction == nullptr )
2154
- return ;
2155
- const Expr *RetVal = S->getRetValue ();
2156
- if (!RetVal)
2157
- return ;
2158
-
2159
- // If returning by reference, check that the function requires the appropriate
2160
- // capabilities.
2161
- const QualType ReturnType =
2162
- Analyzer->CurrentFunction ->getReturnType ().getCanonicalType ();
2163
- if (ReturnType->isLValueReferenceType ()) {
2164
- Analyzer->checkAccess (
2165
- FunctionExitFSet, RetVal,
2166
- ReturnType->getPointeeType ().isConstQualified () ? AK_Read : AK_Written,
2167
- POK_ReturnByRef);
2168
- }
2169
- }
2170
-
2171
2145
// / Given two facts merging on a join point, possibly warn and decide whether to
2172
2146
// / keep or replace.
2173
2147
// /
@@ -2277,7 +2251,8 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
2277
2251
2278
2252
CFG *CFGraph = walker.getGraph ();
2279
2253
const NamedDecl *D = walker.getDecl ();
2280
- CurrentFunction = dyn_cast<FunctionDecl>(D);
2254
+ const auto *CurrentFunction = dyn_cast<FunctionDecl>(D);
2255
+ CurrentMethod = dyn_cast<CXXMethodDecl>(D);
2281
2256
2282
2257
if (D->hasAttr <NoThreadSafetyAnalysisAttr>())
2283
2258
return ;
@@ -2303,7 +2278,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
2303
2278
PostOrderCFGView::CFGBlockSet VisitedBlocks (CFGraph);
2304
2279
2305
2280
CFGBlockInfo &Initial = BlockInfo[CFGraph->getEntry ().getBlockID ()];
2306
- CFGBlockInfo &Final = BlockInfo[CFGraph->getExit ().getBlockID ()];
2281
+ CFGBlockInfo &Final = BlockInfo[CFGraph->getExit ().getBlockID ()];
2307
2282
2308
2283
// Mark entry block as reachable
2309
2284
Initial.Reachable = true ;
@@ -2373,25 +2348,6 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
2373
2348
}
2374
2349
}
2375
2350
2376
- // Compute the expected exit set.
2377
- // By default, we expect all locks held on entry to be held on exit.
2378
- FactSet ExpectedFunctionExitSet = Initial.EntrySet ;
2379
-
2380
- // Adjust the expected exit set by adding or removing locks, as declared
2381
- // by *-LOCK_FUNCTION and UNLOCK_FUNCTION. The intersect below will then
2382
- // issue the appropriate warning.
2383
- // FIXME: the location here is not quite right.
2384
- for (const auto &Lock : ExclusiveLocksAcquired)
2385
- ExpectedFunctionExitSet.addLock (
2386
- FactMan, std::make_unique<LockableFactEntry>(Lock, LK_Exclusive,
2387
- D->getLocation ()));
2388
- for (const auto &Lock : SharedLocksAcquired)
2389
- ExpectedFunctionExitSet.addLock (
2390
- FactMan,
2391
- std::make_unique<LockableFactEntry>(Lock, LK_Shared, D->getLocation ()));
2392
- for (const auto &Lock : LocksReleased)
2393
- ExpectedFunctionExitSet.removeLock (FactMan, Lock);
2394
-
2395
2351
for (const auto *CurrBlock : *SortedGraph) {
2396
2352
unsigned CurrBlockID = CurrBlock->getBlockID ();
2397
2353
CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
@@ -2451,7 +2407,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
2451
2407
if (!CurrBlockInfo->Reachable )
2452
2408
continue ;
2453
2409
2454
- BuildLockset LocksetBuilder (this , *CurrBlockInfo, ExpectedFunctionExitSet );
2410
+ BuildLockset LocksetBuilder (this , *CurrBlockInfo);
2455
2411
2456
2412
// Visit all the statements in the basic block.
2457
2413
for (const auto &BI : *CurrBlock) {
@@ -2527,8 +2483,24 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
2527
2483
if (!Final.Reachable )
2528
2484
return ;
2529
2485
2486
+ // By default, we expect all locks held on entry to be held on exit.
2487
+ FactSet ExpectedExitSet = Initial.EntrySet ;
2488
+
2489
+ // Adjust the expected exit set by adding or removing locks, as declared
2490
+ // by *-LOCK_FUNCTION and UNLOCK_FUNCTION. The intersect below will then
2491
+ // issue the appropriate warning.
2492
+ // FIXME: the location here is not quite right.
2493
+ for (const auto &Lock : ExclusiveLocksAcquired)
2494
+ ExpectedExitSet.addLock (FactMan, std::make_unique<LockableFactEntry>(
2495
+ Lock, LK_Exclusive, D->getLocation ()));
2496
+ for (const auto &Lock : SharedLocksAcquired)
2497
+ ExpectedExitSet.addLock (FactMan, std::make_unique<LockableFactEntry>(
2498
+ Lock, LK_Shared, D->getLocation ()));
2499
+ for (const auto &Lock : LocksReleased)
2500
+ ExpectedExitSet.removeLock (FactMan, Lock);
2501
+
2530
2502
// FIXME: Should we call this function for all blocks which exit the function?
2531
- intersectAndWarn (ExpectedFunctionExitSet , Final.ExitSet , Final.ExitLoc ,
2503
+ intersectAndWarn (ExpectedExitSet , Final.ExitSet , Final.ExitLoc ,
2532
2504
LEK_LockedAtEndOfFunction, LEK_NotLockedAtEndOfFunction);
2533
2505
2534
2506
Handler.leaveFunction (CurrentFunction);
0 commit comments