39#include "llvm/ADT/APFloat.h"
40#include "llvm/ADT/APInt.h"
41#include "llvm/ADT/APSInt.h"
42#include "llvm/ADT/ArrayRef.h"
43#include "llvm/ADT/DenseMap.h"
44#include "llvm/ADT/STLExtras.h"
45#include "llvm/ADT/SetVector.h"
46#include "llvm/ADT/SmallPtrSet.h"
47#include "llvm/ADT/SmallVector.h"
48#include "llvm/Support/Allocator.h"
49#include "llvm/Support/Compiler.h"
50#include "llvm/Support/DOTGraphTraits.h"
51#include "llvm/Support/ErrorHandling.h"
52#include "llvm/Support/Format.h"
53#include "llvm/Support/GraphWriter.h"
54#include "llvm/Support/SaveAndRestore.h"
55#include "llvm/Support/raw_ostream.h"
67 if (
VarDecl *VD = dyn_cast<VarDecl>(D))
68 if (
Expr *Ex = VD->getInit())
69 return Ex->getSourceRange().getEnd();
83 if (
const auto *CE = dyn_cast<CastExpr>(E)) {
84 if (CE->getCastKind() != CK_IntegralCast &&
85 CE->getCastKind() != CK_IntegralToFloating)
91 if (
const auto *UO = dyn_cast<UnaryOperator>(E)) {
92 if (UO->getOpcode() != UO_Minus)
116static std::tuple<const Expr *, BinaryOperatorKind, const Expr *>
123 if (Constant ==
nullptr) {
127 else if (Op == BO_GE)
129 else if (Op == BO_LT)
131 else if (Op == BO_LE)
138 return std::make_tuple(MaybeDecl, Op, Constant);
189 enum Kind { NotAlwaysAdd = 0, AlwaysAdd = 1 };
191 AddStmtChoice(Kind a_kind = NotAlwaysAdd) : kind(a_kind) {}
193 bool alwaysAdd(CFGBuilder &builder,
194 const Stmt *
stmt)
const;
198 AddStmtChoice withAlwaysAdd(
bool alwaysAdd)
const {
199 return AddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd);
229 using AutomaticVarsTy = BumpVector<VarDecl *>;
233 class const_iterator {
234 const LocalScope* Scope =
nullptr;
238 unsigned VarIter = 0;
244 const_iterator() =
default;
248 const_iterator(
const LocalScope& S,
unsigned I)
249 : Scope(&S), VarIter(I) {
252 if (VarIter == 0 && Scope)
256 VarDecl *
const* operator->()
const {
257 assert(Scope &&
"Dereferencing invalid iterator is not allowed");
258 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
259 return &Scope->Vars[VarIter - 1];
262 const VarDecl *getFirstVarInScope()
const {
263 assert(Scope &&
"Dereferencing invalid iterator is not allowed");
264 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
265 return Scope->Vars[0];
269 return *this->operator->();
272 const_iterator &operator++() {
276 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
282 const_iterator operator++(
int) {
283 const_iterator P = *
this;
288 bool operator==(
const const_iterator &rhs)
const {
289 return Scope == rhs.Scope && VarIter == rhs.VarIter;
291 bool operator!=(
const const_iterator &rhs)
const {
292 return !(*
this == rhs);
295 explicit operator bool()
const {
296 return *
this != const_iterator();
300 const_iterator shared_parent(const_iterator L);
301 bool pointsToFirstDeclaredVar() {
return VarIter == 1; }
302 bool inSameLocalScope(const_iterator rhs) {
return Scope == rhs.Scope; }
306 BumpVectorContext ctx;
309 AutomaticVarsTy Vars;
317 LocalScope(BumpVectorContext ctx, const_iterator P)
318 : ctx(std::move(ctx)), Vars(this->ctx, 4), Prev(P) {}
321 const_iterator begin()
const {
return const_iterator(*
this, Vars.size()); }
323 void addVar(VarDecl *VD) {
324 Vars.push_back(VD, ctx);
333int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
335 const_iterator F = *
this;
336 while (F.Scope != L.Scope) {
337 assert(F != const_iterator() &&
338 "L iterator is not reachable from F iterator.");
342 D += F.VarIter - L.VarIter;
350LocalScope::const_iterator
351LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
354 if ((*
this == const_iterator()) || (L == const_iterator())) {
355 return const_iterator();
358 const_iterator F = *
this;
359 if (F.inSameLocalScope(L)) {
361 F.VarIter = std::min(F.VarIter, L.VarIter);
365 llvm::SmallDenseMap<const LocalScope *, unsigned, 4> ScopesOfL;
367 ScopesOfL.try_emplace(L.Scope, L.VarIter);
368 if (L == const_iterator())
374 if (
auto LIt = ScopesOfL.find(F.Scope); LIt != ScopesOfL.end()) {
376 F.VarIter = std::min(F.VarIter, LIt->getSecond());
379 assert(F != const_iterator() &&
380 "L iterator is not reachable from F iterator.");
390struct BlockScopePosPair {
391 CFGBlock *block =
nullptr;
392 LocalScope::const_iterator scopePosition;
394 BlockScopePosPair() =
default;
395 BlockScopePosPair(CFGBlock *
b, LocalScope::const_iterator scopePos)
396 : block(
b), scopePosition(scopePos) {}
407 TryResult() =
default;
408 TryResult(
bool b) :
X(
b ? 1 : 0) {}
410 bool isTrue()
const {
return X == 1; }
411 bool isFalse()
const {
return X == 0; }
412 bool isKnown()
const {
return X >= 0; }
423 if (!R1.isKnown() || !R2.isKnown())
425 return TryResult(R1.isTrue() && R2.isTrue());
430class reverse_children {
431 llvm::SmallVector<Stmt *, 12> childrenBuf;
432 ArrayRef<Stmt *> children;
435 reverse_children(Stmt *S, ASTContext &Ctx);
437 using iterator = ArrayRef<Stmt *>::reverse_iterator;
439 iterator begin()
const {
return children.rbegin(); }
440 iterator end()
const {
return children.rend(); }
445reverse_children::reverse_children(Stmt *S, ASTContext &Ctx) {
446 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
447 children = CE->getRawSubExprs();
453 case Stmt::InitListExprClass: {
455 children = llvm::ArrayRef(
reinterpret_cast<Stmt **
>(IE->
getInits()),
460 case Stmt::AttributedStmtClass: {
466 for (
const auto *Attr : AS->getAttrs()) {
467 if (
const auto *AssumeAttr = dyn_cast<CXXAssumeAttr>(Attr)) {
468 Expr *AssumeExpr = AssumeAttr->getAssumption();
470 childrenBuf.push_back(AssumeExpr);
477 llvm::append_range(childrenBuf, AS->children());
478 children = childrenBuf;
486 llvm::append_range(childrenBuf, S->
children());
489 children = childrenBuf;
508 using JumpTarget = BlockScopePosPair;
509 using JumpSource = BlockScopePosPair;
512 std::unique_ptr<CFG> cfg;
515 CFGBlock *
Block =
nullptr;
518 CFGBlock *Succ =
nullptr;
520 JumpTarget ContinueJumpTarget;
521 JumpTarget BreakJumpTarget;
522 JumpTarget SEHLeaveJumpTarget;
523 CFGBlock *SwitchTerminatedBlock =
nullptr;
524 CFGBlock *DefaultCaseBlock =
nullptr;
530 CFGBlock *TryTerminatedBlock =
nullptr;
533 LocalScope::const_iterator ScopePos;
536 using LabelMapTy = llvm::DenseMap<LabelDecl *, JumpTarget>;
541 using BackpatchBlocksTy = std::vector<JumpSource>;
542 BackpatchBlocksTy BackpatchBlocks;
545 using LabelSetTy = llvm::SmallSetVector<LabelDecl *, 8>;
546 LabelSetTy AddressTakenLabels;
551 llvm::DenseMap<Expr *, const ConstructionContextLayer *>
552 ConstructionContextMap;
555 const CFG::BuildOptions &BuildOpts;
558 bool switchExclusivelyCovered =
false;
559 Expr::EvalResult *switchCond =
nullptr;
561 CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry =
nullptr;
562 const Stmt *lastLookup =
nullptr;
566 using CachedBoolEvalsTy = llvm::DenseMap<Expr *, TryResult>;
567 CachedBoolEvalsTy CachedBoolEvals;
570 explicit CFGBuilder(ASTContext *astContext,
571 const CFG::BuildOptions &buildOpts)
572 : Context(astContext), cfg(new CFG()), BuildOpts(buildOpts) {}
575 std::unique_ptr<CFG> buildCFG(
const Decl *D, Stmt *Statement);
577 bool alwaysAdd(
const Stmt *
stmt);
581 CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc);
582 CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
583 CFGBlock *VisitAttributedStmt(AttributedStmt *A, AddStmtChoice asc);
584 CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
585 CFGBlock *VisitBreakStmt(BreakStmt *B);
586 CFGBlock *VisitCallExpr(CallExpr *
C, AddStmtChoice asc);
587 CFGBlock *VisitCaseStmt(CaseStmt *
C);
588 CFGBlock *VisitChooseExpr(ChooseExpr *
C, AddStmtChoice asc);
589 CFGBlock *VisitCompoundStmt(
CompoundStmt *
C,
bool ExternallyDestructed);
590 CFGBlock *VisitConditionalOperator(AbstractConditionalOperator *
C,
592 CFGBlock *VisitContinueStmt(ContinueStmt *
C);
593 CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
595 CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
596 CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *
C, AddStmtChoice asc);
597 CFGBlock *VisitCXXNewExpr(CXXNewExpr *DE, AddStmtChoice asc);
598 CFGBlock *VisitCXXDeleteExpr(CXXDeleteExpr *DE, AddStmtChoice asc);
599 CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
600 CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
602 CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *
C,
604 CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *
T);
605 CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
606 CFGBlock *VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc);
607 CFGBlock *VisitDeclStmt(DeclStmt *DS);
608 CFGBlock *VisitDeclSubExpr(DeclStmt *DS);
609 CFGBlock *VisitDefaultStmt(DefaultStmt *D);
610 CFGBlock *VisitDoStmt(DoStmt *D);
611 CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E,
612 AddStmtChoice asc,
bool ExternallyDestructed);
613 CFGBlock *VisitForStmt(ForStmt *F);
614 CFGBlock *VisitGotoStmt(GotoStmt *G);
615 CFGBlock *VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc);
616 CFGBlock *VisitIfStmt(IfStmt *I);
617 CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
618 CFGBlock *VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc);
619 CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I);
620 CFGBlock *VisitLabelStmt(LabelStmt *L);
621 CFGBlock *VisitBlockExpr(BlockExpr *E, AddStmtChoice asc);
622 CFGBlock *VisitLambdaExpr(
LambdaExpr *E, AddStmtChoice asc);
623 CFGBlock *VisitLogicalOperator(BinaryOperator *B);
624 std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(BinaryOperator *B,
627 CFGBlock *FalseBlock);
628 CFGBlock *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
630 CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc);
631 CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S);
632 CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S);
633 CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S);
634 CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
635 CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S);
636 CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
637 CFGBlock *VisitObjCMessageExpr(ObjCMessageExpr *E, AddStmtChoice asc);
638 CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);
639 CFGBlock *VisitReturnStmt(Stmt *S);
640 CFGBlock *VisitCoroutineSuspendExpr(CoroutineSuspendExpr *S,
642 CFGBlock *VisitSEHExceptStmt(SEHExceptStmt *S);
643 CFGBlock *VisitSEHFinallyStmt(SEHFinallyStmt *S);
644 CFGBlock *VisitSEHLeaveStmt(SEHLeaveStmt *S);
645 CFGBlock *VisitSEHTryStmt(SEHTryStmt *S);
646 CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
647 CFGBlock *VisitSwitchStmt(SwitchStmt *S);
648 CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
650 CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc);
651 CFGBlock *VisitWhileStmt(WhileStmt *W);
652 CFGBlock *VisitArrayInitLoopExpr(ArrayInitLoopExpr *A, AddStmtChoice asc);
654 CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd,
655 bool ExternallyDestructed =
false);
656 CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc);
657 CFGBlock *VisitChildren(Stmt *S);
658 CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc);
659 CFGBlock *VisitOMPExecutableDirective(OMPExecutableDirective *D,
662 void maybeAddScopeBeginForVarDecl(CFGBlock *B,
const VarDecl *VD,
664 if (ScopePos && (VD == ScopePos.getFirstVarInScope()))
665 appendScopeBegin(B, VD, S);
696 struct TempDtorContext {
697 TempDtorContext() =
default;
698 TempDtorContext(TryResult KnownExecuted)
699 : IsConditional(
true), KnownExecuted(KnownExecuted) {}
707 bool needsTempDtorBranch()
const {
708 return IsConditional && !TerminatorExpr;
713 void setDecisionPoint(CFGBlock *S, CXXBindTemporaryExpr *E) {
718 const bool IsConditional =
false;
719 const TryResult KnownExecuted =
true;
720 CFGBlock *Succ =
nullptr;
721 CXXBindTemporaryExpr *TerminatorExpr =
nullptr;
726 CFGBlock *VisitForTemporaryDtors(Stmt *E,
bool ExternallyDestructed,
727 TempDtorContext &Context);
728 CFGBlock *VisitChildrenForTemporaryDtors(Stmt *E,
bool ExternallyDestructed,
729 TempDtorContext &Context);
730 CFGBlock *VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E,
731 bool ExternallyDestructed,
732 TempDtorContext &Context);
733 CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(
734 CXXBindTemporaryExpr *E,
bool ExternallyDestructed, TempDtorContext &Context);
735 CFGBlock *VisitConditionalOperatorForTemporaryDtors(
736 AbstractConditionalOperator *E,
bool ExternallyDestructed,
737 TempDtorContext &Context);
738 void InsertTempDtorDecisionBlock(
const TempDtorContext &Context,
739 CFGBlock *FalseSucc =
nullptr);
749 void consumeConstructionContext(
const ConstructionContextLayer *Layer,
757 void findConstructionContexts(
const ConstructionContextLayer *Layer,
763 template <
typename CallLikeExpr,
764 typename = std::enable_if_t<
765 std::is_base_of_v<CallExpr, CallLikeExpr> ||
766 std::is_base_of_v<CXXConstructExpr, CallLikeExpr> ||
767 std::is_base_of_v<ObjCMessageExpr, CallLikeExpr>>>
768 void findConstructionContextsForArguments(CallLikeExpr *E) {
769 for (
unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
770 Expr *Arg = E->getArg(i);
772 findConstructionContexts(
774 ConstructionContextItem(E, i)),
782 void cleanupConstructionContext(Expr *E);
784 void autoCreateBlock() {
if (!
Block)
Block = createBlock(); }
786 CFGBlock *createBlock(
bool add_successor =
true);
787 CFGBlock *createNoReturnBlock();
789 CFGBlock *addStmt(Stmt *S) {
790 return Visit(S, AddStmtChoice::AlwaysAdd);
793 CFGBlock *addInitializer(CXXCtorInitializer *I);
794 void addLoopExit(
const Stmt *LoopStmt);
795 void addAutomaticObjHandling(LocalScope::const_iterator B,
796 LocalScope::const_iterator E, Stmt *S);
797 void addAutomaticObjDestruction(LocalScope::const_iterator B,
798 LocalScope::const_iterator E, Stmt *S);
799 void addScopeExitHandling(LocalScope::const_iterator B,
800 LocalScope::const_iterator E, Stmt *S);
801 void addImplicitDtorsForDestructor(
const CXXDestructorDecl *DD);
802 void addScopeChangesHandling(LocalScope::const_iterator SrcPos,
803 LocalScope::const_iterator DstPos,
805 CFGBlock *createScopeChangesHandlingBlock(LocalScope::const_iterator SrcPos,
807 LocalScope::const_iterator DstPost,
811 LocalScope* createOrReuseLocalScope(LocalScope* Scope);
813 void addLocalScopeForStmt(Stmt *S);
814 LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS,
815 LocalScope* Scope =
nullptr);
816 LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope =
nullptr);
818 void addLocalScopeAndDtors(Stmt *S);
820 const ConstructionContext *retrieveAndCleanupConstructionContext(Expr *E) {
824 const ConstructionContextLayer *Layer = ConstructionContextMap.lookup(E);
828 cleanupConstructionContext(E);
835 void appendStmt(CFGBlock *B,
const Stmt *S) {
836 if (alwaysAdd(S) && cachedEntry)
837 cachedEntry->second = B;
841 B->
appendStmt(
const_cast<Stmt*
>(S), cfg->getBumpVectorContext());
844 void appendConstructor(CXXConstructExpr *CE) {
846 if (
C &&
C->isNoReturn())
847 Block = createNoReturnBlock();
851 if (
const ConstructionContext *CC =
852 retrieveAndCleanupConstructionContext(CE)) {
853 Block->appendConstructor(CE, CC, cfg->getBumpVectorContext());
858 Block->appendStmt(CE, cfg->getBumpVectorContext());
861 void appendCall(CFGBlock *B, CallExpr *CE) {
862 if (alwaysAdd(CE) && cachedEntry)
863 cachedEntry->second = B;
865 if (
const ConstructionContext *CC =
866 retrieveAndCleanupConstructionContext(CE)) {
872 B->
appendStmt(CE, cfg->getBumpVectorContext());
875 void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
879 void appendNewAllocator(CFGBlock *B, CXXNewExpr *NE) {
883 void appendBaseDtor(CFGBlock *B,
const CXXBaseSpecifier *BS) {
887 void appendMemberDtor(CFGBlock *B, FieldDecl *FD) {
891 void appendObjCMessage(CFGBlock *B, ObjCMessageExpr *ME) {
892 if (alwaysAdd(ME) && cachedEntry)
893 cachedEntry->second = B;
895 if (
const ConstructionContext *CC =
896 retrieveAndCleanupConstructionContext(ME)) {
901 B->
appendStmt(ME, cfg->getBumpVectorContext());
904 void appendTemporaryDtor(CFGBlock *B, CXXBindTemporaryExpr *E) {
908 void appendAutomaticObjDtor(CFGBlock *B, VarDecl *VD, Stmt *S) {
912 void appendCleanupFunction(CFGBlock *B, VarDecl *VD) {
916 void appendLifetimeEnds(CFGBlock *B, VarDecl *VD, Stmt *S) {
920 void appendLoopExit(CFGBlock *B,
const Stmt *LoopStmt) {
924 void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) {
928 void addSuccessor(CFGBlock *B, CFGBlock *S,
bool IsReachable =
true) {
929 B->
addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable),
930 cfg->getBumpVectorContext());
935 void addSuccessor(CFGBlock *B, CFGBlock *ReachableBlock, CFGBlock *AltBlock) {
936 B->
addSuccessor(CFGBlock::AdjacentBlock(ReachableBlock, AltBlock),
937 cfg->getBumpVectorContext());
940 void appendScopeBegin(CFGBlock *B,
const VarDecl *VD,
const Stmt *S) {
945 void appendScopeEnd(CFGBlock *B,
const VarDecl *VD,
const Stmt *S) {
953 TryResult checkIncorrectRelationalOperator(
const BinaryOperator *B) {
957 const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
958 const Expr *BoolExpr = RHSExpr;
959 bool IntFirst =
true;
961 IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
969 llvm::APInt IntValue = IntLiteral->
getValue();
970 if ((IntValue == 1) || (IntValue == 0))
974 !IntValue.isNegative();
977 if (Bok == BO_GT || Bok == BO_GE) {
980 return TryResult(IntFirst == IntLarger);
984 return TryResult(IntFirst != IntLarger);
992 TryResult checkIncorrectEqualityOperator(
const BinaryOperator *B) {
996 std::optional<llvm::APInt> IntLiteral1 =
997 getIntegerLiteralSubexpressionValue(LHSExpr);
998 const Expr *BoolExpr = RHSExpr;
1001 IntLiteral1 = getIntegerLiteralSubexpressionValue(RHSExpr);
1008 const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
1009 if (BitOp && (BitOp->
getOpcode() == BO_And ||
1014 std::optional<llvm::APInt> IntLiteral2 =
1015 getIntegerLiteralSubexpressionValue(LHSExpr2);
1018 IntLiteral2 = getIntegerLiteralSubexpressionValue(RHSExpr2);
1024 (*IntLiteral2 & *IntLiteral1) != *IntLiteral1) ||
1026 (*IntLiteral2 | *IntLiteral1) != *IntLiteral1)) {
1030 return TryResult(B->
getOpcode() != BO_EQ);
1033 if ((*IntLiteral1 == 1) || (*IntLiteral1 == 0)) {
1036 return TryResult(B->
getOpcode() != BO_EQ);
1048 std::optional<llvm::APInt>
1049 getIntegerLiteralSubexpressionValue(
const Expr *E) {
1052 if (
const auto *UnOp = dyn_cast<UnaryOperator>(E->
IgnoreParens())) {
1055 const Expr *SubExpr = UnOp->getSubExpr()->IgnoreParens();
1057 if (
const auto *IntLiteral = dyn_cast<IntegerLiteral>(SubExpr)) {
1062 switch (UnOp->getOpcode()) {
1072 assert(
false &&
"Unexpected unary operator!");
1073 return std::nullopt;
1076 }
else if (
const auto *IntLiteral =
1080 return std::nullopt;
1083 template <
typename APFloatOrInt>
1085 const APFloatOrInt &Value1,
1086 const APFloatOrInt &Value2) {
1091 return TryResult(Value1 == Value2);
1093 return TryResult(Value1 != Value2);
1095 return TryResult(Value1 < Value2);
1097 return TryResult(Value1 <= Value2);
1099 return TryResult(Value1 > Value2);
1101 return TryResult(Value1 >= Value2);
1112 TryResult checkIncorrectLogicOperator(
const BinaryOperator *B) {
1117 auto CheckLogicalOpWithNegatedVariable = [
this, B](
const Expr *E1,
1119 if (
const auto *Negate = dyn_cast<UnaryOperator>(E1)) {
1120 if (Negate->getOpcode() == UO_LNot &&
1122 bool AlwaysTrue = B->
getOpcode() == BO_LOr;
1125 return TryResult(AlwaysTrue);
1131 TryResult
Result = CheckLogicalOpWithNegatedVariable(LHSExpr, RHSExpr);
1134 Result = CheckLogicalOpWithNegatedVariable(RHSExpr, LHSExpr);
1138 const auto *LHS = dyn_cast<BinaryOperator>(LHSExpr);
1139 const auto *RHS = dyn_cast<BinaryOperator>(RHSExpr);
1143 if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
1146 const Expr *DeclExpr1;
1147 const Expr *NumExpr1;
1151 if (!DeclExpr1 || !NumExpr1)
1154 const Expr *DeclExpr2;
1155 const Expr *NumExpr2;
1159 if (!DeclExpr2 || !NumExpr2)
1172 Expr::EvalResult L1Result, L2Result;
1187 auto AnalyzeConditions = [&](
const auto &Values,
1190 bool AlwaysTrue =
true, AlwaysFalse =
true;
1193 bool LHSAlwaysTrue =
true, LHSAlwaysFalse =
true;
1194 bool RHSAlwaysTrue =
true, RHSAlwaysFalse =
true;
1196 for (
const auto &
Value : Values) {
1198 analyzeLogicOperatorCondition(*BO1,
Value, Values[1] );
1200 analyzeLogicOperatorCondition(*BO2,
Value, Values[3] );
1202 if (!Res1.isKnown() || !Res2.isKnown())
1205 const bool IsAnd = B->
getOpcode() == BO_LAnd;
1206 const bool Combine = IsAnd ? (Res1.isTrue() && Res2.isTrue())
1207 : (Res1.isTrue() || Res2.isTrue());
1209 AlwaysTrue &= Combine;
1210 AlwaysFalse &= !Combine;
1212 LHSAlwaysTrue &= Res1.isTrue();
1213 LHSAlwaysFalse &= Res1.isFalse();
1214 RHSAlwaysTrue &= Res2.isTrue();
1215 RHSAlwaysFalse &= Res2.isFalse();
1218 if (AlwaysTrue || AlwaysFalse) {
1219 if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
1220 !RHSAlwaysFalse && BuildOpts.
Observer) {
1223 return TryResult(AlwaysTrue);
1231 llvm::APSInt L1 = L1Result.
Val.
getInt();
1232 llvm::APSInt L2 = L2Result.
Val.
getInt();
1235 if (L1.isSigned() != L2.isSigned() ||
1236 L1.getBitWidth() != L2.getBitWidth())
1241 const llvm::APSInt Values[] = {
1243 llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
1247 ((L1 < L2) ? L1 : L2) +
1248 llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1), L1.isUnsigned()),
1252 llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
1255 return AnalyzeConditions(Values, &BO1, &BO2);
1274 if (llvm::APFloat::opOK !=
1275 L2.convert(L1.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
1278 }
else if (Order < 0)
1280 if (llvm::APFloat::opOK !=
1281 L1.convert(L2.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
1285 llvm::APFloat MidValue = L1;
1286 MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven);
1287 MidValue.divide(llvm::APFloat(MidValue.getSemantics(),
"2.0"),
1288 llvm::APFloat::rmNearestTiesToEven);
1290 const llvm::APFloat Values[] = {
1291 llvm::APFloat::getSmallest(L1.getSemantics(),
true), L1, MidValue, L2,
1292 llvm::APFloat::getLargest(L2.getSemantics(),
false),
1295 return AnalyzeConditions(Values, &BO1, &BO2);
1302 TryResult checkIncorrectBitwiseOrOperator(
const BinaryOperator *B) {
1303 const Expr *LHSConstant =
1305 const Expr *RHSConstant =
1308 if ((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant))
1311 const Expr *Constant = LHSConstant ? LHSConstant : RHSConstant;
1317 if (
Result.Val.getInt() == 0)
1323 return TryResult(
true);
1327 bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) {
1337 TryResult tryEvaluateBool(Expr *S) {
1342 if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
1343 if (Bop->isLogicalOp() || Bop->isEqualityOp()) {
1345 CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S);
1346 if (I != CachedBoolEvals.end())
1350 TryResult
Result = evaluateAsBooleanConditionNoCache(S);
1351 CachedBoolEvals[S] =
Result;
1355 switch (Bop->getOpcode()) {
1363 Expr::EvalResult LHSResult;
1364 if (Bop->getLHS()->EvaluateAsInt(LHSResult, *Context)) {
1365 llvm::APSInt IntVal = LHSResult.
Val.
getInt();
1366 if (!IntVal.getBoolValue()) {
1367 return TryResult(
false);
1370 Expr::EvalResult RHSResult;
1371 if (Bop->getRHS()->EvaluateAsInt(RHSResult, *Context)) {
1372 llvm::APSInt IntVal = RHSResult.
Val.
getInt();
1373 if (!IntVal.getBoolValue()) {
1374 return TryResult(
false);
1383 return evaluateAsBooleanConditionNoCache(S);
1387 TryResult evaluateAsBooleanConditionNoCache(Expr *E) {
1388 if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(E)) {
1389 if (Bop->isLogicalOp()) {
1390 TryResult LHS = tryEvaluateBool(Bop->getLHS());
1391 if (LHS.isKnown()) {
1394 if (LHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1395 return LHS.isTrue();
1397 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1398 if (RHS.isKnown()) {
1399 if (Bop->getOpcode() == BO_LOr)
1400 return LHS.isTrue() || RHS.isTrue();
1402 return LHS.isTrue() && RHS.isTrue();
1405 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1406 if (RHS.isKnown()) {
1409 if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1410 return RHS.isTrue();
1412 TryResult BopRes = checkIncorrectLogicOperator(Bop);
1413 if (BopRes.isKnown())
1414 return BopRes.isTrue();
1419 }
else if (Bop->isEqualityOp()) {
1420 TryResult BopRes = checkIncorrectEqualityOperator(Bop);
1421 if (BopRes.isKnown())
1422 return BopRes.isTrue();
1423 }
else if (Bop->isRelationalOp()) {
1424 TryResult BopRes = checkIncorrectRelationalOperator(Bop);
1425 if (BopRes.isKnown())
1426 return BopRes.isTrue();
1427 }
else if (Bop->getOpcode() == BO_Or) {
1428 TryResult BopRes = checkIncorrectBitwiseOrOperator(Bop);
1429 if (BopRes.isKnown())
1430 return BopRes.isTrue();
1441 bool hasTrivialDestructor(
const VarDecl *VD)
const;
1442 bool needsAutomaticDestruction(
const VarDecl *VD)
const;
1453 while (
const auto *E = dyn_cast<ArrayInitLoopExpr>(AILEInit))
1454 AILEInit = E->getSubExpr();
1459inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
1461 return builder.alwaysAdd(
stmt) || kind == AlwaysAdd;
1464bool CFGBuilder::alwaysAdd(
const Stmt *
stmt) {
1470 if (lastLookup ==
stmt) {
1472 assert(cachedEntry->first ==
stmt);
1485 assert(!cachedEntry);
1489 CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(
stmt);
1490 if (itr == fb->end()) {
1491 cachedEntry =
nullptr;
1495 cachedEntry = &*itr;
1502 while (
const ArrayType *vt = dyn_cast<ArrayType>(t)) {
1504 if (vat->getSizeExpr())
1507 t = vt->getElementType().getTypePtr();
1513void CFGBuilder::consumeConstructionContext(
1514 const ConstructionContextLayer *Layer, Expr *E) {
1517 if (
const ConstructionContextLayer *PreviouslyStoredLayer =
1518 ConstructionContextMap.lookup(E)) {
1519 (void)PreviouslyStoredLayer;
1522 assert(PreviouslyStoredLayer->isStrictlyMoreSpecificThan(Layer) &&
1523 "Already within a different construction context!");
1525 ConstructionContextMap[E] = Layer;
1529void CFGBuilder::findConstructionContexts(
1530 const ConstructionContextLayer *Layer, Stmt *Child) {
1537 auto withExtraLayer = [
this, Layer](
const ConstructionContextItem &Item) {
1542 switch(Child->getStmtClass()) {
1543 case Stmt::CXXConstructExprClass:
1544 case Stmt::CXXTemporaryObjectExprClass: {
1548 findConstructionContexts(withExtraLayer(CE), CE->
getArg(0));
1551 consumeConstructionContext(Layer, CE);
1557 case Stmt::CallExprClass:
1558 case Stmt::CXXMemberCallExprClass:
1559 case Stmt::CXXOperatorCallExprClass:
1560 case Stmt::UserDefinedLiteralClass:
1561 case Stmt::ObjCMessageExprClass: {
1564 consumeConstructionContext(Layer, E);
1567 case Stmt::ExprWithCleanupsClass: {
1569 findConstructionContexts(Layer, Cleanups->getSubExpr());
1572 case Stmt::CXXFunctionalCastExprClass: {
1574 findConstructionContexts(Layer,
Cast->getSubExpr());
1577 case Stmt::ImplicitCastExprClass: {
1580 switch (
Cast->getCastKind()) {
1582 case CK_ConstructorConversion:
1583 findConstructionContexts(Layer,
Cast->getSubExpr());
1590 case Stmt::CXXBindTemporaryExprClass: {
1592 findConstructionContexts(withExtraLayer(BTE), BTE->getSubExpr());
1595 case Stmt::MaterializeTemporaryExprClass: {
1603 findConstructionContexts(withExtraLayer(MTE), MTE->getSubExpr());
1607 case Stmt::ConditionalOperatorClass: {
1615 assert(!CO->getType()->getAsCXXRecordDecl() || CO->isGLValue() ||
1619 findConstructionContexts(Layer, CO->getLHS());
1620 findConstructionContexts(Layer, CO->getRHS());
1623 case Stmt::InitListExprClass: {
1625 if (ILE->isTransparent()) {
1626 findConstructionContexts(Layer, ILE->getInit(0));
1632 case Stmt::ParenExprClass: {
1636 findConstructionContexts(Layer, PE->getSubExpr());
1644void CFGBuilder::cleanupConstructionContext(Expr *E) {
1646 "We should not be managing construction contexts!");
1647 assert(ConstructionContextMap.count(E) &&
1648 "Cannot exit construction context without the context!");
1649 ConstructionContextMap.erase(E);
1657std::unique_ptr<CFG> CFGBuilder::buildCFG(
const Decl *D, Stmt *Statement) {
1665 Succ = createBlock();
1666 assert(Succ == &cfg->getExit());
1670 LocalScope *paramScope =
nullptr;
1671 if (
const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
1672 for (ParmVarDecl *PD : FD->parameters())
1673 paramScope = addLocalScopeForVarDecl(PD, paramScope);
1676 if (
const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
1677 addImplicitDtorsForDestructor(DD);
1680 CFGBlock *B = addStmt(Statement);
1697 if (
const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) {
1698 CFGBlock *VBaseSucc =
nullptr;
1699 for (
auto *I : llvm::reverse(CD->inits())) {
1701 I->isBaseInitializer() && I->isBaseVirtual()) {
1705 VBaseSucc = Succ = B ? B : &cfg->getExit();
1706 Block = createBlock();
1708 B = addInitializer(I);
1718 addSuccessor(B,
Block,
true);
1727 for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
1728 E = BackpatchBlocks.end(); I != E; ++I ) {
1730 CFGBlock *B = I->block;
1732 LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
1735 if (LI == LabelMap.end())
1737 JumpTarget JT = LI->second;
1739 CFGBlock *SuccBlk = createScopeChangesHandlingBlock(
1740 I->scopePosition, B, JT.scopePosition, JT.block);
1741 addSuccessor(B, SuccBlk);
1742 }
else if (
auto *G = dyn_cast<GCCAsmStmt>(B->
getTerminator())) {
1743 CFGBlock *Successor = (I+1)->block;
1744 for (
auto *L : G->labels()) {
1745 LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
1748 if (LI == LabelMap.end())
1750 JumpTarget JT = LI->second;
1752 if (JT.block == Successor)
1754 addSuccessor(B, JT.block);
1761 if (CFGBlock *B = cfg->getIndirectGotoBlock())
1762 for (LabelDecl *LD : AddressTakenLabels) {
1764 LabelMapTy::iterator LI = LabelMap.find(LD);
1768 if (LI == LabelMap.end())
continue;
1770 addSuccessor(B, LI->second.block);
1774 cfg->setEntry(createBlock());
1777 assert(ConstructionContextMap.empty() &&
1778 "Not all construction contexts were cleaned up!");
1780 return std::move(cfg);
1785CFGBlock *CFGBuilder::createBlock(
bool add_successor) {
1786 CFGBlock *B = cfg->createBlock();
1787 if (add_successor && Succ)
1788 addSuccessor(B, Succ);
1795CFGBlock *CFGBuilder::createNoReturnBlock() {
1796 CFGBlock *B = createBlock(
false);
1798 addSuccessor(B, &cfg->getExit(), Succ);
1803CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
1807 bool HasTemporaries =
false;
1817 TempDtorContext Context;
1824 appendInitializer(
Block, I);
1830 dyn_cast<ArrayInitLoopExpr>(
Init));
1832 findConstructionContexts(
1834 AILEInit ? AILEInit :
Init);
1836 if (HasTemporaries) {
1842 if (CXXDefaultInitExpr *
Default = dyn_cast<CXXDefaultInitExpr>(
Init)) {
1848 if (Stmt *Child =
Default->getExpr())
1849 if (CFGBlock *R = Visit(Child))
1863 bool *FoundMTE =
nullptr) {
1870 Init = EWC->getSubExpr();
1876 = dyn_cast<MaterializeTemporaryExpr>(
Init)) {
1877 Init = MTE->getSubExpr();
1884 const Expr *SkippedInit =
Init->skipRValueSubobjectAdjustments();
1885 if (SkippedInit !=
Init) {
1893 return Init->getType();
1898void CFGBuilder::addLoopExit(
const Stmt *LoopStmt){
1902 appendLoopExit(
Block, LoopStmt);
1910void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
1911 LocalScope::const_iterator E,
1921 if (B.inSameLocalScope(E)) {
1922 addAutomaticObjDestruction(B, E, S);
1927 SmallVector<LocalScope::const_iterator, 10> LocalScopeEndMarkers;
1928 LocalScopeEndMarkers.push_back(B);
1929 for (LocalScope::const_iterator I = B; I != E; ++I) {
1930 if (!I.inSameLocalScope(LocalScopeEndMarkers.back()))
1931 LocalScopeEndMarkers.push_back(I);
1933 LocalScopeEndMarkers.push_back(E);
1937 std::reverse(LocalScopeEndMarkers.begin(), LocalScopeEndMarkers.end());
1939 llvm::zip(LocalScopeEndMarkers, llvm::drop_begin(LocalScopeEndMarkers));
1940 for (
auto [E, B] : Pairwise) {
1941 if (!B.inSameLocalScope(E))
1942 addScopeExitHandling(B, E, S);
1943 addAutomaticObjDestruction(B, E, S);
1950void CFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
1951 LocalScope::const_iterator E,
1959 SmallVector<VarDecl *, 10> DeclsNeedDestruction;
1960 DeclsNeedDestruction.reserve(B.distance(E));
1962 for (VarDecl* D : llvm::make_range(B, E))
1963 if (needsAutomaticDestruction(D))
1964 DeclsNeedDestruction.push_back(D);
1966 for (VarDecl *VD : llvm::reverse(DeclsNeedDestruction)) {
1979 Block = createNoReturnBlock();
1988 appendLifetimeEnds(
Block, VD, S);
1990 appendAutomaticObjDtor(
Block, VD, S);
1991 if (VD->
hasAttr<CleanupAttr>())
1992 appendCleanupFunction(
Block, VD);
2001void CFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
2002 LocalScope::const_iterator E, Stmt *S) {
2003 assert(!B.inSameLocalScope(E));
2009 appendScopeEnd(
Block, B.getFirstVarInScope(), S);
2016 SmallVector<VarDecl *, 10> DeclsTrivial;
2017 DeclsTrivial.reserve(B.distance(E));
2022 for (VarDecl* D : llvm::make_range(B, E))
2023 if (!needsAutomaticDestruction(D))
2024 DeclsTrivial.push_back(D);
2026 if (DeclsTrivial.empty())
2030 for (VarDecl *VD : llvm::reverse(DeclsTrivial))
2031 appendLifetimeEnds(
Block, VD, S);
2039void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
2040 LocalScope::const_iterator DstPos,
2042 assert(
Block &&
"Source block should be always crated");
2048 if (SrcPos == DstPos)
2053 LocalScope::const_iterator BasePos = SrcPos.shared_parent(DstPos);
2056 if (BuildOpts.
AddScopes && !DstPos.inSameLocalScope(BasePos)) {
2057 for (LocalScope::const_iterator I = DstPos; I != BasePos; ++I)
2058 if (I.pointsToFirstDeclaredVar())
2059 appendScopeBegin(
Block, *I, S);
2064 addAutomaticObjHandling(SrcPos, BasePos, S);
2072CFGBlock *CFGBuilder::createScopeChangesHandlingBlock(
2073 LocalScope::const_iterator SrcPos, CFGBlock *SrcBlk,
2074 LocalScope::const_iterator DstPos, CFGBlock *DstBlk) {
2075 if (SrcPos == DstPos)
2079 (!BuildOpts.
AddScopes || SrcPos.inSameLocalScope(DstPos)))
2084 SaveAndRestore save_Block(
Block), save_Succ(Succ);
2087 Block = createBlock(
false);
2090 addSuccessor(
Block, DstBlk);
2093 addScopeChangesHandling(SrcPos, DstPos,
Block->getTerminatorStmt());
2095 assert(
Block &&
"There should be at least one scope changing Block");
2101void CFGBuilder::addImplicitDtorsForDestructor(
const CXXDestructorDecl *DD) {
2103 "Can be called only when dtors should be added");
2104 const CXXRecordDecl *RD = DD->
getParent();
2107 for (
const auto &VI : RD->
vbases()) {
2111 const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
2114 appendBaseDtor(
Block, &VI);
2119 for (
const auto &BI : RD->
bases()) {
2120 if (!BI.isVirtual()) {
2121 const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
2124 appendBaseDtor(
Block, &BI);
2132 for (
auto *FI : RD->
fields()) {
2134 QualType QT = FI->getType();
2137 if (AT->isZeroSize())
2139 QT = AT->getElementType();
2145 appendMemberDtor(
Block, FI);
2152LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) {
2155 llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
2156 return new (alloc) LocalScope(BumpVectorContext(alloc), ScopePos);
2161void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
2166 LocalScope *Scope =
nullptr;
2170 for (
auto *BI : CS->body()) {
2171 Stmt *SI = BI->stripLabelLikeStatements();
2172 if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
2173 Scope = addLocalScopeForDeclStmt(DS, Scope);
2181 addLocalScopeForDeclStmt(DS);
2186LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
2187 LocalScope* Scope) {
2192 for (
auto *DI : DS->
decls())
2193 if (VarDecl *VD = dyn_cast<VarDecl>(DI))
2194 Scope = addLocalScopeForVarDecl(VD, Scope);
2198bool CFGBuilder::needsAutomaticDestruction(
const VarDecl *VD)
const {
2199 return !hasTrivialDestructor(VD) || VD->
hasAttr<CleanupAttr>();
2202bool CFGBuilder::hasTrivialDestructor(
const VarDecl *VD)
const {
2223 bool FoundMTE =
false;
2231 if (AT->isZeroSize())
2233 QT = AT->getElementType();
2245LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
2246 LocalScope* Scope) {
2261 !needsAutomaticDestruction(VD)) {
2267 Scope = createOrReuseLocalScope(Scope);
2269 ScopePos = Scope->begin();
2275void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
2276 LocalScope::const_iterator scopeBeginPos = ScopePos;
2277 addLocalScopeForStmt(S);
2278 addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
2284CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
2285 bool ExternallyDestructed) {
2291 if (Expr *E = dyn_cast<Expr>(S))
2292 S = E->IgnoreParens();
2295 if (
auto *D = dyn_cast<OMPExecutableDirective>(S))
2296 return VisitOMPExecutableDirective(D, asc);
2300 return VisitStmt(S, asc);
2302 case Stmt::ImplicitValueInitExprClass:
2305 return VisitStmt(S, asc);
2307 case Stmt::InitListExprClass:
2310 case Stmt::AttributedStmtClass:
2313 case Stmt::AddrLabelExprClass:
2316 case Stmt::BinaryConditionalOperatorClass:
2319 case Stmt::BinaryOperatorClass:
2322 case Stmt::BlockExprClass:
2325 case Stmt::BreakStmtClass:
2328 case Stmt::CallExprClass:
2329 case Stmt::CXXOperatorCallExprClass:
2330 case Stmt::CXXMemberCallExprClass:
2331 case Stmt::UserDefinedLiteralClass:
2334 case Stmt::CaseStmtClass:
2337 case Stmt::ChooseExprClass:
2340 case Stmt::CompoundStmtClass:
2343 case Stmt::ConditionalOperatorClass:
2346 case Stmt::ContinueStmtClass:
2349 case Stmt::CXXCatchStmtClass:
2352 case Stmt::ExprWithCleanupsClass:
2354 asc, ExternallyDestructed);
2356 case Stmt::CXXDefaultArgExprClass:
2357 case Stmt::CXXDefaultInitExprClass:
2366 return VisitStmt(S, asc);
2368 case Stmt::CXXBindTemporaryExprClass:
2371 case Stmt::CXXConstructExprClass:
2374 case Stmt::CXXNewExprClass:
2377 case Stmt::CXXDeleteExprClass:
2380 case Stmt::CXXFunctionalCastExprClass:
2383 case Stmt::CXXTemporaryObjectExprClass:
2386 case Stmt::CXXThrowExprClass:
2389 case Stmt::CXXTryStmtClass:
2392 case Stmt::CXXTypeidExprClass:
2395 case Stmt::CXXForRangeStmtClass:
2398 case Stmt::DeclStmtClass:
2401 case Stmt::DefaultStmtClass:
2404 case Stmt::DoStmtClass:
2407 case Stmt::ForStmtClass:
2410 case Stmt::GotoStmtClass:
2413 case Stmt::GCCAsmStmtClass:
2416 case Stmt::IfStmtClass:
2419 case Stmt::ImplicitCastExprClass:
2422 case Stmt::ConstantExprClass:
2425 case Stmt::IndirectGotoStmtClass:
2428 case Stmt::LabelStmtClass:
2431 case Stmt::LambdaExprClass:
2434 case Stmt::MaterializeTemporaryExprClass:
2438 case Stmt::MemberExprClass:
2441 case Stmt::NullStmtClass:
2444 case Stmt::ObjCAtCatchStmtClass:
2447 case Stmt::ObjCAutoreleasePoolStmtClass:
2450 case Stmt::ObjCAtSynchronizedStmtClass:
2453 case Stmt::ObjCAtThrowStmtClass:
2456 case Stmt::ObjCAtTryStmtClass:
2459 case Stmt::ObjCForCollectionStmtClass:
2462 case Stmt::ObjCMessageExprClass:
2465 case Stmt::OpaqueValueExprClass:
2468 case Stmt::PseudoObjectExprClass:
2471 case Stmt::ReturnStmtClass:
2472 case Stmt::CoreturnStmtClass:
2473 return VisitReturnStmt(S);
2475 case Stmt::CoyieldExprClass:
2476 case Stmt::CoawaitExprClass:
2479 case Stmt::SEHExceptStmtClass:
2482 case Stmt::SEHFinallyStmtClass:
2485 case Stmt::SEHLeaveStmtClass:
2488 case Stmt::SEHTryStmtClass:
2491 case Stmt::UnaryExprOrTypeTraitExprClass:
2495 case Stmt::StmtExprClass:
2498 case Stmt::SwitchStmtClass:
2501 case Stmt::UnaryOperatorClass:
2504 case Stmt::WhileStmtClass:
2507 case Stmt::ArrayInitLoopExprClass:
2512CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
2513 if (asc.alwaysAdd(*
this, S)) {
2515 appendStmt(
Block, S);
2518 return VisitChildren(S);
2522CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
2523 CFGBlock *B =
Block;
2527 reverse_children RChildren(S, *Context);
2528 for (Stmt *Child : RChildren) {
2530 if (CFGBlock *R = Visit(Child))
2536CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) {
2537 if (asc.alwaysAdd(*
this, ILE)) {
2539 appendStmt(
Block, ILE);
2541 CFGBlock *B =
Block;
2543 reverse_children RChildren(ILE, *Context);
2544 for (Stmt *Child : RChildren) {
2547 if (CFGBlock *R = Visit(Child))
2550 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(Child))
2551 if (Stmt *Child = DIE->getExpr())
2552 if (CFGBlock *R = Visit(Child))
2559CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
2560 AddStmtChoice asc) {
2561 AddressTakenLabels.insert(A->
getLabel());
2563 if (asc.alwaysAdd(*
this, A)) {
2565 appendStmt(
Block, A);
2574 "expected fallthrough not to have children");
2575 return isFallthrough;
2582 "expected [[assume]] not to have children");
2583 return hasAssumeAttr;
2586CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
2587 AddStmtChoice asc) {
2597 if (isInterestingAttribute && asc.alwaysAdd(*
this, A)) {
2599 appendStmt(
Block, A);
2602 return VisitChildren(A);
2605CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc) {
2606 if (asc.alwaysAdd(*
this, U)) {
2608 appendStmt(
Block, U);
2614 return Visit(U->
getSubExpr(), AddStmtChoice());
2617CFGBlock *CFGBuilder::VisitLogicalOperator(BinaryOperator *B) {
2618 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2619 appendStmt(ConfluenceBlock, B);
2624 return VisitLogicalOperator(B,
nullptr, ConfluenceBlock,
2625 ConfluenceBlock).first;
2628std::pair<CFGBlock*, CFGBlock*>
2629CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
2631 CFGBlock *TrueBlock,
2632 CFGBlock *FalseBlock) {
2637 CFGBlock *RHSBlock, *ExitBlock;
2640 if (BinaryOperator *B_RHS = dyn_cast<BinaryOperator>(RHS))
2641 if (B_RHS->isLogicalOp()) {
2642 std::tie(RHSBlock, ExitBlock) =
2643 VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
2651 ExitBlock = RHSBlock = createBlock(
false);
2656 TryResult KnownVal = tryEvaluateBool(RHS);
2657 if (!KnownVal.isKnown())
2658 KnownVal = tryEvaluateBool(B);
2661 assert(TrueBlock == FalseBlock);
2662 addSuccessor(RHSBlock, TrueBlock);
2666 addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
2667 addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
2671 RHSBlock = addStmt(RHS);
2676 return std::make_pair(
nullptr,
nullptr);
2681 if (BinaryOperator *B_LHS = dyn_cast<BinaryOperator>(LHS))
2682 if (B_LHS->isLogicalOp()) {
2684 FalseBlock = RHSBlock;
2686 TrueBlock = RHSBlock;
2691 return VisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock);
2696 CFGBlock *LHSBlock = createBlock(
false);
2700 CFGBlock *EntryLHSBlock = addStmt(LHS);
2703 return std::make_pair(
nullptr,
nullptr);
2706 TryResult KnownVal = tryEvaluateBool(LHS);
2710 addSuccessor(LHSBlock, TrueBlock, !KnownVal.isFalse());
2711 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isTrue());
2714 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isFalse());
2715 addSuccessor(LHSBlock, FalseBlock, !KnownVal.isTrue());
2718 return std::make_pair(EntryLHSBlock, ExitBlock);
2721CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
2722 AddStmtChoice asc) {
2725 return VisitLogicalOperator(B);
2729 appendStmt(
Block, B);
2731 return addStmt(B->
getLHS());
2735 if (asc.alwaysAdd(*
this, B)) {
2737 appendStmt(
Block, B);
2740 return Visit(B->
getRHS());
2743 if (asc.alwaysAdd(*
this, B)) {
2745 appendStmt(
Block, B);
2751 CFGBlock *RBlock = Visit(B->
getRHS());
2752 CFGBlock *LBlock = Visit(B->
getLHS());
2756 return (LBlock ? LBlock : RBlock);
2759CFGBlock *CFGBuilder::VisitNoRecurse(Expr *E, AddStmtChoice asc) {
2760 if (asc.alwaysAdd(*
this, E)) {
2762 appendStmt(
Block, E);
2767CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
2774 Block = createBlock(
false);
2775 Block->setTerminator(B);
2779 if (BreakJumpTarget.block) {
2780 addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
2781 addSuccessor(
Block, BreakJumpTarget.block);
2806 if (BuiltinID != Builtin::BI__assume &&
2807 BuiltinID != Builtin::BI__builtin_assume)
2813CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *
C, AddStmtChoice asc) {
2815 QualType calleeType =
C->getCallee()->getType();
2821 if (!boundType.
isNull()) calleeType = boundType;
2827 bool AddEHEdge =
false;
2837 bool OmitArguments =
false;
2839 if (FunctionDecl *FD =
C->getDirectCallee()) {
2844 if (!FD->isVariadic())
2845 findConstructionContextsForArguments(
C);
2847 if (FD->isNoReturn() || FD->isAnalyzerNoReturn() ||
2848 C->isBuiltinAssumeFalse(*Context))
2850 if (FD->
hasAttr<NoThrowAttr>())
2853 FD->getBuiltinID() == Builtin::BI__builtin_object_size ||
2854 FD->getBuiltinID() == Builtin::BI__builtin_dynamic_object_size)
2855 OmitArguments =
true;
2858 if (!
CanThrow(
C->getCallee(), *Context))
2861 if (OmitArguments) {
2862 assert(!NoReturn &&
"noreturn calls with unevaluated args not implemented");
2863 assert(!AddEHEdge &&
"EH calls with unevaluated args not implemented");
2866 return Visit(
C->getCallee());
2869 if (!NoReturn && !AddEHEdge) {
2873 return VisitChildren(
C);
2883 Block = createNoReturnBlock();
2885 Block = createBlock();
2891 if (TryTerminatedBlock)
2892 addSuccessor(
Block, TryTerminatedBlock);
2894 addSuccessor(
Block, &cfg->getExit());
2897 return VisitChildren(
C);
2900CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *
C,
2901 AddStmtChoice asc) {
2902 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2903 appendStmt(ConfluenceBlock,
C);
2907 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2908 Succ = ConfluenceBlock;
2910 CFGBlock *LHSBlock = Visit(
C->getLHS(), alwaysAdd);
2914 Succ = ConfluenceBlock;
2916 CFGBlock *RHSBlock = Visit(
C->getRHS(), alwaysAdd);
2920 Block = createBlock(
false);
2922 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2923 addSuccessor(
Block, KnownVal.isFalse() ?
nullptr : LHSBlock);
2924 addSuccessor(
Block, KnownVal.isTrue() ?
nullptr : RHSBlock);
2926 return addStmt(
C->getCond());
2930 bool ExternallyDestructed) {
2931 LocalScope::const_iterator scopeBeginPos = ScopePos;
2932 addLocalScopeForStmt(
C);
2937 addAutomaticObjHandling(ScopePos, scopeBeginPos,
C);
2940 CFGBlock *LastBlock =
Block;
2942 for (Stmt *S : llvm::reverse(
C->body())) {
2945 CFGBlock *newBlock = Visit(S, AddStmtChoice::AlwaysAdd,
2946 ExternallyDestructed);
2949 LastBlock = newBlock;
2954 ExternallyDestructed =
false;
2960CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *
C,
2961 AddStmtChoice asc) {
2962 const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(
C);
2963 const OpaqueValueExpr *opaqueValue = (BCO ? BCO->
getOpaqueValue() :
nullptr);
2967 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2968 appendStmt(ConfluenceBlock,
C);
2972 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2978 Succ = ConfluenceBlock;
2980 CFGBlock *LHSBlock =
nullptr;
2981 const Expr *trueExpr =
C->getTrueExpr();
2982 if (trueExpr != opaqueValue) {
2983 LHSBlock = Visit(
C->getTrueExpr(), alwaysAdd);
2989 LHSBlock = ConfluenceBlock;
2992 Succ = ConfluenceBlock;
2993 CFGBlock *RHSBlock = Visit(
C->getFalseExpr(), alwaysAdd);
2998 if (BinaryOperator *
Cond =
2999 dyn_cast<BinaryOperator>(
C->getCond()->IgnoreParens()))
3000 if (
Cond->isLogicalOp())
3001 return VisitLogicalOperator(
Cond,
C, LHSBlock, RHSBlock).first;
3004 Block = createBlock(
false);
3007 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
3008 addSuccessor(
Block, LHSBlock, !KnownVal.isFalse());
3009 addSuccessor(
Block, RHSBlock, !KnownVal.isTrue());
3011 Expr *condExpr =
C->getCond();
3016 if (condExpr != opaqueValue)
3024 return addStmt(condExpr);
3027CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
3035 return VisitDeclSubExpr(DS);
3037 CFGBlock *B =
nullptr;
3046 DeclGroupRef DG(*I);
3049 cfg->addSyntheticDeclStmt(DSNew, DS);
3052 B = VisitDeclSubExpr(DSNew);
3060CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
3061 assert(DS->
isSingleDecl() &&
"Can handle single declarations only.");
3063 if (
const auto *TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl())) {
3065 const Type *
T = TND->getUnderlyingType().getTypePtr();
3070 appendStmt(
Block, DS);
3072 CFGBlock *LastBlock =
Block;
3073 for (
const VariableArrayType *VA =
FindVA(
T); VA !=
nullptr;
3074 VA =
FindVA(VA->getElementType().getTypePtr())) {
3075 if (CFGBlock *NewBlock = addStmt(VA->getSizeExpr()))
3076 LastBlock = NewBlock;
3089 bool HasTemporaries =
false;
3092 CFGBlock *blockAfterStaticInit =
nullptr;
3103 blockAfterStaticInit = Succ;
3114 TempDtorContext Context;
3122 if (
const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
3123 for (
auto *BD : llvm::reverse(DD->bindings())) {
3124 if (
auto *VD = BD->getHoldingVar()) {
3125 DeclGroupRef DG(VD);
3128 cfg->addSyntheticDeclStmt(DSNew, DS);
3129 Block = VisitDeclSubExpr(DSNew);
3135 appendStmt(
Block, DS);
3139 const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(
Init);
3141 findConstructionContexts(
3143 AILE ? AILE->getSubExpr() :
Init);
3148 CFGBlock *LastBlock =
Block;
3151 if (HasTemporaries) {
3155 if (CFGBlock *newBlock = Visit(EC->
getSubExpr()))
3156 LastBlock = newBlock;
3159 if (CFGBlock *newBlock = Visit(
Init))
3160 LastBlock = newBlock;
3168 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr())) {
3169 if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
3170 LastBlock = newBlock;
3173 maybeAddScopeBeginForVarDecl(
Block, VD, DS);
3176 if (ScopePos && VD == *ScopePos)
3179 CFGBlock *B = LastBlock;
3180 if (blockAfterStaticInit) {
3182 Block = createBlock(
false);
3183 Block->setTerminator(DS);
3184 addSuccessor(
Block, blockAfterStaticInit);
3185 addSuccessor(
Block, B);
3192CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
3202 SaveAndRestore save_scope_pos(ScopePos);
3206 addLocalScopeForStmt(
Init);
3211 addLocalScopeForVarDecl(VD);
3213 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
3224 CFGBlock *ElseBlock = Succ;
3226 if (Stmt *Else = I->
getElse()) {
3227 SaveAndRestore sv(Succ);
3236 addLocalScopeAndDtors(Else);
3238 ElseBlock = addStmt(Else);
3241 ElseBlock = sv.get();
3249 CFGBlock *ThenBlock;
3253 SaveAndRestore sv(Succ);
3259 addLocalScopeAndDtors(Then);
3261 ThenBlock = addStmt(Then);
3267 ThenBlock = createBlock(
false);
3268 addSuccessor(ThenBlock, sv.get());
3282 BinaryOperator *
Cond =
3286 CFGBlock *LastBlock;
3288 LastBlock = VisitLogicalOperator(
Cond, I, ThenBlock, ElseBlock).first;
3291 Block = createBlock(
false);
3294 Block->setTerminator(I);
3299 KnownVal = tryEvaluateBool(I->
getCond());
3303 addSuccessor(
Block, ThenBlock, !KnownVal.isFalse());
3304 addSuccessor(
Block, ElseBlock, !KnownVal.isTrue());
3312 LastBlock = addStmt(I->
getCond());
3318 LastBlock = addStmt(
const_cast<DeclStmt *
>(DS));
3325 LastBlock = addStmt(
Init);
3331CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {
3341 Block = createBlock(
false);
3343 addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), S);
3345 if (
auto *R = dyn_cast<ReturnStmt>(S))
3346 findConstructionContexts(
3352 if (!
Block->hasNoReturnElement())
3353 addSuccessor(
Block, &cfg->getExit());
3356 appendStmt(
Block, S);
3359 if (ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
3360 if (Expr *O = RS->getRetValue())
3361 return Visit(O, AddStmtChoice::AlwaysAdd,
true);
3373 if (CFGBlock *R = Visit(RV))
3379CFGBlock *CFGBuilder::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E,
3380 AddStmtChoice asc) {
3384 if (asc.alwaysAdd(*
this, E)) {
3386 appendStmt(
Block, E);
3388 CFGBlock *B =
Block;
3400CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
3406 SaveAndRestore save_scope_pos(ScopePos);
3409 CFGBlock *SEHExceptBlock =
Block;
3410 if (!SEHExceptBlock)
3411 SEHExceptBlock = createBlock();
3413 appendStmt(SEHExceptBlock, ES);
3425 return SEHExceptBlock;
3428CFGBlock *CFGBuilder::VisitSEHFinallyStmt(SEHFinallyStmt *FS) {
3429 return VisitCompoundStmt(FS->
getBlock(),
false);
3432CFGBlock *CFGBuilder::VisitSEHLeaveStmt(SEHLeaveStmt *LS) {
3439 Block = createBlock(
false);
3440 Block->setTerminator(LS);
3444 if (SEHLeaveJumpTarget.block) {
3445 addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS);
3446 addSuccessor(
Block, SEHLeaveJumpTarget.block);
3453CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) {
3456 CFGBlock *SEHTrySuccessor =
nullptr;
3461 SEHTrySuccessor =
Block;
3462 }
else SEHTrySuccessor = Succ;
3468 CFGBlock *PrevSEHTryTerminatedBlock = TryTerminatedBlock;
3471 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
3478 Succ = SEHTrySuccessor;
3480 CFGBlock *ExceptBlock = VisitSEHExceptStmt(Except);
3485 addSuccessor(NewTryTerminatedBlock, ExceptBlock);
3487 if (PrevSEHTryTerminatedBlock)
3488 addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock);
3490 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
3493 Succ = SEHTrySuccessor;
3496 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
3497 cfg->addTryDispatchBlock(TryTerminatedBlock);
3502 SaveAndRestore save_break(SEHLeaveJumpTarget);
3503 SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
3505 assert(Terminator->
getTryBlock() &&
"__try must contain a non-NULL body");
3510CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
3513 CFGBlock *LabelBlock =
Block;
3516 LabelBlock = createBlock();
3518 assert(!LabelMap.contains(L->
getDecl()) &&
"label already in map");
3519 LabelMap[L->
getDecl()] = JumpTarget(LabelBlock, ScopePos);
3538CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
3539 CFGBlock *LastBlock = VisitNoRecurse(E, asc);
3541 if (Expr *CopyExpr = CI.getCopyExpr()) {
3542 CFGBlock *Tmp = Visit(CopyExpr);
3550CFGBlock *CFGBuilder::VisitLambdaExpr(
LambdaExpr *E, AddStmtChoice asc) {
3551 CFGBlock *LastBlock = VisitNoRecurse(E, asc);
3556 it != et; ++it, ++Idx) {
3557 if (Expr *
Init = *it) {
3561 dyn_cast<ArrayInitLoopExpr>(
Init));
3564 cfg->getBumpVectorContext(), {E, Idx}),
3565 AILEInit ? AILEInit :
Init);
3567 CFGBlock *Tmp = Visit(
Init);
3575CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
3579 Block = createBlock(
false);
3580 Block->setTerminator(G);
3583 LabelMapTy::iterator I = LabelMap.find(G->
getLabel());
3585 if (I == LabelMap.end())
3587 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3589 JumpTarget JT = I->second;
3590 addSuccessor(
Block, JT.block);
3591 addScopeChangesHandling(ScopePos, JT.scopePosition, G);
3597CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) {
3602 return VisitStmt(G, asc);
3609 Block = createBlock();
3610 Block->setTerminator(G);
3612 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3615 BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
3616 return VisitChildren(G);
3619CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
3620 CFGBlock *LoopSuccessor =
nullptr;
3624 SaveAndRestore save_scope_pos(ScopePos);
3630 addLocalScopeForStmt(
Init);
3631 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3634 addLocalScopeForVarDecl(VD);
3635 LocalScope::const_iterator ContinueScopePos = ScopePos;
3637 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
3646 LoopSuccessor =
Block;
3648 LoopSuccessor = Succ;
3652 SaveAndRestore save_break(BreakJumpTarget);
3653 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3655 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3662 SaveAndRestore save_Block(
Block), save_Succ(Succ);
3663 SaveAndRestore save_continue(ContinueJumpTarget);
3668 Block = Succ = TransitionBlock = createBlock(
false);
3669 TransitionBlock->setLoopTarget(F);
3674 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
3676 if (Stmt *I = F->
getInc()) {
3684 assert(
Block == Succ);
3692 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
3693 ContinueJumpTarget.block->setLoopTarget(F);
3699 addLocalScopeAndDtors(F->
getBody());
3703 BodyBlock = addStmt(F->
getBody());
3708 BodyBlock = ContinueJumpTarget.block;
3717 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3721 SaveAndRestore save_scope_pos(ScopePos);
3725 if (BinaryOperator *
Cond =
3726 dyn_cast_or_null<BinaryOperator>(
C ?
C->IgnoreParens() :
nullptr))
3727 if (
Cond->isLogicalOp()) {
3728 std::tie(EntryConditionBlock, ExitConditionBlock) =
3729 VisitLogicalOperator(
Cond, F, BodyBlock, LoopSuccessor);
3734 EntryConditionBlock = ExitConditionBlock = createBlock(
false);
3735 ExitConditionBlock->setTerminator(F);
3738 TryResult KnownVal(
true);
3744 Block = ExitConditionBlock;
3745 EntryConditionBlock = addStmt(
C);
3754 findConstructionContexts(
3757 appendStmt(
Block, DS);
3758 EntryConditionBlock = addStmt(
Init);
3759 assert(
Block == EntryConditionBlock);
3760 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3764 if (
Block && badCFG)
3767 KnownVal = tryEvaluateBool(
C);
3771 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
3774 addSuccessor(ExitConditionBlock,
3775 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
3779 addSuccessor(TransitionBlock, EntryConditionBlock);
3782 Succ = EntryConditionBlock;
3787 SaveAndRestore save_scope_pos(ScopePos);
3788 ScopePos = LoopBeginScopePos;
3789 Block = createBlock();
3796 Succ = EntryConditionBlock;
3797 return EntryConditionBlock;
3801CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
3802 AddStmtChoice asc) {
3803 findConstructionContexts(
3807 return VisitStmt(MTE, asc);
3810CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
3811 if (asc.alwaysAdd(*
this, M)) {
3813 appendStmt(
Block, M);
3818CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
3850 CFGBlock *LoopSuccessor =
nullptr;
3855 LoopSuccessor =
Block;
3858 LoopSuccessor = Succ;
3861 CFGBlock *ExitConditionBlock = createBlock(
false);
3869 appendStmt(ExitConditionBlock, S);
3870 Block = ExitConditionBlock;
3875 CFGBlock *EntryConditionBlock = Visit(S->
getElement(),
3876 AddStmtChoice::NotAlwaysAdd);
3885 Succ = EntryConditionBlock;
3890 SaveAndRestore save_Block(
Block), save_Succ(Succ);
3891 SaveAndRestore save_continue(ContinueJumpTarget),
3892 save_break(BreakJumpTarget);
3897 CFGBlock *LoopBackBlock =
nullptr;
3898 Succ = LoopBackBlock = createBlock();
3901 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3902 ContinueJumpTarget = JumpTarget(Succ, ScopePos);
3904 CFGBlock *BodyBlock = addStmt(S->
getBody());
3907 BodyBlock = ContinueJumpTarget.block;
3914 addSuccessor(ExitConditionBlock, BodyBlock);
3919 addSuccessor(ExitConditionBlock, LoopSuccessor);
3922 Block = createBlock();
3926CFGBlock *CFGBuilder::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
3932CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
3950 appendStmt(
Block, S);
3956CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
3960 appendStmt(
Block, E);
3962 CFGBlock *lastBlock =
Block;
3971 if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic))
3972 Semantic = OVE->getSourceExpr();
3974 if (CFGBlock *B = Visit(Semantic))
3981CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
3982 CFGBlock *LoopSuccessor =
nullptr;
3986 SaveAndRestore save_scope_pos(ScopePos);
3990 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3992 addLocalScopeForVarDecl(VD);
3993 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4002 LoopSuccessor =
Block;
4005 LoopSuccessor = Succ;
4008 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
4015 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4016 SaveAndRestore save_continue(ContinueJumpTarget),
4017 save_break(BreakJumpTarget);
4021 Succ = TransitionBlock = createBlock(
false);
4022 TransitionBlock->setLoopTarget(W);
4023 ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
4026 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4029 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4034 addLocalScopeAndDtors(W->
getBody());
4037 BodyBlock = addStmt(W->
getBody());
4040 BodyBlock = ContinueJumpTarget.block;
4041 else if (
Block && badCFG)
4048 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
4055 if (BinaryOperator *
Cond = dyn_cast<BinaryOperator>(
C->IgnoreParens()))
4056 if (
Cond->isLogicalOp()) {
4057 std::tie(EntryConditionBlock, ExitConditionBlock) =
4058 VisitLogicalOperator(
Cond, W, BodyBlock, LoopSuccessor);
4063 ExitConditionBlock = createBlock(
false);
4069 Block = ExitConditionBlock;
4070 Block = EntryConditionBlock = addStmt(
C);
4079 findConstructionContexts(
4081 const_cast<DeclStmt *
>(DS)),
4083 appendStmt(
Block, DS);
4084 EntryConditionBlock = addStmt(
Init);
4085 assert(
Block == EntryConditionBlock);
4086 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
4090 if (
Block && badCFG)
4094 const TryResult& KnownVal = tryEvaluateBool(
C);
4097 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
4100 addSuccessor(ExitConditionBlock,
4101 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4105 addSuccessor(TransitionBlock, EntryConditionBlock);
4112 Succ = EntryConditionBlock;
4113 return EntryConditionBlock;
4116CFGBlock *CFGBuilder::VisitArrayInitLoopExpr(ArrayInitLoopExpr *A,
4117 AddStmtChoice asc) {
4118 if (asc.alwaysAdd(*
this, A)) {
4120 appendStmt(
Block, A);
4123 CFGBlock *B =
Block;
4129 assert(OVE &&
"ArrayInitLoopExpr->getCommonExpr() should be wrapped in an "
4130 "OpaqueValueExpr!");
4131 if (CFGBlock *R = Visit(OVE->getSourceExpr()))
4137CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *CS) {
4143 SaveAndRestore save_scope_pos(ScopePos);
4148 CFGBlock *CatchBlock =
Block;
4150 CatchBlock = createBlock();
4152 appendStmt(CatchBlock, CS);
4167CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
4173 Block = createBlock(
false);
4175 if (TryTerminatedBlock)
4177 addSuccessor(
Block, TryTerminatedBlock);
4180 addSuccessor(
Block, &cfg->getExit());
4184 return VisitStmt(S, AddStmtChoice::AlwaysAdd);
4187CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *Terminator) {
4190 CFGBlock *TrySuccessor =
nullptr;
4195 TrySuccessor =
Block;
4197 TrySuccessor = Succ;
4203 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4206 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4210 bool HasCatchAll =
false;
4211 for (ObjCAtCatchStmt *CS : Terminator->
catch_stmts()) {
4213 Succ = TrySuccessor;
4218 CFGBlock *CatchBlock = VisitObjCAtCatchStmt(CS);
4223 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4228 if (PrevTryTerminatedBlock)
4229 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4231 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4235 Succ = TrySuccessor;
4238 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4239 cfg->addTryDispatchBlock(TryTerminatedBlock);
4241 assert(Terminator->
getTryBody() &&
"try must contain a non-NULL body");
4246CFGBlock *CFGBuilder::VisitObjCMessageExpr(ObjCMessageExpr *ME,
4247 AddStmtChoice asc) {
4248 findConstructionContextsForArguments(ME);
4251 appendObjCMessage(
Block, ME);
4253 return VisitChildren(ME);
4256CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *
T) {
4262 Block = createBlock(
false);
4264 if (TryTerminatedBlock)
4266 addSuccessor(
Block, TryTerminatedBlock);
4269 addSuccessor(
Block, &cfg->getExit());
4273 return VisitStmt(
T, AddStmtChoice::AlwaysAdd);
4276CFGBlock *CFGBuilder::VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc) {
4277 if (asc.alwaysAdd(*
this, S)) {
4279 appendStmt(
Block, S);
4289 return VisitChildren(S);
4295CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
4296 CFGBlock *LoopSuccessor =
nullptr;
4305 LoopSuccessor =
Block;
4307 LoopSuccessor = Succ;
4312 CFGBlock *ExitConditionBlock = createBlock(
false);
4313 CFGBlock *EntryConditionBlock = ExitConditionBlock;
4321 Block = ExitConditionBlock;
4322 EntryConditionBlock = addStmt(
C);
4330 Succ = EntryConditionBlock;
4333 const TryResult &KnownVal = tryEvaluateBool(D->
getCond());
4336 CFGBlock *BodyBlock =
nullptr;
4341 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4342 SaveAndRestore save_continue(ContinueJumpTarget),
4343 save_break(BreakJumpTarget);
4346 ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
4349 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4357 addLocalScopeAndDtors(D->
getBody());
4360 BodyBlock = addStmt(D->
getBody());
4363 BodyBlock = EntryConditionBlock;
4376 CFGBlock *LoopBackBlock = createBlock();
4379 if (!KnownVal.isFalse())
4381 addSuccessor(ExitConditionBlock, LoopBackBlock);
4383 addSuccessor(ExitConditionBlock,
nullptr);
4388 addSuccessor(ExitConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4399CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *
C) {
4406 Block = createBlock(
false);
4411 if (ContinueJumpTarget.block) {
4412 addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition,
C);
4413 addSuccessor(
Block, ContinueJumpTarget.block);
4420CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
4421 AddStmtChoice asc) {
4422 if (asc.alwaysAdd(*
this, E)) {
4424 appendStmt(
Block, E);
4430 if (E->
getKind() != UETT_SizeOf)
4433 CFGBlock *lastBlock =
Block;
4437 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr()))
4438 lastBlock = addStmt(VA->getSizeExpr());
4445CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
4446 if (asc.alwaysAdd(*
this, SE)) {
4448 appendStmt(
Block, SE);
4450 return VisitCompoundStmt(SE->
getSubStmt(),
true);
4453CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
4456 CFGBlock *SwitchSuccessor =
nullptr;
4460 SaveAndRestore save_scope_pos(ScopePos);
4464 addLocalScopeForStmt(
Init);
4469 addLocalScopeForVarDecl(VD);
4471 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
4476 SwitchSuccessor =
Block;
4477 }
else SwitchSuccessor = Succ;
4480 SaveAndRestore save_switch(SwitchTerminatedBlock),
4481 save_default(DefaultCaseBlock);
4482 SaveAndRestore save_break(BreakJumpTarget);
4487 DefaultCaseBlock = SwitchSuccessor;
4490 SwitchTerminatedBlock = createBlock(
false);
4494 Succ = SwitchSuccessor;
4495 BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
4500 assert(Terminator->
getBody() &&
"switch must contain a non-NULL body");
4505 SaveAndRestore save_switchExclusivelyCovered(switchExclusivelyCovered,
false);
4508 assert(Terminator->
getCond() &&
"switch condition must be non-NULL");
4509 Expr::EvalResult result;
4510 bool b = tryEvaluate(Terminator->
getCond(), result);
4511 SaveAndRestore save_switchCond(switchCond,
b ? &result :
nullptr);
4516 addLocalScopeAndDtors(Terminator->
getBody());
4518 addStmt(Terminator->
getBody());
4532 bool SwitchAlwaysHasSuccessor =
false;
4533 SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
4534 SwitchAlwaysHasSuccessor |=
4537 addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock,
4538 !SwitchAlwaysHasSuccessor);
4542 Block = SwitchTerminatedBlock;
4543 CFGBlock *LastBlock = addStmt(Terminator->
getCond());
4551 LastBlock = addStmt(
Init);
4552 maybeAddScopeBeginForVarDecl(LastBlock, VD,
Init);
4559 LastBlock = addStmt(
Init);
4572 bool addCase =
false;
4574 if (!switchExclusivelyCovered) {
4578 const llvm::APSInt &condInt = switchCond->
Val.
getInt();
4580 if (condInt == lhsInt) {
4582 switchExclusivelyCovered =
true;
4584 else if (condInt > lhsInt) {
4588 if (V2 >= condInt) {
4590 switchExclusivelyCovered =
true;
4601CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
4604 CFGBlock *TopBlock =
nullptr, *LastBlock =
nullptr;
4611 CFGBlock *currentBlock = createBlock(
false);
4615 addSuccessor(LastBlock, currentBlock);
4617 TopBlock = currentBlock;
4619 addSuccessor(SwitchTerminatedBlock,
4622 ? currentBlock :
nullptr);
4624 LastBlock = currentBlock;
4632 CFGBlock *CaseBlock =
Block;
4634 CaseBlock = createBlock();
4645 assert(SwitchTerminatedBlock);
4646 addSuccessor(SwitchTerminatedBlock, CaseBlock,
4654 addSuccessor(LastBlock, CaseBlock);
4664CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {
4668 DefaultCaseBlock =
Block;
4670 if (!DefaultCaseBlock)
4671 DefaultCaseBlock = createBlock();
4675 DefaultCaseBlock->
setLabel(Terminator);
4690 Succ = DefaultCaseBlock;
4692 return DefaultCaseBlock;
4695CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
4698 CFGBlock *TrySuccessor =
nullptr;
4703 TrySuccessor =
Block;
4705 TrySuccessor = Succ;
4707 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4710 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4714 bool HasCatchAll =
false;
4715 for (
unsigned I = 0, E = Terminator->
getNumHandlers(); I != E; ++I) {
4717 Succ = TrySuccessor;
4718 CXXCatchStmt *CS = Terminator->
getHandler(I);
4723 CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
4728 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4731 if (PrevTryTerminatedBlock)
4732 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4734 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4738 Succ = TrySuccessor;
4741 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4742 cfg->addTryDispatchBlock(TryTerminatedBlock);
4744 assert(Terminator->
getTryBlock() &&
"try must contain a non-NULL body");
4749CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
4755 SaveAndRestore save_scope_pos(ScopePos);
4760 LocalScope::const_iterator BeginScopePos = ScopePos;
4761 addLocalScopeForVarDecl(VD);
4762 addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
4768 CFGBlock *CatchBlock =
Block;
4770 CatchBlock = createBlock();
4776 appendStmt(CatchBlock, CS);
4792CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
4807 SaveAndRestore save_scope_pos(ScopePos);
4811 addLocalScopeForStmt(Range);
4813 addLocalScopeForStmt(Begin);
4815 addLocalScopeForStmt(End);
4816 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
4818 LocalScope::const_iterator ContinueScopePos = ScopePos;
4822 CFGBlock *LoopSuccessor =
nullptr;
4826 LoopSuccessor =
Block;
4828 LoopSuccessor = Succ;
4832 SaveAndRestore save_break(BreakJumpTarget);
4833 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4836 CFGBlock *ConditionBlock = createBlock(
false);
4841 Block = ConditionBlock;
4842 CFGBlock *BeginConditionBlock = addStmt(
C);
4845 assert(BeginConditionBlock == ConditionBlock &&
4846 "condition block in for-range was unexpectedly complex");
4847 (void)BeginConditionBlock;
4852 Succ = ConditionBlock;
4855 TryResult KnownVal(
true);
4858 KnownVal = tryEvaluateBool(S->
getCond());
4865 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4866 SaveAndRestore save_continue(ContinueJumpTarget);
4871 Succ = addStmt(S->
getInc());
4874 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
4878 ContinueJumpTarget.block->setLoopTarget(S);
4892 addLocalScopeAndDtors(S->
getBody());
4904 addSuccessor(ConditionBlock,
4905 KnownVal.isFalse() ?
nullptr : LoopVarStmtBlock);
4910 addSuccessor(ConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4913 Block = createBlock();
4922CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
4923 AddStmtChoice asc,
bool ExternallyDestructed) {
4927 TempDtorContext Context;
4928 VisitForTemporaryDtors(E->
getSubExpr(), ExternallyDestructed, Context);
4932 asc = asc.withAlwaysAdd(
true);
4937CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
4938 AddStmtChoice asc) {
4939 if (asc.alwaysAdd(*
this, E)) {
4941 appendStmt(
Block, E);
4943 findConstructionContexts(
4948 asc = asc.withAlwaysAdd(
false);
4953CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *
C,
4954 AddStmtChoice asc) {
4958 findConstructionContextsForArguments(
C);
4959 appendConstructor(
C);
4961 return VisitChildren(
C);
4964CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
4965 AddStmtChoice asc) {
4967 appendStmt(
Block, NE);
4969 findConstructionContexts(
4971 const_cast<CXXConstructExpr *
>(
NE->getConstructExpr()));
4973 if (
NE->getInitializer())
4974 Block = Visit(
NE->getInitializer());
4977 appendNewAllocator(
Block, NE);
4979 if (
NE->isArray() && *
NE->getArraySize())
4980 Block = Visit(*
NE->getArraySize());
4983 E =
NE->placement_arg_end(); I != E; ++I)
4989CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
4990 AddStmtChoice asc) {
4992 appendStmt(
Block, DE);
4999 appendDeleteDtor(
Block, RD, DE);
5003 return VisitChildren(DE);
5006CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
5007 AddStmtChoice asc) {
5008 if (asc.alwaysAdd(*
this, E)) {
5010 appendStmt(
Block, E);
5012 asc = asc.withAlwaysAdd(
false);
5017CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E,
5018 AddStmtChoice asc) {
5022 findConstructionContextsForArguments(E);
5023 appendConstructor(E);
5025 return VisitChildren(E);
5028CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
5029 AddStmtChoice asc) {
5030 if (asc.alwaysAdd(*
this, E)) {
5032 appendStmt(
Block, E);
5038 return Visit(E->
getSubExpr(), AddStmtChoice());
5041CFGBlock *CFGBuilder::VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc) {
5042 return Visit(E->
getSubExpr(), AddStmtChoice());
5045CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
5047 CFGBlock *IBlock = cfg->getIndirectGotoBlock();
5050 IBlock = createBlock(
false);
5051 cfg->setIndirectGotoBlock(IBlock);
5059 Block = createBlock(
false);
5060 Block->setTerminator(I);
5061 addSuccessor(
Block, IBlock);
5065CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E,
bool ExternallyDestructed,
5066 TempDtorContext &Context) {
5076 return VisitChildrenForTemporaryDtors(E,
false, Context);
5078 case Stmt::InitListExprClass:
5079 return VisitChildrenForTemporaryDtors(E, ExternallyDestructed, Context);
5081 case Stmt::BinaryOperatorClass:
5083 ExternallyDestructed,
5086 case Stmt::CXXBindTemporaryExprClass:
5087 return VisitCXXBindTemporaryExprForTemporaryDtors(
5090 case Stmt::BinaryConditionalOperatorClass:
5091 case Stmt::ConditionalOperatorClass:
5092 return VisitConditionalOperatorForTemporaryDtors(
5095 case Stmt::ImplicitCastExprClass:
5100 case Stmt::CXXFunctionalCastExprClass:
5105 case Stmt::ConstantExprClass:
5109 case Stmt::ParenExprClass:
5113 case Stmt::MaterializeTemporaryExprClass: {
5116 SmallVector<const Expr *, 2> CommaLHSs;
5117 SmallVector<SubobjectAdjustment, 2> Adjustments;
5119 E =
const_cast<Expr *
>(
5122 ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
5124 for (
const Expr *CommaLHS : CommaLHSs) {
5125 VisitForTemporaryDtors(
const_cast<Expr *
>(CommaLHS),
5131 case Stmt::BlockExprClass:
5136 case Stmt::LambdaExprClass: {
5140 CFGBlock *B =
Block;
5141 for (Expr *
Init :
LE->capture_inits()) {
5143 if (CFGBlock *R = VisitForTemporaryDtors(
5144 Init,
true, Context))
5151 case Stmt::StmtExprClass:
5156 case Stmt::CXXDefaultArgExprClass:
5160 case Stmt::CXXDefaultInitExprClass:
5166CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E,
5167 bool ExternallyDestructed,
5168 TempDtorContext &Context) {
5178 CFGBlock *B =
Block;
5181 if (CFGBlock *R = VisitForTemporaryDtors(Child, ExternallyDestructed, Context))
5187CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
5188 BinaryOperator *E,
bool ExternallyDestructed, TempDtorContext &Context) {
5192 CFGBlock *LHSBlock = VisitForTemporaryDtors(E->
getLHS(),
false, Context);
5193 CFGBlock *RHSBlock = VisitForTemporaryDtors(E->
getRHS(), ExternallyDestructed, Context);
5194 return RHSBlock ? RHSBlock : LHSBlock;
5198 VisitForTemporaryDtors(E->
getLHS(),
false, Context);
5199 TryResult RHSExecuted = tryEvaluateBool(E->
getLHS());
5200 if (RHSExecuted.isKnown() && E->
getOpcode() == BO_LOr)
5201 RHSExecuted.negate();
5206 TempDtorContext RHSContext(
5208 VisitForTemporaryDtors(E->
getRHS(),
false, RHSContext);
5209 InsertTempDtorDecisionBlock(RHSContext);
5217 CFGBlock *RHSBlock = VisitForTemporaryDtors(E->
getRHS(),
false, Context);
5218 CFGBlock *LHSBlock = VisitForTemporaryDtors(E->
getLHS(),
false, Context);
5219 return LHSBlock ? LHSBlock : RHSBlock;
5223 return VisitChildrenForTemporaryDtors(E, ExternallyDestructed, Context);
5226CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
5227 CXXBindTemporaryExpr *E,
bool ExternallyDestructed, TempDtorContext &Context) {
5230 CFGBlock *B = VisitForTemporaryDtors(E->
getSubExpr(),
true, Context);
5231 if (!ExternallyDestructed) {
5243 Block = createNoReturnBlock();
5244 }
else if (Context.needsTempDtorBranch()) {
5248 Block = createBlock();
5252 if (Context.needsTempDtorBranch()) {
5253 Context.setDecisionPoint(Succ, E);
5255 appendTemporaryDtor(
Block, E);
5262void CFGBuilder::InsertTempDtorDecisionBlock(
const TempDtorContext &Context,
5263 CFGBlock *FalseSucc) {
5264 if (!Context.TerminatorExpr) {
5268 assert(Context.TerminatorExpr);
5269 CFGBlock *Decision = createBlock(
false);
5270 Decision->setTerminator(CFGTerminator(Context.TerminatorExpr,
5272 addSuccessor(Decision,
Block, !Context.KnownExecuted.isFalse());
5273 addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
5274 !Context.KnownExecuted.isTrue());
5278CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
5279 AbstractConditionalOperator *E,
bool ExternallyDestructed,
5280 TempDtorContext &Context) {
5281 VisitForTemporaryDtors(E->
getCond(),
false, Context);
5282 CFGBlock *ConditionBlock =
Block;
5283 CFGBlock *ConditionSucc = Succ;
5284 TryResult ConditionVal = tryEvaluateBool(E->
getCond());
5285 TryResult NegatedVal = ConditionVal;
5286 if (NegatedVal.isKnown()) NegatedVal.negate();
5288 TempDtorContext TrueContext(
5290 VisitForTemporaryDtors(E->
getTrueExpr(), ExternallyDestructed, TrueContext);
5291 CFGBlock *TrueBlock =
Block;
5293 Block = ConditionBlock;
5294 Succ = ConditionSucc;
5295 TempDtorContext FalseContext(
5297 VisitForTemporaryDtors(E->
getFalseExpr(), ExternallyDestructed, FalseContext);
5299 if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
5300 InsertTempDtorDecisionBlock(FalseContext, TrueBlock);
5301 }
else if (TrueContext.TerminatorExpr) {
5303 InsertTempDtorDecisionBlock(TrueContext);
5305 InsertTempDtorDecisionBlock(FalseContext);
5310CFGBlock *CFGBuilder::VisitOMPExecutableDirective(OMPExecutableDirective *D,
5311 AddStmtChoice asc) {
5312 if (asc.alwaysAdd(*
this, D)) {
5314 appendStmt(
Block, D);
5318 CFGBlock *B =
Block;
5322 SmallVector<Stmt *, 8>
Used(
5323 OMPExecutableDirective::used_clauses_children(D->clauses()));
5324 for (Stmt *S : llvm::reverse(
Used)) {
5325 assert(S &&
"Expected non-null used-in-clause child.");
5326 if (CFGBlock *R = Visit(S))
5330 if (!D->isStandaloneDirective()) {
5331 Stmt *S = D->getRawStmt();
5333 addLocalScopeAndDtors(S);
5334 if (CFGBlock *R = addStmt(S))
5345 bool first_block =
begin() ==
end();
5349 Blocks.push_back(Mem, BlkBVC);
5353 Entry = Exit = &
back();
5362 CFGBuilder Builder(
C, BO);
5363 return Builder.buildCFG(D, Statement);
5378 auto IteratorAndFlag = Visited.insert(B);
5379 if (!IteratorAndFlag.second) {
5385 const CFGBlock *FirstReachableB =
nullptr;
5387 if (!AB.isReachable())
5390 if (FirstReachableB ==
nullptr) {
5391 FirstReachableB = &*AB;
5398 if (!FirstReachableB) {
5404 B = FirstReachableB;
5424 llvm_unreachable(
"getDestructorDecl should only be used with "
5435 if (
const Expr *
Init = var->getInit()) {
5482 llvm_unreachable(
"getKind() returned bogus value");
5490 : ReachableBlock(IsReachable ? B :
nullptr),
5491 UnreachableBlock(!IsReachable ? B :
nullptr,
5492 B && IsReachable ? AB_Normal : AB_Unreachable) {}
5495 : ReachableBlock(B),
5496 UnreachableBlock(B == AlternateBlock ?
nullptr : AlternateBlock,
5497 B == AlternateBlock ? AB_Alternate : AB_Normal) {}
5507 Succs.push_back(Succ,
C);
5520 if (S->isAllEnumCasesCovered()) {
5538 using StmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>;
5539 using DeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>;
5543 signed currentBlock = 0;
5544 unsigned currStmt = 0;
5554 for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
5555 BI != BEnd; ++BI, ++j ) {
5556 if (std::optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
5557 const Stmt *stmt= SE->getStmt();
5558 std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
5561 switch (stmt->getStmtClass()) {
5562 case Stmt::DeclStmtClass:
5563 DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P;
5565 case Stmt::IfStmtClass: {
5566 const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable();
5571 case Stmt::ForStmtClass: {
5572 const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable();
5577 case Stmt::WhileStmtClass: {
5578 const VarDecl *var =
5579 cast<WhileStmt>(stmt)->getConditionVariable();
5584 case Stmt::SwitchStmtClass: {
5585 const VarDecl *var =
5586 cast<SwitchStmt>(stmt)->getConditionVariable();
5591 case Stmt::CXXCatchStmtClass: {
5592 const VarDecl *var =
5593 cast<CXXCatchStmt>(stmt)->getExceptionDecl();
5606 ~StmtPrinterHelper()
override =
default;
5608 const LangOptions &getLangOpts()
const {
return LangOpts; }
5609 void setBlockID(
signed i) { currentBlock = i; }
5610 void setStmtID(
unsigned i) { currStmt = i; }
5612 bool handledStmt(Stmt *S, raw_ostream &OS)
override {
5613 StmtMapTy::iterator I = StmtMap.find(S);
5615 if (I == StmtMap.end())
5618 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5619 && I->second.second == currStmt) {
5623 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5627 bool handleDecl(
const Decl *D, raw_ostream &OS) {
5628 DeclMapTy::iterator I = DeclMap.find(D);
5630 if (I == DeclMap.end()) {
5633 if (
auto *PVD = dyn_cast_or_null<ParmVarDecl>(D)) {
5634 OS <<
"[Parm: " << PVD->getNameAsString() <<
"]";
5640 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5641 && I->second.second == currStmt) {
5645 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5650class CFGBlockTerminatorPrint
5651 :
public StmtVisitor<CFGBlockTerminatorPrint,void> {
5653 StmtPrinterHelper* Helper;
5654 PrintingPolicy Policy;
5657 CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
5658 const PrintingPolicy &Policy)
5659 :
OS(os), Helper(helper), Policy(Policy) {
5663 void VisitIfStmt(IfStmt *I) {
5666 C->printPretty(OS, Helper, Policy);
5670 void VisitStmt(Stmt *Terminator) {
5674 void VisitDeclStmt(DeclStmt *DS) {
5679 void VisitForStmt(ForStmt *F) {
5685 C->printPretty(OS, Helper, Policy);
5692 void VisitWhileStmt(WhileStmt *W) {
5695 C->printPretty(OS, Helper, Policy);
5698 void VisitDoStmt(DoStmt *D) {
5699 OS <<
"do ... while ";
5701 C->printPretty(OS, Helper, Policy);
5704 void VisitSwitchStmt(SwitchStmt *Terminator) {
5709 void VisitCXXTryStmt(CXXTryStmt *) {
OS <<
"try ..."; }
5711 void VisitObjCAtTryStmt(ObjCAtTryStmt *) {
OS <<
"@try ..."; }
5713 void VisitSEHTryStmt(SEHTryStmt *CS) {
OS <<
"__try ..."; }
5715 void VisitAbstractConditionalOperator(AbstractConditionalOperator*
C) {
5716 if (Stmt *
Cond =
C->getCond())
5718 OS <<
" ? ... : ...";
5721 void VisitChooseExpr(ChooseExpr *
C) {
5722 OS <<
"__builtin_choose_expr( ";
5723 if (Stmt *
Cond =
C->getCond())
5728 void VisitIndirectGotoStmt(IndirectGotoStmt *I) {
5731 T->printPretty(OS, Helper, Policy);
5734 void VisitBinaryOperator(BinaryOperator* B) {
5751 llvm_unreachable(
"Invalid logical operator.");
5755 void VisitExpr(Expr *E) {
5760 void print(CFGTerminator
T) {
5761 switch (
T.getKind()) {
5766 OS <<
"(Temp Dtor) ";
5770 OS <<
"(See if most derived ctor has already initialized vbases)";
5792 OS <<
" (Base initializer)";
5794 OS <<
" (Delegating initializer)";
5796 OS <<
" (Member initializer)";
5800 StmtPrinterHelper &Helper,
5815 Stmts.push_back(CICC->getCXXBindTemporaryExpr());
5820 Stmts.push_back(SDSCC->getDeclStmt());
5825 Stmts.push_back(CDSCC->getDeclStmt());
5826 Stmts.push_back(CDSCC->getCXXBindTemporaryExpr());
5831 Stmts.push_back(NECC->getCXXNewExpr());
5836 Stmts.push_back(RSCC->getReturnStmt());
5842 Stmts.push_back(RSCC->getReturnStmt());
5843 Stmts.push_back(RSCC->getCXXBindTemporaryExpr());
5848 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5849 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5854 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5855 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5856 Stmts.push_back(TOCC->getConstructorAfterElision());
5861 Helper.handledStmt(
const_cast<LambdaExpr *
>(LCC->getLambdaExpr()), OS);
5862 OS <<
"+" << LCC->getIndex();
5867 if (
const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
5869 Helper.handledStmt(
const_cast<Stmt *
>(BTE), OS);
5872 Helper.handledStmt(
const_cast<Expr *
>(ACC->getCallLikeExpr()), OS);
5873 OS <<
"+" << ACC->getIndex();
5880 Helper.handledStmt(
const_cast<Stmt *
>(I), OS);
5884static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5885 const CFGElement &E,
bool TerminateWithNewLine =
true);
5888 bool TerminateWithNewLine)
const {
5890 StmtPrinterHelper Helper(
nullptr, LangOpts);
5891 print_elem(OS, Helper, *
this, TerminateWithNewLine);
5894static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5895 const CFGElement &E,
bool TerminateWithNewLine) {
5902 assert(S !=
nullptr &&
"Expecting non-null Stmt");
5905 if (
const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
5913 if (TerminateWithNewLine)
5922 Helper.handledStmt(B->
getRHS(),OS);
5923 if (TerminateWithNewLine)
5928 S->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
5932 OS <<
" (OperatorCall)";
5933 OS <<
" (CXXRecordTypedCall";
5937 OS <<
" (OperatorCall)";
5939 OS <<
" (BindTemporary)";
5941 OS <<
" (CXXConstructExpr";
5945 OS <<
", " << CCE->getType() <<
")";
5946 }
else if (
const CastExpr *CE = dyn_cast<CastExpr>(S)) {
5948 <<
", " << CE->
getType() <<
")";
5952 if (
isa<Expr>(S) && TerminateWithNewLine)
5965 Helper.handleDecl(VD, OS);
5968 if (
T->isReferenceType())
5972 T.getUnqualifiedType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5973 OS <<
"() (Implicit destructor)";
5978 OS <<
"CleanupFunction ("
5984 OS <<
" (Lifetime ends)";
5993 OS <<
"CFGScopeBegin(";
6000 OS <<
"CFGScopeEnd(";
6007 OS <<
"CFGNewAllocator(";
6009 AllocExpr->getType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
6021 OS <<
"->~" << RD->getName().str() <<
"()";
6022 OS <<
" (Implicit destructor)";
6029 OS <<
" (Base object destructor)";
6036 OS <<
"this->" << FD->
getName();
6037 OS <<
".~" <<
T->getAsCXXRecordDecl()->getName() <<
"()";
6038 OS <<
" (Member object destructor)";
6047 OS <<
"() (Temporary object destructor)";
6051 if (TerminateWithNewLine)
6057 StmtPrinterHelper &Helper,
bool print_edges,
6063 OS.changeColor(raw_ostream::YELLOW,
true);
6068 OS <<
" (ENTRY)]\n";
6069 else if (&B == &cfg->
getExit())
6072 OS <<
" (INDIRECT GOTO DISPATCH)]\n";
6074 OS <<
" (NORETURN)]\n";
6090 if (
const Expr *LHS =
C->getLHS())
6092 if (
const Expr *RHS =
C->getRHS()) {
6107 if (
const VarDecl *PD = CS->getCatchParamDecl())
6118 llvm_unreachable(
"Invalid label statement in CFGBlock.");
6127 I != E ; ++I, ++j ) {
6132 OS << llvm::format(
"%3d", j) <<
": ";
6134 Helper.setStmtID(j);
6142 OS.changeColor(raw_ostream::GREEN);
6146 Helper.setBlockID(-1);
6149 CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
6160 const raw_ostream::Colors Color = raw_ostream::BLUE;
6162 OS.changeColor(Color);
6170 OS.changeColor(Color);
6178 bool Reachable =
true;
6181 B = I->getPossiblyUnreachableBlock();
6186 OS <<
"(Unreachable)";
6197 const raw_ostream::Colors Color = raw_ostream::MAGENTA;
6199 OS.changeColor(Color);
6207 OS.changeColor(Color);
6216 bool Reachable =
true;
6219 B = I->getPossiblyUnreachableBlock();
6225 OS <<
"(Unreachable)";
6241 print(llvm::errs(), LO, ShowColors);
6246 StmtPrinterHelper Helper(
this, LO);
6252 for (
const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
6257 print_block(OS,
this, **I, Helper,
true, ShowColors);
6272 bool ShowColors)
const {
6273 print(llvm::errs(), cfg, LO, ShowColors);
6284 StmtPrinterHelper Helper(cfg, LO);
6285 print_block(OS, cfg, *
this, Helper,
true, ShowColors);
6292 CFGBlockTerminatorPrint TPrinter(OS,
nullptr,
PrintingPolicy(LO));
6298 bool AddQuotes)
const {
6300 llvm::raw_string_ostream TempOut(Buf);
6323 if (llvm::any_of(*Blk, [](
const CFGElement &Elm) {
6324 if (std::optional<CFGStmt> StmtElm = Elm.
getAs<
CFGStmt>())
6344 DFSWorkList.push_back(StartBlk);
6345 while (!DFSWorkList.empty()) {
6346 const CFGBlock *Blk = DFSWorkList.pop_back_val();
6347 Visited.insert(Blk);
6356 for (
const auto &Succ : Blk->
succs()) {
6357 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
6361 DFSWorkList.push_back(SuccBlk);
6390 const Stmt *
Cond = StmtElem->getStmt();
6410 case Stmt::CXXForRangeStmtClass:
6414 case Stmt::ForStmtClass:
6418 case Stmt::WhileStmtClass:
6422 case Stmt::DoStmtClass:
6426 case Stmt::IfStmtClass:
6430 case Stmt::ChooseExprClass:
6434 case Stmt::IndirectGotoStmtClass:
6438 case Stmt::SwitchStmtClass:
6442 case Stmt::BinaryConditionalOperatorClass:
6446 case Stmt::ConditionalOperatorClass:
6450 case Stmt::BinaryOperatorClass:
6454 case Stmt::ObjCForCollectionStmtClass:
6471 StmtPrinterHelper H(
this, LO);
6473 llvm::ViewGraph(
this,
"CFG");
6485 llvm::raw_string_ostream Out(OutStr);
6488 if (OutStr[0] ==
'\n') OutStr.erase(OutStr.begin());
6491 for (
unsigned i = 0; i != OutStr.length(); ++i)
6492 if (OutStr[i] ==
'\n') {
6494 OutStr.insert(OutStr.begin()+i+1,
'l');
Defines the clang::ASTContext interface.
Defines enum values for all the target-independent builtin functions.
static StmtPrinterHelper * GraphHelper
static bool isCXXAssumeAttr(const AttributedStmt *A)
static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const CFGElement &E, bool TerminateWithNewLine=true)
static void print_initializer(raw_ostream &OS, StmtPrinterHelper &Helper, const CXXCtorInitializer *I)
static SourceLocation GetEndLoc(Decl *D)
static bool isBuiltinAssumeWithSideEffects(const ASTContext &Ctx, const CallExpr *CE)
static bool CanThrow(Expr *E, ASTContext &Ctx)
static bool isFallthroughStatement(const AttributedStmt *A)
static void print_block(raw_ostream &OS, const CFG *cfg, const CFGBlock &B, StmtPrinterHelper &Helper, bool print_edges, bool ShowColors)
static bool isImmediateSinkBlock(const CFGBlock *Blk)
static const Expr * tryTransformToLiteralConstant(const Expr *E)
Helper for tryNormalizeBinaryOperator.
static QualType getReferenceInitTemporaryType(const Expr *Init, bool *FoundMTE=nullptr)
Retrieve the type of the temporary object whose lifetime was extended by a local reference with the g...
static const VariableArrayType * FindVA(const Type *t)
static std::tuple< const Expr *, BinaryOperatorKind, const Expr * > tryNormalizeBinaryOperator(const BinaryOperator *B)
Tries to interpret a binary operator into Expr Op NumExpr form, if NumExpr is an integer literal or a...
static bool IsLiteralConstantExpr(const Expr *E)
Returns true on constant values based around a single IntegerLiteral, CharacterLiteral,...
static void print_construction_context(raw_ostream &OS, StmtPrinterHelper &Helper, const ConstructionContext *CC)
static bool shouldAddCase(bool &switchExclusivelyCovered, const Expr::EvalResult *switchCond, const CaseStmt *CS, ASTContext &Ctx)
static bool areExprTypesCompatible(const Expr *E1, const Expr *E2)
For an expression x == Foo && x == Bar, this determines whether the Foo and Bar are either of the sam...
static TryResult bothKnownTrue(TryResult R1, TryResult R2)
clang::CharUnits operator*(clang::CharUnits::QuantityType Scale, const clang::CharUnits &CU)
static Decl::Kind getKind(const Decl *D)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the ExceptionSpecificationType enumeration and various utility functions.
Defines the clang::Expr interface and subclasses for C++ expressions.
static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::LangOptions interface.
Defines the clang::SourceLocation class and associated facilities.
Defines various enumerations that describe declaration and type specifiers.
Defines the Objective-C statement AST node classes.
C Language Family Type Representation.
llvm::APInt getValue() const
ValueKind getKind() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const ConstantArrayType * getAsConstantArrayType(QualType T) const
const LangOptions & getLangOpts() const
int getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const
Compare the rank of two floating point types as above, but compare equal if both types have the same ...
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
CanQualType BoundMemberTy
const ArrayType * getAsArrayType(QualType T) const
Type Query functions.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Expr * getCond() const
getCond - Return the expression representing the condition for the ?
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
LabelDecl * getLabel() const
Represents a loop initializing the elements of an array.
OpaqueValueExpr * getCommonExpr() const
Get the common subexpression shared by all initializations (the source array).
Expr * getSubExpr() const
Get the initializer to use for each array element.
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Represents an attribute applied to a statement.
ArrayRef< const Attr * > getAttrs() const
OpaqueValueExpr * getOpaqueValue() const
getOpaqueValue - Return the opaque value placeholder.
Expr * getCommon() const
getCommon - Return the common expression, written to the left of the condition.
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isLogicalOp(Opcode Opc)
static bool isRelationalOp(Opcode Opc)
static bool isCommaOp(Opcode Opc)
static bool isAssignmentOp(Opcode Opc)
static bool isEqualityOp(Opcode Opc)
ArrayRef< Capture > captures() const
const BlockDecl * getBlockDecl() const
void push_back(const_reference Elt, BumpVectorContext &C)
Represents C++ object destructor implicitly generated for automatic object or temporary bound to cons...
const VarDecl * getVarDecl() const
Represents C++ object destructor implicitly generated for base object in destructor.
This class represents a potential adjacent block in the CFG.
AdjacentBlock(CFGBlock *B, bool IsReachable)
Construct an AdjacentBlock with a possibly unreachable block.
CFGBlock * getReachableBlock() const
Get the reachable block, if one exists.
CFGBlock * getPossiblyUnreachableBlock() const
Get the potentially unreachable block.
unsigned IgnoreNullPredecessors
unsigned IgnoreDefaultsWithCoveredEnums
Represents a single basic block in a source-level CFG.
void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C)
void printTerminator(raw_ostream &OS, const LangOptions &LO) const
printTerminator - A simple pretty printer of the terminator of a CFGBlock.
void setLoopTarget(const Stmt *loopTarget)
bool isInevitablySinking() const
Returns true if the block would eventually end with a sink (a noreturn node).
size_t getIndexInCFG() const
void appendScopeBegin(const VarDecl *VD, const Stmt *S, BumpVectorContext &C)
static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src, const CFGBlock *Dst)
reverse_iterator rbegin()
void setTerminator(CFGTerminator Term)
void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C)
void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C)
void print(raw_ostream &OS, const CFG *cfg, const LangOptions &LO, bool ShowColors) const
print - A simple pretty printer of a CFGBlock that outputs to an ostream.
ElementList::const_iterator const_iterator
bool hasNoReturnElement() const
void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C)
void appendScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C)
void appendInitializer(CXXCtorInitializer *initializer, BumpVectorContext &C)
void printTerminatorJson(raw_ostream &Out, const LangOptions &LO, bool AddQuotes) const
printTerminatorJson - Pretty-prints the terminator in JSON format.
void appendNewAllocator(CXXNewExpr *NE, BumpVectorContext &C)
CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent)
Stmt * Label
An (optional) label that prefixes the executable statements in the block.
CFGTerminator getTerminator() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C)
AdjacentBlocks::const_iterator const_pred_iterator
unsigned pred_size() const
void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C)
void appendCXXRecordTypedCall(Expr *E, const ConstructionContext *CC, BumpVectorContext &C)
pred_iterator pred_begin()
void appendCleanupFunction(const VarDecl *VD, BumpVectorContext &C)
void setLabel(Stmt *Statement)
unsigned getBlockID() const
void appendStmt(Stmt *statement, BumpVectorContext &C)
void setHasNoReturnElement()
const Expr * getLastCondition() const
Stmt * getTerminatorCondition(bool StripParens=true)
void addSuccessor(AdjacentBlock Succ, BumpVectorContext &C)
Adds a (potentially unreachable) successor block to the current block.
void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C)
AdjacentBlocks::const_iterator const_succ_iterator
CFGTerminator Terminator
The terminator for a basic block that indicates the type of control-flow that occurs between a block ...
unsigned succ_size() const
Represents a function call that returns a C++ object by value.
static bool isCXXRecordTypedCall(const Expr *E)
Returns true when call expression CE needs to be represented by CFGCXXRecordTypedCall,...
virtual void compareBitwiseEquality(const BinaryOperator *B, bool isAlwaysTrue)
virtual void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)
virtual void compareBitwiseOr(const BinaryOperator *B)
Represents C++ constructor call.
Represents C++ object destructor generated from a call to delete.
const CXXDeleteExpr * getDeleteExpr() const
const CXXRecordDecl * getCXXRecordDecl() const
Represents a top-level expression in a basic block.
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
void dumpToStream(llvm::raw_ostream &OS, bool TerminateWithNewLine=true) const
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
const CXXDestructorDecl * getDestructorDecl(ASTContext &astContext) const
Represents C++ base or member initializer from constructor's initialization list.
CXXCtorInitializer * getInitializer() const
Represents the point where the lifetime of an automatic object ends.
const VarDecl * getVarDecl() const
Represents the point where a loop ends.
Represents C++ object destructor implicitly generated for member object in destructor.
Represents C++ allocator call.
const CXXNewExpr * getAllocatorExpr() const
Represents beginning of a scope implicitly generated by the compiler on encountering a CompoundStmt.
const VarDecl * getVarDecl() const
Represents end of a scope implicitly generated by the compiler after the last Stmt in a CompoundStmt'...
const VarDecl * getVarDecl() const
const Stmt * getStmt() const
Represents C++ object destructor implicitly generated at the end of full expression for temporary obj...
@ TemporaryDtorsBranch
A branch in control flow of destructors of temporaries.
@ VirtualBaseBranch
A shortcut around virtual base initializers.
@ StmtBranch
A branch that corresponds to a statement in the code, such as an if-statement.
bool PruneTriviallyFalseEdges
bool AddStaticInitBranches
bool OmitImplicitValueInitializers
ForcedBlkExprs ** forcedBlkExprs
bool AddCXXDefaultInitExprInAggregates
bool AddCXXDefaultInitExprInCtors
bool AssumeReachableDefaultInSwitchStatements
bool alwaysAdd(const Stmt *stmt) const
bool AddRichCXXConstructors
bool AddVirtualBaseBranches
llvm::DenseMap< const Stmt *, const CFGBlock * > ForcedBlkExprs
bool MarkElidedCXXConstructors
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned size() const
Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...
CFGBlockListTy::const_iterator const_iterator
void print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const
print - A simple pretty printer of a CFG that outputs to an ostream.
bool isLinear() const
Returns true if the CFG has no branches.
static std::unique_ptr< CFG > buildCFG(const Decl *D, Stmt *AST, ASTContext *C, const BuildOptions &BO)
Builds a CFG from an AST.
llvm::BumpPtrAllocator & getAllocator()
CFGBlock * createBlock()
Create a new block in the CFG.
CFGBlock * getIndirectGotoBlock()
void dump(const LangOptions &LO, bool ShowColors) const
dump - A simple pretty printer of a CFG that outputs to stderr.
void viewCFG(const LangOptions &LO) const
Represents a base class of a C++ class.
QualType getType() const
Retrieves the type of the base class.
Represents binding an expression to a temporary.
CXXTemporary * getTemporary()
const Expr * getSubExpr() const
CXXCatchStmt - This represents a C++ catch block.
Stmt * getHandlerBlock() const
VarDecl * getExceptionDecl() const
Represents a call to a C++ constructor.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Represents a C++ base or member initializer.
bool isDelegatingInitializer() const
Determine whether this initializer is creating a delegating constructor.
Expr * getInit() const
Get the initializer.
TypeSourceInfo * getTypeSourceInfo() const
Returns the declarator information for a base class or delegating initializer.
bool isBaseInitializer() const
Determine whether this initializer is initializing a base class.
const Type * getBaseClass() const
If this is a base class initializer, returns the type of the base class.
FieldDecl * getAnyMember() const
Represents a delete expression for memory deallocation and destructor calls, e.g.
QualType getDestroyedType() const
Retrieve the type being destroyed.
Represents a C++ destructor within a class.
DeclStmt * getBeginStmt()
DeclStmt * getLoopVarStmt()
DeclStmt * getRangeStmt()
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
ExprIterator arg_iterator
Represents a C++ struct/union/class.
bool hasTrivialDestructor() const
Determine whether this class has a trivial destructor (C++ [class.dtor]p3)
base_class_range vbases()
bool hasDefinition() const
CXXDestructorDecl * getDestructor() const
Returns the destructor decl for this class.
bool isAnyDestructorNoReturn() const
Returns true if the class destructor, or any implicitly invoked destructors are marked noreturn.
Represents a C++ temporary.
const CXXDestructorDecl * getDestructor() const
CXXCatchStmt * getHandler(unsigned i)
unsigned getNumHandlers() const
CompoundStmt * getTryBlock()
bool isPotentiallyEvaluated() const
Determine whether this typeid has a type operand which is potentially evaluated, per C++11 [expr....
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
unsigned getBuiltinCallee() const
getBuiltinCallee - If this is a call to a builtin, return the builtin ID of the callee.
CaseStmt - Represent a case statement.
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
CastKind getCastKind() const
CompoundStmt - This represents a group of statements like { stmt stmt }.
reverse_body_iterator body_rbegin()
@ ElidableConstructorKind
static const ConstructionContextLayer * create(BumpVectorContext &C, const ConstructionContextItem &Item, const ConstructionContextLayer *Parent=nullptr)
const ConstructionContextItem & getItem() const
ConstructionContext's subclasses describe different ways of constructing an object in C++.
static const ConstructionContext * createFromLayers(BumpVectorContext &C, const ConstructionContextLayer *TopLayer)
Consume the construction context layer, together with its parent layers, and wrap it up into a comple...
@ CXX17ElidedCopyVariableKind
@ ElidedTemporaryObjectKind
@ SimpleTemporaryObjectKind
@ CXX17ElidedCopyConstructorInitializerKind
@ SimpleConstructorInitializerKind
@ SimpleReturnedValueKind
@ CXX17ElidedCopyReturnedValueKind
Expr * getOperand() const
Retrieve the operand of the 'co_return' statement.
Expr * getPromiseCall() const
Retrieve the promise call that results from this 'co_return' statement.
Expr * getReadyExpr() const
Expr * getResumeExpr() const
Expr * getSuspendExpr() const
Expr * getCommonExpr() const
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
std::reverse_iterator< decl_iterator > reverse_decl_iterator
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
decl_iterator decl_begin()
const Decl * getSingleDecl() const
reverse_decl_iterator decl_rend()
reverse_decl_iterator decl_rbegin()
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
SourceLocation getLocation() const
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
This represents one expression.
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
static QualType findBoundMemberType(const Expr *expr)
Given an expression of bound-member type, find the type of the member.
bool isValueDependent() const
Determines whether the value of this expression depends on.
bool isTypeDependent() const
Determines whether the type of this expression depends on.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsRValue - Return true if this is a constant which we can fold to an rvalue using any crazy t...
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsBooleanCondition - Return true if this is a constant which we can fold and convert to a boo...
static bool isSameComparisonOperand(const Expr *E1, const Expr *E2)
Checks that the two Expr's will refer to the same value as a comparison operand.
bool isKnownToHaveBooleanValue(bool Semantic=true) const
isKnownToHaveBooleanValue - Return true if this is an integer expression that is known to return 0 or...
Represents a member of a struct/union/class.
VarDecl * getConditionVariable() const
Retrieve the variable declared in this "for" statement, if any.
DeclStmt * getConditionVariableDeclStmt()
If this ForStmt has a condition variable, return the faux DeclStmt associated with the creation of th...
const Expr * getSubExpr() const
Represents a prototype with parameter type info, e.g.
FunctionType - C99 6.7.5.3 - Function Declarators.
LabelDecl * getLabel() const
DeclStmt * getConditionVariableDeclStmt()
If this IfStmt has a condition variable, return the faux DeclStmt associated with the creation of tha...
VarDecl * getConditionVariable()
Retrieve the variable declared in this "if" statement, if any.
unsigned getNumInits() const
Expr ** getInits()
Retrieve the set of initializers.
LabelStmt - Represents a label, which has a substatement.
LabelDecl * getDecl() const
const char * getName() const
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Expr ** capture_init_iterator
Iterator that walks over the capture initialization arguments.
capture_init_iterator capture_init_end()
Retrieve the iterator pointing one past the last initialization argument for this lambda expression.
capture_init_iterator capture_init_begin()
Retrieve the first initialization argument for this lambda expression (which initializes the first ca...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
StorageDuration getStorageDuration() const
Retrieve the storage duration for the materialized temporary.
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getQualifiedNameAsString() const
Represents Objective-C's @catch statement.
const Stmt * getCatchBody() const
const Expr * getSynchExpr() const
const CompoundStmt * getSynchBody() const
const ObjCAtFinallyStmt * getFinallyStmt() const
Retrieve the @finally statement, if any.
const Stmt * getTryBody() const
Retrieve the @try body.
catch_range catch_stmts()
const Stmt * getSubStmt() const
unsigned getNumSemanticExprs() const
Expr * getSemanticExpr(unsigned index)
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
field_range fields() const
CompoundStmt * getBlock() const
Expr * getFilterExpr() const
CompoundStmt * getBlock() const
CompoundStmt * getTryBlock() const
SEHFinallyStmt * getFinallyHandler() const
SEHExceptStmt * getExceptHandler() const
Returns 0 if not defined.
Encodes a location in the source.
StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
CompoundStmt * getSubStmt()
Stmt - This represents one statement.
void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation=0, StringRef NewlineSymbol="\n", const ASTContext *Context=nullptr) const
const Stmt * stripLabelLikeStatements() const
Strip off all label-like statements.
StmtClass getStmtClass() const
const char * getStmtClassName() const
SwitchStmt - This represents a 'switch' stmt.
bool isAllEnumCasesCovered() const
Returns true if the SwitchStmt is a switch of an enum value and all cases have been explicitly covere...
VarDecl * getConditionVariable()
Retrieve the variable declared in this "switch" statement, if any.
SwitchCase * getSwitchCaseList()
DeclStmt * getConditionVariableDeclStmt()
If this SwitchStmt has a condition variable, return the faux DeclStmt associated with the creation of...
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
QualType getType() const
Return the type wrapped by this type source info.
The base class of the type hierarchy.
bool isBlockPointerType() const
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isFunctionPointerType() const
bool isReferenceType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const Type * getBaseElementTypeUnsafe() const
Get the base element type of this type, potentially discarding type qualifiers.
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
const T * getAs() const
Member-template getAs<specific type>'.
QualType getArgumentType() const
bool isArgumentType() const
UnaryExprOrTypeTrait getKind() const
Expr * getSubExpr() const
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
const Expr * getInit() const
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Represents a C array with a specified size that is not an integer-constant-expression.
DeclStmt * getConditionVariableDeclStmt()
If this WhileStmt has a condition variable, return the faux DeclStmt associated with the creation of ...
VarDecl * getConditionVariable()
Retrieve the variable declared in this "while" statement, if any.
const AstTypeMatcher< ArrayType > arrayType
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
bool Sub(InterpState &S, CodePtr OpPC)
bool NE(InterpState &S, CodePtr OpPC)
bool LE(InterpState &S, CodePtr OpPC)
bool Cast(InterpState &S, CodePtr OpPC)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
bool hasSpecificAttr(const Container &container)
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType)
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ SD_FullExpression
Full-expression storage duration (for temporaries).
@ Result
The result type of a method or function.
const FunctionProtoType * T
std::string JsonFormat(StringRef RawSR, bool AddQuotes)
@ Type
The name was classified as a type.
bool operator!=(CanQual< T > x, CanQual< U > y)
U cast(CodeGen::Address addr)
Expr * extractElementInitializerFromNestedAILE(const ArrayInitLoopExpr *AILE)
Diagnostic wrappers for TextAPI types for error reporting.
float __ovld __cnfn distance(float, float)
Returns the distance between p0 and p1.
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
Describes how types, statements, expressions, and declarations should be printed.
unsigned IncludeNewlines
When true, include newlines after statements like "break", etc.
DOTGraphTraits(bool isSimple=false)
static std::string getNodeLabel(const CFGBlock *Node, const CFG *Graph)