39#include "llvm/ADT/APInt.h"
40#include "llvm/ADT/APSInt.h"
41#include "llvm/ADT/ArrayRef.h"
42#include "llvm/ADT/DenseMap.h"
43#include "llvm/ADT/STLExtras.h"
44#include "llvm/ADT/SetVector.h"
45#include "llvm/ADT/SmallPtrSet.h"
46#include "llvm/ADT/SmallVector.h"
47#include "llvm/Support/Allocator.h"
48#include "llvm/Support/Casting.h"
49#include "llvm/Support/Compiler.h"
50#include "llvm/Support/DOTGraphTraits.h"
51#include "llvm/Support/ErrorHandling.h"
52#include "llvm/Support/Format.h"
53#include "llvm/Support/GraphWriter.h"
54#include "llvm/Support/SaveAndRestore.h"
55#include "llvm/Support/raw_ostream.h"
67 if (
VarDecl *VD = dyn_cast<VarDecl>(
D))
68 if (
Expr *Ex = VD->getInit())
69 return Ex->getSourceRange().getEnd();
84 if (
const auto *CE = dyn_cast<CastExpr>(
E)) {
85 if (CE->getCastKind() != CK_IntegralCast)
91 if (
const auto *UO = dyn_cast<UnaryOperator>(
E)) {
92 if (UO->getOpcode() != UO_Minus)
97 return isa<IntegerLiteral>(
E);
108 return isa<EnumConstantDecl>(DR->getDecl()) ? DR :
nullptr;
117static std::tuple<const Expr *, BinaryOperatorKind, const Expr *>
124 if (Constant ==
nullptr) {
128 else if (Op == BO_GE)
130 else if (Op == BO_LT)
132 else if (Op == BO_LE)
139 return std::make_tuple(MaybeDecl, Op, Constant);
151 if (isa<DeclRefExpr>(E1) != isa<DeclRefExpr>(E2))
155 if (!isa<DeclRefExpr>(E1))
160 assert(isa<DeclRefExpr>(E1) && isa<DeclRefExpr>(E2));
161 auto *Decl1 = cast<DeclRefExpr>(E1)->getDecl();
162 auto *Decl2 = cast<DeclRefExpr>(E2)->getDecl();
164 assert(isa<EnumConstantDecl>(Decl1) && isa<EnumConstantDecl>(Decl2));
168 assert(isa<EnumDecl>(DC1) && isa<EnumDecl>(DC2));
190 enum Kind { NotAlwaysAdd = 0, AlwaysAdd = 1 };
192 AddStmtChoice(Kind a_kind = NotAlwaysAdd) :
kind(a_kind) {}
194 bool alwaysAdd(CFGBuilder &builder,
199 AddStmtChoice withAlwaysAdd(
bool alwaysAdd)
const {
200 return AddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd);
234 class const_iterator {
235 const LocalScope*
Scope =
nullptr;
239 unsigned VarIter = 0;
245 const_iterator() =
default;
249 const_iterator(
const LocalScope& S,
unsigned I)
250 :
Scope(&S), VarIter(I) {
253 if (VarIter == 0 &&
Scope)
257 VarDecl *
const* operator->()
const {
258 assert(
Scope &&
"Dereferencing invalid iterator is not allowed");
259 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
260 return &
Scope->Vars[VarIter - 1];
263 const VarDecl *getFirstVarInScope()
const {
264 assert(
Scope &&
"Dereferencing invalid iterator is not allowed");
265 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
266 return Scope->Vars[0];
270 return *this->operator->();
273 const_iterator &operator++() {
277 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
283 const_iterator operator++(
int) {
284 const_iterator
P = *
this;
289 bool operator==(
const const_iterator &rhs)
const {
290 return Scope == rhs.
Scope && VarIter == rhs.VarIter;
292 bool operator!=(
const const_iterator &rhs)
const {
293 return !(*
this == rhs);
296 explicit operator bool()
const {
297 return *
this != const_iterator();
301 const_iterator shared_parent(const_iterator L);
302 bool pointsToFirstDeclaredVar() {
return VarIter == 1; }
303 bool inSameLocalScope(const_iterator rhs) {
return Scope == rhs.
Scope; }
310 AutomaticVarsTy Vars;
319 : ctx(
std::move(ctx)), Vars(this->ctx, 4), Prev(
P) {}
322 const_iterator begin()
const {
return const_iterator(*
this, Vars.size()); }
325 Vars.push_back(VD, ctx);
334int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
336 const_iterator F = *
this;
337 while (F.Scope != L.Scope) {
338 assert(F != const_iterator() &&
339 "L iterator is not reachable from F iterator.");
343 D += F.VarIter - L.VarIter;
351LocalScope::const_iterator
352LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
355 if ((*
this == const_iterator()) || (L == const_iterator())) {
356 return const_iterator();
359 const_iterator F = *
this;
360 if (F.inSameLocalScope(L)) {
362 F.VarIter = std::min(F.VarIter, L.VarIter);
366 llvm::SmallDenseMap<const LocalScope *, unsigned, 4> ScopesOfL;
368 ScopesOfL.try_emplace(L.Scope, L.VarIter);
369 if (L == const_iterator())
375 if (
auto LIt = ScopesOfL.find(F.Scope); LIt != ScopesOfL.end()) {
377 F.VarIter = std::min(F.VarIter, LIt->getSecond());
380 assert(F != const_iterator() &&
381 "L iterator is not reachable from F iterator.");
391struct BlockScopePosPair {
393 LocalScope::const_iterator scopePosition;
395 BlockScopePosPair() =
default;
396 BlockScopePosPair(
CFGBlock *
b, LocalScope::const_iterator scopePos)
397 : block(
b), scopePosition(scopePos) {}
408 TryResult() =
default;
409 TryResult(
bool b) :
X(
b ? 1 : 0) {}
411 bool isTrue()
const {
return X == 1; }
412 bool isFalse()
const {
return X == 0; }
413 bool isKnown()
const {
return X >= 0; }
424 if (!R1.isKnown() || !R2.isKnown())
426 return TryResult(R1.isTrue() && R2.isTrue());
431class reverse_children {
436 reverse_children(
Stmt *S);
440 iterator begin()
const {
return children.rbegin(); }
441 iterator end()
const {
return children.rend(); }
446reverse_children::reverse_children(
Stmt *S) {
447 if (
CallExpr *CE = dyn_cast<CallExpr>(S)) {
448 children = CE->getRawSubExprs();
451 switch (S->getStmtClass()) {
453 case Stmt::InitListExprClass: {
464 llvm::append_range(childrenBuf, S->children());
467 children = childrenBuf;
486 using JumpTarget = BlockScopePosPair;
487 using JumpSource = BlockScopePosPair;
490 std::unique_ptr<CFG> cfg;
498 JumpTarget ContinueJumpTarget;
499 JumpTarget BreakJumpTarget;
500 JumpTarget SEHLeaveJumpTarget;
501 CFGBlock *SwitchTerminatedBlock =
nullptr;
502 CFGBlock *DefaultCaseBlock =
nullptr;
508 CFGBlock *TryTerminatedBlock =
nullptr;
511 LocalScope::const_iterator ScopePos;
514 using LabelMapTy = llvm::DenseMap<LabelDecl *, JumpTarget>;
519 using BackpatchBlocksTy = std::vector<JumpSource>;
520 BackpatchBlocksTy BackpatchBlocks;
524 LabelSetTy AddressTakenLabels;
529 llvm::DenseMap<Expr *, const ConstructionContextLayer *>
530 ConstructionContextMap;
536 bool switchExclusivelyCovered =
false;
539 CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry =
nullptr;
540 const Stmt *lastLookup =
nullptr;
544 using CachedBoolEvalsTy = llvm::DenseMap<Expr *, TryResult>;
545 CachedBoolEvalsTy CachedBoolEvals;
550 : Context(astContext), cfg(new
CFG()), BuildOpts(buildOpts) {}
553 std::unique_ptr<CFG> buildCFG(
const Decl *
D,
Stmt *Statement);
590 AddStmtChoice asc,
bool ExternallyDestructed);
602 std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(
BinaryOperator *B,
632 CFGBlock *Visit(
Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd,
633 bool ExternallyDestructed =
false);
642 if (ScopePos && (VD == ScopePos.getFirstVarInScope()))
643 appendScopeBegin(B, VD, S);
674 struct TempDtorContext {
675 TempDtorContext() =
default;
676 TempDtorContext(TryResult KnownExecuted)
677 : IsConditional(
true), KnownExecuted(KnownExecuted) {}
685 bool needsTempDtorBranch()
const {
686 return IsConditional && !TerminatorExpr;
696 const bool IsConditional =
false;
697 const TryResult KnownExecuted =
true;
704 CFGBlock *VisitForTemporaryDtors(
Stmt *
E,
bool ExternallyDestructed,
705 TempDtorContext &Context);
706 CFGBlock *VisitChildrenForTemporaryDtors(
Stmt *
E,
bool ExternallyDestructed,
707 TempDtorContext &Context);
709 bool ExternallyDestructed,
710 TempDtorContext &Context);
711 CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(
713 CFGBlock *VisitConditionalOperatorForTemporaryDtors(
715 TempDtorContext &Context);
716 void InsertTempDtorDecisionBlock(
const TempDtorContext &Context,
741 template <
typename CallLikeExpr,
742 typename = std::enable_if_t<
743 std::is_base_of_v<CallExpr, CallLikeExpr> ||
744 std::is_base_of_v<CXXConstructExpr, CallLikeExpr> ||
745 std::is_base_of_v<ObjCMessageExpr, CallLikeExpr>>>
746 void findConstructionContextsForArguments(CallLikeExpr *
E) {
747 for (
unsigned i = 0, e =
E->getNumArgs(); i != e; ++i) {
748 Expr *Arg =
E->getArg(i);
750 findConstructionContexts(
760 void cleanupConstructionContext(
Expr *
E);
762 void autoCreateBlock() {
if (!Block)
Block = createBlock(); }
763 CFGBlock *createBlock(
bool add_successor =
true);
767 return Visit(S, AddStmtChoice::AlwaysAdd);
771 void addLoopExit(
const Stmt *LoopStmt);
772 void addAutomaticObjHandling(LocalScope::const_iterator B,
773 LocalScope::const_iterator
E,
Stmt *S);
774 void addAutomaticObjDestruction(LocalScope::const_iterator B,
775 LocalScope::const_iterator
E,
Stmt *S);
776 void addScopeExitHandling(LocalScope::const_iterator B,
777 LocalScope::const_iterator
E,
Stmt *S);
779 void addScopeChangesHandling(LocalScope::const_iterator SrcPos,
780 LocalScope::const_iterator DstPos,
782 CFGBlock *createScopeChangesHandlingBlock(LocalScope::const_iterator SrcPos,
784 LocalScope::const_iterator DstPost,
788 LocalScope* createOrReuseLocalScope(LocalScope*
Scope);
790 void addLocalScopeForStmt(
Stmt *S);
791 LocalScope* addLocalScopeForDeclStmt(
DeclStmt *DS,
792 LocalScope*
Scope =
nullptr);
793 LocalScope* addLocalScopeForVarDecl(
VarDecl *VD, LocalScope*
Scope =
nullptr);
795 void addLocalScopeAndDtors(
Stmt *S);
805 cleanupConstructionContext(
E);
813 if (alwaysAdd(S) && cachedEntry)
814 cachedEntry->second = B;
817 assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S);
823 retrieveAndCleanupConstructionContext(CE)) {
829 B->
appendStmt(CE, cfg->getBumpVectorContext());
833 if (alwaysAdd(CE) && cachedEntry)
834 cachedEntry->second = B;
837 retrieveAndCleanupConstructionContext(CE)) {
843 B->
appendStmt(CE, cfg->getBumpVectorContext());
863 if (alwaysAdd(ME) && cachedEntry)
864 cachedEntry->second = B;
867 retrieveAndCleanupConstructionContext(ME)) {
873 cfg->getBumpVectorContext());
892 void appendLoopExit(
CFGBlock *B,
const Stmt *LoopStmt) {
902 cfg->getBumpVectorContext());
909 cfg->getBumpVectorContext());
925 TryResult checkIncorrectRelationalOperator(
const BinaryOperator *B) {
929 const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
930 const Expr *BoolExpr = RHSExpr;
931 bool IntFirst =
true;
933 IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
941 llvm::APInt IntValue = IntLiteral->
getValue();
942 if ((IntValue == 1) || (IntValue == 0))
946 !IntValue.isNegative();
949 if (Bok == BO_GT || Bok == BO_GE) {
952 return TryResult(IntFirst == IntLarger);
956 return TryResult(IntFirst != IntLarger);
964 TryResult checkIncorrectEqualityOperator(
const BinaryOperator *B) {
968 std::optional<llvm::APInt> IntLiteral1 =
969 getIntegerLiteralSubexpressionValue(LHSExpr);
970 const Expr *BoolExpr = RHSExpr;
973 IntLiteral1 = getIntegerLiteralSubexpressionValue(RHSExpr);
981 if (BitOp && (BitOp->
getOpcode() == BO_And ||
986 std::optional<llvm::APInt> IntLiteral2 =
987 getIntegerLiteralSubexpressionValue(LHSExpr2);
990 IntLiteral2 = getIntegerLiteralSubexpressionValue(RHSExpr2);
996 (*IntLiteral2 & *IntLiteral1) != *IntLiteral1) ||
998 (*IntLiteral2 | *IntLiteral1) != *IntLiteral1)) {
1002 return TryResult(B->
getOpcode() != BO_EQ);
1005 if ((*IntLiteral1 == 1) || (*IntLiteral1 == 0)) {
1008 return TryResult(B->
getOpcode() != BO_EQ);
1020 std::optional<llvm::APInt>
1021 getIntegerLiteralSubexpressionValue(
const Expr *
E) {
1024 if (
const auto *UnOp = dyn_cast<UnaryOperator>(
E->
IgnoreParens())) {
1029 if (
const auto *IntLiteral = dyn_cast<IntegerLiteral>(SubExpr)) {
1034 switch (UnOp->getOpcode()) {
1044 assert(
false &&
"Unexpected unary operator!");
1045 return std::nullopt;
1048 }
else if (
const auto *IntLiteral =
1052 return std::nullopt;
1056 const llvm::APSInt &Value1,
1057 const llvm::APSInt &Value2) {
1058 assert(Value1.isSigned() == Value2.isSigned());
1063 return TryResult(Value1 == Value2);
1065 return TryResult(Value1 != Value2);
1067 return TryResult(Value1 < Value2);
1069 return TryResult(Value1 <= Value2);
1071 return TryResult(Value1 > Value2);
1073 return TryResult(Value1 >= Value2);
1089 auto CheckLogicalOpWithNegatedVariable = [
this, B](
const Expr *E1,
1091 if (
const auto *Negate = dyn_cast<UnaryOperator>(E1)) {
1092 if (Negate->getOpcode() == UO_LNot &&
1094 bool AlwaysTrue = B->
getOpcode() == BO_LOr;
1097 return TryResult(AlwaysTrue);
1103 TryResult Result = CheckLogicalOpWithNegatedVariable(LHSExpr, RHSExpr);
1104 if (Result.isKnown())
1106 Result = CheckLogicalOpWithNegatedVariable(RHSExpr, LHSExpr);
1107 if (Result.isKnown())
1110 const auto *LHS = dyn_cast<BinaryOperator>(LHSExpr);
1111 const auto *RHS = dyn_cast<BinaryOperator>(RHSExpr);
1115 if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
1118 const Expr *DeclExpr1;
1119 const Expr *NumExpr1;
1123 if (!DeclExpr1 || !NumExpr1)
1126 const Expr *DeclExpr2;
1127 const Expr *NumExpr2;
1131 if (!DeclExpr2 || !NumExpr2)
1148 llvm::APSInt L1 = L1Result.
Val.
getInt();
1149 llvm::APSInt L2 = L2Result.
Val.
getInt();
1152 if (L1.isSigned() != L2.isSigned() || L1.getBitWidth() != L2.getBitWidth())
1157 const llvm::APSInt Values[] = {
1159 llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
1163 ((L1 < L2) ? L1 : L2) + llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1),
1168 llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
1177 bool AlwaysTrue =
true, AlwaysFalse =
true;
1180 bool LHSAlwaysTrue =
true, LHSAlwaysFalse =
true;
1181 bool RHSAlwaysTrue =
true, RHSAlwaysFalse =
true;
1182 for (
const llvm::APSInt &
Value : Values) {
1183 TryResult Res1, Res2;
1184 Res1 = analyzeLogicOperatorCondition(BO1,
Value, L1);
1185 Res2 = analyzeLogicOperatorCondition(BO2,
Value, L2);
1187 if (!Res1.isKnown() || !Res2.isKnown())
1191 AlwaysTrue &= (Res1.isTrue() && Res2.isTrue());
1192 AlwaysFalse &= !(Res1.isTrue() && Res2.isTrue());
1194 AlwaysTrue &= (Res1.isTrue() || Res2.isTrue());
1195 AlwaysFalse &= !(Res1.isTrue() || Res2.isTrue());
1198 LHSAlwaysTrue &= Res1.isTrue();
1199 LHSAlwaysFalse &= Res1.isFalse();
1200 RHSAlwaysTrue &= Res2.isTrue();
1201 RHSAlwaysFalse &= Res2.isFalse();
1204 if (AlwaysTrue || AlwaysFalse) {
1205 if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
1206 !RHSAlwaysFalse && BuildOpts.
Observer)
1208 return TryResult(AlwaysTrue);
1214 TryResult checkIncorrectBitwiseOrOperator(
const BinaryOperator *B) {
1215 const Expr *LHSConstant =
1217 const Expr *RHSConstant =
1220 if ((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant))
1223 const Expr *Constant = LHSConstant ? LHSConstant : RHSConstant;
1229 if (Result.Val.getInt() == 0)
1235 return TryResult(
true);
1242 return !S->isTypeDependent() &&
1243 !S->isValueDependent() &&
1244 S->EvaluateAsRValue(outResult, *Context);
1249 TryResult tryEvaluateBool(
Expr *S) {
1251 S->isTypeDependent() || S->isValueDependent())
1255 if (Bop->isLogicalOp() || Bop->isEqualityOp()) {
1257 CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S);
1258 if (I != CachedBoolEvals.end())
1262 TryResult Result = evaluateAsBooleanConditionNoCache(S);
1263 CachedBoolEvals[S] = Result;
1267 switch (Bop->getOpcode()) {
1276 if (Bop->getLHS()->EvaluateAsInt(LHSResult, *Context)) {
1277 llvm::APSInt IntVal = LHSResult.
Val.
getInt();
1278 if (!IntVal.getBoolValue()) {
1279 return TryResult(
false);
1283 if (Bop->getRHS()->EvaluateAsInt(RHSResult, *Context)) {
1284 llvm::APSInt IntVal = RHSResult.
Val.
getInt();
1285 if (!IntVal.getBoolValue()) {
1286 return TryResult(
false);
1295 return evaluateAsBooleanConditionNoCache(S);
1299 TryResult evaluateAsBooleanConditionNoCache(
Expr *
E) {
1301 if (Bop->isLogicalOp()) {
1302 TryResult LHS = tryEvaluateBool(Bop->getLHS());
1303 if (LHS.isKnown()) {
1306 if (LHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1307 return LHS.isTrue();
1309 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1310 if (RHS.isKnown()) {
1311 if (Bop->getOpcode() == BO_LOr)
1312 return LHS.isTrue() || RHS.isTrue();
1314 return LHS.isTrue() && RHS.isTrue();
1317 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1318 if (RHS.isKnown()) {
1321 if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1322 return RHS.isTrue();
1324 TryResult BopRes = checkIncorrectLogicOperator(Bop);
1325 if (BopRes.isKnown())
1326 return BopRes.isTrue();
1331 }
else if (Bop->isEqualityOp()) {
1332 TryResult BopRes = checkIncorrectEqualityOperator(Bop);
1333 if (BopRes.isKnown())
1334 return BopRes.isTrue();
1335 }
else if (Bop->isRelationalOp()) {
1336 TryResult BopRes = checkIncorrectRelationalOperator(Bop);
1337 if (BopRes.isKnown())
1338 return BopRes.isTrue();
1339 }
else if (Bop->getOpcode() == BO_Or) {
1340 TryResult BopRes = checkIncorrectBitwiseOrOperator(Bop);
1341 if (BopRes.isKnown())
1342 return BopRes.isTrue();
1353 bool hasTrivialDestructor(
const VarDecl *VD)
const;
1354 bool needsAutomaticDestruction(
const VarDecl *VD)
const;
1365 while (
const auto *
E = dyn_cast<ArrayInitLoopExpr>(AILEInit))
1366 AILEInit =
E->getSubExpr();
1371inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
1373 return builder.alwaysAdd(
stmt) || kind == AlwaysAdd;
1376bool CFGBuilder::alwaysAdd(
const Stmt *
stmt) {
1382 if (lastLookup ==
stmt) {
1384 assert(cachedEntry->first ==
stmt);
1397 assert(!cachedEntry);
1401 CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(
stmt);
1402 if (itr == fb->end()) {
1403 cachedEntry =
nullptr;
1407 cachedEntry = &*itr;
1414 while (
const ArrayType *vt = dyn_cast<ArrayType>(t)) {
1416 if (vat->getSizeExpr())
1419 t = vt->getElementType().getTypePtr();
1425void CFGBuilder::consumeConstructionContext(
1427 assert((isa<CXXConstructExpr>(
E) || isa<CallExpr>(
E) ||
1428 isa<ObjCMessageExpr>(
E)) &&
"Expression cannot construct an object!");
1430 ConstructionContextMap.lookup(
E)) {
1431 (void)PreviouslyStoredLayer;
1434 assert(PreviouslyStoredLayer->isStrictlyMoreSpecificThan(Layer) &&
1435 "Already within a different construction context!");
1437 ConstructionContextMap[
E] = Layer;
1441void CFGBuilder::findConstructionContexts(
1454 switch(Child->getStmtClass()) {
1455 case Stmt::CXXConstructExprClass:
1456 case Stmt::CXXTemporaryObjectExprClass: {
1458 auto *CE = cast<CXXConstructExpr>(Child);
1460 findConstructionContexts(withExtraLayer(CE), CE->
getArg(0));
1463 consumeConstructionContext(Layer, CE);
1469 case Stmt::CallExprClass:
1470 case Stmt::CXXMemberCallExprClass:
1471 case Stmt::CXXOperatorCallExprClass:
1472 case Stmt::UserDefinedLiteralClass:
1473 case Stmt::ObjCMessageExprClass: {
1474 auto *
E = cast<Expr>(Child);
1476 consumeConstructionContext(Layer,
E);
1479 case Stmt::ExprWithCleanupsClass: {
1480 auto *Cleanups = cast<ExprWithCleanups>(Child);
1481 findConstructionContexts(Layer, Cleanups->getSubExpr());
1484 case Stmt::CXXFunctionalCastExprClass: {
1485 auto *
Cast = cast<CXXFunctionalCastExpr>(Child);
1486 findConstructionContexts(Layer,
Cast->getSubExpr());
1489 case Stmt::ImplicitCastExprClass: {
1490 auto *
Cast = cast<ImplicitCastExpr>(Child);
1492 switch (
Cast->getCastKind()) {
1494 case CK_ConstructorConversion:
1495 findConstructionContexts(Layer,
Cast->getSubExpr());
1502 case Stmt::CXXBindTemporaryExprClass: {
1503 auto *BTE = cast<CXXBindTemporaryExpr>(Child);
1504 findConstructionContexts(withExtraLayer(BTE), BTE->getSubExpr());
1507 case Stmt::MaterializeTemporaryExprClass: {
1514 auto *MTE = cast<MaterializeTemporaryExpr>(Child);
1515 findConstructionContexts(withExtraLayer(MTE), MTE->getSubExpr());
1519 case Stmt::ConditionalOperatorClass: {
1520 auto *CO = cast<ConditionalOperator>(Child);
1527 assert(!CO->getType()->getAsCXXRecordDecl() || CO->isGLValue() ||
1531 findConstructionContexts(Layer, CO->getLHS());
1532 findConstructionContexts(Layer, CO->getRHS());
1535 case Stmt::InitListExprClass: {
1536 auto *ILE = cast<InitListExpr>(Child);
1537 if (ILE->isTransparent()) {
1538 findConstructionContexts(Layer, ILE->getInit(0));
1544 case Stmt::ParenExprClass: {
1547 auto *PE = cast<ParenExpr>(Child);
1548 findConstructionContexts(Layer, PE->getSubExpr());
1556void CFGBuilder::cleanupConstructionContext(
Expr *
E) {
1558 "We should not be managing construction contexts!");
1559 assert(ConstructionContextMap.count(
E) &&
1560 "Cannot exit construction context without the context!");
1561 ConstructionContextMap.erase(
E);
1569std::unique_ptr<CFG> CFGBuilder::buildCFG(
const Decl *
D,
Stmt *Statement) {
1577 Succ = createBlock();
1578 assert(Succ == &cfg->getExit());
1583 addImplicitDtorsForDestructor(DD);
1603 if (
const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(
D)) {
1605 for (
auto *I : llvm::reverse(CD->inits())) {
1607 I->isBaseInitializer() && I->isBaseVirtual()) {
1611 VBaseSucc = Succ = B ? B : &cfg->getExit();
1612 Block = createBlock();
1614 B = addInitializer(I);
1624 addSuccessor(B,
Block,
true);
1633 for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
1634 E = BackpatchBlocks.end(); I !=
E; ++I ) {
1638 LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
1641 if (LI == LabelMap.end())
1643 JumpTarget JT = LI->second;
1645 CFGBlock *SuccBlk = createScopeChangesHandlingBlock(
1646 I->scopePosition, B, JT.scopePosition, JT.block);
1647 addSuccessor(B, SuccBlk);
1648 }
else if (
auto *G = dyn_cast<GCCAsmStmt>(B->
getTerminator())) {
1649 CFGBlock *Successor = (I+1)->block;
1650 for (
auto *L : G->labels()) {
1651 LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
1654 if (LI == LabelMap.end())
1656 JumpTarget JT = LI->second;
1658 if (JT.block == Successor)
1660 addSuccessor(B, JT.block);
1667 if (
CFGBlock *B = cfg->getIndirectGotoBlock())
1668 for (LabelSetTy::iterator I = AddressTakenLabels.begin(),
1669 E = AddressTakenLabels.end(); I !=
E; ++I ) {
1671 LabelMapTy::iterator LI = LabelMap.find(*I);
1675 if (LI == LabelMap.end())
continue;
1677 addSuccessor(B, LI->second.block);
1681 cfg->setEntry(createBlock());
1684 assert(ConstructionContextMap.empty() &&
1685 "Not all construction contexts were cleaned up!");
1687 return std::move(cfg);
1692CFGBlock *CFGBuilder::createBlock(
bool add_successor) {
1694 if (add_successor && Succ)
1695 addSuccessor(B, Succ);
1702CFGBlock *CFGBuilder::createNoReturnBlock() {
1705 addSuccessor(B, &cfg->getExit(), Succ);
1714 bool HasTemporaries =
false;
1720 HasTemporaries = isa<ExprWithCleanups>(
Init);
1724 TempDtorContext Context;
1725 VisitForTemporaryDtors(cast<ExprWithCleanups>(
Init)->getSubExpr(),
1731 appendInitializer(
Block, I);
1737 dyn_cast<ArrayInitLoopExpr>(
Init));
1739 findConstructionContexts(
1741 AILEInit ? AILEInit :
Init);
1743 if (HasTemporaries) {
1746 return Visit(cast<ExprWithCleanups>(
Init)->getSubExpr());
1770 bool *FoundMTE =
nullptr) {
1777 Init = EWC->getSubExpr();
1783 = dyn_cast<MaterializeTemporaryExpr>(
Init)) {
1784 Init = MTE->getSubExpr();
1791 const Expr *SkippedInit =
Init->skipRValueSubobjectAdjustments();
1792 if (SkippedInit !=
Init) {
1800 return Init->getType();
1805void CFGBuilder::addLoopExit(
const Stmt *LoopStmt){
1809 appendLoopExit(
Block, LoopStmt);
1817void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
1818 LocalScope::const_iterator
E,
1828 if (B.inSameLocalScope(
E)) {
1829 addAutomaticObjDestruction(B,
E, S);
1835 LocalScopeEndMarkers.push_back(B);
1836 for (LocalScope::const_iterator I = B; I !=
E; ++I) {
1837 if (!I.inSameLocalScope(LocalScopeEndMarkers.back()))
1838 LocalScopeEndMarkers.push_back(I);
1840 LocalScopeEndMarkers.push_back(
E);
1844 std::reverse(LocalScopeEndMarkers.begin(), LocalScopeEndMarkers.end());
1846 llvm::zip(LocalScopeEndMarkers, llvm::drop_begin(LocalScopeEndMarkers));
1847 for (
auto [
E, B] : Pairwise) {
1848 if (!B.inSameLocalScope(
E))
1849 addScopeExitHandling(B,
E, S);
1850 addAutomaticObjDestruction(B,
E, S);
1857void CFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
1858 LocalScope::const_iterator
E,
1867 DeclsNeedDestruction.reserve(B.distance(
E));
1869 for (
VarDecl*
D : llvm::make_range(B,
E))
1870 if (needsAutomaticDestruction(
D))
1871 DeclsNeedDestruction.push_back(
D);
1873 for (
VarDecl *VD : llvm::reverse(DeclsNeedDestruction)) {
1886 Block = createNoReturnBlock();
1895 appendLifetimeEnds(
Block, VD, S);
1897 appendAutomaticObjDtor(
Block, VD, S);
1898 if (VD->
hasAttr<CleanupAttr>())
1899 appendCleanupFunction(
Block, VD);
1908void CFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
1909 LocalScope::const_iterator
E,
Stmt *S) {
1910 assert(!B.inSameLocalScope(
E));
1916 appendScopeEnd(
Block, B.getFirstVarInScope(), S);
1924 DeclsTrivial.reserve(B.distance(
E));
1929 for (
VarDecl*
D : llvm::make_range(B,
E))
1930 if (!needsAutomaticDestruction(
D))
1931 DeclsTrivial.push_back(
D);
1933 if (DeclsTrivial.empty())
1937 for (
VarDecl *VD : llvm::reverse(DeclsTrivial))
1938 appendLifetimeEnds(
Block, VD, S);
1946void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
1947 LocalScope::const_iterator DstPos,
1949 assert(
Block &&
"Source block should be always crated");
1955 if (SrcPos == DstPos)
1960 LocalScope::const_iterator BasePos = SrcPos.shared_parent(DstPos);
1963 if (BuildOpts.
AddScopes && !DstPos.inSameLocalScope(BasePos)) {
1964 for (LocalScope::const_iterator I = DstPos; I != BasePos; ++I)
1965 if (I.pointsToFirstDeclaredVar())
1966 appendScopeBegin(
Block, *I, S);
1971 addAutomaticObjHandling(SrcPos, BasePos, S);
1979CFGBlock *CFGBuilder::createScopeChangesHandlingBlock(
1980 LocalScope::const_iterator SrcPos,
CFGBlock *SrcBlk,
1981 LocalScope::const_iterator DstPos,
CFGBlock *DstBlk) {
1982 if (SrcPos == DstPos)
1986 (!BuildOpts.
AddScopes || SrcPos.inSameLocalScope(DstPos)))
1994 Block = createBlock(
false);
1997 addSuccessor(
Block, DstBlk);
2002 assert(
Block &&
"There should be at least one scope changing Block");
2010 "Can be called only when dtors should be added");
2014 for (
const auto &VI : RD->
vbases()) {
2018 const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
2021 appendBaseDtor(
Block, &VI);
2026 for (
const auto &BI : RD->
bases()) {
2027 if (!BI.isVirtual()) {
2028 const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
2031 appendBaseDtor(
Block, &BI);
2037 for (
auto *FI : RD->
fields()) {
2042 if (AT->isZeroSize())
2044 QT = AT->getElementType();
2050 appendMemberDtor(
Block, FI);
2057LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope*
Scope) {
2060 llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
2066void CFGBuilder::addLocalScopeForStmt(
Stmt *S) {
2071 LocalScope *
Scope =
nullptr;
2075 for (
auto *BI : CS->body()) {
2077 if (
DeclStmt *DS = dyn_cast<DeclStmt>(SI))
2085 if (
DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements()))
2086 addLocalScopeForDeclStmt(DS);
2091LocalScope* CFGBuilder::addLocalScopeForDeclStmt(
DeclStmt *DS,
2092 LocalScope*
Scope) {
2097 for (
auto *DI : DS->
decls())
2098 if (
VarDecl *VD = dyn_cast<VarDecl>(DI))
2103bool CFGBuilder::needsAutomaticDestruction(
const VarDecl *VD)
const {
2104 return !hasTrivialDestructor(VD) || VD->
hasAttr<CleanupAttr>();
2107bool CFGBuilder::hasTrivialDestructor(
const VarDecl *VD)
const {
2128 bool FoundMTE =
false;
2136 if (AT->isZeroSize())
2138 QT = AT->getElementType();
2150LocalScope* CFGBuilder::addLocalScopeForVarDecl(
VarDecl *VD,
2151 LocalScope*
Scope) {
2161 !needsAutomaticDestruction(VD)) {
2169 ScopePos =
Scope->begin();
2175void CFGBuilder::addLocalScopeAndDtors(
Stmt *S) {
2176 LocalScope::const_iterator scopeBeginPos = ScopePos;
2177 addLocalScopeForStmt(S);
2178 addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
2184CFGBlock *CFGBuilder::Visit(
Stmt * S, AddStmtChoice asc,
2185 bool ExternallyDestructed) {
2191 if (
Expr *
E = dyn_cast<Expr>(S))
2195 if (
auto *
D = dyn_cast<OMPExecutableDirective>(S))
2196 return VisitOMPExecutableDirective(
D, asc);
2198 switch (S->getStmtClass()) {
2200 return VisitStmt(S, asc);
2202 case Stmt::ImplicitValueInitExprClass:
2205 return VisitStmt(S, asc);
2207 case Stmt::InitListExprClass:
2208 return VisitInitListExpr(cast<InitListExpr>(S), asc);
2210 case Stmt::AttributedStmtClass:
2211 return VisitAttributedStmt(cast<AttributedStmt>(S), asc);
2213 case Stmt::AddrLabelExprClass:
2214 return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
2216 case Stmt::BinaryConditionalOperatorClass:
2217 return VisitConditionalOperator(cast<BinaryConditionalOperator>(S), asc);
2219 case Stmt::BinaryOperatorClass:
2220 return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
2222 case Stmt::BlockExprClass:
2223 return VisitBlockExpr(cast<BlockExpr>(S), asc);
2225 case Stmt::BreakStmtClass:
2226 return VisitBreakStmt(cast<BreakStmt>(S));
2228 case Stmt::CallExprClass:
2229 case Stmt::CXXOperatorCallExprClass:
2230 case Stmt::CXXMemberCallExprClass:
2231 case Stmt::UserDefinedLiteralClass:
2232 return VisitCallExpr(cast<CallExpr>(S), asc);
2234 case Stmt::CaseStmtClass:
2235 return VisitCaseStmt(cast<CaseStmt>(S));
2237 case Stmt::ChooseExprClass:
2238 return VisitChooseExpr(cast<ChooseExpr>(S), asc);
2240 case Stmt::CompoundStmtClass:
2241 return VisitCompoundStmt(cast<CompoundStmt>(S), ExternallyDestructed);
2243 case Stmt::ConditionalOperatorClass:
2244 return VisitConditionalOperator(cast<ConditionalOperator>(S), asc);
2246 case Stmt::ContinueStmtClass:
2247 return VisitContinueStmt(cast<ContinueStmt>(S));
2249 case Stmt::CXXCatchStmtClass:
2250 return VisitCXXCatchStmt(cast<CXXCatchStmt>(S));
2252 case Stmt::ExprWithCleanupsClass:
2253 return VisitExprWithCleanups(cast<ExprWithCleanups>(S),
2254 asc, ExternallyDestructed);
2256 case Stmt::CXXDefaultArgExprClass:
2257 case Stmt::CXXDefaultInitExprClass:
2266 return VisitStmt(S, asc);
2268 case Stmt::CXXBindTemporaryExprClass:
2269 return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc);
2271 case Stmt::CXXConstructExprClass:
2272 return VisitCXXConstructExpr(cast<CXXConstructExpr>(S), asc);
2274 case Stmt::CXXNewExprClass:
2275 return VisitCXXNewExpr(cast<CXXNewExpr>(S), asc);
2277 case Stmt::CXXDeleteExprClass:
2278 return VisitCXXDeleteExpr(cast<CXXDeleteExpr>(S), asc);
2280 case Stmt::CXXFunctionalCastExprClass:
2281 return VisitCXXFunctionalCastExpr(cast<CXXFunctionalCastExpr>(S), asc);
2283 case Stmt::CXXTemporaryObjectExprClass:
2284 return VisitCXXTemporaryObjectExpr(cast<CXXTemporaryObjectExpr>(S), asc);
2286 case Stmt::CXXThrowExprClass:
2287 return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
2289 case Stmt::CXXTryStmtClass:
2290 return VisitCXXTryStmt(cast<CXXTryStmt>(S));
2292 case Stmt::CXXTypeidExprClass:
2293 return VisitCXXTypeidExpr(cast<CXXTypeidExpr>(S), asc);
2295 case Stmt::CXXForRangeStmtClass:
2296 return VisitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
2298 case Stmt::DeclStmtClass:
2299 return VisitDeclStmt(cast<DeclStmt>(S));
2301 case Stmt::DefaultStmtClass:
2302 return VisitDefaultStmt(cast<DefaultStmt>(S));
2304 case Stmt::DoStmtClass:
2305 return VisitDoStmt(cast<DoStmt>(S));
2307 case Stmt::ForStmtClass:
2308 return VisitForStmt(cast<ForStmt>(S));
2310 case Stmt::GotoStmtClass:
2311 return VisitGotoStmt(cast<GotoStmt>(S));
2313 case Stmt::GCCAsmStmtClass:
2314 return VisitGCCAsmStmt(cast<GCCAsmStmt>(S), asc);
2316 case Stmt::IfStmtClass:
2317 return VisitIfStmt(cast<IfStmt>(S));
2319 case Stmt::ImplicitCastExprClass:
2320 return VisitImplicitCastExpr(cast<ImplicitCastExpr>(S), asc);
2322 case Stmt::ConstantExprClass:
2323 return VisitConstantExpr(cast<ConstantExpr>(S), asc);
2325 case Stmt::IndirectGotoStmtClass:
2326 return VisitIndirectGotoStmt(cast<IndirectGotoStmt>(S));
2328 case Stmt::LabelStmtClass:
2329 return VisitLabelStmt(cast<LabelStmt>(S));
2331 case Stmt::LambdaExprClass:
2332 return VisitLambdaExpr(cast<LambdaExpr>(S), asc);
2334 case Stmt::MaterializeTemporaryExprClass:
2335 return VisitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(S),
2338 case Stmt::MemberExprClass:
2339 return VisitMemberExpr(cast<MemberExpr>(S), asc);
2341 case Stmt::NullStmtClass:
2344 case Stmt::ObjCAtCatchStmtClass:
2345 return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
2347 case Stmt::ObjCAutoreleasePoolStmtClass:
2348 return VisitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(S));
2350 case Stmt::ObjCAtSynchronizedStmtClass:
2351 return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S));
2353 case Stmt::ObjCAtThrowStmtClass:
2354 return VisitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(S));
2356 case Stmt::ObjCAtTryStmtClass:
2357 return VisitObjCAtTryStmt(cast<ObjCAtTryStmt>(S));
2359 case Stmt::ObjCForCollectionStmtClass:
2360 return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
2362 case Stmt::ObjCMessageExprClass:
2363 return VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), asc);
2365 case Stmt::OpaqueValueExprClass:
2368 case Stmt::PseudoObjectExprClass:
2369 return VisitPseudoObjectExpr(cast<PseudoObjectExpr>(S));
2371 case Stmt::ReturnStmtClass:
2372 case Stmt::CoreturnStmtClass:
2373 return VisitReturnStmt(S);
2375 case Stmt::CoyieldExprClass:
2376 case Stmt::CoawaitExprClass:
2377 return VisitCoroutineSuspendExpr(cast<CoroutineSuspendExpr>(S), asc);
2379 case Stmt::SEHExceptStmtClass:
2380 return VisitSEHExceptStmt(cast<SEHExceptStmt>(S));
2382 case Stmt::SEHFinallyStmtClass:
2383 return VisitSEHFinallyStmt(cast<SEHFinallyStmt>(S));
2385 case Stmt::SEHLeaveStmtClass:
2386 return VisitSEHLeaveStmt(cast<SEHLeaveStmt>(S));
2388 case Stmt::SEHTryStmtClass:
2389 return VisitSEHTryStmt(cast<SEHTryStmt>(S));
2391 case Stmt::UnaryExprOrTypeTraitExprClass:
2392 return VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
2395 case Stmt::StmtExprClass:
2396 return VisitStmtExpr(cast<StmtExpr>(S), asc);
2398 case Stmt::SwitchStmtClass:
2399 return VisitSwitchStmt(cast<SwitchStmt>(S));
2401 case Stmt::UnaryOperatorClass:
2402 return VisitUnaryOperator(cast<UnaryOperator>(S), asc);
2404 case Stmt::WhileStmtClass:
2405 return VisitWhileStmt(cast<WhileStmt>(S));
2407 case Stmt::ArrayInitLoopExprClass:
2408 return VisitArrayInitLoopExpr(cast<ArrayInitLoopExpr>(S), asc);
2412CFGBlock *CFGBuilder::VisitStmt(
Stmt *S, AddStmtChoice asc) {
2413 if (asc.alwaysAdd(*
this, S)) {
2415 appendStmt(
Block, S);
2418 return VisitChildren(S);
2427 reverse_children RChildren(S);
2428 for (
Stmt *Child : RChildren) {
2437 if (asc.alwaysAdd(*
this, ILE)) {
2439 appendStmt(
Block, ILE);
2443 reverse_children RChildren(ILE);
2444 for (
Stmt *Child : RChildren) {
2450 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(Child))
2451 if (
Stmt *Child = DIE->getExpr())
2460 AddStmtChoice asc) {
2461 AddressTakenLabels.insert(A->
getLabel());
2463 if (asc.alwaysAdd(*
this, A)) {
2465 appendStmt(
Block, A);
2472 bool isFallthrough = hasSpecificAttr<FallThroughAttr>(A->
getAttrs());
2473 assert((!isFallthrough || isa<NullStmt>(A->
getSubStmt())) &&
2474 "expected fallthrough not to have children");
2475 return isFallthrough;
2479 AddStmtChoice asc) {
2490 appendStmt(
Block, A);
2493 return VisitChildren(A);
2497 if (asc.alwaysAdd(*
this,
U)) {
2502 if (
U->getOpcode() == UO_LNot)
2503 tryEvaluateBool(
U->getSubExpr()->IgnoreParens());
2505 return Visit(
U->getSubExpr(), AddStmtChoice());
2510 appendStmt(ConfluenceBlock, B);
2515 return VisitLogicalOperator(B,
nullptr, ConfluenceBlock,
2516 ConfluenceBlock).first;
2519std::pair<CFGBlock*, CFGBlock*>
2532 if (B_RHS->isLogicalOp()) {
2533 std::tie(RHSBlock, ExitBlock) =
2534 VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
2542 ExitBlock = RHSBlock = createBlock(
false);
2547 TryResult KnownVal = tryEvaluateBool(RHS);
2548 if (!KnownVal.isKnown())
2549 KnownVal = tryEvaluateBool(B);
2552 assert(TrueBlock == FalseBlock);
2553 addSuccessor(RHSBlock, TrueBlock);
2557 addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
2558 addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
2562 RHSBlock = addStmt(RHS);
2567 return std::make_pair(
nullptr,
nullptr);
2573 if (B_LHS->isLogicalOp()) {
2575 FalseBlock = RHSBlock;
2577 TrueBlock = RHSBlock;
2582 return VisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock);
2587 CFGBlock *LHSBlock = createBlock(
false);
2591 CFGBlock *EntryLHSBlock = addStmt(LHS);
2594 return std::make_pair(
nullptr,
nullptr);
2597 TryResult KnownVal = tryEvaluateBool(LHS);
2601 addSuccessor(LHSBlock, TrueBlock, !KnownVal.isFalse());
2602 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isTrue());
2605 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isFalse());
2606 addSuccessor(LHSBlock, FalseBlock, !KnownVal.isTrue());
2609 return std::make_pair(EntryLHSBlock, ExitBlock);
2613 AddStmtChoice asc) {
2616 return VisitLogicalOperator(B);
2620 appendStmt(
Block, B);
2622 return addStmt(B->
getLHS());
2626 if (asc.alwaysAdd(*
this, B)) {
2628 appendStmt(
Block, B);
2631 return Visit(B->
getRHS());
2634 if (asc.alwaysAdd(*
this, B)) {
2636 appendStmt(
Block, B);
2647 return (LBlock ? LBlock : RBlock);
2650CFGBlock *CFGBuilder::VisitNoRecurse(
Expr *
E, AddStmtChoice asc) {
2651 if (asc.alwaysAdd(*
this,
E)) {
2665 Block = createBlock(
false);
2670 if (BreakJumpTarget.block) {
2671 addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
2672 addSuccessor(
Block, BreakJumpTarget.block);
2696 QualType calleeType =
C->getCallee()->getType();
2702 if (!boundType.
isNull()) calleeType = boundType;
2708 bool AddEHEdge =
false;
2718 bool OmitArguments =
false;
2725 if (!FD->isVariadic())
2726 findConstructionContextsForArguments(
C);
2728 if (FD->isNoReturn() ||
C->isBuiltinAssumeFalse(*Context))
2730 if (FD->
hasAttr<NoThrowAttr>())
2732 if (FD->getBuiltinID() == Builtin::BI__builtin_object_size ||
2733 FD->getBuiltinID() == Builtin::BI__builtin_dynamic_object_size)
2734 OmitArguments =
true;
2737 if (!
CanThrow(
C->getCallee(), *Context))
2740 if (OmitArguments) {
2741 assert(!NoReturn &&
"noreturn calls with unevaluated args not implemented");
2742 assert(!AddEHEdge &&
"EH calls with unevaluated args not implemented");
2745 return Visit(
C->getCallee());
2748 if (!NoReturn && !AddEHEdge) {
2752 return VisitChildren(
C);
2762 Block = createNoReturnBlock();
2764 Block = createBlock();
2770 if (TryTerminatedBlock)
2771 addSuccessor(
Block, TryTerminatedBlock);
2773 addSuccessor(
Block, &cfg->getExit());
2776 return VisitChildren(
C);
2780 AddStmtChoice asc) {
2782 appendStmt(ConfluenceBlock,
C);
2786 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2787 Succ = ConfluenceBlock;
2789 CFGBlock *LHSBlock = Visit(
C->getLHS(), alwaysAdd);
2793 Succ = ConfluenceBlock;
2795 CFGBlock *RHSBlock = Visit(
C->getRHS(), alwaysAdd);
2799 Block = createBlock(
false);
2801 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2802 addSuccessor(
Block, KnownVal.isFalse() ?
nullptr : LHSBlock);
2803 addSuccessor(
Block, KnownVal.isTrue() ?
nullptr : RHSBlock);
2805 return addStmt(
C->getCond());
2809 bool ExternallyDestructed) {
2810 LocalScope::const_iterator scopeBeginPos = ScopePos;
2811 addLocalScopeForStmt(
C);
2813 if (!
C->body_empty() && !isa<ReturnStmt>(*
C->body_rbegin())) {
2816 addAutomaticObjHandling(ScopePos, scopeBeginPos,
C);
2821 for (
Stmt *S : llvm::reverse(
C->body())) {
2824 CFGBlock *newBlock = Visit(S, AddStmtChoice::AlwaysAdd,
2825 ExternallyDestructed);
2828 LastBlock = newBlock;
2833 ExternallyDestructed =
false;
2840 AddStmtChoice asc) {
2847 appendStmt(ConfluenceBlock,
C);
2851 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2857 Succ = ConfluenceBlock;
2860 const Expr *trueExpr =
C->getTrueExpr();
2861 if (trueExpr != opaqueValue) {
2862 LHSBlock = Visit(
C->getTrueExpr(), alwaysAdd);
2868 LHSBlock = ConfluenceBlock;
2871 Succ = ConfluenceBlock;
2872 CFGBlock *RHSBlock = Visit(
C->getFalseExpr(), alwaysAdd);
2878 dyn_cast<BinaryOperator>(
C->getCond()->IgnoreParens()))
2879 if (Cond->isLogicalOp())
2880 return VisitLogicalOperator(Cond,
C, LHSBlock, RHSBlock).first;
2883 Block = createBlock(
false);
2886 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2887 addSuccessor(
Block, LHSBlock, !KnownVal.isFalse());
2888 addSuccessor(
Block, RHSBlock, !KnownVal.isTrue());
2890 Expr *condExpr =
C->getCond();
2895 if (condExpr != opaqueValue)
2903 return addStmt(condExpr);
2914 return VisitDeclSubExpr(DS);
2928 cfg->addSyntheticDeclStmt(DSNew, DS);
2931 B = VisitDeclSubExpr(DSNew);
2940 assert(DS->
isSingleDecl() &&
"Can handle single declarations only.");
2942 if (
const auto *TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl())) {
2944 const Type *
T = TND->getUnderlyingType().getTypePtr();
2949 appendStmt(
Block, DS);
2953 VA =
FindVA(VA->getElementType().getTypePtr())) {
2954 if (
CFGBlock *NewBlock = addStmt(VA->getSizeExpr()))
2955 LastBlock = NewBlock;
2968 bool HasTemporaries =
false;
2971 CFGBlock *blockAfterStaticInit =
nullptr;
2982 blockAfterStaticInit = Succ;
2989 HasTemporaries = isa<ExprWithCleanups>(
Init);
2993 TempDtorContext Context;
2994 VisitForTemporaryDtors(cast<ExprWithCleanups>(
Init)->getSubExpr(),
3001 if (
const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
3002 for (
auto *BD : llvm::reverse(DD->bindings())) {
3003 if (
auto *VD = BD->getHoldingVar()) {
3007 cfg->addSyntheticDeclStmt(DSNew, DS);
3008 Block = VisitDeclSubExpr(DSNew);
3014 appendStmt(
Block, DS);
3018 const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(
Init);
3020 findConstructionContexts(
3022 AILE ? AILE->getSubExpr() :
Init);
3030 if (HasTemporaries) {
3035 LastBlock = newBlock;
3039 LastBlock = newBlock;
3047 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr())) {
3048 if (
CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
3049 LastBlock = newBlock;
3052 maybeAddScopeBeginForVarDecl(
Block, VD, DS);
3055 if (ScopePos && VD == *ScopePos)
3059 if (blockAfterStaticInit) {
3061 Block = createBlock(
false);
3063 addSuccessor(
Block, blockAfterStaticInit);
3064 addSuccessor(
Block, B);
3085 addLocalScopeForStmt(
Init);
3090 addLocalScopeForVarDecl(VD);
3092 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
3114 if (!isa<CompoundStmt>(Else))
3115 addLocalScopeAndDtors(Else);
3117 ElseBlock = addStmt(Else);
3120 ElseBlock = sv.get();
3137 if (!isa<CompoundStmt>(Then))
3138 addLocalScopeAndDtors(Then);
3140 ThenBlock = addStmt(Then);
3146 ThenBlock = createBlock(
false);
3147 addSuccessor(ThenBlock, sv.get());
3167 LastBlock = VisitLogicalOperator(Cond, I, ThenBlock, ElseBlock).first;
3170 Block = createBlock(
false);
3178 KnownVal = tryEvaluateBool(I->
getCond());
3182 addSuccessor(
Block, ThenBlock, !KnownVal.isFalse());
3183 addSuccessor(
Block, ElseBlock, !KnownVal.isTrue());
3188 LastBlock = addStmt(I->
getCond());
3194 LastBlock = addStmt(
const_cast<DeclStmt *
>(DS));
3201 LastBlock = addStmt(
Init);
3214 assert(isa<ReturnStmt>(S) || isa<CoreturnStmt>(S));
3217 Block = createBlock(
false);
3219 addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), S);
3221 if (
auto *R = dyn_cast<ReturnStmt>(S))
3222 findConstructionContexts(
3229 addSuccessor(
Block, &cfg->getExit());
3232 appendStmt(
Block, S);
3235 if (
ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
3236 if (
Expr *O = RS->getRetValue())
3237 return Visit(O, AddStmtChoice::AlwaysAdd,
true);
3247 if (RV->getType()->isVoidType() && !isa<InitListExpr>(RV))
3256 AddStmtChoice asc) {
3260 if (asc.alwaysAdd(*
this,
E)) {
3265 if (
auto *R = Visit(
E->getResumeExpr()))
3267 if (
auto *R = Visit(
E->getSuspendExpr()))
3269 if (
auto *R = Visit(
E->getReadyExpr()))
3271 if (
auto *R = Visit(
E->getCommonExpr()))
3286 if (!SEHExceptBlock)
3287 SEHExceptBlock = createBlock();
3289 appendStmt(SEHExceptBlock, ES);
3301 return SEHExceptBlock;
3305 return VisitCompoundStmt(FS->getBlock(),
false);
3315 Block = createBlock(
false);
3320 if (SEHLeaveJumpTarget.block) {
3321 addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS);
3322 addSuccessor(
Block, SEHLeaveJumpTarget.block);
3332 CFGBlock *SEHTrySuccessor =
nullptr;
3337 SEHTrySuccessor =
Block;
3338 }
else SEHTrySuccessor = Succ;
3344 CFGBlock *PrevSEHTryTerminatedBlock = TryTerminatedBlock;
3347 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
3354 Succ = SEHTrySuccessor;
3356 CFGBlock *ExceptBlock = VisitSEHExceptStmt(Except);
3361 addSuccessor(NewTryTerminatedBlock, ExceptBlock);
3363 if (PrevSEHTryTerminatedBlock)
3364 addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock);
3366 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
3369 Succ = SEHTrySuccessor;
3372 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
3373 cfg->addTryDispatchBlock(TryTerminatedBlock);
3379 SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
3381 assert(Terminator->
getTryBlock() &&
"__try must contain a non-NULL body");
3392 LabelBlock = createBlock();
3394 assert(!LabelMap.contains(L->
getDecl()) &&
"label already in map");
3395 LabelMap[L->
getDecl()] = JumpTarget(LabelBlock, ScopePos);
3415 CFGBlock *LastBlock = VisitNoRecurse(
E, asc);
3417 if (
Expr *CopyExpr = CI.getCopyExpr()) {
3427 CFGBlock *LastBlock = VisitNoRecurse(
E, asc);
3431 et =
E->capture_init_end();
3432 it != et; ++it, ++Idx) {
3437 dyn_cast<ArrayInitLoopExpr>(
Init));
3440 cfg->getBumpVectorContext(), {E, Idx}),
3441 AILEInit ? AILEInit :
Init);
3455 Block = createBlock(
false);
3459 LabelMapTy::iterator I = LabelMap.find(G->
getLabel());
3461 if (I == LabelMap.end())
3463 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3465 JumpTarget JT = I->second;
3466 addSuccessor(
Block, JT.block);
3467 addScopeChangesHandling(ScopePos, JT.scopePosition, G);
3478 return VisitStmt(G, asc);
3485 Block = createBlock();
3488 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3491 BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
3492 return VisitChildren(G);
3506 addLocalScopeForStmt(
Init);
3507 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3510 addLocalScopeForVarDecl(VD);
3511 LocalScope::const_iterator ContinueScopePos = ScopePos;
3513 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
3522 LoopSuccessor =
Block;
3524 LoopSuccessor = Succ;
3529 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3531 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3544 Block = Succ = TransitionBlock = createBlock(
false);
3545 TransitionBlock->setLoopTarget(F);
3550 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
3560 assert(
Block == Succ);
3568 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
3569 ContinueJumpTarget.block->setLoopTarget(F);
3574 if (!isa<CompoundStmt>(F->
getBody()))
3575 addLocalScopeAndDtors(F->
getBody());
3579 BodyBlock = addStmt(F->
getBody());
3584 BodyBlock = ContinueJumpTarget.block;
3593 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3602 dyn_cast_or_null<BinaryOperator>(
C ?
C->IgnoreParens() :
nullptr))
3604 std::tie(EntryConditionBlock, ExitConditionBlock) =
3605 VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor);
3610 EntryConditionBlock = ExitConditionBlock = createBlock(
false);
3611 ExitConditionBlock->setTerminator(F);
3614 TryResult KnownVal(
true);
3620 Block = ExitConditionBlock;
3621 EntryConditionBlock = addStmt(
C);
3630 findConstructionContexts(
3633 appendStmt(
Block, DS);
3634 EntryConditionBlock = addStmt(
Init);
3635 assert(
Block == EntryConditionBlock);
3636 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3640 if (
Block && badCFG)
3643 KnownVal = tryEvaluateBool(
C);
3647 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
3650 addSuccessor(ExitConditionBlock,
3651 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
3655 addSuccessor(TransitionBlock, EntryConditionBlock);
3658 Succ = EntryConditionBlock;
3664 ScopePos = LoopBeginScopePos;
3665 Block = createBlock();
3672 Succ = EntryConditionBlock;
3673 return EntryConditionBlock;
3678 AddStmtChoice asc) {
3679 findConstructionContexts(
3683 return VisitStmt(MTE, asc);
3687 if (asc.alwaysAdd(*
this, M)) {
3689 appendStmt(
Block, M);
3731 LoopSuccessor =
Block;
3734 LoopSuccessor = Succ;
3737 CFGBlock *ExitConditionBlock = createBlock(
false);
3745 appendStmt(ExitConditionBlock, S);
3746 Block = ExitConditionBlock;
3751 CFGBlock *EntryConditionBlock = Visit(S->getElement(),
3752 AddStmtChoice::NotAlwaysAdd);
3761 Succ = EntryConditionBlock;
3768 save_break(BreakJumpTarget);
3774 Succ = LoopBackBlock = createBlock();
3777 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3778 ContinueJumpTarget = JumpTarget(Succ, ScopePos);
3780 CFGBlock *BodyBlock = addStmt(S->getBody());
3783 BodyBlock = ContinueJumpTarget.block;
3790 addSuccessor(ExitConditionBlock, BodyBlock);
3795 addSuccessor(ExitConditionBlock, LoopSuccessor);
3798 Block = createBlock();
3799 return addStmt(S->getCollection());
3804 return addStmt(S->getSubStmt());
3812 CFGBlock *SyncBlock = addStmt(S->getSynchBody());
3826 appendStmt(
Block, S);
3829 return addStmt(S->getSynchExpr());
3842 for (
unsigned i =
E->getNumSemanticExprs(); i != 0; ) {
3843 Expr *Semantic =
E->getSemanticExpr(--i);
3848 Semantic = OVE->getSourceExpr();
3866 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3868 addLocalScopeForVarDecl(VD);
3869 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
3878 LoopSuccessor =
Block;
3881 LoopSuccessor = Succ;
3884 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3893 save_break(BreakJumpTarget);
3897 Succ = TransitionBlock = createBlock(
false);
3898 TransitionBlock->setLoopTarget(W);
3899 ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
3902 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3905 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
3909 if (!isa<CompoundStmt>(W->
getBody()))
3910 addLocalScopeAndDtors(W->
getBody());
3913 BodyBlock = addStmt(W->
getBody());
3916 BodyBlock = ContinueJumpTarget.block;
3917 else if (
Block && badCFG)
3924 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3931 if (
BinaryOperator *Cond = dyn_cast<BinaryOperator>(
C->IgnoreParens()))
3933 std::tie(EntryConditionBlock, ExitConditionBlock) =
3934 VisitLogicalOperator(Cond, W, BodyBlock, LoopSuccessor);
3939 ExitConditionBlock = createBlock(
false);
3945 Block = ExitConditionBlock;
3946 Block = EntryConditionBlock = addStmt(
C);
3955 findConstructionContexts(
3959 appendStmt(
Block, DS);
3960 EntryConditionBlock = addStmt(
Init);
3961 assert(
Block == EntryConditionBlock);
3962 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3966 if (
Block && badCFG)
3970 const TryResult& KnownVal = tryEvaluateBool(
C);
3973 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
3976 addSuccessor(ExitConditionBlock,
3977 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
3981 addSuccessor(TransitionBlock, EntryConditionBlock);
3988 Succ = EntryConditionBlock;
3989 return EntryConditionBlock;
3993 AddStmtChoice asc) {
3994 if (asc.alwaysAdd(*
this, A)) {
3996 appendStmt(
Block, A);
4005 assert(OVE &&
"ArrayInitLoopExpr->getCommonExpr() should be wrapped in an "
4006 "OpaqueValueExpr!");
4007 if (
CFGBlock *R = Visit(OVE->getSourceExpr()))
4026 CatchBlock = createBlock();
4028 appendStmt(CatchBlock, CS);
4049 Block = createBlock(
false);
4051 if (TryTerminatedBlock)
4053 addSuccessor(
Block, TryTerminatedBlock);
4056 addSuccessor(
Block, &cfg->getExit());
4060 return VisitStmt(S, AddStmtChoice::AlwaysAdd);
4071 TrySuccessor =
Block;
4073 TrySuccessor = Succ;
4079 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4082 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4086 bool HasCatchAll =
false;
4089 Succ = TrySuccessor;
4094 CFGBlock *CatchBlock = VisitObjCAtCatchStmt(CS);
4099 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4104 if (PrevTryTerminatedBlock)
4105 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4107 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4111 Succ = TrySuccessor;
4114 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4115 cfg->addTryDispatchBlock(TryTerminatedBlock);
4117 assert(Terminator->
getTryBody() &&
"try must contain a non-NULL body");
4123 AddStmtChoice asc) {
4124 findConstructionContextsForArguments(ME);
4127 appendObjCMessage(
Block, ME);
4129 return VisitChildren(ME);
4138 Block = createBlock(
false);
4140 if (TryTerminatedBlock)
4142 addSuccessor(
Block, TryTerminatedBlock);
4145 addSuccessor(
Block, &cfg->getExit());
4149 return VisitStmt(
T, AddStmtChoice::AlwaysAdd);
4153 if (asc.alwaysAdd(*
this, S)) {
4155 appendStmt(
Block, S);
4164 if (!S->isTypeDependent() && S->isPotentiallyEvaluated())
4165 return VisitChildren(S);
4181 LoopSuccessor =
Block;
4183 LoopSuccessor = Succ;
4188 CFGBlock *ExitConditionBlock = createBlock(
false);
4189 CFGBlock *EntryConditionBlock = ExitConditionBlock;
4196 if (
Stmt *
C =
D->getCond()) {
4197 Block = ExitConditionBlock;
4198 EntryConditionBlock = addStmt(
C);
4206 Succ = EntryConditionBlock;
4209 const TryResult &KnownVal = tryEvaluateBool(
D->getCond());
4219 save_break(BreakJumpTarget);
4222 ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
4225 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4232 if (!isa<CompoundStmt>(
D->
getBody()))
4233 addLocalScopeAndDtors(
D->
getBody());
4239 BodyBlock = EntryConditionBlock;
4252 CFGBlock *LoopBackBlock = createBlock();
4255 if (!KnownVal.isFalse())
4257 addSuccessor(ExitConditionBlock, LoopBackBlock);
4259 addSuccessor(ExitConditionBlock,
nullptr);
4264 addSuccessor(ExitConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4282 Block = createBlock(
false);
4287 if (ContinueJumpTarget.block) {
4288 addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition,
C);
4289 addSuccessor(
Block, ContinueJumpTarget.block);
4297 AddStmtChoice asc) {
4298 if (asc.alwaysAdd(*
this,
E)) {
4306 if (
E->getKind() != UETT_SizeOf)
4311 if (
E->isArgumentType()) {
4313 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr()))
4314 lastBlock = addStmt(VA->getSizeExpr());
4322 if (asc.alwaysAdd(*
this, SE)) {
4324 appendStmt(
Block, SE);
4326 return VisitCompoundStmt(SE->
getSubStmt(),
true);
4332 CFGBlock *SwitchSuccessor =
nullptr;
4340 addLocalScopeForStmt(
Init);
4345 addLocalScopeForVarDecl(VD);
4347 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
4352 SwitchSuccessor =
Block;
4353 }
else SwitchSuccessor = Succ;
4357 save_default(DefaultCaseBlock);
4363 DefaultCaseBlock = SwitchSuccessor;
4366 SwitchTerminatedBlock = createBlock(
false);
4370 Succ = SwitchSuccessor;
4371 BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
4376 assert(Terminator->
getBody() &&
"switch must contain a non-NULL body");
4381 SaveAndRestore save_switchExclusivelyCovered(switchExclusivelyCovered,
false);
4384 assert(Terminator->
getCond() &&
"switch condition must be non-NULL");
4386 bool b = tryEvaluate(Terminator->
getCond(), result);
4391 if (!isa<CompoundStmt>(Terminator->
getBody()))
4392 addLocalScopeAndDtors(Terminator->
getBody());
4394 addStmt(Terminator->
getBody());
4406 bool SwitchAlwaysHasSuccessor =
false;
4407 SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
4410 addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock,
4411 !SwitchAlwaysHasSuccessor);
4415 Block = SwitchTerminatedBlock;
4424 LastBlock = addStmt(
Init);
4425 maybeAddScopeBeginForVarDecl(LastBlock, VD,
Init);
4432 LastBlock = addStmt(
Init);
4445 bool addCase =
false;
4447 if (!switchExclusivelyCovered) {
4451 const llvm::APSInt &condInt = switchCond->
Val.
getInt();
4453 if (condInt == lhsInt) {
4455 switchExclusivelyCovered =
true;
4457 else if (condInt > lhsInt) {
4461 if (V2 >= condInt) {
4463 switchExclusivelyCovered =
true;
4477 CFGBlock *TopBlock =
nullptr, *LastBlock =
nullptr;
4483 while (isa<CaseStmt>(Sub)) {
4484 CFGBlock *currentBlock = createBlock(
false);
4488 addSuccessor(LastBlock, currentBlock);
4490 TopBlock = currentBlock;
4492 addSuccessor(SwitchTerminatedBlock,
4495 ? currentBlock :
nullptr);
4497 LastBlock = currentBlock;
4498 CS = cast<CaseStmt>(Sub);
4507 CaseBlock = createBlock();
4518 assert(SwitchTerminatedBlock);
4519 addSuccessor(SwitchTerminatedBlock, CaseBlock,
4527 addSuccessor(LastBlock, CaseBlock);
4541 DefaultCaseBlock =
Block;
4543 if (!DefaultCaseBlock)
4544 DefaultCaseBlock = createBlock();
4548 DefaultCaseBlock->
setLabel(Terminator);
4563 Succ = DefaultCaseBlock;
4565 return DefaultCaseBlock;
4576 TrySuccessor =
Block;
4578 TrySuccessor = Succ;
4580 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4583 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4587 bool HasCatchAll =
false;
4590 Succ = TrySuccessor;
4596 CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
4601 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4604 if (PrevTryTerminatedBlock)
4605 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4607 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4611 Succ = TrySuccessor;
4614 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4615 cfg->addTryDispatchBlock(TryTerminatedBlock);
4617 assert(Terminator->
getTryBlock() &&
"try must contain a non-NULL body");
4633 LocalScope::const_iterator BeginScopePos = ScopePos;
4634 addLocalScopeForVarDecl(VD);
4635 addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
4643 CatchBlock = createBlock();
4649 appendStmt(CatchBlock, CS);
4684 addLocalScopeForStmt(
Range);
4686 addLocalScopeForStmt(
Begin);
4687 if (
Stmt *End = S->getEndStmt())
4688 addLocalScopeForStmt(End);
4689 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
4691 LocalScope::const_iterator ContinueScopePos = ScopePos;
4699 LoopSuccessor =
Block;
4701 LoopSuccessor = Succ;
4706 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4709 CFGBlock *ConditionBlock = createBlock(
false);
4713 if (
Expr *
C = S->getCond()) {
4714 Block = ConditionBlock;
4715 CFGBlock *BeginConditionBlock = addStmt(
C);
4718 assert(BeginConditionBlock == ConditionBlock &&
4719 "condition block in for-range was unexpectedly complex");
4720 (void)BeginConditionBlock;
4725 Succ = ConditionBlock;
4728 TryResult KnownVal(
true);
4731 KnownVal = tryEvaluateBool(S->getCond());
4735 assert(S->getBody());
4744 Succ = addStmt(S->getInc());
4747 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
4751 ContinueJumpTarget.block->setLoopTarget(S);
4760 addLocalScopeAndDtors(S->getLoopVarStmt());
4764 if (!isa<CompoundStmt>(S->getBody()))
4765 addLocalScopeAndDtors(S->getBody());
4768 addStmt(S->getBody());
4772 CFGBlock *LoopVarStmtBlock = addStmt(S->getLoopVarStmt());
4777 addSuccessor(ConditionBlock,
4778 KnownVal.isFalse() ?
nullptr : LoopVarStmtBlock);
4783 addSuccessor(ConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4786 Block = createBlock();
4787 addStmt(S->getBeginStmt());
4788 addStmt(S->getEndStmt());
4789 CFGBlock *Head = addStmt(S->getRangeStmt());
4791 Head = addStmt(S->getInit());
4796 AddStmtChoice asc,
bool ExternallyDestructed) {
4800 TempDtorContext Context;
4801 VisitForTemporaryDtors(
E->getSubExpr(), ExternallyDestructed, Context);
4805 asc = asc.withAlwaysAdd(
true);
4807 return Visit(
E->getSubExpr(), asc);
4811 AddStmtChoice asc) {
4812 if (asc.alwaysAdd(*
this,
E)) {
4816 findConstructionContexts(
4821 asc = asc.withAlwaysAdd(
false);
4823 return Visit(
E->getSubExpr(), asc);
4827 AddStmtChoice asc) {
4831 findConstructionContextsForArguments(
C);
4834 appendConstructor(
Block,
C);
4836 return VisitChildren(
C);
4840 AddStmtChoice asc) {
4842 appendStmt(
Block, NE);
4844 findConstructionContexts(
4848 if (
NE->getInitializer())
4849 Block = Visit(
NE->getInitializer());
4852 appendNewAllocator(
Block, NE);
4854 if (
NE->isArray() && *
NE->getArraySize())
4855 Block = Visit(*
NE->getArraySize());
4858 E =
NE->placement_arg_end(); I !=
E; ++I)
4865 AddStmtChoice asc) {
4867 appendStmt(
Block, DE);
4874 appendDeleteDtor(
Block, RD, DE);
4878 return VisitChildren(DE);
4882 AddStmtChoice asc) {
4883 if (asc.alwaysAdd(*
this,
E)) {
4887 asc = asc.withAlwaysAdd(
false);
4889 return Visit(
E->getSubExpr(), asc);
4893 AddStmtChoice asc) {
4897 findConstructionContextsForArguments(
C);
4900 appendConstructor(
Block,
C);
4901 return VisitChildren(
C);
4905 AddStmtChoice asc) {
4906 if (asc.alwaysAdd(*
this,
E)) {
4911 if (
E->getCastKind() == CK_IntegralToBoolean)
4914 return Visit(
E->getSubExpr(), AddStmtChoice());
4918 return Visit(
E->getSubExpr(), AddStmtChoice());
4923 CFGBlock *IBlock = cfg->getIndirectGotoBlock();
4926 IBlock = createBlock(
false);
4927 cfg->setIndirectGotoBlock(IBlock);
4935 Block = createBlock(
false);
4937 addSuccessor(
Block, IBlock);
4941CFGBlock *CFGBuilder::VisitForTemporaryDtors(
Stmt *
E,
bool ExternallyDestructed,
4942 TempDtorContext &Context) {
4952 return VisitChildrenForTemporaryDtors(
E,
false, Context);
4954 case Stmt::InitListExprClass:
4955 return VisitChildrenForTemporaryDtors(
E, ExternallyDestructed, Context);
4957 case Stmt::BinaryOperatorClass:
4958 return VisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(
E),
4959 ExternallyDestructed,
4962 case Stmt::CXXBindTemporaryExprClass:
4963 return VisitCXXBindTemporaryExprForTemporaryDtors(
4964 cast<CXXBindTemporaryExpr>(
E), ExternallyDestructed, Context);
4966 case Stmt::BinaryConditionalOperatorClass:
4967 case Stmt::ConditionalOperatorClass:
4968 return VisitConditionalOperatorForTemporaryDtors(
4969 cast<AbstractConditionalOperator>(
E), ExternallyDestructed, Context);
4971 case Stmt::ImplicitCastExprClass:
4973 E = cast<CastExpr>(
E)->getSubExpr();
4976 case Stmt::CXXFunctionalCastExprClass:
4978 E = cast<CXXFunctionalCastExpr>(
E)->getSubExpr();
4981 case Stmt::ConstantExprClass:
4982 E = cast<ConstantExpr>(
E)->getSubExpr();
4985 case Stmt::ParenExprClass:
4986 E = cast<ParenExpr>(
E)->getSubExpr();
4989 case Stmt::MaterializeTemporaryExprClass: {
4995 E =
const_cast<Expr *
>(
4996 cast<MaterializeTemporaryExpr>(
E)
4998 ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
5000 for (
const Expr *CommaLHS : CommaLHSs) {
5001 VisitForTemporaryDtors(
const_cast<Expr *
>(CommaLHS),
5007 case Stmt::BlockExprClass:
5012 case Stmt::LambdaExprClass: {
5015 auto *
LE = cast<LambdaExpr>(
E);
5019 if (
CFGBlock *R = VisitForTemporaryDtors(
5020 Init,
true, Context))
5027 case Stmt::StmtExprClass:
5032 case Stmt::CXXDefaultArgExprClass:
5033 E = cast<CXXDefaultArgExpr>(
E)->getExpr();
5036 case Stmt::CXXDefaultInitExprClass:
5037 E = cast<CXXDefaultInitExpr>(
E)->getExpr();
5042CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(
Stmt *
E,
5043 bool ExternallyDestructed,
5044 TempDtorContext &Context) {
5045 if (isa<LambdaExpr>(
E)) {
5057 if (
CFGBlock *R = VisitForTemporaryDtors(Child, ExternallyDestructed, Context))
5063CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
5064 BinaryOperator *
E,
bool ExternallyDestructed, TempDtorContext &Context) {
5065 if (
E->isCommaOp()) {
5068 CFGBlock *LHSBlock = VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5069 CFGBlock *RHSBlock = VisitForTemporaryDtors(
E->getRHS(), ExternallyDestructed, Context);
5070 return RHSBlock ? RHSBlock : LHSBlock;
5073 if (
E->isLogicalOp()) {
5074 VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5075 TryResult RHSExecuted = tryEvaluateBool(
E->getLHS());
5076 if (RHSExecuted.isKnown() &&
E->getOpcode() == BO_LOr)
5077 RHSExecuted.negate();
5082 TempDtorContext RHSContext(
5084 VisitForTemporaryDtors(
E->getRHS(),
false, RHSContext);
5085 InsertTempDtorDecisionBlock(RHSContext);
5090 if (
E->isAssignmentOp()) {
5093 CFGBlock *RHSBlock = VisitForTemporaryDtors(
E->getRHS(),
false, Context);
5094 CFGBlock *LHSBlock = VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5095 return LHSBlock ? LHSBlock : RHSBlock;
5099 return VisitChildrenForTemporaryDtors(
E, ExternallyDestructed, Context);
5102CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
5106 CFGBlock *B = VisitForTemporaryDtors(
E->getSubExpr(),
true, Context);
5107 if (!ExternallyDestructed) {
5119 Block = createNoReturnBlock();
5120 }
else if (Context.needsTempDtorBranch()) {
5124 Block = createBlock();
5128 if (Context.needsTempDtorBranch()) {
5129 Context.setDecisionPoint(Succ,
E);
5131 appendTemporaryDtor(
Block,
E);
5138void CFGBuilder::InsertTempDtorDecisionBlock(
const TempDtorContext &Context,
5140 if (!Context.TerminatorExpr) {
5144 assert(Context.TerminatorExpr);
5145 CFGBlock *Decision = createBlock(
false);
5148 addSuccessor(Decision,
Block, !Context.KnownExecuted.isFalse());
5149 addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
5150 !Context.KnownExecuted.isTrue());
5154CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
5156 TempDtorContext &Context) {
5157 VisitForTemporaryDtors(
E->getCond(),
false, Context);
5160 TryResult ConditionVal = tryEvaluateBool(
E->getCond());
5161 TryResult NegatedVal = ConditionVal;
5162 if (NegatedVal.isKnown()) NegatedVal.negate();
5164 TempDtorContext TrueContext(
5166 VisitForTemporaryDtors(
E->getTrueExpr(), ExternallyDestructed, TrueContext);
5169 Block = ConditionBlock;
5170 Succ = ConditionSucc;
5171 TempDtorContext FalseContext(
5173 VisitForTemporaryDtors(
E->getFalseExpr(), ExternallyDestructed, FalseContext);
5175 if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
5176 InsertTempDtorDecisionBlock(FalseContext, TrueBlock);
5177 }
else if (TrueContext.TerminatorExpr) {
5179 InsertTempDtorDecisionBlock(TrueContext);
5181 InsertTempDtorDecisionBlock(FalseContext);
5187 AddStmtChoice asc) {
5188 if (asc.alwaysAdd(*
this,
D)) {
5200 for (
Stmt *S : llvm::reverse(
Used)) {
5201 assert(S &&
"Expected non-null used-in-clause child.");
5206 if (!
D->isStandaloneDirective()) {
5207 Stmt *S =
D->getRawStmt();
5208 if (!isa<CompoundStmt>(S))
5209 addLocalScopeAndDtors(S);
5221 bool first_block =
begin() ==
end();
5229 Entry = Exit = &
back();
5238 CFGBuilder Builder(
C, BO);
5239 return Builder.buildCFG(
D, Statement);
5254 auto IteratorAndFlag =
Visited.insert(B);
5255 if (!IteratorAndFlag.second) {
5261 const CFGBlock *FirstReachableB =
nullptr;
5263 if (!AB.isReachable())
5266 if (FirstReachableB ==
nullptr) {
5267 FirstReachableB = &*AB;
5274 if (!FirstReachableB) {
5280 B = FirstReachableB;
5300 llvm_unreachable(
"getDestructorDecl should only be used with "
5303 const VarDecl *var = castAs<CFGAutomaticObjDtor>().getVarDecl();
5311 if (
const Expr *
Init = var->getInit()) {
5329 const CXXDeleteExpr *DE = castAs<CFGDeleteDtor>().getDeleteExpr();
5338 castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
5343 const FieldDecl *field = castAs<CFGMemberDtor>().getFieldDecl();
5358 llvm_unreachable(
"getKind() returned bogus value");
5366 : ReachableBlock(IsReachable ? B : nullptr),
5367 UnreachableBlock(!IsReachable ? B : nullptr,
5368 B && IsReachable ? AB_Normal : AB_Unreachable) {}
5371 : ReachableBlock(B),
5372 UnreachableBlock(B == AlternateBlock ? nullptr : AlternateBlock,
5373 B == AlternateBlock ? AB_Alternate : AB_Normal) {}
5396 if (S->isAllEnumCasesCovered()) {
5398 if (!L || !isa<CaseStmt>(L))
5414 using StmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>;
5415 using DeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>;
5419 signed currentBlock = 0;
5420 unsigned currStmt = 0;
5431 BI != BEnd; ++BI, ++j ) {
5432 if (std::optional<CFGStmt> SE = BI->getAs<
CFGStmt>()) {
5434 std::pair<unsigned, unsigned>
P((*I)->getBlockID(), j);
5437 switch (
stmt->getStmtClass()) {
5438 case Stmt::DeclStmtClass:
5439 DeclMap[cast<DeclStmt>(
stmt)->getSingleDecl()] =
P;
5441 case Stmt::IfStmtClass: {
5442 const VarDecl *var = cast<IfStmt>(
stmt)->getConditionVariable();
5447 case Stmt::ForStmtClass: {
5448 const VarDecl *var = cast<ForStmt>(
stmt)->getConditionVariable();
5453 case Stmt::WhileStmtClass: {
5455 cast<WhileStmt>(
stmt)->getConditionVariable();
5460 case Stmt::SwitchStmtClass: {
5462 cast<SwitchStmt>(
stmt)->getConditionVariable();
5467 case Stmt::CXXCatchStmtClass: {
5469 cast<CXXCatchStmt>(
stmt)->getExceptionDecl();
5482 ~StmtPrinterHelper()
override =
default;
5484 const LangOptions &getLangOpts()
const {
return LangOpts; }
5485 void setBlockID(
signed i) { currentBlock = i; }
5486 void setStmtID(
unsigned i) { currStmt = i; }
5488 bool handledStmt(
Stmt *S, raw_ostream &OS)
override {
5489 StmtMapTy::iterator I = StmtMap.find(S);
5491 if (I == StmtMap.end())
5494 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5495 && I->second.second == currStmt) {
5499 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5503 bool handleDecl(
const Decl *
D, raw_ostream &OS) {
5504 DeclMapTy::iterator I = DeclMap.find(
D);
5506 if (I == DeclMap.end())
5509 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5510 && I->second.second == currStmt) {
5514 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5519class CFGBlockTerminatorPrint
5520 :
public StmtVisitor<CFGBlockTerminatorPrint,void> {
5522 StmtPrinterHelper* Helper;
5526 CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
5528 : OS(os), Helper(helper), Policy(Policy) {
5532 void VisitIfStmt(
IfStmt *I) {
5535 C->printPretty(OS, Helper, Policy);
5539 void VisitStmt(
Stmt *Terminator) {
5545 OS <<
"static init " << VD->
getName();
5548 void VisitForStmt(
ForStmt *F) {
5554 C->printPretty(OS, Helper, Policy);
5564 C->printPretty(OS, Helper, Policy);
5568 OS <<
"do ... while ";
5569 if (
Stmt *
C =
D->getCond())
5570 C->printPretty(OS, Helper, Policy);
5573 void VisitSwitchStmt(
SwitchStmt *Terminator) {
5578 void VisitCXXTryStmt(
CXXTryStmt *) { OS <<
"try ..."; }
5580 void VisitObjCAtTryStmt(
ObjCAtTryStmt *) { OS <<
"@try ..."; }
5582 void VisitSEHTryStmt(
SEHTryStmt *CS) { OS <<
"__try ..."; }
5585 if (
Stmt *Cond =
C->getCond())
5587 OS <<
" ? ... : ...";
5591 OS <<
"__builtin_choose_expr( ";
5592 if (
Stmt *Cond =
C->getCond())
5600 T->printPretty(OS, Helper, Policy);
5620 llvm_unreachable(
"Invalid logical operator.");
5624 void VisitExpr(
Expr *
E) {
5630 switch (
T.getKind()) {
5635 OS <<
"(Temp Dtor) ";
5639 OS <<
"(See if most derived ctor has already initialized vbases)";
5657 IE->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
5661 OS <<
" (Base initializer)";
5663 OS <<
" (Delegating initializer)";
5665 OS <<
" (Member initializer)";
5669 StmtPrinterHelper &Helper,
5675 const auto *SICC = cast<SimpleConstructorInitializerConstructionContext>(CC);
5682 cast<CXX17ElidedCopyConstructorInitializerConstructionContext>(CC);
5684 Stmts.push_back(CICC->getCXXBindTemporaryExpr());
5688 const auto *SDSCC = cast<SimpleVariableConstructionContext>(CC);
5689 Stmts.push_back(SDSCC->getDeclStmt());
5693 const auto *CDSCC = cast<CXX17ElidedCopyVariableConstructionContext>(CC);
5694 Stmts.push_back(CDSCC->getDeclStmt());
5695 Stmts.push_back(CDSCC->getCXXBindTemporaryExpr());
5699 const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
5700 Stmts.push_back(NECC->getCXXNewExpr());
5704 const auto *RSCC = cast<SimpleReturnedValueConstructionContext>(CC);
5705 Stmts.push_back(RSCC->getReturnStmt());
5710 cast<CXX17ElidedCopyReturnedValueConstructionContext>(CC);
5711 Stmts.push_back(RSCC->getReturnStmt());
5712 Stmts.push_back(RSCC->getCXXBindTemporaryExpr());
5716 const auto *TOCC = cast<SimpleTemporaryObjectConstructionContext>(CC);
5717 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5718 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5722 const auto *TOCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
5723 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5724 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5725 Stmts.push_back(TOCC->getConstructorAfterElision());
5729 const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
5730 Helper.handledStmt(
const_cast<LambdaExpr *
>(LCC->getLambdaExpr()), OS);
5731 OS <<
"+" << LCC->getIndex();
5735 const auto *ACC = cast<ArgumentConstructionContext>(CC);
5736 if (
const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
5738 Helper.handledStmt(
const_cast<Stmt *
>(BTE), OS);
5741 Helper.handledStmt(
const_cast<Expr *
>(ACC->getCallLikeExpr()), OS);
5742 OS <<
"+" << ACC->getIndex();
5749 Helper.handledStmt(
const_cast<Stmt *
>(I), OS);
5753static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5758 StmtPrinterHelper Helper(
nullptr, LangOpts);
5762static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5764 switch (
E.getKind()) {
5770 assert(S !=
nullptr &&
"Expecting non-null Stmt");
5773 if (
const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
5776 auto Children = Sub->children();
5777 if (Children.begin() != Children.end()) {
5788 Helper.handledStmt(B->
getRHS(),OS);
5793 S->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
5796 if (isa<CXXOperatorCallExpr>(S))
5797 OS <<
" (OperatorCall)";
5798 OS <<
" (CXXRecordTypedCall";
5801 }
else if (isa<CXXOperatorCallExpr>(S)) {
5802 OS <<
" (OperatorCall)";
5803 }
else if (isa<CXXBindTemporaryExpr>(S)) {
5804 OS <<
" (BindTemporary)";
5806 OS <<
" (CXXConstructExpr";
5810 OS <<
", " << CCE->getType() <<
")";
5811 }
else if (
const CastExpr *CE = dyn_cast<CastExpr>(S)) {
5813 <<
", " << CE->
getType() <<
")";
5831 Helper.handleDecl(VD, OS);
5838 T.getUnqualifiedType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5839 OS <<
"() (Implicit destructor)\n";
5844 OS <<
"CleanupFunction ("
5850 OS <<
" (Lifetime ends)\n";
5854 OS <<
E.castAs<
CFGLoopExit>().getLoopStmt()->getStmtClassName() <<
" (LoopExit)\n";
5858 OS <<
"CFGScopeBegin(";
5865 OS <<
"CFGScopeEnd(";
5872 OS <<
"CFGNewAllocator(";
5874 AllocExpr->getType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5885 Helper.handledStmt(cast<Stmt>(DelExpr->
getArgument()), OS);
5886 OS <<
"->~" << RD->getName().str() <<
"()";
5887 OS <<
" (Implicit destructor)\n";
5894 OS <<
" (Base object destructor)\n";
5901 OS <<
"this->" << FD->
getName();
5903 OS <<
" (Member object destructor)\n";
5912 OS <<
"() (Temporary object destructor)\n";
5920 StmtPrinterHelper &Helper,
bool print_edges,
5926 OS.changeColor(raw_ostream::YELLOW,
true);
5931 OS <<
" (ENTRY)]\n";
5932 else if (&B == &cfg->
getExit())
5935 OS <<
" (INDIRECT GOTO DISPATCH)]\n";
5937 OS <<
" (NORETURN)]\n";
5953 if (
const Expr *LHS =
C->getLHS())
5955 if (
const Expr *RHS =
C->getRHS()) {
5959 }
else if (isa<DefaultStmt>(
Label))
5970 if (
const VarDecl *PD = CS->getCatchParamDecl())
5981 llvm_unreachable(
"Invalid label statement in CFGBlock.");
5990 I !=
E ; ++I, ++j ) {
5995 OS << llvm::format(
"%3d", j) <<
": ";
5997 Helper.setStmtID(j);
6005 OS.changeColor(raw_ostream::GREEN);
6009 Helper.setBlockID(-1);
6012 CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
6023 const raw_ostream::Colors Color = raw_ostream::BLUE;
6025 OS.changeColor(Color);
6033 OS.changeColor(Color);
6041 bool Reachable =
true;
6044 B = I->getPossiblyUnreachableBlock();
6049 OS <<
"(Unreachable)";
6060 const raw_ostream::Colors Color = raw_ostream::MAGENTA;
6062 OS.changeColor(Color);
6070 OS.changeColor(Color);
6079 bool Reachable =
true;
6082 B = I->getPossiblyUnreachableBlock();
6088 OS <<
"(Unreachable)";
6109 StmtPrinterHelper Helper(
this, LO);
6117 if (&(**I) == &getEntry() || &(**I) == &getExit())
6147 StmtPrinterHelper Helper(cfg, LO);
6155 CFGBlockTerminatorPrint TPrinter(OS,
nullptr,
PrintingPolicy(LO));
6161 bool AddQuotes)
const {
6163 llvm::raw_string_ostream TempOut(Buf);
6186 if (llvm::any_of(*Blk, [](
const CFGElement &Elm) {
6187 if (std::optional<CFGStmt> StmtElm = Elm.
getAs<
CFGStmt>())
6188 if (isa<CXXThrowExpr>(StmtElm->getStmt()))
6207 DFSWorkList.push_back(StartBlk);
6208 while (!DFSWorkList.empty()) {
6209 const CFGBlock *Blk = DFSWorkList.back();
6210 DFSWorkList.pop_back();
6220 for (
const auto &Succ : Blk->
succs()) {
6221 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
6225 DFSWorkList.push_back(SuccBlk);
6254 const Stmt *Cond = StmtElem->getStmt();
6255 if (isa<ObjCForCollectionStmt>(Cond) || isa<DeclStmt>(Cond))
6274 case Stmt::CXXForRangeStmtClass:
6278 case Stmt::ForStmtClass:
6282 case Stmt::WhileStmtClass:
6286 case Stmt::DoStmtClass:
6290 case Stmt::IfStmtClass:
6294 case Stmt::ChooseExprClass:
6298 case Stmt::IndirectGotoStmtClass:
6299 E = cast<IndirectGotoStmt>(
Terminator)->getTarget();
6302 case Stmt::SwitchStmtClass:
6306 case Stmt::BinaryConditionalOperatorClass:
6307 E = cast<BinaryConditionalOperator>(
Terminator)->getCond();
6310 case Stmt::ConditionalOperatorClass:
6311 E = cast<ConditionalOperator>(
Terminator)->getCond();
6314 case Stmt::BinaryOperatorClass:
6318 case Stmt::ObjCForCollectionStmtClass:
6335 StmtPrinterHelper H(
this, LO);
6337 llvm::ViewGraph(
this,
"CFG");
6348 std::string OutSStr;
6349 llvm::raw_string_ostream Out(OutSStr);
6351 std::string& OutStr = Out.str();
6353 if (OutStr[0] ==
'\n') OutStr.erase(OutStr.begin());
6356 for (
unsigned i = 0; i != OutStr.length(); ++i)
6357 if (OutStr[i] ==
'\n') {
6359 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 void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const CFGElement &E)
static const Expr * tryTransformToIntOrEnumConstant(const Expr *E)
Helper for tryNormalizeBinaryOperator.
static void print_initializer(raw_ostream &OS, StmtPrinterHelper &Helper, const CXXCtorInitializer *I)
static bool IsIntegerLiteralConstantExpr(const Expr *E)
Returns true on constant values based around a single IntegerLiteral.
static SourceLocation GetEndLoc(Decl *D)
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 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 void print_construction_context(raw_ostream &OS, StmtPrinterHelper &Helper, const ConstructionContext *CC)
static bool shouldAddCase(bool &switchExclusivelyCovered, const Expr::EvalResult *switchCond, const CaseStmt *CS, ASTContext &Ctx)
static bool areExprTypesCompatible(const Expr *E1, const Expr *E2)
For an expression x == Foo && x == Bar, this determines whether the Foo and Bar are either of the sam...
static TryResult bothKnownTrue(TryResult R1, TryResult R2)
clang::CharUnits operator*(clang::CharUnits::QuantityType Scale, const clang::CharUnits &CU)
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.
llvm::DenseSet< const void * > Visited
static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::LangOptions interface.
Defines the clang::SourceLocation class and associated facilities.
Defines various enumerations that describe declaration and type specifiers.
Defines the Objective-C statement AST node classes.
C Language Family Type Representation.
llvm::APInt getValue() const
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
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.
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
AddrLabelExpr - The GNU address of label extension, representing &&label.
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
BinaryConditionalOperator - The GNU extension to the conditional operator which allows the middle ope...
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 isAssignmentOp(Opcode Opc)
static bool isEqualityOp(Opcode Opc)
A class which contains all the information about a particular captured value.
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
BreakStmt - This represents a break.
void push_back(const_reference Elt, BumpVectorContext &C)
Represents C++ object destructor implicitly generated for automatic object or temporary bound to cons...
const VarDecl * getVarDecl() const
Represents C++ object destructor implicitly generated for base object in destructor.
This class represents a potential adjacent block in the CFG.
AdjacentBlock(CFGBlock *B, bool IsReachable)
Construct an AdjacentBlock with a possibly unreachable block.
CFGBlock * getReachableBlock() const
Get the reachable block, if one exists.
CFGBlock * getPossiblyUnreachableBlock() const
Get the potentially unreachable block.
unsigned IgnoreNullPredecessors
unsigned IgnoreDefaultsWithCoveredEnums
Represents a single basic block in a source-level CFG.
void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C)
void printTerminator(raw_ostream &OS, const LangOptions &LO) const
printTerminator - A simple pretty printer of the terminator of a CFGBlock.
void setLoopTarget(const Stmt *loopTarget)
bool isInevitablySinking() const
Returns true if the block would eventually end with a sink (a noreturn node).
size_t getIndexInCFG() const
void appendScopeBegin(const VarDecl *VD, const Stmt *S, BumpVectorContext &C)
static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src, const CFGBlock *Dst)
reverse_iterator rbegin()
void setTerminator(CFGTerminator Term)
void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C)
void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C)
void print(raw_ostream &OS, const CFG *cfg, const LangOptions &LO, bool ShowColors) const
print - A simple pretty printer of a CFGBlock that outputs to an ostream.
ElementList::const_iterator const_iterator
bool hasNoReturnElement() const
void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C)
void appendScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C)
void appendInitializer(CXXCtorInitializer *initializer, BumpVectorContext &C)
void printTerminatorJson(raw_ostream &Out, const LangOptions &LO, bool AddQuotes) const
printTerminatorJson - Pretty-prints the terminator in JSON format.
void appendNewAllocator(CXXNewExpr *NE, BumpVectorContext &C)
Stmt * Label
An (optional) label that prefixes the executable statements in the block.
CFGTerminator getTerminator() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C)
AdjacentBlocks::const_iterator const_pred_iterator
unsigned pred_size() const
void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C)
void appendCXXRecordTypedCall(Expr *E, const ConstructionContext *CC, BumpVectorContext &C)
pred_iterator pred_begin()
void appendCleanupFunction(const VarDecl *VD, BumpVectorContext &C)
void setLabel(Stmt *Statement)
unsigned getBlockID() const
void appendStmt(Stmt *statement, BumpVectorContext &C)
void setHasNoReturnElement()
const Expr * getLastCondition() const
void appendConstructor(CXXConstructExpr *CE, const ConstructionContext *CC, BumpVectorContext &C)
Stmt * getTerminatorCondition(bool StripParens=true)
void addSuccessor(AdjacentBlock Succ, BumpVectorContext &C)
Adds a (potentially unreachable) successor block to the current block.
void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C)
AdjacentBlocks::const_iterator const_succ_iterator
CFGTerminator Terminator
The terminator for a basic block that indicates the type of control-flow that occurs between a block ...
unsigned succ_size() const
Represents a function call that returns a C++ object by value.
static bool isCXXRecordTypedCall(const Expr *E)
Returns true when call expression CE needs to be represented by CFGCXXRecordTypedCall,...
virtual void compareBitwiseEquality(const BinaryOperator *B, bool isAlwaysTrue)
virtual void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)
virtual void compareBitwiseOr(const BinaryOperator *B)
Represents C++ constructor call.
Represents C++ object destructor generated from a call to delete.
const CXXDeleteExpr * getDeleteExpr() const
const CXXRecordDecl * getCXXRecordDecl() const
Represents a top-level expression in a basic block.
void dumpToStream(llvm::raw_ostream &OS) const
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
const CXXDestructorDecl * getDestructorDecl(ASTContext &astContext) const
Represents C++ base or member initializer from constructor's initialization list.
CXXCtorInitializer * getInitializer() const
Represents the point where the lifetime of an automatic object ends.
const VarDecl * getVarDecl() const
Represents the point where a loop ends.
Represents C++ object destructor implicitly generated for member object in destructor.
Represents C++ allocator call.
const CXXNewExpr * getAllocatorExpr() const
Represents beginning of a scope implicitly generated by the compiler on encountering a CompoundStmt.
const VarDecl * getVarDecl() const
Represents end of a scope implicitly generated by the compiler after the last Stmt in a CompoundStmt'...
const VarDecl * getVarDecl() const
const Stmt * getStmt() const
Represents C++ object destructor implicitly generated at the end of full expression for temporary obj...
Represents CFGBlock terminator statement.
@ 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 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()...
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()
CXXCatchStmt - This represents a C++ catch block.
Stmt * getHandlerBlock() const
VarDecl * getExceptionDecl() const
Represents a call to a C++ constructor.
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
A use of a default initializer in a constructor or in aggregate initialization.
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.
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Represents an explicit C++ type conversion that uses "functional" notation (C++ [expr....
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)".
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++ functional cast expression that builds a temporary object.
Represents a C++ temporary.
const CXXDestructorDecl * getDestructor() const
A C++ throw-expression (C++ [except.throw]).
CXXTryStmt - A C++ try block, including all handlers.
CXXCatchStmt * getHandler(unsigned i)
unsigned getNumHandlers() const
CompoundStmt * getTryBlock()
A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
CaseStmt - Represent a case statement.
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
ChooseExpr - GNU builtin-in function __builtin_choose_expr.
CompoundStmt - This represents a group of statements like { stmt stmt }.
reverse_body_iterator body_rbegin()
Represents the canonical version of C arrays with a specified constant size.
ConstantExpr - An expression that occurs in a constant context and optionally the result of evaluatin...
Represents a single point (AST node) in the program that requires attention during construction of an...
@ ElidableConstructorKind
Construction context can be seen as a linked list of multiple layers.
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
ContinueStmt - This represents a continue.
Represents a 'co_return' statement in the C++ Coroutines TS.
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.
Represents an expression that might suspend coroutine execution; either a co_await or co_yield expres...
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
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.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
SourceLocation getLocation() const
DoStmt - This represents a 'do/while' stmt.
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
This represents one expression.
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
static QualType findBoundMemberType(const Expr *expr)
Given an expression of bound-member type, find the type of the member.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, SmallVectorImpl< PartialDiagnosticAt > *Diag=nullptr) 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 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.
ForStmt - This represents a 'for (init;cond;inc)' stmt.
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 function declaration or definition.
Represents a prototype with parameter type info, e.g.
FunctionType - C99 6.7.5.3 - Function Declarators.
This represents a GCC inline-assembly statement extension.
GotoStmt - This represents a direct goto.
LabelDecl * getLabel() const
IfStmt - This represents an if/then/else.
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.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
IndirectGotoStmt - This represents an indirect goto.
Describes an C or C++ initializer list.
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...
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.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getQualifiedNameAsString() const
This is a basic class for representing single OpenMP executable directive.
static llvm::iterator_range< used_clauses_child_iterator > used_clauses_children(ArrayRef< OMPClause * > Clauses)
Represents Objective-C's @catch statement.
const Stmt * getCatchBody() const
Represents Objective-C's @synchronized statement.
Represents Objective-C's @throw statement.
Represents Objective-C's @try ... @catch ... @finally statement.
const ObjCAtFinallyStmt * getFinallyStmt() const
Retrieve the @finally statement, if any.
const Stmt * getTryBody() const
Retrieve the @try body.
catch_range catch_stmts()
Represents Objective-C's @autoreleasepool Statement.
Represents Objective-C's collection statement.
An expression that sends a message to the given Objective-C object or class.
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
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
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
CompoundStmt * getBlock() const
Expr * getFilterExpr() const
Represents a __leave statement.
CompoundStmt * getTryBlock() const
SEHFinallyStmt * getFinallyHandler() const
SEHExceptStmt * getExceptHandler() const
Returns 0 if not defined.
Scope - A scope is a transient data structure that is used while parsing the program.
Scope(Scope *Parent, unsigned ScopeFlags, DiagnosticsEngine &Diag)
Encodes a location in the source.
StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
CompoundStmt * getSubStmt()
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
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.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isBlockPointerType() const
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>'.
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
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.
WhileStmt - This represents a 'while' stmt.
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
Matches all kinds of arrays.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
constexpr Variable var(Literal L)
Returns the variable of L.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
bool Sub(InterpState &S, CodePtr OpPC)
bool NE(InterpState &S, CodePtr OpPC)
bool LE(InterpState &S, CodePtr OpPC)
bool Cast(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType)
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
@ SD_FullExpression
Full-expression storage duration (for temporaries).
std::string JsonFormat(StringRef RawSR, bool AddQuotes)
bool operator!=(CanQual< T > x, CanQual< U > y)
const FunctionProtoType * T
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.
Iterator for iterating over Stmt * arrays that contain only T *.
DOTGraphTraits(bool isSimple=false)
static std::string getNodeLabel(const CFGBlock *Node, const CFG *Graph)