aboutsummaryrefslogtreecommitdiff
path: root/include/clang/Analysis/CFG.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/Analysis/CFG.h')
-rw-r--r--include/clang/Analysis/CFG.h113
1 files changed, 82 insertions, 31 deletions
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index bf81d8358a54..277b2292e5ea 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -1,9 +1,8 @@
//===- CFG.h - Classes for representing and building CFGs -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -495,33 +494,51 @@ private:
/// Represents CFGBlock terminator statement.
///
-/// TemporaryDtorsBranch bit is set to true if the terminator marks a branch
-/// in control flow of destructors of temporaries. In this case terminator
-/// statement is the same statement that branches control flow in evaluation
-/// of matching full expression.
class CFGTerminator {
- llvm::PointerIntPair<Stmt *, 1> Data;
-
public:
- CFGTerminator() = default;
- CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false)
- : Data(S, TemporaryDtorsBranch) {}
-
- Stmt *getStmt() { return Data.getPointer(); }
- const Stmt *getStmt() const { return Data.getPointer(); }
+ enum Kind {
+ /// A branch that corresponds to a statement in the code,
+ /// such as an if-statement.
+ StmtBranch,
+ /// A branch in control flow of destructors of temporaries. In this case
+ /// terminator statement is the same statement that branches control flow
+ /// in evaluation of matching full expression.
+ TemporaryDtorsBranch,
+ /// A shortcut around virtual base initializers. It gets taken when
+ /// virtual base classes have already been initialized by the constructor
+ /// of the most derived class while we're in the base class.
+ VirtualBaseBranch,
- bool isTemporaryDtorsBranch() const { return Data.getInt(); }
+ /// Number of different kinds, for sanity checks. We subtract 1 so that
+ /// to keep receiving compiler warnings when we don't cover all enum values
+ /// in a switch.
+ NumKindsMinusOne = VirtualBaseBranch
+ };
- operator Stmt *() { return getStmt(); }
- operator const Stmt *() const { return getStmt(); }
+private:
+ static constexpr int KindBits = 2;
+ static_assert((1 << KindBits) > NumKindsMinusOne,
+ "Not enough room for kind!");
+ llvm::PointerIntPair<Stmt *, KindBits> Data;
- Stmt *operator->() { return getStmt(); }
- const Stmt *operator->() const { return getStmt(); }
+public:
+ CFGTerminator() { assert(!isValid()); }
+ CFGTerminator(Stmt *S, Kind K = StmtBranch) : Data(S, K) {}
- Stmt &operator*() { return *getStmt(); }
- const Stmt &operator*() const { return *getStmt(); }
+ bool isValid() const { return Data.getOpaqueValue() != nullptr; }
+ Stmt *getStmt() { return Data.getPointer(); }
+ const Stmt *getStmt() const { return Data.getPointer(); }
+ Kind getKind() const { return static_cast<Kind>(Data.getInt()); }
- explicit operator bool() const { return getStmt(); }
+ bool isStmtBranch() const {
+ return getKind() == StmtBranch;
+ }
+ bool isTemporaryDtorsBranch() const {
+ return getKind() == TemporaryDtorsBranch;
+ }
+ bool isVirtualBaseBranch() const {
+ return getKind() == VirtualBaseBranch;
+ }
};
/// Represents a single basic block in a source-level CFG.
@@ -542,11 +559,12 @@ public:
/// Successors: the order in the set of successors is NOT arbitrary. We
/// currently have the following orderings based on the terminator:
///
-/// Terminator Successor Ordering
-/// -----------------------------------------------------
-/// if Then Block; Else Block
-/// ? operator LHS expression; RHS expression
-/// &&, || expression that uses result of && or ||, RHS
+/// Terminator | Successor Ordering
+/// ------------------|------------------------------------
+/// if | Then Block; Else Block
+/// ? operator | LHS expression; RHS expression
+/// logical and/or | expression that consumes the op, RHS
+/// vbase inits | already handled by the most derived class; not yet
///
/// But note that any of that may be NULL in case of optimized-out edges.
class CFGBlock {
@@ -837,8 +855,18 @@ public:
void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
void setHasNoReturnElement() { HasNoReturnElement = true; }
- CFGTerminator getTerminator() { return Terminator; }
- const CFGTerminator getTerminator() const { return Terminator; }
+ CFGTerminator getTerminator() const { return Terminator; }
+
+ Stmt *getTerminatorStmt() { return Terminator.getStmt(); }
+ const Stmt *getTerminatorStmt() const { return Terminator.getStmt(); }
+
+ /// \returns the last (\c rbegin()) condition, e.g. observe the following code
+ /// snippet:
+ /// if (A && B && C)
+ /// A block would be created for \c A, \c B, and \c C. For the latter,
+ /// \c getTerminatorStmt() would retrieve the entire condition, rather than
+ /// C itself, while this method would only return C.
+ const Expr *getLastCondition() const;
Stmt *getTerminatorCondition(bool StripParens = true);
@@ -862,7 +890,11 @@ public:
void dump(const CFG *cfg, const LangOptions &LO, bool ShowColors = false) const;
void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO,
bool ShowColors) const;
+
void printTerminator(raw_ostream &OS, const LangOptions &LO) const;
+ void printTerminatorJson(raw_ostream &Out, const LangOptions &LO,
+ bool AddQuotes) const;
+
void printAsOperand(raw_ostream &OS, bool /*PrintType*/) {
OS << "BB#" << getBlockID();
}
@@ -1027,6 +1059,7 @@ public:
bool AddCXXDefaultInitExprInCtors = false;
bool AddRichCXXConstructors = false;
bool MarkElidedCXXConstructors = false;
+ bool AddVirtualBaseBranches = false;
BuildOptions() = default;
@@ -1173,6 +1206,12 @@ public:
/// implementation needs such an interface.
unsigned size() const { return NumBlockIDs; }
+ /// Returns true if the CFG has no branches. Usually it boils down to the CFG
+ /// having exactly three blocks (entry, the actual code, exit), but sometimes
+ /// more blocks appear due to having control flow that can be fully
+ /// resolved in compile time.
+ bool isLinear() const;
+
//===--------------------------------------------------------------------===//
// CFG Debugging: Pretty-Printing and Visualization.
//===--------------------------------------------------------------------===//
@@ -1246,6 +1285,9 @@ 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;
@@ -1255,6 +1297,9 @@ 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;
@@ -1267,6 +1312,9 @@ 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;
@@ -1279,6 +1327,9 @@ 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* >