mirror of https://github.com/microsoft/clang.git
[Analysis] Fix some Clang-tidy modernize and Include What You Use warnings; other minor fixes (NFC).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@327453 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
edf8cedd1b
commit
79bbdd4289
|
@ -1,4 +1,4 @@
|
|||
//===- Consumed.h ----------------------------------------------*- C++ --*-===//
|
||||
//===- Consumed.h -----------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -15,16 +15,32 @@
|
|||
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
|
||||
#define LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
|
||||
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
||||
#include "clang/Analysis/AnalysisDeclContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class AnalysisDeclContext;
|
||||
class CXXBindTemporaryExpr;
|
||||
class FunctionDecl;
|
||||
class PostOrderCFGView;
|
||||
class Stmt;
|
||||
class VarDecl;
|
||||
|
||||
namespace consumed {
|
||||
|
||||
class ConsumedStmtVisitor;
|
||||
|
||||
enum ConsumedState {
|
||||
// No state information for the given variable.
|
||||
CS_None,
|
||||
|
@ -34,16 +50,12 @@ namespace consumed {
|
|||
CS_Consumed
|
||||
};
|
||||
|
||||
class ConsumedStmtVisitor;
|
||||
|
||||
typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
|
||||
typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
|
||||
typedef std::list<DelayedDiag> DiagList;
|
||||
using OptionalNotes = SmallVector<PartialDiagnosticAt, 1>;
|
||||
using DelayedDiag = std::pair<PartialDiagnosticAt, OptionalNotes>;
|
||||
using DiagList = std::list<DelayedDiag>;
|
||||
|
||||
class ConsumedWarningsHandlerBase {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~ConsumedWarningsHandlerBase();
|
||||
|
||||
/// \brief Emit the warnings and notes left by the analysis.
|
||||
|
@ -129,23 +141,21 @@ namespace consumed {
|
|||
};
|
||||
|
||||
class ConsumedStateMap {
|
||||
|
||||
typedef llvm::DenseMap<const VarDecl *, ConsumedState> VarMapType;
|
||||
typedef llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState>
|
||||
TmpMapType;
|
||||
using VarMapType = llvm::DenseMap<const VarDecl *, ConsumedState>;
|
||||
using TmpMapType =
|
||||
llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState>;
|
||||
|
||||
protected:
|
||||
|
||||
bool Reachable;
|
||||
const Stmt *From;
|
||||
bool Reachable = true;
|
||||
const Stmt *From = nullptr;
|
||||
VarMapType VarMap;
|
||||
TmpMapType TmpMap;
|
||||
|
||||
public:
|
||||
ConsumedStateMap() : Reachable(true), From(nullptr) {}
|
||||
ConsumedStateMap() = default;
|
||||
ConsumedStateMap(const ConsumedStateMap &Other)
|
||||
: Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap),
|
||||
TmpMap() {}
|
||||
: Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap),
|
||||
TmpMap() {}
|
||||
|
||||
/// \brief Warn if any of the parameters being tracked are not in the state
|
||||
/// they were declared to be in upon return from a function.
|
||||
|
@ -205,10 +215,8 @@ namespace consumed {
|
|||
ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph)
|
||||
: StateMapsArray(NumBlocks), VisitOrder(NumBlocks, 0) {
|
||||
unsigned int VisitOrderCounter = 0;
|
||||
for (PostOrderCFGView::iterator BI = SortedGraph->begin(),
|
||||
BE = SortedGraph->end(); BI != BE; ++BI) {
|
||||
VisitOrder[(*BI)->getBlockID()] = VisitOrderCounter++;
|
||||
}
|
||||
for (const auto BI : *SortedGraph)
|
||||
VisitOrder[BI->getBlockID()] = VisitOrderCounter++;
|
||||
}
|
||||
|
||||
bool allBackEdgesVisited(const CFGBlock *CurrBlock,
|
||||
|
@ -231,7 +239,6 @@ namespace consumed {
|
|||
|
||||
/// A class that handles the analysis of uniqueness violations.
|
||||
class ConsumedAnalyzer {
|
||||
|
||||
ConsumedBlockInfo BlockInfo;
|
||||
std::unique_ptr<ConsumedStateMap> CurrStates;
|
||||
|
||||
|
@ -243,7 +250,6 @@ namespace consumed {
|
|||
const ConsumedStmtVisitor &Visitor);
|
||||
|
||||
public:
|
||||
|
||||
ConsumedWarningsHandlerBase &WarningsHandler;
|
||||
|
||||
ConsumedAnalyzer(ConsumedWarningsHandlerBase &WarningsHandler)
|
||||
|
@ -259,6 +265,9 @@ namespace consumed {
|
|||
/// exactly once.
|
||||
void run(AnalysisDeclContext &AC);
|
||||
};
|
||||
}} // end namespace clang::consumed
|
||||
|
||||
#endif
|
||||
} // namespace consumed
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//==- Dominators.h - Implementation of dominators tree for Clang CFG C++ -*-==//
|
||||
//- Dominators.h - Implementation of dominators tree for Clang CFG -*- C++ -*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -16,29 +16,35 @@
|
|||
|
||||
#include "clang/Analysis/AnalysisDeclContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Support/GenericDomTree.h"
|
||||
#include "llvm/Support/GenericDomTreeConstruction.h"
|
||||
#include "llvm/Support/GenericDomTreeConstruction.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
// FIXME: There is no good reason for the domtree to require a print method
|
||||
// which accepts an LLVM Module, so remove this (and the method's argument that
|
||||
// needs it) when that is fixed.
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Module;
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
namespace clang {
|
||||
|
||||
class CFGBlock;
|
||||
typedef llvm::DomTreeNodeBase<CFGBlock> DomTreeNode;
|
||||
using DomTreeNode = llvm::DomTreeNodeBase<CFGBlock>;
|
||||
|
||||
/// \brief Concrete subclass of DominatorTreeBase for Clang
|
||||
/// This class implements the dominators tree functionality given a Clang CFG.
|
||||
///
|
||||
class DominatorTree : public ManagedAnalysis {
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
llvm::DomTreeBase<CFGBlock>* DT;
|
||||
llvm::DomTreeBase<CFGBlock> *DT;
|
||||
|
||||
DominatorTree() {
|
||||
DT = new llvm::DomTreeBase<CFGBlock>();
|
||||
|
@ -49,22 +55,20 @@ public:
|
|||
llvm::DomTreeBase<CFGBlock>& getBase() { return *DT; }
|
||||
|
||||
/// \brief This method returns the root CFGBlock of the dominators tree.
|
||||
///
|
||||
inline CFGBlock *getRoot() const {
|
||||
CFGBlock *getRoot() const {
|
||||
return DT->getRoot();
|
||||
}
|
||||
|
||||
/// \brief This method returns the root DomTreeNode, which is the wrapper
|
||||
/// for CFGBlock.
|
||||
inline DomTreeNode *getRootNode() const {
|
||||
DomTreeNode *getRootNode() const {
|
||||
return DT->getRootNode();
|
||||
}
|
||||
|
||||
/// \brief This method compares two dominator trees.
|
||||
/// The method returns false if the other dominator tree matches this
|
||||
/// dominator tree, otherwise returns true.
|
||||
///
|
||||
inline bool compare(DominatorTree &Other) const {
|
||||
bool compare(DominatorTree &Other) const {
|
||||
DomTreeNode *R = getRootNode();
|
||||
DomTreeNode *OtherR = Other.getRootNode();
|
||||
|
||||
|
@ -79,7 +83,6 @@ public:
|
|||
|
||||
/// \brief This method builds the dominator tree for a given CFG
|
||||
/// The CFG information is passed via AnalysisDeclContext
|
||||
///
|
||||
void buildDominatorTree(AnalysisDeclContext &AC) {
|
||||
cfg = AC.getCFG();
|
||||
DT->recalculate(*cfg);
|
||||
|
@ -87,7 +90,6 @@ public:
|
|||
|
||||
/// \brief This method dumps immediate dominators for each block,
|
||||
/// mainly used for debug purposes.
|
||||
///
|
||||
void dump() {
|
||||
llvm::errs() << "Immediate dominance tree (Node#,IDom#):\n";
|
||||
for (CFG::const_iterator I = cfg->begin(),
|
||||
|
@ -105,52 +107,45 @@ public:
|
|||
/// \brief This method tests if one CFGBlock dominates the other.
|
||||
/// The method return true if A dominates B, false otherwise.
|
||||
/// Note a block always dominates itself.
|
||||
///
|
||||
inline bool dominates(const CFGBlock* A, const CFGBlock* B) const {
|
||||
bool dominates(const CFGBlock *A, const CFGBlock *B) const {
|
||||
return DT->dominates(A, B);
|
||||
}
|
||||
|
||||
/// \brief This method tests if one CFGBlock properly dominates the other.
|
||||
/// The method return true if A properly dominates B, false otherwise.
|
||||
///
|
||||
bool properlyDominates(const CFGBlock*A, const CFGBlock*B) const {
|
||||
bool properlyDominates(const CFGBlock *A, const CFGBlock *B) const {
|
||||
return DT->properlyDominates(A, B);
|
||||
}
|
||||
|
||||
/// \brief This method finds the nearest common dominator CFG block
|
||||
/// for CFG block A and B. If there is no such block then return NULL.
|
||||
///
|
||||
inline CFGBlock *findNearestCommonDominator(CFGBlock *A, CFGBlock *B) {
|
||||
CFGBlock *findNearestCommonDominator(CFGBlock *A, CFGBlock *B) {
|
||||
return DT->findNearestCommonDominator(A, B);
|
||||
}
|
||||
|
||||
inline const CFGBlock *findNearestCommonDominator(const CFGBlock *A,
|
||||
const CFGBlock *B) {
|
||||
const CFGBlock *findNearestCommonDominator(const CFGBlock *A,
|
||||
const CFGBlock *B) {
|
||||
return DT->findNearestCommonDominator(A, B);
|
||||
}
|
||||
|
||||
/// \brief This method is used to update the dominator
|
||||
/// tree information when a node's immediate dominator changes.
|
||||
///
|
||||
inline void changeImmediateDominator(CFGBlock *N, CFGBlock *NewIDom) {
|
||||
void changeImmediateDominator(CFGBlock *N, CFGBlock *NewIDom) {
|
||||
DT->changeImmediateDominator(N, NewIDom);
|
||||
}
|
||||
|
||||
/// \brief This method tests if the given CFGBlock can be reachable from root.
|
||||
/// Returns true if reachable, false otherwise.
|
||||
///
|
||||
bool isReachableFromEntry(const CFGBlock *A) {
|
||||
return DT->isReachableFromEntry(A);
|
||||
}
|
||||
|
||||
/// \brief This method releases the memory held by the dominator tree.
|
||||
///
|
||||
virtual void releaseMemory() {
|
||||
DT->releaseMemory();
|
||||
}
|
||||
|
||||
/// \brief This method converts the dominator tree to human readable form.
|
||||
///
|
||||
virtual void print(raw_ostream &OS, const llvm::Module* M= nullptr) const {
|
||||
DT->print(OS);
|
||||
}
|
||||
|
@ -159,23 +154,24 @@ private:
|
|||
CFG *cfg;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
} // namespace clang
|
||||
|
||||
//===-------------------------------------
|
||||
/// DominatorTree GraphTraits specialization so the DominatorTree can be
|
||||
/// iterable by generic graph iterators.
|
||||
///
|
||||
namespace llvm {
|
||||
|
||||
template <> struct GraphTraits< ::clang::DomTreeNode* > {
|
||||
typedef ::clang::DomTreeNode *NodeRef;
|
||||
typedef ::clang::DomTreeNode::iterator ChildIteratorType;
|
||||
using NodeRef = ::clang::DomTreeNode *;
|
||||
using ChildIteratorType = ::clang::DomTreeNode::iterator;
|
||||
|
||||
static NodeRef getEntryNode(NodeRef N) { return N; }
|
||||
static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(NodeRef N) { return N->end(); }
|
||||
|
||||
typedef llvm::pointer_iterator<df_iterator<::clang::DomTreeNode *>>
|
||||
nodes_iterator;
|
||||
using nodes_iterator =
|
||||
llvm::pointer_iterator<df_iterator<::clang::DomTreeNode *>>;
|
||||
|
||||
static nodes_iterator nodes_begin(::clang::DomTreeNode *N) {
|
||||
return nodes_iterator(df_begin(getEntryNode(N)));
|
||||
|
@ -187,7 +183,7 @@ template <> struct GraphTraits< ::clang::DomTreeNode* > {
|
|||
};
|
||||
|
||||
template <> struct GraphTraits< ::clang::DominatorTree* >
|
||||
: public GraphTraits< ::clang::DomTreeNode* > {
|
||||
: public GraphTraits< ::clang::DomTreeNode* > {
|
||||
static NodeRef getEntryNode(::clang::DominatorTree *DT) {
|
||||
return DT->getRootNode();
|
||||
}
|
||||
|
@ -200,6 +196,7 @@ template <> struct GraphTraits< ::clang::DominatorTree* >
|
|||
return nodes_iterator(df_end(getEntryNode(N)));
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===- PostOrderCFGView.h - Post order view of CFG blocks ---------*- C++ --*-//
|
||||
//===- PostOrderCFGView.h - Post order view of CFG blocks -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -14,20 +14,21 @@
|
|||
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H
|
||||
#define LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H
|
||||
|
||||
#include <vector>
|
||||
//#include <algorithm>
|
||||
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
|
||||
#include "clang/Analysis/AnalysisDeclContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class PostOrderCFGView : public ManagedAnalysis {
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
/// \brief Implements a set of CFGBlocks using a BitVector.
|
||||
///
|
||||
|
@ -37,12 +38,13 @@ public:
|
|||
/// visit during the analysis.
|
||||
class CFGBlockSet {
|
||||
llvm::BitVector VisitedBlockIDs;
|
||||
|
||||
public:
|
||||
// po_iterator requires this iterator, but the only interface needed is the
|
||||
// value_type typedef.
|
||||
struct iterator { typedef const CFGBlock *value_type; };
|
||||
// value_type type.
|
||||
struct iterator { using value_type = const CFGBlock *; };
|
||||
|
||||
CFGBlockSet() {}
|
||||
CFGBlockSet() = default;
|
||||
CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {}
|
||||
|
||||
/// \brief Set the bit associated with a particular CFGBlock.
|
||||
|
@ -69,33 +71,34 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator;
|
||||
std::vector<const CFGBlock*> Blocks;
|
||||
using po_iterator = llvm::po_iterator<const CFG *, CFGBlockSet, true>;
|
||||
std::vector<const CFGBlock *> Blocks;
|
||||
|
||||
typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy;
|
||||
using BlockOrderTy = llvm::DenseMap<const CFGBlock *, unsigned>;
|
||||
BlockOrderTy BlockOrder;
|
||||
|
||||
public:
|
||||
typedef std::vector<const CFGBlock *>::reverse_iterator iterator;
|
||||
typedef std::vector<const CFGBlock *>::const_reverse_iterator const_iterator;
|
||||
friend struct BlockOrderCompare;
|
||||
|
||||
using iterator = std::vector<const CFGBlock *>::reverse_iterator;
|
||||
using const_iterator = std::vector<const CFGBlock *>::const_reverse_iterator;
|
||||
|
||||
PostOrderCFGView(const CFG *cfg);
|
||||
|
||||
iterator begin() { return Blocks.rbegin(); }
|
||||
iterator end() { return Blocks.rend(); }
|
||||
iterator end() { return Blocks.rend(); }
|
||||
|
||||
const_iterator begin() const { return Blocks.rbegin(); }
|
||||
const_iterator end() const { return Blocks.rend(); }
|
||||
|
||||
bool empty() const { return begin() == end(); }
|
||||
|
||||
struct BlockOrderCompare;
|
||||
friend struct BlockOrderCompare;
|
||||
|
||||
struct BlockOrderCompare {
|
||||
const PostOrderCFGView &POV;
|
||||
|
||||
public:
|
||||
BlockOrderCompare(const PostOrderCFGView &pov) : POV(pov) {}
|
||||
|
||||
bool operator()(const CFGBlock *b1, const CFGBlock *b2) const;
|
||||
};
|
||||
|
||||
|
@ -109,7 +112,6 @@ public:
|
|||
static PostOrderCFGView *create(AnalysisDeclContext &analysisContext);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===- ThreadSafetyCommon.h ------------------------------------*- C++ --*-===//
|
||||
//===- ThreadSafetyCommon.h -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -22,20 +22,41 @@
|
|||
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
|
||||
#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
|
||||
#include "clang/Analysis/AnalysisDeclContext.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace clang {
|
||||
namespace threadSafety {
|
||||
|
||||
class AbstractConditionalOperator;
|
||||
class ArraySubscriptExpr;
|
||||
class BinaryOperator;
|
||||
class CallExpr;
|
||||
class CastExpr;
|
||||
class CXXDestructorDecl;
|
||||
class CXXMemberCallExpr;
|
||||
class CXXOperatorCallExpr;
|
||||
class CXXThisExpr;
|
||||
class DeclRefExpr;
|
||||
class DeclStmt;
|
||||
class Expr;
|
||||
class MemberExpr;
|
||||
class Stmt;
|
||||
class UnaryOperator;
|
||||
|
||||
namespace threadSafety {
|
||||
|
||||
// Various helper functions on til::SExpr
|
||||
namespace sx {
|
||||
|
@ -72,9 +93,7 @@ inline std::string toString(const til::SExpr *E) {
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
} // end namespace sx
|
||||
|
||||
|
||||
} // namespace sx
|
||||
|
||||
// This class defines the interface of a clang CFG Visitor.
|
||||
// CFGWalker will invoke the following methods.
|
||||
|
@ -123,11 +142,10 @@ class CFGVisitor {
|
|||
void exitCFG(const CFGBlock *Last) {}
|
||||
};
|
||||
|
||||
|
||||
// Walks the clang CFG, and invokes methods on a given CFGVisitor.
|
||||
class CFGWalker {
|
||||
public:
|
||||
CFGWalker() : CFGraph(nullptr), ACtx(nullptr), SortedGraph(nullptr) {}
|
||||
CFGWalker() = default;
|
||||
|
||||
// Initialize the CFGWalker. This setup only needs to be done once, even
|
||||
// if there are multiple passes over the CFG.
|
||||
|
@ -186,15 +204,15 @@ public:
|
|||
// Process statements
|
||||
for (const auto &BI : *CurrBlock) {
|
||||
switch (BI.getKind()) {
|
||||
case CFGElement::Statement: {
|
||||
case CFGElement::Statement:
|
||||
V.handleStatement(BI.castAs<CFGStmt>().getStmt());
|
||||
break;
|
||||
}
|
||||
|
||||
case CFGElement::AutomaticObjectDtor: {
|
||||
CFGAutomaticObjDtor AD = BI.castAs<CFGAutomaticObjDtor>();
|
||||
CXXDestructorDecl *DD = const_cast<CXXDestructorDecl*>(
|
||||
auto *DD = const_cast<CXXDestructorDecl *>(
|
||||
AD.getDestructorDecl(ACtx->getASTContext()));
|
||||
VarDecl *VD = const_cast<VarDecl*>(AD.getVarDecl());
|
||||
auto *VD = const_cast<VarDecl *>(AD.getVarDecl());
|
||||
V.handleDestructorCall(VD, DD);
|
||||
break;
|
||||
}
|
||||
|
@ -242,28 +260,27 @@ public:
|
|||
const PostOrderCFGView *getSortedGraph() const { return SortedGraph; }
|
||||
|
||||
private:
|
||||
CFG *CFGraph;
|
||||
AnalysisDeclContext *ACtx;
|
||||
PostOrderCFGView *SortedGraph;
|
||||
CFG *CFGraph = nullptr;
|
||||
AnalysisDeclContext *ACtx = nullptr;
|
||||
PostOrderCFGView *SortedGraph = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: move this back into ThreadSafety.cpp
|
||||
// This is specific to thread safety. It is here because
|
||||
// translateAttrExpr needs it, but that should be moved too.
|
||||
class CapabilityExpr {
|
||||
// TODO: move this back into ThreadSafety.cpp
|
||||
// This is specific to thread safety. It is here because
|
||||
// translateAttrExpr needs it, but that should be moved too.
|
||||
|
||||
private:
|
||||
const til::SExpr* CapExpr; ///< The capability expression.
|
||||
bool Negated; ///< True if this is a negative capability
|
||||
/// The capability expression.
|
||||
const til::SExpr* CapExpr;
|
||||
|
||||
/// True if this is a negative capability.
|
||||
bool Negated;
|
||||
|
||||
public:
|
||||
CapabilityExpr(const til::SExpr *E, bool Neg) : CapExpr(E), Negated(Neg) {}
|
||||
|
||||
const til::SExpr* sexpr() const { return CapExpr; }
|
||||
bool negative() const { return Negated; }
|
||||
const til::SExpr* sexpr() const { return CapExpr; }
|
||||
bool negative() const { return Negated; }
|
||||
|
||||
CapabilityExpr operator!() const {
|
||||
return CapabilityExpr(CapExpr, !Negated);
|
||||
|
@ -289,9 +306,9 @@ public:
|
|||
const ValueDecl* valueDecl() const {
|
||||
if (Negated || CapExpr == nullptr)
|
||||
return nullptr;
|
||||
if (auto *P = dyn_cast<til::Project>(CapExpr))
|
||||
if (const auto *P = dyn_cast<til::Project>(CapExpr))
|
||||
return P->clangDecl();
|
||||
if (auto *P = dyn_cast<til::LiteralPtr>(CapExpr))
|
||||
if (const auto *P = dyn_cast<til::LiteralPtr>(CapExpr))
|
||||
return P->clangDecl();
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -309,8 +326,6 @@ public:
|
|||
bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Translate clang::Expr to til::SExpr.
|
||||
class SExprBuilder {
|
||||
public:
|
||||
|
@ -324,22 +339,29 @@ public:
|
|||
/// should be evaluated; multiple calling contexts can be chained together
|
||||
/// by the lock_returned attribute.
|
||||
struct CallingContext {
|
||||
CallingContext *Prev; // The previous context; or 0 if none.
|
||||
const NamedDecl *AttrDecl; // The decl to which the attr is attached.
|
||||
const Expr *SelfArg; // Implicit object argument -- e.g. 'this'
|
||||
unsigned NumArgs; // Number of funArgs
|
||||
const Expr *const *FunArgs; // Function arguments
|
||||
bool SelfArrow; // is Self referred to with -> or .?
|
||||
// The previous context; or 0 if none.
|
||||
CallingContext *Prev;
|
||||
|
||||
// The decl to which the attr is attached.
|
||||
const NamedDecl *AttrDecl;
|
||||
|
||||
// Implicit object argument -- e.g. 'this'
|
||||
const Expr *SelfArg = nullptr;
|
||||
|
||||
// Number of funArgs
|
||||
unsigned NumArgs = 0;
|
||||
|
||||
// Function arguments
|
||||
const Expr *const *FunArgs = nullptr;
|
||||
|
||||
// is Self referred to with -> or .?
|
||||
bool SelfArrow = false;
|
||||
|
||||
CallingContext(CallingContext *P, const NamedDecl *D = nullptr)
|
||||
: Prev(P), AttrDecl(D), SelfArg(nullptr),
|
||||
NumArgs(0), FunArgs(nullptr), SelfArrow(false)
|
||||
{}
|
||||
: Prev(P), AttrDecl(D) {}
|
||||
};
|
||||
|
||||
SExprBuilder(til::MemRegionRef A)
|
||||
: Arena(A), SelfVar(nullptr), Scfg(nullptr), CurrentBB(nullptr),
|
||||
CurrentBlockInfo(nullptr) {
|
||||
SExprBuilder(til::MemRegionRef A) : Arena(A), CurrentBB() {
|
||||
// FIXME: we don't always have a self-variable.
|
||||
SelfVar = new (Arena) til::Variable(nullptr);
|
||||
SelfVar->setKind(til::Variable::VK_SFun);
|
||||
|
@ -368,6 +390,9 @@ public:
|
|||
til::SCFG *getCFG() { return Scfg; }
|
||||
|
||||
private:
|
||||
// We implement the CFGVisitor API
|
||||
friend class CFGWalker;
|
||||
|
||||
til::SExpr *translateDeclRefExpr(const DeclRefExpr *DRE,
|
||||
CallingContext *Ctx) ;
|
||||
til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx);
|
||||
|
@ -397,31 +422,30 @@ private:
|
|||
til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx);
|
||||
|
||||
// Map from statements in the clang CFG to SExprs in the til::SCFG.
|
||||
typedef llvm::DenseMap<const Stmt*, til::SExpr*> StatementMap;
|
||||
using StatementMap = llvm::DenseMap<const Stmt *, til::SExpr *>;
|
||||
|
||||
// Map from clang local variables to indices in a LVarDefinitionMap.
|
||||
typedef llvm::DenseMap<const ValueDecl *, unsigned> LVarIndexMap;
|
||||
using LVarIndexMap = llvm::DenseMap<const ValueDecl *, unsigned>;
|
||||
|
||||
// Map from local variable indices to SSA variables (or constants).
|
||||
typedef std::pair<const ValueDecl *, til::SExpr *> NameVarPair;
|
||||
typedef CopyOnWriteVector<NameVarPair> LVarDefinitionMap;
|
||||
using NameVarPair = std::pair<const ValueDecl *, til::SExpr *>;
|
||||
using LVarDefinitionMap = CopyOnWriteVector<NameVarPair>;
|
||||
|
||||
struct BlockInfo {
|
||||
LVarDefinitionMap ExitMap;
|
||||
bool HasBackEdges;
|
||||
unsigned UnprocessedSuccessors; // Successors yet to be processed
|
||||
unsigned ProcessedPredecessors; // Predecessors already processed
|
||||
bool HasBackEdges = false;
|
||||
|
||||
BlockInfo()
|
||||
: HasBackEdges(false), UnprocessedSuccessors(0),
|
||||
ProcessedPredecessors(0) {}
|
||||
// Successors yet to be processed
|
||||
unsigned UnprocessedSuccessors = 0;
|
||||
|
||||
// Predecessors already processed
|
||||
unsigned ProcessedPredecessors = 0;
|
||||
|
||||
BlockInfo() = default;
|
||||
BlockInfo(BlockInfo &&) = default;
|
||||
BlockInfo &operator=(BlockInfo &&) = default;
|
||||
};
|
||||
|
||||
// We implement the CFGVisitor API
|
||||
friend class CFGWalker;
|
||||
|
||||
void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First);
|
||||
void enterCFGBlock(const CFGBlock *B);
|
||||
bool visitPredecessors() { return true; }
|
||||
|
@ -440,6 +464,7 @@ private:
|
|||
void insertStmt(const Stmt *S, til::SExpr *E) {
|
||||
SMap.insert(std::make_pair(S, E));
|
||||
}
|
||||
|
||||
til::SExpr *getCurrentLVarDefinition(const ValueDecl *VD);
|
||||
|
||||
til::SExpr *addStatement(til::SExpr *E, const Stmt *S,
|
||||
|
@ -459,30 +484,36 @@ private:
|
|||
static const bool CapabilityExprMode = true;
|
||||
|
||||
til::MemRegionRef Arena;
|
||||
til::Variable *SelfVar; // Variable to use for 'this'. May be null.
|
||||
|
||||
til::SCFG *Scfg;
|
||||
StatementMap SMap; // Map from Stmt to TIL Variables
|
||||
LVarIndexMap LVarIdxMap; // Indices of clang local vars.
|
||||
std::vector<til::BasicBlock *> BlockMap; // Map from clang to til BBs.
|
||||
std::vector<BlockInfo> BBInfo; // Extra information per BB.
|
||||
// Indexed by clang BlockID.
|
||||
// Variable to use for 'this'. May be null.
|
||||
til::Variable *SelfVar = nullptr;
|
||||
|
||||
til::SCFG *Scfg = nullptr;
|
||||
|
||||
// Map from Stmt to TIL Variables
|
||||
StatementMap SMap;
|
||||
|
||||
// Indices of clang local vars.
|
||||
LVarIndexMap LVarIdxMap;
|
||||
|
||||
// Map from clang to til BBs.
|
||||
std::vector<til::BasicBlock *> BlockMap;
|
||||
|
||||
// Extra information per BB. Indexed by clang BlockID.
|
||||
std::vector<BlockInfo> BBInfo;
|
||||
|
||||
LVarDefinitionMap CurrentLVarMap;
|
||||
std::vector<til::Phi*> CurrentArguments;
|
||||
std::vector<til::SExpr*> CurrentInstructions;
|
||||
std::vector<til::Phi*> IncompleteArgs;
|
||||
til::BasicBlock *CurrentBB;
|
||||
BlockInfo *CurrentBlockInfo;
|
||||
std::vector<til::Phi *> CurrentArguments;
|
||||
std::vector<til::SExpr *> CurrentInstructions;
|
||||
std::vector<til::Phi *> IncompleteArgs;
|
||||
til::BasicBlock *CurrentBB = nullptr;
|
||||
BlockInfo *CurrentBlockInfo = nullptr;
|
||||
};
|
||||
|
||||
|
||||
// Dump an SCFG to llvm::errs().
|
||||
void printSCFG(CFGWalker &Walker);
|
||||
|
||||
} // namespace threadSafety
|
||||
} // namespace clang
|
||||
|
||||
} // end namespace threadSafety
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_THREAD_SAFETY_COMMON_H
|
||||
#endif // LLVM_CLANG_THREAD_SAFETY_COMMON_H
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===- Consumed.cpp --------------------------------------------*- C++ --*-===//
|
||||
//===- Consumed.cpp -------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -13,21 +13,29 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/Analyses/Consumed.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
||||
#include "clang/Analysis/AnalysisDeclContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
// TODO: Adjust states of args to constructors in the same way that arguments to
|
||||
// function calls are handled.
|
||||
|
@ -49,7 +57,7 @@ using namespace clang;
|
|||
using namespace consumed;
|
||||
|
||||
// Key method definition
|
||||
ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
|
||||
ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() = default;
|
||||
|
||||
static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
|
||||
// Find the source location of the first statement in the block, if the block
|
||||
|
@ -63,7 +71,7 @@ static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
|
|||
if (Block->succ_size() == 1 && *Block->succ_begin())
|
||||
return getFirstStmtLoc(*Block->succ_begin());
|
||||
|
||||
return SourceLocation();
|
||||
return {};
|
||||
}
|
||||
|
||||
static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
|
||||
|
@ -109,7 +117,6 @@ static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
|
|||
|
||||
static bool isCallableInState(const CallableWhenAttr *CWAttr,
|
||||
ConsumedState State) {
|
||||
|
||||
for (const auto &S : CWAttr->callableStates()) {
|
||||
ConsumedState MappedAttrState = CS_None;
|
||||
|
||||
|
@ -134,7 +141,6 @@ static bool isCallableInState(const CallableWhenAttr *CWAttr,
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool isConsumableType(const QualType &QT) {
|
||||
if (QT->isPointerType() || QT->isReferenceType())
|
||||
return false;
|
||||
|
@ -161,7 +167,6 @@ static bool isSetOnReadPtrType(const QualType &QT) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool isKnownState(ConsumedState State) {
|
||||
switch (State) {
|
||||
case CS_Unconsumed:
|
||||
|
@ -270,11 +275,13 @@ static ConsumedState testsFor(const FunctionDecl *FunDecl) {
|
|||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct VarTestResult {
|
||||
const VarDecl *Var;
|
||||
ConsumedState TestsFor;
|
||||
};
|
||||
} // end anonymous::VarTestResult
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace clang {
|
||||
namespace consumed {
|
||||
|
@ -292,7 +299,7 @@ class PropagationInfo {
|
|||
IT_BinTest,
|
||||
IT_Var,
|
||||
IT_Tmp
|
||||
} InfoType;
|
||||
} InfoType = IT_None;
|
||||
|
||||
struct BinTestTy {
|
||||
const BinaryOperator *Source;
|
||||
|
@ -310,22 +317,19 @@ class PropagationInfo {
|
|||
};
|
||||
|
||||
public:
|
||||
PropagationInfo() : InfoType(IT_None) {}
|
||||
|
||||
PropagationInfo() = default;
|
||||
PropagationInfo(const VarTestResult &VarTest)
|
||||
: InfoType(IT_VarTest), VarTest(VarTest) {}
|
||||
|
||||
: InfoType(IT_VarTest), VarTest(VarTest) {}
|
||||
|
||||
PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
|
||||
: InfoType(IT_VarTest) {
|
||||
|
||||
: InfoType(IT_VarTest) {
|
||||
VarTest.Var = Var;
|
||||
VarTest.TestsFor = TestsFor;
|
||||
}
|
||||
|
||||
PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
|
||||
const VarTestResult <est, const VarTestResult &RTest)
|
||||
: InfoType(IT_BinTest) {
|
||||
|
||||
: InfoType(IT_BinTest) {
|
||||
BinTest.Source = Source;
|
||||
BinTest.EOp = EOp;
|
||||
BinTest.LTest = LTest;
|
||||
|
@ -335,8 +339,7 @@ public:
|
|||
PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
|
||||
const VarDecl *LVar, ConsumedState LTestsFor,
|
||||
const VarDecl *RVar, ConsumedState RTestsFor)
|
||||
: InfoType(IT_BinTest) {
|
||||
|
||||
: InfoType(IT_BinTest) {
|
||||
BinTest.Source = Source;
|
||||
BinTest.EOp = EOp;
|
||||
BinTest.LTest.Var = LVar;
|
||||
|
@ -346,38 +349,37 @@ public:
|
|||
}
|
||||
|
||||
PropagationInfo(ConsumedState State)
|
||||
: InfoType(IT_State), State(State) {}
|
||||
|
||||
: InfoType(IT_State), State(State) {}
|
||||
PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
|
||||
PropagationInfo(const CXXBindTemporaryExpr *Tmp)
|
||||
: InfoType(IT_Tmp), Tmp(Tmp) {}
|
||||
: InfoType(IT_Tmp), Tmp(Tmp) {}
|
||||
|
||||
const ConsumedState & getState() const {
|
||||
const ConsumedState &getState() const {
|
||||
assert(InfoType == IT_State);
|
||||
return State;
|
||||
}
|
||||
|
||||
const VarTestResult & getVarTest() const {
|
||||
const VarTestResult &getVarTest() const {
|
||||
assert(InfoType == IT_VarTest);
|
||||
return VarTest;
|
||||
}
|
||||
|
||||
const VarTestResult & getLTest() const {
|
||||
const VarTestResult &getLTest() const {
|
||||
assert(InfoType == IT_BinTest);
|
||||
return BinTest.LTest;
|
||||
}
|
||||
|
||||
const VarTestResult & getRTest() const {
|
||||
const VarTestResult &getRTest() const {
|
||||
assert(InfoType == IT_BinTest);
|
||||
return BinTest.RTest;
|
||||
}
|
||||
|
||||
const VarDecl * getVar() const {
|
||||
const VarDecl *getVar() const {
|
||||
assert(InfoType == IT_Var);
|
||||
return Var;
|
||||
}
|
||||
|
||||
const CXXBindTemporaryExpr * getTmp() const {
|
||||
const CXXBindTemporaryExpr *getTmp() const {
|
||||
assert(InfoType == IT_Tmp);
|
||||
return Tmp;
|
||||
}
|
||||
|
@ -405,12 +407,12 @@ public:
|
|||
return BinTest.Source;
|
||||
}
|
||||
|
||||
inline bool isValid() const { return InfoType != IT_None; }
|
||||
inline bool isState() const { return InfoType == IT_State; }
|
||||
inline bool isVarTest() const { return InfoType == IT_VarTest; }
|
||||
inline bool isBinTest() const { return InfoType == IT_BinTest; }
|
||||
inline bool isVar() const { return InfoType == IT_Var; }
|
||||
inline bool isTmp() const { return InfoType == IT_Tmp; }
|
||||
bool isValid() const { return InfoType != IT_None; }
|
||||
bool isState() const { return InfoType == IT_State; }
|
||||
bool isVarTest() const { return InfoType == IT_VarTest; }
|
||||
bool isBinTest() const { return InfoType == IT_BinTest; }
|
||||
bool isVar() const { return InfoType == IT_Var; }
|
||||
bool isTmp() const { return InfoType == IT_Tmp; }
|
||||
|
||||
bool isTest() const {
|
||||
return InfoType == IT_VarTest || InfoType == IT_BinTest;
|
||||
|
@ -433,15 +435,17 @@ public:
|
|||
BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
|
||||
BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
|
||||
} else {
|
||||
return PropagationInfo();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static inline void
|
||||
} // namespace consumed
|
||||
} // namespace clang
|
||||
|
||||
static void
|
||||
setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
|
||||
ConsumedState State) {
|
||||
|
||||
assert(PInfo.isVar() || PInfo.isTmp());
|
||||
|
||||
if (PInfo.isVar())
|
||||
|
@ -450,12 +454,14 @@ setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
|
|||
StateMap->setState(PInfo.getTmp(), State);
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
namespace consumed {
|
||||
|
||||
class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
|
||||
|
||||
typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType;
|
||||
typedef std::pair<const Stmt *, PropagationInfo> PairType;
|
||||
typedef MapType::iterator InfoEntry;
|
||||
typedef MapType::const_iterator ConstInfoEntry;
|
||||
using MapType = llvm::DenseMap<const Stmt *, PropagationInfo>;
|
||||
using PairType= std::pair<const Stmt *, PropagationInfo>;
|
||||
using InfoEntry = MapType::iterator;
|
||||
using ConstInfoEntry = MapType::const_iterator;
|
||||
|
||||
AnalysisDeclContext &AC;
|
||||
ConsumedAnalyzer &Analyzer;
|
||||
|
@ -463,17 +469,19 @@ class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
|
|||
MapType PropagationMap;
|
||||
|
||||
InfoEntry findInfo(const Expr *E) {
|
||||
if (auto Cleanups = dyn_cast<ExprWithCleanups>(E))
|
||||
if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
|
||||
if (!Cleanups->cleanupsHaveSideEffects())
|
||||
E = Cleanups->getSubExpr();
|
||||
return PropagationMap.find(E->IgnoreParens());
|
||||
}
|
||||
|
||||
ConstInfoEntry findInfo(const Expr *E) const {
|
||||
if (auto Cleanups = dyn_cast<ExprWithCleanups>(E))
|
||||
if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
|
||||
if (!Cleanups->cleanupsHaveSideEffects())
|
||||
E = Cleanups->getSubExpr();
|
||||
return PropagationMap.find(E->IgnoreParens());
|
||||
}
|
||||
|
||||
void insertInfo(const Expr *E, const PropagationInfo &PI) {
|
||||
PropagationMap.insert(PairType(E->IgnoreParens(), PI));
|
||||
}
|
||||
|
@ -517,7 +525,7 @@ public:
|
|||
if (Entry != PropagationMap.end())
|
||||
return Entry->second;
|
||||
else
|
||||
return PropagationInfo();
|
||||
return {};
|
||||
}
|
||||
|
||||
void reset(ConsumedStateMap *NewStateMap) {
|
||||
|
@ -525,6 +533,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace consumed
|
||||
} // namespace clang
|
||||
|
||||
void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
|
||||
InfoEntry Entry = findInfo(From);
|
||||
|
@ -532,7 +542,6 @@ void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
|
|||
insertInfo(To, Entry->second);
|
||||
}
|
||||
|
||||
|
||||
// Create a new state for To, which is initialized to the state of From.
|
||||
// If NS is not CS_None, sets the state of From to NS.
|
||||
void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
|
||||
|
@ -548,7 +557,6 @@ void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the ConsumedState for From
|
||||
ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) {
|
||||
InfoEntry Entry = findInfo(From);
|
||||
|
@ -559,7 +567,6 @@ ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) {
|
|||
return CS_None;
|
||||
}
|
||||
|
||||
|
||||
// If we already have info for To then update it, otherwise create a new entry.
|
||||
void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
|
||||
InfoEntry Entry = findInfo(To);
|
||||
|
@ -572,8 +579,6 @@ void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
|
||||
const FunctionDecl *FunDecl,
|
||||
SourceLocation BlameLoc) {
|
||||
|
@ -592,7 +597,6 @@ void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
|
|||
Analyzer.WarningsHandler.warnUseInInvalidState(
|
||||
FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
|
||||
stateToString(VarState), BlameLoc);
|
||||
|
||||
} else {
|
||||
ConsumedState TmpState = PInfo.getAsState(StateMap);
|
||||
|
||||
|
@ -604,7 +608,6 @@ void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Factors out common behavior for function, method, and operator calls.
|
||||
// Check parameters and set parameter state if necessary.
|
||||
// Returns true if the state of ObjArg is set, or false otherwise.
|
||||
|
@ -681,7 +684,6 @@ bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
|
||||
const FunctionDecl *Fun) {
|
||||
QualType RetType = Fun->getCallResultType();
|
||||
|
@ -699,7 +701,6 @@ void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
|
||||
switch (BinOp->getOpcode()) {
|
||||
case BO_LAnd:
|
||||
|
@ -711,7 +712,6 @@ void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
|
|||
|
||||
if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
|
||||
LTest = LEntry->second.getVarTest();
|
||||
|
||||
} else {
|
||||
LTest.Var = nullptr;
|
||||
LTest.TestsFor = CS_None;
|
||||
|
@ -719,7 +719,6 @@ void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
|
|||
|
||||
if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
|
||||
RTest = REntry->second.getVarTest();
|
||||
|
||||
} else {
|
||||
RTest.Var = nullptr;
|
||||
RTest.TestsFor = CS_None;
|
||||
|
@ -728,7 +727,6 @@ void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
|
|||
if (!(LTest.Var == nullptr && RTest.Var == nullptr))
|
||||
PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
|
||||
static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -805,7 +803,6 @@ void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
|
||||
const CXXMemberCallExpr *Call) {
|
||||
CXXMethodDecl* MD = Call->getMethodDecl();
|
||||
|
@ -816,12 +813,9 @@ void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
|
|||
propagateReturnType(Call, MD);
|
||||
}
|
||||
|
||||
|
||||
void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
|
||||
const CXXOperatorCallExpr *Call) {
|
||||
|
||||
const FunctionDecl *FunDecl =
|
||||
dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
|
||||
const auto *FunDecl = dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
|
||||
if (!FunDecl) return;
|
||||
|
||||
if (Call->getOperator() == OO_Equal) {
|
||||
|
@ -831,7 +825,7 @@ void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
|
|||
return;
|
||||
}
|
||||
|
||||
if (const CXXMemberCallExpr *MCall = dyn_cast<CXXMemberCallExpr>(Call))
|
||||
if (const auto *MCall = dyn_cast<CXXMemberCallExpr>(Call))
|
||||
handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
|
||||
else
|
||||
handleCall(Call, Call->getArg(0), FunDecl);
|
||||
|
@ -840,7 +834,7 @@ void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
|
|||
}
|
||||
|
||||
void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
|
||||
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
|
||||
if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
|
||||
if (StateMap->getState(Var) != consumed::CS_None)
|
||||
PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
|
||||
}
|
||||
|
@ -851,13 +845,12 @@ void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
|
|||
VisitVarDecl(cast<VarDecl>(DI));
|
||||
|
||||
if (DeclS->isSingleDecl())
|
||||
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
|
||||
if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
|
||||
PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
|
||||
}
|
||||
|
||||
void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
|
||||
const MaterializeTemporaryExpr *Temp) {
|
||||
|
||||
forwardInfo(Temp->GetTemporaryExpr(), Temp);
|
||||
}
|
||||
|
||||
|
@ -865,7 +858,6 @@ void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
|
|||
forwardInfo(MExpr->getBase(), MExpr);
|
||||
}
|
||||
|
||||
|
||||
void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
|
||||
QualType ParamType = Param->getType();
|
||||
ConsumedState ParamState = consumed::CS_None;
|
||||
|
@ -943,10 +935,6 @@ void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
|
|||
StateMap->setState(Var, consumed::CS_Unknown);
|
||||
}
|
||||
}
|
||||
}} // end clang::consumed::ConsumedStmtVisitor
|
||||
|
||||
namespace clang {
|
||||
namespace consumed {
|
||||
|
||||
static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test,
|
||||
ConsumedStateMap *ThenStates,
|
||||
|
@ -956,10 +944,8 @@ static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test,
|
|||
if (VarState == CS_Unknown) {
|
||||
ThenStates->setState(Test.Var, Test.TestsFor);
|
||||
ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
|
||||
|
||||
} else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
|
||||
ThenStates->markUnreachable();
|
||||
|
||||
} else if (VarState == Test.TestsFor) {
|
||||
ElseStates->markUnreachable();
|
||||
}
|
||||
|
@ -978,28 +964,22 @@ static void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
|
|||
if (PInfo.testEffectiveOp() == EO_And) {
|
||||
if (LState == CS_Unknown) {
|
||||
ThenStates->setState(LTest.Var, LTest.TestsFor);
|
||||
|
||||
} else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
|
||||
ThenStates->markUnreachable();
|
||||
|
||||
} else if (LState == LTest.TestsFor && isKnownState(RState)) {
|
||||
if (RState == RTest.TestsFor)
|
||||
ElseStates->markUnreachable();
|
||||
else
|
||||
ThenStates->markUnreachable();
|
||||
}
|
||||
|
||||
} else {
|
||||
if (LState == CS_Unknown) {
|
||||
ElseStates->setState(LTest.Var,
|
||||
invertConsumedUnconsumed(LTest.TestsFor));
|
||||
|
||||
} else if (LState == LTest.TestsFor) {
|
||||
ElseStates->markUnreachable();
|
||||
|
||||
} else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
|
||||
isKnownState(RState)) {
|
||||
|
||||
if (RState == RTest.TestsFor)
|
||||
ElseStates->markUnreachable();
|
||||
else
|
||||
|
@ -1014,7 +994,6 @@ static void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
|
|||
ThenStates->setState(RTest.Var, RTest.TestsFor);
|
||||
else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
|
||||
ThenStates->markUnreachable();
|
||||
|
||||
} else {
|
||||
if (RState == CS_Unknown)
|
||||
ElseStates->setState(RTest.Var,
|
||||
|
@ -1027,7 +1006,6 @@ static void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
|
|||
|
||||
bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
|
||||
const CFGBlock *TargetBlock) {
|
||||
|
||||
assert(CurrBlock && "Block pointer must not be NULL");
|
||||
assert(TargetBlock && "TargetBlock pointer must not be NULL");
|
||||
|
||||
|
@ -1043,7 +1021,6 @@ bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
|
|||
void ConsumedBlockInfo::addInfo(
|
||||
const CFGBlock *Block, ConsumedStateMap *StateMap,
|
||||
std::unique_ptr<ConsumedStateMap> &OwnedStateMap) {
|
||||
|
||||
assert(Block && "Block pointer must not be NULL");
|
||||
|
||||
auto &Entry = StateMapsArray[Block->getBlockID()];
|
||||
|
@ -1058,7 +1035,6 @@ void ConsumedBlockInfo::addInfo(
|
|||
|
||||
void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
|
||||
std::unique_ptr<ConsumedStateMap> StateMap) {
|
||||
|
||||
assert(Block && "Block pointer must not be NULL");
|
||||
|
||||
auto &Entry = StateMapsArray[Block->getBlockID()];
|
||||
|
@ -1119,7 +1095,7 @@ void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
|
|||
|
||||
for (const auto &DM : VarMap) {
|
||||
if (isa<ParmVarDecl>(DM.first)) {
|
||||
const ParmVarDecl *Param = cast<ParmVarDecl>(DM.first);
|
||||
const auto *Param = cast<ParmVarDecl>(DM.first);
|
||||
const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
|
||||
|
||||
if (!RTA)
|
||||
|
@ -1226,7 +1202,7 @@ bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
|
|||
void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
|
||||
const FunctionDecl *D) {
|
||||
QualType ReturnType;
|
||||
if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
||||
if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
||||
ASTContext &CurrContext = AC.getASTContext();
|
||||
ReturnType = Constructor->getThisType(CurrContext)->getPointeeType();
|
||||
} else
|
||||
|
@ -1256,14 +1232,12 @@ void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
|
|||
|
||||
bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
|
||||
const ConsumedStmtVisitor &Visitor) {
|
||||
|
||||
std::unique_ptr<ConsumedStateMap> FalseStates(
|
||||
new ConsumedStateMap(*CurrStates));
|
||||
PropagationInfo PInfo;
|
||||
|
||||
if (const IfStmt *IfNode =
|
||||
dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
|
||||
|
||||
if (const auto *IfNode =
|
||||
dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
|
||||
const Expr *Cond = IfNode->getCond();
|
||||
|
||||
PInfo = Visitor.getInfo(Cond);
|
||||
|
@ -1275,19 +1249,15 @@ bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
|
|||
FalseStates->setSource(Cond);
|
||||
splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates.get(),
|
||||
FalseStates.get());
|
||||
|
||||
} else if (PInfo.isBinTest()) {
|
||||
CurrStates->setSource(PInfo.testSourceNode());
|
||||
FalseStates->setSource(PInfo.testSourceNode());
|
||||
splitVarStateForIfBinOp(PInfo, CurrStates.get(), FalseStates.get());
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (const BinaryOperator *BinOp =
|
||||
dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
|
||||
|
||||
} else if (const auto *BinOp =
|
||||
dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
|
||||
PInfo = Visitor.getInfo(BinOp->getLHS());
|
||||
if (!PInfo.isVarTest()) {
|
||||
if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
|
||||
|
@ -1295,7 +1265,6 @@ bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
|
|||
|
||||
if (!PInfo.isVarTest())
|
||||
return false;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -1320,7 +1289,6 @@ bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
|
|||
else if (VarState == Test.TestsFor)
|
||||
FalseStates->markUnreachable();
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -1339,7 +1307,7 @@ bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
|
|||
}
|
||||
|
||||
void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
|
||||
const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
|
||||
const auto *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
|
||||
if (!D)
|
||||
return;
|
||||
|
||||
|
@ -1368,7 +1336,6 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
|
|||
|
||||
if (!CurrStates) {
|
||||
continue;
|
||||
|
||||
} else if (!CurrStates->isReachable()) {
|
||||
CurrStates = nullptr;
|
||||
continue;
|
||||
|
@ -1423,7 +1390,6 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
|
|||
|
||||
for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
|
||||
SE = CurrBlock->succ_end(); SI != SE; ++SI) {
|
||||
|
||||
if (*SI == nullptr) continue;
|
||||
|
||||
if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
|
||||
|
@ -1452,4 +1418,3 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
|
|||
|
||||
WarningsHandler.emitDiagnostics();
|
||||
}
|
||||
}} // end namespace clang::consumed
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//=- Dominators.cpp - Implementation of dominators tree for Clang CFG C++ -*-=//
|
||||
//===- Dominators.cpp - Implementation of dominators tree for Clang CFG ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -11,4 +11,4 @@
|
|||
|
||||
using namespace clang;
|
||||
|
||||
void DominatorTree::anchor() { }
|
||||
void DominatorTree::anchor() {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===- PostOrderCFGView.cpp - Post order view of CFG blocks -------*- C++ --*-//
|
||||
//===- PostOrderCFGView.cpp - Post order view of CFG blocks ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -12,10 +12,12 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
||||
#include "clang/Analysis/AnalysisDeclContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
void PostOrderCFGView::anchor() { }
|
||||
void PostOrderCFGView::anchor() {}
|
||||
|
||||
PostOrderCFGView::PostOrderCFGView(const CFG *cfg) {
|
||||
Blocks.reserve(cfg->getNumBlockIDs());
|
||||
|
@ -46,4 +48,3 @@ bool PostOrderCFGView::BlockOrderCompare::operator()(const CFGBlock *b1,
|
|||
unsigned b2V = (b2It == POV.BlockOrder.end()) ? 0 : b2It->second;
|
||||
return b1V > b2V;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===- ThreadSafetyCommon.cpp -----------------------------------*- C++ -*-===//
|
||||
//===- ThreadSafetyCommon.cpp ---------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -13,24 +13,32 @@
|
|||
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclGroup.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/OperationKinds.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
|
||||
#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
|
||||
#include "clang/Analysis/AnalysisDeclContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
using namespace clang;
|
||||
using namespace threadSafety;
|
||||
|
||||
// From ThreadSafetyUtil.h
|
||||
std::string threadSafety::getSourceLiteralString(const clang::Expr *CE) {
|
||||
std::string threadSafety::getSourceLiteralString(const Expr *CE) {
|
||||
switch (CE->getStmtClass()) {
|
||||
case Stmt::IntegerLiteralClass:
|
||||
return cast<IntegerLiteral>(CE)->getValue().toString(10, true);
|
||||
|
@ -59,7 +67,7 @@ static bool isIncompletePhi(const til::SExpr *E) {
|
|||
return false;
|
||||
}
|
||||
|
||||
typedef SExprBuilder::CallingContext CallingContext;
|
||||
using CallingContext = SExprBuilder::CallingContext;
|
||||
|
||||
til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
|
||||
auto It = SMap.find(S);
|
||||
|
@ -74,7 +82,7 @@ til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
|
|||
}
|
||||
|
||||
static bool isCalleeArrow(const Expr *E) {
|
||||
const MemberExpr *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts());
|
||||
const auto *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts());
|
||||
return ME ? ME->isArrow() : false;
|
||||
}
|
||||
|
||||
|
@ -97,20 +105,18 @@ CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
|
|||
|
||||
// Examine DeclExp to find SelfArg and FunArgs, which are used to substitute
|
||||
// for formal parameters when we call buildMutexID later.
|
||||
if (const MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
|
||||
if (const auto *ME = dyn_cast<MemberExpr>(DeclExp)) {
|
||||
Ctx.SelfArg = ME->getBase();
|
||||
Ctx.SelfArrow = ME->isArrow();
|
||||
} else if (const CXXMemberCallExpr *CE =
|
||||
dyn_cast<CXXMemberCallExpr>(DeclExp)) {
|
||||
} else if (const auto *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {
|
||||
Ctx.SelfArg = CE->getImplicitObjectArgument();
|
||||
Ctx.SelfArrow = isCalleeArrow(CE->getCallee());
|
||||
Ctx.NumArgs = CE->getNumArgs();
|
||||
Ctx.FunArgs = CE->getArgs();
|
||||
} else if (const CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
|
||||
} else if (const auto *CE = dyn_cast<CallExpr>(DeclExp)) {
|
||||
Ctx.NumArgs = CE->getNumArgs();
|
||||
Ctx.FunArgs = CE->getArgs();
|
||||
} else if (const CXXConstructExpr *CE =
|
||||
dyn_cast<CXXConstructExpr>(DeclExp)) {
|
||||
} else if (const auto *CE = dyn_cast<CXXConstructExpr>(DeclExp)) {
|
||||
Ctx.SelfArg = nullptr; // Will be set below
|
||||
Ctx.NumArgs = CE->getNumArgs();
|
||||
Ctx.FunArgs = CE->getArgs();
|
||||
|
@ -147,7 +153,7 @@ CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
|
|||
if (!AttrExp)
|
||||
return CapabilityExpr(nullptr, false);
|
||||
|
||||
if (auto* SLit = dyn_cast<StringLiteral>(AttrExp)) {
|
||||
if (const auto* SLit = dyn_cast<StringLiteral>(AttrExp)) {
|
||||
if (SLit->getString() == StringRef("*"))
|
||||
// The "*" expr is a universal lock, which essentially turns off
|
||||
// checks until it is removed from the lockset.
|
||||
|
@ -158,13 +164,13 @@ CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
|
|||
}
|
||||
|
||||
bool Neg = false;
|
||||
if (auto *OE = dyn_cast<CXXOperatorCallExpr>(AttrExp)) {
|
||||
if (const auto *OE = dyn_cast<CXXOperatorCallExpr>(AttrExp)) {
|
||||
if (OE->getOperator() == OO_Exclaim) {
|
||||
Neg = true;
|
||||
AttrExp = OE->getArg(0);
|
||||
}
|
||||
}
|
||||
else if (auto *UO = dyn_cast<UnaryOperator>(AttrExp)) {
|
||||
else if (const auto *UO = dyn_cast<UnaryOperator>(AttrExp)) {
|
||||
if (UO->getOpcode() == UO_LNot) {
|
||||
Neg = true;
|
||||
AttrExp = UO->getSubExpr();
|
||||
|
@ -179,7 +185,7 @@ CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
|
|||
return CapabilityExpr(nullptr, false);
|
||||
|
||||
// Hack to deal with smart pointers -- strip off top-level pointer casts.
|
||||
if (auto *CE = dyn_cast_or_null<til::Cast>(E)) {
|
||||
if (const auto *CE = dyn_cast_or_null<til::Cast>(E)) {
|
||||
if (CE->castOpcode() == til::CAST_objToPtr)
|
||||
return CapabilityExpr(CE->expr(), Neg);
|
||||
}
|
||||
|
@ -254,7 +260,7 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if (const CastExpr *CE = dyn_cast<CastExpr>(S))
|
||||
if (const auto *CE = dyn_cast<CastExpr>(S))
|
||||
return translateCastExpr(CE, Ctx);
|
||||
|
||||
return new (Arena) til::Undefined(S);
|
||||
|
@ -262,11 +268,11 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
|
|||
|
||||
til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
|
||||
CallingContext *Ctx) {
|
||||
const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
|
||||
const auto *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
|
||||
|
||||
// Function parameters require substitution and/or renaming.
|
||||
if (const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(VD)) {
|
||||
const FunctionDecl *FD =
|
||||
if (const auto *PV = dyn_cast_or_null<ParmVarDecl>(VD)) {
|
||||
const auto *FD =
|
||||
cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
|
||||
unsigned I = PV->getFunctionScopeIndex();
|
||||
|
||||
|
@ -294,13 +300,13 @@ til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
|
|||
}
|
||||
|
||||
static const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) {
|
||||
if (auto *V = dyn_cast<til::Variable>(E))
|
||||
if (const auto *V = dyn_cast<til::Variable>(E))
|
||||
return V->clangDecl();
|
||||
if (auto *Ph = dyn_cast<til::Phi>(E))
|
||||
if (const auto *Ph = dyn_cast<til::Phi>(E))
|
||||
return Ph->clangDecl();
|
||||
if (auto *P = dyn_cast<til::Project>(E))
|
||||
if (const auto *P = dyn_cast<til::Project>(E))
|
||||
return P->clangDecl();
|
||||
if (auto *L = dyn_cast<til::LiteralPtr>(E))
|
||||
if (const auto *L = dyn_cast<til::LiteralPtr>(E))
|
||||
return L->clangDecl();
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -309,7 +315,7 @@ static bool hasCppPointerType(const til::SExpr *E) {
|
|||
auto *VD = getValueDeclFromSExpr(E);
|
||||
if (VD && VD->getType()->isPointerType())
|
||||
return true;
|
||||
if (auto *C = dyn_cast<til::Cast>(E))
|
||||
if (const auto *C = dyn_cast<til::Cast>(E))
|
||||
return C->castOpcode() == til::CAST_objToPtr;
|
||||
|
||||
return false;
|
||||
|
@ -333,9 +339,8 @@ til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
|
|||
til::SExpr *BE = translate(ME->getBase(), Ctx);
|
||||
til::SExpr *E = new (Arena) til::SApply(BE);
|
||||
|
||||
const ValueDecl *D =
|
||||
cast<ValueDecl>(ME->getMemberDecl()->getCanonicalDecl());
|
||||
if (auto *VD = dyn_cast<CXXMethodDecl>(D))
|
||||
const auto *D = cast<ValueDecl>(ME->getMemberDecl()->getCanonicalDecl());
|
||||
if (const auto *VD = dyn_cast<CXXMethodDecl>(D))
|
||||
D = getFirstVirtualDecl(VD);
|
||||
|
||||
til::Project *P = new (Arena) til::Project(E, D);
|
||||
|
@ -356,7 +361,7 @@ til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
|
|||
LRCallCtx.SelfArg = SelfE;
|
||||
LRCallCtx.NumArgs = CE->getNumArgs();
|
||||
LRCallCtx.FunArgs = CE->getArgs();
|
||||
return const_cast<til::SExpr*>(
|
||||
return const_cast<til::SExpr *>(
|
||||
translateAttrExpr(At->getArg(), &LRCallCtx).sexpr());
|
||||
}
|
||||
}
|
||||
|
@ -407,10 +412,10 @@ til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
|
|||
case UO_PreDec:
|
||||
return new (Arena) til::Undefined(UO);
|
||||
|
||||
case UO_AddrOf: {
|
||||
case UO_AddrOf:
|
||||
if (CapabilityExprMode) {
|
||||
// interpret &Graph::mu_ as an existential.
|
||||
if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(UO->getSubExpr())) {
|
||||
if (const auto *DRE = dyn_cast<DeclRefExpr>(UO->getSubExpr())) {
|
||||
if (DRE->getDecl()->isCXXInstanceMember()) {
|
||||
// This is a pointer-to-member expression, e.g. &MyClass::mu_.
|
||||
// We interpret this syntax specially, as a wildcard.
|
||||
|
@ -421,7 +426,6 @@ til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
|
|||
}
|
||||
// otherwise, & is a no-op
|
||||
return translate(UO->getSubExpr(), Ctx);
|
||||
}
|
||||
|
||||
// We treat these as no-ops
|
||||
case UO_Deref:
|
||||
|
@ -470,7 +474,7 @@ til::SExpr *SExprBuilder::translateBinAssign(til::TIL_BinaryOpcode Op,
|
|||
|
||||
const ValueDecl *VD = nullptr;
|
||||
til::SExpr *CV = nullptr;
|
||||
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHS)) {
|
||||
if (const auto *DRE = dyn_cast<DeclRefExpr>(LHS)) {
|
||||
VD = DRE->getDecl();
|
||||
CV = lookupVarDecl(VD);
|
||||
}
|
||||
|
@ -533,10 +537,10 @@ til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
|
|||
|
||||
til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
|
||||
CallingContext *Ctx) {
|
||||
clang::CastKind K = CE->getCastKind();
|
||||
CastKind K = CE->getCastKind();
|
||||
switch (K) {
|
||||
case CK_LValueToRValue: {
|
||||
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
|
||||
if (const auto *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
|
||||
til::SExpr *E0 = lookupVarDecl(DRE->getDecl());
|
||||
if (E0)
|
||||
return E0;
|
||||
|
@ -584,16 +588,15 @@ SExprBuilder::translateAbstractConditionalOperator(
|
|||
til::SExpr *
|
||||
SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
|
||||
DeclGroupRef DGrp = S->getDeclGroup();
|
||||
for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
|
||||
if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) {
|
||||
for (auto I : DGrp) {
|
||||
if (auto *VD = dyn_cast_or_null<VarDecl>(I)) {
|
||||
Expr *E = VD->getInit();
|
||||
til::SExpr* SE = translate(E, Ctx);
|
||||
|
||||
// Add local variables with trivial type to the variable map
|
||||
QualType T = VD->getType();
|
||||
if (T.isTrivialType(VD->getASTContext())) {
|
||||
if (T.isTrivialType(VD->getASTContext()))
|
||||
return addVarDecl(VD, SE);
|
||||
}
|
||||
else {
|
||||
// TODO: add alloca
|
||||
}
|
||||
|
@ -632,7 +635,7 @@ til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) {
|
|||
static void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) {
|
||||
if (!E)
|
||||
return;
|
||||
if (til::Variable *V = dyn_cast<til::Variable>(E)) {
|
||||
if (auto *V = dyn_cast<til::Variable>(E)) {
|
||||
if (!V->clangDecl())
|
||||
V->setClangDecl(VD);
|
||||
}
|
||||
|
@ -672,7 +675,7 @@ void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
|
|||
if (CurrE->block() == CurrentBB) {
|
||||
// We already have a Phi node in the current block,
|
||||
// so just add the new variable to the Phi node.
|
||||
til::Phi *Ph = dyn_cast<til::Phi>(CurrE);
|
||||
auto *Ph = dyn_cast<til::Phi>(CurrE);
|
||||
assert(Ph && "Expecting Phi node.");
|
||||
if (E)
|
||||
Ph->values()[ArgIndex] = E;
|
||||
|
@ -690,9 +693,8 @@ void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
|
|||
Ph->setClangDecl(CurrentLVarMap[i].first);
|
||||
// If E is from a back-edge, or either E or CurrE are incomplete, then
|
||||
// mark this node as incomplete; we may need to remove it later.
|
||||
if (!E || isIncompletePhi(E) || isIncompletePhi(CurrE)) {
|
||||
if (!E || isIncompletePhi(E) || isIncompletePhi(CurrE))
|
||||
Ph->setStatus(til::Phi::PH_Incomplete);
|
||||
}
|
||||
|
||||
// Add Phi node to current block, and update CurrentLVarMap[i]
|
||||
CurrentArguments.push_back(Ph);
|
||||
|
@ -721,7 +723,7 @@ void SExprBuilder::mergeEntryMap(LVarDefinitionMap Map) {
|
|||
unsigned MSz = Map.size();
|
||||
unsigned Sz = std::min(ESz, MSz);
|
||||
|
||||
for (unsigned i=0; i<Sz; ++i) {
|
||||
for (unsigned i = 0; i < Sz; ++i) {
|
||||
if (CurrentLVarMap[i].first != Map[i].first) {
|
||||
// We've reached the end of variables in common.
|
||||
CurrentLVarMap.makeWritable();
|
||||
|
@ -758,9 +760,8 @@ void SExprBuilder::mergeEntryMapBackEdge() {
|
|||
unsigned Sz = CurrentLVarMap.size();
|
||||
unsigned NPreds = CurrentBB->numPredecessors();
|
||||
|
||||
for (unsigned i=0; i < Sz; ++i) {
|
||||
for (unsigned i = 0; i < Sz; ++i)
|
||||
makePhiNodeVar(i, NPreds, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the phi nodes that were initially created for a back edge
|
||||
|
@ -772,7 +773,7 @@ void SExprBuilder::mergePhiNodesBackEdge(const CFGBlock *Blk) {
|
|||
assert(ArgIndex > 0 && ArgIndex < BB->numPredecessors());
|
||||
|
||||
for (til::SExpr *PE : BB->arguments()) {
|
||||
til::Phi *Ph = dyn_cast_or_null<til::Phi>(PE);
|
||||
auto *Ph = dyn_cast_or_null<til::Phi>(PE);
|
||||
assert(Ph && "Expecting Phi Node.");
|
||||
assert(Ph->values()[ArgIndex] == nullptr && "Wrong index for back edge.");
|
||||
|
||||
|
|
Loading…
Reference in New Issue