aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/include/clang/Analysis/CFG.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/Analysis/CFG.h')
-rw-r--r--contrib/llvm-project/clang/include/clang/Analysis/CFG.h161
1 files changed, 78 insertions, 83 deletions
diff --git a/contrib/llvm-project/clang/include/clang/Analysis/CFG.h b/contrib/llvm-project/clang/include/clang/Analysis/CFG.h
index 43fb523c863a..9f776ca6cc26 100644
--- a/contrib/llvm-project/clang/include/clang/Analysis/CFG.h
+++ b/contrib/llvm-project/clang/include/clang/Analysis/CFG.h
@@ -14,15 +14,14 @@
#ifndef LLVM_CLANG_ANALYSIS_CFG_H
#define LLVM_CLANG_ANALYSIS_CFG_H
-#include "clang/Analysis/Support/BumpVector.h"
-#include "clang/Analysis/ConstructionContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/ConstructionContext.h"
+#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/GraphTraits.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Allocator.h"
@@ -32,6 +31,7 @@
#include <cstddef>
#include <iterator>
#include <memory>
+#include <optional>
#include <vector>
namespace clang {
@@ -75,7 +75,8 @@ public:
MemberDtor,
TemporaryDtor,
DTOR_BEGIN = AutomaticObjectDtor,
- DTOR_END = TemporaryDtor
+ DTOR_END = TemporaryDtor,
+ CleanupFunction,
};
protected:
@@ -103,12 +104,11 @@ public:
return t;
}
- /// Convert to the specified CFGElement type, returning None if this
+ /// Convert to the specified CFGElement type, returning std::nullopt if this
/// CFGElement is not of the desired type.
- template<typename T>
- Optional<T> getAs() const {
+ template <typename T> std::optional<T> getAs() const {
if (!T::isKind(*this))
- return None;
+ return std::nullopt;
T t;
CFGElement& e = t;
e = *this;
@@ -131,7 +131,7 @@ public:
class CFGStmt : public CFGElement {
public:
- explicit CFGStmt(Stmt *S, Kind K = Statement) : CFGElement(K, S) {
+ explicit CFGStmt(const Stmt *S, Kind K = Statement) : CFGElement(K, S) {
assert(isKind(*this));
}
@@ -155,7 +155,8 @@ protected:
/// this is only used by the analyzer's CFG.
class CFGConstructor : public CFGStmt {
public:
- explicit CFGConstructor(CXXConstructExpr *CE, const ConstructionContext *C)
+ explicit CFGConstructor(const CXXConstructExpr *CE,
+ const ConstructionContext *C)
: CFGStmt(CE, Constructor) {
assert(C);
Data2.setPointer(const_cast<ConstructionContext *>(C));
@@ -185,7 +186,7 @@ class CFGCXXRecordTypedCall : public CFGStmt {
public:
/// Returns true when call expression \p CE needs to be represented
/// by CFGCXXRecordTypedCall, as opposed to a regular CFGStmt.
- static bool isCXXRecordTypedCall(Expr *E) {
+ static bool isCXXRecordTypedCall(const Expr *E) {
assert(isa<CallExpr>(E) || isa<ObjCMessageExpr>(E));
// There is no such thing as reference-type expression. If the function
// returns a reference, it'll return the respective lvalue or xvalue
@@ -194,7 +195,7 @@ public:
E->getType().getCanonicalType()->getAsCXXRecordDecl();
}
- explicit CFGCXXRecordTypedCall(Expr *E, const ConstructionContext *C)
+ explicit CFGCXXRecordTypedCall(const Expr *E, const ConstructionContext *C)
: CFGStmt(E, CXXRecordTypedCall) {
assert(isCXXRecordTypedCall(E));
assert(C && (isa<TemporaryObjectConstructionContext>(C) ||
@@ -202,7 +203,8 @@ public:
isa<ReturnedValueConstructionContext>(C) ||
isa<VariableConstructionContext>(C) ||
isa<ConstructorInitializerConstructionContext>(C) ||
- isa<ArgumentConstructionContext>(C)));
+ isa<ArgumentConstructionContext>(C) ||
+ isa<LambdaCaptureConstructionContext>(C)));
Data2.setPointer(const_cast<ConstructionContext *>(C));
}
@@ -224,7 +226,7 @@ private:
/// list.
class CFGInitializer : public CFGElement {
public:
- explicit CFGInitializer(CXXCtorInitializer *initializer)
+ explicit CFGInitializer(const CXXCtorInitializer *initializer)
: CFGElement(Initializer, initializer) {}
CXXCtorInitializer* getInitializer() const {
@@ -263,7 +265,7 @@ private:
};
/// Represents the point where a loop ends.
-/// This element is is only produced when building the CFG for the static
+/// This element is only produced when building the CFG for the static
/// analyzer and hidden behind the 'cfg-loopexit' analyzer config flag.
///
/// Note: a loop exit element can be reached even when the loop body was never
@@ -383,6 +385,32 @@ private:
}
};
+class CFGCleanupFunction final : public CFGElement {
+public:
+ CFGCleanupFunction() = default;
+ CFGCleanupFunction(const VarDecl *VD)
+ : CFGElement(Kind::CleanupFunction, VD) {
+ assert(VD->hasAttr<CleanupAttr>());
+ }
+
+ const VarDecl *getVarDecl() const {
+ return static_cast<VarDecl *>(Data1.getPointer());
+ }
+
+ /// Returns the function to be called when cleaning up the var decl.
+ const FunctionDecl *getFunctionDecl() const {
+ const CleanupAttr *A = getVarDecl()->getAttr<CleanupAttr>();
+ return A->getFunctionDecl();
+ }
+
+private:
+ friend class CFGElement;
+
+ static bool isKind(const CFGElement E) {
+ return E.getKind() == Kind::CleanupFunction;
+ }
+};
+
/// Represents C++ object destructor implicitly generated for automatic object
/// or temporary bound to const reference at the point of leaving its local
/// scope.
@@ -481,7 +509,7 @@ private:
/// expression for temporary object.
class CFGTemporaryDtor : public CFGImplicitDtor {
public:
- CFGTemporaryDtor(CXXBindTemporaryExpr *expr)
+ CFGTemporaryDtor(const CXXBindTemporaryExpr *expr)
: CFGImplicitDtor(TemporaryDtor, expr, nullptr) {}
const CXXBindTemporaryExpr *getBindTemporaryExpr() const {
@@ -515,7 +543,7 @@ public:
/// of the most derived class while we're in the base class.
VirtualBaseBranch,
- /// Number of different kinds, for sanity checks. We subtract 1 so that
+ /// Number of different kinds, for assertions. We subtract 1 so that
/// to keep receiving compiler warnings when we don't cover all enum values
/// in a switch.
NumKindsMinusOne = VirtualBaseBranch
@@ -707,7 +735,7 @@ class CFGBlock {
template <bool IsOtherConst>
ElementRefIterator(ElementRefIterator<true, IsOtherConst> E)
- : ElementRefIterator(E.Parent, llvm::make_reverse_iterator(E.Pos)) {}
+ : ElementRefIterator(E.Parent, std::make_reverse_iterator(E.Pos)) {}
bool operator<(ElementRefIterator Other) const {
assert(Parent == Other.Parent);
@@ -1122,19 +1150,10 @@ public:
Elements.push_back(CFGScopeBegin(VD, S), C);
}
- void prependScopeBegin(const VarDecl *VD, const Stmt *S,
- BumpVectorContext &C) {
- Elements.insert(Elements.rbegin(), 1, CFGScopeBegin(VD, S), C);
- }
-
void appendScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
Elements.push_back(CFGScopeEnd(VD, S), C);
}
- void prependScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
- Elements.insert(Elements.rbegin(), 1, CFGScopeEnd(VD, S), C);
- }
-
void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) {
Elements.push_back(CFGBaseDtor(BS), C);
}
@@ -1151,6 +1170,10 @@ public:
Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
}
+ void appendCleanupFunction(const VarDecl *VD, BumpVectorContext &C) {
+ Elements.push_back(CFGCleanupFunction(VD), C);
+ }
+
void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
Elements.push_back(CFGLifetimeEnds(VD, S), C);
}
@@ -1162,44 +1185,6 @@ public:
void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
Elements.push_back(CFGDeleteDtor(RD, DE), C);
}
-
- // Destructors must be inserted in reversed order. So insertion is in two
- // steps. First we prepare space for some number of elements, then we insert
- // the elements beginning at the last position in prepared space.
- iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt,
- BumpVectorContext &C) {
- return iterator(Elements.insert(I.base(), Cnt,
- CFGAutomaticObjDtor(nullptr, nullptr), C));
- }
- iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) {
- *I = CFGAutomaticObjDtor(VD, S);
- return ++I;
- }
-
- // Scope leaving must be performed in reversed order. So insertion is in two
- // steps. First we prepare space for some number of elements, then we insert
- // the elements beginning at the last position in prepared space.
- iterator beginLifetimeEndsInsert(iterator I, size_t Cnt,
- BumpVectorContext &C) {
- return iterator(
- Elements.insert(I.base(), Cnt, CFGLifetimeEnds(nullptr, nullptr), C));
- }
- iterator insertLifetimeEnds(iterator I, VarDecl *VD, Stmt *S) {
- *I = CFGLifetimeEnds(VD, S);
- return ++I;
- }
-
- // Scope leaving must be performed in reversed order. So insertion is in two
- // steps. First we prepare space for some number of elements, then we insert
- // the elements beginning at the last position in prepared space.
- iterator beginScopeEndInsert(iterator I, size_t Cnt, BumpVectorContext &C) {
- return iterator(
- Elements.insert(I.base(), Cnt, CFGScopeEnd(nullptr, nullptr), C));
- }
- iterator insertScopeEnd(iterator I, VarDecl *VD, Stmt *S) {
- *I = CFGScopeEnd(VD, S);
- return ++I;
- }
};
/// CFGCallback defines methods that should be called when a logical
@@ -1209,6 +1194,7 @@ public:
CFGCallback() = default;
virtual ~CFGCallback() = default;
+ virtual void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
virtual void compareBitwiseEquality(const BinaryOperator *B,
bool isAlwaysTrue) {}
@@ -1229,7 +1215,9 @@ public:
//===--------------------------------------------------------------------===//
class BuildOptions {
- std::bitset<Stmt::lastStmtConstant> alwaysAddMask;
+ // Stmt::lastStmtConstant has the same value as the last Stmt kind,
+ // so make sure we add one to account for this!
+ std::bitset<Stmt::lastStmtConstant + 1> alwaysAddMask;
public:
using ForcedBlkExprs = llvm::DenseMap<const Stmt *, const CFGBlock *>;
@@ -1307,6 +1295,12 @@ public:
iterator nodes_begin() { return iterator(Blocks.begin()); }
iterator nodes_end() { return iterator(Blocks.end()); }
+
+ llvm::iterator_range<iterator> nodes() { return {begin(), end()}; }
+ llvm::iterator_range<const_iterator> const_nodes() const {
+ return {begin(), end()};
+ }
+
const_iterator nodes_begin() const { return const_iterator(Blocks.begin()); }
const_iterator nodes_end() const { return const_iterator(Blocks.end()); }
@@ -1315,6 +1309,13 @@ public:
const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
const_reverse_iterator rend() const { return Blocks.rend(); }
+ llvm::iterator_range<reverse_iterator> reverse_nodes() {
+ return {rbegin(), rend()};
+ }
+ llvm::iterator_range<const_reverse_iterator> const_reverse_nodes() const {
+ return {rbegin(), rend()};
+ }
+
CFGBlock & getEntry() { return *Entry; }
const CFGBlock & getEntry() const { return *Entry; }
CFGBlock & getExit() { return *Exit; }
@@ -1324,6 +1325,7 @@ public:
const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; }
using try_block_iterator = std::vector<const CFGBlock *>::const_iterator;
+ using try_block_range = llvm::iterator_range<try_block_iterator>;
try_block_iterator try_blocks_begin() const {
return TryDispatchBlocks.begin();
@@ -1333,6 +1335,10 @@ public:
return TryDispatchBlocks.end();
}
+ try_block_range try_blocks() const {
+ return try_block_range(try_blocks_begin(), try_blocks_end());
+ }
+
void addTryDispatchBlock(const CFGBlock *block) {
TryDispatchBlocks.push_back(block);
}
@@ -1376,13 +1382,12 @@ public:
// Member templates useful for various batch operations over CFGs.
//===--------------------------------------------------------------------===//
- template <typename CALLBACK>
- void VisitBlockStmts(CALLBACK& O) const {
+ template <typename Callback> void VisitBlockStmts(Callback &O) const {
for (const_iterator I = begin(), E = end(); I != E; ++I)
for (CFGBlock::const_iterator BI = (*I)->begin(), BE = (*I)->end();
BI != BE; ++BI) {
- if (Optional<CFGStmt> stmt = BI->getAs<CFGStmt>())
- O(const_cast<Stmt*>(stmt->getStmt()));
+ if (std::optional<CFGStmt> stmt = BI->getAs<CFGStmt>())
+ O(const_cast<Stmt *>(stmt->getStmt()));
}
}
@@ -1448,6 +1453,8 @@ private:
llvm::DenseMap<const DeclStmt *, const DeclStmt *> SyntheticDeclStmts;
};
+Expr *extractElementInitializerFromNestedAILE(const ArrayInitLoopExpr *AILE);
+
} // namespace clang
//===----------------------------------------------------------------------===//
@@ -1477,9 +1484,6 @@ template <> struct GraphTraits< ::clang::CFGBlock *> {
static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
};
-template <> struct GraphTraits<clang::CFGBlock>
- : GraphTraits<clang::CFGBlock *> {};
-
template <> struct GraphTraits< const ::clang::CFGBlock *> {
using NodeRef = const ::clang::CFGBlock *;
using ChildIteratorType = ::clang::CFGBlock::const_succ_iterator;
@@ -1489,9 +1493,6 @@ template <> struct GraphTraits< const ::clang::CFGBlock *> {
static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
};
-template <> struct GraphTraits<const clang::CFGBlock>
- : GraphTraits<clang::CFGBlock *> {};
-
template <> struct GraphTraits<Inverse< ::clang::CFGBlock *>> {
using NodeRef = ::clang::CFGBlock *;
using ChildIteratorType = ::clang::CFGBlock::const_pred_iterator;
@@ -1504,9 +1505,6 @@ template <> struct GraphTraits<Inverse< ::clang::CFGBlock *>> {
static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
};
-template <> struct GraphTraits<Inverse<clang::CFGBlock>>
- : GraphTraits<clang::CFGBlock *> {};
-
template <> struct GraphTraits<Inverse<const ::clang::CFGBlock *>> {
using NodeRef = const ::clang::CFGBlock *;
using ChildIteratorType = ::clang::CFGBlock::const_pred_iterator;
@@ -1519,9 +1517,6 @@ template <> struct GraphTraits<Inverse<const ::clang::CFGBlock *>> {
static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
};
-template <> struct GraphTraits<const Inverse<clang::CFGBlock>>
- : GraphTraits<clang::CFGBlock *> {};
-
// Traits for: CFG
template <> struct GraphTraits< ::clang::CFG* >