Thread Safety Analysis: some minor cleanups to the latest thread safety changes. No functional changes intended.

* Adds an iterator_range interface to CallExpr to get the arguments
* Modifies SExpr such that it must be allocated in the Arena, and cannot be deleted
* Minor const-correctness and nullptr updates
* Adds some operator!= implementations to complement operator==
* Removes unused functionality

llvm-svn: 205915
This commit is contained in:
Aaron Ballman 2014-04-09 17:45:44 +00:00
parent 97d8ee3824
commit 3f993c1320
4 changed files with 99 additions and 101 deletions

View File

@ -2227,6 +2227,13 @@ public:
typedef ExprIterator arg_iterator; typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator; typedef ConstExprIterator const_arg_iterator;
typedef llvm::iterator_range<arg_iterator> arg_range;
typedef llvm::iterator_range<const_arg_iterator> arg_const_range;
arg_range arguments() { return arg_range(arg_begin(), arg_end()); }
arg_const_range arguments() const {
return arg_const_range(arg_begin(), arg_end());
}
arg_iterator arg_begin() { return SubExprs+PREARGS_START+getNumPreArgs(); } arg_iterator arg_begin() { return SubExprs+PREARGS_START+getNumPreArgs(); }
arg_iterator arg_end() { arg_iterator arg_end() {

View File

@ -42,35 +42,32 @@
namespace clang { namespace clang {
namespace threadSafety { namespace threadSafety {
// CFG traversal uses templates instead of virtual function dispatch. Visitors
// Simple Visitor class for traversing a clang CFG. // must implement the following functions:
class CFGVisitor { //
public: // Enter the CFG for Decl D, and perform any initial setup operations.
// Enter the CFG for Decl D, and perform any initial setup operations. // void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {}
void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {} //
// Enter a CFGBlock.
// Enter a CFGBlock. // void enterCFGBlock(const CFGBlock *B) {}
void enterCFGBlock(const CFGBlock *B) {} //
// Process an ordinary statement.
// Process an ordinary statement. // void handleStatement(const Stmt *S) {}
void handleStatement(const Stmt *S) {} //
// Process a destructor call
// Process a destructor call // void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {} //
// Process a successor edge.
// Process a successor edge. // void handleSuccessor(const CFGBlock *Succ) {}
void handleSuccessor(const CFGBlock *Succ) {} //
// Process a successor back edge to a previously visited block.
// Process a successor back edge to a previously visited block. // void handleSuccessorBackEdge(const CFGBlock *Succ) {}
void handleSuccessorBackEdge(const CFGBlock *Succ) {} //
// Leave a CFGBlock.
// Leave a CFGBlock. // void exitCFGBlock(const CFGBlock *B) {}
void exitCFGBlock(const CFGBlock *B) {} //
// Leave the CFG, and perform any final cleanup operations.
// Leave the CFG, and perform any final cleanup operations. // void exitCFG(const CFGBlock *Last) {}
void exitCFG(const CFGBlock *Last) {}
};
// Walks the clang CFG, and invokes methods on a given CFGVisitor. // Walks the clang CFG, and invokes methods on a given CFGVisitor.
class CFGWalker { class CFGWalker {
@ -104,13 +101,13 @@ public:
V.enterCFG(CFGraph, FDecl, &CFGraph->getEntry()); V.enterCFG(CFGraph, FDecl, &CFGraph->getEntry());
for (const CFGBlock* CurrBlock : *SortedGraph) { for (const auto *CurrBlock : *SortedGraph) {
VisitedBlocks.insert(CurrBlock); VisitedBlocks.insert(CurrBlock);
V.enterCFGBlock(CurrBlock); V.enterCFGBlock(CurrBlock);
// Process statements // Process statements
for (auto BI : *CurrBlock) { for (const auto &BI : *CurrBlock) {
switch (BI.getKind()) { switch (BI.getKind()) {
case CFGElement::Statement: { case CFGElement::Statement: {
V.handleStatement(BI.castAs<CFGStmt>().getStmt()); V.handleStatement(BI.castAs<CFGStmt>().getStmt());

View File

@ -207,6 +207,10 @@ public:
// compare all subexpressions, following the comparator interface // compare all subexpressions, following the comparator interface
// } // }
void *operator new(size_t S, clang::threadSafety::til::MemRegionRef &R) {
return ::operator new(S, R);
}
protected: protected:
SExpr(TIL_Opcode Op) : Opcode(Op), Reserved(0), Flags(0) {} SExpr(TIL_Opcode Op) : Opcode(Op), Reserved(0), Flags(0) {}
SExpr(const SExpr &E) : Opcode(E.Opcode), Reserved(0), Flags(E.Flags) {} SExpr(const SExpr &E) : Opcode(E.Opcode), Reserved(0), Flags(E.Flags) {}
@ -216,7 +220,15 @@ protected:
unsigned short Flags; unsigned short Flags;
private: private:
SExpr(); // Note, this cannot be explicitly deleted due to initializers automatically
// referencing destructor declarations. However, it does not need to be
// defined because that reference does not require an definition.
~SExpr();
SExpr() = delete;
// SExpr objects must be created in an arena and cannot be deleted.
void *operator new(size_t) = delete;
void operator delete(void *) = delete;
}; };
@ -227,7 +239,7 @@ class SExprRef {
public: public:
SExprRef() : Ptr(nullptr) { } SExprRef() : Ptr(nullptr) { }
SExprRef(std::nullptr_t P) : Ptr(nullptr) { } SExprRef(std::nullptr_t P) : Ptr(nullptr) { }
SExprRef(SExprRef &&R) : Ptr(R.Ptr) { } SExprRef(SExprRef &&R) : Ptr(R.Ptr) { R.Ptr = nullptr; }
// Defined after Variable and Future, below. // Defined after Variable and Future, below.
inline SExprRef(SExpr *P); inline SExprRef(SExpr *P);
@ -242,9 +254,12 @@ public:
SExpr &operator*() { return *Ptr; } SExpr &operator*() { return *Ptr; }
const SExpr &operator*() const { return *Ptr; } const SExpr &operator*() const { return *Ptr; }
bool operator==(const SExprRef& R) const { return Ptr == R.Ptr; } bool operator==(const SExprRef &R) const { return Ptr == R.Ptr; }
bool operator==(const SExpr* P) const { return Ptr == P; } bool operator!=(const SExprRef &R) const { return !operator==(R); }
bool operator==(std::nullptr_t P) const { return Ptr == nullptr; } bool operator==(const SExpr *P) const { return Ptr == P; }
bool operator!=(const SExpr *P) const { return !operator==(P); }
bool operator==(std::nullptr_t) const { return Ptr == nullptr; }
bool operator!=(std::nullptr_t) const { return Ptr != nullptr; }
inline void reset(SExpr *E); inline void reset(SExpr *E);
@ -252,28 +267,17 @@ private:
inline void attach(); inline void attach();
inline void detach(); inline void detach();
SExprRef(const SExprRef& R) : Ptr(R.Ptr) { }
SExpr *Ptr; SExpr *Ptr;
}; };
// Contains various helper functions for SExprs. // Contains various helper functions for SExprs.
class ThreadSafetyTIL { namespace ThreadSafetyTIL {
public: static bool isTrivial(SExpr *E) {
static const int MaxOpcode = COP_MAX; unsigned Op = E->opcode();
return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr;
static inline bool isTrivial(SExpr *E) { }
unsigned Op = E->opcode(); }
return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr;
}
static inline bool isLargeValue(SExpr *E) {
unsigned Op = E->opcode();
return (Op >= COP_Function && Op <= COP_Code);
}
};
class Function; class Function;
class SFunction; class SFunction;
@ -311,7 +315,7 @@ public:
VariableKind kind() const { return static_cast<VariableKind>(Flags); } VariableKind kind() const { return static_cast<VariableKind>(Flags); }
StringRef name() const { return Cvdecl ? Cvdecl->getName() : "_x"; } const StringRef name() const { return Cvdecl ? Cvdecl->getName() : "_x"; }
const clang::ValueDecl *clangDecl() const { return Cvdecl; } const clang::ValueDecl *clangDecl() const { return Cvdecl; }
// Returns the definition (for let vars) or type (for parameter & self vars) // Returns the definition (for let vars) or type (for parameter & self vars)
@ -320,8 +324,8 @@ public:
void attachVar() const { ++NumUses; } void attachVar() const { ++NumUses; }
void detachVar() const { assert(NumUses > 0); --NumUses; } void detachVar() const { assert(NumUses > 0); --NumUses; }
unsigned getID() { return Id; } unsigned getID() const { return Id; }
unsigned getBlockID() { return BlockID; } unsigned getBlockID() const { return BlockID; }
void setID(unsigned Bid, unsigned I) { void setID(unsigned Bid, unsigned I) {
BlockID = static_cast<unsigned short>(Bid); BlockID = static_cast<unsigned short>(Bid);
@ -369,7 +373,7 @@ public:
Future() : Future() :
SExpr(COP_Future), Status(FS_pending), Result(nullptr), Location(nullptr) SExpr(COP_Future), Status(FS_pending), Result(nullptr), Location(nullptr)
{} {}
virtual ~Future() {} virtual ~Future() = delete;
// Registers the location in the AST where this future is stored. // Registers the location in the AST where this future is stored.
// Forcing the future will automatically update the AST. // Forcing the future will automatically update the AST.

View File

@ -37,11 +37,11 @@ typedef SExprBuilder::CallingContext CallingContext;
til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) { til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
if (!SMap) if (!SMap)
return 0; return nullptr;
auto It = SMap->find(S); auto It = SMap->find(S);
if (It != SMap->end()) if (It != SMap->end())
return It->second; return It->second;
return 0; return nullptr;
} }
void SExprBuilder::insertStmt(const Stmt *S, til::Variable *V) { void SExprBuilder::insertStmt(const Stmt *S, til::Variable *V) {
@ -160,8 +160,8 @@ til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
CallingContext *Ctx) { CallingContext *Ctx) {
// TODO -- Lock returned // TODO -- Lock returned
til::SExpr *E = translate(CE->getCallee(), Ctx); til::SExpr *E = translate(CE->getCallee(), Ctx);
for (unsigned I = 0, N = CE->getNumArgs(); I < N; ++I) { for (const auto *Arg : CE->arguments()) {
til::SExpr *A = translate(CE->getArg(I), Ctx); til::SExpr *A = translate(Arg, Ctx);
E = new (Arena) til::Apply(E, A); E = new (Arena) til::Apply(E, A);
} }
return new (Arena) til::Call(E, CE); return new (Arena) til::Call(E, CE);
@ -200,10 +200,9 @@ til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
case UO_LNot: case UO_LNot:
case UO_Real: case UO_Real:
case UO_Imag: case UO_Imag:
case UO_Extension: { case UO_Extension:
til::SExpr *E0 = translate(UO->getSubExpr(), Ctx); return new (Arena)
return new (Arena) til::UnaryOp(UO->getOpcode(), E0); til::UnaryOp(UO->getOpcode(), translate(UO->getSubExpr(), Ctx));
}
} }
return new (Arena) til::Undefined(UO); return new (Arena) til::Undefined(UO);
} }
@ -232,16 +231,15 @@ til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
case BO_Xor: case BO_Xor:
case BO_Or: case BO_Or:
case BO_LAnd: case BO_LAnd:
case BO_LOr: { case BO_LOr:
til::SExpr *E0 = translate(BO->getLHS(), Ctx); return new (Arena)
til::SExpr *E1 = translate(BO->getRHS(), Ctx); til::BinaryOp(BO->getOpcode(), translate(BO->getLHS(), Ctx),
return new (Arena) til::BinaryOp(BO->getOpcode(), E0, E1); translate(BO->getRHS(), Ctx));
}
case BO_Assign: { case BO_Assign:
til::SExpr *E0 = translate(BO->getLHS(), Ctx); return new (Arena)
til::SExpr *E1 = translate(BO->getRHS(), Ctx); til::Store(translate(BO->getLHS(), Ctx), translate(BO->getRHS(), Ctx));
return new (Arena) til::Store(E0, E1);
}
case BO_MulAssign: case BO_MulAssign:
case BO_DivAssign: case BO_DivAssign:
case BO_RemAssign: case BO_RemAssign:
@ -284,42 +282,39 @@ til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
} }
} }
til::SExpr *
til::SExpr *SExprBuilder::translateArraySubscriptExpr( SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
const ArraySubscriptExpr *E, CallingContext *Ctx) { CallingContext *Ctx) {
return new (Arena) til::Undefined(E); return new (Arena) til::Undefined(E);
} }
til::SExpr *
til::SExpr *SExprBuilder::translateConditionalOperator( SExprBuilder::translateConditionalOperator(const ConditionalOperator *C,
const ConditionalOperator *C, CallingContext *Ctx) { CallingContext *Ctx) {
return new (Arena) til::Undefined(C); return new (Arena) til::Undefined(C);
} }
til::SExpr *SExprBuilder::translateBinaryConditionalOperator( til::SExpr *SExprBuilder::translateBinaryConditionalOperator(
const BinaryConditionalOperator *C, CallingContext *Ctx) { const BinaryConditionalOperator *C, CallingContext *Ctx) {
return new (Arena) til::Undefined(C); return new (Arena) til::Undefined(C);
} }
// Build a complete SCFG from a clang CFG. // Build a complete SCFG from a clang CFG.
class SCFGBuilder : public CFGVisitor { class SCFGBuilder {
public: void addStatement(til::SExpr* E, const Stmt *S) {
til::Variable *addStatement(til::SExpr* E, const Stmt *S) {
if (!E) if (!E)
return 0; return;
if (til::ThreadSafetyTIL::isTrivial(E)) if (til::ThreadSafetyTIL::isTrivial(E))
return 0; return;
til::Variable *V = new (Arena) til::Variable(til::Variable::VK_Let, E); til::Variable *V = new (Arena) til::Variable(til::Variable::VK_Let, E);
V->setID(CurrentBlockID, CurrentVarID++); V->setID(CurrentBlockID, CurrentVarID++);
CurrentBB->addInstr(V); CurrentBB->addInstr(V);
if (S) if (S)
BuildEx.insertStmt(S, V); BuildEx.insertStmt(S, V);
return V;
} }
public:
// Enter the CFG for Decl D, and perform any initial setup operations. // Enter the CFG for Decl D, and perform any initial setup operations.
void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) { void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {
Scfg = new (Arena) til::SCFG(Arena, Cfg->getNumBlockIDs()); Scfg = new (Arena) til::SCFG(Arena, Cfg->getNumBlockIDs());
@ -345,7 +340,7 @@ public:
til::SExpr *Sf = new (Arena) til::LiteralPtr(VD); til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);
til::SExpr *Dr = new (Arena) til::LiteralPtr(DD); til::SExpr *Dr = new (Arena) til::LiteralPtr(DD);
til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf); til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf);
til::SExpr *E = new (Arena) til::Call(Ap, 0); til::SExpr *E = new (Arena) til::Call(Ap);
addStatement(E, nullptr); addStatement(E, nullptr);
} }
@ -363,20 +358,15 @@ public:
// Leave the CFG, and perform any final cleanup operations. // Leave the CFG, and perform any final cleanup operations.
void exitCFG(const CFGBlock *Last) { void exitCFG(const CFGBlock *Last) {
if (CallCtx) { delete CallCtx;
delete CallCtx; CallCtx = nullptr;
CallCtx = nullptr;
}
} }
SCFGBuilder(til::MemRegionRef A) SCFGBuilder(til::MemRegionRef A)
: Arena(A), Scfg(0), CurrentBB(0), CurrentBlockID(0), : Arena(A), Scfg(nullptr), CurrentBB(nullptr), CurrentBlockID(0),
CallCtx(0), SMap(new SExprBuilder::StatementMap()), CurrentVarID(0), CallCtx(nullptr),
BuildEx(A, SMap) SMap(new SExprBuilder::StatementMap()), BuildEx(A, SMap) {}
{ } ~SCFGBuilder() { delete SMap; }
~SCFGBuilder() {
delete SMap;
}
til::SCFG *getCFG() const { return Scfg; } til::SCFG *getCFG() const { return Scfg; }