diff options
Diffstat (limited to 'clang/lib/Analysis/CFG.cpp')
-rw-r--r-- | clang/lib/Analysis/CFG.cpp | 210 |
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; |