/// \brief Set the bit associated with a particular CFGBlock.
/// This is the important method for the SetType template parameter.
bool insert(const CFGBlock *Block) {
+ // Note that insert() is called by po_iterator, which doesn't check to make
+ // sure that Block is non-null. Moreover, the CFGBlock iterator will
+ // occasionally hand out null pointers for pruned edges, so we catch those
+ // here.
+ if (Block == 0)
+ return false; // if an edge is trivially false.
if (VisitedBlockIDs.test(Block->getBlockID()))
return false;
VisitedBlockIDs.set(Block->getBlockID());
}
/// \brief Check if the bit for a CFGBlock has been already set.
- /// This mehtod is for tracking visited blocks in the main threadsafety loop.
+ /// This method is for tracking visited blocks in the main threadsafety loop.
+ /// Block must not be null.
bool alreadySet(const CFGBlock *Block) {
return VisitedBlockIDs.test(Block->getBlockID());
}
/// the method that is being called and add, remove or check locks in the
/// lockset accordingly.
void BuildLockset::VisitCXXMemberCallExpr(CXXMemberCallExpr *Exp) {
- NamedDecl *D = dyn_cast<NamedDecl>(Exp->getCalleeDecl());
+ NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
+
SourceLocation ExpLocation = Exp->getExprLoc();
Expr *Parent = Exp->getImplicitObjectArgument();
/// \brief Returns the location of the first Stmt in a Block.
static SourceLocation getFirstStmtLocation(CFGBlock *Block) {
+ SourceLocation Loc;
for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
BI != BE; ++BI) {
- if (const CFGStmt *CfgStmt = dyn_cast<CFGStmt>(&(*BI)))
- return CfgStmt->getStmt()->getLocStart();
+ if (const CFGStmt *CfgStmt = dyn_cast<CFGStmt>(&(*BI))) {
+ Loc = CfgStmt->getStmt()->getLocStart();
+ if (Loc.isValid()) return Loc;
+ }
+ }
+ if (Stmt *S = Block->getTerminator().getStmt()) {
+ Loc = S->getLocStart();
+ if (Loc.isValid()) return Loc;
}
- return SourceLocation();
+ return Loc;
}
/// \brief Warn about different locksets along backedges of loops.
CFG *CFGraph = AC.getCFG();
if (!CFGraph) return;
- StringRef FunName;
- if (const NamedDecl *ContextDecl = dyn_cast<NamedDecl>(AC.getDecl()))
- FunName = ContextDecl->getName();
-
Lockset::Factory LocksetFactory;
// FIXME: Swith to SmallVector? Otherwise improve performance impact?
PE = CurrBlock->pred_end(); PI != PE; ++PI) {
// if *PI -> CurrBlock is a back edge
- if (!VisitedBlocks.alreadySet(*PI))
+ if (*PI == 0 || !VisitedBlocks.alreadySet(*PI))
continue;
int PrevBlockID = (*PI)->getBlockID();
BuildLockset LocksetBuilder(S, Entryset, LocksetFactory);
for (CFGBlock::const_iterator BI = CurrBlock->begin(),
BE = CurrBlock->end(); BI != BE; ++BI) {
- if (const CFGStmt *CfgStmt = dyn_cast<CFGStmt>(&*BI)) {
+ if (const CFGStmt *CfgStmt = dyn_cast<CFGStmt>(&*BI))
LocksetBuilder.Visit(const_cast<Stmt*>(CfgStmt->getStmt()));
- }
}
Exitset = LocksetBuilder.getLockset();
SE = CurrBlock->succ_end(); SI != SE; ++SI) {
// if CurrBlock -> *SI is *not* a back edge
- if (!VisitedBlocks.alreadySet(*SI))
+ if (*SI == 0 || !VisitedBlocks.alreadySet(*SI))
continue;
CFGBlock *FirstLoopBlock = *SI;
SourceLocation FirstLoopLocation = getFirstStmtLocation(FirstLoopBlock);
+ assert(FirstLoopLocation.isValid());
+ // Fail gracefully in release code.
+ if (!FirstLoopLocation.isValid())
+ continue;
+
Lockset PreLoop = EntryLocksets[FirstLoopBlock->getBlockID()];
Lockset LoopEnd = ExitLocksets[CurrBlockID];
warnBackEdgeUnequalLocksets(S, LoopEnd, PreLoop, FirstLoopLocation);
I != E; ++I) {
const LockID &MissingLock = I.getKey();
const LockData &MissingLockData = I.getData();
+
+ std::string FunName = "<unknown>";
+ if (const NamedDecl *ContextDecl = dyn_cast<NamedDecl>(AC.getDecl())) {
+ FunName = ContextDecl->getDeclName().getAsString();
+ }
+
PartialDiagnostic Warning =
S.PDiag(diag::warn_locks_not_released)
<< MissingLock.getName() << FunName;
int slr_function_bad_4() __attribute__((shared_locks_required(umu))); // \
expected-error {{'shared_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+//-----------------------------------------//
+// Regression tests for unusual cases.
+//-----------------------------------------//
+
+int trivially_false_edges(bool b) {
+ // Create NULL (never taken) edges in CFG
+ if (false) return 1;
+ else return 2;
+}
+
+// Possible Clang bug -- method pointer in template parameter
+class UnFoo {
+public:
+ void foo();
+};
+
+template<void (UnFoo::*methptr)()>
+class MCaller {
+public:
+ static void call_method_ptr(UnFoo *f) {
+ // FIXME: Possible Clang bug:
+ // getCalleeDecl() returns NULL in the following case:
+ (f->*methptr)();
+ }
+};
+
+void call_method_ptr_inst(UnFoo* f) {
+ MCaller<&UnFoo::foo>::call_method_ptr(f);
+}
+
+int temp;
+void empty_back_edge() {
+ // Create a back edge to a block with with no statements
+ for (;;) {
+ ++temp;
+ if (temp > 10) break;
+ }
+}
+
+struct Foomger {
+ void operator++();
+};
+
+struct Foomgoper {
+ Foomger f;
+
+ bool done();
+ void invalid_back_edge() {
+ do {
+ // FIXME: Possible Clang bug:
+ // The first statement in this basic block has no source location
+ ++f;
+ } while (!done());
+ }
+};
+
+