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(
bool AnalyzerOnly =
false);
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);
1818CFGBlock *CFGBuilder::createNoReturnBlock(
bool AnalyzerOnly) {
1819 CFGBlock *B = createBlock(
false);
1821 addSuccessor(B, &cfg->getExit(), Succ);
1826CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
1830 bool HasTemporaries =
false;
1836 Expr *ActualInit =
Init;
1838 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(
Init))
1839 ActualInit = DIE->getExpr();
1843 if (HasTemporaries &&
1846 TempDtorContext Context;
1848 VisitForTemporaries(FullExprWithCleanups->getSubExpr(),
1851 addFullExprCleanupMarker(Context, FullExprWithCleanups);
1856 appendInitializer(
Block, I);
1862 dyn_cast<ArrayInitLoopExpr>(
Init));
1864 findConstructionContexts(
1866 AILEInit ? AILEInit :
Init);
1869 if (CXXDefaultInitExpr *
Default = dyn_cast<CXXDefaultInitExpr>(
Init)) {
1875 if (Stmt *Child =
Default->getExpr()) {
1878 if (CFGBlock *R = Visit(Child))
1885 if (HasTemporaries) {
1899 bool *FoundMTE =
nullptr) {
1906 Init = EWC->getSubExpr();
1912 = dyn_cast<MaterializeTemporaryExpr>(
Init)) {
1913 Init = MTE->getSubExpr();
1920 const Expr *SkippedInit =
Init->skipRValueSubobjectAdjustments();
1921 if (SkippedInit !=
Init) {
1929 return Init->getType();
1934void CFGBuilder::addLoopExit(
const Stmt *LoopStmt){
1938 appendLoopExit(
Block, LoopStmt);
1946void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
1947 LocalScope::const_iterator E,
1957 if (B.inSameLocalScope(E)) {
1958 addAutomaticObjDestruction(B, E, S);
1963 SmallVector<LocalScope::const_iterator, 10> LocalScopeEndMarkers;
1964 LocalScopeEndMarkers.push_back(B);
1965 for (LocalScope::const_iterator I = B; I != E; ++I) {
1966 if (!I.inSameLocalScope(LocalScopeEndMarkers.back()))
1967 LocalScopeEndMarkers.push_back(I);
1969 LocalScopeEndMarkers.push_back(E);
1973 std::reverse(LocalScopeEndMarkers.begin(), LocalScopeEndMarkers.end());
1975 llvm::zip(LocalScopeEndMarkers, llvm::drop_begin(LocalScopeEndMarkers));
1976 for (
auto [E, B] : Pairwise) {
1977 if (!B.inSameLocalScope(E))
1978 addScopeExitHandling(B, E, S);
1979 addAutomaticObjDestruction(B, E, S);
1986void CFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
1987 LocalScope::const_iterator E,
1995 SmallVector<VarDecl *, 10> DeclsNeedDestruction;
1996 DeclsNeedDestruction.reserve(B.distance(E));
1998 for (VarDecl* D : llvm::make_range(B, E))
1999 if (needsAutomaticDestruction(D))
2000 DeclsNeedDestruction.push_back(D);
2002 for (VarDecl *VD : llvm::reverse(DeclsNeedDestruction)) {
2015 Block = createNoReturnBlock();
2024 appendLifetimeEnds(
Block, VD, S);
2026 appendAutomaticObjDtor(
Block, VD, S);
2027 if (VD->
hasAttr<CleanupAttr>())
2028 appendCleanupFunction(
Block, VD);
2037void CFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
2038 LocalScope::const_iterator E, Stmt *S) {
2039 assert(!B.inSameLocalScope(E));
2045 appendScopeEnd(
Block, B.getFirstVarInScope(), S);
2052 SmallVector<VarDecl *, 10> DeclsTrivial;
2053 DeclsTrivial.reserve(B.distance(E));
2058 for (VarDecl* D : llvm::make_range(B, E))
2059 if (!needsAutomaticDestruction(D))
2060 DeclsTrivial.push_back(D);
2062 if (DeclsTrivial.empty())
2066 for (VarDecl *VD : llvm::reverse(DeclsTrivial))
2067 appendLifetimeEnds(
Block, VD, S);
2075void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
2076 LocalScope::const_iterator DstPos,
2078 assert(
Block &&
"Source block should be always crated");
2084 if (SrcPos == DstPos)
2089 LocalScope::const_iterator BasePos = SrcPos.shared_parent(DstPos);
2092 if (BuildOpts.
AddScopes && !DstPos.inSameLocalScope(BasePos)) {
2093 for (LocalScope::const_iterator I = DstPos; I != BasePos; ++I)
2094 if (I.pointsToFirstDeclaredVar())
2095 appendScopeBegin(
Block, *I, S);
2100 addAutomaticObjHandling(SrcPos, BasePos, S);
2103void CFGBuilder::addFullExprCleanupMarker(TempDtorContext &Context,
2104 const ExprWithCleanups *CleanupExpr) {
2106 BumpVectorContext &BVC = cfg->getBumpVectorContext();
2108 size_t NumCollected = Context.CollectedMTEs.size();
2109 if (NumCollected > 0) {
2111 ExpiringMTEs =
new (cfg->getAllocator())
2113 for (
const MaterializeTemporaryExpr *MTE : Context.CollectedMTEs)
2115 Block->appendFullExprCleanup(ExpiringMTEs, CleanupExpr, BVC);
2124CFGBlock *CFGBuilder::createScopeChangesHandlingBlock(
2125 LocalScope::const_iterator SrcPos, CFGBlock *SrcBlk,
2126 LocalScope::const_iterator DstPos, CFGBlock *DstBlk) {
2127 if (SrcPos == DstPos)
2131 (!BuildOpts.
AddScopes || SrcPos.inSameLocalScope(DstPos)))
2136 SaveAndRestore save_Block(
Block), save_Succ(Succ);
2139 Block = createBlock(
false);
2142 addSuccessor(
Block, DstBlk);
2145 addScopeChangesHandling(SrcPos, DstPos,
Block->getTerminatorStmt());
2147 assert(
Block &&
"There should be at least one scope changing Block");
2153void CFGBuilder::addImplicitDtorsForDestructor(
const CXXDestructorDecl *DD) {
2155 "Can be called only when dtors should be added");
2156 const CXXRecordDecl *RD = DD->
getParent();
2159 for (
const auto &VI : RD->
vbases()) {
2163 const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
2166 appendBaseDtor(
Block, &VI);
2171 for (
const auto &BI : RD->
bases()) {
2172 if (!BI.isVirtual()) {
2173 const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
2176 appendBaseDtor(
Block, &BI);
2184 for (
auto *FI : RD->
fields()) {
2186 QualType QT = FI->getType();
2189 if (AT->isZeroSize())
2191 QT = AT->getElementType();
2197 appendMemberDtor(
Block, FI);
2204LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) {
2207 llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
2208 return new (alloc) LocalScope(BumpVectorContext(alloc), ScopePos);
2213void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
2218 LocalScope *Scope =
nullptr;
2222 for (
auto *BI : CS->body()) {
2223 Stmt *SI = BI->stripLabelLikeStatements();
2224 if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
2225 Scope = addLocalScopeForDeclStmt(DS, Scope);
2233 addLocalScopeForDeclStmt(DS);
2238LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
2239 LocalScope* Scope) {
2244 for (
auto *DI : DS->
decls())
2245 if (VarDecl *VD = dyn_cast<VarDecl>(DI))
2246 Scope = addLocalScopeForVarDecl(VD, Scope);
2250bool CFGBuilder::needsAutomaticDestruction(
const VarDecl *VD)
const {
2251 return !hasTrivialDestructor(VD) || VD->
hasAttr<CleanupAttr>();
2254bool CFGBuilder::hasTrivialDestructor(
const VarDecl *VD)
const {
2275 bool FoundMTE =
false;
2283 if (AT->isZeroSize())
2285 QT = AT->getElementType();
2297LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD,
2298 LocalScope* Scope) {
2313 !needsAutomaticDestruction(VD)) {
2319 Scope = createOrReuseLocalScope(Scope);
2321 ScopePos = Scope->begin();
2327void CFGBuilder::addLocalScopeAndDtors(Stmt *S) {
2328 LocalScope::const_iterator scopeBeginPos = ScopePos;
2329 addLocalScopeForStmt(S);
2330 addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
2336CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
2337 bool ExternallyDestructed) {
2343 if (Expr *E = dyn_cast<Expr>(S))
2344 S = E->IgnoreParens();
2347 if (
auto *D = dyn_cast<OMPExecutableDirective>(S))
2348 return VisitOMPExecutableDirective(D, asc);
2352 return VisitStmt(S, asc);
2354 case Stmt::ImplicitValueInitExprClass:
2357 return VisitStmt(S, asc);
2359 case Stmt::InitListExprClass:
2362 case Stmt::AttributedStmtClass:
2365 case Stmt::AddrLabelExprClass:
2368 case Stmt::BinaryConditionalOperatorClass:
2371 case Stmt::BinaryOperatorClass:
2372 case Stmt::CompoundAssignOperatorClass:
2375 case Stmt::BlockExprClass:
2378 case Stmt::BreakStmtClass:
2381 case Stmt::CallExprClass:
2382 case Stmt::CXXOperatorCallExprClass:
2383 case Stmt::CXXMemberCallExprClass:
2384 case Stmt::UserDefinedLiteralClass:
2387 case Stmt::CaseStmtClass:
2390 case Stmt::ChooseExprClass:
2393 case Stmt::CompoundStmtClass:
2396 case Stmt::ConditionalOperatorClass:
2399 case Stmt::ContinueStmtClass:
2402 case Stmt::CXXCatchStmtClass:
2405 case Stmt::ExprWithCleanupsClass:
2407 asc, ExternallyDestructed);
2409 case Stmt::CXXDefaultArgExprClass:
2410 case Stmt::CXXDefaultInitExprClass:
2419 return VisitStmt(S, asc);
2421 case Stmt::CXXBindTemporaryExprClass:
2424 case Stmt::CXXConstructExprClass:
2427 case Stmt::CXXNewExprClass:
2430 case Stmt::CXXDeleteExprClass:
2433 case Stmt::CXXFunctionalCastExprClass:
2436 case Stmt::CXXTemporaryObjectExprClass:
2439 case Stmt::CXXThrowExprClass:
2442 case Stmt::CXXTryStmtClass:
2445 case Stmt::CXXTypeidExprClass:
2448 case Stmt::CXXForRangeStmtClass:
2451 case Stmt::DeclStmtClass:
2454 case Stmt::DefaultStmtClass:
2457 case Stmt::DoStmtClass:
2460 case Stmt::ForStmtClass:
2463 case Stmt::GotoStmtClass:
2466 case Stmt::GCCAsmStmtClass:
2469 case Stmt::IfStmtClass:
2472 case Stmt::ImplicitCastExprClass:
2475 case Stmt::ConstantExprClass:
2478 case Stmt::IndirectGotoStmtClass:
2481 case Stmt::LabelStmtClass:
2484 case Stmt::LambdaExprClass:
2487 case Stmt::MaterializeTemporaryExprClass:
2491 case Stmt::MemberExprClass:
2494 case Stmt::NullStmtClass:
2497 case Stmt::ObjCAtCatchStmtClass:
2500 case Stmt::ObjCAutoreleasePoolStmtClass:
2503 case Stmt::ObjCAtSynchronizedStmtClass:
2506 case Stmt::ObjCAtThrowStmtClass:
2509 case Stmt::ObjCAtTryStmtClass:
2512 case Stmt::ObjCForCollectionStmtClass:
2515 case Stmt::ObjCMessageExprClass:
2518 case Stmt::OpaqueValueExprClass:
2521 case Stmt::PseudoObjectExprClass:
2524 case Stmt::ReturnStmtClass:
2525 case Stmt::CoreturnStmtClass:
2526 return VisitReturnStmt(S);
2528 case Stmt::CoyieldExprClass:
2529 case Stmt::CoawaitExprClass:
2532 case Stmt::SEHExceptStmtClass:
2535 case Stmt::SEHFinallyStmtClass:
2538 case Stmt::SEHLeaveStmtClass:
2541 case Stmt::SEHTryStmtClass:
2544 case Stmt::UnaryExprOrTypeTraitExprClass:
2548 case Stmt::StmtExprClass:
2551 case Stmt::SwitchStmtClass:
2554 case Stmt::UnaryOperatorClass:
2557 case Stmt::WhileStmtClass:
2560 case Stmt::ArrayInitLoopExprClass:
2565CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
2566 if (asc.alwaysAdd(*
this, S)) {
2568 appendStmt(
Block, S);
2571 return VisitChildren(S);
2575CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
2576 CFGBlock *B =
Block;
2580 reverse_children RChildren(S, *Context);
2581 for (Stmt *Child : RChildren) {
2583 if (CFGBlock *R = Visit(Child))
2589CFGBlock *CFGBuilder::VisitCallExprChildren(CallExpr *
C) {
2593 if (
auto *OCE = dyn_cast<CXXOperatorCallExpr>(
C);
2594 OCE && OCE->isAssignmentOp()) {
2595 Visit(OCE->getArg(0));
2596 Visit(OCE->getArg(1));
2597 return Visit(OCE->getCallee());
2599 return VisitChildren(
C);
2602CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) {
2603 if (asc.alwaysAdd(*
this, ILE)) {
2605 appendStmt(
Block, ILE);
2607 CFGBlock *B =
Block;
2609 reverse_children RChildren(ILE, *Context);
2610 for (Stmt *Child : RChildren) {
2613 if (CFGBlock *R = Visit(Child))
2616 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(Child))
2617 if (Stmt *Child = DIE->getExpr())
2618 if (CFGBlock *R = Visit(Child))
2625CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
2626 AddStmtChoice asc) {
2627 AddressTakenLabels.insert(A->
getLabel());
2629 if (asc.alwaysAdd(*
this, A)) {
2631 appendStmt(
Block, A);
2640 "expected fallthrough not to have children");
2641 return isFallthrough;
2648 "expected [[assume]] not to have children");
2649 return hasAssumeAttr;
2652CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
2653 AddStmtChoice asc) {
2663 if (isInterestingAttribute && asc.alwaysAdd(*
this, A)) {
2665 appendStmt(
Block, A);
2668 return VisitChildren(A);
2671CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc) {
2672 if (asc.alwaysAdd(*
this, U)) {
2674 appendStmt(
Block, U);
2680 return Visit(U->
getSubExpr(), AddStmtChoice());
2683CFGBlock *CFGBuilder::VisitLogicalOperator(BinaryOperator *B) {
2684 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2685 appendStmt(ConfluenceBlock, B);
2690 return VisitLogicalOperator(B,
nullptr, ConfluenceBlock,
2691 ConfluenceBlock).first;
2694std::pair<CFGBlock*, CFGBlock*>
2695CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
2697 CFGBlock *TrueBlock,
2698 CFGBlock *FalseBlock) {
2703 CFGBlock *RHSBlock, *ExitBlock;
2706 if (BinaryOperator *B_RHS = dyn_cast<BinaryOperator>(RHS))
2707 if (B_RHS->isLogicalOp()) {
2708 std::tie(RHSBlock, ExitBlock) =
2709 VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
2717 ExitBlock = RHSBlock = createBlock(
false);
2722 TryResult KnownVal = tryEvaluateBool(RHS);
2723 if (!KnownVal.isKnown())
2724 KnownVal = tryEvaluateBool(B);
2727 assert(TrueBlock == FalseBlock);
2728 addSuccessor(RHSBlock, TrueBlock);
2732 addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
2733 addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
2737 RHSBlock = addStmt(RHS);
2742 return std::make_pair(
nullptr,
nullptr);
2747 if (BinaryOperator *B_LHS = dyn_cast<BinaryOperator>(LHS))
2748 if (B_LHS->isLogicalOp()) {
2750 FalseBlock = RHSBlock;
2752 TrueBlock = RHSBlock;
2757 return VisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock);
2762 CFGBlock *LHSBlock = createBlock(
false);
2766 CFGBlock *EntryLHSBlock = addStmt(LHS);
2769 return std::make_pair(
nullptr,
nullptr);
2772 TryResult KnownVal = tryEvaluateBool(LHS);
2776 addSuccessor(LHSBlock, TrueBlock, !KnownVal.isFalse());
2777 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isTrue());
2780 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isFalse());
2781 addSuccessor(LHSBlock, FalseBlock, !KnownVal.isTrue());
2784 return std::make_pair(EntryLHSBlock, ExitBlock);
2787CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
2788 AddStmtChoice asc) {
2791 return VisitLogicalOperator(B);
2795 appendStmt(
Block, B);
2797 return addStmt(B->
getLHS());
2801 if (asc.alwaysAdd(*
this, B)) {
2803 appendStmt(
Block, B);
2806 return Visit(B->
getRHS());
2809 if (asc.alwaysAdd(*
this, B)) {
2811 appendStmt(
Block, B);
2817 CFGBlock *RBlock = Visit(B->
getRHS());
2818 CFGBlock *LBlock = Visit(B->
getLHS());
2822 return (LBlock ? LBlock : RBlock);
2825CFGBlock *CFGBuilder::VisitNoRecurse(Expr *E, AddStmtChoice asc) {
2826 if (asc.alwaysAdd(*
this, E)) {
2828 appendStmt(
Block, E);
2833CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
2840 Block = createBlock(
false);
2841 Block->setTerminator(B);
2845 if (BreakJumpTarget.block) {
2846 addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
2847 addSuccessor(
Block, BreakJumpTarget.block);
2872 if (BuiltinID != Builtin::BI__assume &&
2873 BuiltinID != Builtin::BI__builtin_assume)
2879CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *
C, AddStmtChoice asc) {
2881 QualType calleeType =
C->getCallee()->getType();
2887 if (!boundType.
isNull()) calleeType = boundType;
2892 bool AnalyzerNoReturn =
false;
2894 bool AddEHEdge =
false;
2904 bool OmitArguments =
false;
2906 if (FunctionDecl *FD =
C->getDirectCallee()) {
2911 if (!FD->isVariadic())
2912 findConstructionContextsForArguments(
C);
2914 if (FD->isNoReturn() ||
C->isBuiltinAssumeFalse(*Context))
2916 else if (FD->isAnalyzerNoReturn())
2917 AnalyzerNoReturn =
true;
2918 if (FD->
hasAttr<NoThrowAttr>())
2921 FD->getBuiltinID() == Builtin::BI__builtin_object_size ||
2922 FD->getBuiltinID() == Builtin::BI__builtin_dynamic_object_size)
2923 OmitArguments =
true;
2926 if (!
CanThrow(
C->getCallee(), *Context))
2929 if (OmitArguments) {
2930 assert(!NoReturn && !AnalyzerNoReturn &&
2931 "noreturn calls with unevaluated args not implemented");
2932 assert(!AddEHEdge &&
"EH calls with unevaluated args not implemented");
2935 return Visit(
C->getCallee());
2938 if (!NoReturn && !AnalyzerNoReturn && !AddEHEdge) {
2942 return VisitCallExprChildren(
C);
2952 Block = createNoReturnBlock(
false);
2953 else if (AnalyzerNoReturn)
2954 Block = createNoReturnBlock(
true);
2956 Block = createBlock();
2962 if (TryTerminatedBlock)
2963 addSuccessor(
Block, TryTerminatedBlock);
2965 addSuccessor(
Block, &cfg->getExit());
2968 return VisitCallExprChildren(
C);
2971CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *
C,
2972 AddStmtChoice asc) {
2973 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
2974 appendStmt(ConfluenceBlock,
C);
2978 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2979 Succ = ConfluenceBlock;
2981 CFGBlock *LHSBlock = Visit(
C->getLHS(), alwaysAdd);
2985 Succ = ConfluenceBlock;
2987 CFGBlock *RHSBlock = Visit(
C->getRHS(), alwaysAdd);
2991 Block = createBlock(
false);
2993 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2994 addSuccessor(
Block, KnownVal.isFalse() ?
nullptr : LHSBlock);
2995 addSuccessor(
Block, KnownVal.isTrue() ?
nullptr : RHSBlock);
2997 return addStmt(
C->getCond());
3001 bool ExternallyDestructed) {
3002 LocalScope::const_iterator scopeBeginPos = ScopePos;
3003 addLocalScopeForStmt(
C);
3008 addAutomaticObjHandling(ScopePos, scopeBeginPos,
C);
3011 CFGBlock *LastBlock =
Block;
3013 for (Stmt *S : llvm::reverse(
C->body())) {
3016 CFGBlock *newBlock = Visit(S, AddStmtChoice::AlwaysAdd,
3017 ExternallyDestructed);
3020 LastBlock = newBlock;
3025 ExternallyDestructed =
false;
3031CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *
C,
3032 AddStmtChoice asc) {
3033 const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(
C);
3034 const OpaqueValueExpr *opaqueValue = (BCO ? BCO->
getOpaqueValue() :
nullptr);
3038 CFGBlock *ConfluenceBlock =
Block ?
Block : createBlock();
3039 appendStmt(ConfluenceBlock,
C);
3043 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
3049 Succ = ConfluenceBlock;
3051 CFGBlock *LHSBlock =
nullptr;
3052 const Expr *trueExpr =
C->getTrueExpr();
3053 if (trueExpr != opaqueValue) {
3054 LHSBlock = Visit(
C->getTrueExpr(), alwaysAdd);
3060 LHSBlock = ConfluenceBlock;
3063 Succ = ConfluenceBlock;
3064 CFGBlock *RHSBlock = Visit(
C->getFalseExpr(), alwaysAdd);
3069 if (BinaryOperator *Cond =
3070 dyn_cast<BinaryOperator>(
C->getCond()->IgnoreParens()))
3071 if (Cond->isLogicalOp())
3072 return VisitLogicalOperator(Cond,
C, LHSBlock, RHSBlock).first;
3075 Block = createBlock(
false);
3078 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
3079 addSuccessor(
Block, LHSBlock, !KnownVal.isFalse());
3080 addSuccessor(
Block, RHSBlock, !KnownVal.isTrue());
3082 Expr *condExpr =
C->getCond();
3087 if (condExpr != opaqueValue)
3095 return addStmt(condExpr);
3098CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
3106 return VisitDeclSubExpr(DS);
3108 CFGBlock *B =
nullptr;
3117 DeclGroupRef DG(*I);
3120 cfg->addSyntheticDeclStmt(DSNew, DS);
3123 B = VisitDeclSubExpr(DSNew);
3131CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
3132 assert(DS->
isSingleDecl() &&
"Can handle single declarations only.");
3134 if (
const auto *TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl())) {
3136 const Type *
T = TND->getUnderlyingType().getTypePtr();
3141 appendStmt(
Block, DS);
3143 CFGBlock *LastBlock =
Block;
3144 for (
const VariableArrayType *VA =
FindVA(
T); VA !=
nullptr;
3145 VA =
FindVA(VA->getElementType().getTypePtr())) {
3146 if (CFGBlock *NewBlock = addStmt(VA->getSizeExpr()))
3147 LastBlock = NewBlock;
3160 bool HasTemporaries =
false;
3163 CFGBlock *blockAfterStaticInit =
nullptr;
3174 blockAfterStaticInit = Succ;
3183 if (HasTemporaries &&
3186 TempDtorContext Context;
3188 VisitForTemporaries(FullExprWithCleanups->getSubExpr(),
3191 addFullExprCleanupMarker(Context, FullExprWithCleanups);
3197 if (
const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
3198 for (
auto *BD : llvm::reverse(DD->bindings())) {
3199 if (
auto *VD = BD->getHoldingVar()) {
3200 DeclGroupRef DG(VD);
3203 cfg->addSyntheticDeclStmt(DSNew, DS);
3204 Block = VisitDeclSubExpr(DSNew);
3210 appendStmt(
Block, DS);
3214 const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(
Init);
3216 findConstructionContexts(
3218 AILE ? AILE->getSubExpr() :
Init);
3223 CFGBlock *LastBlock =
Block;
3226 if (HasTemporaries) {
3230 if (CFGBlock *newBlock = Visit(EC->
getSubExpr()))
3231 LastBlock = newBlock;
3234 if (CFGBlock *newBlock = Visit(
Init))
3235 LastBlock = newBlock;
3243 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr())) {
3244 if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
3245 LastBlock = newBlock;
3248 maybeAddScopeBeginForVarDecl(
Block, VD, DS);
3251 if (ScopePos && VD == *ScopePos)
3254 CFGBlock *B = LastBlock;
3255 if (blockAfterStaticInit) {
3257 Block = createBlock(
false);
3258 Block->setTerminator(DS);
3259 addSuccessor(
Block, blockAfterStaticInit);
3260 addSuccessor(
Block, B);
3267CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
3277 SaveAndRestore save_scope_pos(ScopePos);
3281 addLocalScopeForStmt(
Init);
3286 addLocalScopeForVarDecl(VD);
3288 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
3299 CFGBlock *ElseBlock = Succ;
3301 if (Stmt *Else = I->
getElse()) {
3302 SaveAndRestore sv(Succ);
3311 addLocalScopeAndDtors(Else);
3313 ElseBlock = addStmt(Else);
3316 ElseBlock = sv.get();
3324 CFGBlock *ThenBlock;
3328 SaveAndRestore sv(Succ);
3334 addLocalScopeAndDtors(Then);
3336 ThenBlock = addStmt(Then);
3342 ThenBlock = createBlock(
false);
3343 addSuccessor(ThenBlock, sv.get());
3357 BinaryOperator *Cond =
3361 CFGBlock *LastBlock;
3363 LastBlock = VisitLogicalOperator(Cond, I, ThenBlock, ElseBlock).first;
3366 Block = createBlock(
false);
3369 Block->setTerminator(I);
3374 KnownVal = tryEvaluateBool(I->
getCond());
3378 addSuccessor(
Block, ThenBlock, !KnownVal.isFalse());
3379 addSuccessor(
Block, ElseBlock, !KnownVal.isTrue());
3387 LastBlock = addStmt(I->
getCond());
3393 LastBlock = addStmt(
const_cast<DeclStmt *
>(DS));
3400 LastBlock = addStmt(
Init);
3406CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {
3416 Block = createBlock(
false);
3418 addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), S);
3420 if (
auto *R = dyn_cast<ReturnStmt>(S))
3421 findConstructionContexts(
3427 if (!
Block->hasNoReturnElement())
3428 addSuccessor(
Block, &cfg->getExit());
3431 appendStmt(
Block, S);
3434 if (ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
3435 if (Expr *O = RS->getRetValue())
3436 return Visit(O, AddStmtChoice::AlwaysAdd,
true);
3443 if (CFGBlock *R = Visit(PromiseCall))
3449 if (CFGBlock *R = Visit(RV))
3455CFGBlock *CFGBuilder::VisitCoroutineSuspendExpr(CoroutineSuspendExpr *E,
3456 AddStmtChoice asc) {
3460 if (asc.alwaysAdd(*
this, E)) {
3462 appendStmt(
Block, E);
3464 CFGBlock *B =
Block;
3476CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
3482 SaveAndRestore save_scope_pos(ScopePos);
3485 CFGBlock *SEHExceptBlock =
Block;
3486 if (!SEHExceptBlock)
3487 SEHExceptBlock = createBlock();
3489 appendStmt(SEHExceptBlock, ES);
3501 return SEHExceptBlock;
3504CFGBlock *CFGBuilder::VisitSEHFinallyStmt(SEHFinallyStmt *FS) {
3505 return VisitCompoundStmt(FS->
getBlock(),
false);
3508CFGBlock *CFGBuilder::VisitSEHLeaveStmt(SEHLeaveStmt *LS) {
3515 Block = createBlock(
false);
3516 Block->setTerminator(LS);
3520 if (SEHLeaveJumpTarget.block) {
3521 addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS);
3522 addSuccessor(
Block, SEHLeaveJumpTarget.block);
3529CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) {
3532 CFGBlock *SEHTrySuccessor =
nullptr;
3537 SEHTrySuccessor =
Block;
3538 }
else SEHTrySuccessor = Succ;
3544 CFGBlock *PrevSEHTryTerminatedBlock = TryTerminatedBlock;
3547 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
3554 Succ = SEHTrySuccessor;
3556 CFGBlock *ExceptBlock = VisitSEHExceptStmt(Except);
3561 addSuccessor(NewTryTerminatedBlock, ExceptBlock);
3563 if (PrevSEHTryTerminatedBlock)
3564 addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock);
3566 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
3569 Succ = SEHTrySuccessor;
3572 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
3573 cfg->addTryDispatchBlock(TryTerminatedBlock);
3578 SaveAndRestore save_break(SEHLeaveJumpTarget);
3579 SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
3581 assert(Terminator->
getTryBlock() &&
"__try must contain a non-NULL body");
3586CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
3589 CFGBlock *LabelBlock =
Block;
3592 LabelBlock = createBlock();
3594 assert(!LabelMap.contains(L->
getDecl()) &&
"label already in map");
3595 LabelMap[L->
getDecl()] = JumpTarget(LabelBlock, ScopePos);
3614CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
3615 CFGBlock *LastBlock = VisitNoRecurse(E, asc);
3617 if (Expr *CopyExpr = CI.getCopyExpr()) {
3618 CFGBlock *Tmp = Visit(CopyExpr);
3626CFGBlock *CFGBuilder::VisitLambdaExpr(
LambdaExpr *E, AddStmtChoice asc) {
3627 CFGBlock *LastBlock = VisitNoRecurse(E, asc);
3638 dyn_cast<ArrayInitLoopExpr>(
Init));
3641 cfg->getBumpVectorContext(), {E, Idx}),
3642 AILEInit ? AILEInit :
Init);
3644 CFGBlock *Tmp = Visit(
Init);
3652CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
3656 Block = createBlock(
false);
3657 Block->setTerminator(G);
3660 LabelMapTy::iterator I = LabelMap.find(G->
getLabel());
3662 if (I == LabelMap.end())
3664 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3666 JumpTarget JT = I->second;
3667 addSuccessor(
Block, JT.block);
3668 addScopeChangesHandling(ScopePos, JT.scopePosition, G);
3674CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) {
3679 return VisitStmt(G, asc);
3686 Block = createBlock();
3687 Block->setTerminator(G);
3689 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3692 BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
3693 return VisitChildren(G);
3696CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
3697 CFGBlock *LoopSuccessor =
nullptr;
3701 SaveAndRestore save_scope_pos(ScopePos);
3707 addLocalScopeForStmt(
Init);
3708 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3711 addLocalScopeForVarDecl(VD);
3712 LocalScope::const_iterator ContinueScopePos = ScopePos;
3714 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
3723 LoopSuccessor =
Block;
3725 LoopSuccessor = Succ;
3729 SaveAndRestore save_break(BreakJumpTarget);
3730 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3732 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3739 SaveAndRestore save_Block(
Block), save_Succ(Succ);
3740 SaveAndRestore save_continue(ContinueJumpTarget);
3745 Block = Succ = TransitionBlock = createBlock(
false);
3746 TransitionBlock->setLoopTarget(F);
3751 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
3753 if (Stmt *I = F->
getInc()) {
3761 assert(
Block == Succ);
3769 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
3770 ContinueJumpTarget.block->setLoopTarget(F);
3776 addLocalScopeAndDtors(F->
getBody());
3780 BodyBlock = addStmt(F->
getBody());
3785 BodyBlock = ContinueJumpTarget.block;
3794 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3798 SaveAndRestore save_scope_pos(ScopePos);
3802 if (BinaryOperator *Cond =
3803 dyn_cast_or_null<BinaryOperator>(
C ?
C->IgnoreParens() :
nullptr))
3805 std::tie(EntryConditionBlock, ExitConditionBlock) =
3806 VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor);
3811 EntryConditionBlock = ExitConditionBlock = createBlock(
false);
3812 ExitConditionBlock->setTerminator(F);
3815 TryResult KnownVal(
true);
3821 Block = ExitConditionBlock;
3822 EntryConditionBlock = addStmt(
C);
3831 findConstructionContexts(
3834 appendStmt(
Block, DS);
3835 EntryConditionBlock = addStmt(
Init);
3836 assert(
Block == EntryConditionBlock);
3837 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3841 if (
Block && badCFG)
3844 KnownVal = tryEvaluateBool(
C);
3848 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
3851 addSuccessor(ExitConditionBlock,
3852 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
3856 addSuccessor(TransitionBlock, EntryConditionBlock);
3859 Succ = EntryConditionBlock;
3864 SaveAndRestore save_scope_pos(ScopePos);
3865 ScopePos = LoopBeginScopePos;
3866 Block = createBlock();
3873 Succ = EntryConditionBlock;
3874 return EntryConditionBlock;
3878CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
3879 AddStmtChoice asc) {
3880 findConstructionContexts(
3884 return VisitStmt(MTE, asc);
3887CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
3888 if (asc.alwaysAdd(*
this, M)) {
3890 appendStmt(
Block, M);
3895CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
3927 CFGBlock *LoopSuccessor =
nullptr;
3932 LoopSuccessor =
Block;
3935 LoopSuccessor = Succ;
3938 CFGBlock *ExitConditionBlock = createBlock(
false);
3946 appendStmt(ExitConditionBlock, S);
3947 Block = ExitConditionBlock;
3952 CFGBlock *EntryConditionBlock = Visit(S->
getElement(),
3953 AddStmtChoice::NotAlwaysAdd);
3962 Succ = EntryConditionBlock;
3967 SaveAndRestore save_Block(
Block), save_Succ(Succ);
3968 SaveAndRestore save_continue(ContinueJumpTarget),
3969 save_break(BreakJumpTarget);
3974 CFGBlock *LoopBackBlock =
nullptr;
3975 Succ = LoopBackBlock = createBlock();
3978 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3979 ContinueJumpTarget = JumpTarget(Succ, ScopePos);
3981 CFGBlock *BodyBlock = addStmt(S->
getBody());
3984 BodyBlock = ContinueJumpTarget.block;
3991 addSuccessor(ExitConditionBlock, BodyBlock);
3996 addSuccessor(ExitConditionBlock, LoopSuccessor);
3999 Block = createBlock();
4003CFGBlock *CFGBuilder::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
4009CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
4027 appendStmt(
Block, S);
4033CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
4037 appendStmt(
Block, E);
4039 CFGBlock *lastBlock =
Block;
4048 if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic))
4049 Semantic = OVE->getSourceExpr();
4051 if (CFGBlock *B = Visit(Semantic))
4058CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
4059 CFGBlock *LoopSuccessor =
nullptr;
4063 SaveAndRestore save_scope_pos(ScopePos);
4067 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
4069 addLocalScopeForVarDecl(VD);
4070 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4079 LoopSuccessor =
Block;
4082 LoopSuccessor = Succ;
4085 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
4092 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4093 SaveAndRestore save_continue(ContinueJumpTarget),
4094 save_break(BreakJumpTarget);
4098 Succ = TransitionBlock = createBlock(
false);
4099 TransitionBlock->setLoopTarget(W);
4100 ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
4103 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4106 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4111 addLocalScopeAndDtors(W->
getBody());
4114 BodyBlock = addStmt(W->
getBody());
4117 BodyBlock = ContinueJumpTarget.block;
4118 else if (
Block && badCFG)
4125 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
4132 if (BinaryOperator *Cond = dyn_cast<BinaryOperator>(
C->IgnoreParens()))
4134 std::tie(EntryConditionBlock, ExitConditionBlock) =
4135 VisitLogicalOperator(Cond, W, BodyBlock, LoopSuccessor);
4140 ExitConditionBlock = createBlock(
false);
4146 Block = ExitConditionBlock;
4147 Block = EntryConditionBlock = addStmt(
C);
4156 findConstructionContexts(
4158 const_cast<DeclStmt *
>(DS)),
4160 appendStmt(
Block, DS);
4161 EntryConditionBlock = addStmt(
Init);
4162 assert(
Block == EntryConditionBlock);
4163 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
4167 if (
Block && badCFG)
4171 const TryResult& KnownVal = tryEvaluateBool(
C);
4174 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
4177 addSuccessor(ExitConditionBlock,
4178 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4182 addSuccessor(TransitionBlock, EntryConditionBlock);
4189 Succ = EntryConditionBlock;
4190 return EntryConditionBlock;
4193CFGBlock *CFGBuilder::VisitArrayInitLoopExpr(ArrayInitLoopExpr *A,
4194 AddStmtChoice asc) {
4195 if (asc.alwaysAdd(*
this, A)) {
4197 appendStmt(
Block, A);
4200 CFGBlock *B =
Block;
4212CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *CS) {
4218 SaveAndRestore save_scope_pos(ScopePos);
4223 CFGBlock *CatchBlock =
Block;
4225 CatchBlock = createBlock();
4227 appendStmt(CatchBlock, CS);
4242CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
4248 Block = createBlock(
false);
4250 if (TryTerminatedBlock)
4252 addSuccessor(
Block, TryTerminatedBlock);
4255 addSuccessor(
Block, &cfg->getExit());
4259 return VisitStmt(S, AddStmtChoice::AlwaysAdd);
4262CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *Terminator) {
4265 CFGBlock *TrySuccessor =
nullptr;
4270 TrySuccessor =
Block;
4272 TrySuccessor = Succ;
4278 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4281 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4285 bool HasCatchAll =
false;
4286 for (ObjCAtCatchStmt *CS : Terminator->
catch_stmts()) {
4288 Succ = TrySuccessor;
4293 CFGBlock *CatchBlock = VisitObjCAtCatchStmt(CS);
4298 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4303 if (PrevTryTerminatedBlock)
4304 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4306 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4310 Succ = TrySuccessor;
4313 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4314 cfg->addTryDispatchBlock(TryTerminatedBlock);
4316 assert(Terminator->
getTryBody() &&
"try must contain a non-NULL body");
4321CFGBlock *CFGBuilder::VisitObjCMessageExpr(ObjCMessageExpr *ME,
4322 AddStmtChoice asc) {
4323 findConstructionContextsForArguments(ME);
4326 appendObjCMessage(
Block, ME);
4328 return VisitChildren(ME);
4331CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *
T) {
4337 Block = createBlock(
false);
4339 if (TryTerminatedBlock)
4341 addSuccessor(
Block, TryTerminatedBlock);
4344 addSuccessor(
Block, &cfg->getExit());
4348 return VisitStmt(
T, AddStmtChoice::AlwaysAdd);
4351CFGBlock *CFGBuilder::VisitCXXTypeidExpr(CXXTypeidExpr *S, AddStmtChoice asc) {
4352 if (asc.alwaysAdd(*
this, S)) {
4354 appendStmt(
Block, S);
4364 return VisitChildren(S);
4370CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
4371 CFGBlock *LoopSuccessor =
nullptr;
4380 LoopSuccessor =
Block;
4382 LoopSuccessor = Succ;
4387 CFGBlock *ExitConditionBlock = createBlock(
false);
4388 CFGBlock *EntryConditionBlock = ExitConditionBlock;
4396 Block = ExitConditionBlock;
4397 EntryConditionBlock = addStmt(
C);
4405 Succ = EntryConditionBlock;
4408 const TryResult &KnownVal = tryEvaluateBool(D->
getCond());
4411 CFGBlock *BodyBlock =
nullptr;
4416 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4417 SaveAndRestore save_continue(ContinueJumpTarget),
4418 save_break(BreakJumpTarget);
4421 ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
4424 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4432 addLocalScopeAndDtors(D->
getBody());
4435 BodyBlock = addStmt(D->
getBody());
4438 BodyBlock = EntryConditionBlock;
4451 CFGBlock *LoopBackBlock = createBlock();
4454 if (!KnownVal.isFalse())
4456 addSuccessor(ExitConditionBlock, LoopBackBlock);
4458 addSuccessor(ExitConditionBlock,
nullptr);
4463 addSuccessor(ExitConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4474CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *
C) {
4481 Block = createBlock(
false);
4486 if (ContinueJumpTarget.block) {
4487 addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition,
C);
4488 addSuccessor(
Block, ContinueJumpTarget.block);
4495CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
4496 AddStmtChoice asc) {
4497 if (asc.alwaysAdd(*
this, E)) {
4499 appendStmt(
Block, E);
4505 if (E->
getKind() != UETT_SizeOf)
4508 CFGBlock *lastBlock =
Block;
4512 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr()))
4513 lastBlock = addStmt(VA->getSizeExpr());
4520CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
4521 if (asc.alwaysAdd(*
this, SE)) {
4523 appendStmt(
Block, SE);
4525 return VisitCompoundStmt(SE->
getSubStmt(),
true);
4528CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
4531 CFGBlock *SwitchSuccessor =
nullptr;
4535 SaveAndRestore save_scope_pos(ScopePos);
4539 addLocalScopeForStmt(
Init);
4544 addLocalScopeForVarDecl(VD);
4546 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
4551 SwitchSuccessor =
Block;
4552 }
else SwitchSuccessor = Succ;
4555 SaveAndRestore save_switch(SwitchTerminatedBlock),
4556 save_default(DefaultCaseBlock);
4557 SaveAndRestore save_break(BreakJumpTarget);
4562 DefaultCaseBlock = SwitchSuccessor;
4565 SwitchTerminatedBlock = createBlock(
false);
4569 Succ = SwitchSuccessor;
4570 BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
4575 assert(Terminator->
getBody() &&
"switch must contain a non-NULL body");
4580 SaveAndRestore save_switchExclusivelyCovered(switchExclusivelyCovered,
false);
4583 assert(Terminator->
getCond() &&
"switch condition must be non-NULL");
4584 Expr::EvalResult result;
4585 bool b = tryEvaluate(Terminator->
getCond(), result);
4586 SaveAndRestore save_switchCond(switchCond, b ? &result :
nullptr);
4591 addLocalScopeAndDtors(Terminator->
getBody());
4593 addStmt(Terminator->
getBody());
4607 bool SwitchAlwaysHasSuccessor =
false;
4608 SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
4609 SwitchAlwaysHasSuccessor |=
4612 addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock,
4613 !SwitchAlwaysHasSuccessor);
4617 Block = SwitchTerminatedBlock;
4618 CFGBlock *LastBlock = addStmt(Terminator->
getCond());
4626 LastBlock = addStmt(
Init);
4627 maybeAddScopeBeginForVarDecl(LastBlock, VD,
Init);
4634 LastBlock = addStmt(
Init);
4647 bool addCase =
false;
4649 if (!switchExclusivelyCovered) {
4653 const llvm::APSInt &condInt = switchCond->
Val.
getInt();
4655 if (condInt == lhsInt) {
4657 switchExclusivelyCovered =
true;
4659 else if (condInt > lhsInt) {
4663 if (V2 >= condInt) {
4665 switchExclusivelyCovered =
true;
4676CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
4679 CFGBlock *TopBlock =
nullptr, *LastBlock =
nullptr;
4686 CFGBlock *currentBlock = createBlock(
false);
4690 addSuccessor(LastBlock, currentBlock);
4692 TopBlock = currentBlock;
4694 addSuccessor(SwitchTerminatedBlock,
4697 ? currentBlock :
nullptr);
4699 LastBlock = currentBlock;
4707 CFGBlock *CaseBlock =
Block;
4709 CaseBlock = createBlock();
4720 assert(SwitchTerminatedBlock);
4721 addSuccessor(SwitchTerminatedBlock, CaseBlock,
4729 addSuccessor(LastBlock, CaseBlock);
4739CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {
4743 DefaultCaseBlock =
Block;
4745 if (!DefaultCaseBlock)
4746 DefaultCaseBlock = createBlock();
4750 DefaultCaseBlock->
setLabel(Terminator);
4765 Succ = DefaultCaseBlock;
4767 return DefaultCaseBlock;
4770CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
4773 CFGBlock *TrySuccessor =
nullptr;
4778 TrySuccessor =
Block;
4780 TrySuccessor = Succ;
4782 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4785 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4789 bool HasCatchAll =
false;
4790 for (
unsigned I = 0, E = Terminator->
getNumHandlers(); I != E; ++I) {
4792 Succ = TrySuccessor;
4793 CXXCatchStmt *CS = Terminator->
getHandler(I);
4798 CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
4803 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4806 if (PrevTryTerminatedBlock)
4807 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4809 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4813 Succ = TrySuccessor;
4816 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4817 cfg->addTryDispatchBlock(TryTerminatedBlock);
4819 assert(Terminator->
getTryBlock() &&
"try must contain a non-NULL body");
4824CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
4830 SaveAndRestore save_scope_pos(ScopePos);
4835 LocalScope::const_iterator BeginScopePos = ScopePos;
4836 addLocalScopeForVarDecl(VD);
4837 addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
4843 CFGBlock *CatchBlock =
Block;
4845 CatchBlock = createBlock();
4851 appendStmt(CatchBlock, CS);
4867CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
4882 SaveAndRestore save_scope_pos(ScopePos);
4887 addLocalScopeForStmt(
Init);
4889 addLocalScopeForStmt(Range);
4891 addLocalScopeForStmt(Begin);
4893 addLocalScopeForStmt(End);
4894 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
4896 LocalScope::const_iterator ContinueScopePos = ScopePos;
4900 CFGBlock *LoopSuccessor =
nullptr;
4904 LoopSuccessor =
Block;
4906 LoopSuccessor = Succ;
4910 SaveAndRestore save_break(BreakJumpTarget);
4911 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4914 CFGBlock *ConditionBlock = createBlock(
false);
4919 Block = ConditionBlock;
4920 CFGBlock *BeginConditionBlock = addStmt(
C);
4923 assert(BeginConditionBlock == ConditionBlock &&
4924 "condition block in for-range was unexpectedly complex");
4925 (void)BeginConditionBlock;
4930 Succ = ConditionBlock;
4933 TryResult KnownVal(
true);
4936 KnownVal = tryEvaluateBool(S->
getCond());
4943 SaveAndRestore save_Block(
Block), save_Succ(Succ);
4944 SaveAndRestore save_continue(ContinueJumpTarget);
4949 Succ = addStmt(S->
getInc());
4952 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
4956 ContinueJumpTarget.block->setLoopTarget(S);
4970 addLocalScopeAndDtors(S->
getBody());
4982 addSuccessor(ConditionBlock,
4983 KnownVal.isFalse() ?
nullptr : LoopVarStmtBlock);
4988 addSuccessor(ConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4992 Block = createBlock();
5001CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
5003 bool ExternallyDestructed) {
5007 TempDtorContext Context;
5009 VisitForTemporaries(FullExpr, ExternallyDestructed, Context);
5011 addFullExprCleanupMarker(Context, E);
5015 asc = asc.withAlwaysAdd(
true);
5020CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
5021 AddStmtChoice asc) {
5022 if (asc.alwaysAdd(*
this, E)) {
5024 appendStmt(
Block, E);
5026 findConstructionContexts(
5031 asc = asc.withAlwaysAdd(
false);
5036CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *
C,
5037 AddStmtChoice asc) {
5041 findConstructionContextsForArguments(
C);
5042 appendConstructor(
C);
5044 return VisitChildren(
C);
5047CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
5048 AddStmtChoice asc) {
5050 appendStmt(
Block, NE);
5052 findConstructionContexts(
5054 const_cast<CXXConstructExpr *
>(
NE->getConstructExpr()));
5056 if (
NE->getInitializer())
5057 Block = Visit(
NE->getInitializer());
5060 appendNewAllocator(
Block, NE);
5062 if (
NE->isArray() && *
NE->getArraySize())
5063 Block = Visit(*
NE->getArraySize());
5066 E =
NE->placement_arg_end(); I != E; ++I)
5072CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
5073 AddStmtChoice asc) {
5075 appendStmt(
Block, DE);
5082 appendDeleteDtor(
Block, RD, DE);
5086 return VisitChildren(DE);
5089CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
5090 AddStmtChoice asc) {
5091 if (asc.alwaysAdd(*
this, E)) {
5093 appendStmt(
Block, E);
5095 asc = asc.withAlwaysAdd(
false);
5100CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E,
5101 AddStmtChoice asc) {
5105 findConstructionContextsForArguments(E);
5106 appendConstructor(E);
5108 return VisitChildren(E);
5111CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
5112 AddStmtChoice asc) {
5113 if (asc.alwaysAdd(*
this, E)) {
5115 appendStmt(
Block, E);
5121 return Visit(E->
getSubExpr(), AddStmtChoice());
5124CFGBlock *CFGBuilder::VisitConstantExpr(ConstantExpr *E, AddStmtChoice asc) {
5125 return Visit(E->
getSubExpr(), AddStmtChoice());
5128CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
5130 CFGBlock *IBlock = cfg->getIndirectGotoBlock();
5133 IBlock = createBlock(
false);
5134 cfg->setIndirectGotoBlock(IBlock);
5142 Block = createBlock(
false);
5143 Block->setTerminator(I);
5144 addSuccessor(
Block, IBlock);
5148CFGBlock *CFGBuilder::VisitForTemporaries(Stmt *E,
bool ExternallyDestructed,
5149 TempDtorContext &Context) {
5158 return VisitChildrenForTemporaries(E,
false, Context);
5160 case Stmt::InitListExprClass:
5161 return VisitChildrenForTemporaries(E, ExternallyDestructed, Context);
5163 case Stmt::BinaryOperatorClass:
5164 case Stmt::CompoundAssignOperatorClass:
5166 ExternallyDestructed, Context);
5168 case Stmt::CXXOperatorCallExprClass:
5169 return VisitCXXOperatorCallExprForTemporaryDtors(
5172 case Stmt::CXXBindTemporaryExprClass:
5173 return VisitCXXBindTemporaryExprForTemporaryDtors(
5176 case Stmt::BinaryConditionalOperatorClass:
5177 case Stmt::ConditionalOperatorClass:
5178 return VisitConditionalOperatorForTemporaries(
5181 case Stmt::ImplicitCastExprClass:
5186 case Stmt::CXXFunctionalCastExprClass:
5191 case Stmt::ConstantExprClass:
5195 case Stmt::ParenExprClass:
5199 case Stmt::MaterializeTemporaryExprClass: {
5202 if (BuildOpts.
AddLifetime && !ExternallyDestructed)
5204 SmallVector<const Expr *, 2> CommaLHSs;
5205 SmallVector<SubobjectAdjustment, 2> Adjustments;
5207 E =
const_cast<Expr *
>(
5210 ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
5212 for (
const Expr *CommaLHS : CommaLHSs) {
5213 VisitForTemporaries(
const_cast<Expr *
>(CommaLHS),
5219 case Stmt::BlockExprClass:
5224 case Stmt::LambdaExprClass: {
5228 CFGBlock *B =
Block;
5229 for (Expr *
Init :
LE->capture_inits()) {
5231 if (CFGBlock *R = VisitForTemporaries(
5232 Init,
true, Context))
5239 case Stmt::StmtExprClass:
5244 case Stmt::CXXDefaultArgExprClass:
5248 case Stmt::CXXDefaultInitExprClass:
5254CFGBlock *CFGBuilder::VisitChildrenForTemporaries(Stmt *E,
5255 bool ExternallyDestructed,
5256 TempDtorContext &Context) {
5266 CFGBlock *B =
Block;
5270 VisitForTemporaries(Child, ExternallyDestructed, Context))
5276CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaries(
5277 BinaryOperator *E,
bool ExternallyDestructed, TempDtorContext &Context) {
5281 CFGBlock *LHSBlock = VisitForTemporaries(E->
getLHS(),
false, Context);
5282 CFGBlock *RHSBlock =
5283 VisitForTemporaries(E->
getRHS(), ExternallyDestructed, Context);
5284 return RHSBlock ? RHSBlock : LHSBlock;
5288 VisitForTemporaries(E->
getLHS(),
false, Context);
5289 TryResult RHSExecuted = tryEvaluateBool(E->
getLHS());
5290 if (RHSExecuted.isKnown() && E->
getOpcode() == BO_LOr)
5291 RHSExecuted.negate();
5296 TempDtorContext RHSContext(
5298 VisitForTemporaries(E->
getRHS(),
false, RHSContext);
5299 InsertTempDecisionBlock(RHSContext);
5302 Context.CollectedMTEs.append(RHSContext.CollectedMTEs);
5310 CFGBlock *RHSBlock = VisitForTemporaries(E->
getRHS(),
false, Context);
5311 CFGBlock *LHSBlock = VisitForTemporaries(E->
getLHS(),
false, Context);
5312 return LHSBlock ? LHSBlock : RHSBlock;
5316 return VisitChildrenForTemporaries(E, ExternallyDestructed, Context);
5319CFGBlock *CFGBuilder::VisitCXXOperatorCallExprForTemporaryDtors(
5320 CXXOperatorCallExpr *E, TempDtorContext &Context) {
5324 CFGBlock *RHSBlock = VisitForTemporaries(E->
getArg(1),
false, Context);
5325 CFGBlock *LHSBlock = VisitForTemporaries(E->
getArg(0),
false, Context);
5326 return LHSBlock ? LHSBlock : RHSBlock;
5328 return VisitChildrenForTemporaries(E,
false, Context);
5331CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
5332 CXXBindTemporaryExpr *E,
bool ExternallyDestructed, TempDtorContext &Context) {
5335 CFGBlock *B = VisitForTemporaries(E->
getSubExpr(),
true, Context);
5343 if (
Dtor->getParent()->isAnyDestructorNoReturn()) {
5349 Block = createNoReturnBlock();
5350 }
else if (Context.needsTempDtorBranch()) {
5354 Block = createBlock();
5358 if (Context.needsTempDtorBranch()) {
5359 Context.setDecisionPoint(Succ, E);
5361 appendTemporaryDtor(
Block, E);
5367void CFGBuilder::InsertTempDecisionBlock(
const TempDtorContext &Context,
5368 CFGBlock *FalseSucc) {
5369 if (!Context.TerminatorExpr) {
5373 assert(Context.TerminatorExpr);
5374 CFGBlock *Decision = createBlock(
false);
5375 Decision->setTerminator(CFGTerminator(Context.TerminatorExpr,
5377 addSuccessor(Decision,
Block, !Context.KnownExecuted.isFalse());
5378 addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
5379 !Context.KnownExecuted.isTrue());
5383CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaries(
5384 AbstractConditionalOperator *E,
bool ExternallyDestructed,
5385 TempDtorContext &Context) {
5386 VisitForTemporaries(E->
getCond(),
false, Context);
5387 CFGBlock *ConditionBlock =
Block;
5388 CFGBlock *ConditionSucc = Succ;
5389 TryResult ConditionVal = tryEvaluateBool(E->
getCond());
5390 TryResult NegatedVal = ConditionVal;
5391 if (NegatedVal.isKnown()) NegatedVal.negate();
5393 TempDtorContext TrueContext(
5395 VisitForTemporaries(E->
getTrueExpr(), ExternallyDestructed, TrueContext);
5396 CFGBlock *TrueBlock =
Block;
5398 Block = ConditionBlock;
5399 Succ = ConditionSucc;
5400 TempDtorContext FalseContext(
5402 VisitForTemporaries(E->
getFalseExpr(), ExternallyDestructed, FalseContext);
5404 if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
5405 InsertTempDecisionBlock(FalseContext, TrueBlock);
5406 }
else if (TrueContext.TerminatorExpr) {
5408 InsertTempDecisionBlock(TrueContext);
5410 InsertTempDecisionBlock(FalseContext);
5413 Context.CollectedMTEs.append(TrueContext.CollectedMTEs);
5414 Context.CollectedMTEs.append(FalseContext.CollectedMTEs);
5420CFGBlock *CFGBuilder::VisitOMPExecutableDirective(OMPExecutableDirective *D,
5421 AddStmtChoice asc) {
5422 if (asc.alwaysAdd(*
this, D)) {
5424 appendStmt(
Block, D);
5428 CFGBlock *B =
Block;
5432 SmallVector<Stmt *, 8>
Used(
5433 OMPExecutableDirective::used_clauses_children(D->clauses()));
5434 for (Stmt *S : llvm::reverse(
Used)) {
5435 assert(S &&
"Expected non-null used-in-clause child.");
5436 if (CFGBlock *R = Visit(S))
5440 if (!D->isStandaloneDirective()) {
5441 Stmt *S = D->getRawStmt();
5443 addLocalScopeAndDtors(S);
5444 if (CFGBlock *R = addStmt(S))
5455 bool first_block =
begin() ==
end();
5459 Blocks.push_back(Mem, BlkBVC);
5463 Entry = Exit = &
back();
5472 llvm::TimeTraceScope TimeProfile(
"BuildCFG");
5473 CFGBuilder Builder(
C, BO);
5474 return Builder.buildCFG(D, Statement);
5489 auto IteratorAndFlag = Visited.insert(B);
5490 if (!IteratorAndFlag.second) {
5496 const CFGBlock *FirstReachableB =
nullptr;
5498 if (!AB.isReachable())
5501 if (FirstReachableB ==
nullptr) {
5502 FirstReachableB = &*AB;
5509 if (!FirstReachableB) {
5515 B = FirstReachableB;
5536 llvm_unreachable(
"getDestructorDecl should only be used with "
5547 if (
const Expr *
Init = var->getInit()) {
5594 llvm_unreachable(
"getKind() returned bogus value");
5602 : ReachableBlock(IsReachable ? B :
nullptr),
5603 UnreachableBlock(!IsReachable ? B :
nullptr,
5604 B && IsReachable ? AB_Normal : AB_Unreachable) {}
5607 : ReachableBlock(B),
5608 UnreachableBlock(B == AlternateBlock ?
nullptr : AlternateBlock,
5609 B == AlternateBlock ? AB_Alternate : AB_Normal) {}
5619 Succs.push_back(Succ,
C);
5632 if (S->isAllEnumCasesCovered()) {
5650 using StmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>;
5651 using DeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>;
5655 signed currentBlock = 0;
5656 unsigned currStmt = 0;
5666 for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
5667 BI != BEnd; ++BI, ++j ) {
5668 if (std::optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
5669 const Stmt *stmt= SE->getStmt();
5670 std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
5673 switch (stmt->getStmtClass()) {
5674 case Stmt::DeclStmtClass:
5675 DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P;
5677 case Stmt::IfStmtClass: {
5678 const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable();
5683 case Stmt::ForStmtClass: {
5684 const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable();
5689 case Stmt::WhileStmtClass: {
5690 const VarDecl *var =
5691 cast<WhileStmt>(stmt)->getConditionVariable();
5696 case Stmt::SwitchStmtClass: {
5697 const VarDecl *var =
5698 cast<SwitchStmt>(stmt)->getConditionVariable();
5703 case Stmt::CXXCatchStmtClass: {
5704 const VarDecl *var =
5705 cast<CXXCatchStmt>(stmt)->getExceptionDecl();
5718 ~StmtPrinterHelper()
override =
default;
5720 const LangOptions &getLangOpts()
const {
return LangOpts; }
5721 void setBlockID(
signed i) { currentBlock = i; }
5722 void setStmtID(
unsigned i) { currStmt = i; }
5724 bool handledStmt(Stmt *S, raw_ostream &OS)
override {
5725 StmtMapTy::iterator I = StmtMap.find(S);
5727 if (I == StmtMap.end())
5730 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5731 && I->second.second == currStmt) {
5735 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5739 bool handleDecl(
const Decl *D, raw_ostream &OS) {
5740 DeclMapTy::iterator I = DeclMap.find(D);
5742 if (I == DeclMap.end()) {
5745 if (
auto *PVD = dyn_cast_or_null<ParmVarDecl>(D)) {
5746 OS <<
"[Parm: " << PVD->getNameAsString() <<
"]";
5752 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5753 && I->second.second == currStmt) {
5757 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5762class CFGBlockTerminatorPrint
5763 :
public StmtVisitor<CFGBlockTerminatorPrint,void> {
5765 StmtPrinterHelper* Helper;
5766 PrintingPolicy Policy;
5769 CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
5770 const PrintingPolicy &Policy)
5771 :
OS(os), Helper(helper), Policy(Policy) {
5775 void VisitIfStmt(IfStmt *I) {
5778 C->printPretty(OS, Helper, Policy);
5782 void VisitStmt(Stmt *Terminator) {
5786 void VisitDeclStmt(DeclStmt *DS) {
5791 void VisitForStmt(ForStmt *F) {
5797 C->printPretty(OS, Helper, Policy);
5804 void VisitWhileStmt(WhileStmt *W) {
5807 C->printPretty(OS, Helper, Policy);
5810 void VisitDoStmt(DoStmt *D) {
5811 OS <<
"do ... while ";
5813 C->printPretty(OS, Helper, Policy);
5816 void VisitSwitchStmt(SwitchStmt *Terminator) {
5821 void VisitCXXTryStmt(CXXTryStmt *) {
OS <<
"try ..."; }
5823 void VisitObjCAtTryStmt(ObjCAtTryStmt *) {
OS <<
"@try ..."; }
5825 void VisitSEHTryStmt(SEHTryStmt *CS) {
OS <<
"__try ..."; }
5827 void VisitAbstractConditionalOperator(AbstractConditionalOperator*
C) {
5828 if (Stmt *Cond =
C->getCond())
5830 OS <<
" ? ... : ...";
5833 void VisitChooseExpr(ChooseExpr *
C) {
5834 OS <<
"__builtin_choose_expr( ";
5835 if (Stmt *Cond =
C->getCond())
5840 void VisitIndirectGotoStmt(IndirectGotoStmt *I) {
5843 T->printPretty(OS, Helper, Policy);
5846 void VisitBinaryOperator(BinaryOperator* B) {
5863 llvm_unreachable(
"Invalid logical operator.");
5867 void VisitExpr(Expr *E) {
5872 void print(CFGTerminator
T) {
5873 switch (
T.getKind()) {
5878 OS <<
"(Temp Dtor) ";
5882 OS <<
"(See if most derived ctor has already initialized vbases)";
5904 OS <<
" (Base initializer)";
5906 OS <<
" (Delegating initializer)";
5908 OS <<
" (Member initializer)";
5912 StmtPrinterHelper &Helper,
5927 Stmts.push_back(CICC->getCXXBindTemporaryExpr());
5932 Stmts.push_back(SDSCC->getDeclStmt());
5937 Stmts.push_back(CDSCC->getDeclStmt());
5938 Stmts.push_back(CDSCC->getCXXBindTemporaryExpr());
5943 Stmts.push_back(NECC->getCXXNewExpr());
5948 Stmts.push_back(RSCC->getReturnStmt());
5954 Stmts.push_back(RSCC->getReturnStmt());
5955 Stmts.push_back(RSCC->getCXXBindTemporaryExpr());
5960 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5961 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5966 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5967 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5968 Stmts.push_back(TOCC->getConstructorAfterElision());
5973 Helper.handledStmt(
const_cast<LambdaExpr *
>(LCC->getLambdaExpr()), OS);
5974 OS <<
"+" << LCC->getIndex();
5979 if (
const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
5981 Helper.handledStmt(
const_cast<Stmt *
>(BTE), OS);
5984 Helper.handledStmt(
const_cast<Expr *
>(ACC->getCallLikeExpr()), OS);
5985 OS <<
"+" << ACC->getIndex();
5992 Helper.handledStmt(
const_cast<Stmt *
>(I), OS);
5996static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5997 const CFGElement &E,
bool TerminateWithNewLine =
true);
6000 bool TerminateWithNewLine)
const {
6002 StmtPrinterHelper Helper(
nullptr, LangOpts);
6003 print_elem(OS, Helper, *
this, TerminateWithNewLine);
6006static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
6007 const CFGElement &E,
bool TerminateWithNewLine) {
6014 assert(S !=
nullptr &&
"Expecting non-null Stmt");
6017 if (
const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
6025 if (TerminateWithNewLine)
6034 Helper.handledStmt(B->
getRHS(),OS);
6035 if (TerminateWithNewLine)
6040 S->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
6044 OS <<
" (OperatorCall)";
6045 OS <<
" (CXXRecordTypedCall";
6049 OS <<
" (OperatorCall)";
6051 OS <<
" (BindTemporary)";
6053 OS <<
" (CXXConstructExpr";
6057 OS <<
", " << CCE->getType() <<
")";
6058 }
else if (
const CastExpr *CE = dyn_cast<CastExpr>(S)) {
6060 <<
", " << CE->
getType() <<
")";
6064 if (
isa<Expr>(S) && TerminateWithNewLine)
6077 Helper.handleDecl(VD, OS);
6080 if (
T->isReferenceType())
6084 T.getUnqualifiedType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
6085 OS <<
"() (Implicit destructor)";
6090 OS <<
"CleanupFunction ("
6096 OS <<
" (Lifetime ends)";
6101 size_t MTECount = MTEs.size();
6102 OS <<
"(FullExprCleanup collected " << MTECount
6103 << (MTECount > 1 ?
" MTEs: " :
" MTE: ");
6104 bool FirstMTE =
true;
6108 if (!Helper.handledStmt(MTE->
getSubExpr(), OS)) {
6126 OS <<
"CFGScopeBegin(";
6133 OS <<
"CFGScopeEnd(";
6140 OS <<
"CFGNewAllocator(";
6142 AllocExpr->getType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
6154 OS <<
"->~" << RD->getName().str() <<
"()";
6155 OS <<
" (Implicit destructor)";
6162 OS <<
" (Base object destructor)";
6169 OS <<
"this->" << FD->
getName();
6170 OS <<
".~" <<
T->getAsCXXRecordDecl()->getName() <<
"()";
6171 OS <<
" (Member object destructor)";
6180 OS <<
"() (Temporary object destructor)";
6184 if (TerminateWithNewLine)
6190 StmtPrinterHelper &Helper,
bool print_edges,
6196 OS.changeColor(raw_ostream::YELLOW,
true);
6201 OS <<
" (ENTRY)]\n";
6202 else if (&B == &cfg->
getExit())
6205 OS <<
" (INDIRECT GOTO DISPATCH)]\n";
6207 OS <<
" (ANALYZER NORETURN)]\n";
6209 OS <<
" (NORETURN)]\n";
6225 if (
const Expr *LHS =
C->getLHS())
6227 if (
const Expr *RHS =
C->getRHS()) {
6242 if (
const VarDecl *PD = CS->getCatchParamDecl())
6253 llvm_unreachable(
"Invalid label statement in CFGBlock.");
6262 I != E ; ++I, ++j ) {
6267 OS << llvm::format(
"%3d", j) <<
": ";
6269 Helper.setStmtID(j);
6277 OS.changeColor(raw_ostream::GREEN);
6281 Helper.setBlockID(-1);
6284 CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
6295 const raw_ostream::Colors Color = raw_ostream::BLUE;
6297 OS.changeColor(Color);
6305 OS.changeColor(Color);
6313 bool Reachable =
true;
6316 B = I->getPossiblyUnreachableBlock();
6321 OS <<
"(Unreachable)";
6332 const raw_ostream::Colors Color = raw_ostream::MAGENTA;
6334 OS.changeColor(Color);
6342 OS.changeColor(Color);
6351 bool Reachable =
true;
6354 B = I->getPossiblyUnreachableBlock();
6360 OS <<
"(Unreachable)";
6376 print(llvm::errs(), LO, ShowColors);
6381 StmtPrinterHelper Helper(
this, LO);
6387 for (
const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
6392 print_block(OS,
this, **I, Helper,
true, ShowColors);
6407 bool ShowColors)
const {
6408 print(llvm::errs(), cfg, LO, ShowColors);
6419 StmtPrinterHelper Helper(cfg, LO);
6420 print_block(OS, cfg, *
this, Helper,
true, ShowColors);
6427 CFGBlockTerminatorPrint TPrinter(OS,
nullptr,
PrintingPolicy(LO));
6433 bool AddQuotes)
const {
6435 llvm::raw_string_ostream TempOut(Buf);
6458 if (llvm::any_of(*Blk, [](
const CFGElement &Elm) {
6459 if (std::optional<CFGStmt> StmtElm = Elm.
getAs<
CFGStmt>())
6479 DFSWorkList.push_back(StartBlk);
6480 while (!DFSWorkList.empty()) {
6481 const CFGBlock *Blk = DFSWorkList.pop_back_val();
6482 Visited.insert(Blk);
6491 for (
const auto &Succ : Blk->
succs()) {
6492 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
6496 DFSWorkList.push_back(SuccBlk);
6525 const Stmt *Cond = StmtElem->getStmt();
6539 const Expr *E =
nullptr;
6545 case Stmt::CXXForRangeStmtClass:
6549 case Stmt::ForStmtClass:
6553 case Stmt::WhileStmtClass:
6557 case Stmt::DoStmtClass:
6561 case Stmt::IfStmtClass:
6565 case Stmt::ChooseExprClass:
6569 case Stmt::IndirectGotoStmtClass:
6573 case Stmt::SwitchStmtClass:
6577 case Stmt::BinaryConditionalOperatorClass:
6581 case Stmt::ConditionalOperatorClass:
6585 case Stmt::BinaryOperatorClass:
6589 case Stmt::ObjCForCollectionStmtClass:
6606 StmtPrinterHelper H(
this, LO);
6608 llvm::ViewGraph(
this,
"CFG");
6620 llvm::raw_string_ostream Out(OutStr);
6623 if (OutStr[0] ==
'\n') OutStr.erase(OutStr.begin());
6626 for (
unsigned i = 0; i != OutStr.length(); ++i)
6627 if (OutStr[i] ==
'\n') {
6629 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, 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()
bool hasOnlyAnalyzerNoReturnElement() const
Returns true if the block ends in an 'analyzer_noreturn' call (as opposed to a real 'noreturn' one).
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
Returns true if the block has a noreturn element, whether it is a real 'noreturn' or an 'analyzer_nor...
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)
void setHasNoReturnElement(bool AnalyzerOnly=false)
Mark the block as ending in a noreturn element.
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)
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.
Top level wrappers for InstallAPI frontend operations.
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)
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)