aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/CFG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Analysis/CFG.cpp')
-rw-r--r--clang/lib/Analysis/CFG.cpp210
1 files changed, 140 insertions, 70 deletions
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 84178ff488a5..ea8b73e81ea2 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -40,7 +40,6 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -56,6 +55,7 @@
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <memory>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -72,6 +72,10 @@ static SourceLocation GetEndLoc(Decl *D) {
/// Returns true on constant values based around a single IntegerLiteral.
/// Allow for use of parentheses, integer casts, and negative signs.
+/// FIXME: it would be good to unify this function with
+/// getIntegerLiteralSubexpressionValue at some point given the similarity
+/// between the functions.
+
static bool IsIntegerLiteralConstantExpr(const Expr *E) {
// Allow parentheses
E = E->IgnoreParens();
@@ -432,8 +436,8 @@ reverse_children::reverse_children(Stmt *S) {
// Note: Fill in this switch with more cases we want to optimize.
case Stmt::InitListExprClass: {
InitListExpr *IE = cast<InitListExpr>(S);
- children = llvm::makeArrayRef(reinterpret_cast<Stmt**>(IE->getInits()),
- IE->getNumInits());
+ children = llvm::ArrayRef(reinterpret_cast<Stmt **>(IE->getInits()),
+ IE->getNumInits());
return;
}
default:
@@ -723,9 +727,9 @@ private:
// hence strict duck-typing.
template <typename CallLikeExpr,
typename = std::enable_if_t<
- std::is_base_of<CallExpr, CallLikeExpr>::value ||
- std::is_base_of<CXXConstructExpr, CallLikeExpr>::value ||
- std::is_base_of<ObjCMessageExpr, CallLikeExpr>::value>>
+ std::is_base_of_v<CallExpr, CallLikeExpr> ||
+ std::is_base_of_v<CXXConstructExpr, CallLikeExpr> ||
+ std::is_base_of_v<ObjCMessageExpr, CallLikeExpr>>>
void findConstructionContextsForArguments(CallLikeExpr *E) {
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
Expr *Arg = E->getArg(i);
@@ -964,15 +968,16 @@ private:
const Expr *LHSExpr = B->getLHS()->IgnoreParens();
const Expr *RHSExpr = B->getRHS()->IgnoreParens();
- const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
+ std::optional<llvm::APInt> IntLiteral1 =
+ getIntegerLiteralSubexpressionValue(LHSExpr);
const Expr *BoolExpr = RHSExpr;
- if (!IntLiteral) {
- IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
+ if (!IntLiteral1) {
+ IntLiteral1 = getIntegerLiteralSubexpressionValue(RHSExpr);
BoolExpr = LHSExpr;
}
- if (!IntLiteral)
+ if (!IntLiteral1)
return TryResult();
const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
@@ -981,26 +986,26 @@ private:
const Expr *LHSExpr2 = BitOp->getLHS()->IgnoreParens();
const Expr *RHSExpr2 = BitOp->getRHS()->IgnoreParens();
- const IntegerLiteral *IntLiteral2 = dyn_cast<IntegerLiteral>(LHSExpr2);
+ std::optional<llvm::APInt> IntLiteral2 =
+ getIntegerLiteralSubexpressionValue(LHSExpr2);
if (!IntLiteral2)
- IntLiteral2 = dyn_cast<IntegerLiteral>(RHSExpr2);
+ IntLiteral2 = getIntegerLiteralSubexpressionValue(RHSExpr2);
if (!IntLiteral2)
return TryResult();
- llvm::APInt L1 = IntLiteral->getValue();
- llvm::APInt L2 = IntLiteral2->getValue();
- if ((BitOp->getOpcode() == BO_And && (L2 & L1) != L1) ||
- (BitOp->getOpcode() == BO_Or && (L2 | L1) != L1)) {
+ if ((BitOp->getOpcode() == BO_And &&
+ (*IntLiteral2 & *IntLiteral1) != *IntLiteral1) ||
+ (BitOp->getOpcode() == BO_Or &&
+ (*IntLiteral2 | *IntLiteral1) != *IntLiteral1)) {
if (BuildOpts.Observer)
BuildOpts.Observer->compareBitwiseEquality(B,
B->getOpcode() != BO_EQ);
- TryResult(B->getOpcode() != BO_EQ);
+ return TryResult(B->getOpcode() != BO_EQ);
}
} else if (BoolExpr->isKnownToHaveBooleanValue()) {
- llvm::APInt IntValue = IntLiteral->getValue();
- if ((IntValue == 1) || (IntValue == 0)) {
+ if ((*IntLiteral1 == 1) || (*IntLiteral1 == 0)) {
return TryResult();
}
return TryResult(B->getOpcode() != BO_EQ);
@@ -1009,6 +1014,47 @@ private:
return TryResult();
}
+ // Helper function to get an APInt from an expression. Supports expressions
+ // which are an IntegerLiteral or a UnaryOperator and returns the value with
+ // all operations performed on it.
+ // FIXME: it would be good to unify this function with
+ // IsIntegerLiteralConstantExpr at some point given the similarity between the
+ // functions.
+ std::optional<llvm::APInt>
+ getIntegerLiteralSubexpressionValue(const Expr *E) {
+
+ // If unary.
+ if (const auto *UnOp = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
+ // Get the sub expression of the unary expression and get the Integer
+ // Literal.
+ const Expr *SubExpr = UnOp->getSubExpr()->IgnoreParens();
+
+ if (const auto *IntLiteral = dyn_cast<IntegerLiteral>(SubExpr)) {
+
+ llvm::APInt Value = IntLiteral->getValue();
+
+ // Perform the operation manually.
+ switch (UnOp->getOpcode()) {
+ case UO_Plus:
+ return Value;
+ case UO_Minus:
+ return -Value;
+ case UO_Not:
+ return ~Value;
+ case UO_LNot:
+ return llvm::APInt(Context->getTypeSize(Context->IntTy), !Value);
+ default:
+ assert(false && "Unexpected unary operator!");
+ return std::nullopt;
+ }
+ }
+ } else if (const auto *IntLiteral =
+ dyn_cast<IntegerLiteral>(E->IgnoreParens()))
+ return IntLiteral->getValue();
+
+ return std::nullopt;
+ }
+
TryResult analyzeLogicOperatorCondition(BinaryOperatorKind Relation,
const llvm::APSInt &Value1,
const llvm::APSInt &Value2) {
@@ -1287,6 +1333,18 @@ private:
} // namespace
+Expr *
+clang::extractElementInitializerFromNestedAILE(const ArrayInitLoopExpr *AILE) {
+ if (!AILE)
+ return nullptr;
+
+ Expr *AILEInit = AILE->getSubExpr();
+ while (const auto *E = dyn_cast<ArrayInitLoopExpr>(AILEInit))
+ AILEInit = E->getSubExpr();
+
+ return AILEInit;
+}
+
inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
const Stmt *stmt) const {
return builder.alwaysAdd(stmt) || kind == AlwaysAdd;
@@ -1616,7 +1674,7 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
}
/// createBlock - Used to lazily create blocks that are connected
-/// to the current (global) succcessor.
+/// to the current (global) successor.
CFGBlock *CFGBuilder::createBlock(bool add_successor) {
CFGBlock *B = cfg->createBlock();
if (add_successor && Succ)
@@ -1661,11 +1719,12 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
if (Init) {
// If the initializer is an ArrayInitLoopExpr, we want to extract the
// initializer, that's used for each element.
- const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
+ auto *AILEInit = extractElementInitializerFromNestedAILE(
+ dyn_cast<ArrayInitLoopExpr>(Init));
findConstructionContexts(
ConstructionContextLayer::create(cfg->getBumpVectorContext(), I),
- AILE ? AILE->getSubExpr() : Init);
+ AILEInit ? AILEInit : Init);
if (HasTemporaries) {
// For expression with temporaries go directly to subexpression to omit
@@ -1891,7 +1950,7 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
// (which is different from the current class) is responsible for
// destroying them.
const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
- if (!CD->hasTrivialDestructor()) {
+ if (CD && !CD->hasTrivialDestructor()) {
autoCreateBlock();
appendBaseDtor(Block, &VI);
}
@@ -1901,7 +1960,7 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
for (const auto &BI : RD->bases()) {
if (!BI.isVirtual()) {
const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
- if (!CD->hasTrivialDestructor()) {
+ if (CD && !CD->hasTrivialDestructor()) {
autoCreateBlock();
appendBaseDtor(Block, &BI);
}
@@ -1912,9 +1971,10 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
for (auto *FI : RD->fields()) {
// Check for constant size array. Set type to array element type.
QualType QT = FI->getType();
- if (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
+ // It may be a multidimensional array.
+ while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
if (AT->getSize() == 0)
- continue;
+ break;
QT = AT->getElementType();
}
@@ -2935,7 +2995,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
// If we bind to a tuple-like type, we iterate over the HoldingVars, and
// create a DeclStmt for each of them.
if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
- for (auto BD : llvm::reverse(DD->bindings())) {
+ for (auto *BD : llvm::reverse(DD->bindings())) {
if (auto *VD = BD->getHoldingVar()) {
DeclGroupRef DG(VD);
DeclStmt *DSNew =
@@ -3014,7 +3074,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scope for C++17 if init-stmt if one exists.
if (Stmt *Init = I->getInit())
@@ -3039,7 +3099,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
CFGBlock *ElseBlock = Succ;
if (Stmt *Else = I->getElse()) {
- SaveAndRestore<CFGBlock*> sv(Succ);
+ SaveAndRestore sv(Succ);
// NULL out Block so that the recursive call to Visit will
// create a new basic block.
@@ -3065,7 +3125,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
{
Stmt *Then = I->getThen();
assert(Then);
- SaveAndRestore<CFGBlock*> sv(Succ);
+ SaveAndRestore sv(Succ);
Block = nullptr;
// If branch is not a compound statement create implicit scope
@@ -3215,7 +3275,7 @@ CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
// Save local scope position because in case of exception variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
addStmt(ES->getBlock());
CFGBlock *SEHExceptBlock = Block;
@@ -3305,13 +3365,13 @@ CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) {
Succ = SEHTrySuccessor;
// Save the current "__try" context.
- SaveAndRestore<CFGBlock *> SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
+ SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
cfg->addTryDispatchBlock(TryTerminatedBlock);
// Save the current value for the __leave target.
// All __leaves should go to the code following the __try
// (FIXME: or if the __try has a __finally, to the __finally.)
- SaveAndRestore<JumpTarget> save_break(SEHLeaveJumpTarget);
+ SaveAndRestore save_break(SEHLeaveJumpTarget);
SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
assert(Terminator->getTryBlock() && "__try must contain a non-NULL body");
@@ -3370,11 +3430,12 @@ CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {
if (Expr *Init = *it) {
// If the initializer is an ArrayInitLoopExpr, we want to extract the
// initializer, that's used for each element.
- const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
+ auto *AILEInit = extractElementInitializerFromNestedAILE(
+ dyn_cast<ArrayInitLoopExpr>(Init));
findConstructionContexts(ConstructionContextLayer::create(
cfg->getBumpVectorContext(), {E, Idx}),
- AILE ? AILE->getSubExpr() : Init);
+ AILEInit ? AILEInit : Init);
CFGBlock *Tmp = Visit(Init);
if (Tmp)
@@ -3433,7 +3494,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scope for init statement and possible condition variable.
// Add destructor for init statement and condition variable.
@@ -3461,7 +3522,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
// Save the current value for the break targets.
// All breaks should go to the code following the loop.
- SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
+ SaveAndRestore save_break(BreakJumpTarget);
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
CFGBlock *BodyBlock = nullptr, *TransitionBlock = nullptr;
@@ -3471,8 +3532,8 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
assert(F->getBody());
// Save the current values for Block, Succ, continue and break targets.
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
- SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget);
+ SaveAndRestore save_Block(Block), save_Succ(Succ);
+ SaveAndRestore save_continue(ContinueJumpTarget);
// Create an empty block to represent the transition block for looping back
// to the head of the loop. If we have increment code, it will
@@ -3527,7 +3588,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
do {
Expr *C = F->getCond();
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Specially handle logical operators, which have a slightly
// more optimal CFG representation.
@@ -3593,7 +3654,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
// If the loop contains initialization, create a new block for those
// statements. This block can also contain statements that precede the loop.
if (Stmt *I = F->getInit()) {
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
ScopePos = LoopBeginScopePos;
Block = createBlock();
return addStmt(I);
@@ -3696,9 +3757,9 @@ CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
// Now create the true branch.
{
// Save the current values for Succ, continue and break targets.
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
- SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
- save_break(BreakJumpTarget);
+ SaveAndRestore save_Block(Block), save_Succ(Succ);
+ SaveAndRestore save_continue(ContinueJumpTarget),
+ save_break(BreakJumpTarget);
// Add an intermediate block between the BodyBlock and the
// EntryConditionBlock to represent the "loop back" transition, for looping
@@ -3792,7 +3853,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scope for possible condition variable.
// Store scope position for continue statement.
@@ -3821,9 +3882,9 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
assert(W->getBody());
// Save the current values for Block, Succ, continue and break targets.
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
- SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
- save_break(BreakJumpTarget);
+ SaveAndRestore save_Block(Block), save_Succ(Succ);
+ SaveAndRestore save_continue(ContinueJumpTarget),
+ save_break(BreakJumpTarget);
// Create an empty block to represent the transition block for looping back
// to the head of the loop.
@@ -3949,7 +4010,7 @@ CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *CS) {
// Save local scope position because in case of exception variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
if (CS->getCatchBody())
addStmt(CS->getCatchBody());
@@ -4044,7 +4105,7 @@ CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *Terminator) {
Succ = TrySuccessor;
// Save the current "try" context.
- SaveAndRestore<CFGBlock *> SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
+ SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
cfg->addTryDispatchBlock(TryTerminatedBlock);
assert(Terminator->getTryBody() && "try must contain a non-NULL body");
@@ -4147,8 +4208,8 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
assert(D->getBody());
// Save the current values for Block, Succ, and continue and break targets
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
- SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
+ SaveAndRestore save_Block(Block), save_Succ(Succ);
+ SaveAndRestore save_continue(ContinueJumpTarget),
save_break(BreakJumpTarget);
// All continues within this loop should go to the condition block
@@ -4266,7 +4327,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scope for C++17 switch init-stmt if one exists.
if (Stmt *Init = Terminator->getInit())
@@ -4286,9 +4347,9 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
} else SwitchSuccessor = Succ;
// Save the current "switch" context.
- SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock),
- save_default(DefaultCaseBlock);
- SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
+ SaveAndRestore save_switch(SwitchTerminatedBlock),
+ save_default(DefaultCaseBlock);
+ SaveAndRestore save_break(BreakJumpTarget);
// Set the "default" case to be the block after the switch statement. If the
// switch statement contains a "default:", this value will be overwritten with
@@ -4311,15 +4372,13 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// For pruning unreachable case statements, save the current state
// for tracking the condition value.
- SaveAndRestore<bool> save_switchExclusivelyCovered(switchExclusivelyCovered,
- false);
+ SaveAndRestore save_switchExclusivelyCovered(switchExclusivelyCovered, false);
// Determine if the switch condition can be explicitly evaluated.
assert(Terminator->getCond() && "switch condition must be non-NULL");
Expr::EvalResult result;
bool b = tryEvaluate(Terminator->getCond(), result);
- SaveAndRestore<Expr::EvalResult*> save_switchCond(switchCond,
- b ? &result : nullptr);
+ SaveAndRestore save_switchCond(switchCond, b ? &result : nullptr);
// If body is not a compound statement create implicit scope
// and add destructors.
@@ -4546,7 +4605,7 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
Succ = TrySuccessor;
// Save the current "try" context.
- SaveAndRestore<CFGBlock *> SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
+ SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
cfg->addTryDispatchBlock(TryTerminatedBlock);
assert(Terminator->getTryBlock() && "try must contain a non-NULL body");
@@ -4560,7 +4619,7 @@ CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
// Save local scope position because in case of exception variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scope for possible exception variable.
// Store scope position. Add implicit destructor.
@@ -4612,7 +4671,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
// }
// Save local scope position before the addition of the implicit variables.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scopes and destructors for range, begin and end variables.
if (Stmt *Range = S->getRangeStmt())
@@ -4637,7 +4696,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
// Save the current value for the break targets.
// All breaks should go to the code following the loop.
- SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
+ SaveAndRestore save_break(BreakJumpTarget);
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
// The block for the __begin != __end expression.
@@ -4670,8 +4729,8 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
assert(S->getBody());
// Save the current values for Block, Succ, and continue targets.
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
- SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget);
+ SaveAndRestore save_Block(Block), save_Succ(Succ);
+ SaveAndRestore save_continue(ContinueJumpTarget);
// Generate increment code in its own basic block. This is the target of
// continue statements.
@@ -5274,8 +5333,19 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
const CXXTemporary *temp = bindExpr->getTemporary();
return temp->getDestructor();
}
+ case CFGElement::MemberDtor: {
+ const FieldDecl *field = castAs<CFGMemberDtor>().getFieldDecl();
+ QualType ty = field->getType();
+
+ while (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
+ ty = arrayType->getElementType();
+ }
+
+ const CXXRecordDecl *classDecl = ty->getAsCXXRecordDecl();
+ assert(classDecl);
+ return classDecl->getDestructor();
+ }
case CFGElement::BaseDtor:
- case CFGElement::MemberDtor:
// Not yet supported.
return nullptr;
}
@@ -5353,7 +5423,7 @@ public:
unsigned j = 1;
for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
BI != BEnd; ++BI, ++j ) {
- if (Optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
const Stmt *stmt= SE->getStmt();
std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
StmtMap[stmt] = P;
@@ -5727,7 +5797,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
OS << " (BindTemporary)";
} else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) {
OS << " (CXXConstructExpr";
- if (Optional<CFGConstructor> CE = E.getAs<CFGConstructor>()) {
+ if (std::optional<CFGConstructor> CE = E.getAs<CFGConstructor>()) {
print_construction_context(OS, Helper, CE->getConstructionContext());
}
OS << ", " << CCE->getType() << ")";
@@ -6102,7 +6172,7 @@ static bool isImmediateSinkBlock(const CFGBlock *Blk) {
// we'd need to carefully handle the case when the throw is being
// immediately caught.
if (llvm::any_of(*Blk, [](const CFGElement &Elm) {
- if (Optional<CFGStmt> StmtElm = Elm.getAs<CFGStmt>())
+ if (std::optional<CFGStmt> StmtElm = Elm.getAs<CFGStmt>())
if (isa<CXXThrowExpr>(StmtElm->getStmt()))
return true;
return false;