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());
1672 LocalScope *paramScope =
nullptr;
1673 if (
const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
1674 for (ParmVarDecl *PD : FD->parameters()) {
1675 paramScope = addLocalScopeForVarDecl(PD, paramScope);
1677 if (
auto *
C = dyn_cast<CompoundStmt>(Statement))
1681 addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(),
1685 if (
const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
1686 addImplicitDtorsForDestructor(DD);
1689 CFGBlock *B = addStmt(Statement);
1706 if (
const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) {
1707 CFGBlock *VBaseSucc =
nullptr;
1708 for (
auto *I : llvm::reverse(CD->inits())) {
1710 I->isBaseInitializer() && I->isBaseVirtual()) {
1714 VBaseSucc = Succ = B ? B : &cfg->getExit();
1715 Block = createBlock();
1717 B = addInitializer(I);
1727 addSuccessor(B,
Block,
true);
1736 for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
1737 E = BackpatchBlocks.end(); I != E; ++I ) {
1739 CFGBlock *B = I->block;
1741 LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
1744 if (LI == LabelMap.end())
1746 JumpTarget JT = LI->second;
1748 CFGBlock *SuccBlk = createScopeChangesHandlingBlock(
1749 I->scopePosition, B, JT.scopePosition, JT.block);
1750 addSuccessor(B, SuccBlk);
1751 }
else if (
auto *G = dyn_cast<GCCAsmStmt>(B->
getTerminator())) {
1752 CFGBlock *Successor = (I+1)->block;
1753 for (
auto *L : G->labels()) {
1754 LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
1757 if (LI == LabelMap.end())
1759 JumpTarget JT = LI->second;
1761 if (JT.block == Successor)
1763 addSuccessor(B, JT.block);
1770 if (CFGBlock *B = cfg->getIndirectGotoBlock())
1771 for (LabelDecl *LD : AddressTakenLabels) {
1773 LabelMapTy::iterator LI = LabelMap.find(LD);
1777 if (LI == LabelMap.end())
continue;
1779 addSuccessor(B, LI->second.block);
1783 cfg->setEntry(createBlock());
1786 assert(ConstructionContextMap.empty() &&
1787 "Not all construction contexts were cleaned up!");
1789 return std::move(cfg);
1794CFGBlock *CFGBuilder::createBlock(
bool add_successor) {
1795 CFGBlock *B = cfg->createBlock();
1796 if (add_successor && Succ)
1797 addSuccessor(B, Succ);
1804CFGBlock *CFGBuilder::createNoReturnBlock() {
1805 CFGBlock *B = createBlock(
false);
1807 addSuccessor(B, &cfg->getExit(), Succ);
1812CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
1816 bool HasTemporaries =
false;
1826 TempDtorContext Context;
1833 appendInitializer(
Block, I);
1839 dyn_cast<ArrayInitLoopExpr>(
Init));
1841 findConstructionContexts(
1843 AILEInit ? AILEInit :
Init);
1845 if (HasTemporaries) {
1851 if (CXXDefaultInitExpr *
Default = dyn_cast<CXXDefaultInitExpr>(
Init)) {
1857 if (Stmt *Child =
Default->getExpr())
1858 if (CFGBlock *R = Visit(Child))
1872 bool *FoundMTE =
nullptr) {
1879 Init = EWC->getSubExpr();
1885 = dyn_cast<MaterializeTemporaryExpr>(
Init)) {
1886 Init = MTE->getSubExpr();
1893 const Expr *SkippedInit =
Init->skipRValueSubobjectAdjustments();
1894 if (SkippedInit !=
Init) {
1902 return Init->getType();
1907void CFGBuilder::addLoopExit(
const Stmt *LoopStmt){
1911 appendLoopExit(
Block, LoopStmt);
1919void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
1920 LocalScope::const_iterator E,
1930 if (B.inSameLocalScope(E)) {
1931 addAutomaticObjDestruction(B, E, S);
1936 SmallVector<LocalScope::const_iterator, 10> LocalScopeEndMarkers;
1937 LocalScopeEndMarkers.push_back(B);
1938 for (LocalScope::const_iterator I = B; I != E; ++I) {
1939 if (!I.inSameLocalScope(LocalScopeEndMarkers.back()))
1940 LocalScopeEndMarkers.push_back(I);
1942 LocalScopeEndMarkers.push_back(E);
1946 std::reverse(LocalScopeEndMarkers.begin(), LocalScopeEndMarkers.end());
1948 llvm::zip(LocalScopeEndMarkers, llvm::drop_begin(LocalScopeEndMarkers));
1949 for (
auto [E, B] : Pairwise) {
1950 if (!B.inSameLocalScope(E))
1951 addScopeExitHandling(B, E, S);
1952 addAutomaticObjDestruction(B, E, S);
1959void CFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
1960 LocalScope::const_iterator E,
1968 SmallVector<VarDecl *, 10> DeclsNeedDestruction;
1969 DeclsNeedDestruction.reserve(B.distance(E));
1971 for (VarDecl* D : llvm::make_range(B, E))
1972 if (needsAutomaticDestruction(D))
1973 DeclsNeedDestruction.push_back(D);
1975 for (VarDecl *VD : llvm::reverse(DeclsNeedDestruction)) {
1988 Block = createNoReturnBlock();
1997 appendLifetimeEnds(
Block, VD, S);
1999 appendAutomaticObjDtor(
Block, VD, S);
2000 if (VD->
hasAttr<CleanupAttr>())
2001 appendCleanupFunction(
Block, VD);
2010void CFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
2011 LocalScope::const_iterator E, Stmt *S) {
2012 assert(!B.inSameLocalScope(E));
2018 appendScopeEnd(
Block, B.getFirstVarInScope(), S);
2025 SmallVector<VarDecl *, 10> DeclsTrivial;
2026 DeclsTrivial.reserve(B.distance(E));
2031 for (VarDecl* D : llvm::make_range(B, E))
2032 if (!needsAutomaticDestruction(D))
2033 DeclsTrivial.push_back(D);
2035 if (DeclsTrivial.empty())
2039 for (VarDecl *VD : llvm::reverse(DeclsTrivial))
2040 appendLifetimeEnds(
Block, VD, S);
2048void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
2049 LocalScope::const_iterator DstPos,
2051 assert(
Block &&
"Source block should be always crated");
2057 if (SrcPos == DstPos)
2062 LocalScope::const_iterator BasePos = SrcPos.shared_parent(DstPos);
2065 if (BuildOpts.
AddScopes && !DstPos.inSameLocalScope(BasePos)) {
2066 for (LocalScope::const_iterator I = DstPos; I != BasePos; ++I)
2067 if (I.pointsToFirstDeclaredVar())
2068 appendScopeBegin(
Block, *I, S);
2073 addAutomaticObjHandling(SrcPos, BasePos, S);
2081CFGBlock *CFGBuilder::createScopeChangesHandlingBlock(
2082 LocalScope::const_iterator SrcPos, CFGBlock *SrcBlk,
2083 LocalScope::const_iterator DstPos, CFGBlock *DstBlk) {
2084 if (SrcPos == DstPos)
2088 (!BuildOpts.
AddScopes || SrcPos.inSameLocalScope(DstPos)))
2093 SaveAndRestore save_Block(
Block), save_Succ(Succ);
2096 Block = createBlock(
false);
2099 addSuccessor(
Block, DstBlk);
2102 addScopeChangesHandling(SrcPos, DstPos,
Block->getTerminatorStmt());
2104 assert(
Block &&
"There should be at least one scope changing Block");
2110void CFGBuilder::addImplicitDtorsForDestructor(
const CXXDestructorDecl *DD) {
2112 "Can be called only when dtors should be added");
2113 const CXXRecordDecl *RD = DD->
getParent();
2116 for (
const auto &VI : RD->
vbases()) {
2120 const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
2123 appendBaseDtor(
Block, &VI);
2128 for (
const auto &BI : RD->
bases()) {
2129 if (!BI.isVirtual()) {
2130 const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
2133 appendBaseDtor(
Block, &BI);
2141 for (
auto *FI : RD->
fields()) {
2143 QualType QT = FI->getType();
2146 if (AT->isZeroSize())
2148 QT = AT->getElementType();
2154 appendMemberDtor(
Block, FI);
2161LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) {
2164 llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
2165 return new (alloc) LocalScope(BumpVectorContext(alloc), ScopePos);
2170void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
2175 LocalScope *Scope =
nullptr;
2179 for (
auto *BI : CS->body()) {
2180 Stmt *SI = BI->stripLabelLikeStatements();
2181 if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
2182 Scope = addLocalScopeForDeclStmt(DS, Scope);
2190 addLocalScopeForDeclStmt(DS);
2195LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
2196 LocalScope* Scope) {
2201 for (
auto *DI : DS->
decls())
2202 if (VarDecl *VD = dyn_cast<VarDecl>(DI))
2203 Scope = addLocalScopeForVarDecl(VD, Scope);
2207bool CFGBuilder::needsAutomaticDestruction(
const VarDecl *VD)
const {
2208 return !hasTrivialDestructor(VD) || VD->
hasAttr<CleanupAttr>();
2211bool CFGBuilder::hasTrivialDestructor(
const VarDecl *VD)
const {
2232 bool FoundMTE =
false;
2240 if (AT->isZeroSize())
2242 QT = AT->getElementType();
2254LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
2255 LocalScope* Scope) {
2270 !needsAutomaticDestruction(VD)) {
2276 Scope = createOrReuseLocalScope(Scope);
2278 ScopePos = Scope->begin();
2284void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
2285 LocalScope::const_iterator scopeBeginPos = ScopePos;
2286 addLocalScopeForStmt(S);
2287 addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
2293CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
2294 bool ExternallyDestructed) {
2300 if (Expr *E = dyn_cast<Expr>(S))
2301 S = E->IgnoreParens();
2304 if (
auto *D = dyn_cast<OMPExecutableDirective>(S))
2305 return VisitOMPExecutableDirective(D, asc);
2309 return VisitStmt(S, asc);
2311 case Stmt::ImplicitValueInitExprClass:
2314 return VisitStmt(S, asc);
2316 case Stmt::InitListExprClass:
2319 case Stmt::AttributedStmtClass:
2322 case Stmt::AddrLabelExprClass:
2325 case Stmt::BinaryConditionalOperatorClass:
2328 case Stmt::BinaryOperatorClass:
2331 case Stmt::BlockExprClass:
2334 case Stmt::BreakStmtClass:
2337 case Stmt::CallExprClass:
2338 case Stmt::CXXOperatorCallExprClass:
2339 case Stmt::CXXMemberCallExprClass:
2340 case Stmt::UserDefinedLiteralClass:
2343 case Stmt::CaseStmtClass:
2346 case Stmt::ChooseExprClass:
2349 case Stmt::CompoundStmtClass:
2352 case Stmt::ConditionalOperatorClass:
2355 case Stmt::ContinueStmtClass:
2358 case Stmt::CXXCatchStmtClass:
2361 case Stmt::ExprWithCleanupsClass:
2363 asc, ExternallyDestructed);
2365 case Stmt::CXXDefaultArgExprClass:
2366 case Stmt::CXXDefaultInitExprClass:
2375 return VisitStmt(S, asc);
2377 case Stmt::CXXBindTemporaryExprClass:
2380 case Stmt::CXXConstructExprClass:
2383 case Stmt::CXXNewExprClass:
2386 case Stmt::CXXDeleteExprClass:
2389 case Stmt::CXXFunctionalCastExprClass:
2392 case Stmt::CXXTemporaryObjectExprClass:
2395 case Stmt::CXXThrowExprClass:
2398 case Stmt::CXXTryStmtClass:
2401 case Stmt::CXXTypeidExprClass:
2404 case Stmt::CXXForRangeStmtClass:
2407 case Stmt::DeclStmtClass:
2410 case Stmt::DefaultStmtClass:
2413 case Stmt::DoStmtClass:
2416 case Stmt::ForStmtClass:
2419 case Stmt::GotoStmtClass:
2422 case Stmt::GCCAsmStmtClass:
2425 case Stmt::IfStmtClass:
2428 case Stmt::ImplicitCastExprClass:
2431 case Stmt::ConstantExprClass:
2434 case Stmt::IndirectGotoStmtClass:
2437 case Stmt::LabelStmtClass:
2440 case Stmt::LambdaExprClass:
2443 case Stmt::MaterializeTemporaryExprClass:
2447 case Stmt::MemberExprClass:
2450 case Stmt::NullStmtClass:
2453 case Stmt::ObjCAtCatchStmtClass:
2456 case Stmt::ObjCAutoreleasePoolStmtClass:
2459 case Stmt::ObjCAtSynchronizedStmtClass:
2462 case Stmt::ObjCAtThrowStmtClass:
2465 case Stmt::ObjCAtTryStmtClass:
2468 case Stmt::ObjCForCollectionStmtClass:
2471 case Stmt::ObjCMessageExprClass:
2474 case Stmt::OpaqueValueExprClass:
2477 case Stmt::PseudoObjectExprClass:
2480 case Stmt::ReturnStmtClass:
2481 case Stmt::CoreturnStmtClass:
2482 return VisitReturnStmt(S);
2484 case Stmt::CoyieldExprClass:
2485 case Stmt::CoawaitExprClass:
2488 case Stmt::SEHExceptStmtClass:
2491 case Stmt::SEHFinallyStmtClass:
2494 case Stmt::SEHLeaveStmtClass:
2497 case Stmt::SEHTryStmtClass:
2500 case Stmt::UnaryExprOrTypeTraitExprClass:
2504 case Stmt::StmtExprClass:
2507 case Stmt::SwitchStmtClass:
2510 case Stmt::UnaryOperatorClass:
2513 case Stmt::WhileStmtClass:
2516 case Stmt::ArrayInitLoopExprClass:
2521CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
2522 if (asc.alwaysAdd(*
this, S)) {
2524 appendStmt(
Block, S);
2527 return VisitChildren(S);
2531CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
2532 CFGBlock *B =
Block;
2536 reverse_children RChildren(S, *Context);
2537 for (Stmt *Child : RChildren) {
2539 if (CFGBlock *R = Visit(Child))
2545CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) {
2546 if (asc.alwaysAdd(*
this, ILE)) {
2548 appendStmt(
Block, ILE);
2550 CFGBlock *B =
Block;
2552 reverse_children RChildren(ILE, *Context);
2553 for (Stmt *Child : RChildren) {
2556 if (CFGBlock *R = Visit(Child))
2559 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(Child))
2560 if (Stmt *Child = DIE->getExpr())
2561 if (CFGBlock *R = Visit(Child))
2568CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
2569 AddStmtChoice asc) {
2570 AddressTakenLabels.insert(A->
getLabel());
2572 if (asc.alwaysAdd(*
this, A)) {
2574 appendStmt(
Block, A);
2583 "expected fallthrough not to have children");
2584 return isFallthrough;
2591 "expected [[assume]] not to have children");
2592 return hasAssumeAttr;
2595CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
2596 AddStmtChoice asc) {
2606 if (isInterestingAttribute && asc.alwaysAdd(*
this, A)) {
2608 appendStmt(
Block, A);
2611 return VisitChildren(A);
2614CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc) {
2615 if (asc.alwaysAdd(*
this, U)) {
2617 appendStmt(
Block, U);
2623 return Visit(U->
getSubExpr(), AddStmtChoice());
2626CFGBlock *CFGBuilder::VisitLogicalOperator(BinaryOperator *B) {
2627 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2628 appendStmt(ConfluenceBlock, B);
2633 return VisitLogicalOperator(B,
nullptr, ConfluenceBlock,
2634 ConfluenceBlock).first;
2637std::pair<CFGBlock*, CFGBlock*>
2638CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
2640 CFGBlock *TrueBlock,
2641 CFGBlock *FalseBlock) {
2646 CFGBlock *RHSBlock, *ExitBlock;
2649 if (BinaryOperator *B_RHS = dyn_cast<BinaryOperator>(RHS))
2650 if (B_RHS->isLogicalOp()) {
2651 std::tie(RHSBlock, ExitBlock) =
2652 VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
2660 ExitBlock = RHSBlock = createBlock(
false);
2665 TryResult KnownVal = tryEvaluateBool(RHS);
2666 if (!KnownVal.isKnown())
2667 KnownVal = tryEvaluateBool(B);
2670 assert(TrueBlock == FalseBlock);
2671 addSuccessor(RHSBlock, TrueBlock);
2675 addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
2676 addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
2680 RHSBlock = addStmt(RHS);
2685 return std::make_pair(
nullptr,
nullptr);
2690 if (BinaryOperator *B_LHS = dyn_cast<BinaryOperator>(LHS))
2691 if (B_LHS->isLogicalOp()) {
2693 FalseBlock = RHSBlock;
2695 TrueBlock = RHSBlock;
2700 return VisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock);
2705 CFGBlock *LHSBlock = createBlock(
false);
2709 CFGBlock *EntryLHSBlock = addStmt(LHS);
2712 return std::make_pair(
nullptr,
nullptr);
2715 TryResult KnownVal = tryEvaluateBool(LHS);
2719 addSuccessor(LHSBlock, TrueBlock, !KnownVal.isFalse());
2720 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isTrue());
2723 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isFalse());
2724 addSuccessor(LHSBlock, FalseBlock, !KnownVal.isTrue());
2727 return std::make_pair(EntryLHSBlock, ExitBlock);
2730CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
2731 AddStmtChoice asc) {
2734 return VisitLogicalOperator(B);
2738 appendStmt(
Block, B);
2740 return addStmt(B->
getLHS());
2744 if (asc.alwaysAdd(*
this, B)) {
2746 appendStmt(
Block, B);
2749 return Visit(B->
getRHS());
2752 if (asc.alwaysAdd(*
this, B)) {
2754 appendStmt(
Block, B);
2760 CFGBlock *RBlock = Visit(B->
getRHS());
2761 CFGBlock *LBlock = Visit(B->
getLHS());
2765 return (LBlock ? LBlock : RBlock);
2768CFGBlock *CFGBuilder::VisitNoRecurse(Expr *E, AddStmtChoice asc) {
2769 if (asc.alwaysAdd(*
this, E)) {
2771 appendStmt(
Block, E);
2776CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
2783 Block = createBlock(
false);
2784 Block->setTerminator(B);
2788 if (BreakJumpTarget.block) {
2789 addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
2790 addSuccessor(
Block, BreakJumpTarget.block);
2815 if (BuiltinID != Builtin::BI__assume &&
2816 BuiltinID != Builtin::BI__builtin_assume)
2822CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *
C, AddStmtChoice asc) {
2824 QualType calleeType =
C->getCallee()->getType();
2830 if (!boundType.
isNull()) calleeType = boundType;
2836 bool AddEHEdge =
false;
2846 bool OmitArguments =
false;
2848 if (FunctionDecl *FD =
C->getDirectCallee()) {
2853 if (!FD->isVariadic())
2854 findConstructionContextsForArguments(
C);
2856 if (FD->isNoReturn() || FD->isAnalyzerNoReturn() ||
2857 C->isBuiltinAssumeFalse(*Context))
2859 if (FD->
hasAttr<NoThrowAttr>())
2862 FD->getBuiltinID() == Builtin::BI__builtin_object_size ||
2863 FD->getBuiltinID() == Builtin::BI__builtin_dynamic_object_size)
2864 OmitArguments =
true;
2867 if (!
CanThrow(
C->getCallee(), *Context))
2870 if (OmitArguments) {
2871 assert(!NoReturn &&
"noreturn calls with unevaluated args not implemented");
2872 assert(!AddEHEdge &&
"EH calls with unevaluated args not implemented");
2875 return Visit(
C->getCallee());
2878 if (!NoReturn && !AddEHEdge) {
2882 return VisitChildren(
C);
2892 Block = createNoReturnBlock();
2894 Block = createBlock();
2900 if (TryTerminatedBlock)
2901 addSuccessor(
Block, TryTerminatedBlock);
2903 addSuccessor(
Block, &cfg->getExit());
2906 return VisitChildren(
C);
2909CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *
C,
2910 AddStmtChoice asc) {
2911 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2912 appendStmt(ConfluenceBlock,
C);
2916 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2917 Succ = ConfluenceBlock;
2919 CFGBlock *LHSBlock = Visit(
C->getLHS(), alwaysAdd);
2923 Succ = ConfluenceBlock;
2925 CFGBlock *RHSBlock = Visit(
C->getRHS(), alwaysAdd);
2929 Block = createBlock(
false);
2931 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2932 addSuccessor(
Block, KnownVal.isFalse() ?
nullptr : LHSBlock);
2933 addSuccessor(
Block, KnownVal.isTrue() ?
nullptr : RHSBlock);
2935 return addStmt(
C->getCond());
2939 bool ExternallyDestructed) {
2940 LocalScope::const_iterator scopeBeginPos = ScopePos;
2941 addLocalScopeForStmt(
C);
2946 addAutomaticObjHandling(ScopePos, scopeBeginPos,
C);
2949 CFGBlock *LastBlock =
Block;
2951 for (Stmt *S : llvm::reverse(
C->body())) {
2954 CFGBlock *newBlock = Visit(S, AddStmtChoice::AlwaysAdd,
2955 ExternallyDestructed);
2958 LastBlock = newBlock;
2963 ExternallyDestructed =
false;
2969CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *
C,
2970 AddStmtChoice asc) {
2971 const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(
C);
2972 const OpaqueValueExpr *opaqueValue = (BCO ? BCO->
getOpaqueValue() :
nullptr);
2976 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2977 appendStmt(ConfluenceBlock,
C);
2981 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2987 Succ = ConfluenceBlock;
2989 CFGBlock *LHSBlock =
nullptr;
2990 const Expr *trueExpr =
C->getTrueExpr();
2991 if (trueExpr != opaqueValue) {
2992 LHSBlock = Visit(
C->getTrueExpr(), alwaysAdd);
2998 LHSBlock = ConfluenceBlock;
3001 Succ = ConfluenceBlock;
3002 CFGBlock *RHSBlock = Visit(
C->getFalseExpr(), alwaysAdd);
3007 if (BinaryOperator *
Cond =
3008 dyn_cast<BinaryOperator>(
C->getCond()->IgnoreParens()))
3009 if (
Cond->isLogicalOp())
3010 return VisitLogicalOperator(
Cond,
C, LHSBlock, RHSBlock).first;
3013 Block = createBlock(
false);
3016 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
3017 addSuccessor(
Block, LHSBlock, !KnownVal.isFalse());
3018 addSuccessor(
Block, RHSBlock, !KnownVal.isTrue());
3020 Expr *condExpr =
C->getCond();
3025 if (condExpr != opaqueValue)
3033 return addStmt(condExpr);
3036CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
3044 return VisitDeclSubExpr(DS);
3046 CFGBlock *B =
nullptr;
3055 DeclGroupRef DG(*I);
3058 cfg->addSyntheticDeclStmt(DSNew, DS);
3061 B = VisitDeclSubExpr(DSNew);
3069CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
3070 assert(DS->
isSingleDecl() &&
"Can handle single declarations only.");
3072 if (
const auto *TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl())) {
3074 const Type *
T = TND->getUnderlyingType().getTypePtr();
3079 appendStmt(
Block, DS);
3081 CFGBlock *LastBlock =
Block;
3082 for (
const VariableArrayType *VA =
FindVA(
T); VA !=
nullptr;
3083 VA =
FindVA(VA->getElementType().getTypePtr())) {
3084 if (CFGBlock *NewBlock = addStmt(VA->getSizeExpr()))
3085 LastBlock = NewBlock;
3098 bool HasTemporaries =
false;
3101 CFGBlock *blockAfterStaticInit =
nullptr;
3112 blockAfterStaticInit = Succ;
3123 TempDtorContext Context;
3131 if (
const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
3132 for (
auto *BD : llvm::reverse(DD->bindings())) {
3133 if (
auto *VD = BD->getHoldingVar()) {
3134 DeclGroupRef DG(VD);
3137 cfg->addSyntheticDeclStmt(DSNew, DS);
3138 Block = VisitDeclSubExpr(DSNew);
3144 appendStmt(
Block, DS);
3148 const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(
Init);
3150 findConstructionContexts(
3152 AILE ? AILE->getSubExpr() :
Init);
3157 CFGBlock *LastBlock =
Block;
3160 if (HasTemporaries) {
3164 if (CFGBlock *newBlock = Visit(EC->
getSubExpr()))
3165 LastBlock = newBlock;
3168 if (CFGBlock *newBlock = Visit(
Init))
3169 LastBlock = newBlock;
3177 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr())) {
3178 if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
3179 LastBlock = newBlock;
3182 maybeAddScopeBeginForVarDecl(
Block, VD, DS);
3185 if (ScopePos && VD == *ScopePos)
3188 CFGBlock *B = LastBlock;
3189 if (blockAfterStaticInit) {
3191 Block = createBlock(
false);
3192 Block->setTerminator(DS);
3193 addSuccessor(
Block, blockAfterStaticInit);
3194 addSuccessor(
Block, B);
3201CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
3211 SaveAndRestore save_scope_pos(ScopePos);
3215 addLocalScopeForStmt(
Init);
3220 addLocalScopeForVarDecl(VD);
3222 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
3233 CFGBlock *ElseBlock = Succ;
3235 if (Stmt *Else = I->
getElse()) {
3236 SaveAndRestore sv(Succ);
3245 addLocalScopeAndDtors(Else);
3247 ElseBlock = addStmt(Else);
3250 ElseBlock = sv.get();
3258 CFGBlock *ThenBlock;
3262 SaveAndRestore sv(Succ);
3268 addLocalScopeAndDtors(Then);
3270 ThenBlock = addStmt(Then);
3276 ThenBlock = createBlock(
false);
3277 addSuccessor(ThenBlock, sv.get());
3291 BinaryOperator *
Cond =
3295 CFGBlock *LastBlock;
3297 LastBlock = VisitLogicalOperator(
Cond, I, ThenBlock, ElseBlock).first;
3300 Block = createBlock(
false);
3303 Block->setTerminator(I);
3308 KnownVal = tryEvaluateBool(I->
getCond());
3312 addSuccessor(
Block, ThenBlock, !KnownVal.isFalse());
3313 addSuccessor(
Block, ElseBlock, !KnownVal.isTrue());
3321 LastBlock = addStmt(I->
getCond());
3327 LastBlock = addStmt(
const_cast<DeclStmt *
>(DS));
3334 LastBlock = addStmt(
Init);
3340CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {
3350 Block = createBlock(
false);
3352 addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), S);
3354 if (
auto *R = dyn_cast<ReturnStmt>(S))
3355 findConstructionContexts(
3361 if (!
Block->hasNoReturnElement())
3362 addSuccessor(
Block, &cfg->getExit());
3365 appendStmt(
Block, S);
3368 if (ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
3369 if (Expr *O = RS->getRetValue())
3370 return Visit(O, AddStmtChoice::AlwaysAdd,
true);
3382 if (CFGBlock *R = Visit(RV))
3388CFGBlock *CFGBuilder::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E,
3389 AddStmtChoice asc) {
3393 if (asc.alwaysAdd(*
this, E)) {
3395 appendStmt(
Block, E);
3397 CFGBlock *B =
Block;
3409CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
3415 SaveAndRestore save_scope_pos(ScopePos);
3418 CFGBlock *SEHExceptBlock =
Block;
3419 if (!SEHExceptBlock)
3420 SEHExceptBlock = createBlock();
3422 appendStmt(SEHExceptBlock, ES);
3434 return SEHExceptBlock;
3437CFGBlock *CFGBuilder::VisitSEHFinallyStmt(SEHFinallyStmt *FS) {
3438 return VisitCompoundStmt(FS->
getBlock(),
false);
3441CFGBlock *CFGBuilder::VisitSEHLeaveStmt(SEHLeaveStmt *LS) {
3448 Block = createBlock(
false);
3449 Block->setTerminator(LS);
3453 if (SEHLeaveJumpTarget.block) {
3454 addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS);
3455 addSuccessor(
Block, SEHLeaveJumpTarget.block);
3462CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) {
3465 CFGBlock *SEHTrySuccessor =
nullptr;
3470 SEHTrySuccessor =
Block;
3471 }
else SEHTrySuccessor = Succ;
3477 CFGBlock *PrevSEHTryTerminatedBlock = TryTerminatedBlock;
3480 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
3487 Succ = SEHTrySuccessor;
3489 CFGBlock *ExceptBlock = VisitSEHExceptStmt(Except);
3494 addSuccessor(NewTryTerminatedBlock, ExceptBlock);
3496 if (PrevSEHTryTerminatedBlock)
3497 addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock);
3499 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
3502 Succ = SEHTrySuccessor;
3505 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
3506 cfg->addTryDispatchBlock(TryTerminatedBlock);
3511 SaveAndRestore save_break(SEHLeaveJumpTarget);
3512 SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
3514 assert(Terminator->
getTryBlock() &&
"__try must contain a non-NULL body");
3519CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
3522 CFGBlock *LabelBlock =
Block;
3525 LabelBlock = createBlock();
3527 assert(!LabelMap.contains(L->
getDecl()) &&
"label already in map");
3528 LabelMap[L->
getDecl()] = JumpTarget(LabelBlock, ScopePos);
3547CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
3548 CFGBlock *LastBlock = VisitNoRecurse(E, asc);
3550 if (Expr *CopyExpr = CI.getCopyExpr()) {
3551 CFGBlock *Tmp = Visit(CopyExpr);
3559CFGBlock *CFGBuilder::VisitLambdaExpr(
LambdaExpr *E, AddStmtChoice asc) {
3560 CFGBlock *LastBlock = VisitNoRecurse(E, asc);
3565 it != et; ++it, ++Idx) {
3566 if (Expr *
Init = *it) {
3570 dyn_cast<ArrayInitLoopExpr>(
Init));
3573 cfg->getBumpVectorContext(), {E, Idx}),
3574 AILEInit ? AILEInit :
Init);
3576 CFGBlock *Tmp = Visit(
Init);
3584CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
3588 Block = createBlock(
false);
3589 Block->setTerminator(G);
3592 LabelMapTy::iterator I = LabelMap.find(G->
getLabel());
3594 if (I == LabelMap.end())
3596 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3598 JumpTarget JT = I->second;
3599 addSuccessor(
Block, JT.block);
3600 addScopeChangesHandling(ScopePos, JT.scopePosition, G);
3606CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) {
3611 return VisitStmt(G, asc);
3618 Block = createBlock();
3619 Block->setTerminator(G);
3621 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3624 BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
3625 return VisitChildren(G);
3628CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
3629 CFGBlock *LoopSuccessor =
nullptr;
3633 SaveAndRestore save_scope_pos(ScopePos);
3639 addLocalScopeForStmt(
Init);
3640 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3643 addLocalScopeForVarDecl(VD);
3644 LocalScope::const_iterator ContinueScopePos = ScopePos;
3646 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
3655 LoopSuccessor =
Block;
3657 LoopSuccessor = Succ;
3661 SaveAndRestore save_break(BreakJumpTarget);
3662 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3664 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3671 SaveAndRestore save_Block(
Block), save_Succ(Succ);
3672 SaveAndRestore save_continue(ContinueJumpTarget);
3677 Block = Succ = TransitionBlock = createBlock(
false);
3678 TransitionBlock->setLoopTarget(F);
3683 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
3685 if (Stmt *I = F->
getInc()) {
3693 assert(
Block == Succ);
3701 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
3702 ContinueJumpTarget.block->setLoopTarget(F);
3708 addLocalScopeAndDtors(F->
getBody());
3712 BodyBlock = addStmt(F->
getBody());
3717 BodyBlock = ContinueJumpTarget.block;
3726 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3730 SaveAndRestore save_scope_pos(ScopePos);
3734 if (BinaryOperator *
Cond =
3735 dyn_cast_or_null<BinaryOperator>(
C ?
C->IgnoreParens() :
nullptr))
3736 if (
Cond->isLogicalOp()) {
3737 std::tie(EntryConditionBlock, ExitConditionBlock) =
3738 VisitLogicalOperator(
Cond, F, BodyBlock, LoopSuccessor);
3743 EntryConditionBlock = ExitConditionBlock = createBlock(
false);
3744 ExitConditionBlock->setTerminator(F);
3747 TryResult KnownVal(
true);
3753 Block = ExitConditionBlock;
3754 EntryConditionBlock = addStmt(
C);
3763 findConstructionContexts(
3766 appendStmt(
Block, DS);
3767 EntryConditionBlock = addStmt(
Init);
3768 assert(
Block == EntryConditionBlock);
3769 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3773 if (
Block && badCFG)
3776 KnownVal = tryEvaluateBool(
C);
3780 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
3783 addSuccessor(ExitConditionBlock,
3784 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
3788 addSuccessor(TransitionBlock, EntryConditionBlock);
3791 Succ = EntryConditionBlock;
3796 SaveAndRestore save_scope_pos(ScopePos);
3797 ScopePos = LoopBeginScopePos;
3798 Block = createBlock();
3805 Succ = EntryConditionBlock;
3806 return EntryConditionBlock;
3810CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
3811 AddStmtChoice asc) {
3812 findConstructionContexts(
3816 return VisitStmt(MTE, asc);
3819CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
3820 if (asc.alwaysAdd(*
this, M)) {
3822 appendStmt(
Block, M);
3827CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
3859 CFGBlock *LoopSuccessor =
nullptr;
3864 LoopSuccessor =
Block;
3867 LoopSuccessor = Succ;
3870 CFGBlock *ExitConditionBlock = createBlock(
false);
3878 appendStmt(ExitConditionBlock, S);
3879 Block = ExitConditionBlock;
3884 CFGBlock *EntryConditionBlock = Visit(S->
getElement(),
3885 AddStmtChoice::NotAlwaysAdd);
3894 Succ = EntryConditionBlock;
3899 SaveAndRestore save_Block(
Block), save_Succ(Succ);
3900 SaveAndRestore save_continue(ContinueJumpTarget),
3901 save_break(BreakJumpTarget);
3906 CFGBlock *LoopBackBlock =
nullptr;
3907 Succ = LoopBackBlock = createBlock();
3910 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3911 ContinueJumpTarget = JumpTarget(Succ, ScopePos);
3913 CFGBlock *BodyBlock = addStmt(S->
getBody());
3916 BodyBlock = ContinueJumpTarget.block;
3923 addSuccessor(ExitConditionBlock, BodyBlock);
3928 addSuccessor(ExitConditionBlock, LoopSuccessor);
3931 Block = createBlock();
3935CFGBlock *CFGBuilder::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
3941CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
3959 appendStmt(
Block, S);
3965CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
3969 appendStmt(
Block, E);
3971 CFGBlock *lastBlock =
Block;
3980 if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic))
3981 Semantic = OVE->getSourceExpr();
3983 if (CFGBlock *B = Visit(Semantic))
3990CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
3991 CFGBlock *LoopSuccessor =
nullptr;
3995 SaveAndRestore save_scope_pos(ScopePos);
3999 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
4001 addLocalScopeForVarDecl(VD);
4002 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4011 LoopSuccessor =
Block;
4014 LoopSuccessor = Succ;
4017 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
4024 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4025 SaveAndRestore save_continue(ContinueJumpTarget),
4026 save_break(BreakJumpTarget);
4030 Succ = TransitionBlock = createBlock(
false);
4031 TransitionBlock->setLoopTarget(W);
4032 ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
4035 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4038 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4043 addLocalScopeAndDtors(W->
getBody());
4046 BodyBlock = addStmt(W->
getBody());
4049 BodyBlock = ContinueJumpTarget.block;
4050 else if (
Block && badCFG)
4057 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
4064 if (BinaryOperator *
Cond = dyn_cast<BinaryOperator>(
C->IgnoreParens()))
4065 if (
Cond->isLogicalOp()) {
4066 std::tie(EntryConditionBlock, ExitConditionBlock) =
4067 VisitLogicalOperator(
Cond, W, BodyBlock, LoopSuccessor);
4072 ExitConditionBlock = createBlock(
false);
4078 Block = ExitConditionBlock;
4079 Block = EntryConditionBlock = addStmt(
C);
4088 findConstructionContexts(
4090 const_cast<DeclStmt *
>(DS)),
4092 appendStmt(
Block, DS);
4093 EntryConditionBlock = addStmt(
Init);
4094 assert(
Block == EntryConditionBlock);
4095 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
4099 if (
Block && badCFG)
4103 const TryResult& KnownVal = tryEvaluateBool(
C);
4106 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
4109 addSuccessor(ExitConditionBlock,
4110 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4114 addSuccessor(TransitionBlock, EntryConditionBlock);
4121 Succ = EntryConditionBlock;
4122 return EntryConditionBlock;
4125CFGBlock *CFGBuilder::VisitArrayInitLoopExpr(ArrayInitLoopExpr *A,
4126 AddStmtChoice asc) {
4127 if (asc.alwaysAdd(*
this, A)) {
4129 appendStmt(
Block, A);
4132 CFGBlock *B =
Block;
4138 assert(OVE &&
"ArrayInitLoopExpr->getCommonExpr() should be wrapped in an "
4139 "OpaqueValueExpr!");
4140 if (CFGBlock *R = Visit(OVE->getSourceExpr()))
4146CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *CS) {
4152 SaveAndRestore save_scope_pos(ScopePos);
4157 CFGBlock *CatchBlock =
Block;
4159 CatchBlock = createBlock();
4161 appendStmt(CatchBlock, CS);
4176CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
4182 Block = createBlock(
false);
4184 if (TryTerminatedBlock)
4186 addSuccessor(
Block, TryTerminatedBlock);
4189 addSuccessor(
Block, &cfg->getExit());
4193 return VisitStmt(S, AddStmtChoice::AlwaysAdd);
4196CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *Terminator) {
4199 CFGBlock *TrySuccessor =
nullptr;
4204 TrySuccessor =
Block;
4206 TrySuccessor = Succ;
4212 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4215 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4219 bool HasCatchAll =
false;
4220 for (ObjCAtCatchStmt *CS : Terminator->
catch_stmts()) {
4222 Succ = TrySuccessor;
4227 CFGBlock *CatchBlock = VisitObjCAtCatchStmt(CS);
4232 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4237 if (PrevTryTerminatedBlock)
4238 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4240 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4244 Succ = TrySuccessor;
4247 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4248 cfg->addTryDispatchBlock(TryTerminatedBlock);
4250 assert(Terminator->
getTryBody() &&
"try must contain a non-NULL body");
4255CFGBlock *CFGBuilder::VisitObjCMessageExpr(ObjCMessageExpr *ME,
4256 AddStmtChoice asc) {
4257 findConstructionContextsForArguments(ME);
4260 appendObjCMessage(
Block, ME);
4262 return VisitChildren(ME);
4265CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *
T) {
4271 Block = createBlock(
false);
4273 if (TryTerminatedBlock)
4275 addSuccessor(
Block, TryTerminatedBlock);
4278 addSuccessor(
Block, &cfg->getExit());
4282 return VisitStmt(
T, AddStmtChoice::AlwaysAdd);
4285CFGBlock *CFGBuilder::VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc) {
4286 if (asc.alwaysAdd(*
this, S)) {
4288 appendStmt(
Block, S);
4298 return VisitChildren(S);
4304CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
4305 CFGBlock *LoopSuccessor =
nullptr;
4314 LoopSuccessor =
Block;
4316 LoopSuccessor = Succ;
4321 CFGBlock *ExitConditionBlock = createBlock(
false);
4322 CFGBlock *EntryConditionBlock = ExitConditionBlock;
4330 Block = ExitConditionBlock;
4331 EntryConditionBlock = addStmt(
C);
4339 Succ = EntryConditionBlock;
4342 const TryResult &KnownVal = tryEvaluateBool(D->
getCond());
4345 CFGBlock *BodyBlock =
nullptr;
4350 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4351 SaveAndRestore save_continue(ContinueJumpTarget),
4352 save_break(BreakJumpTarget);
4355 ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
4358 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4366 addLocalScopeAndDtors(D->
getBody());
4369 BodyBlock = addStmt(D->
getBody());
4372 BodyBlock = EntryConditionBlock;
4385 CFGBlock *LoopBackBlock = createBlock();
4388 if (!KnownVal.isFalse())
4390 addSuccessor(ExitConditionBlock, LoopBackBlock);
4392 addSuccessor(ExitConditionBlock,
nullptr);
4397 addSuccessor(ExitConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4408CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *
C) {
4415 Block = createBlock(
false);
4420 if (ContinueJumpTarget.block) {
4421 addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition,
C);
4422 addSuccessor(
Block, ContinueJumpTarget.block);
4429CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
4430 AddStmtChoice asc) {
4431 if (asc.alwaysAdd(*
this, E)) {
4433 appendStmt(
Block, E);
4439 if (E->
getKind() != UETT_SizeOf)
4442 CFGBlock *lastBlock =
Block;
4446 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr()))
4447 lastBlock = addStmt(VA->getSizeExpr());
4454CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
4455 if (asc.alwaysAdd(*
this, SE)) {
4457 appendStmt(
Block, SE);
4459 return VisitCompoundStmt(SE->
getSubStmt(),
true);
4462CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
4465 CFGBlock *SwitchSuccessor =
nullptr;
4469 SaveAndRestore save_scope_pos(ScopePos);
4473 addLocalScopeForStmt(
Init);
4478 addLocalScopeForVarDecl(VD);
4480 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
4485 SwitchSuccessor =
Block;
4486 }
else SwitchSuccessor = Succ;
4489 SaveAndRestore save_switch(SwitchTerminatedBlock),
4490 save_default(DefaultCaseBlock);
4491 SaveAndRestore save_break(BreakJumpTarget);
4496 DefaultCaseBlock = SwitchSuccessor;
4499 SwitchTerminatedBlock = createBlock(
false);
4503 Succ = SwitchSuccessor;
4504 BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
4509 assert(Terminator->
getBody() &&
"switch must contain a non-NULL body");
4514 SaveAndRestore save_switchExclusivelyCovered(switchExclusivelyCovered,
false);
4517 assert(Terminator->
getCond() &&
"switch condition must be non-NULL");
4518 Expr::EvalResult result;
4519 bool b = tryEvaluate(Terminator->
getCond(), result);
4520 SaveAndRestore save_switchCond(switchCond,
b ? &result :
nullptr);
4525 addLocalScopeAndDtors(Terminator->
getBody());
4527 addStmt(Terminator->
getBody());
4541 bool SwitchAlwaysHasSuccessor =
false;
4542 SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
4543 SwitchAlwaysHasSuccessor |=
4546 addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock,
4547 !SwitchAlwaysHasSuccessor);
4551 Block = SwitchTerminatedBlock;
4552 CFGBlock *LastBlock = addStmt(Terminator->
getCond());
4560 LastBlock = addStmt(
Init);
4561 maybeAddScopeBeginForVarDecl(LastBlock, VD,
Init);
4568 LastBlock = addStmt(
Init);
4581 bool addCase =
false;
4583 if (!switchExclusivelyCovered) {
4587 const llvm::APSInt &condInt = switchCond->
Val.
getInt();
4589 if (condInt == lhsInt) {
4591 switchExclusivelyCovered =
true;
4593 else if (condInt > lhsInt) {
4597 if (V2 >= condInt) {
4599 switchExclusivelyCovered =
true;
4610CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
4613 CFGBlock *TopBlock =
nullptr, *LastBlock =
nullptr;
4620 CFGBlock *currentBlock = createBlock(
false);
4624 addSuccessor(LastBlock, currentBlock);
4626 TopBlock = currentBlock;
4628 addSuccessor(SwitchTerminatedBlock,
4631 ? currentBlock :
nullptr);
4633 LastBlock = currentBlock;
4641 CFGBlock *CaseBlock =
Block;
4643 CaseBlock = createBlock();
4654 assert(SwitchTerminatedBlock);
4655 addSuccessor(SwitchTerminatedBlock, CaseBlock,
4663 addSuccessor(LastBlock, CaseBlock);
4673CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {
4677 DefaultCaseBlock =
Block;
4679 if (!DefaultCaseBlock)
4680 DefaultCaseBlock = createBlock();
4684 DefaultCaseBlock->
setLabel(Terminator);
4699 Succ = DefaultCaseBlock;
4701 return DefaultCaseBlock;
4704CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
4707 CFGBlock *TrySuccessor =
nullptr;
4712 TrySuccessor =
Block;
4714 TrySuccessor = Succ;
4716 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4719 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4723 bool HasCatchAll =
false;
4724 for (
unsigned I = 0, E = Terminator->
getNumHandlers(); I != E; ++I) {
4726 Succ = TrySuccessor;
4727 CXXCatchStmt *CS = Terminator->
getHandler(I);
4732 CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
4737 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4740 if (PrevTryTerminatedBlock)
4741 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4743 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4747 Succ = TrySuccessor;
4750 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4751 cfg->addTryDispatchBlock(TryTerminatedBlock);
4753 assert(Terminator->
getTryBlock() &&
"try must contain a non-NULL body");
4758CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
4764 SaveAndRestore save_scope_pos(ScopePos);
4769 LocalScope::const_iterator BeginScopePos = ScopePos;
4770 addLocalScopeForVarDecl(VD);
4771 addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
4777 CFGBlock *CatchBlock =
Block;
4779 CatchBlock = createBlock();
4785 appendStmt(CatchBlock, CS);
4801CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
4816 SaveAndRestore save_scope_pos(ScopePos);
4821 addLocalScopeForStmt(
Init);
4823 addLocalScopeForStmt(Range);
4825 addLocalScopeForStmt(Begin);
4827 addLocalScopeForStmt(End);
4828 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
4830 LocalScope::const_iterator ContinueScopePos = ScopePos;
4834 CFGBlock *LoopSuccessor =
nullptr;
4838 LoopSuccessor =
Block;
4840 LoopSuccessor = Succ;
4844 SaveAndRestore save_break(BreakJumpTarget);
4845 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4848 CFGBlock *ConditionBlock = createBlock(
false);
4853 Block = ConditionBlock;
4854 CFGBlock *BeginConditionBlock = addStmt(
C);
4857 assert(BeginConditionBlock == ConditionBlock &&
4858 "condition block in for-range was unexpectedly complex");
4859 (void)BeginConditionBlock;
4864 Succ = ConditionBlock;
4867 TryResult KnownVal(
true);
4870 KnownVal = tryEvaluateBool(S->
getCond());
4877 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4878 SaveAndRestore save_continue(ContinueJumpTarget);
4883 Succ = addStmt(S->
getInc());
4886 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
4890 ContinueJumpTarget.block->setLoopTarget(S);
4904 addLocalScopeAndDtors(S->
getBody());
4916 addSuccessor(ConditionBlock,
4917 KnownVal.isFalse() ?
nullptr : LoopVarStmtBlock);
4922 addSuccessor(ConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4925 Block = createBlock();
4934CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
4935 AddStmtChoice asc,
bool ExternallyDestructed) {
4939 TempDtorContext Context;
4940 VisitForTemporaryDtors(E->
getSubExpr(), ExternallyDestructed, Context);
4944 asc = asc.withAlwaysAdd(
true);
4949CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
4950 AddStmtChoice asc) {
4951 if (asc.alwaysAdd(*
this, E)) {
4953 appendStmt(
Block, E);
4955 findConstructionContexts(
4960 asc = asc.withAlwaysAdd(
false);
4965CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *
C,
4966 AddStmtChoice asc) {
4970 findConstructionContextsForArguments(
C);
4971 appendConstructor(
C);
4973 return VisitChildren(
C);
4976CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
4977 AddStmtChoice asc) {
4979 appendStmt(
Block, NE);
4981 findConstructionContexts(
4983 const_cast<CXXConstructExpr *
>(
NE->getConstructExpr()));
4985 if (
NE->getInitializer())
4986 Block = Visit(
NE->getInitializer());
4989 appendNewAllocator(
Block, NE);
4991 if (
NE->isArray() && *
NE->getArraySize())
4992 Block = Visit(*
NE->getArraySize());
4995 E =
NE->placement_arg_end(); I != E; ++I)
5001CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
5002 AddStmtChoice asc) {
5004 appendStmt(
Block, DE);
5011 appendDeleteDtor(
Block, RD, DE);
5015 return VisitChildren(DE);
5018CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
5019 AddStmtChoice asc) {
5020 if (asc.alwaysAdd(*
this, E)) {
5022 appendStmt(
Block, E);
5024 asc = asc.withAlwaysAdd(
false);
5029CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E,
5030 AddStmtChoice asc) {
5034 findConstructionContextsForArguments(E);
5035 appendConstructor(E);
5037 return VisitChildren(E);
5040CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
5041 AddStmtChoice asc) {
5042 if (asc.alwaysAdd(*
this, E)) {
5044 appendStmt(
Block, E);
5050 return Visit(E->
getSubExpr(), AddStmtChoice());
5053CFGBlock *CFGBuilder::VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc) {
5054 return Visit(E->
getSubExpr(), AddStmtChoice());
5057CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
5059 CFGBlock *IBlock = cfg->getIndirectGotoBlock();
5062 IBlock = createBlock(
false);
5063 cfg->setIndirectGotoBlock(IBlock);
5071 Block = createBlock(
false);
5072 Block->setTerminator(I);
5073 addSuccessor(
Block, IBlock);
5077CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E,
bool ExternallyDestructed,
5078 TempDtorContext &Context) {
5088 return VisitChildrenForTemporaryDtors(E,
false, Context);
5090 case Stmt::InitListExprClass:
5091 return VisitChildrenForTemporaryDtors(E, ExternallyDestructed, Context);
5093 case Stmt::BinaryOperatorClass:
5095 ExternallyDestructed,
5098 case Stmt::CXXBindTemporaryExprClass:
5099 return VisitCXXBindTemporaryExprForTemporaryDtors(
5102 case Stmt::BinaryConditionalOperatorClass:
5103 case Stmt::ConditionalOperatorClass:
5104 return VisitConditionalOperatorForTemporaryDtors(
5107 case Stmt::ImplicitCastExprClass:
5112 case Stmt::CXXFunctionalCastExprClass:
5117 case Stmt::ConstantExprClass:
5121 case Stmt::ParenExprClass:
5125 case Stmt::MaterializeTemporaryExprClass: {
5128 SmallVector<const Expr *, 2> CommaLHSs;
5129 SmallVector<SubobjectAdjustment, 2> Adjustments;
5131 E =
const_cast<Expr *
>(
5134 ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
5136 for (
const Expr *CommaLHS : CommaLHSs) {
5137 VisitForTemporaryDtors(
const_cast<Expr *
>(CommaLHS),
5143 case Stmt::BlockExprClass:
5148 case Stmt::LambdaExprClass: {
5152 CFGBlock *B =
Block;
5153 for (Expr *
Init :
LE->capture_inits()) {
5155 if (CFGBlock *R = VisitForTemporaryDtors(
5156 Init,
true, Context))
5163 case Stmt::StmtExprClass:
5168 case Stmt::CXXDefaultArgExprClass:
5172 case Stmt::CXXDefaultInitExprClass:
5178CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E,
5179 bool ExternallyDestructed,
5180 TempDtorContext &Context) {
5190 CFGBlock *B =
Block;
5193 if (CFGBlock *R = VisitForTemporaryDtors(Child, ExternallyDestructed, Context))
5199CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
5200 BinaryOperator *E,
bool ExternallyDestructed, TempDtorContext &Context) {
5204 CFGBlock *LHSBlock = VisitForTemporaryDtors(E->
getLHS(),
false, Context);
5205 CFGBlock *RHSBlock = VisitForTemporaryDtors(E->
getRHS(), ExternallyDestructed, Context);
5206 return RHSBlock ? RHSBlock : LHSBlock;
5210 VisitForTemporaryDtors(E->
getLHS(),
false, Context);
5211 TryResult RHSExecuted = tryEvaluateBool(E->
getLHS());
5212 if (RHSExecuted.isKnown() && E->
getOpcode() == BO_LOr)
5213 RHSExecuted.negate();
5218 TempDtorContext RHSContext(
5220 VisitForTemporaryDtors(E->
getRHS(),
false, RHSContext);
5221 InsertTempDtorDecisionBlock(RHSContext);
5229 CFGBlock *RHSBlock = VisitForTemporaryDtors(E->
getRHS(),
false, Context);
5230 CFGBlock *LHSBlock = VisitForTemporaryDtors(E->
getLHS(),
false, Context);
5231 return LHSBlock ? LHSBlock : RHSBlock;
5235 return VisitChildrenForTemporaryDtors(E, ExternallyDestructed, Context);
5238CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
5239 CXXBindTemporaryExpr *E,
bool ExternallyDestructed, TempDtorContext &Context) {
5242 CFGBlock *B = VisitForTemporaryDtors(E->
getSubExpr(),
true, Context);
5243 if (!ExternallyDestructed) {
5255 Block = createNoReturnBlock();
5256 }
else if (Context.needsTempDtorBranch()) {
5260 Block = createBlock();
5264 if (Context.needsTempDtorBranch()) {
5265 Context.setDecisionPoint(Succ, E);
5267 appendTemporaryDtor(
Block, E);
5274void CFGBuilder::InsertTempDtorDecisionBlock(
const TempDtorContext &Context,
5275 CFGBlock *FalseSucc) {
5276 if (!Context.TerminatorExpr) {
5280 assert(Context.TerminatorExpr);
5281 CFGBlock *Decision = createBlock(
false);
5282 Decision->setTerminator(CFGTerminator(Context.TerminatorExpr,
5284 addSuccessor(Decision,
Block, !Context.KnownExecuted.isFalse());
5285 addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
5286 !Context.KnownExecuted.isTrue());
5290CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
5291 AbstractConditionalOperator *E,
bool ExternallyDestructed,
5292 TempDtorContext &Context) {
5293 VisitForTemporaryDtors(E->
getCond(),
false, Context);
5294 CFGBlock *ConditionBlock =
Block;
5295 CFGBlock *ConditionSucc = Succ;
5296 TryResult ConditionVal = tryEvaluateBool(E->
getCond());
5297 TryResult NegatedVal = ConditionVal;
5298 if (NegatedVal.isKnown()) NegatedVal.negate();
5300 TempDtorContext TrueContext(
5302 VisitForTemporaryDtors(E->
getTrueExpr(), ExternallyDestructed, TrueContext);
5303 CFGBlock *TrueBlock =
Block;
5305 Block = ConditionBlock;
5306 Succ = ConditionSucc;
5307 TempDtorContext FalseContext(
5309 VisitForTemporaryDtors(E->
getFalseExpr(), ExternallyDestructed, FalseContext);
5311 if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
5312 InsertTempDtorDecisionBlock(FalseContext, TrueBlock);
5313 }
else if (TrueContext.TerminatorExpr) {
5315 InsertTempDtorDecisionBlock(TrueContext);
5317 InsertTempDtorDecisionBlock(FalseContext);
5322CFGBlock *CFGBuilder::VisitOMPExecutableDirective(OMPExecutableDirective *D,
5323 AddStmtChoice asc) {
5324 if (asc.alwaysAdd(*
this, D)) {
5326 appendStmt(
Block, D);
5330 CFGBlock *B =
Block;
5334 SmallVector<Stmt *, 8>
Used(
5335 OMPExecutableDirective::used_clauses_children(D->clauses()));
5336 for (Stmt *S : llvm::reverse(
Used)) {
5337 assert(S &&
"Expected non-null used-in-clause child.");
5338 if (CFGBlock *R = Visit(S))
5342 if (!D->isStandaloneDirective()) {
5343 Stmt *S = D->getRawStmt();
5345 addLocalScopeAndDtors(S);
5346 if (CFGBlock *R = addStmt(S))
5357 bool first_block =
begin() ==
end();
5361 Blocks.push_back(Mem, BlkBVC);
5365 Entry = Exit = &
back();
5374 llvm::TimeTraceScope TimeProfile(
"BuildCFG");
5375 CFGBuilder Builder(
C, BO);
5376 return Builder.buildCFG(D, Statement);
5391 auto IteratorAndFlag = Visited.insert(B);
5392 if (!IteratorAndFlag.second) {
5398 const CFGBlock *FirstReachableB =
nullptr;
5400 if (!AB.isReachable())
5403 if (FirstReachableB ==
nullptr) {
5404 FirstReachableB = &*AB;
5411 if (!FirstReachableB) {
5417 B = FirstReachableB;
5437 llvm_unreachable(
"getDestructorDecl should only be used with "
5448 if (
const Expr *
Init = var->getInit()) {
5495 llvm_unreachable(
"getKind() returned bogus value");
5503 : ReachableBlock(IsReachable ? B :
nullptr),
5504 UnreachableBlock(!IsReachable ? B :
nullptr,
5505 B && IsReachable ? AB_Normal : AB_Unreachable) {}
5508 : ReachableBlock(B),
5509 UnreachableBlock(B == AlternateBlock ?
nullptr : AlternateBlock,
5510 B == AlternateBlock ? AB_Alternate : AB_Normal) {}
5520 Succs.push_back(Succ,
C);
5533 if (S->isAllEnumCasesCovered()) {
5551 using StmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>;
5552 using DeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>;
5556 signed currentBlock = 0;
5557 unsigned currStmt = 0;
5567 for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
5568 BI != BEnd; ++BI, ++j ) {
5569 if (std::optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
5570 const Stmt *stmt= SE->getStmt();
5571 std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
5574 switch (stmt->getStmtClass()) {
5575 case Stmt::DeclStmtClass:
5576 DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P;
5578 case Stmt::IfStmtClass: {
5579 const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable();
5584 case Stmt::ForStmtClass: {
5585 const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable();
5590 case Stmt::WhileStmtClass: {
5591 const VarDecl *var =
5592 cast<WhileStmt>(stmt)->getConditionVariable();
5597 case Stmt::SwitchStmtClass: {
5598 const VarDecl *var =
5599 cast<SwitchStmt>(stmt)->getConditionVariable();
5604 case Stmt::CXXCatchStmtClass: {
5605 const VarDecl *var =
5606 cast<CXXCatchStmt>(stmt)->getExceptionDecl();
5619 ~StmtPrinterHelper()
override =
default;
5621 const LangOptions &getLangOpts()
const {
return LangOpts; }
5622 void setBlockID(
signed i) { currentBlock = i; }
5623 void setStmtID(
unsigned i) { currStmt = i; }
5625 bool handledStmt(Stmt *S, raw_ostream &OS)
override {
5626 StmtMapTy::iterator I = StmtMap.find(S);
5628 if (I == StmtMap.end())
5631 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5632 && I->second.second == currStmt) {
5636 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5640 bool handleDecl(
const Decl *D, raw_ostream &OS) {
5641 DeclMapTy::iterator I = DeclMap.find(D);
5643 if (I == DeclMap.end()) {
5646 if (
auto *PVD = dyn_cast_or_null<ParmVarDecl>(D)) {
5647 OS <<
"[Parm: " << PVD->getNameAsString() <<
"]";
5653 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5654 && I->second.second == currStmt) {
5658 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5663class CFGBlockTerminatorPrint
5664 :
public StmtVisitor<CFGBlockTerminatorPrint,void> {
5666 StmtPrinterHelper* Helper;
5667 PrintingPolicy Policy;
5670 CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
5671 const PrintingPolicy &Policy)
5672 :
OS(os), Helper(helper), Policy(Policy) {
5676 void VisitIfStmt(IfStmt *I) {
5679 C->printPretty(OS, Helper, Policy);
5683 void VisitStmt(Stmt *Terminator) {
5687 void VisitDeclStmt(DeclStmt *DS) {
5692 void VisitForStmt(ForStmt *F) {
5698 C->printPretty(OS, Helper, Policy);
5705 void VisitWhileStmt(WhileStmt *W) {
5708 C->printPretty(OS, Helper, Policy);
5711 void VisitDoStmt(DoStmt *D) {
5712 OS <<
"do ... while ";
5714 C->printPretty(OS, Helper, Policy);
5717 void VisitSwitchStmt(SwitchStmt *Terminator) {
5722 void VisitCXXTryStmt(CXXTryStmt *) {
OS <<
"try ..."; }
5724 void VisitObjCAtTryStmt(ObjCAtTryStmt *) {
OS <<
"@try ..."; }
5726 void VisitSEHTryStmt(SEHTryStmt *CS) {
OS <<
"__try ..."; }
5728 void VisitAbstractConditionalOperator(AbstractConditionalOperator*
C) {
5729 if (Stmt *
Cond =
C->getCond())
5731 OS <<
" ? ... : ...";
5734 void VisitChooseExpr(ChooseExpr *
C) {
5735 OS <<
"__builtin_choose_expr( ";
5736 if (Stmt *
Cond =
C->getCond())
5741 void VisitIndirectGotoStmt(IndirectGotoStmt *I) {
5744 T->printPretty(OS, Helper, Policy);
5747 void VisitBinaryOperator(BinaryOperator* B) {
5764 llvm_unreachable(
"Invalid logical operator.");
5768 void VisitExpr(Expr *E) {
5773 void print(CFGTerminator
T) {
5774 switch (
T.getKind()) {
5779 OS <<
"(Temp Dtor) ";
5783 OS <<
"(See if most derived ctor has already initialized vbases)";
5805 OS <<
" (Base initializer)";
5807 OS <<
" (Delegating initializer)";
5809 OS <<
" (Member initializer)";
5813 StmtPrinterHelper &Helper,
5828 Stmts.push_back(CICC->getCXXBindTemporaryExpr());
5833 Stmts.push_back(SDSCC->getDeclStmt());
5838 Stmts.push_back(CDSCC->getDeclStmt());
5839 Stmts.push_back(CDSCC->getCXXBindTemporaryExpr());
5844 Stmts.push_back(NECC->getCXXNewExpr());
5849 Stmts.push_back(RSCC->getReturnStmt());
5855 Stmts.push_back(RSCC->getReturnStmt());
5856 Stmts.push_back(RSCC->getCXXBindTemporaryExpr());
5861 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5862 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5867 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5868 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5869 Stmts.push_back(TOCC->getConstructorAfterElision());
5874 Helper.handledStmt(
const_cast<LambdaExpr *
>(LCC->getLambdaExpr()), OS);
5875 OS <<
"+" << LCC->getIndex();
5880 if (
const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
5882 Helper.handledStmt(
const_cast<Stmt *
>(BTE), OS);
5885 Helper.handledStmt(
const_cast<Expr *
>(ACC->getCallLikeExpr()), OS);
5886 OS <<
"+" << ACC->getIndex();
5893 Helper.handledStmt(
const_cast<Stmt *
>(I), OS);
5897static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5898 const CFGElement &E,
bool TerminateWithNewLine =
true);
5901 bool TerminateWithNewLine)
const {
5903 StmtPrinterHelper Helper(
nullptr, LangOpts);
5904 print_elem(OS, Helper, *
this, TerminateWithNewLine);
5907static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5908 const CFGElement &E,
bool TerminateWithNewLine) {
5915 assert(S !=
nullptr &&
"Expecting non-null Stmt");
5918 if (
const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
5926 if (TerminateWithNewLine)
5935 Helper.handledStmt(B->
getRHS(),OS);
5936 if (TerminateWithNewLine)
5941 S->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
5945 OS <<
" (OperatorCall)";
5946 OS <<
" (CXXRecordTypedCall";
5950 OS <<
" (OperatorCall)";
5952 OS <<
" (BindTemporary)";
5954 OS <<
" (CXXConstructExpr";
5958 OS <<
", " << CCE->getType() <<
")";
5959 }
else if (
const CastExpr *CE = dyn_cast<CastExpr>(S)) {
5961 <<
", " << CE->
getType() <<
")";
5965 if (
isa<Expr>(S) && TerminateWithNewLine)
5978 Helper.handleDecl(VD, OS);
5981 if (
T->isReferenceType())
5985 T.getUnqualifiedType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5986 OS <<
"() (Implicit destructor)";
5991 OS <<
"CleanupFunction ("
5997 OS <<
" (Lifetime ends)";
6006 OS <<
"CFGScopeBegin(";
6013 OS <<
"CFGScopeEnd(";
6020 OS <<
"CFGNewAllocator(";
6022 AllocExpr->getType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
6034 OS <<
"->~" << RD->getName().str() <<
"()";
6035 OS <<
" (Implicit destructor)";
6042 OS <<
" (Base object destructor)";
6049 OS <<
"this->" << FD->
getName();
6050 OS <<
".~" <<
T->getAsCXXRecordDecl()->getName() <<
"()";
6051 OS <<
" (Member object destructor)";
6060 OS <<
"() (Temporary object destructor)";
6064 if (TerminateWithNewLine)
6070 StmtPrinterHelper &Helper,
bool print_edges,
6076 OS.changeColor(raw_ostream::YELLOW,
true);
6081 OS <<
" (ENTRY)]\n";
6082 else if (&B == &cfg->
getExit())
6085 OS <<
" (INDIRECT GOTO DISPATCH)]\n";
6087 OS <<
" (NORETURN)]\n";
6103 if (
const Expr *LHS =
C->getLHS())
6105 if (
const Expr *RHS =
C->getRHS()) {
6120 if (
const VarDecl *PD = CS->getCatchParamDecl())
6131 llvm_unreachable(
"Invalid label statement in CFGBlock.");
6140 I != E ; ++I, ++j ) {
6145 OS << llvm::format(
"%3d", j) <<
": ";
6147 Helper.setStmtID(j);
6155 OS.changeColor(raw_ostream::GREEN);
6159 Helper.setBlockID(-1);
6162 CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
6173 const raw_ostream::Colors Color = raw_ostream::BLUE;
6175 OS.changeColor(Color);
6183 OS.changeColor(Color);
6191 bool Reachable =
true;
6194 B = I->getPossiblyUnreachableBlock();
6199 OS <<
"(Unreachable)";
6210 const raw_ostream::Colors Color = raw_ostream::MAGENTA;
6212 OS.changeColor(Color);
6220 OS.changeColor(Color);
6229 bool Reachable =
true;
6232 B = I->getPossiblyUnreachableBlock();
6238 OS <<
"(Unreachable)";
6254 print(llvm::errs(), LO, ShowColors);
6259 StmtPrinterHelper Helper(
this, LO);
6265 for (
const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
6270 print_block(OS,
this, **I, Helper,
true, ShowColors);
6285 bool ShowColors)
const {
6286 print(llvm::errs(), cfg, LO, ShowColors);
6297 StmtPrinterHelper Helper(cfg, LO);
6298 print_block(OS, cfg, *
this, Helper,
true, ShowColors);
6305 CFGBlockTerminatorPrint TPrinter(OS,
nullptr,
PrintingPolicy(LO));
6311 bool AddQuotes)
const {
6313 llvm::raw_string_ostream TempOut(Buf);
6336 if (llvm::any_of(*Blk, [](
const CFGElement &Elm) {
6337 if (std::optional<CFGStmt> StmtElm = Elm.
getAs<
CFGStmt>())
6357 DFSWorkList.push_back(StartBlk);
6358 while (!DFSWorkList.empty()) {
6359 const CFGBlock *Blk = DFSWorkList.pop_back_val();
6360 Visited.insert(Blk);
6369 for (
const auto &Succ : Blk->
succs()) {
6370 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
6374 DFSWorkList.push_back(SuccBlk);
6403 const Stmt *
Cond = StmtElem->getStmt();
6417 const Expr *E =
nullptr;
6423 case Stmt::CXXForRangeStmtClass:
6427 case Stmt::ForStmtClass:
6431 case Stmt::WhileStmtClass:
6435 case Stmt::DoStmtClass:
6439 case Stmt::IfStmtClass:
6443 case Stmt::ChooseExprClass:
6447 case Stmt::IndirectGotoStmtClass:
6451 case Stmt::SwitchStmtClass:
6455 case Stmt::BinaryConditionalOperatorClass:
6459 case Stmt::ConditionalOperatorClass:
6463 case Stmt::BinaryOperatorClass:
6467 case Stmt::ObjCForCollectionStmtClass:
6484 StmtPrinterHelper H(
this, LO);
6486 llvm::ViewGraph(
this,
"CFG");
6498 llvm::raw_string_ostream Out(OutStr);
6501 if (OutStr[0] ==
'\n') OutStr.erase(OutStr.begin());
6504 for (
unsigned i = 0; i != OutStr.length(); ++i)
6505 if (OutStr[i] ==
'\n') {
6507 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 AddParameterLifetimes
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)