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/TimeProfiler.h"
56#include "llvm/Support/raw_ostream.h"
68 if (
VarDecl *VD = dyn_cast<VarDecl>(D))
69 if (
Expr *Ex = VD->getInit())
70 return Ex->getSourceRange().getEnd();
84 if (
const auto *CE = dyn_cast<CastExpr>(E)) {
85 if (CE->getCastKind() != CK_IntegralCast &&
86 CE->getCastKind() != CK_IntegralToFloating)
92 if (
const auto *UO = dyn_cast<UnaryOperator>(E)) {
93 if (UO->getOpcode() != UO_Minus)
117static std::tuple<const Expr *, BinaryOperatorKind, const Expr *>
124 if (Constant ==
nullptr) {
128 else if (Op == BO_GE)
130 else if (Op == BO_LT)
132 else if (Op == BO_LE)
139 return std::make_tuple(MaybeDecl, Op, Constant);
190 enum Kind { NotAlwaysAdd = 0, AlwaysAdd = 1 };
192 AddStmtChoice(Kind a_kind = NotAlwaysAdd) : kind(a_kind) {}
194 bool alwaysAdd(CFGBuilder &builder,
195 const Stmt *
stmt)
const;
199 AddStmtChoice withAlwaysAdd(
bool alwaysAdd)
const {
200 return AddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd);
230 using AutomaticVarsTy = BumpVector<VarDecl *>;
234 class const_iterator {
235 const LocalScope* Scope =
nullptr;
239 unsigned VarIter = 0;
245 const_iterator() =
default;
249 const_iterator(
const LocalScope& S,
unsigned I)
250 : Scope(&S), VarIter(I) {
253 if (VarIter == 0 && Scope)
257 VarDecl *
const* operator->()
const {
258 assert(Scope &&
"Dereferencing invalid iterator is not allowed");
259 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
260 return &Scope->Vars[VarIter - 1];
263 const VarDecl *getFirstVarInScope()
const {
264 assert(Scope &&
"Dereferencing invalid iterator is not allowed");
265 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
266 return Scope->Vars[0];
270 return *this->operator->();
273 const_iterator &operator++() {
277 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
283 const_iterator operator++(
int) {
284 const_iterator P = *
this;
289 bool operator==(
const const_iterator &rhs)
const {
290 return Scope == rhs.Scope && VarIter == rhs.VarIter;
292 bool operator!=(
const const_iterator &rhs)
const {
293 return !(*
this == rhs);
296 explicit operator bool()
const {
297 return *
this != const_iterator();
301 const_iterator shared_parent(const_iterator L);
302 bool pointsToFirstDeclaredVar() {
return VarIter == 1; }
303 bool inSameLocalScope(const_iterator rhs) {
return Scope == rhs.Scope; }
307 BumpVectorContext ctx;
310 AutomaticVarsTy Vars;
318 LocalScope(BumpVectorContext ctx, const_iterator P)
319 : ctx(std::move(ctx)), Vars(this->ctx, 4), Prev(P) {}
322 const_iterator begin()
const {
return const_iterator(*
this, Vars.size()); }
324 void addVar(VarDecl *VD) {
325 Vars.push_back(VD, ctx);
334int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
336 const_iterator F = *
this;
337 while (F.Scope != L.Scope) {
338 assert(F != const_iterator() &&
339 "L iterator is not reachable from F iterator.");
343 D += F.VarIter - L.VarIter;
351LocalScope::const_iterator
352LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
355 if ((*
this == const_iterator()) || (L == const_iterator())) {
356 return const_iterator();
359 const_iterator F = *
this;
360 if (F.inSameLocalScope(L)) {
362 F.VarIter = std::min(F.VarIter, L.VarIter);
366 llvm::SmallDenseMap<const LocalScope *, unsigned, 4> ScopesOfL;
368 ScopesOfL.try_emplace(L.Scope, L.VarIter);
369 if (L == const_iterator())
375 if (
auto LIt = ScopesOfL.find(F.Scope); LIt != ScopesOfL.end()) {
377 F.VarIter = std::min(F.VarIter, LIt->getSecond());
380 assert(F != const_iterator() &&
381 "L iterator is not reachable from F iterator.");
391struct BlockScopePosPair {
392 CFGBlock *block =
nullptr;
393 LocalScope::const_iterator scopePosition;
395 BlockScopePosPair() =
default;
396 BlockScopePosPair(CFGBlock *
b, LocalScope::const_iterator scopePos)
397 : block(
b), scopePosition(scopePos) {}
408 TryResult() =
default;
409 TryResult(
bool b) :
X(
b ? 1 : 0) {}
411 bool isTrue()
const {
return X == 1; }
412 bool isFalse()
const {
return X == 0; }
413 bool isKnown()
const {
return X >= 0; }
424 if (!R1.isKnown() || !R2.isKnown())
426 return TryResult(R1.isTrue() && R2.isTrue());
431class reverse_children {
432 llvm::SmallVector<Stmt *, 12> childrenBuf;
436 reverse_children(Stmt *S, ASTContext &Ctx);
438 using iterator = ArrayRef<Stmt *>::reverse_iterator;
440 iterator begin()
const {
return children.rbegin(); }
441 iterator end()
const {
return children.rend(); }
446reverse_children::reverse_children(Stmt *S, ASTContext &Ctx) {
447 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
454 case Stmt::InitListExprClass: {
461 case Stmt::AttributedStmtClass: {
467 for (
const auto *Attr : AS->getAttrs()) {
468 if (
const auto *AssumeAttr = dyn_cast<CXXAssumeAttr>(Attr)) {
469 Expr *AssumeExpr = AssumeAttr->getAssumption();
471 childrenBuf.push_back(AssumeExpr);
478 llvm::append_range(childrenBuf, AS->children());
487 llvm::append_range(childrenBuf, S->
children());
509 using JumpTarget = BlockScopePosPair;
510 using JumpSource = BlockScopePosPair;
513 std::unique_ptr<CFG> cfg;
516 CFGBlock *
Block =
nullptr;
519 CFGBlock *Succ =
nullptr;
521 JumpTarget ContinueJumpTarget;
522 JumpTarget BreakJumpTarget;
523 JumpTarget SEHLeaveJumpTarget;
524 CFGBlock *SwitchTerminatedBlock =
nullptr;
525 CFGBlock *DefaultCaseBlock =
nullptr;
531 CFGBlock *TryTerminatedBlock =
nullptr;
534 LocalScope::const_iterator ScopePos;
537 using LabelMapTy = llvm::DenseMap<LabelDecl *, JumpTarget>;
542 using BackpatchBlocksTy = std::vector<JumpSource>;
543 BackpatchBlocksTy BackpatchBlocks;
546 using LabelSetTy = llvm::SmallSetVector<LabelDecl *, 8>;
547 LabelSetTy AddressTakenLabels;
552 llvm::DenseMap<Expr *, const ConstructionContextLayer *>
553 ConstructionContextMap;
556 const CFG::BuildOptions &BuildOpts;
559 bool switchExclusivelyCovered =
false;
560 Expr::EvalResult *switchCond =
nullptr;
562 CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry =
nullptr;
563 const Stmt *lastLookup =
nullptr;
567 using CachedBoolEvalsTy = llvm::DenseMap<Expr *, TryResult>;
568 CachedBoolEvalsTy CachedBoolEvals;
571 explicit CFGBuilder(ASTContext *astContext,
572 const CFG::BuildOptions &buildOpts)
573 : Context(astContext), cfg(new CFG()), BuildOpts(buildOpts) {}
576 std::unique_ptr<CFG> buildCFG(
const Decl *D, Stmt *Statement);
578 bool alwaysAdd(
const Stmt *
stmt);
582 CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc);
583 CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
584 CFGBlock *VisitAttributedStmt(AttributedStmt *A, AddStmtChoice asc);
585 CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
586 CFGBlock *VisitBreakStmt(BreakStmt *B);
587 CFGBlock *VisitCallExpr(CallExpr *
C, AddStmtChoice asc);
588 CFGBlock *VisitCaseStmt(CaseStmt *
C);
589 CFGBlock *VisitChooseExpr(ChooseExpr *
C, AddStmtChoice asc);
590 CFGBlock *VisitCompoundStmt(
CompoundStmt *
C,
bool ExternallyDestructed);
591 CFGBlock *VisitConditionalOperator(AbstractConditionalOperator *
C,
593 CFGBlock *VisitContinueStmt(ContinueStmt *
C);
594 CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
596 CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
597 CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *
C, AddStmtChoice asc);
598 CFGBlock *VisitCXXNewExpr(CXXNewExpr *DE, AddStmtChoice asc);
599 CFGBlock *VisitCXXDeleteExpr(CXXDeleteExpr *DE, AddStmtChoice asc);
600 CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
601 CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
603 CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *
C,
605 CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *
T);
606 CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
607 CFGBlock *VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc);
608 CFGBlock *VisitDeclStmt(DeclStmt *DS);
609 CFGBlock *VisitDeclSubExpr(DeclStmt *DS);
610 CFGBlock *VisitDefaultStmt(DefaultStmt *D);
611 CFGBlock *VisitDoStmt(DoStmt *D);
612 CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E,
613 AddStmtChoice asc,
bool ExternallyDestructed);
614 CFGBlock *VisitForStmt(ForStmt *F);
615 CFGBlock *VisitGotoStmt(GotoStmt *G);
616 CFGBlock *VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc);
617 CFGBlock *VisitIfStmt(IfStmt *I);
618 CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
619 CFGBlock *VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc);
620 CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I);
621 CFGBlock *VisitLabelStmt(LabelStmt *L);
622 CFGBlock *VisitBlockExpr(BlockExpr *E, AddStmtChoice asc);
623 CFGBlock *VisitLambdaExpr(
LambdaExpr *E, AddStmtChoice asc);
624 CFGBlock *VisitLogicalOperator(BinaryOperator *B);
625 std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(BinaryOperator *B,
628 CFGBlock *FalseBlock);
629 CFGBlock *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
631 CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc);
632 CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S);
633 CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S);
634 CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S);
635 CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
636 CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S);
637 CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
638 CFGBlock *VisitObjCMessageExpr(ObjCMessageExpr *E, AddStmtChoice asc);
639 CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);
640 CFGBlock *VisitReturnStmt(Stmt *S);
641 CFGBlock *VisitCoroutineSuspendExpr(CoroutineSuspendExpr *S,
643 CFGBlock *VisitSEHExceptStmt(SEHExceptStmt *S);
644 CFGBlock *VisitSEHFinallyStmt(SEHFinallyStmt *S);
645 CFGBlock *VisitSEHLeaveStmt(SEHLeaveStmt *S);
646 CFGBlock *VisitSEHTryStmt(SEHTryStmt *S);
647 CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
648 CFGBlock *VisitSwitchStmt(SwitchStmt *S);
649 CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
651 CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc);
652 CFGBlock *VisitWhileStmt(WhileStmt *W);
653 CFGBlock *VisitArrayInitLoopExpr(ArrayInitLoopExpr *A, AddStmtChoice asc);
655 CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd,
656 bool ExternallyDestructed =
false);
657 CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc);
658 CFGBlock *VisitChildren(Stmt *S);
659 CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc);
660 CFGBlock *VisitOMPExecutableDirective(OMPExecutableDirective *D,
663 void maybeAddScopeBeginForVarDecl(CFGBlock *B,
const VarDecl *VD,
665 if (ScopePos && (VD == ScopePos.getFirstVarInScope()))
666 appendScopeBegin(B, VD, S);
697 struct TempDtorContext {
698 TempDtorContext() =
default;
699 TempDtorContext(TryResult KnownExecuted)
700 : IsConditional(
true), KnownExecuted(KnownExecuted) {}
708 bool needsTempDtorBranch()
const {
709 return IsConditional && !TerminatorExpr;
714 void setDecisionPoint(CFGBlock *S, CXXBindTemporaryExpr *E) {
719 const bool IsConditional =
false;
720 const TryResult KnownExecuted =
true;
721 CFGBlock *Succ =
nullptr;
722 CXXBindTemporaryExpr *TerminatorExpr =
nullptr;
727 CFGBlock *VisitForTemporaryDtors(Stmt *E,
bool ExternallyDestructed,
728 TempDtorContext &Context);
729 CFGBlock *VisitChildrenForTemporaryDtors(Stmt *E,
bool ExternallyDestructed,
730 TempDtorContext &Context);
731 CFGBlock *VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E,
732 bool ExternallyDestructed,
733 TempDtorContext &Context);
734 CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(
735 CXXBindTemporaryExpr *E,
bool ExternallyDestructed, TempDtorContext &Context);
736 CFGBlock *VisitConditionalOperatorForTemporaryDtors(
737 AbstractConditionalOperator *E,
bool ExternallyDestructed,
738 TempDtorContext &Context);
739 void InsertTempDtorDecisionBlock(
const TempDtorContext &Context,
740 CFGBlock *FalseSucc =
nullptr);
750 void consumeConstructionContext(
const ConstructionContextLayer *Layer,
758 void findConstructionContexts(
const ConstructionContextLayer *Layer,
764 template <
typename CallLikeExpr,
765 typename = std::enable_if_t<
766 std::is_base_of_v<CallExpr, CallLikeExpr> ||
767 std::is_base_of_v<CXXConstructExpr, CallLikeExpr> ||
768 std::is_base_of_v<ObjCMessageExpr, CallLikeExpr>>>
769 void findConstructionContextsForArguments(CallLikeExpr *E) {
770 for (
unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
771 Expr *Arg = E->getArg(i);
773 findConstructionContexts(
775 ConstructionContextItem(E, i)),
783 void cleanupConstructionContext(Expr *E);
785 void autoCreateBlock() {
if (!
Block)
Block = createBlock(); }
787 CFGBlock *createBlock(
bool add_successor =
true);
788 CFGBlock *createNoReturnBlock();
790 CFGBlock *addStmt(Stmt *S) {
791 return Visit(S, AddStmtChoice::AlwaysAdd);
794 CFGBlock *addInitializer(CXXCtorInitializer *I);
795 void addLoopExit(
const Stmt *LoopStmt);
796 void addAutomaticObjHandling(LocalScope::const_iterator B,
797 LocalScope::const_iterator E, Stmt *S);
798 void addAutomaticObjDestruction(LocalScope::const_iterator B,
799 LocalScope::const_iterator E, Stmt *S);
800 void addScopeExitHandling(LocalScope::const_iterator B,
801 LocalScope::const_iterator E, Stmt *S);
802 void addImplicitDtorsForDestructor(
const CXXDestructorDecl *DD);
803 void addScopeChangesHandling(LocalScope::const_iterator SrcPos,
804 LocalScope::const_iterator DstPos,
806 CFGBlock *createScopeChangesHandlingBlock(LocalScope::const_iterator SrcPos,
808 LocalScope::const_iterator DstPost,
812 LocalScope* createOrReuseLocalScope(LocalScope* Scope);
814 void addLocalScopeForStmt(Stmt *S);
815 LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS,
816 LocalScope* Scope =
nullptr);
817 LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope =
nullptr);
819 void addLocalScopeAndDtors(Stmt *S);
821 const ConstructionContext *retrieveAndCleanupConstructionContext(Expr *E) {
825 const ConstructionContextLayer *Layer = ConstructionContextMap.lookup(E);
829 cleanupConstructionContext(E);
836 void appendStmt(CFGBlock *B,
const Stmt *S) {
837 if (alwaysAdd(S) && cachedEntry)
838 cachedEntry->second = B;
842 B->
appendStmt(
const_cast<Stmt*
>(S), cfg->getBumpVectorContext());
845 void appendConstructor(CXXConstructExpr *CE) {
847 if (
C &&
C->isNoReturn())
848 Block = createNoReturnBlock();
852 if (
const ConstructionContext *CC =
853 retrieveAndCleanupConstructionContext(CE)) {
854 Block->appendConstructor(CE, CC, cfg->getBumpVectorContext());
859 Block->appendStmt(CE, cfg->getBumpVectorContext());
862 void appendCall(CFGBlock *B, CallExpr *CE) {
863 if (alwaysAdd(CE) && cachedEntry)
864 cachedEntry->second = B;
866 if (
const ConstructionContext *CC =
867 retrieveAndCleanupConstructionContext(CE)) {
873 B->
appendStmt(CE, cfg->getBumpVectorContext());
876 void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
880 void appendNewAllocator(CFGBlock *B, CXXNewExpr *NE) {
884 void appendBaseDtor(CFGBlock *B,
const CXXBaseSpecifier *BS) {
888 void appendMemberDtor(CFGBlock *B, FieldDecl *FD) {
892 void appendObjCMessage(CFGBlock *B, ObjCMessageExpr *ME) {
893 if (alwaysAdd(ME) && cachedEntry)
894 cachedEntry->second = B;
896 if (
const ConstructionContext *CC =
897 retrieveAndCleanupConstructionContext(ME)) {
902 B->
appendStmt(ME, cfg->getBumpVectorContext());
905 void appendTemporaryDtor(CFGBlock *B, CXXBindTemporaryExpr *E) {
909 void appendAutomaticObjDtor(CFGBlock *B, VarDecl *VD, Stmt *S) {
913 void appendCleanupFunction(CFGBlock *B, VarDecl *VD) {
917 void appendLifetimeEnds(CFGBlock *B, VarDecl *VD, Stmt *S) {
921 void appendLoopExit(CFGBlock *B,
const Stmt *LoopStmt) {
925 void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) {
929 void addSuccessor(CFGBlock *B, CFGBlock *S,
bool IsReachable =
true) {
930 B->
addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable),
931 cfg->getBumpVectorContext());
936 void addSuccessor(CFGBlock *B, CFGBlock *ReachableBlock, CFGBlock *AltBlock) {
937 B->
addSuccessor(CFGBlock::AdjacentBlock(ReachableBlock, AltBlock),
938 cfg->getBumpVectorContext());
941 void appendScopeBegin(CFGBlock *B,
const VarDecl *VD,
const Stmt *S) {
946 void appendScopeEnd(CFGBlock *B,
const VarDecl *VD,
const Stmt *S) {
954 TryResult checkIncorrectRelationalOperator(
const BinaryOperator *B) {
958 const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
959 const Expr *BoolExpr = RHSExpr;
960 bool IntFirst =
true;
962 IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
970 llvm::APInt IntValue = IntLiteral->
getValue();
971 if ((IntValue == 1) || (IntValue == 0))
975 !IntValue.isNegative();
978 if (Bok == BO_GT || Bok == BO_GE) {
981 return TryResult(IntFirst == IntLarger);
985 return TryResult(IntFirst != IntLarger);
993 TryResult checkIncorrectEqualityOperator(
const BinaryOperator *B) {
997 std::optional<llvm::APInt> IntLiteral1 =
998 getIntegerLiteralSubexpressionValue(LHSExpr);
999 const Expr *BoolExpr = RHSExpr;
1002 IntLiteral1 = getIntegerLiteralSubexpressionValue(RHSExpr);
1009 const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
1010 if (BitOp && (BitOp->
getOpcode() == BO_And ||
1015 std::optional<llvm::APInt> IntLiteral2 =
1016 getIntegerLiteralSubexpressionValue(LHSExpr2);
1019 IntLiteral2 = getIntegerLiteralSubexpressionValue(RHSExpr2);
1025 (*IntLiteral2 & *IntLiteral1) != *IntLiteral1) ||
1027 (*IntLiteral2 | *IntLiteral1) != *IntLiteral1)) {
1031 return TryResult(B->
getOpcode() != BO_EQ);
1034 if ((*IntLiteral1 == 1) || (*IntLiteral1 == 0)) {
1037 return TryResult(B->
getOpcode() != BO_EQ);
1049 std::optional<llvm::APInt>
1050 getIntegerLiteralSubexpressionValue(
const Expr *E) {
1053 if (
const auto *UnOp = dyn_cast<UnaryOperator>(E->
IgnoreParens())) {
1056 const Expr *SubExpr = UnOp->getSubExpr()->IgnoreParens();
1058 if (
const auto *IntLiteral = dyn_cast<IntegerLiteral>(SubExpr)) {
1063 switch (UnOp->getOpcode()) {
1073 assert(
false &&
"Unexpected unary operator!");
1074 return std::nullopt;
1077 }
else if (
const auto *IntLiteral =
1081 return std::nullopt;
1084 template <
typename APFloatOrInt>
1086 const APFloatOrInt &Value1,
1087 const APFloatOrInt &Value2) {
1092 return TryResult(Value1 == Value2);
1094 return TryResult(Value1 != Value2);
1096 return TryResult(Value1 < Value2);
1098 return TryResult(Value1 <= Value2);
1100 return TryResult(Value1 > Value2);
1102 return TryResult(Value1 >= Value2);
1113 TryResult checkIncorrectLogicOperator(
const BinaryOperator *B) {
1118 auto CheckLogicalOpWithNegatedVariable = [
this, B](
const Expr *E1,
1120 if (
const auto *Negate = dyn_cast<UnaryOperator>(E1)) {
1121 if (Negate->getOpcode() == UO_LNot &&
1123 bool AlwaysTrue = B->
getOpcode() == BO_LOr;
1126 return TryResult(AlwaysTrue);
1132 TryResult
Result = CheckLogicalOpWithNegatedVariable(LHSExpr, RHSExpr);
1135 Result = CheckLogicalOpWithNegatedVariable(RHSExpr, LHSExpr);
1139 const auto *LHS = dyn_cast<BinaryOperator>(LHSExpr);
1140 const auto *RHS = dyn_cast<BinaryOperator>(RHSExpr);
1144 if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
1147 const Expr *DeclExpr1;
1148 const Expr *NumExpr1;
1152 if (!DeclExpr1 || !NumExpr1)
1155 const Expr *DeclExpr2;
1156 const Expr *NumExpr2;
1160 if (!DeclExpr2 || !NumExpr2)
1173 Expr::EvalResult L1Result, L2Result;
1188 auto AnalyzeConditions = [&](
const auto &Values,
1191 bool AlwaysTrue =
true, AlwaysFalse =
true;
1194 bool LHSAlwaysTrue =
true, LHSAlwaysFalse =
true;
1195 bool RHSAlwaysTrue =
true, RHSAlwaysFalse =
true;
1197 for (
const auto &
Value : Values) {
1199 analyzeLogicOperatorCondition(*BO1,
Value, Values[1] );
1201 analyzeLogicOperatorCondition(*BO2,
Value, Values[3] );
1203 if (!Res1.isKnown() || !Res2.isKnown())
1206 const bool IsAnd = B->
getOpcode() == BO_LAnd;
1207 const bool Combine = IsAnd ? (Res1.isTrue() && Res2.isTrue())
1208 : (Res1.isTrue() || Res2.isTrue());
1210 AlwaysTrue &= Combine;
1211 AlwaysFalse &= !Combine;
1213 LHSAlwaysTrue &= Res1.isTrue();
1214 LHSAlwaysFalse &= Res1.isFalse();
1215 RHSAlwaysTrue &= Res2.isTrue();
1216 RHSAlwaysFalse &= Res2.isFalse();
1219 if (AlwaysTrue || AlwaysFalse) {
1220 if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
1221 !RHSAlwaysFalse && BuildOpts.
Observer) {
1224 return TryResult(AlwaysTrue);
1232 llvm::APSInt L1 = L1Result.
Val.
getInt();
1233 llvm::APSInt L2 = L2Result.
Val.
getInt();
1236 if (L1.isSigned() != L2.isSigned() ||
1237 L1.getBitWidth() != L2.getBitWidth())
1242 const llvm::APSInt Values[] = {
1244 llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
1248 ((L1 < L2) ? L1 : L2) +
1249 llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1), L1.isUnsigned()),
1253 llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
1256 return AnalyzeConditions(Values, &BO1, &BO2);
1275 if (llvm::APFloat::opOK !=
1276 L2.convert(L1.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
1279 }
else if (Order < 0)
1281 if (llvm::APFloat::opOK !=
1282 L1.convert(L2.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
1286 llvm::APFloat MidValue = L1;
1287 MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven);
1288 MidValue.divide(llvm::APFloat(MidValue.getSemantics(),
"2.0"),
1289 llvm::APFloat::rmNearestTiesToEven);
1291 const llvm::APFloat Values[] = {
1292 llvm::APFloat::getSmallest(L1.getSemantics(),
true), L1, MidValue, L2,
1293 llvm::APFloat::getLargest(L2.getSemantics(),
false),
1296 return AnalyzeConditions(Values, &BO1, &BO2);
1303 TryResult checkIncorrectBitwiseOrOperator(
const BinaryOperator *B) {
1304 const Expr *LHSConstant =
1306 const Expr *RHSConstant =
1309 if ((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant))
1312 const Expr *Constant = LHSConstant ? LHSConstant : RHSConstant;
1318 if (
Result.Val.getInt() == 0)
1324 return TryResult(
true);
1328 bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) {
1338 TryResult tryEvaluateBool(Expr *S) {
1343 if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
1344 if (Bop->isLogicalOp() || Bop->isEqualityOp()) {
1346 CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S);
1347 if (I != CachedBoolEvals.end())
1351 TryResult
Result = evaluateAsBooleanConditionNoCache(S);
1352 CachedBoolEvals[S] =
Result;
1356 switch (Bop->getOpcode()) {
1364 Expr::EvalResult LHSResult;
1365 if (Bop->getLHS()->EvaluateAsInt(LHSResult, *Context)) {
1366 llvm::APSInt IntVal = LHSResult.
Val.
getInt();
1367 if (!IntVal.getBoolValue()) {
1368 return TryResult(
false);
1371 Expr::EvalResult RHSResult;
1372 if (Bop->getRHS()->EvaluateAsInt(RHSResult, *Context)) {
1373 llvm::APSInt IntVal = RHSResult.
Val.
getInt();
1374 if (!IntVal.getBoolValue()) {
1375 return TryResult(
false);
1384 return evaluateAsBooleanConditionNoCache(S);
1388 TryResult evaluateAsBooleanConditionNoCache(Expr *E) {
1389 if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(E)) {
1390 if (Bop->isLogicalOp()) {
1391 TryResult LHS = tryEvaluateBool(Bop->getLHS());
1392 if (LHS.isKnown()) {
1395 if (LHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1396 return LHS.isTrue();
1398 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1399 if (RHS.isKnown()) {
1400 if (Bop->getOpcode() == BO_LOr)
1401 return LHS.isTrue() || RHS.isTrue();
1403 return LHS.isTrue() && RHS.isTrue();
1406 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1407 if (RHS.isKnown()) {
1410 if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1411 return RHS.isTrue();
1413 TryResult BopRes = checkIncorrectLogicOperator(Bop);
1414 if (BopRes.isKnown())
1415 return BopRes.isTrue();
1420 }
else if (Bop->isEqualityOp()) {
1421 TryResult BopRes = checkIncorrectEqualityOperator(Bop);
1422 if (BopRes.isKnown())
1423 return BopRes.isTrue();
1424 }
else if (Bop->isRelationalOp()) {
1425 TryResult BopRes = checkIncorrectRelationalOperator(Bop);
1426 if (BopRes.isKnown())
1427 return BopRes.isTrue();
1428 }
else if (Bop->getOpcode() == BO_Or) {
1429 TryResult BopRes = checkIncorrectBitwiseOrOperator(Bop);
1430 if (BopRes.isKnown())
1431 return BopRes.isTrue();
1442 bool hasTrivialDestructor(
const VarDecl *VD)
const;
1443 bool needsAutomaticDestruction(
const VarDecl *VD)
const;
1454 while (
const auto *E = dyn_cast<ArrayInitLoopExpr>(AILEInit))
1455 AILEInit = E->getSubExpr();
1460inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
1462 return builder.alwaysAdd(
stmt) ||
kind == AlwaysAdd;
1465bool CFGBuilder::alwaysAdd(
const Stmt *
stmt) {
1471 if (lastLookup ==
stmt) {
1473 assert(cachedEntry->first ==
stmt);
1486 assert(!cachedEntry);
1490 CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(
stmt);
1491 if (itr == fb->end()) {
1492 cachedEntry =
nullptr;
1496 cachedEntry = &*itr;
1503 while (
const ArrayType *vt = dyn_cast<ArrayType>(t)) {
1505 if (vat->getSizeExpr())
1508 t = vt->getElementType().getTypePtr();
1514void CFGBuilder::consumeConstructionContext(
1515 const ConstructionContextLayer *Layer, Expr *E) {
1518 if (
const ConstructionContextLayer *PreviouslyStoredLayer =
1519 ConstructionContextMap.lookup(E)) {
1520 (void)PreviouslyStoredLayer;
1523 assert(PreviouslyStoredLayer->isStrictlyMoreSpecificThan(Layer) &&
1524 "Already within a different construction context!");
1526 ConstructionContextMap[E] = Layer;
1530void CFGBuilder::findConstructionContexts(
1531 const ConstructionContextLayer *Layer, Stmt *Child) {
1538 auto withExtraLayer = [
this, Layer](
const ConstructionContextItem &Item) {
1543 switch(Child->getStmtClass()) {
1544 case Stmt::CXXConstructExprClass:
1545 case Stmt::CXXTemporaryObjectExprClass: {
1549 findConstructionContexts(withExtraLayer(CE), CE->
getArg(0));
1552 consumeConstructionContext(Layer, CE);
1558 case Stmt::CallExprClass:
1559 case Stmt::CXXMemberCallExprClass:
1560 case Stmt::CXXOperatorCallExprClass:
1561 case Stmt::UserDefinedLiteralClass:
1562 case Stmt::ObjCMessageExprClass: {
1565 consumeConstructionContext(Layer, E);
1568 case Stmt::ExprWithCleanupsClass: {
1570 findConstructionContexts(Layer, Cleanups->getSubExpr());
1573 case Stmt::CXXFunctionalCastExprClass: {
1575 findConstructionContexts(Layer,
Cast->getSubExpr());
1578 case Stmt::ImplicitCastExprClass: {
1581 switch (
Cast->getCastKind()) {
1583 case CK_ConstructorConversion:
1584 findConstructionContexts(Layer,
Cast->getSubExpr());
1591 case Stmt::CXXBindTemporaryExprClass: {
1593 findConstructionContexts(withExtraLayer(BTE), BTE->getSubExpr());
1596 case Stmt::MaterializeTemporaryExprClass: {
1604 findConstructionContexts(withExtraLayer(MTE), MTE->getSubExpr());
1608 case Stmt::ConditionalOperatorClass: {
1616 assert(!CO->getType()->getAsCXXRecordDecl() || CO->isGLValue() ||
1620 findConstructionContexts(Layer, CO->getLHS());
1621 findConstructionContexts(Layer, CO->getRHS());
1624 case Stmt::InitListExprClass: {
1626 if (ILE->isTransparent()) {
1627 findConstructionContexts(Layer, ILE->getInit(0));
1633 case Stmt::ParenExprClass: {
1637 findConstructionContexts(Layer, PE->getSubExpr());
1645void CFGBuilder::cleanupConstructionContext(Expr *E) {
1647 "We should not be managing construction contexts!");
1648 assert(ConstructionContextMap.count(E) &&
1649 "Cannot exit construction context without the context!");
1650 ConstructionContextMap.erase(E);
1658std::unique_ptr<CFG> CFGBuilder::buildCFG(
const Decl *D, Stmt *Statement) {
1666 Succ = createBlock();
1667 assert(Succ == &cfg->getExit());
1671 LocalScope *paramScope =
nullptr;
1672 if (
const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
1673 for (ParmVarDecl *PD : FD->parameters())
1674 paramScope = addLocalScopeForVarDecl(PD, paramScope);
1677 if (
const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
1678 addImplicitDtorsForDestructor(DD);
1681 CFGBlock *B = addStmt(Statement);
1698 if (
const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) {
1699 CFGBlock *VBaseSucc =
nullptr;
1700 for (
auto *I : llvm::reverse(CD->inits())) {
1702 I->isBaseInitializer() && I->isBaseVirtual()) {
1706 VBaseSucc = Succ = B ? B : &cfg->getExit();
1707 Block = createBlock();
1709 B = addInitializer(I);
1719 addSuccessor(B,
Block,
true);
1728 for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
1729 E = BackpatchBlocks.end(); I != E; ++I ) {
1731 CFGBlock *B = I->block;
1733 LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
1736 if (LI == LabelMap.end())
1738 JumpTarget JT = LI->second;
1740 CFGBlock *SuccBlk = createScopeChangesHandlingBlock(
1741 I->scopePosition, B, JT.scopePosition, JT.block);
1742 addSuccessor(B, SuccBlk);
1743 }
else if (
auto *G = dyn_cast<GCCAsmStmt>(B->
getTerminator())) {
1744 CFGBlock *Successor = (I+1)->block;
1745 for (
auto *L : G->labels()) {
1746 LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
1749 if (LI == LabelMap.end())
1751 JumpTarget JT = LI->second;
1753 if (JT.block == Successor)
1755 addSuccessor(B, JT.block);
1762 if (CFGBlock *B = cfg->getIndirectGotoBlock())
1763 for (LabelDecl *LD : AddressTakenLabels) {
1765 LabelMapTy::iterator LI = LabelMap.find(LD);
1769 if (LI == LabelMap.end())
continue;
1771 addSuccessor(B, LI->second.block);
1775 cfg->setEntry(createBlock());
1778 assert(ConstructionContextMap.empty() &&
1779 "Not all construction contexts were cleaned up!");
1781 return std::move(cfg);
1786CFGBlock *CFGBuilder::createBlock(
bool add_successor) {
1787 CFGBlock *B = cfg->createBlock();
1788 if (add_successor && Succ)
1789 addSuccessor(B, Succ);
1796CFGBlock *CFGBuilder::createNoReturnBlock() {
1797 CFGBlock *B = createBlock(
false);
1799 addSuccessor(B, &cfg->getExit(), Succ);
1804CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
1808 bool HasTemporaries =
false;
1818 TempDtorContext Context;
1825 appendInitializer(
Block, I);
1831 dyn_cast<ArrayInitLoopExpr>(
Init));
1833 findConstructionContexts(
1835 AILEInit ? AILEInit :
Init);
1837 if (HasTemporaries) {
1843 if (CXXDefaultInitExpr *
Default = dyn_cast<CXXDefaultInitExpr>(
Init)) {
1849 if (Stmt *Child =
Default->getExpr())
1850 if (CFGBlock *R = Visit(Child))
1864 bool *FoundMTE =
nullptr) {
1871 Init = EWC->getSubExpr();
1877 = dyn_cast<MaterializeTemporaryExpr>(
Init)) {
1878 Init = MTE->getSubExpr();
1885 const Expr *SkippedInit =
Init->skipRValueSubobjectAdjustments();
1886 if (SkippedInit !=
Init) {
1894 return Init->getType();
1899void CFGBuilder::addLoopExit(
const Stmt *LoopStmt){
1903 appendLoopExit(
Block, LoopStmt);
1911void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
1912 LocalScope::const_iterator E,
1922 if (B.inSameLocalScope(E)) {
1923 addAutomaticObjDestruction(B, E, S);
1928 SmallVector<LocalScope::const_iterator, 10> LocalScopeEndMarkers;
1929 LocalScopeEndMarkers.push_back(B);
1930 for (LocalScope::const_iterator I = B; I != E; ++I) {
1931 if (!I.inSameLocalScope(LocalScopeEndMarkers.back()))
1932 LocalScopeEndMarkers.push_back(I);
1934 LocalScopeEndMarkers.push_back(E);
1938 std::reverse(LocalScopeEndMarkers.begin(), LocalScopeEndMarkers.end());
1940 llvm::zip(LocalScopeEndMarkers, llvm::drop_begin(LocalScopeEndMarkers));
1941 for (
auto [E, B] : Pairwise) {
1942 if (!B.inSameLocalScope(E))
1943 addScopeExitHandling(B, E, S);
1944 addAutomaticObjDestruction(B, E, S);
1951void CFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
1952 LocalScope::const_iterator E,
1960 SmallVector<VarDecl *, 10> DeclsNeedDestruction;
1961 DeclsNeedDestruction.reserve(B.distance(E));
1963 for (VarDecl* D : llvm::make_range(B, E))
1964 if (needsAutomaticDestruction(D))
1965 DeclsNeedDestruction.push_back(D);
1967 for (VarDecl *VD : llvm::reverse(DeclsNeedDestruction)) {
1980 Block = createNoReturnBlock();
1989 appendLifetimeEnds(
Block, VD, S);
1991 appendAutomaticObjDtor(
Block, VD, S);
1992 if (VD->
hasAttr<CleanupAttr>())
1993 appendCleanupFunction(
Block, VD);
2002void CFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
2003 LocalScope::const_iterator E, Stmt *S) {
2004 assert(!B.inSameLocalScope(E));
2010 appendScopeEnd(
Block, B.getFirstVarInScope(), S);
2017 SmallVector<VarDecl *, 10> DeclsTrivial;
2018 DeclsTrivial.reserve(B.distance(E));
2023 for (VarDecl* D : llvm::make_range(B, E))
2024 if (!needsAutomaticDestruction(D))
2025 DeclsTrivial.push_back(D);
2027 if (DeclsTrivial.empty())
2031 for (VarDecl *VD : llvm::reverse(DeclsTrivial))
2032 appendLifetimeEnds(
Block, VD, S);
2040void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
2041 LocalScope::const_iterator DstPos,
2043 assert(
Block &&
"Source block should be always crated");
2049 if (SrcPos == DstPos)
2054 LocalScope::const_iterator BasePos = SrcPos.shared_parent(DstPos);
2057 if (BuildOpts.
AddScopes && !DstPos.inSameLocalScope(BasePos)) {
2058 for (LocalScope::const_iterator I = DstPos; I != BasePos; ++I)
2059 if (I.pointsToFirstDeclaredVar())
2060 appendScopeBegin(
Block, *I, S);
2065 addAutomaticObjHandling(SrcPos, BasePos, S);
2073CFGBlock *CFGBuilder::createScopeChangesHandlingBlock(
2074 LocalScope::const_iterator SrcPos, CFGBlock *SrcBlk,
2075 LocalScope::const_iterator DstPos, CFGBlock *DstBlk) {
2076 if (SrcPos == DstPos)
2080 (!BuildOpts.
AddScopes || SrcPos.inSameLocalScope(DstPos)))
2085 SaveAndRestore save_Block(
Block), save_Succ(Succ);
2088 Block = createBlock(
false);
2091 addSuccessor(
Block, DstBlk);
2094 addScopeChangesHandling(SrcPos, DstPos,
Block->getTerminatorStmt());
2096 assert(
Block &&
"There should be at least one scope changing Block");
2102void CFGBuilder::addImplicitDtorsForDestructor(
const CXXDestructorDecl *DD) {
2104 "Can be called only when dtors should be added");
2105 const CXXRecordDecl *RD = DD->
getParent();
2108 for (
const auto &VI : RD->
vbases()) {
2112 const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
2115 appendBaseDtor(
Block, &VI);
2120 for (
const auto &BI : RD->
bases()) {
2121 if (!BI.isVirtual()) {
2122 const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
2125 appendBaseDtor(
Block, &BI);
2133 for (
auto *FI : RD->
fields()) {
2135 QualType QT = FI->getType();
2138 if (AT->isZeroSize())
2140 QT = AT->getElementType();
2146 appendMemberDtor(
Block, FI);
2153LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) {
2156 llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
2157 return new (alloc) LocalScope(BumpVectorContext(alloc), ScopePos);
2162void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
2167 LocalScope *Scope =
nullptr;
2171 for (
auto *BI : CS->body()) {
2172 Stmt *SI = BI->stripLabelLikeStatements();
2173 if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
2174 Scope = addLocalScopeForDeclStmt(DS, Scope);
2182 addLocalScopeForDeclStmt(DS);
2187LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
2188 LocalScope* Scope) {
2193 for (
auto *DI : DS->
decls())
2194 if (VarDecl *VD = dyn_cast<VarDecl>(DI))
2195 Scope = addLocalScopeForVarDecl(VD, Scope);
2199bool CFGBuilder::needsAutomaticDestruction(
const VarDecl *VD)
const {
2200 return !hasTrivialDestructor(VD) || VD->
hasAttr<CleanupAttr>();
2203bool CFGBuilder::hasTrivialDestructor(
const VarDecl *VD)
const {
2224 bool FoundMTE =
false;
2232 if (AT->isZeroSize())
2234 QT = AT->getElementType();
2246LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
2247 LocalScope* Scope) {
2262 !needsAutomaticDestruction(VD)) {
2268 Scope = createOrReuseLocalScope(Scope);
2270 ScopePos = Scope->begin();
2276void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
2277 LocalScope::const_iterator scopeBeginPos = ScopePos;
2278 addLocalScopeForStmt(S);
2279 addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
2285CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
2286 bool ExternallyDestructed) {
2292 if (Expr *E = dyn_cast<Expr>(S))
2293 S = E->IgnoreParens();
2296 if (
auto *D = dyn_cast<OMPExecutableDirective>(S))
2297 return VisitOMPExecutableDirective(D, asc);
2301 return VisitStmt(S, asc);
2303 case Stmt::ImplicitValueInitExprClass:
2306 return VisitStmt(S, asc);
2308 case Stmt::InitListExprClass:
2311 case Stmt::AttributedStmtClass:
2314 case Stmt::AddrLabelExprClass:
2317 case Stmt::BinaryConditionalOperatorClass:
2320 case Stmt::BinaryOperatorClass:
2323 case Stmt::BlockExprClass:
2326 case Stmt::BreakStmtClass:
2329 case Stmt::CallExprClass:
2330 case Stmt::CXXOperatorCallExprClass:
2331 case Stmt::CXXMemberCallExprClass:
2332 case Stmt::UserDefinedLiteralClass:
2335 case Stmt::CaseStmtClass:
2338 case Stmt::ChooseExprClass:
2341 case Stmt::CompoundStmtClass:
2344 case Stmt::ConditionalOperatorClass:
2347 case Stmt::ContinueStmtClass:
2350 case Stmt::CXXCatchStmtClass:
2353 case Stmt::ExprWithCleanupsClass:
2355 asc, ExternallyDestructed);
2357 case Stmt::CXXDefaultArgExprClass:
2358 case Stmt::CXXDefaultInitExprClass:
2367 return VisitStmt(S, asc);
2369 case Stmt::CXXBindTemporaryExprClass:
2372 case Stmt::CXXConstructExprClass:
2375 case Stmt::CXXNewExprClass:
2378 case Stmt::CXXDeleteExprClass:
2381 case Stmt::CXXFunctionalCastExprClass:
2384 case Stmt::CXXTemporaryObjectExprClass:
2387 case Stmt::CXXThrowExprClass:
2390 case Stmt::CXXTryStmtClass:
2393 case Stmt::CXXTypeidExprClass:
2396 case Stmt::CXXForRangeStmtClass:
2399 case Stmt::DeclStmtClass:
2402 case Stmt::DefaultStmtClass:
2405 case Stmt::DoStmtClass:
2408 case Stmt::ForStmtClass:
2411 case Stmt::GotoStmtClass:
2414 case Stmt::GCCAsmStmtClass:
2417 case Stmt::IfStmtClass:
2420 case Stmt::ImplicitCastExprClass:
2423 case Stmt::ConstantExprClass:
2426 case Stmt::IndirectGotoStmtClass:
2429 case Stmt::LabelStmtClass:
2432 case Stmt::LambdaExprClass:
2435 case Stmt::MaterializeTemporaryExprClass:
2439 case Stmt::MemberExprClass:
2442 case Stmt::NullStmtClass:
2445 case Stmt::ObjCAtCatchStmtClass:
2448 case Stmt::ObjCAutoreleasePoolStmtClass:
2451 case Stmt::ObjCAtSynchronizedStmtClass:
2454 case Stmt::ObjCAtThrowStmtClass:
2457 case Stmt::ObjCAtTryStmtClass:
2460 case Stmt::ObjCForCollectionStmtClass:
2463 case Stmt::ObjCMessageExprClass:
2466 case Stmt::OpaqueValueExprClass:
2469 case Stmt::PseudoObjectExprClass:
2472 case Stmt::ReturnStmtClass:
2473 case Stmt::CoreturnStmtClass:
2474 return VisitReturnStmt(S);
2476 case Stmt::CoyieldExprClass:
2477 case Stmt::CoawaitExprClass:
2480 case Stmt::SEHExceptStmtClass:
2483 case Stmt::SEHFinallyStmtClass:
2486 case Stmt::SEHLeaveStmtClass:
2489 case Stmt::SEHTryStmtClass:
2492 case Stmt::UnaryExprOrTypeTraitExprClass:
2496 case Stmt::StmtExprClass:
2499 case Stmt::SwitchStmtClass:
2502 case Stmt::UnaryOperatorClass:
2505 case Stmt::WhileStmtClass:
2508 case Stmt::ArrayInitLoopExprClass:
2513CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
2514 if (asc.alwaysAdd(*
this, S)) {
2516 appendStmt(
Block, S);
2519 return VisitChildren(S);
2523CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
2524 CFGBlock *B =
Block;
2528 reverse_children RChildren(S, *Context);
2529 for (Stmt *Child : RChildren) {
2531 if (CFGBlock *R = Visit(Child))
2537CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) {
2538 if (asc.alwaysAdd(*
this, ILE)) {
2540 appendStmt(
Block, ILE);
2542 CFGBlock *B =
Block;
2544 reverse_children RChildren(ILE, *Context);
2545 for (Stmt *Child : RChildren) {
2548 if (CFGBlock *R = Visit(Child))
2551 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(Child))
2552 if (Stmt *Child = DIE->getExpr())
2553 if (CFGBlock *R = Visit(Child))
2560CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
2561 AddStmtChoice asc) {
2562 AddressTakenLabels.insert(A->
getLabel());
2564 if (asc.alwaysAdd(*
this, A)) {
2566 appendStmt(
Block, A);
2575 "expected fallthrough not to have children");
2576 return isFallthrough;
2583 "expected [[assume]] not to have children");
2584 return hasAssumeAttr;
2587CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
2588 AddStmtChoice asc) {
2598 if (isInterestingAttribute && asc.alwaysAdd(*
this, A)) {
2600 appendStmt(
Block, A);
2603 return VisitChildren(A);
2606CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc) {
2607 if (asc.alwaysAdd(*
this, U)) {
2609 appendStmt(
Block, U);
2615 return Visit(U->
getSubExpr(), AddStmtChoice());
2618CFGBlock *CFGBuilder::VisitLogicalOperator(BinaryOperator *B) {
2619 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2620 appendStmt(ConfluenceBlock, B);
2625 return VisitLogicalOperator(B,
nullptr, ConfluenceBlock,
2626 ConfluenceBlock).first;
2629std::pair<CFGBlock*, CFGBlock*>
2630CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
2632 CFGBlock *TrueBlock,
2633 CFGBlock *FalseBlock) {
2638 CFGBlock *RHSBlock, *ExitBlock;
2641 if (BinaryOperator *B_RHS = dyn_cast<BinaryOperator>(RHS))
2642 if (B_RHS->isLogicalOp()) {
2643 std::tie(RHSBlock, ExitBlock) =
2644 VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
2652 ExitBlock = RHSBlock = createBlock(
false);
2657 TryResult KnownVal = tryEvaluateBool(RHS);
2658 if (!KnownVal.isKnown())
2659 KnownVal = tryEvaluateBool(B);
2662 assert(TrueBlock == FalseBlock);
2663 addSuccessor(RHSBlock, TrueBlock);
2667 addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
2668 addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
2672 RHSBlock = addStmt(RHS);
2677 return std::make_pair(
nullptr,
nullptr);
2682 if (BinaryOperator *B_LHS = dyn_cast<BinaryOperator>(LHS))
2683 if (B_LHS->isLogicalOp()) {
2685 FalseBlock = RHSBlock;
2687 TrueBlock = RHSBlock;
2692 return VisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock);
2697 CFGBlock *LHSBlock = createBlock(
false);
2701 CFGBlock *EntryLHSBlock = addStmt(LHS);
2704 return std::make_pair(
nullptr,
nullptr);
2707 TryResult KnownVal = tryEvaluateBool(LHS);
2711 addSuccessor(LHSBlock, TrueBlock, !KnownVal.isFalse());
2712 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isTrue());
2715 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isFalse());
2716 addSuccessor(LHSBlock, FalseBlock, !KnownVal.isTrue());
2719 return std::make_pair(EntryLHSBlock, ExitBlock);
2722CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
2723 AddStmtChoice asc) {
2726 return VisitLogicalOperator(B);
2730 appendStmt(
Block, B);
2732 return addStmt(B->
getLHS());
2736 if (asc.alwaysAdd(*
this, B)) {
2738 appendStmt(
Block, B);
2741 return Visit(B->
getRHS());
2744 if (asc.alwaysAdd(*
this, B)) {
2746 appendStmt(
Block, B);
2752 CFGBlock *RBlock = Visit(B->
getRHS());
2753 CFGBlock *LBlock = Visit(B->
getLHS());
2757 return (LBlock ? LBlock : RBlock);
2760CFGBlock *CFGBuilder::VisitNoRecurse(Expr *E, AddStmtChoice asc) {
2761 if (asc.alwaysAdd(*
this, E)) {
2763 appendStmt(
Block, E);
2768CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
2775 Block = createBlock(
false);
2776 Block->setTerminator(B);
2780 if (BreakJumpTarget.block) {
2781 addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
2782 addSuccessor(
Block, BreakJumpTarget.block);
2807 if (BuiltinID != Builtin::BI__assume &&
2808 BuiltinID != Builtin::BI__builtin_assume)
2814CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *
C, AddStmtChoice asc) {
2816 QualType calleeType =
C->getCallee()->getType();
2822 if (!boundType.
isNull()) calleeType = boundType;
2828 bool AddEHEdge =
false;
2838 bool OmitArguments =
false;
2840 if (FunctionDecl *FD =
C->getDirectCallee()) {
2845 if (!FD->isVariadic())
2846 findConstructionContextsForArguments(
C);
2848 if (FD->isNoReturn() || FD->isAnalyzerNoReturn() ||
2849 C->isBuiltinAssumeFalse(*Context))
2851 if (FD->
hasAttr<NoThrowAttr>())
2854 FD->getBuiltinID() == Builtin::BI__builtin_object_size ||
2855 FD->getBuiltinID() == Builtin::BI__builtin_dynamic_object_size)
2856 OmitArguments =
true;
2859 if (!
CanThrow(
C->getCallee(), *Context))
2862 if (OmitArguments) {
2863 assert(!NoReturn &&
"noreturn calls with unevaluated args not implemented");
2864 assert(!AddEHEdge &&
"EH calls with unevaluated args not implemented");
2867 return Visit(
C->getCallee());
2870 if (!NoReturn && !AddEHEdge) {
2874 return VisitChildren(
C);
2884 Block = createNoReturnBlock();
2886 Block = createBlock();
2892 if (TryTerminatedBlock)
2893 addSuccessor(
Block, TryTerminatedBlock);
2895 addSuccessor(
Block, &cfg->getExit());
2898 return VisitChildren(
C);
2901CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *
C,
2902 AddStmtChoice asc) {
2903 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2904 appendStmt(ConfluenceBlock,
C);
2908 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2909 Succ = ConfluenceBlock;
2911 CFGBlock *LHSBlock = Visit(
C->getLHS(), alwaysAdd);
2915 Succ = ConfluenceBlock;
2917 CFGBlock *RHSBlock = Visit(
C->getRHS(), alwaysAdd);
2921 Block = createBlock(
false);
2923 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2924 addSuccessor(
Block, KnownVal.isFalse() ?
nullptr : LHSBlock);
2925 addSuccessor(
Block, KnownVal.isTrue() ?
nullptr : RHSBlock);
2927 return addStmt(
C->getCond());
2931 bool ExternallyDestructed) {
2932 LocalScope::const_iterator scopeBeginPos = ScopePos;
2933 addLocalScopeForStmt(
C);
2938 addAutomaticObjHandling(ScopePos, scopeBeginPos,
C);
2941 CFGBlock *LastBlock =
Block;
2943 for (Stmt *S : llvm::reverse(
C->body())) {
2946 CFGBlock *newBlock = Visit(S, AddStmtChoice::AlwaysAdd,
2947 ExternallyDestructed);
2950 LastBlock = newBlock;
2955 ExternallyDestructed =
false;
2961CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *
C,
2962 AddStmtChoice asc) {
2963 const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(
C);
2964 const OpaqueValueExpr *opaqueValue = (BCO ? BCO->
getOpaqueValue() :
nullptr);
2968 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2969 appendStmt(ConfluenceBlock,
C);
2973 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2979 Succ = ConfluenceBlock;
2981 CFGBlock *LHSBlock =
nullptr;
2982 const Expr *trueExpr =
C->getTrueExpr();
2983 if (trueExpr != opaqueValue) {
2984 LHSBlock = Visit(
C->getTrueExpr(), alwaysAdd);
2990 LHSBlock = ConfluenceBlock;
2993 Succ = ConfluenceBlock;
2994 CFGBlock *RHSBlock = Visit(
C->getFalseExpr(), alwaysAdd);
2999 if (BinaryOperator *
Cond =
3000 dyn_cast<BinaryOperator>(
C->getCond()->IgnoreParens()))
3001 if (
Cond->isLogicalOp())
3002 return VisitLogicalOperator(
Cond,
C, LHSBlock, RHSBlock).first;
3005 Block = createBlock(
false);
3008 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
3009 addSuccessor(
Block, LHSBlock, !KnownVal.isFalse());
3010 addSuccessor(
Block, RHSBlock, !KnownVal.isTrue());
3012 Expr *condExpr =
C->getCond();
3017 if (condExpr != opaqueValue)
3025 return addStmt(condExpr);
3028CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
3036 return VisitDeclSubExpr(DS);
3038 CFGBlock *B =
nullptr;
3047 DeclGroupRef DG(*I);
3050 cfg->addSyntheticDeclStmt(DSNew, DS);
3053 B = VisitDeclSubExpr(DSNew);
3061CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
3062 assert(DS->
isSingleDecl() &&
"Can handle single declarations only.");
3064 if (
const auto *TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl())) {
3066 const Type *
T = TND->getUnderlyingType().getTypePtr();
3071 appendStmt(
Block, DS);
3073 CFGBlock *LastBlock =
Block;
3074 for (
const VariableArrayType *VA =
FindVA(
T); VA !=
nullptr;
3075 VA =
FindVA(VA->getElementType().getTypePtr())) {
3076 if (CFGBlock *NewBlock = addStmt(VA->getSizeExpr()))
3077 LastBlock = NewBlock;
3090 bool HasTemporaries =
false;
3093 CFGBlock *blockAfterStaticInit =
nullptr;
3104 blockAfterStaticInit = Succ;
3115 TempDtorContext Context;
3123 if (
const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
3124 for (
auto *BD : llvm::reverse(DD->bindings())) {
3125 if (
auto *VD = BD->getHoldingVar()) {
3126 DeclGroupRef DG(VD);
3129 cfg->addSyntheticDeclStmt(DSNew, DS);
3130 Block = VisitDeclSubExpr(DSNew);
3136 appendStmt(
Block, DS);
3140 const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(
Init);
3142 findConstructionContexts(
3144 AILE ? AILE->getSubExpr() :
Init);
3149 CFGBlock *LastBlock =
Block;
3152 if (HasTemporaries) {
3156 if (CFGBlock *newBlock = Visit(EC->
getSubExpr()))
3157 LastBlock = newBlock;
3160 if (CFGBlock *newBlock = Visit(
Init))
3161 LastBlock = newBlock;
3169 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr())) {
3170 if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
3171 LastBlock = newBlock;
3174 maybeAddScopeBeginForVarDecl(
Block, VD, DS);
3177 if (ScopePos && VD == *ScopePos)
3180 CFGBlock *B = LastBlock;
3181 if (blockAfterStaticInit) {
3183 Block = createBlock(
false);
3184 Block->setTerminator(DS);
3185 addSuccessor(
Block, blockAfterStaticInit);
3186 addSuccessor(
Block, B);
3193CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
3203 SaveAndRestore save_scope_pos(ScopePos);
3207 addLocalScopeForStmt(
Init);
3212 addLocalScopeForVarDecl(VD);
3214 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
3225 CFGBlock *ElseBlock = Succ;
3227 if (Stmt *Else = I->
getElse()) {
3228 SaveAndRestore sv(Succ);
3237 addLocalScopeAndDtors(Else);
3239 ElseBlock = addStmt(Else);
3242 ElseBlock = sv.get();
3250 CFGBlock *ThenBlock;
3254 SaveAndRestore sv(Succ);
3260 addLocalScopeAndDtors(Then);
3262 ThenBlock = addStmt(Then);
3268 ThenBlock = createBlock(
false);
3269 addSuccessor(ThenBlock, sv.get());
3283 BinaryOperator *
Cond =
3287 CFGBlock *LastBlock;
3289 LastBlock = VisitLogicalOperator(
Cond, I, ThenBlock, ElseBlock).first;
3292 Block = createBlock(
false);
3295 Block->setTerminator(I);
3300 KnownVal = tryEvaluateBool(I->
getCond());
3304 addSuccessor(
Block, ThenBlock, !KnownVal.isFalse());
3305 addSuccessor(
Block, ElseBlock, !KnownVal.isTrue());
3313 LastBlock = addStmt(I->
getCond());
3319 LastBlock = addStmt(
const_cast<DeclStmt *
>(DS));
3326 LastBlock = addStmt(
Init);
3332CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {
3342 Block = createBlock(
false);
3344 addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), S);
3346 if (
auto *R = dyn_cast<ReturnStmt>(S))
3347 findConstructionContexts(
3353 if (!
Block->hasNoReturnElement())
3354 addSuccessor(
Block, &cfg->getExit());
3357 appendStmt(
Block, S);
3360 if (ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
3361 if (Expr *O = RS->getRetValue())
3362 return Visit(O, AddStmtChoice::AlwaysAdd,
true);
3374 if (CFGBlock *R = Visit(RV))
3380CFGBlock *CFGBuilder::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E,
3381 AddStmtChoice asc) {
3385 if (asc.alwaysAdd(*
this, E)) {
3387 appendStmt(
Block, E);
3389 CFGBlock *B =
Block;
3401CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
3407 SaveAndRestore save_scope_pos(ScopePos);
3410 CFGBlock *SEHExceptBlock =
Block;
3411 if (!SEHExceptBlock)
3412 SEHExceptBlock = createBlock();
3414 appendStmt(SEHExceptBlock, ES);
3426 return SEHExceptBlock;
3429CFGBlock *CFGBuilder::VisitSEHFinallyStmt(SEHFinallyStmt *FS) {
3430 return VisitCompoundStmt(FS->
getBlock(),
false);
3433CFGBlock *CFGBuilder::VisitSEHLeaveStmt(SEHLeaveStmt *LS) {
3440 Block = createBlock(
false);
3441 Block->setTerminator(LS);
3445 if (SEHLeaveJumpTarget.block) {
3446 addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS);
3447 addSuccessor(
Block, SEHLeaveJumpTarget.block);
3454CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) {
3457 CFGBlock *SEHTrySuccessor =
nullptr;
3462 SEHTrySuccessor =
Block;
3463 }
else SEHTrySuccessor = Succ;
3469 CFGBlock *PrevSEHTryTerminatedBlock = TryTerminatedBlock;
3472 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
3479 Succ = SEHTrySuccessor;
3481 CFGBlock *ExceptBlock = VisitSEHExceptStmt(Except);
3486 addSuccessor(NewTryTerminatedBlock, ExceptBlock);
3488 if (PrevSEHTryTerminatedBlock)
3489 addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock);
3491 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
3494 Succ = SEHTrySuccessor;
3497 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
3498 cfg->addTryDispatchBlock(TryTerminatedBlock);
3503 SaveAndRestore save_break(SEHLeaveJumpTarget);
3504 SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
3506 assert(Terminator->
getTryBlock() &&
"__try must contain a non-NULL body");
3511CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
3514 CFGBlock *LabelBlock =
Block;
3517 LabelBlock = createBlock();
3519 assert(!LabelMap.contains(L->
getDecl()) &&
"label already in map");
3520 LabelMap[L->
getDecl()] = JumpTarget(LabelBlock, ScopePos);
3539CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
3540 CFGBlock *LastBlock = VisitNoRecurse(E, asc);
3542 if (Expr *CopyExpr = CI.getCopyExpr()) {
3543 CFGBlock *Tmp = Visit(CopyExpr);
3551CFGBlock *CFGBuilder::VisitLambdaExpr(
LambdaExpr *E, AddStmtChoice asc) {
3552 CFGBlock *LastBlock = VisitNoRecurse(E, asc);
3557 it != et; ++it, ++Idx) {
3558 if (Expr *
Init = *it) {
3562 dyn_cast<ArrayInitLoopExpr>(
Init));
3565 cfg->getBumpVectorContext(), {E, Idx}),
3566 AILEInit ? AILEInit :
Init);
3568 CFGBlock *Tmp = Visit(
Init);
3576CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
3580 Block = createBlock(
false);
3581 Block->setTerminator(G);
3584 LabelMapTy::iterator I = LabelMap.find(G->
getLabel());
3586 if (I == LabelMap.end())
3588 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3590 JumpTarget JT = I->second;
3591 addSuccessor(
Block, JT.block);
3592 addScopeChangesHandling(ScopePos, JT.scopePosition, G);
3598CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) {
3603 return VisitStmt(G, asc);
3610 Block = createBlock();
3611 Block->setTerminator(G);
3613 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3616 BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
3617 return VisitChildren(G);
3620CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
3621 CFGBlock *LoopSuccessor =
nullptr;
3625 SaveAndRestore save_scope_pos(ScopePos);
3631 addLocalScopeForStmt(
Init);
3632 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3635 addLocalScopeForVarDecl(VD);
3636 LocalScope::const_iterator ContinueScopePos = ScopePos;
3638 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
3647 LoopSuccessor =
Block;
3649 LoopSuccessor = Succ;
3653 SaveAndRestore save_break(BreakJumpTarget);
3654 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3656 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3663 SaveAndRestore save_Block(
Block), save_Succ(Succ);
3664 SaveAndRestore save_continue(ContinueJumpTarget);
3669 Block = Succ = TransitionBlock = createBlock(
false);
3670 TransitionBlock->setLoopTarget(F);
3675 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
3677 if (Stmt *I = F->
getInc()) {
3685 assert(
Block == Succ);
3693 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
3694 ContinueJumpTarget.block->setLoopTarget(F);
3700 addLocalScopeAndDtors(F->
getBody());
3704 BodyBlock = addStmt(F->
getBody());
3709 BodyBlock = ContinueJumpTarget.block;
3718 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3722 SaveAndRestore save_scope_pos(ScopePos);
3726 if (BinaryOperator *
Cond =
3727 dyn_cast_or_null<BinaryOperator>(
C ?
C->IgnoreParens() :
nullptr))
3728 if (
Cond->isLogicalOp()) {
3729 std::tie(EntryConditionBlock, ExitConditionBlock) =
3730 VisitLogicalOperator(
Cond, F, BodyBlock, LoopSuccessor);
3735 EntryConditionBlock = ExitConditionBlock = createBlock(
false);
3736 ExitConditionBlock->setTerminator(F);
3739 TryResult KnownVal(
true);
3745 Block = ExitConditionBlock;
3746 EntryConditionBlock = addStmt(
C);
3755 findConstructionContexts(
3758 appendStmt(
Block, DS);
3759 EntryConditionBlock = addStmt(
Init);
3760 assert(
Block == EntryConditionBlock);
3761 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3765 if (
Block && badCFG)
3768 KnownVal = tryEvaluateBool(
C);
3772 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
3775 addSuccessor(ExitConditionBlock,
3776 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
3780 addSuccessor(TransitionBlock, EntryConditionBlock);
3783 Succ = EntryConditionBlock;
3788 SaveAndRestore save_scope_pos(ScopePos);
3789 ScopePos = LoopBeginScopePos;
3790 Block = createBlock();
3797 Succ = EntryConditionBlock;
3798 return EntryConditionBlock;
3802CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
3803 AddStmtChoice asc) {
3804 findConstructionContexts(
3808 return VisitStmt(MTE, asc);
3811CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
3812 if (asc.alwaysAdd(*
this, M)) {
3814 appendStmt(
Block, M);
3819CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
3851 CFGBlock *LoopSuccessor =
nullptr;
3856 LoopSuccessor =
Block;
3859 LoopSuccessor = Succ;
3862 CFGBlock *ExitConditionBlock = createBlock(
false);
3870 appendStmt(ExitConditionBlock, S);
3871 Block = ExitConditionBlock;
3876 CFGBlock *EntryConditionBlock = Visit(S->
getElement(),
3877 AddStmtChoice::NotAlwaysAdd);
3886 Succ = EntryConditionBlock;
3891 SaveAndRestore save_Block(
Block), save_Succ(Succ);
3892 SaveAndRestore save_continue(ContinueJumpTarget),
3893 save_break(BreakJumpTarget);
3898 CFGBlock *LoopBackBlock =
nullptr;
3899 Succ = LoopBackBlock = createBlock();
3902 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3903 ContinueJumpTarget = JumpTarget(Succ, ScopePos);
3905 CFGBlock *BodyBlock = addStmt(S->
getBody());
3908 BodyBlock = ContinueJumpTarget.block;
3915 addSuccessor(ExitConditionBlock, BodyBlock);
3920 addSuccessor(ExitConditionBlock, LoopSuccessor);
3923 Block = createBlock();
3927CFGBlock *CFGBuilder::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
3933CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
3951 appendStmt(
Block, S);
3957CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
3961 appendStmt(
Block, E);
3963 CFGBlock *lastBlock =
Block;
3972 if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic))
3973 Semantic = OVE->getSourceExpr();
3975 if (CFGBlock *B = Visit(Semantic))
3982CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
3983 CFGBlock *LoopSuccessor =
nullptr;
3987 SaveAndRestore save_scope_pos(ScopePos);
3991 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3993 addLocalScopeForVarDecl(VD);
3994 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4003 LoopSuccessor =
Block;
4006 LoopSuccessor = Succ;
4009 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
4016 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4017 SaveAndRestore save_continue(ContinueJumpTarget),
4018 save_break(BreakJumpTarget);
4022 Succ = TransitionBlock = createBlock(
false);
4023 TransitionBlock->setLoopTarget(W);
4024 ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
4027 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4030 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4035 addLocalScopeAndDtors(W->
getBody());
4038 BodyBlock = addStmt(W->
getBody());
4041 BodyBlock = ContinueJumpTarget.block;
4042 else if (
Block && badCFG)
4049 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
4056 if (BinaryOperator *
Cond = dyn_cast<BinaryOperator>(
C->IgnoreParens()))
4057 if (
Cond->isLogicalOp()) {
4058 std::tie(EntryConditionBlock, ExitConditionBlock) =
4059 VisitLogicalOperator(
Cond, W, BodyBlock, LoopSuccessor);
4064 ExitConditionBlock = createBlock(
false);
4070 Block = ExitConditionBlock;
4071 Block = EntryConditionBlock = addStmt(
C);
4080 findConstructionContexts(
4082 const_cast<DeclStmt *
>(DS)),
4084 appendStmt(
Block, DS);
4085 EntryConditionBlock = addStmt(
Init);
4086 assert(
Block == EntryConditionBlock);
4087 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
4091 if (
Block && badCFG)
4095 const TryResult& KnownVal = tryEvaluateBool(
C);
4098 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
4101 addSuccessor(ExitConditionBlock,
4102 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4106 addSuccessor(TransitionBlock, EntryConditionBlock);
4113 Succ = EntryConditionBlock;
4114 return EntryConditionBlock;
4117CFGBlock *CFGBuilder::VisitArrayInitLoopExpr(ArrayInitLoopExpr *A,
4118 AddStmtChoice asc) {
4119 if (asc.alwaysAdd(*
this, A)) {
4121 appendStmt(
Block, A);
4124 CFGBlock *B =
Block;
4130 assert(OVE &&
"ArrayInitLoopExpr->getCommonExpr() should be wrapped in an "
4131 "OpaqueValueExpr!");
4132 if (CFGBlock *R = Visit(OVE->getSourceExpr()))
4138CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *CS) {
4144 SaveAndRestore save_scope_pos(ScopePos);
4149 CFGBlock *CatchBlock =
Block;
4151 CatchBlock = createBlock();
4153 appendStmt(CatchBlock, CS);
4168CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
4174 Block = createBlock(
false);
4176 if (TryTerminatedBlock)
4178 addSuccessor(
Block, TryTerminatedBlock);
4181 addSuccessor(
Block, &cfg->getExit());
4185 return VisitStmt(S, AddStmtChoice::AlwaysAdd);
4188CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *Terminator) {
4191 CFGBlock *TrySuccessor =
nullptr;
4196 TrySuccessor =
Block;
4198 TrySuccessor = Succ;
4204 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4207 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4211 bool HasCatchAll =
false;
4212 for (ObjCAtCatchStmt *CS : Terminator->
catch_stmts()) {
4214 Succ = TrySuccessor;
4219 CFGBlock *CatchBlock = VisitObjCAtCatchStmt(CS);
4224 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4229 if (PrevTryTerminatedBlock)
4230 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4232 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4236 Succ = TrySuccessor;
4239 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4240 cfg->addTryDispatchBlock(TryTerminatedBlock);
4242 assert(Terminator->
getTryBody() &&
"try must contain a non-NULL body");
4247CFGBlock *CFGBuilder::VisitObjCMessageExpr(ObjCMessageExpr *ME,
4248 AddStmtChoice asc) {
4249 findConstructionContextsForArguments(ME);
4252 appendObjCMessage(
Block, ME);
4254 return VisitChildren(ME);
4257CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *
T) {
4263 Block = createBlock(
false);
4265 if (TryTerminatedBlock)
4267 addSuccessor(
Block, TryTerminatedBlock);
4270 addSuccessor(
Block, &cfg->getExit());
4274 return VisitStmt(
T, AddStmtChoice::AlwaysAdd);
4277CFGBlock *CFGBuilder::VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc) {
4278 if (asc.alwaysAdd(*
this, S)) {
4280 appendStmt(
Block, S);
4290 return VisitChildren(S);
4296CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
4297 CFGBlock *LoopSuccessor =
nullptr;
4306 LoopSuccessor =
Block;
4308 LoopSuccessor = Succ;
4313 CFGBlock *ExitConditionBlock = createBlock(
false);
4314 CFGBlock *EntryConditionBlock = ExitConditionBlock;
4322 Block = ExitConditionBlock;
4323 EntryConditionBlock = addStmt(
C);
4331 Succ = EntryConditionBlock;
4334 const TryResult &KnownVal = tryEvaluateBool(D->
getCond());
4337 CFGBlock *BodyBlock =
nullptr;
4342 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4343 SaveAndRestore save_continue(ContinueJumpTarget),
4344 save_break(BreakJumpTarget);
4347 ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
4350 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4358 addLocalScopeAndDtors(D->
getBody());
4361 BodyBlock = addStmt(D->
getBody());
4364 BodyBlock = EntryConditionBlock;
4377 CFGBlock *LoopBackBlock = createBlock();
4380 if (!KnownVal.isFalse())
4382 addSuccessor(ExitConditionBlock, LoopBackBlock);
4384 addSuccessor(ExitConditionBlock,
nullptr);
4389 addSuccessor(ExitConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4400CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *
C) {
4407 Block = createBlock(
false);
4412 if (ContinueJumpTarget.block) {
4413 addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition,
C);
4414 addSuccessor(
Block, ContinueJumpTarget.block);
4421CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
4422 AddStmtChoice asc) {
4423 if (asc.alwaysAdd(*
this, E)) {
4425 appendStmt(
Block, E);
4431 if (E->
getKind() != UETT_SizeOf)
4434 CFGBlock *lastBlock =
Block;
4438 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr()))
4439 lastBlock = addStmt(VA->getSizeExpr());
4446CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
4447 if (asc.alwaysAdd(*
this, SE)) {
4449 appendStmt(
Block, SE);
4451 return VisitCompoundStmt(SE->
getSubStmt(),
true);
4454CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
4457 CFGBlock *SwitchSuccessor =
nullptr;
4461 SaveAndRestore save_scope_pos(ScopePos);
4465 addLocalScopeForStmt(
Init);
4470 addLocalScopeForVarDecl(VD);
4472 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
4477 SwitchSuccessor =
Block;
4478 }
else SwitchSuccessor = Succ;
4481 SaveAndRestore save_switch(SwitchTerminatedBlock),
4482 save_default(DefaultCaseBlock);
4483 SaveAndRestore save_break(BreakJumpTarget);
4488 DefaultCaseBlock = SwitchSuccessor;
4491 SwitchTerminatedBlock = createBlock(
false);
4495 Succ = SwitchSuccessor;
4496 BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
4501 assert(Terminator->
getBody() &&
"switch must contain a non-NULL body");
4506 SaveAndRestore save_switchExclusivelyCovered(switchExclusivelyCovered,
false);
4509 assert(Terminator->
getCond() &&
"switch condition must be non-NULL");
4510 Expr::EvalResult result;
4511 bool b = tryEvaluate(Terminator->
getCond(), result);
4512 SaveAndRestore save_switchCond(switchCond,
b ? &result :
nullptr);
4517 addLocalScopeAndDtors(Terminator->
getBody());
4519 addStmt(Terminator->
getBody());
4533 bool SwitchAlwaysHasSuccessor =
false;
4534 SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
4535 SwitchAlwaysHasSuccessor |=
4538 addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock,
4539 !SwitchAlwaysHasSuccessor);
4543 Block = SwitchTerminatedBlock;
4544 CFGBlock *LastBlock = addStmt(Terminator->
getCond());
4552 LastBlock = addStmt(
Init);
4553 maybeAddScopeBeginForVarDecl(LastBlock, VD,
Init);
4560 LastBlock = addStmt(
Init);
4573 bool addCase =
false;
4575 if (!switchExclusivelyCovered) {
4579 const llvm::APSInt &condInt = switchCond->
Val.
getInt();
4581 if (condInt == lhsInt) {
4583 switchExclusivelyCovered =
true;
4585 else if (condInt > lhsInt) {
4589 if (V2 >= condInt) {
4591 switchExclusivelyCovered =
true;
4602CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
4605 CFGBlock *TopBlock =
nullptr, *LastBlock =
nullptr;
4612 CFGBlock *currentBlock = createBlock(
false);
4616 addSuccessor(LastBlock, currentBlock);
4618 TopBlock = currentBlock;
4620 addSuccessor(SwitchTerminatedBlock,
4623 ? currentBlock :
nullptr);
4625 LastBlock = currentBlock;
4633 CFGBlock *CaseBlock =
Block;
4635 CaseBlock = createBlock();
4646 assert(SwitchTerminatedBlock);
4647 addSuccessor(SwitchTerminatedBlock, CaseBlock,
4655 addSuccessor(LastBlock, CaseBlock);
4665CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {
4669 DefaultCaseBlock =
Block;
4671 if (!DefaultCaseBlock)
4672 DefaultCaseBlock = createBlock();
4676 DefaultCaseBlock->
setLabel(Terminator);
4691 Succ = DefaultCaseBlock;
4693 return DefaultCaseBlock;
4696CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
4699 CFGBlock *TrySuccessor =
nullptr;
4704 TrySuccessor =
Block;
4706 TrySuccessor = Succ;
4708 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4711 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4715 bool HasCatchAll =
false;
4716 for (
unsigned I = 0, E = Terminator->
getNumHandlers(); I != E; ++I) {
4718 Succ = TrySuccessor;
4719 CXXCatchStmt *CS = Terminator->
getHandler(I);
4724 CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
4729 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4732 if (PrevTryTerminatedBlock)
4733 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4735 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4739 Succ = TrySuccessor;
4742 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4743 cfg->addTryDispatchBlock(TryTerminatedBlock);
4745 assert(Terminator->
getTryBlock() &&
"try must contain a non-NULL body");
4750CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
4756 SaveAndRestore save_scope_pos(ScopePos);
4761 LocalScope::const_iterator BeginScopePos = ScopePos;
4762 addLocalScopeForVarDecl(VD);
4763 addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
4769 CFGBlock *CatchBlock =
Block;
4771 CatchBlock = createBlock();
4777 appendStmt(CatchBlock, CS);
4793CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
4808 SaveAndRestore save_scope_pos(ScopePos);
4813 addLocalScopeForStmt(
Init);
4815 addLocalScopeForStmt(Range);
4817 addLocalScopeForStmt(Begin);
4819 addLocalScopeForStmt(End);
4820 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
4822 LocalScope::const_iterator ContinueScopePos = ScopePos;
4826 CFGBlock *LoopSuccessor =
nullptr;
4830 LoopSuccessor =
Block;
4832 LoopSuccessor = Succ;
4836 SaveAndRestore save_break(BreakJumpTarget);
4837 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4840 CFGBlock *ConditionBlock = createBlock(
false);
4845 Block = ConditionBlock;
4846 CFGBlock *BeginConditionBlock = addStmt(
C);
4849 assert(BeginConditionBlock == ConditionBlock &&
4850 "condition block in for-range was unexpectedly complex");
4851 (void)BeginConditionBlock;
4856 Succ = ConditionBlock;
4859 TryResult KnownVal(
true);
4862 KnownVal = tryEvaluateBool(S->
getCond());
4869 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4870 SaveAndRestore save_continue(ContinueJumpTarget);
4875 Succ = addStmt(S->
getInc());
4878 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
4882 ContinueJumpTarget.block->setLoopTarget(S);
4896 addLocalScopeAndDtors(S->
getBody());
4908 addSuccessor(ConditionBlock,
4909 KnownVal.isFalse() ?
nullptr : LoopVarStmtBlock);
4914 addSuccessor(ConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4917 Block = createBlock();
4926CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
4927 AddStmtChoice asc,
bool ExternallyDestructed) {
4931 TempDtorContext Context;
4932 VisitForTemporaryDtors(E->
getSubExpr(), ExternallyDestructed, Context);
4936 asc = asc.withAlwaysAdd(
true);
4941CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
4942 AddStmtChoice asc) {
4943 if (asc.alwaysAdd(*
this, E)) {
4945 appendStmt(
Block, E);
4947 findConstructionContexts(
4952 asc = asc.withAlwaysAdd(
false);
4957CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *
C,
4958 AddStmtChoice asc) {
4962 findConstructionContextsForArguments(
C);
4963 appendConstructor(
C);
4965 return VisitChildren(
C);
4968CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
4969 AddStmtChoice asc) {
4971 appendStmt(
Block, NE);
4973 findConstructionContexts(
4975 const_cast<CXXConstructExpr *
>(
NE->getConstructExpr()));
4977 if (
NE->getInitializer())
4978 Block = Visit(
NE->getInitializer());
4981 appendNewAllocator(
Block, NE);
4983 if (
NE->isArray() && *
NE->getArraySize())
4984 Block = Visit(*
NE->getArraySize());
4987 E =
NE->placement_arg_end(); I != E; ++I)
4993CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
4994 AddStmtChoice asc) {
4996 appendStmt(
Block, DE);
5003 appendDeleteDtor(
Block, RD, DE);
5007 return VisitChildren(DE);
5010CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
5011 AddStmtChoice asc) {
5012 if (asc.alwaysAdd(*
this, E)) {
5014 appendStmt(
Block, E);
5016 asc = asc.withAlwaysAdd(
false);
5021CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E,
5022 AddStmtChoice asc) {
5026 findConstructionContextsForArguments(E);
5027 appendConstructor(E);
5029 return VisitChildren(E);
5032CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
5033 AddStmtChoice asc) {
5034 if (asc.alwaysAdd(*
this, E)) {
5036 appendStmt(
Block, E);
5042 return Visit(E->
getSubExpr(), AddStmtChoice());
5045CFGBlock *CFGBuilder::VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc) {
5046 return Visit(E->
getSubExpr(), AddStmtChoice());
5049CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
5051 CFGBlock *IBlock = cfg->getIndirectGotoBlock();
5054 IBlock = createBlock(
false);
5055 cfg->setIndirectGotoBlock(IBlock);
5063 Block = createBlock(
false);
5064 Block->setTerminator(I);
5065 addSuccessor(
Block, IBlock);
5069CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E,
bool ExternallyDestructed,
5070 TempDtorContext &Context) {
5080 return VisitChildrenForTemporaryDtors(E,
false, Context);
5082 case Stmt::InitListExprClass:
5083 return VisitChildrenForTemporaryDtors(E, ExternallyDestructed, Context);
5085 case Stmt::BinaryOperatorClass:
5087 ExternallyDestructed,
5090 case Stmt::CXXBindTemporaryExprClass:
5091 return VisitCXXBindTemporaryExprForTemporaryDtors(
5094 case Stmt::BinaryConditionalOperatorClass:
5095 case Stmt::ConditionalOperatorClass:
5096 return VisitConditionalOperatorForTemporaryDtors(
5099 case Stmt::ImplicitCastExprClass:
5104 case Stmt::CXXFunctionalCastExprClass:
5109 case Stmt::ConstantExprClass:
5113 case Stmt::ParenExprClass:
5117 case Stmt::MaterializeTemporaryExprClass: {
5120 SmallVector<const Expr *, 2> CommaLHSs;
5121 SmallVector<SubobjectAdjustment, 2> Adjustments;
5123 E =
const_cast<Expr *
>(
5126 ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
5128 for (
const Expr *CommaLHS : CommaLHSs) {
5129 VisitForTemporaryDtors(
const_cast<Expr *
>(CommaLHS),
5135 case Stmt::BlockExprClass:
5140 case Stmt::LambdaExprClass: {
5144 CFGBlock *B =
Block;
5145 for (Expr *
Init :
LE->capture_inits()) {
5147 if (CFGBlock *R = VisitForTemporaryDtors(
5148 Init,
true, Context))
5155 case Stmt::StmtExprClass:
5160 case Stmt::CXXDefaultArgExprClass:
5164 case Stmt::CXXDefaultInitExprClass:
5170CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E,
5171 bool ExternallyDestructed,
5172 TempDtorContext &Context) {
5182 CFGBlock *B =
Block;
5185 if (CFGBlock *R = VisitForTemporaryDtors(Child, ExternallyDestructed, Context))
5191CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
5192 BinaryOperator *E,
bool ExternallyDestructed, TempDtorContext &Context) {
5196 CFGBlock *LHSBlock = VisitForTemporaryDtors(E->
getLHS(),
false, Context);
5197 CFGBlock *RHSBlock = VisitForTemporaryDtors(E->
getRHS(), ExternallyDestructed, Context);
5198 return RHSBlock ? RHSBlock : LHSBlock;
5202 VisitForTemporaryDtors(E->
getLHS(),
false, Context);
5203 TryResult RHSExecuted = tryEvaluateBool(E->
getLHS());
5204 if (RHSExecuted.isKnown() && E->
getOpcode() == BO_LOr)
5205 RHSExecuted.negate();
5210 TempDtorContext RHSContext(
5212 VisitForTemporaryDtors(E->
getRHS(),
false, RHSContext);
5213 InsertTempDtorDecisionBlock(RHSContext);
5221 CFGBlock *RHSBlock = VisitForTemporaryDtors(E->
getRHS(),
false, Context);
5222 CFGBlock *LHSBlock = VisitForTemporaryDtors(E->
getLHS(),
false, Context);
5223 return LHSBlock ? LHSBlock : RHSBlock;
5227 return VisitChildrenForTemporaryDtors(E, ExternallyDestructed, Context);
5230CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
5231 CXXBindTemporaryExpr *E,
bool ExternallyDestructed, TempDtorContext &Context) {
5234 CFGBlock *B = VisitForTemporaryDtors(E->
getSubExpr(),
true, Context);
5235 if (!ExternallyDestructed) {
5247 Block = createNoReturnBlock();
5248 }
else if (Context.needsTempDtorBranch()) {
5252 Block = createBlock();
5256 if (Context.needsTempDtorBranch()) {
5257 Context.setDecisionPoint(Succ, E);
5259 appendTemporaryDtor(
Block, E);
5266void CFGBuilder::InsertTempDtorDecisionBlock(
const TempDtorContext &Context,
5267 CFGBlock *FalseSucc) {
5268 if (!Context.TerminatorExpr) {
5272 assert(Context.TerminatorExpr);
5273 CFGBlock *Decision = createBlock(
false);
5274 Decision->setTerminator(CFGTerminator(Context.TerminatorExpr,
5276 addSuccessor(Decision,
Block, !Context.KnownExecuted.isFalse());
5277 addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
5278 !Context.KnownExecuted.isTrue());
5282CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
5283 AbstractConditionalOperator *E,
bool ExternallyDestructed,
5284 TempDtorContext &Context) {
5285 VisitForTemporaryDtors(E->
getCond(),
false, Context);
5286 CFGBlock *ConditionBlock =
Block;
5287 CFGBlock *ConditionSucc = Succ;
5288 TryResult ConditionVal = tryEvaluateBool(E->
getCond());
5289 TryResult NegatedVal = ConditionVal;
5290 if (NegatedVal.isKnown()) NegatedVal.negate();
5292 TempDtorContext TrueContext(
5294 VisitForTemporaryDtors(E->
getTrueExpr(), ExternallyDestructed, TrueContext);
5295 CFGBlock *TrueBlock =
Block;
5297 Block = ConditionBlock;
5298 Succ = ConditionSucc;
5299 TempDtorContext FalseContext(
5301 VisitForTemporaryDtors(E->
getFalseExpr(), ExternallyDestructed, FalseContext);
5303 if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
5304 InsertTempDtorDecisionBlock(FalseContext, TrueBlock);
5305 }
else if (TrueContext.TerminatorExpr) {
5307 InsertTempDtorDecisionBlock(TrueContext);
5309 InsertTempDtorDecisionBlock(FalseContext);
5314CFGBlock *CFGBuilder::VisitOMPExecutableDirective(OMPExecutableDirective *D,
5315 AddStmtChoice asc) {
5316 if (asc.alwaysAdd(*
this, D)) {
5318 appendStmt(
Block, D);
5322 CFGBlock *B =
Block;
5326 SmallVector<Stmt *, 8>
Used(
5327 OMPExecutableDirective::used_clauses_children(D->clauses()));
5328 for (Stmt *S : llvm::reverse(
Used)) {
5329 assert(S &&
"Expected non-null used-in-clause child.");
5330 if (CFGBlock *R = Visit(S))
5334 if (!D->isStandaloneDirective()) {
5335 Stmt *S = D->getRawStmt();
5337 addLocalScopeAndDtors(S);
5338 if (CFGBlock *R = addStmt(S))
5349 bool first_block =
begin() ==
end();
5353 Blocks.push_back(Mem, BlkBVC);
5357 Entry = Exit = &
back();
5366 llvm::TimeTraceScope TimeProfile(
"BuildCFG");
5367 CFGBuilder Builder(
C, BO);
5368 return Builder.buildCFG(D, Statement);
5383 auto IteratorAndFlag = Visited.insert(B);
5384 if (!IteratorAndFlag.second) {
5390 const CFGBlock *FirstReachableB =
nullptr;
5392 if (!AB.isReachable())
5395 if (FirstReachableB ==
nullptr) {
5396 FirstReachableB = &*AB;
5403 if (!FirstReachableB) {
5409 B = FirstReachableB;
5429 llvm_unreachable(
"getDestructorDecl should only be used with "
5440 if (
const Expr *
Init = var->getInit()) {
5487 llvm_unreachable(
"getKind() returned bogus value");
5495 : ReachableBlock(IsReachable ? B :
nullptr),
5496 UnreachableBlock(!IsReachable ? B :
nullptr,
5497 B && IsReachable ? AB_Normal : AB_Unreachable) {}
5500 : ReachableBlock(B),
5501 UnreachableBlock(B == AlternateBlock ?
nullptr : AlternateBlock,
5502 B == AlternateBlock ? AB_Alternate : AB_Normal) {}
5512 Succs.push_back(Succ,
C);
5525 if (S->isAllEnumCasesCovered()) {
5543 using StmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>;
5544 using DeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>;
5548 signed currentBlock = 0;
5549 unsigned currStmt = 0;
5559 for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
5560 BI != BEnd; ++BI, ++j ) {
5561 if (std::optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
5562 const Stmt *stmt= SE->getStmt();
5563 std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
5566 switch (stmt->getStmtClass()) {
5567 case Stmt::DeclStmtClass:
5568 DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P;
5570 case Stmt::IfStmtClass: {
5571 const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable();
5576 case Stmt::ForStmtClass: {
5577 const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable();
5582 case Stmt::WhileStmtClass: {
5583 const VarDecl *var =
5584 cast<WhileStmt>(stmt)->getConditionVariable();
5589 case Stmt::SwitchStmtClass: {
5590 const VarDecl *var =
5591 cast<SwitchStmt>(stmt)->getConditionVariable();
5596 case Stmt::CXXCatchStmtClass: {
5597 const VarDecl *var =
5598 cast<CXXCatchStmt>(stmt)->getExceptionDecl();
5611 ~StmtPrinterHelper()
override =
default;
5613 const LangOptions &getLangOpts()
const {
return LangOpts; }
5614 void setBlockID(
signed i) { currentBlock = i; }
5615 void setStmtID(
unsigned i) { currStmt = i; }
5617 bool handledStmt(Stmt *S, raw_ostream &OS)
override {
5618 StmtMapTy::iterator I = StmtMap.find(S);
5620 if (I == StmtMap.end())
5623 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5624 && I->second.second == currStmt) {
5628 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5632 bool handleDecl(
const Decl *D, raw_ostream &OS) {
5633 DeclMapTy::iterator I = DeclMap.find(D);
5635 if (I == DeclMap.end()) {
5638 if (
auto *PVD = dyn_cast_or_null<ParmVarDecl>(D)) {
5639 OS <<
"[Parm: " << PVD->getNameAsString() <<
"]";
5645 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5646 && I->second.second == currStmt) {
5650 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5655class CFGBlockTerminatorPrint
5656 :
public StmtVisitor<CFGBlockTerminatorPrint,void> {
5658 StmtPrinterHelper* Helper;
5659 PrintingPolicy Policy;
5662 CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
5663 const PrintingPolicy &Policy)
5664 :
OS(os), Helper(helper), Policy(Policy) {
5668 void VisitIfStmt(IfStmt *I) {
5671 C->printPretty(OS, Helper, Policy);
5675 void VisitStmt(Stmt *Terminator) {
5679 void VisitDeclStmt(DeclStmt *DS) {
5684 void VisitForStmt(ForStmt *F) {
5690 C->printPretty(OS, Helper, Policy);
5697 void VisitWhileStmt(WhileStmt *W) {
5700 C->printPretty(OS, Helper, Policy);
5703 void VisitDoStmt(DoStmt *D) {
5704 OS <<
"do ... while ";
5706 C->printPretty(OS, Helper, Policy);
5709 void VisitSwitchStmt(SwitchStmt *Terminator) {
5714 void VisitCXXTryStmt(CXXTryStmt *) {
OS <<
"try ..."; }
5716 void VisitObjCAtTryStmt(ObjCAtTryStmt *) {
OS <<
"@try ..."; }
5718 void VisitSEHTryStmt(SEHTryStmt *CS) {
OS <<
"__try ..."; }
5720 void VisitAbstractConditionalOperator(AbstractConditionalOperator*
C) {
5721 if (Stmt *
Cond =
C->getCond())
5723 OS <<
" ? ... : ...";
5726 void VisitChooseExpr(ChooseExpr *
C) {
5727 OS <<
"__builtin_choose_expr( ";
5728 if (Stmt *
Cond =
C->getCond())
5733 void VisitIndirectGotoStmt(IndirectGotoStmt *I) {
5736 T->printPretty(OS, Helper, Policy);
5739 void VisitBinaryOperator(BinaryOperator* B) {
5756 llvm_unreachable(
"Invalid logical operator.");
5760 void VisitExpr(Expr *E) {
5765 void print(CFGTerminator
T) {
5766 switch (
T.getKind()) {
5771 OS <<
"(Temp Dtor) ";
5775 OS <<
"(See if most derived ctor has already initialized vbases)";
5797 OS <<
" (Base initializer)";
5799 OS <<
" (Delegating initializer)";
5801 OS <<
" (Member initializer)";
5805 StmtPrinterHelper &Helper,
5820 Stmts.push_back(CICC->getCXXBindTemporaryExpr());
5825 Stmts.push_back(SDSCC->getDeclStmt());
5830 Stmts.push_back(CDSCC->getDeclStmt());
5831 Stmts.push_back(CDSCC->getCXXBindTemporaryExpr());
5836 Stmts.push_back(NECC->getCXXNewExpr());
5841 Stmts.push_back(RSCC->getReturnStmt());
5847 Stmts.push_back(RSCC->getReturnStmt());
5848 Stmts.push_back(RSCC->getCXXBindTemporaryExpr());
5853 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5854 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5859 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5860 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5861 Stmts.push_back(TOCC->getConstructorAfterElision());
5866 Helper.handledStmt(
const_cast<LambdaExpr *
>(LCC->getLambdaExpr()), OS);
5867 OS <<
"+" << LCC->getIndex();
5872 if (
const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
5874 Helper.handledStmt(
const_cast<Stmt *
>(BTE), OS);
5877 Helper.handledStmt(
const_cast<Expr *
>(ACC->getCallLikeExpr()), OS);
5878 OS <<
"+" << ACC->getIndex();
5885 Helper.handledStmt(
const_cast<Stmt *
>(I), OS);
5889static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5890 const CFGElement &E,
bool TerminateWithNewLine =
true);
5893 bool TerminateWithNewLine)
const {
5895 StmtPrinterHelper Helper(
nullptr, LangOpts);
5896 print_elem(OS, Helper, *
this, TerminateWithNewLine);
5899static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5900 const CFGElement &E,
bool TerminateWithNewLine) {
5907 assert(S !=
nullptr &&
"Expecting non-null Stmt");
5910 if (
const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
5918 if (TerminateWithNewLine)
5927 Helper.handledStmt(B->
getRHS(),OS);
5928 if (TerminateWithNewLine)
5933 S->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
5937 OS <<
" (OperatorCall)";
5938 OS <<
" (CXXRecordTypedCall";
5942 OS <<
" (OperatorCall)";
5944 OS <<
" (BindTemporary)";
5946 OS <<
" (CXXConstructExpr";
5950 OS <<
", " << CCE->getType() <<
")";
5951 }
else if (
const CastExpr *CE = dyn_cast<CastExpr>(S)) {
5953 <<
", " << CE->
getType() <<
")";
5957 if (
isa<Expr>(S) && TerminateWithNewLine)
5970 Helper.handleDecl(VD, OS);
5973 if (
T->isReferenceType())
5977 T.getUnqualifiedType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5978 OS <<
"() (Implicit destructor)";
5983 OS <<
"CleanupFunction ("
5989 OS <<
" (Lifetime ends)";
5998 OS <<
"CFGScopeBegin(";
6005 OS <<
"CFGScopeEnd(";
6012 OS <<
"CFGNewAllocator(";
6014 AllocExpr->getType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
6026 OS <<
"->~" << RD->getName().str() <<
"()";
6027 OS <<
" (Implicit destructor)";
6034 OS <<
" (Base object destructor)";
6041 OS <<
"this->" << FD->
getName();
6042 OS <<
".~" <<
T->getAsCXXRecordDecl()->getName() <<
"()";
6043 OS <<
" (Member object destructor)";
6052 OS <<
"() (Temporary object destructor)";
6056 if (TerminateWithNewLine)
6062 StmtPrinterHelper &Helper,
bool print_edges,
6068 OS.changeColor(raw_ostream::YELLOW,
true);
6073 OS <<
" (ENTRY)]\n";
6074 else if (&B == &cfg->
getExit())
6077 OS <<
" (INDIRECT GOTO DISPATCH)]\n";
6079 OS <<
" (NORETURN)]\n";
6095 if (
const Expr *LHS =
C->getLHS())
6097 if (
const Expr *RHS =
C->getRHS()) {
6112 if (
const VarDecl *PD = CS->getCatchParamDecl())
6123 llvm_unreachable(
"Invalid label statement in CFGBlock.");
6132 I != E ; ++I, ++j ) {
6137 OS << llvm::format(
"%3d", j) <<
": ";
6139 Helper.setStmtID(j);
6147 OS.changeColor(raw_ostream::GREEN);
6151 Helper.setBlockID(-1);
6154 CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
6165 const raw_ostream::Colors Color = raw_ostream::BLUE;
6167 OS.changeColor(Color);
6175 OS.changeColor(Color);
6183 bool Reachable =
true;
6186 B = I->getPossiblyUnreachableBlock();
6191 OS <<
"(Unreachable)";
6202 const raw_ostream::Colors Color = raw_ostream::MAGENTA;
6204 OS.changeColor(Color);
6212 OS.changeColor(Color);
6221 bool Reachable =
true;
6224 B = I->getPossiblyUnreachableBlock();
6230 OS <<
"(Unreachable)";
6246 print(llvm::errs(), LO, ShowColors);
6251 StmtPrinterHelper Helper(
this, LO);
6257 for (
const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
6262 print_block(OS,
this, **I, Helper,
true, ShowColors);
6277 bool ShowColors)
const {
6278 print(llvm::errs(), cfg, LO, ShowColors);
6289 StmtPrinterHelper Helper(cfg, LO);
6290 print_block(OS, cfg, *
this, Helper,
true, ShowColors);
6297 CFGBlockTerminatorPrint TPrinter(OS,
nullptr,
PrintingPolicy(LO));
6303 bool AddQuotes)
const {
6305 llvm::raw_string_ostream TempOut(Buf);
6328 if (llvm::any_of(*Blk, [](
const CFGElement &Elm) {
6329 if (std::optional<CFGStmt> StmtElm = Elm.
getAs<
CFGStmt>())
6349 DFSWorkList.push_back(StartBlk);
6350 while (!DFSWorkList.empty()) {
6351 const CFGBlock *Blk = DFSWorkList.pop_back_val();
6352 Visited.insert(Blk);
6361 for (
const auto &Succ : Blk->
succs()) {
6362 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
6366 DFSWorkList.push_back(SuccBlk);
6395 const Stmt *
Cond = StmtElem->getStmt();
6409 const Expr *E =
nullptr;
6415 case Stmt::CXXForRangeStmtClass:
6419 case Stmt::ForStmtClass:
6423 case Stmt::WhileStmtClass:
6427 case Stmt::DoStmtClass:
6431 case Stmt::IfStmtClass:
6435 case Stmt::ChooseExprClass:
6439 case Stmt::IndirectGotoStmtClass:
6443 case Stmt::SwitchStmtClass:
6447 case Stmt::BinaryConditionalOperatorClass:
6451 case Stmt::ConditionalOperatorClass:
6455 case Stmt::BinaryOperatorClass:
6459 case Stmt::ObjCForCollectionStmtClass:
6476 StmtPrinterHelper H(
this, LO);
6478 llvm::ViewGraph(
this,
"CFG");
6490 llvm::raw_string_ostream Out(OutStr);
6493 if (OutStr[0] ==
'\n') OutStr.erase(OutStr.begin());
6496 for (
unsigned i = 0; i != OutStr.length(); ++i)
6497 if (OutStr[i] ==
'\n') {
6499 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.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
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)
const Stmt * getTerminatorCondition(bool StripParens=true) const
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
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.
const 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)