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"
70 if (
VarDecl *VD = dyn_cast<VarDecl>(D))
71 if (
Expr *Ex = VD->getInit())
72 return Ex->getSourceRange().getEnd();
86 if (
const auto *CE = dyn_cast<CastExpr>(E)) {
87 if (CE->getCastKind() != CK_IntegralCast &&
88 CE->getCastKind() != CK_IntegralToFloating)
94 if (
const auto *UO = dyn_cast<UnaryOperator>(E)) {
95 if (UO->getOpcode() != UO_Minus)
119static std::tuple<const Expr *, BinaryOperatorKind, const Expr *>
130 else if (Op == BO_GE)
132 else if (Op == BO_LT)
134 else if (Op == BO_LE)
141 return std::make_tuple(MaybeDecl, Op,
Constant);
192 enum Kind { NotAlwaysAdd = 0, AlwaysAdd = 1 };
194 AddStmtChoice(Kind a_kind = NotAlwaysAdd) : kind(a_kind) {}
196 bool alwaysAdd(CFGBuilder &builder,
197 const Stmt *
stmt)
const;
201 AddStmtChoice withAlwaysAdd(
bool alwaysAdd)
const {
202 return AddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd);
232 using AutomaticVarsTy = BumpVector<VarDecl *>;
236 class const_iterator {
237 const LocalScope* Scope =
nullptr;
241 unsigned VarIter = 0;
247 const_iterator() =
default;
251 const_iterator(
const LocalScope& S,
unsigned I)
252 : Scope(&S), VarIter(I) {
255 if (VarIter == 0 && Scope)
259 VarDecl *
const* operator->()
const {
260 assert(Scope &&
"Dereferencing invalid iterator is not allowed");
261 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
262 return &Scope->Vars[VarIter - 1];
265 const VarDecl *getFirstVarInScope()
const {
266 assert(Scope &&
"Dereferencing invalid iterator is not allowed");
267 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
268 return Scope->Vars[0];
272 return *this->operator->();
275 const_iterator &operator++() {
279 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
285 const_iterator operator++(
int) {
286 const_iterator P = *
this;
291 bool operator==(
const const_iterator &rhs)
const {
292 return Scope == rhs.Scope && VarIter == rhs.VarIter;
294 bool operator!=(
const const_iterator &rhs)
const {
295 return !(*
this == rhs);
298 explicit operator bool()
const {
299 return *
this != const_iterator();
303 const_iterator shared_parent(const_iterator L);
304 bool pointsToFirstDeclaredVar() {
return VarIter == 1; }
305 bool inSameLocalScope(const_iterator rhs) {
return Scope == rhs.Scope; }
309 BumpVectorContext ctx;
312 AutomaticVarsTy Vars;
320 LocalScope(BumpVectorContext ctx, const_iterator P)
321 : ctx(std::move(ctx)), Vars(this->ctx, 4), Prev(P) {}
324 const_iterator begin()
const {
return const_iterator(*
this, Vars.size()); }
326 void addVar(VarDecl *VD) {
327 Vars.push_back(VD, ctx);
336int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
338 const_iterator F = *
this;
339 while (F.Scope != L.Scope) {
340 assert(F != const_iterator() &&
341 "L iterator is not reachable from F iterator.");
345 D += F.VarIter - L.VarIter;
353LocalScope::const_iterator
354LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
357 if ((*
this == const_iterator()) || (L == const_iterator())) {
358 return const_iterator();
361 const_iterator F = *
this;
362 if (F.inSameLocalScope(L)) {
364 F.VarIter = std::min(F.VarIter, L.VarIter);
368 llvm::SmallDenseMap<const LocalScope *, unsigned, 4> ScopesOfL;
370 ScopesOfL.try_emplace(L.Scope, L.VarIter);
371 if (L == const_iterator())
377 if (
auto LIt = ScopesOfL.find(F.Scope); LIt != ScopesOfL.end()) {
379 F.VarIter = std::min(F.VarIter, LIt->getSecond());
382 assert(F != const_iterator() &&
383 "L iterator is not reachable from F iterator.");
393struct BlockScopePosPair {
394 CFGBlock *block =
nullptr;
395 LocalScope::const_iterator scopePosition;
397 BlockScopePosPair() =
default;
398 BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos)
399 : block(b), scopePosition(scopePos) {}
410 TryResult() =
default;
411 TryResult(
bool b) :
X(b ? 1 : 0) {}
413 bool isTrue()
const {
return X == 1; }
414 bool isFalse()
const {
return X == 0; }
415 bool isKnown()
const {
return X >= 0; }
426 if (!R1.isKnown() || !R2.isKnown())
428 return TryResult(R1.isTrue() && R2.isTrue());
433class reverse_children {
434 llvm::SmallVector<Stmt *, 12> childrenBuf;
438 reverse_children(Stmt *S, ASTContext &Ctx);
440 using iterator = ArrayRef<Stmt *>::reverse_iterator;
442 iterator begin()
const {
return children.rbegin(); }
443 iterator end()
const {
return children.rend(); }
448reverse_children::reverse_children(Stmt *S, ASTContext &Ctx) {
449 if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
456 case Stmt::InitListExprClass: {
463 case Stmt::AttributedStmtClass: {
469 for (
const auto *Attr : AS->getAttrs()) {
470 if (
const auto *AssumeAttr = dyn_cast<CXXAssumeAttr>(Attr)) {
471 Expr *AssumeExpr = AssumeAttr->getAssumption();
473 childrenBuf.push_back(AssumeExpr);
480 llvm::append_range(childrenBuf, AS->children());
489 llvm::append_range(childrenBuf, S->
children());
511 using JumpTarget = BlockScopePosPair;
512 using JumpSource = BlockScopePosPair;
515 std::unique_ptr<CFG> cfg;
518 CFGBlock *
Block =
nullptr;
521 CFGBlock *Succ =
nullptr;
523 JumpTarget ContinueJumpTarget;
524 JumpTarget BreakJumpTarget;
525 JumpTarget SEHLeaveJumpTarget;
526 CFGBlock *SwitchTerminatedBlock =
nullptr;
527 CFGBlock *DefaultCaseBlock =
nullptr;
533 CFGBlock *TryTerminatedBlock =
nullptr;
536 LocalScope::const_iterator ScopePos;
539 using LabelMapTy = llvm::DenseMap<LabelDecl *, JumpTarget>;
544 using BackpatchBlocksTy = std::vector<JumpSource>;
545 BackpatchBlocksTy BackpatchBlocks;
548 using LabelSetTy = llvm::SmallSetVector<LabelDecl *, 8>;
549 LabelSetTy AddressTakenLabels;
554 llvm::DenseMap<Expr *, const ConstructionContextLayer *>
555 ConstructionContextMap;
558 const CFG::BuildOptions &BuildOpts;
561 bool switchExclusivelyCovered =
false;
562 Expr::EvalResult *switchCond =
nullptr;
564 CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry =
nullptr;
565 const Stmt *lastLookup =
nullptr;
569 using CachedBoolEvalsTy = llvm::DenseMap<Expr *, TryResult>;
570 CachedBoolEvalsTy CachedBoolEvals;
573 explicit CFGBuilder(ASTContext *astContext,
574 const CFG::BuildOptions &buildOpts)
575 : Context(astContext), cfg(new CFG()), BuildOpts(buildOpts) {}
578 std::unique_ptr<CFG> buildCFG(
const Decl *D, Stmt *Statement);
580 bool alwaysAdd(
const Stmt *
stmt);
584 CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc);
585 CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
586 CFGBlock *VisitAttributedStmt(AttributedStmt *A, AddStmtChoice asc);
587 CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
588 CFGBlock *VisitBreakStmt(BreakStmt *B);
589 CFGBlock *VisitCallExpr(CallExpr *
C, AddStmtChoice asc);
590 CFGBlock *VisitCaseStmt(CaseStmt *
C);
591 CFGBlock *VisitChooseExpr(ChooseExpr *
C, AddStmtChoice asc);
592 CFGBlock *VisitCompoundStmt(
CompoundStmt *
C,
bool ExternallyDestructed);
593 CFGBlock *VisitConditionalOperator(AbstractConditionalOperator *
C,
595 CFGBlock *VisitContinueStmt(ContinueStmt *
C);
596 CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
598 CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
599 CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *
C, AddStmtChoice asc);
600 CFGBlock *VisitCXXNewExpr(CXXNewExpr *DE, AddStmtChoice asc);
601 CFGBlock *VisitCXXDeleteExpr(CXXDeleteExpr *DE, AddStmtChoice asc);
602 CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
603 CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
605 CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *
C,
607 CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *
T);
608 CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
609 CFGBlock *VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc);
610 CFGBlock *VisitDeclStmt(DeclStmt *DS);
611 CFGBlock *VisitDeclSubExpr(DeclStmt *DS);
612 CFGBlock *VisitDefaultStmt(DefaultStmt *D);
613 CFGBlock *VisitDoStmt(DoStmt *D);
614 CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E,
615 AddStmtChoice asc,
bool ExternallyDestructed);
616 CFGBlock *VisitForStmt(ForStmt *F);
617 CFGBlock *VisitGotoStmt(GotoStmt *G);
618 CFGBlock *VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc);
619 CFGBlock *VisitIfStmt(IfStmt *I);
620 CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc);
621 CFGBlock *VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc);
622 CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I);
623 CFGBlock *VisitLabelStmt(LabelStmt *L);
624 CFGBlock *VisitBlockExpr(BlockExpr *E, AddStmtChoice asc);
625 CFGBlock *VisitLambdaExpr(
LambdaExpr *E, AddStmtChoice asc);
626 CFGBlock *VisitLogicalOperator(BinaryOperator *B);
627 std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(BinaryOperator *B,
630 CFGBlock *FalseBlock);
631 CFGBlock *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
633 CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc);
634 CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S);
635 CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S);
636 CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S);
637 CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
638 CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S);
639 CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
640 CFGBlock *VisitObjCMessageExpr(ObjCMessageExpr *E, AddStmtChoice asc);
641 CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);
642 CFGBlock *VisitReturnStmt(Stmt *S);
643 CFGBlock *VisitCoroutineSuspendExpr(CoroutineSuspendExpr *S,
645 CFGBlock *VisitSEHExceptStmt(SEHExceptStmt *S);
646 CFGBlock *VisitSEHFinallyStmt(SEHFinallyStmt *S);
647 CFGBlock *VisitSEHLeaveStmt(SEHLeaveStmt *S);
648 CFGBlock *VisitSEHTryStmt(SEHTryStmt *S);
649 CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
650 CFGBlock *VisitSwitchStmt(SwitchStmt *S);
651 CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
653 CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc);
654 CFGBlock *VisitWhileStmt(WhileStmt *W);
655 CFGBlock *VisitArrayInitLoopExpr(ArrayInitLoopExpr *A, AddStmtChoice asc);
657 CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd,
658 bool ExternallyDestructed =
false);
659 CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc);
660 CFGBlock *VisitChildren(Stmt *S);
661 CFGBlock *VisitCallExprChildren(CallExpr *
C);
662 CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc);
663 CFGBlock *VisitOMPExecutableDirective(OMPExecutableDirective *D,
666 void maybeAddScopeBeginForVarDecl(CFGBlock *B,
const VarDecl *VD,
668 if (ScopePos && (VD == ScopePos.getFirstVarInScope()))
669 appendScopeBegin(B, VD, S);
700 struct TempDtorContext {
701 TempDtorContext() =
default;
702 TempDtorContext(TryResult KnownExecuted)
703 : IsConditional(
true), KnownExecuted(KnownExecuted) {}
710 bool needsTempDtorBranch()
const {
711 return IsConditional && !TerminatorExpr;
716 void setDecisionPoint(CFGBlock *S, CXXBindTemporaryExpr *E) {
721 void track(
const MaterializeTemporaryExpr *MTE) {
722 CollectedMTEs.push_back(MTE);
725 const bool IsConditional =
false;
726 SmallVector<const MaterializeTemporaryExpr *, 5> CollectedMTEs;
727 const TryResult KnownExecuted =
true;
728 CFGBlock *Succ =
nullptr;
729 CXXBindTemporaryExpr *TerminatorExpr =
nullptr;
734 CFGBlock *VisitForTemporaries(Stmt *E,
bool ExternallyDestructed,
735 TempDtorContext &Context);
736 CFGBlock *VisitChildrenForTemporaries(Stmt *E,
bool ExternallyDestructed,
737 TempDtorContext &Context);
738 CFGBlock *VisitBinaryOperatorForTemporaries(BinaryOperator *E,
739 bool ExternallyDestructed,
740 TempDtorContext &Context);
741 CFGBlock *VisitCXXOperatorCallExprForTemporaryDtors(CXXOperatorCallExpr *E,
742 TempDtorContext &Context);
743 CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(
744 CXXBindTemporaryExpr *E,
bool ExternallyDestructed, TempDtorContext &Context);
746 VisitConditionalOperatorForTemporaries(AbstractConditionalOperator *E,
747 bool ExternallyDestructed,
748 TempDtorContext &Context);
749 void InsertTempDecisionBlock(
const TempDtorContext &Context,
750 CFGBlock *FalseSucc =
nullptr);
760 void consumeConstructionContext(
const ConstructionContextLayer *Layer,
768 void findConstructionContexts(
const ConstructionContextLayer *Layer,
774 template <
typename CallLikeExpr,
775 typename = std::enable_if_t<
776 std::is_base_of_v<CallExpr, CallLikeExpr> ||
777 std::is_base_of_v<CXXConstructExpr, CallLikeExpr> ||
778 std::is_base_of_v<ObjCMessageExpr, CallLikeExpr>>>
779 void findConstructionContextsForArguments(CallLikeExpr *E) {
780 for (
unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
781 Expr *Arg = E->getArg(i);
783 findConstructionContexts(
785 ConstructionContextItem(E, i)),
793 void cleanupConstructionContext(Expr *E);
795 void autoCreateBlock() {
if (!
Block)
Block = createBlock(); }
797 CFGBlock *createBlock(
bool add_successor =
true);
798 CFGBlock *createNoReturnBlock();
800 CFGBlock *addStmt(Stmt *S) {
801 return Visit(S, AddStmtChoice::AlwaysAdd);
804 CFGBlock *addInitializer(CXXCtorInitializer *I);
805 void addLoopExit(
const Stmt *LoopStmt);
806 void addAutomaticObjHandling(LocalScope::const_iterator B,
807 LocalScope::const_iterator E, Stmt *S);
808 void addAutomaticObjDestruction(LocalScope::const_iterator B,
809 LocalScope::const_iterator E, Stmt *S);
810 void addScopeExitHandling(LocalScope::const_iterator B,
811 LocalScope::const_iterator E, Stmt *S);
812 void addImplicitDtorsForDestructor(
const CXXDestructorDecl *DD);
813 void addScopeChangesHandling(LocalScope::const_iterator SrcPos,
814 LocalScope::const_iterator DstPos,
816 void addFullExprCleanupMarker(TempDtorContext &Context,
817 const ExprWithCleanups *CleanupExpr);
818 CFGBlock *createScopeChangesHandlingBlock(LocalScope::const_iterator SrcPos,
820 LocalScope::const_iterator DstPost,
824 LocalScope* createOrReuseLocalScope(LocalScope* Scope);
826 void addLocalScopeForStmt(Stmt *S);
827 LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS,
828 LocalScope* Scope =
nullptr);
829 LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope =
nullptr);
831 void addLocalScopeAndDtors(Stmt *S);
833 const ConstructionContext *retrieveAndCleanupConstructionContext(Expr *E) {
837 const ConstructionContextLayer *Layer = ConstructionContextMap.lookup(E);
841 cleanupConstructionContext(E);
848 void appendStmt(CFGBlock *B,
const Stmt *S) {
849 if (alwaysAdd(S) && cachedEntry)
850 cachedEntry->second = B;
854 B->
appendStmt(
const_cast<Stmt*
>(S), cfg->getBumpVectorContext());
857 void appendConstructor(CXXConstructExpr *CE) {
859 if (
C &&
C->isNoReturn())
860 Block = createNoReturnBlock();
864 if (
const ConstructionContext *CC =
865 retrieveAndCleanupConstructionContext(CE)) {
866 Block->appendConstructor(CE, CC, cfg->getBumpVectorContext());
871 Block->appendStmt(CE, cfg->getBumpVectorContext());
874 void appendCall(CFGBlock *B, CallExpr *CE) {
875 if (alwaysAdd(CE) && cachedEntry)
876 cachedEntry->second = B;
878 if (
const ConstructionContext *CC =
879 retrieveAndCleanupConstructionContext(CE)) {
885 B->
appendStmt(CE, cfg->getBumpVectorContext());
888 void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
892 void appendNewAllocator(CFGBlock *B, CXXNewExpr *NE) {
896 void appendBaseDtor(CFGBlock *B,
const CXXBaseSpecifier *BS) {
900 void appendMemberDtor(CFGBlock *B, FieldDecl *FD) {
904 void appendObjCMessage(CFGBlock *B, ObjCMessageExpr *ME) {
905 if (alwaysAdd(ME) && cachedEntry)
906 cachedEntry->second = B;
908 if (
const ConstructionContext *CC =
909 retrieveAndCleanupConstructionContext(ME)) {
914 B->
appendStmt(ME, cfg->getBumpVectorContext());
917 void appendTemporaryDtor(CFGBlock *B, CXXBindTemporaryExpr *E) {
921 void appendAutomaticObjDtor(CFGBlock *B, VarDecl *VD, Stmt *S) {
925 void appendCleanupFunction(CFGBlock *B, VarDecl *VD) {
929 void appendLifetimeEnds(CFGBlock *B, VarDecl *VD, Stmt *S) {
933 void appendLoopExit(CFGBlock *B,
const Stmt *LoopStmt) {
937 void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) {
941 void addSuccessor(CFGBlock *B, CFGBlock *S,
bool IsReachable =
true) {
942 B->
addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable),
943 cfg->getBumpVectorContext());
948 void addSuccessor(CFGBlock *B, CFGBlock *ReachableBlock, CFGBlock *AltBlock) {
949 B->
addSuccessor(CFGBlock::AdjacentBlock(ReachableBlock, AltBlock),
950 cfg->getBumpVectorContext());
953 void appendScopeBegin(CFGBlock *B,
const VarDecl *VD,
const Stmt *S) {
958 void appendScopeEnd(CFGBlock *B,
const VarDecl *VD,
const Stmt *S) {
966 TryResult checkIncorrectRelationalOperator(
const BinaryOperator *B) {
970 const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
971 const Expr *BoolExpr = RHSExpr;
972 bool IntFirst =
true;
974 IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
982 llvm::APInt IntValue = IntLiteral->
getValue();
983 if ((IntValue == 1) || (IntValue == 0))
987 !IntValue.isNegative();
990 if (Bok == BO_GT || Bok == BO_GE) {
993 return TryResult(IntFirst == IntLarger);
997 return TryResult(IntFirst != IntLarger);
1005 TryResult checkIncorrectEqualityOperator(
const BinaryOperator *B) {
1009 std::optional<llvm::APInt> IntLiteral1 =
1010 getIntegerLiteralSubexpressionValue(LHSExpr);
1011 const Expr *BoolExpr = RHSExpr;
1014 IntLiteral1 = getIntegerLiteralSubexpressionValue(RHSExpr);
1021 const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
1022 if (BitOp && (BitOp->
getOpcode() == BO_And ||
1027 std::optional<llvm::APInt> IntLiteral2 =
1028 getIntegerLiteralSubexpressionValue(LHSExpr2);
1031 IntLiteral2 = getIntegerLiteralSubexpressionValue(RHSExpr2);
1037 (*IntLiteral2 & *IntLiteral1) != *IntLiteral1) ||
1039 (*IntLiteral2 | *IntLiteral1) != *IntLiteral1)) {
1043 return TryResult(B->
getOpcode() != BO_EQ);
1046 if ((*IntLiteral1 == 1) || (*IntLiteral1 == 0)) {
1049 return TryResult(B->
getOpcode() != BO_EQ);
1061 std::optional<llvm::APInt>
1062 getIntegerLiteralSubexpressionValue(
const Expr *E) {
1065 if (
const auto *UnOp = dyn_cast<UnaryOperator>(E->
IgnoreParens())) {
1068 const Expr *SubExpr = UnOp->getSubExpr()->IgnoreParens();
1070 if (
const auto *IntLiteral = dyn_cast<IntegerLiteral>(SubExpr)) {
1075 switch (UnOp->getOpcode()) {
1085 assert(
false &&
"Unexpected unary operator!");
1086 return std::nullopt;
1089 }
else if (
const auto *IntLiteral =
1093 return std::nullopt;
1096 template <
typename APFloatOrInt>
1098 const APFloatOrInt &Value1,
1099 const APFloatOrInt &Value2) {
1104 return TryResult(Value1 == Value2);
1106 return TryResult(Value1 != Value2);
1108 return TryResult(Value1 < Value2);
1110 return TryResult(Value1 <= Value2);
1112 return TryResult(Value1 > Value2);
1114 return TryResult(Value1 >= Value2);
1125 TryResult checkIncorrectLogicOperator(
const BinaryOperator *B) {
1130 auto CheckLogicalOpWithNegatedVariable = [
this, B](
const Expr *E1,
1132 if (
const auto *Negate = dyn_cast<UnaryOperator>(E1)) {
1133 if (Negate->getOpcode() == UO_LNot &&
1135 bool AlwaysTrue = B->
getOpcode() == BO_LOr;
1138 return TryResult(AlwaysTrue);
1144 TryResult
Result = CheckLogicalOpWithNegatedVariable(LHSExpr, RHSExpr);
1147 Result = CheckLogicalOpWithNegatedVariable(RHSExpr, LHSExpr);
1151 const auto *LHS = dyn_cast<BinaryOperator>(LHSExpr);
1152 const auto *RHS = dyn_cast<BinaryOperator>(RHSExpr);
1156 if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
1159 const Expr *DeclExpr1;
1160 const Expr *NumExpr1;
1164 if (!DeclExpr1 || !NumExpr1)
1167 const Expr *DeclExpr2;
1168 const Expr *NumExpr2;
1172 if (!DeclExpr2 || !NumExpr2)
1185 Expr::EvalResult L1Result, L2Result;
1200 auto AnalyzeConditions = [&](
const auto &Values,
1203 bool AlwaysTrue =
true, AlwaysFalse =
true;
1206 bool LHSAlwaysTrue =
true, LHSAlwaysFalse =
true;
1207 bool RHSAlwaysTrue =
true, RHSAlwaysFalse =
true;
1209 for (
const auto &
Value : Values) {
1211 analyzeLogicOperatorCondition(*BO1,
Value, Values[1] );
1213 analyzeLogicOperatorCondition(*BO2,
Value, Values[3] );
1215 if (!Res1.isKnown() || !Res2.isKnown())
1218 const bool IsAnd = B->
getOpcode() == BO_LAnd;
1219 const bool Combine = IsAnd ? (Res1.isTrue() && Res2.isTrue())
1220 : (Res1.isTrue() || Res2.isTrue());
1222 AlwaysTrue &= Combine;
1223 AlwaysFalse &= !Combine;
1225 LHSAlwaysTrue &= Res1.isTrue();
1226 LHSAlwaysFalse &= Res1.isFalse();
1227 RHSAlwaysTrue &= Res2.isTrue();
1228 RHSAlwaysFalse &= Res2.isFalse();
1231 if (AlwaysTrue || AlwaysFalse) {
1232 if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
1233 !RHSAlwaysFalse && BuildOpts.
Observer) {
1236 return TryResult(AlwaysTrue);
1244 llvm::APSInt L1 = L1Result.
Val.
getInt();
1245 llvm::APSInt L2 = L2Result.
Val.
getInt();
1248 if (L1.isSigned() != L2.isSigned() ||
1249 L1.getBitWidth() != L2.getBitWidth())
1254 const llvm::APSInt Values[] = {
1256 llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
1260 ((L1 < L2) ? L1 : L2) +
1261 llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1), L1.isUnsigned()),
1265 llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
1268 return AnalyzeConditions(Values, &BO1, &BO2);
1287 if (llvm::APFloat::opOK !=
1288 L2.convert(L1.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
1291 }
else if (Order < 0)
1293 if (llvm::APFloat::opOK !=
1294 L1.convert(L2.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
1298 llvm::APFloat MidValue = L1;
1299 MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven);
1300 MidValue.divide(llvm::APFloat(MidValue.getSemantics(),
"2.0"),
1301 llvm::APFloat::rmNearestTiesToEven);
1303 const llvm::APFloat Values[] = {
1304 llvm::APFloat::getSmallest(L1.getSemantics(),
true), L1, MidValue, L2,
1305 llvm::APFloat::getLargest(L2.getSemantics(),
false),
1308 return AnalyzeConditions(Values, &BO1, &BO2);
1315 TryResult checkIncorrectBitwiseOrOperator(
const BinaryOperator *B) {
1316 const Expr *LHSConstant =
1318 const Expr *RHSConstant =
1321 if ((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant))
1324 const Expr *
Constant = LHSConstant ? LHSConstant : RHSConstant;
1330 if (
Result.Val.getInt() == 0)
1336 return TryResult(
true);
1340 bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) {
1350 TryResult tryEvaluateBool(Expr *S) {
1355 if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
1356 if (Bop->isLogicalOp() || Bop->isEqualityOp()) {
1358 CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S);
1359 if (I != CachedBoolEvals.end())
1363 TryResult
Result = evaluateAsBooleanConditionNoCache(S);
1364 CachedBoolEvals[S] =
Result;
1368 switch (Bop->getOpcode()) {
1376 Expr::EvalResult LHSResult;
1377 if (Bop->getLHS()->EvaluateAsInt(LHSResult, *Context)) {
1378 llvm::APSInt IntVal = LHSResult.
Val.
getInt();
1379 if (!IntVal.getBoolValue()) {
1380 return TryResult(
false);
1383 Expr::EvalResult RHSResult;
1384 if (Bop->getRHS()->EvaluateAsInt(RHSResult, *Context)) {
1385 llvm::APSInt IntVal = RHSResult.
Val.
getInt();
1386 if (!IntVal.getBoolValue()) {
1387 return TryResult(
false);
1396 return evaluateAsBooleanConditionNoCache(S);
1400 TryResult evaluateAsBooleanConditionNoCache(Expr *E) {
1401 if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(E)) {
1402 if (Bop->isLogicalOp()) {
1403 TryResult LHS = tryEvaluateBool(Bop->getLHS());
1404 if (LHS.isKnown()) {
1407 if (LHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1408 return LHS.isTrue();
1410 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1411 if (RHS.isKnown()) {
1412 if (Bop->getOpcode() == BO_LOr)
1413 return LHS.isTrue() || RHS.isTrue();
1415 return LHS.isTrue() && RHS.isTrue();
1418 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1419 if (RHS.isKnown()) {
1422 if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1423 return RHS.isTrue();
1425 TryResult BopRes = checkIncorrectLogicOperator(Bop);
1426 if (BopRes.isKnown())
1427 return BopRes.isTrue();
1432 }
else if (Bop->isEqualityOp()) {
1433 TryResult BopRes = checkIncorrectEqualityOperator(Bop);
1434 if (BopRes.isKnown())
1435 return BopRes.isTrue();
1436 }
else if (Bop->isRelationalOp()) {
1437 TryResult BopRes = checkIncorrectRelationalOperator(Bop);
1438 if (BopRes.isKnown())
1439 return BopRes.isTrue();
1440 }
else if (Bop->getOpcode() == BO_Or) {
1441 TryResult BopRes = checkIncorrectBitwiseOrOperator(Bop);
1442 if (BopRes.isKnown())
1443 return BopRes.isTrue();
1454 bool hasTrivialDestructor(
const VarDecl *VD)
const;
1455 bool needsAutomaticDestruction(
const VarDecl *VD)
const;
1466 while (
const auto *E = dyn_cast<ArrayInitLoopExpr>(AILEInit))
1467 AILEInit = E->getSubExpr();
1472inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
1474 return builder.alwaysAdd(
stmt) ||
kind == AlwaysAdd;
1477bool CFGBuilder::alwaysAdd(
const Stmt *
stmt) {
1483 if (lastLookup ==
stmt) {
1485 assert(cachedEntry->first ==
stmt);
1498 assert(!cachedEntry);
1502 CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(
stmt);
1503 if (itr == fb->end()) {
1504 cachedEntry =
nullptr;
1508 cachedEntry = &*itr;
1515 while (
const ArrayType *vt = dyn_cast<ArrayType>(t)) {
1517 if (vat->getSizeExpr())
1520 t = vt->getElementType().getTypePtr();
1526void CFGBuilder::consumeConstructionContext(
1527 const ConstructionContextLayer *Layer, Expr *E) {
1530 if (
const ConstructionContextLayer *PreviouslyStoredLayer =
1531 ConstructionContextMap.lookup(E)) {
1532 (void)PreviouslyStoredLayer;
1535 assert(PreviouslyStoredLayer->isStrictlyMoreSpecificThan(Layer) &&
1536 "Already within a different construction context!");
1538 ConstructionContextMap[E] = Layer;
1542void CFGBuilder::findConstructionContexts(
1543 const ConstructionContextLayer *Layer, Stmt *Child) {
1550 auto withExtraLayer = [
this, Layer](
const ConstructionContextItem &Item) {
1555 switch(Child->getStmtClass()) {
1556 case Stmt::CXXConstructExprClass:
1557 case Stmt::CXXTemporaryObjectExprClass: {
1561 findConstructionContexts(withExtraLayer(CE), CE->
getArg(0));
1564 consumeConstructionContext(Layer, CE);
1570 case Stmt::CallExprClass:
1571 case Stmt::CXXMemberCallExprClass:
1572 case Stmt::CXXOperatorCallExprClass:
1573 case Stmt::UserDefinedLiteralClass:
1574 case Stmt::ObjCMessageExprClass: {
1577 consumeConstructionContext(Layer, E);
1580 case Stmt::ExprWithCleanupsClass: {
1582 findConstructionContexts(Layer, Cleanups->getSubExpr());
1585 case Stmt::CXXFunctionalCastExprClass: {
1587 findConstructionContexts(Layer,
Cast->getSubExpr());
1590 case Stmt::ImplicitCastExprClass: {
1593 switch (
Cast->getCastKind()) {
1595 case CK_ConstructorConversion:
1596 findConstructionContexts(Layer,
Cast->getSubExpr());
1603 case Stmt::CXXBindTemporaryExprClass: {
1605 findConstructionContexts(withExtraLayer(BTE), BTE->getSubExpr());
1608 case Stmt::MaterializeTemporaryExprClass: {
1616 findConstructionContexts(withExtraLayer(MTE), MTE->getSubExpr());
1620 case Stmt::ConditionalOperatorClass: {
1628 assert(!CO->getType()->getAsCXXRecordDecl() || CO->isGLValue() ||
1632 findConstructionContexts(Layer, CO->getLHS());
1633 findConstructionContexts(Layer, CO->getRHS());
1636 case Stmt::InitListExprClass: {
1638 if (ILE->isTransparent()) {
1639 findConstructionContexts(Layer, ILE->getInit(0));
1645 case Stmt::ParenExprClass: {
1649 findConstructionContexts(Layer, PE->getSubExpr());
1657void CFGBuilder::cleanupConstructionContext(Expr *E) {
1659 "We should not be managing construction contexts!");
1660 assert(ConstructionContextMap.count(E) &&
1661 "Cannot exit construction context without the context!");
1662 ConstructionContextMap.erase(E);
1670std::unique_ptr<CFG> CFGBuilder::buildCFG(
const Decl *D, Stmt *Statement) {
1678 Succ = createBlock();
1679 assert(Succ == &cfg->getExit());
1684 LocalScope *paramScope =
nullptr;
1685 if (
const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
1686 for (ParmVarDecl *PD : FD->parameters()) {
1687 paramScope = addLocalScopeForVarDecl(PD, paramScope);
1689 if (
auto *
C = dyn_cast<CompoundStmt>(Statement))
1693 addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(),
1697 if (
const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
1698 addImplicitDtorsForDestructor(DD);
1701 CFGBlock *B = addStmt(Statement);
1718 if (
const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) {
1719 CFGBlock *VBaseSucc =
nullptr;
1720 for (
auto *I : llvm::reverse(CD->inits())) {
1722 I->isBaseInitializer() && I->isBaseVirtual()) {
1726 VBaseSucc = Succ = B ? B : &cfg->getExit();
1727 Block = createBlock();
1729 B = addInitializer(I);
1739 addSuccessor(B,
Block,
true);
1748 for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
1749 E = BackpatchBlocks.end(); I != E; ++I ) {
1751 CFGBlock *B = I->block;
1753 LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
1756 if (LI == LabelMap.end())
1758 JumpTarget JT = LI->second;
1760 CFGBlock *SuccBlk = createScopeChangesHandlingBlock(
1761 I->scopePosition, B, JT.scopePosition, JT.block);
1762 addSuccessor(B, SuccBlk);
1763 }
else if (
auto *G = dyn_cast<GCCAsmStmt>(B->
getTerminator())) {
1764 CFGBlock *Successor = (I+1)->block;
1765 for (
auto *L : G->labels()) {
1766 LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
1769 if (LI == LabelMap.end())
1771 JumpTarget JT = LI->second;
1773 if (JT.block == Successor)
1775 addSuccessor(B, JT.block);
1782 if (CFGBlock *B = cfg->getIndirectGotoBlock())
1783 for (LabelDecl *LD : AddressTakenLabels) {
1785 LabelMapTy::iterator LI = LabelMap.find(LD);
1789 if (LI == LabelMap.end())
continue;
1791 addSuccessor(B, LI->second.block);
1795 cfg->setEntry(createBlock());
1798 assert(ConstructionContextMap.empty() &&
1799 "Not all construction contexts were cleaned up!");
1801 return std::move(cfg);
1806CFGBlock *CFGBuilder::createBlock(
bool add_successor) {
1807 CFGBlock *B = cfg->createBlock();
1808 if (add_successor && Succ)
1809 addSuccessor(B, Succ);
1816CFGBlock *CFGBuilder::createNoReturnBlock() {
1817 CFGBlock *B = createBlock(
false);
1819 addSuccessor(B, &cfg->getExit(), Succ);
1824CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
1828 bool HasTemporaries =
false;
1834 Expr *ActualInit =
Init;
1836 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(
Init))
1837 ActualInit = DIE->getExpr();
1841 if (HasTemporaries &&
1844 TempDtorContext Context;
1846 VisitForTemporaries(FullExprWithCleanups->getSubExpr(),
1849 addFullExprCleanupMarker(Context, FullExprWithCleanups);
1854 appendInitializer(
Block, I);
1860 dyn_cast<ArrayInitLoopExpr>(
Init));
1862 findConstructionContexts(
1864 AILEInit ? AILEInit :
Init);
1867 if (CXXDefaultInitExpr *
Default = dyn_cast<CXXDefaultInitExpr>(
Init)) {
1873 if (Stmt *Child =
Default->getExpr()) {
1876 if (CFGBlock *R = Visit(Child))
1883 if (HasTemporaries) {
1897 bool *FoundMTE =
nullptr) {
1904 Init = EWC->getSubExpr();
1910 = dyn_cast<MaterializeTemporaryExpr>(
Init)) {
1911 Init = MTE->getSubExpr();
1918 const Expr *SkippedInit =
Init->skipRValueSubobjectAdjustments();
1919 if (SkippedInit !=
Init) {
1927 return Init->getType();
1932void CFGBuilder::addLoopExit(
const Stmt *LoopStmt){
1936 appendLoopExit(
Block, LoopStmt);
1944void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
1945 LocalScope::const_iterator E,
1955 if (B.inSameLocalScope(E)) {
1956 addAutomaticObjDestruction(B, E, S);
1961 SmallVector<LocalScope::const_iterator, 10> LocalScopeEndMarkers;
1962 LocalScopeEndMarkers.push_back(B);
1963 for (LocalScope::const_iterator I = B; I != E; ++I) {
1964 if (!I.inSameLocalScope(LocalScopeEndMarkers.back()))
1965 LocalScopeEndMarkers.push_back(I);
1967 LocalScopeEndMarkers.push_back(E);
1971 std::reverse(LocalScopeEndMarkers.begin(), LocalScopeEndMarkers.end());
1973 llvm::zip(LocalScopeEndMarkers, llvm::drop_begin(LocalScopeEndMarkers));
1974 for (
auto [E, B] : Pairwise) {
1975 if (!B.inSameLocalScope(E))
1976 addScopeExitHandling(B, E, S);
1977 addAutomaticObjDestruction(B, E, S);
1984void CFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
1985 LocalScope::const_iterator E,
1993 SmallVector<VarDecl *, 10> DeclsNeedDestruction;
1994 DeclsNeedDestruction.reserve(B.distance(E));
1996 for (VarDecl* D : llvm::make_range(B, E))
1997 if (needsAutomaticDestruction(D))
1998 DeclsNeedDestruction.push_back(D);
2000 for (VarDecl *VD : llvm::reverse(DeclsNeedDestruction)) {
2013 Block = createNoReturnBlock();
2022 appendLifetimeEnds(
Block, VD, S);
2024 appendAutomaticObjDtor(
Block, VD, S);
2025 if (VD->
hasAttr<CleanupAttr>())
2026 appendCleanupFunction(
Block, VD);
2035void CFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
2036 LocalScope::const_iterator E, Stmt *S) {
2037 assert(!B.inSameLocalScope(E));
2043 appendScopeEnd(
Block, B.getFirstVarInScope(), S);
2050 SmallVector<VarDecl *, 10> DeclsTrivial;
2051 DeclsTrivial.reserve(B.distance(E));
2056 for (VarDecl* D : llvm::make_range(B, E))
2057 if (!needsAutomaticDestruction(D))
2058 DeclsTrivial.push_back(D);
2060 if (DeclsTrivial.empty())
2064 for (VarDecl *VD : llvm::reverse(DeclsTrivial))
2065 appendLifetimeEnds(
Block, VD, S);
2073void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
2074 LocalScope::const_iterator DstPos,
2076 assert(
Block &&
"Source block should be always crated");
2082 if (SrcPos == DstPos)
2087 LocalScope::const_iterator BasePos = SrcPos.shared_parent(DstPos);
2090 if (BuildOpts.
AddScopes && !DstPos.inSameLocalScope(BasePos)) {
2091 for (LocalScope::const_iterator I = DstPos; I != BasePos; ++I)
2092 if (I.pointsToFirstDeclaredVar())
2093 appendScopeBegin(
Block, *I, S);
2098 addAutomaticObjHandling(SrcPos, BasePos, S);
2101void CFGBuilder::addFullExprCleanupMarker(TempDtorContext &Context,
2102 const ExprWithCleanups *CleanupExpr) {
2104 BumpVectorContext &BVC = cfg->getBumpVectorContext();
2106 size_t NumCollected = Context.CollectedMTEs.size();
2107 if (NumCollected > 0) {
2109 ExpiringMTEs =
new (cfg->getAllocator())
2111 for (
const MaterializeTemporaryExpr *MTE : Context.CollectedMTEs)
2113 Block->appendFullExprCleanup(ExpiringMTEs, CleanupExpr, BVC);
2122CFGBlock *CFGBuilder::createScopeChangesHandlingBlock(
2123 LocalScope::const_iterator SrcPos, CFGBlock *SrcBlk,
2124 LocalScope::const_iterator DstPos, CFGBlock *DstBlk) {
2125 if (SrcPos == DstPos)
2129 (!BuildOpts.
AddScopes || SrcPos.inSameLocalScope(DstPos)))
2134 SaveAndRestore save_Block(
Block), save_Succ(Succ);
2137 Block = createBlock(
false);
2140 addSuccessor(
Block, DstBlk);
2143 addScopeChangesHandling(SrcPos, DstPos,
Block->getTerminatorStmt());
2145 assert(
Block &&
"There should be at least one scope changing Block");
2151void CFGBuilder::addImplicitDtorsForDestructor(
const CXXDestructorDecl *DD) {
2153 "Can be called only when dtors should be added");
2154 const CXXRecordDecl *RD = DD->
getParent();
2157 for (
const auto &VI : RD->
vbases()) {
2161 const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
2164 appendBaseDtor(
Block, &VI);
2169 for (
const auto &BI : RD->
bases()) {
2170 if (!BI.isVirtual()) {
2171 const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
2174 appendBaseDtor(
Block, &BI);
2182 for (
auto *FI : RD->
fields()) {
2184 QualType QT = FI->getType();
2187 if (AT->isZeroSize())
2189 QT = AT->getElementType();
2195 appendMemberDtor(
Block, FI);
2202LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) {
2205 llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
2206 return new (alloc) LocalScope(BumpVectorContext(alloc), ScopePos);
2211void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
2216 LocalScope *Scope =
nullptr;
2220 for (
auto *BI : CS->body()) {
2221 Stmt *SI = BI->stripLabelLikeStatements();
2222 if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
2223 Scope = addLocalScopeForDeclStmt(DS, Scope);
2231 addLocalScopeForDeclStmt(DS);
2236LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
2237 LocalScope* Scope) {
2242 for (
auto *DI : DS->
decls())
2243 if (VarDecl *VD = dyn_cast<VarDecl>(DI))
2244 Scope = addLocalScopeForVarDecl(VD, Scope);
2248bool CFGBuilder::needsAutomaticDestruction(
const VarDecl *VD)
const {
2249 return !hasTrivialDestructor(VD) || VD->
hasAttr<CleanupAttr>();
2252bool CFGBuilder::hasTrivialDestructor(
const VarDecl *VD)
const {
2273 bool FoundMTE =
false;
2281 if (AT->isZeroSize())
2283 QT = AT->getElementType();
2295LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
2296 LocalScope* Scope) {
2311 !needsAutomaticDestruction(VD)) {
2317 Scope = createOrReuseLocalScope(Scope);
2319 ScopePos = Scope->begin();
2325void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
2326 LocalScope::const_iterator scopeBeginPos = ScopePos;
2327 addLocalScopeForStmt(S);
2328 addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
2334CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
2335 bool ExternallyDestructed) {
2341 if (Expr *E = dyn_cast<Expr>(S))
2342 S = E->IgnoreParens();
2345 if (
auto *D = dyn_cast<OMPExecutableDirective>(S))
2346 return VisitOMPExecutableDirective(D, asc);
2350 return VisitStmt(S, asc);
2352 case Stmt::ImplicitValueInitExprClass:
2355 return VisitStmt(S, asc);
2357 case Stmt::InitListExprClass:
2360 case Stmt::AttributedStmtClass:
2363 case Stmt::AddrLabelExprClass:
2366 case Stmt::BinaryConditionalOperatorClass:
2369 case Stmt::BinaryOperatorClass:
2370 case Stmt::CompoundAssignOperatorClass:
2373 case Stmt::BlockExprClass:
2376 case Stmt::BreakStmtClass:
2379 case Stmt::CallExprClass:
2380 case Stmt::CXXOperatorCallExprClass:
2381 case Stmt::CXXMemberCallExprClass:
2382 case Stmt::UserDefinedLiteralClass:
2385 case Stmt::CaseStmtClass:
2388 case Stmt::ChooseExprClass:
2391 case Stmt::CompoundStmtClass:
2394 case Stmt::ConditionalOperatorClass:
2397 case Stmt::ContinueStmtClass:
2400 case Stmt::CXXCatchStmtClass:
2403 case Stmt::ExprWithCleanupsClass:
2405 asc, ExternallyDestructed);
2407 case Stmt::CXXDefaultArgExprClass:
2408 case Stmt::CXXDefaultInitExprClass:
2417 return VisitStmt(S, asc);
2419 case Stmt::CXXBindTemporaryExprClass:
2422 case Stmt::CXXConstructExprClass:
2425 case Stmt::CXXNewExprClass:
2428 case Stmt::CXXDeleteExprClass:
2431 case Stmt::CXXFunctionalCastExprClass:
2434 case Stmt::CXXTemporaryObjectExprClass:
2437 case Stmt::CXXThrowExprClass:
2440 case Stmt::CXXTryStmtClass:
2443 case Stmt::CXXTypeidExprClass:
2446 case Stmt::CXXForRangeStmtClass:
2449 case Stmt::DeclStmtClass:
2452 case Stmt::DefaultStmtClass:
2455 case Stmt::DoStmtClass:
2458 case Stmt::ForStmtClass:
2461 case Stmt::GotoStmtClass:
2464 case Stmt::GCCAsmStmtClass:
2467 case Stmt::IfStmtClass:
2470 case Stmt::ImplicitCastExprClass:
2473 case Stmt::ConstantExprClass:
2476 case Stmt::IndirectGotoStmtClass:
2479 case Stmt::LabelStmtClass:
2482 case Stmt::LambdaExprClass:
2485 case Stmt::MaterializeTemporaryExprClass:
2489 case Stmt::MemberExprClass:
2492 case Stmt::NullStmtClass:
2495 case Stmt::ObjCAtCatchStmtClass:
2498 case Stmt::ObjCAutoreleasePoolStmtClass:
2501 case Stmt::ObjCAtSynchronizedStmtClass:
2504 case Stmt::ObjCAtThrowStmtClass:
2507 case Stmt::ObjCAtTryStmtClass:
2510 case Stmt::ObjCForCollectionStmtClass:
2513 case Stmt::ObjCMessageExprClass:
2516 case Stmt::OpaqueValueExprClass:
2519 case Stmt::PseudoObjectExprClass:
2522 case Stmt::ReturnStmtClass:
2523 case Stmt::CoreturnStmtClass:
2524 return VisitReturnStmt(S);
2526 case Stmt::CoyieldExprClass:
2527 case Stmt::CoawaitExprClass:
2530 case Stmt::SEHExceptStmtClass:
2533 case Stmt::SEHFinallyStmtClass:
2536 case Stmt::SEHLeaveStmtClass:
2539 case Stmt::SEHTryStmtClass:
2542 case Stmt::UnaryExprOrTypeTraitExprClass:
2546 case Stmt::StmtExprClass:
2549 case Stmt::SwitchStmtClass:
2552 case Stmt::UnaryOperatorClass:
2555 case Stmt::WhileStmtClass:
2558 case Stmt::ArrayInitLoopExprClass:
2563CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
2564 if (asc.alwaysAdd(*
this, S)) {
2566 appendStmt(
Block, S);
2569 return VisitChildren(S);
2573CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
2574 CFGBlock *B =
Block;
2578 reverse_children RChildren(S, *Context);
2579 for (Stmt *Child : RChildren) {
2581 if (CFGBlock *R = Visit(Child))
2587CFGBlock *CFGBuilder::VisitCallExprChildren(CallExpr *
C) {
2591 if (
auto *OCE = dyn_cast<CXXOperatorCallExpr>(
C);
2592 OCE && OCE->isAssignmentOp()) {
2593 Visit(OCE->getArg(0));
2594 Visit(OCE->getArg(1));
2595 return Visit(OCE->getCallee());
2597 return VisitChildren(
C);
2600CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) {
2601 if (asc.alwaysAdd(*
this, ILE)) {
2603 appendStmt(
Block, ILE);
2605 CFGBlock *B =
Block;
2607 reverse_children RChildren(ILE, *Context);
2608 for (Stmt *Child : RChildren) {
2611 if (CFGBlock *R = Visit(Child))
2614 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(Child))
2615 if (Stmt *Child = DIE->getExpr())
2616 if (CFGBlock *R = Visit(Child))
2623CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
2624 AddStmtChoice asc) {
2625 AddressTakenLabels.insert(A->
getLabel());
2627 if (asc.alwaysAdd(*
this, A)) {
2629 appendStmt(
Block, A);
2638 "expected fallthrough not to have children");
2639 return isFallthrough;
2646 "expected [[assume]] not to have children");
2647 return hasAssumeAttr;
2650CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
2651 AddStmtChoice asc) {
2661 if (isInterestingAttribute && asc.alwaysAdd(*
this, A)) {
2663 appendStmt(
Block, A);
2666 return VisitChildren(A);
2669CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc) {
2670 if (asc.alwaysAdd(*
this, U)) {
2672 appendStmt(
Block, U);
2678 return Visit(U->
getSubExpr(), AddStmtChoice());
2681CFGBlock *CFGBuilder::VisitLogicalOperator(BinaryOperator *B) {
2682 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2683 appendStmt(ConfluenceBlock, B);
2688 return VisitLogicalOperator(B,
nullptr, ConfluenceBlock,
2689 ConfluenceBlock).first;
2692std::pair<CFGBlock*, CFGBlock*>
2693CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
2695 CFGBlock *TrueBlock,
2696 CFGBlock *FalseBlock) {
2701 CFGBlock *RHSBlock, *ExitBlock;
2704 if (BinaryOperator *B_RHS = dyn_cast<BinaryOperator>(RHS))
2705 if (B_RHS->isLogicalOp()) {
2706 std::tie(RHSBlock, ExitBlock) =
2707 VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
2715 ExitBlock = RHSBlock = createBlock(
false);
2720 TryResult KnownVal = tryEvaluateBool(RHS);
2721 if (!KnownVal.isKnown())
2722 KnownVal = tryEvaluateBool(B);
2725 assert(TrueBlock == FalseBlock);
2726 addSuccessor(RHSBlock, TrueBlock);
2730 addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
2731 addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
2735 RHSBlock = addStmt(RHS);
2740 return std::make_pair(
nullptr,
nullptr);
2745 if (BinaryOperator *B_LHS = dyn_cast<BinaryOperator>(LHS))
2746 if (B_LHS->isLogicalOp()) {
2748 FalseBlock = RHSBlock;
2750 TrueBlock = RHSBlock;
2755 return VisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock);
2760 CFGBlock *LHSBlock = createBlock(
false);
2764 CFGBlock *EntryLHSBlock = addStmt(LHS);
2767 return std::make_pair(
nullptr,
nullptr);
2770 TryResult KnownVal = tryEvaluateBool(LHS);
2774 addSuccessor(LHSBlock, TrueBlock, !KnownVal.isFalse());
2775 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isTrue());
2778 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isFalse());
2779 addSuccessor(LHSBlock, FalseBlock, !KnownVal.isTrue());
2782 return std::make_pair(EntryLHSBlock, ExitBlock);
2785CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
2786 AddStmtChoice asc) {
2789 return VisitLogicalOperator(B);
2793 appendStmt(
Block, B);
2795 return addStmt(B->
getLHS());
2799 if (asc.alwaysAdd(*
this, B)) {
2801 appendStmt(
Block, B);
2804 return Visit(B->
getRHS());
2807 if (asc.alwaysAdd(*
this, B)) {
2809 appendStmt(
Block, B);
2815 CFGBlock *RBlock = Visit(B->
getRHS());
2816 CFGBlock *LBlock = Visit(B->
getLHS());
2820 return (LBlock ? LBlock : RBlock);
2823CFGBlock *CFGBuilder::VisitNoRecurse(Expr *E, AddStmtChoice asc) {
2824 if (asc.alwaysAdd(*
this, E)) {
2826 appendStmt(
Block, E);
2831CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
2838 Block = createBlock(
false);
2839 Block->setTerminator(B);
2843 if (BreakJumpTarget.block) {
2844 addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
2845 addSuccessor(
Block, BreakJumpTarget.block);
2870 if (BuiltinID != Builtin::BI__assume &&
2871 BuiltinID != Builtin::BI__builtin_assume)
2877CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *
C, AddStmtChoice asc) {
2879 QualType calleeType =
C->getCallee()->getType();
2885 if (!boundType.
isNull()) calleeType = boundType;
2891 bool AddEHEdge =
false;
2901 bool OmitArguments =
false;
2903 if (FunctionDecl *FD =
C->getDirectCallee()) {
2908 if (!FD->isVariadic())
2909 findConstructionContextsForArguments(
C);
2911 if (FD->isNoReturn() || FD->isAnalyzerNoReturn() ||
2912 C->isBuiltinAssumeFalse(*Context))
2914 if (FD->
hasAttr<NoThrowAttr>())
2917 FD->getBuiltinID() == Builtin::BI__builtin_object_size ||
2918 FD->getBuiltinID() == Builtin::BI__builtin_dynamic_object_size)
2919 OmitArguments =
true;
2922 if (!
CanThrow(
C->getCallee(), *Context))
2925 if (OmitArguments) {
2926 assert(!NoReturn &&
"noreturn calls with unevaluated args not implemented");
2927 assert(!AddEHEdge &&
"EH calls with unevaluated args not implemented");
2930 return Visit(
C->getCallee());
2933 if (!NoReturn && !AddEHEdge) {
2937 return VisitCallExprChildren(
C);
2947 Block = createNoReturnBlock();
2949 Block = createBlock();
2955 if (TryTerminatedBlock)
2956 addSuccessor(
Block, TryTerminatedBlock);
2958 addSuccessor(
Block, &cfg->getExit());
2961 return VisitCallExprChildren(
C);
2964CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *
C,
2965 AddStmtChoice asc) {
2966 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2967 appendStmt(ConfluenceBlock,
C);
2971 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2972 Succ = ConfluenceBlock;
2974 CFGBlock *LHSBlock = Visit(
C->getLHS(), alwaysAdd);
2978 Succ = ConfluenceBlock;
2980 CFGBlock *RHSBlock = Visit(
C->getRHS(), alwaysAdd);
2984 Block = createBlock(
false);
2986 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2987 addSuccessor(
Block, KnownVal.isFalse() ?
nullptr : LHSBlock);
2988 addSuccessor(
Block, KnownVal.isTrue() ?
nullptr : RHSBlock);
2990 return addStmt(
C->getCond());
2994 bool ExternallyDestructed) {
2995 LocalScope::const_iterator scopeBeginPos = ScopePos;
2996 addLocalScopeForStmt(
C);
3001 addAutomaticObjHandling(ScopePos, scopeBeginPos,
C);
3004 CFGBlock *LastBlock =
Block;
3006 for (Stmt *S : llvm::reverse(
C->body())) {
3009 CFGBlock *newBlock = Visit(S, AddStmtChoice::AlwaysAdd,
3010 ExternallyDestructed);
3013 LastBlock = newBlock;
3018 ExternallyDestructed =
false;
3024CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *
C,
3025 AddStmtChoice asc) {
3026 const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(
C);
3027 const OpaqueValueExpr *opaqueValue = (BCO ? BCO->
getOpaqueValue() :
nullptr);
3031 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
3032 appendStmt(ConfluenceBlock,
C);
3036 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
3042 Succ = ConfluenceBlock;
3044 CFGBlock *LHSBlock =
nullptr;
3045 const Expr *trueExpr =
C->getTrueExpr();
3046 if (trueExpr != opaqueValue) {
3047 LHSBlock = Visit(
C->getTrueExpr(), alwaysAdd);
3053 LHSBlock = ConfluenceBlock;
3056 Succ = ConfluenceBlock;
3057 CFGBlock *RHSBlock = Visit(
C->getFalseExpr(), alwaysAdd);
3062 if (BinaryOperator *
Cond =
3063 dyn_cast<BinaryOperator>(
C->getCond()->IgnoreParens()))
3064 if (
Cond->isLogicalOp())
3065 return VisitLogicalOperator(
Cond,
C, LHSBlock, RHSBlock).first;
3068 Block = createBlock(
false);
3071 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
3072 addSuccessor(
Block, LHSBlock, !KnownVal.isFalse());
3073 addSuccessor(
Block, RHSBlock, !KnownVal.isTrue());
3075 Expr *condExpr =
C->getCond();
3080 if (condExpr != opaqueValue)
3088 return addStmt(condExpr);
3091CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
3099 return VisitDeclSubExpr(DS);
3101 CFGBlock *B =
nullptr;
3110 DeclGroupRef DG(*I);
3113 cfg->addSyntheticDeclStmt(DSNew, DS);
3116 B = VisitDeclSubExpr(DSNew);
3124CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
3125 assert(DS->
isSingleDecl() &&
"Can handle single declarations only.");
3127 if (
const auto *TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl())) {
3129 const Type *
T = TND->getUnderlyingType().getTypePtr();
3134 appendStmt(
Block, DS);
3136 CFGBlock *LastBlock =
Block;
3137 for (
const VariableArrayType *VA =
FindVA(
T); VA !=
nullptr;
3138 VA =
FindVA(VA->getElementType().getTypePtr())) {
3139 if (CFGBlock *NewBlock = addStmt(VA->getSizeExpr()))
3140 LastBlock = NewBlock;
3153 bool HasTemporaries =
false;
3156 CFGBlock *blockAfterStaticInit =
nullptr;
3167 blockAfterStaticInit = Succ;
3176 if (HasTemporaries &&
3179 TempDtorContext Context;
3181 VisitForTemporaries(FullExprWithCleanups->getSubExpr(),
3184 addFullExprCleanupMarker(Context, FullExprWithCleanups);
3190 if (
const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
3191 for (
auto *BD : llvm::reverse(DD->bindings())) {
3192 if (
auto *VD = BD->getHoldingVar()) {
3193 DeclGroupRef DG(VD);
3196 cfg->addSyntheticDeclStmt(DSNew, DS);
3197 Block = VisitDeclSubExpr(DSNew);
3203 appendStmt(
Block, DS);
3207 const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(
Init);
3209 findConstructionContexts(
3211 AILE ? AILE->getSubExpr() :
Init);
3216 CFGBlock *LastBlock =
Block;
3219 if (HasTemporaries) {
3223 if (CFGBlock *newBlock = Visit(EC->
getSubExpr()))
3224 LastBlock = newBlock;
3227 if (CFGBlock *newBlock = Visit(
Init))
3228 LastBlock = newBlock;
3236 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr())) {
3237 if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
3238 LastBlock = newBlock;
3241 maybeAddScopeBeginForVarDecl(
Block, VD, DS);
3244 if (ScopePos && VD == *ScopePos)
3247 CFGBlock *B = LastBlock;
3248 if (blockAfterStaticInit) {
3250 Block = createBlock(
false);
3251 Block->setTerminator(DS);
3252 addSuccessor(
Block, blockAfterStaticInit);
3253 addSuccessor(
Block, B);
3260CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
3270 SaveAndRestore save_scope_pos(ScopePos);
3274 addLocalScopeForStmt(
Init);
3279 addLocalScopeForVarDecl(VD);
3281 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
3292 CFGBlock *ElseBlock = Succ;
3294 if (Stmt *Else = I->
getElse()) {
3295 SaveAndRestore sv(Succ);
3304 addLocalScopeAndDtors(Else);
3306 ElseBlock = addStmt(Else);
3309 ElseBlock = sv.get();
3317 CFGBlock *ThenBlock;
3321 SaveAndRestore sv(Succ);
3327 addLocalScopeAndDtors(Then);
3329 ThenBlock = addStmt(Then);
3335 ThenBlock = createBlock(
false);
3336 addSuccessor(ThenBlock, sv.get());
3350 BinaryOperator *
Cond =
3354 CFGBlock *LastBlock;
3356 LastBlock = VisitLogicalOperator(
Cond, I, ThenBlock, ElseBlock).first;
3359 Block = createBlock(
false);
3362 Block->setTerminator(I);
3367 KnownVal = tryEvaluateBool(I->
getCond());
3371 addSuccessor(
Block, ThenBlock, !KnownVal.isFalse());
3372 addSuccessor(
Block, ElseBlock, !KnownVal.isTrue());
3380 LastBlock = addStmt(I->
getCond());
3386 LastBlock = addStmt(
const_cast<DeclStmt *
>(DS));
3393 LastBlock = addStmt(
Init);
3399CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {
3409 Block = createBlock(
false);
3411 addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), S);
3413 if (
auto *R = dyn_cast<ReturnStmt>(S))
3414 findConstructionContexts(
3420 if (!
Block->hasNoReturnElement())
3421 addSuccessor(
Block, &cfg->getExit());
3424 appendStmt(
Block, S);
3427 if (ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
3428 if (Expr *O = RS->getRetValue())
3429 return Visit(O, AddStmtChoice::AlwaysAdd,
true);
3441 if (CFGBlock *R = Visit(RV))
3447CFGBlock *CFGBuilder::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E,
3448 AddStmtChoice asc) {
3452 if (asc.alwaysAdd(*
this, E)) {
3454 appendStmt(
Block, E);
3456 CFGBlock *B =
Block;
3468CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
3474 SaveAndRestore save_scope_pos(ScopePos);
3477 CFGBlock *SEHExceptBlock =
Block;
3478 if (!SEHExceptBlock)
3479 SEHExceptBlock = createBlock();
3481 appendStmt(SEHExceptBlock, ES);
3493 return SEHExceptBlock;
3496CFGBlock *CFGBuilder::VisitSEHFinallyStmt(SEHFinallyStmt *FS) {
3497 return VisitCompoundStmt(FS->
getBlock(),
false);
3500CFGBlock *CFGBuilder::VisitSEHLeaveStmt(SEHLeaveStmt *LS) {
3507 Block = createBlock(
false);
3508 Block->setTerminator(LS);
3512 if (SEHLeaveJumpTarget.block) {
3513 addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS);
3514 addSuccessor(
Block, SEHLeaveJumpTarget.block);
3521CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) {
3524 CFGBlock *SEHTrySuccessor =
nullptr;
3529 SEHTrySuccessor =
Block;
3530 }
else SEHTrySuccessor = Succ;
3536 CFGBlock *PrevSEHTryTerminatedBlock = TryTerminatedBlock;
3539 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
3546 Succ = SEHTrySuccessor;
3548 CFGBlock *ExceptBlock = VisitSEHExceptStmt(Except);
3553 addSuccessor(NewTryTerminatedBlock, ExceptBlock);
3555 if (PrevSEHTryTerminatedBlock)
3556 addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock);
3558 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
3561 Succ = SEHTrySuccessor;
3564 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
3565 cfg->addTryDispatchBlock(TryTerminatedBlock);
3570 SaveAndRestore save_break(SEHLeaveJumpTarget);
3571 SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
3573 assert(Terminator->
getTryBlock() &&
"__try must contain a non-NULL body");
3578CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
3581 CFGBlock *LabelBlock =
Block;
3584 LabelBlock = createBlock();
3586 assert(!LabelMap.contains(L->
getDecl()) &&
"label already in map");
3587 LabelMap[L->
getDecl()] = JumpTarget(LabelBlock, ScopePos);
3606CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
3607 CFGBlock *LastBlock = VisitNoRecurse(E, asc);
3609 if (Expr *CopyExpr = CI.getCopyExpr()) {
3610 CFGBlock *Tmp = Visit(CopyExpr);
3618CFGBlock *CFGBuilder::VisitLambdaExpr(
LambdaExpr *E, AddStmtChoice asc) {
3619 CFGBlock *LastBlock = VisitNoRecurse(E, asc);
3630 dyn_cast<ArrayInitLoopExpr>(
Init));
3633 cfg->getBumpVectorContext(), {E, Idx}),
3634 AILEInit ? AILEInit :
Init);
3636 CFGBlock *Tmp = Visit(
Init);
3644CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
3648 Block = createBlock(
false);
3649 Block->setTerminator(G);
3652 LabelMapTy::iterator I = LabelMap.find(G->
getLabel());
3654 if (I == LabelMap.end())
3656 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3658 JumpTarget JT = I->second;
3659 addSuccessor(
Block, JT.block);
3660 addScopeChangesHandling(ScopePos, JT.scopePosition, G);
3666CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) {
3671 return VisitStmt(G, asc);
3678 Block = createBlock();
3679 Block->setTerminator(G);
3681 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3684 BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
3685 return VisitChildren(G);
3688CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
3689 CFGBlock *LoopSuccessor =
nullptr;
3693 SaveAndRestore save_scope_pos(ScopePos);
3699 addLocalScopeForStmt(
Init);
3700 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3703 addLocalScopeForVarDecl(VD);
3704 LocalScope::const_iterator ContinueScopePos = ScopePos;
3706 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
3715 LoopSuccessor =
Block;
3717 LoopSuccessor = Succ;
3721 SaveAndRestore save_break(BreakJumpTarget);
3722 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3724 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3731 SaveAndRestore save_Block(
Block), save_Succ(Succ);
3732 SaveAndRestore save_continue(ContinueJumpTarget);
3737 Block = Succ = TransitionBlock = createBlock(
false);
3738 TransitionBlock->setLoopTarget(F);
3743 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
3745 if (Stmt *I = F->
getInc()) {
3753 assert(
Block == Succ);
3761 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
3762 ContinueJumpTarget.block->setLoopTarget(F);
3768 addLocalScopeAndDtors(F->
getBody());
3772 BodyBlock = addStmt(F->
getBody());
3777 BodyBlock = ContinueJumpTarget.block;
3786 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3790 SaveAndRestore save_scope_pos(ScopePos);
3794 if (BinaryOperator *
Cond =
3795 dyn_cast_or_null<BinaryOperator>(
C ?
C->IgnoreParens() :
nullptr))
3796 if (
Cond->isLogicalOp()) {
3797 std::tie(EntryConditionBlock, ExitConditionBlock) =
3798 VisitLogicalOperator(
Cond, F, BodyBlock, LoopSuccessor);
3803 EntryConditionBlock = ExitConditionBlock = createBlock(
false);
3804 ExitConditionBlock->setTerminator(F);
3807 TryResult KnownVal(
true);
3813 Block = ExitConditionBlock;
3814 EntryConditionBlock = addStmt(
C);
3823 findConstructionContexts(
3826 appendStmt(
Block, DS);
3827 EntryConditionBlock = addStmt(
Init);
3828 assert(
Block == EntryConditionBlock);
3829 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3833 if (
Block && badCFG)
3836 KnownVal = tryEvaluateBool(
C);
3840 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
3843 addSuccessor(ExitConditionBlock,
3844 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
3848 addSuccessor(TransitionBlock, EntryConditionBlock);
3851 Succ = EntryConditionBlock;
3856 SaveAndRestore save_scope_pos(ScopePos);
3857 ScopePos = LoopBeginScopePos;
3858 Block = createBlock();
3865 Succ = EntryConditionBlock;
3866 return EntryConditionBlock;
3870CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
3871 AddStmtChoice asc) {
3872 findConstructionContexts(
3876 return VisitStmt(MTE, asc);
3879CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
3880 if (asc.alwaysAdd(*
this, M)) {
3882 appendStmt(
Block, M);
3887CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
3919 CFGBlock *LoopSuccessor =
nullptr;
3924 LoopSuccessor =
Block;
3927 LoopSuccessor = Succ;
3930 CFGBlock *ExitConditionBlock = createBlock(
false);
3938 appendStmt(ExitConditionBlock, S);
3939 Block = ExitConditionBlock;
3944 CFGBlock *EntryConditionBlock = Visit(S->
getElement(),
3945 AddStmtChoice::NotAlwaysAdd);
3954 Succ = EntryConditionBlock;
3959 SaveAndRestore save_Block(
Block), save_Succ(Succ);
3960 SaveAndRestore save_continue(ContinueJumpTarget),
3961 save_break(BreakJumpTarget);
3966 CFGBlock *LoopBackBlock =
nullptr;
3967 Succ = LoopBackBlock = createBlock();
3970 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3971 ContinueJumpTarget = JumpTarget(Succ, ScopePos);
3973 CFGBlock *BodyBlock = addStmt(S->
getBody());
3976 BodyBlock = ContinueJumpTarget.block;
3983 addSuccessor(ExitConditionBlock, BodyBlock);
3988 addSuccessor(ExitConditionBlock, LoopSuccessor);
3991 Block = createBlock();
3995CFGBlock *CFGBuilder::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
4001CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
4019 appendStmt(
Block, S);
4025CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
4029 appendStmt(
Block, E);
4031 CFGBlock *lastBlock =
Block;
4040 if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic))
4041 Semantic = OVE->getSourceExpr();
4043 if (CFGBlock *B = Visit(Semantic))
4050CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
4051 CFGBlock *LoopSuccessor =
nullptr;
4055 SaveAndRestore save_scope_pos(ScopePos);
4059 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
4061 addLocalScopeForVarDecl(VD);
4062 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4071 LoopSuccessor =
Block;
4074 LoopSuccessor = Succ;
4077 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
4084 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4085 SaveAndRestore save_continue(ContinueJumpTarget),
4086 save_break(BreakJumpTarget);
4090 Succ = TransitionBlock = createBlock(
false);
4091 TransitionBlock->setLoopTarget(W);
4092 ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
4095 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4098 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4103 addLocalScopeAndDtors(W->
getBody());
4106 BodyBlock = addStmt(W->
getBody());
4109 BodyBlock = ContinueJumpTarget.block;
4110 else if (
Block && badCFG)
4117 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
4124 if (BinaryOperator *
Cond = dyn_cast<BinaryOperator>(
C->IgnoreParens()))
4125 if (
Cond->isLogicalOp()) {
4126 std::tie(EntryConditionBlock, ExitConditionBlock) =
4127 VisitLogicalOperator(
Cond, W, BodyBlock, LoopSuccessor);
4132 ExitConditionBlock = createBlock(
false);
4138 Block = ExitConditionBlock;
4139 Block = EntryConditionBlock = addStmt(
C);
4148 findConstructionContexts(
4150 const_cast<DeclStmt *
>(DS)),
4152 appendStmt(
Block, DS);
4153 EntryConditionBlock = addStmt(
Init);
4154 assert(
Block == EntryConditionBlock);
4155 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
4159 if (
Block && badCFG)
4163 const TryResult& KnownVal = tryEvaluateBool(
C);
4166 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
4169 addSuccessor(ExitConditionBlock,
4170 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4174 addSuccessor(TransitionBlock, EntryConditionBlock);
4181 Succ = EntryConditionBlock;
4182 return EntryConditionBlock;
4185CFGBlock *CFGBuilder::VisitArrayInitLoopExpr(ArrayInitLoopExpr *A,
4186 AddStmtChoice asc) {
4187 if (asc.alwaysAdd(*
this, A)) {
4189 appendStmt(
Block, A);
4192 CFGBlock *B =
Block;
4204CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *CS) {
4210 SaveAndRestore save_scope_pos(ScopePos);
4215 CFGBlock *CatchBlock =
Block;
4217 CatchBlock = createBlock();
4219 appendStmt(CatchBlock, CS);
4234CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
4240 Block = createBlock(
false);
4242 if (TryTerminatedBlock)
4244 addSuccessor(
Block, TryTerminatedBlock);
4247 addSuccessor(
Block, &cfg->getExit());
4251 return VisitStmt(S, AddStmtChoice::AlwaysAdd);
4254CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *Terminator) {
4257 CFGBlock *TrySuccessor =
nullptr;
4262 TrySuccessor =
Block;
4264 TrySuccessor = Succ;
4270 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4273 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4277 bool HasCatchAll =
false;
4278 for (ObjCAtCatchStmt *CS : Terminator->
catch_stmts()) {
4280 Succ = TrySuccessor;
4285 CFGBlock *CatchBlock = VisitObjCAtCatchStmt(CS);
4290 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4295 if (PrevTryTerminatedBlock)
4296 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4298 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4302 Succ = TrySuccessor;
4305 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4306 cfg->addTryDispatchBlock(TryTerminatedBlock);
4308 assert(Terminator->
getTryBody() &&
"try must contain a non-NULL body");
4313CFGBlock *CFGBuilder::VisitObjCMessageExpr(ObjCMessageExpr *ME,
4314 AddStmtChoice asc) {
4315 findConstructionContextsForArguments(ME);
4318 appendObjCMessage(
Block, ME);
4320 return VisitChildren(ME);
4323CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *
T) {
4329 Block = createBlock(
false);
4331 if (TryTerminatedBlock)
4333 addSuccessor(
Block, TryTerminatedBlock);
4336 addSuccessor(
Block, &cfg->getExit());
4340 return VisitStmt(
T, AddStmtChoice::AlwaysAdd);
4343CFGBlock *CFGBuilder::VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc) {
4344 if (asc.alwaysAdd(*
this, S)) {
4346 appendStmt(
Block, S);
4356 return VisitChildren(S);
4362CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
4363 CFGBlock *LoopSuccessor =
nullptr;
4372 LoopSuccessor =
Block;
4374 LoopSuccessor = Succ;
4379 CFGBlock *ExitConditionBlock = createBlock(
false);
4380 CFGBlock *EntryConditionBlock = ExitConditionBlock;
4388 Block = ExitConditionBlock;
4389 EntryConditionBlock = addStmt(
C);
4397 Succ = EntryConditionBlock;
4400 const TryResult &KnownVal = tryEvaluateBool(D->
getCond());
4403 CFGBlock *BodyBlock =
nullptr;
4408 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4409 SaveAndRestore save_continue(ContinueJumpTarget),
4410 save_break(BreakJumpTarget);
4413 ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
4416 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4424 addLocalScopeAndDtors(D->
getBody());
4427 BodyBlock = addStmt(D->
getBody());
4430 BodyBlock = EntryConditionBlock;
4443 CFGBlock *LoopBackBlock = createBlock();
4446 if (!KnownVal.isFalse())
4448 addSuccessor(ExitConditionBlock, LoopBackBlock);
4450 addSuccessor(ExitConditionBlock,
nullptr);
4455 addSuccessor(ExitConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4466CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *
C) {
4473 Block = createBlock(
false);
4478 if (ContinueJumpTarget.block) {
4479 addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition,
C);
4480 addSuccessor(
Block, ContinueJumpTarget.block);
4487CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
4488 AddStmtChoice asc) {
4489 if (asc.alwaysAdd(*
this, E)) {
4491 appendStmt(
Block, E);
4497 if (E->
getKind() != UETT_SizeOf)
4500 CFGBlock *lastBlock =
Block;
4504 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr()))
4505 lastBlock = addStmt(VA->getSizeExpr());
4512CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
4513 if (asc.alwaysAdd(*
this, SE)) {
4515 appendStmt(
Block, SE);
4517 return VisitCompoundStmt(SE->
getSubStmt(),
true);
4520CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
4523 CFGBlock *SwitchSuccessor =
nullptr;
4527 SaveAndRestore save_scope_pos(ScopePos);
4531 addLocalScopeForStmt(
Init);
4536 addLocalScopeForVarDecl(VD);
4538 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
4543 SwitchSuccessor =
Block;
4544 }
else SwitchSuccessor = Succ;
4547 SaveAndRestore save_switch(SwitchTerminatedBlock),
4548 save_default(DefaultCaseBlock);
4549 SaveAndRestore save_break(BreakJumpTarget);
4554 DefaultCaseBlock = SwitchSuccessor;
4557 SwitchTerminatedBlock = createBlock(
false);
4561 Succ = SwitchSuccessor;
4562 BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
4567 assert(Terminator->
getBody() &&
"switch must contain a non-NULL body");
4572 SaveAndRestore save_switchExclusivelyCovered(switchExclusivelyCovered,
false);
4575 assert(Terminator->
getCond() &&
"switch condition must be non-NULL");
4576 Expr::EvalResult result;
4577 bool b = tryEvaluate(Terminator->
getCond(), result);
4578 SaveAndRestore save_switchCond(switchCond, b ? &result :
nullptr);
4583 addLocalScopeAndDtors(Terminator->
getBody());
4585 addStmt(Terminator->
getBody());
4599 bool SwitchAlwaysHasSuccessor =
false;
4600 SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
4601 SwitchAlwaysHasSuccessor |=
4604 addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock,
4605 !SwitchAlwaysHasSuccessor);
4609 Block = SwitchTerminatedBlock;
4610 CFGBlock *LastBlock = addStmt(Terminator->
getCond());
4618 LastBlock = addStmt(
Init);
4619 maybeAddScopeBeginForVarDecl(LastBlock, VD,
Init);
4626 LastBlock = addStmt(
Init);
4639 bool addCase =
false;
4641 if (!switchExclusivelyCovered) {
4645 const llvm::APSInt &condInt = switchCond->
Val.
getInt();
4647 if (condInt == lhsInt) {
4649 switchExclusivelyCovered =
true;
4651 else if (condInt > lhsInt) {
4655 if (V2 >= condInt) {
4657 switchExclusivelyCovered =
true;
4668CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
4671 CFGBlock *TopBlock =
nullptr, *LastBlock =
nullptr;
4678 CFGBlock *currentBlock = createBlock(
false);
4682 addSuccessor(LastBlock, currentBlock);
4684 TopBlock = currentBlock;
4686 addSuccessor(SwitchTerminatedBlock,
4689 ? currentBlock :
nullptr);
4691 LastBlock = currentBlock;
4699 CFGBlock *CaseBlock =
Block;
4701 CaseBlock = createBlock();
4712 assert(SwitchTerminatedBlock);
4713 addSuccessor(SwitchTerminatedBlock, CaseBlock,
4721 addSuccessor(LastBlock, CaseBlock);
4731CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {
4735 DefaultCaseBlock =
Block;
4737 if (!DefaultCaseBlock)
4738 DefaultCaseBlock = createBlock();
4742 DefaultCaseBlock->
setLabel(Terminator);
4757 Succ = DefaultCaseBlock;
4759 return DefaultCaseBlock;
4762CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
4765 CFGBlock *TrySuccessor =
nullptr;
4770 TrySuccessor =
Block;
4772 TrySuccessor = Succ;
4774 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4777 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4781 bool HasCatchAll =
false;
4782 for (
unsigned I = 0, E = Terminator->
getNumHandlers(); I != E; ++I) {
4784 Succ = TrySuccessor;
4785 CXXCatchStmt *CS = Terminator->
getHandler(I);
4790 CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
4795 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4798 if (PrevTryTerminatedBlock)
4799 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4801 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4805 Succ = TrySuccessor;
4808 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4809 cfg->addTryDispatchBlock(TryTerminatedBlock);
4811 assert(Terminator->
getTryBlock() &&
"try must contain a non-NULL body");
4816CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
4822 SaveAndRestore save_scope_pos(ScopePos);
4827 LocalScope::const_iterator BeginScopePos = ScopePos;
4828 addLocalScopeForVarDecl(VD);
4829 addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
4835 CFGBlock *CatchBlock =
Block;
4837 CatchBlock = createBlock();
4843 appendStmt(CatchBlock, CS);
4859CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
4874 SaveAndRestore save_scope_pos(ScopePos);
4879 addLocalScopeForStmt(
Init);
4881 addLocalScopeForStmt(Range);
4883 addLocalScopeForStmt(Begin);
4885 addLocalScopeForStmt(End);
4886 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
4888 LocalScope::const_iterator ContinueScopePos = ScopePos;
4892 CFGBlock *LoopSuccessor =
nullptr;
4896 LoopSuccessor =
Block;
4898 LoopSuccessor = Succ;
4902 SaveAndRestore save_break(BreakJumpTarget);
4903 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4906 CFGBlock *ConditionBlock = createBlock(
false);
4911 Block = ConditionBlock;
4912 CFGBlock *BeginConditionBlock = addStmt(
C);
4915 assert(BeginConditionBlock == ConditionBlock &&
4916 "condition block in for-range was unexpectedly complex");
4917 (void)BeginConditionBlock;
4922 Succ = ConditionBlock;
4925 TryResult KnownVal(
true);
4928 KnownVal = tryEvaluateBool(S->
getCond());
4935 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4936 SaveAndRestore save_continue(ContinueJumpTarget);
4941 Succ = addStmt(S->
getInc());
4944 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
4948 ContinueJumpTarget.block->setLoopTarget(S);
4962 addLocalScopeAndDtors(S->
getBody());
4974 addSuccessor(ConditionBlock,
4975 KnownVal.isFalse() ?
nullptr : LoopVarStmtBlock);
4980 addSuccessor(ConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4983 Block = createBlock();
4992CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
4994 bool ExternallyDestructed) {
4998 TempDtorContext Context;
5000 VisitForTemporaries(FullExpr, ExternallyDestructed, Context);
5002 addFullExprCleanupMarker(Context, E);
5006 asc = asc.withAlwaysAdd(
true);
5011CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
5012 AddStmtChoice asc) {
5013 if (asc.alwaysAdd(*
this, E)) {
5015 appendStmt(
Block, E);
5017 findConstructionContexts(
5022 asc = asc.withAlwaysAdd(
false);
5027CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *
C,
5028 AddStmtChoice asc) {
5032 findConstructionContextsForArguments(
C);
5033 appendConstructor(
C);
5035 return VisitChildren(
C);
5038CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
5039 AddStmtChoice asc) {
5041 appendStmt(
Block, NE);
5043 findConstructionContexts(
5045 const_cast<CXXConstructExpr *
>(
NE->getConstructExpr()));
5047 if (
NE->getInitializer())
5048 Block = Visit(
NE->getInitializer());
5051 appendNewAllocator(
Block, NE);
5053 if (
NE->isArray() && *
NE->getArraySize())
5054 Block = Visit(*
NE->getArraySize());
5057 E =
NE->placement_arg_end(); I != E; ++I)
5063CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
5064 AddStmtChoice asc) {
5066 appendStmt(
Block, DE);
5073 appendDeleteDtor(
Block, RD, DE);
5077 return VisitChildren(DE);
5080CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
5081 AddStmtChoice asc) {
5082 if (asc.alwaysAdd(*
this, E)) {
5084 appendStmt(
Block, E);
5086 asc = asc.withAlwaysAdd(
false);
5091CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E,
5092 AddStmtChoice asc) {
5096 findConstructionContextsForArguments(E);
5097 appendConstructor(E);
5099 return VisitChildren(E);
5102CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
5103 AddStmtChoice asc) {
5104 if (asc.alwaysAdd(*
this, E)) {
5106 appendStmt(
Block, E);
5112 return Visit(E->
getSubExpr(), AddStmtChoice());
5115CFGBlock *CFGBuilder::VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc) {
5116 return Visit(E->
getSubExpr(), AddStmtChoice());
5119CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
5121 CFGBlock *IBlock = cfg->getIndirectGotoBlock();
5124 IBlock = createBlock(
false);
5125 cfg->setIndirectGotoBlock(IBlock);
5133 Block = createBlock(
false);
5134 Block->setTerminator(I);
5135 addSuccessor(
Block, IBlock);
5139CFGBlock *CFGBuilder::VisitForTemporaries(Stmt *E,
bool ExternallyDestructed,
5140 TempDtorContext &Context) {
5149 return VisitChildrenForTemporaries(E,
false, Context);
5151 case Stmt::InitListExprClass:
5152 return VisitChildrenForTemporaries(E, ExternallyDestructed, Context);
5154 case Stmt::BinaryOperatorClass:
5155 case Stmt::CompoundAssignOperatorClass:
5157 ExternallyDestructed, Context);
5159 case Stmt::CXXOperatorCallExprClass:
5160 return VisitCXXOperatorCallExprForTemporaryDtors(
5163 case Stmt::CXXBindTemporaryExprClass:
5164 return VisitCXXBindTemporaryExprForTemporaryDtors(
5167 case Stmt::BinaryConditionalOperatorClass:
5168 case Stmt::ConditionalOperatorClass:
5169 return VisitConditionalOperatorForTemporaries(
5172 case Stmt::ImplicitCastExprClass:
5177 case Stmt::CXXFunctionalCastExprClass:
5182 case Stmt::ConstantExprClass:
5186 case Stmt::ParenExprClass:
5190 case Stmt::MaterializeTemporaryExprClass: {
5193 if (BuildOpts.
AddLifetime && !ExternallyDestructed)
5195 SmallVector<const Expr *, 2> CommaLHSs;
5196 SmallVector<SubobjectAdjustment, 2> Adjustments;
5198 E =
const_cast<Expr *
>(
5201 ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
5203 for (
const Expr *CommaLHS : CommaLHSs) {
5204 VisitForTemporaries(
const_cast<Expr *
>(CommaLHS),
5210 case Stmt::BlockExprClass:
5215 case Stmt::LambdaExprClass: {
5219 CFGBlock *B =
Block;
5220 for (Expr *
Init :
LE->capture_inits()) {
5222 if (CFGBlock *R = VisitForTemporaries(
5223 Init,
true, Context))
5230 case Stmt::StmtExprClass:
5235 case Stmt::CXXDefaultArgExprClass:
5239 case Stmt::CXXDefaultInitExprClass:
5245CFGBlock *CFGBuilder::VisitChildrenForTemporaries(Stmt *E,
5246 bool ExternallyDestructed,
5247 TempDtorContext &Context) {
5257 CFGBlock *B =
Block;
5261 VisitForTemporaries(Child, ExternallyDestructed, Context))
5267CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaries(
5268 BinaryOperator *E,
bool ExternallyDestructed, TempDtorContext &Context) {
5272 CFGBlock *LHSBlock = VisitForTemporaries(E->
getLHS(),
false, Context);
5273 CFGBlock *RHSBlock =
5274 VisitForTemporaries(E->
getRHS(), ExternallyDestructed, Context);
5275 return RHSBlock ? RHSBlock : LHSBlock;
5279 VisitForTemporaries(E->
getLHS(),
false, Context);
5280 TryResult RHSExecuted = tryEvaluateBool(E->
getLHS());
5281 if (RHSExecuted.isKnown() && E->
getOpcode() == BO_LOr)
5282 RHSExecuted.negate();
5287 TempDtorContext RHSContext(
5289 VisitForTemporaries(E->
getRHS(),
false, RHSContext);
5290 InsertTempDecisionBlock(RHSContext);
5293 Context.CollectedMTEs.append(RHSContext.CollectedMTEs);
5301 CFGBlock *RHSBlock = VisitForTemporaries(E->
getRHS(),
false, Context);
5302 CFGBlock *LHSBlock = VisitForTemporaries(E->
getLHS(),
false, Context);
5303 return LHSBlock ? LHSBlock : RHSBlock;
5307 return VisitChildrenForTemporaries(E, ExternallyDestructed, Context);
5310CFGBlock *CFGBuilder::VisitCXXOperatorCallExprForTemporaryDtors(
5311 CXXOperatorCallExpr *E, TempDtorContext &Context) {
5315 CFGBlock *RHSBlock = VisitForTemporaries(E->
getArg(1),
false, Context);
5316 CFGBlock *LHSBlock = VisitForTemporaries(E->
getArg(0),
false, Context);
5317 return LHSBlock ? LHSBlock : RHSBlock;
5319 return VisitChildrenForTemporaries(E,
false, Context);
5322CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
5323 CXXBindTemporaryExpr *E,
bool ExternallyDestructed, TempDtorContext &Context) {
5326 CFGBlock *B = VisitForTemporaries(E->
getSubExpr(),
true, Context);
5334 if (
Dtor->getParent()->isAnyDestructorNoReturn()) {
5340 Block = createNoReturnBlock();
5341 }
else if (Context.needsTempDtorBranch()) {
5345 Block = createBlock();
5349 if (Context.needsTempDtorBranch()) {
5350 Context.setDecisionPoint(Succ, E);
5352 appendTemporaryDtor(
Block, E);
5358void CFGBuilder::InsertTempDecisionBlock(
const TempDtorContext &Context,
5359 CFGBlock *FalseSucc) {
5360 if (!Context.TerminatorExpr) {
5364 assert(Context.TerminatorExpr);
5365 CFGBlock *Decision = createBlock(
false);
5366 Decision->setTerminator(CFGTerminator(Context.TerminatorExpr,
5368 addSuccessor(Decision,
Block, !Context.KnownExecuted.isFalse());
5369 addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
5370 !Context.KnownExecuted.isTrue());
5374CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaries(
5375 AbstractConditionalOperator *E,
bool ExternallyDestructed,
5376 TempDtorContext &Context) {
5377 VisitForTemporaries(E->
getCond(),
false, Context);
5378 CFGBlock *ConditionBlock =
Block;
5379 CFGBlock *ConditionSucc = Succ;
5380 TryResult ConditionVal = tryEvaluateBool(E->
getCond());
5381 TryResult NegatedVal = ConditionVal;
5382 if (NegatedVal.isKnown()) NegatedVal.negate();
5384 TempDtorContext TrueContext(
5386 VisitForTemporaries(E->
getTrueExpr(), ExternallyDestructed, TrueContext);
5387 CFGBlock *TrueBlock =
Block;
5389 Block = ConditionBlock;
5390 Succ = ConditionSucc;
5391 TempDtorContext FalseContext(
5393 VisitForTemporaries(E->
getFalseExpr(), ExternallyDestructed, FalseContext);
5395 if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
5396 InsertTempDecisionBlock(FalseContext, TrueBlock);
5397 }
else if (TrueContext.TerminatorExpr) {
5399 InsertTempDecisionBlock(TrueContext);
5401 InsertTempDecisionBlock(FalseContext);
5404 Context.CollectedMTEs.append(TrueContext.CollectedMTEs);
5405 Context.CollectedMTEs.append(FalseContext.CollectedMTEs);
5411CFGBlock *CFGBuilder::VisitOMPExecutableDirective(OMPExecutableDirective *D,
5412 AddStmtChoice asc) {
5413 if (asc.alwaysAdd(*
this, D)) {
5415 appendStmt(
Block, D);
5419 CFGBlock *B =
Block;
5423 SmallVector<Stmt *, 8>
Used(
5424 OMPExecutableDirective::used_clauses_children(D->clauses()));
5425 for (Stmt *S : llvm::reverse(
Used)) {
5426 assert(S &&
"Expected non-null used-in-clause child.");
5427 if (CFGBlock *R = Visit(S))
5431 if (!D->isStandaloneDirective()) {
5432 Stmt *S = D->getRawStmt();
5434 addLocalScopeAndDtors(S);
5435 if (CFGBlock *R = addStmt(S))
5446 bool first_block =
begin() ==
end();
5450 Blocks.push_back(Mem, BlkBVC);
5454 Entry = Exit = &
back();
5463 llvm::TimeTraceScope TimeProfile(
"BuildCFG");
5464 CFGBuilder Builder(
C, BO);
5465 return Builder.buildCFG(D, Statement);
5480 auto IteratorAndFlag = Visited.insert(B);
5481 if (!IteratorAndFlag.second) {
5487 const CFGBlock *FirstReachableB =
nullptr;
5489 if (!AB.isReachable())
5492 if (FirstReachableB ==
nullptr) {
5493 FirstReachableB = &*AB;
5500 if (!FirstReachableB) {
5506 B = FirstReachableB;
5527 llvm_unreachable(
"getDestructorDecl should only be used with "
5538 if (
const Expr *
Init = var->getInit()) {
5585 llvm_unreachable(
"getKind() returned bogus value");
5593 : ReachableBlock(IsReachable ? B :
nullptr),
5594 UnreachableBlock(!IsReachable ? B :
nullptr,
5595 B && IsReachable ? AB_Normal : AB_Unreachable) {}
5598 : ReachableBlock(B),
5599 UnreachableBlock(B == AlternateBlock ?
nullptr : AlternateBlock,
5600 B == AlternateBlock ? AB_Alternate : AB_Normal) {}
5610 Succs.push_back(Succ,
C);
5623 if (S->isAllEnumCasesCovered()) {
5641 using StmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>;
5642 using DeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>;
5646 signed currentBlock = 0;
5647 unsigned currStmt = 0;
5657 for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
5658 BI != BEnd; ++BI, ++j ) {
5659 if (std::optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
5660 const Stmt *stmt= SE->getStmt();
5661 std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
5664 switch (stmt->getStmtClass()) {
5665 case Stmt::DeclStmtClass:
5666 DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P;
5668 case Stmt::IfStmtClass: {
5669 const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable();
5674 case Stmt::ForStmtClass: {
5675 const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable();
5680 case Stmt::WhileStmtClass: {
5681 const VarDecl *var =
5682 cast<WhileStmt>(stmt)->getConditionVariable();
5687 case Stmt::SwitchStmtClass: {
5688 const VarDecl *var =
5689 cast<SwitchStmt>(stmt)->getConditionVariable();
5694 case Stmt::CXXCatchStmtClass: {
5695 const VarDecl *var =
5696 cast<CXXCatchStmt>(stmt)->getExceptionDecl();
5709 ~StmtPrinterHelper()
override =
default;
5711 const LangOptions &getLangOpts()
const {
return LangOpts; }
5712 void setBlockID(
signed i) { currentBlock = i; }
5713 void setStmtID(
unsigned i) { currStmt = i; }
5715 bool handledStmt(Stmt *S, raw_ostream &OS)
override {
5716 StmtMapTy::iterator I = StmtMap.find(S);
5718 if (I == StmtMap.end())
5721 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5722 && I->second.second == currStmt) {
5726 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5730 bool handleDecl(
const Decl *D, raw_ostream &OS) {
5731 DeclMapTy::iterator I = DeclMap.find(D);
5733 if (I == DeclMap.end()) {
5736 if (
auto *PVD = dyn_cast_or_null<ParmVarDecl>(D)) {
5737 OS <<
"[Parm: " << PVD->getNameAsString() <<
"]";
5743 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5744 && I->second.second == currStmt) {
5748 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5753class CFGBlockTerminatorPrint
5754 :
public StmtVisitor<CFGBlockTerminatorPrint,void> {
5756 StmtPrinterHelper* Helper;
5757 PrintingPolicy Policy;
5760 CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
5761 const PrintingPolicy &Policy)
5762 :
OS(os), Helper(helper), Policy(Policy) {
5766 void VisitIfStmt(IfStmt *I) {
5769 C->printPretty(OS, Helper, Policy);
5773 void VisitStmt(Stmt *Terminator) {
5777 void VisitDeclStmt(DeclStmt *DS) {
5782 void VisitForStmt(ForStmt *F) {
5788 C->printPretty(OS, Helper, Policy);
5795 void VisitWhileStmt(WhileStmt *W) {
5798 C->printPretty(OS, Helper, Policy);
5801 void VisitDoStmt(DoStmt *D) {
5802 OS <<
"do ... while ";
5804 C->printPretty(OS, Helper, Policy);
5807 void VisitSwitchStmt(SwitchStmt *Terminator) {
5812 void VisitCXXTryStmt(CXXTryStmt *) {
OS <<
"try ..."; }
5814 void VisitObjCAtTryStmt(ObjCAtTryStmt *) {
OS <<
"@try ..."; }
5816 void VisitSEHTryStmt(SEHTryStmt *CS) {
OS <<
"__try ..."; }
5818 void VisitAbstractConditionalOperator(AbstractConditionalOperator*
C) {
5819 if (Stmt *
Cond =
C->getCond())
5821 OS <<
" ? ... : ...";
5824 void VisitChooseExpr(ChooseExpr *
C) {
5825 OS <<
"__builtin_choose_expr( ";
5826 if (Stmt *
Cond =
C->getCond())
5831 void VisitIndirectGotoStmt(IndirectGotoStmt *I) {
5834 T->printPretty(OS, Helper, Policy);
5837 void VisitBinaryOperator(BinaryOperator* B) {
5854 llvm_unreachable(
"Invalid logical operator.");
5858 void VisitExpr(Expr *E) {
5863 void print(CFGTerminator
T) {
5864 switch (
T.getKind()) {
5869 OS <<
"(Temp Dtor) ";
5873 OS <<
"(See if most derived ctor has already initialized vbases)";
5895 OS <<
" (Base initializer)";
5897 OS <<
" (Delegating initializer)";
5899 OS <<
" (Member initializer)";
5903 StmtPrinterHelper &Helper,
5918 Stmts.push_back(CICC->getCXXBindTemporaryExpr());
5923 Stmts.push_back(SDSCC->getDeclStmt());
5928 Stmts.push_back(CDSCC->getDeclStmt());
5929 Stmts.push_back(CDSCC->getCXXBindTemporaryExpr());
5934 Stmts.push_back(NECC->getCXXNewExpr());
5939 Stmts.push_back(RSCC->getReturnStmt());
5945 Stmts.push_back(RSCC->getReturnStmt());
5946 Stmts.push_back(RSCC->getCXXBindTemporaryExpr());
5951 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5952 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5957 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5958 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5959 Stmts.push_back(TOCC->getConstructorAfterElision());
5964 Helper.handledStmt(
const_cast<LambdaExpr *
>(LCC->getLambdaExpr()), OS);
5965 OS <<
"+" << LCC->getIndex();
5970 if (
const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
5972 Helper.handledStmt(
const_cast<Stmt *
>(BTE), OS);
5975 Helper.handledStmt(
const_cast<Expr *
>(ACC->getCallLikeExpr()), OS);
5976 OS <<
"+" << ACC->getIndex();
5983 Helper.handledStmt(
const_cast<Stmt *
>(I), OS);
5987static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5988 const CFGElement &E,
bool TerminateWithNewLine =
true);
5991 bool TerminateWithNewLine)
const {
5993 StmtPrinterHelper Helper(
nullptr, LangOpts);
5994 print_elem(OS, Helper, *
this, TerminateWithNewLine);
5997static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5998 const CFGElement &E,
bool TerminateWithNewLine) {
6005 assert(S !=
nullptr &&
"Expecting non-null Stmt");
6008 if (
const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
6016 if (TerminateWithNewLine)
6025 Helper.handledStmt(B->
getRHS(),OS);
6026 if (TerminateWithNewLine)
6031 S->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
6035 OS <<
" (OperatorCall)";
6036 OS <<
" (CXXRecordTypedCall";
6040 OS <<
" (OperatorCall)";
6042 OS <<
" (BindTemporary)";
6044 OS <<
" (CXXConstructExpr";
6048 OS <<
", " << CCE->getType() <<
")";
6049 }
else if (
const CastExpr *CE = dyn_cast<CastExpr>(S)) {
6051 <<
", " << CE->
getType() <<
")";
6055 if (
isa<Expr>(S) && TerminateWithNewLine)
6068 Helper.handleDecl(VD, OS);
6071 if (
T->isReferenceType())
6075 T.getUnqualifiedType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
6076 OS <<
"() (Implicit destructor)";
6081 OS <<
"CleanupFunction ("
6087 OS <<
" (Lifetime ends)";
6092 size_t MTECount = MTEs.size();
6093 OS <<
"(FullExprCleanup collected " << MTECount
6094 << (MTECount > 1 ?
" MTEs: " :
" MTE: ");
6095 bool FirstMTE =
true;
6099 if (!Helper.handledStmt(MTE->
getSubExpr(), OS)) {
6117 OS <<
"CFGScopeBegin(";
6124 OS <<
"CFGScopeEnd(";
6131 OS <<
"CFGNewAllocator(";
6133 AllocExpr->getType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
6145 OS <<
"->~" << RD->getName().str() <<
"()";
6146 OS <<
" (Implicit destructor)";
6153 OS <<
" (Base object destructor)";
6160 OS <<
"this->" << FD->
getName();
6161 OS <<
".~" <<
T->getAsCXXRecordDecl()->getName() <<
"()";
6162 OS <<
" (Member object destructor)";
6171 OS <<
"() (Temporary object destructor)";
6175 if (TerminateWithNewLine)
6181 StmtPrinterHelper &Helper,
bool print_edges,
6187 OS.changeColor(raw_ostream::YELLOW,
true);
6192 OS <<
" (ENTRY)]\n";
6193 else if (&B == &cfg->
getExit())
6196 OS <<
" (INDIRECT GOTO DISPATCH)]\n";
6198 OS <<
" (NORETURN)]\n";
6214 if (
const Expr *LHS =
C->getLHS())
6216 if (
const Expr *RHS =
C->getRHS()) {
6231 if (
const VarDecl *PD = CS->getCatchParamDecl())
6242 llvm_unreachable(
"Invalid label statement in CFGBlock.");
6251 I != E ; ++I, ++j ) {
6256 OS << llvm::format(
"%3d", j) <<
": ";
6258 Helper.setStmtID(j);
6266 OS.changeColor(raw_ostream::GREEN);
6270 Helper.setBlockID(-1);
6273 CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
6284 const raw_ostream::Colors Color = raw_ostream::BLUE;
6286 OS.changeColor(Color);
6294 OS.changeColor(Color);
6302 bool Reachable =
true;
6305 B = I->getPossiblyUnreachableBlock();
6310 OS <<
"(Unreachable)";
6321 const raw_ostream::Colors Color = raw_ostream::MAGENTA;
6323 OS.changeColor(Color);
6331 OS.changeColor(Color);
6340 bool Reachable =
true;
6343 B = I->getPossiblyUnreachableBlock();
6349 OS <<
"(Unreachable)";
6365 print(llvm::errs(), LO, ShowColors);
6370 StmtPrinterHelper Helper(
this, LO);
6376 for (
const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
6381 print_block(OS,
this, **I, Helper,
true, ShowColors);
6396 bool ShowColors)
const {
6397 print(llvm::errs(), cfg, LO, ShowColors);
6408 StmtPrinterHelper Helper(cfg, LO);
6409 print_block(OS, cfg, *
this, Helper,
true, ShowColors);
6416 CFGBlockTerminatorPrint TPrinter(OS,
nullptr,
PrintingPolicy(LO));
6422 bool AddQuotes)
const {
6424 llvm::raw_string_ostream TempOut(Buf);
6447 if (llvm::any_of(*Blk, [](
const CFGElement &Elm) {
6448 if (std::optional<CFGStmt> StmtElm = Elm.
getAs<
CFGStmt>())
6468 DFSWorkList.push_back(StartBlk);
6469 while (!DFSWorkList.empty()) {
6470 const CFGBlock *Blk = DFSWorkList.pop_back_val();
6471 Visited.insert(Blk);
6480 for (
const auto &Succ : Blk->
succs()) {
6481 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
6485 DFSWorkList.push_back(SuccBlk);
6514 const Stmt *
Cond = StmtElem->getStmt();
6528 const Expr *E =
nullptr;
6534 case Stmt::CXXForRangeStmtClass:
6538 case Stmt::ForStmtClass:
6542 case Stmt::WhileStmtClass:
6546 case Stmt::DoStmtClass:
6550 case Stmt::IfStmtClass:
6554 case Stmt::ChooseExprClass:
6558 case Stmt::IndirectGotoStmtClass:
6562 case Stmt::SwitchStmtClass:
6566 case Stmt::BinaryConditionalOperatorClass:
6570 case Stmt::ConditionalOperatorClass:
6574 case Stmt::BinaryOperatorClass:
6578 case Stmt::ObjCForCollectionStmtClass:
6595 StmtPrinterHelper H(
this, LO);
6597 llvm::ViewGraph(
this,
"CFG");
6609 llvm::raw_string_ostream Out(OutStr);
6612 if (OutStr[0] ==
'\n') OutStr.erase(OutStr.begin());
6615 for (
unsigned i = 0; i != OutStr.length(); ++i)
6616 if (OutStr[i] ==
'\n') {
6618 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.
Result
Implement __builtin_bit_cast and related operations.
static void print(llvm::raw_ostream &OS, const T &V, const Context &Ctx, 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...
BumpVector< const MaterializeTemporaryExpr * > MTEVecTy
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
static bool isAssignmentOp(OverloadedOperatorKind Opc)
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.
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...
unsigned capture_size() const
Determine the number of captures in this lambda.
llvm::iterator_range< capture_init_iterator > capture_inits()
Retrieve the initialization expressions for this lambda's captures.
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
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
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',...
@ Default
Set to the current date and time.
@ SD_FullExpression
Full-expression storage duration (for temporaries).
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)