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(); }
764 CFGBlock *createBlock(
bool add_successor =
true);
768 return Visit(S, AddStmtChoice::AlwaysAdd);
772 void addLoopExit(
const Stmt *LoopStmt);
773 void addAutomaticObjHandling(LocalScope::const_iterator B,
774 LocalScope::const_iterator
E,
Stmt *S);
775 void addAutomaticObjDestruction(LocalScope::const_iterator B,
776 LocalScope::const_iterator
E,
Stmt *S);
777 void addScopeExitHandling(LocalScope::const_iterator B,
778 LocalScope::const_iterator
E,
Stmt *S);
780 void addScopeChangesHandling(LocalScope::const_iterator SrcPos,
781 LocalScope::const_iterator DstPos,
783 CFGBlock *createScopeChangesHandlingBlock(LocalScope::const_iterator SrcPos,
785 LocalScope::const_iterator DstPost,
789 LocalScope* createOrReuseLocalScope(LocalScope*
Scope);
791 void addLocalScopeForStmt(
Stmt *S);
792 LocalScope* addLocalScopeForDeclStmt(
DeclStmt *DS,
793 LocalScope*
Scope =
nullptr);
794 LocalScope* addLocalScopeForVarDecl(
VarDecl *VD, LocalScope*
Scope =
nullptr);
796 void addLocalScopeAndDtors(
Stmt *S);
806 cleanupConstructionContext(
E);
814 if (alwaysAdd(S) && cachedEntry)
815 cachedEntry->second = B;
818 assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S);
824 if (
C &&
C->isNoReturn())
825 Block = createNoReturnBlock();
830 retrieveAndCleanupConstructionContext(CE)) {
840 if (alwaysAdd(CE) && cachedEntry)
841 cachedEntry->second = B;
844 retrieveAndCleanupConstructionContext(CE)) {
850 B->
appendStmt(CE, cfg->getBumpVectorContext());
870 if (alwaysAdd(ME) && cachedEntry)
871 cachedEntry->second = B;
874 retrieveAndCleanupConstructionContext(ME)) {
880 cfg->getBumpVectorContext());
899 void appendLoopExit(
CFGBlock *B,
const Stmt *LoopStmt) {
909 cfg->getBumpVectorContext());
916 cfg->getBumpVectorContext());
932 TryResult checkIncorrectRelationalOperator(
const BinaryOperator *B) {
936 const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
937 const Expr *BoolExpr = RHSExpr;
938 bool IntFirst =
true;
940 IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
948 llvm::APInt IntValue = IntLiteral->
getValue();
949 if ((IntValue == 1) || (IntValue == 0))
953 !IntValue.isNegative();
956 if (Bok == BO_GT || Bok == BO_GE) {
959 return TryResult(IntFirst == IntLarger);
963 return TryResult(IntFirst != IntLarger);
971 TryResult checkIncorrectEqualityOperator(
const BinaryOperator *B) {
975 std::optional<llvm::APInt> IntLiteral1 =
976 getIntegerLiteralSubexpressionValue(LHSExpr);
977 const Expr *BoolExpr = RHSExpr;
980 IntLiteral1 = getIntegerLiteralSubexpressionValue(RHSExpr);
988 if (BitOp && (BitOp->
getOpcode() == BO_And ||
993 std::optional<llvm::APInt> IntLiteral2 =
994 getIntegerLiteralSubexpressionValue(LHSExpr2);
997 IntLiteral2 = getIntegerLiteralSubexpressionValue(RHSExpr2);
1003 (*IntLiteral2 & *IntLiteral1) != *IntLiteral1) ||
1005 (*IntLiteral2 | *IntLiteral1) != *IntLiteral1)) {
1009 return TryResult(B->
getOpcode() != BO_EQ);
1012 if ((*IntLiteral1 == 1) || (*IntLiteral1 == 0)) {
1015 return TryResult(B->
getOpcode() != BO_EQ);
1027 std::optional<llvm::APInt>
1028 getIntegerLiteralSubexpressionValue(
const Expr *
E) {
1031 if (
const auto *UnOp = dyn_cast<UnaryOperator>(
E->
IgnoreParens())) {
1036 if (
const auto *IntLiteral = dyn_cast<IntegerLiteral>(SubExpr)) {
1041 switch (UnOp->getOpcode()) {
1051 assert(
false &&
"Unexpected unary operator!");
1052 return std::nullopt;
1055 }
else if (
const auto *IntLiteral =
1059 return std::nullopt;
1063 const llvm::APSInt &Value1,
1064 const llvm::APSInt &Value2) {
1065 assert(Value1.isSigned() == Value2.isSigned());
1070 return TryResult(Value1 == Value2);
1072 return TryResult(Value1 != Value2);
1074 return TryResult(Value1 < Value2);
1076 return TryResult(Value1 <= Value2);
1078 return TryResult(Value1 > Value2);
1080 return TryResult(Value1 >= Value2);
1096 auto CheckLogicalOpWithNegatedVariable = [
this, B](
const Expr *E1,
1098 if (
const auto *Negate = dyn_cast<UnaryOperator>(E1)) {
1099 if (Negate->getOpcode() == UO_LNot &&
1101 bool AlwaysTrue = B->
getOpcode() == BO_LOr;
1104 return TryResult(AlwaysTrue);
1110 TryResult Result = CheckLogicalOpWithNegatedVariable(LHSExpr, RHSExpr);
1111 if (Result.isKnown())
1113 Result = CheckLogicalOpWithNegatedVariable(RHSExpr, LHSExpr);
1114 if (Result.isKnown())
1117 const auto *LHS = dyn_cast<BinaryOperator>(LHSExpr);
1118 const auto *RHS = dyn_cast<BinaryOperator>(RHSExpr);
1122 if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
1125 const Expr *DeclExpr1;
1126 const Expr *NumExpr1;
1130 if (!DeclExpr1 || !NumExpr1)
1133 const Expr *DeclExpr2;
1134 const Expr *NumExpr2;
1138 if (!DeclExpr2 || !NumExpr2)
1155 llvm::APSInt L1 = L1Result.
Val.
getInt();
1156 llvm::APSInt L2 = L2Result.
Val.
getInt();
1159 if (L1.isSigned() != L2.isSigned() || L1.getBitWidth() != L2.getBitWidth())
1164 const llvm::APSInt Values[] = {
1166 llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
1170 ((L1 < L2) ? L1 : L2) + llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1),
1175 llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
1184 bool AlwaysTrue =
true, AlwaysFalse =
true;
1187 bool LHSAlwaysTrue =
true, LHSAlwaysFalse =
true;
1188 bool RHSAlwaysTrue =
true, RHSAlwaysFalse =
true;
1189 for (
const llvm::APSInt &
Value : Values) {
1190 TryResult Res1, Res2;
1191 Res1 = analyzeLogicOperatorCondition(BO1,
Value, L1);
1192 Res2 = analyzeLogicOperatorCondition(BO2,
Value, L2);
1194 if (!Res1.isKnown() || !Res2.isKnown())
1198 AlwaysTrue &= (Res1.isTrue() && Res2.isTrue());
1199 AlwaysFalse &= !(Res1.isTrue() && Res2.isTrue());
1201 AlwaysTrue &= (Res1.isTrue() || Res2.isTrue());
1202 AlwaysFalse &= !(Res1.isTrue() || Res2.isTrue());
1205 LHSAlwaysTrue &= Res1.isTrue();
1206 LHSAlwaysFalse &= Res1.isFalse();
1207 RHSAlwaysTrue &= Res2.isTrue();
1208 RHSAlwaysFalse &= Res2.isFalse();
1211 if (AlwaysTrue || AlwaysFalse) {
1212 if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
1213 !RHSAlwaysFalse && BuildOpts.
Observer)
1215 return TryResult(AlwaysTrue);
1221 TryResult checkIncorrectBitwiseOrOperator(
const BinaryOperator *B) {
1222 const Expr *LHSConstant =
1224 const Expr *RHSConstant =
1227 if ((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant))
1230 const Expr *Constant = LHSConstant ? LHSConstant : RHSConstant;
1236 if (Result.Val.getInt() == 0)
1242 return TryResult(
true);
1249 return !S->isTypeDependent() &&
1250 !S->isValueDependent() &&
1251 S->EvaluateAsRValue(outResult, *Context);
1256 TryResult tryEvaluateBool(
Expr *S) {
1258 S->isTypeDependent() || S->isValueDependent())
1262 if (Bop->isLogicalOp() || Bop->isEqualityOp()) {
1264 CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S);
1265 if (I != CachedBoolEvals.end())
1269 TryResult Result = evaluateAsBooleanConditionNoCache(S);
1270 CachedBoolEvals[S] = Result;
1274 switch (Bop->getOpcode()) {
1283 if (Bop->getLHS()->EvaluateAsInt(LHSResult, *Context)) {
1284 llvm::APSInt IntVal = LHSResult.
Val.
getInt();
1285 if (!IntVal.getBoolValue()) {
1286 return TryResult(
false);
1290 if (Bop->getRHS()->EvaluateAsInt(RHSResult, *Context)) {
1291 llvm::APSInt IntVal = RHSResult.
Val.
getInt();
1292 if (!IntVal.getBoolValue()) {
1293 return TryResult(
false);
1302 return evaluateAsBooleanConditionNoCache(S);
1306 TryResult evaluateAsBooleanConditionNoCache(
Expr *
E) {
1308 if (Bop->isLogicalOp()) {
1309 TryResult LHS = tryEvaluateBool(Bop->getLHS());
1310 if (LHS.isKnown()) {
1313 if (LHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1314 return LHS.isTrue();
1316 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1317 if (RHS.isKnown()) {
1318 if (Bop->getOpcode() == BO_LOr)
1319 return LHS.isTrue() || RHS.isTrue();
1321 return LHS.isTrue() && RHS.isTrue();
1324 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1325 if (RHS.isKnown()) {
1328 if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1329 return RHS.isTrue();
1331 TryResult BopRes = checkIncorrectLogicOperator(Bop);
1332 if (BopRes.isKnown())
1333 return BopRes.isTrue();
1338 }
else if (Bop->isEqualityOp()) {
1339 TryResult BopRes = checkIncorrectEqualityOperator(Bop);
1340 if (BopRes.isKnown())
1341 return BopRes.isTrue();
1342 }
else if (Bop->isRelationalOp()) {
1343 TryResult BopRes = checkIncorrectRelationalOperator(Bop);
1344 if (BopRes.isKnown())
1345 return BopRes.isTrue();
1346 }
else if (Bop->getOpcode() == BO_Or) {
1347 TryResult BopRes = checkIncorrectBitwiseOrOperator(Bop);
1348 if (BopRes.isKnown())
1349 return BopRes.isTrue();
1360 bool hasTrivialDestructor(
const VarDecl *VD)
const;
1361 bool needsAutomaticDestruction(
const VarDecl *VD)
const;
1372 while (
const auto *
E = dyn_cast<ArrayInitLoopExpr>(AILEInit))
1373 AILEInit =
E->getSubExpr();
1378inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
1380 return builder.alwaysAdd(
stmt) || kind == AlwaysAdd;
1383bool CFGBuilder::alwaysAdd(
const Stmt *
stmt) {
1389 if (lastLookup ==
stmt) {
1391 assert(cachedEntry->first ==
stmt);
1404 assert(!cachedEntry);
1408 CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(
stmt);
1409 if (itr == fb->end()) {
1410 cachedEntry =
nullptr;
1414 cachedEntry = &*itr;
1421 while (
const ArrayType *vt = dyn_cast<ArrayType>(t)) {
1423 if (vat->getSizeExpr())
1426 t = vt->getElementType().getTypePtr();
1432void CFGBuilder::consumeConstructionContext(
1434 assert((isa<CXXConstructExpr>(
E) || isa<CallExpr>(
E) ||
1435 isa<ObjCMessageExpr>(
E)) &&
"Expression cannot construct an object!");
1437 ConstructionContextMap.lookup(
E)) {
1438 (void)PreviouslyStoredLayer;
1441 assert(PreviouslyStoredLayer->isStrictlyMoreSpecificThan(Layer) &&
1442 "Already within a different construction context!");
1444 ConstructionContextMap[
E] = Layer;
1448void CFGBuilder::findConstructionContexts(
1461 switch(Child->getStmtClass()) {
1462 case Stmt::CXXConstructExprClass:
1463 case Stmt::CXXTemporaryObjectExprClass: {
1465 auto *CE = cast<CXXConstructExpr>(Child);
1467 findConstructionContexts(withExtraLayer(CE), CE->
getArg(0));
1470 consumeConstructionContext(Layer, CE);
1476 case Stmt::CallExprClass:
1477 case Stmt::CXXMemberCallExprClass:
1478 case Stmt::CXXOperatorCallExprClass:
1479 case Stmt::UserDefinedLiteralClass:
1480 case Stmt::ObjCMessageExprClass: {
1481 auto *
E = cast<Expr>(Child);
1483 consumeConstructionContext(Layer,
E);
1486 case Stmt::ExprWithCleanupsClass: {
1487 auto *Cleanups = cast<ExprWithCleanups>(Child);
1488 findConstructionContexts(Layer, Cleanups->getSubExpr());
1491 case Stmt::CXXFunctionalCastExprClass: {
1492 auto *
Cast = cast<CXXFunctionalCastExpr>(Child);
1493 findConstructionContexts(Layer,
Cast->getSubExpr());
1496 case Stmt::ImplicitCastExprClass: {
1497 auto *
Cast = cast<ImplicitCastExpr>(Child);
1499 switch (
Cast->getCastKind()) {
1501 case CK_ConstructorConversion:
1502 findConstructionContexts(Layer,
Cast->getSubExpr());
1509 case Stmt::CXXBindTemporaryExprClass: {
1510 auto *BTE = cast<CXXBindTemporaryExpr>(Child);
1511 findConstructionContexts(withExtraLayer(BTE), BTE->getSubExpr());
1514 case Stmt::MaterializeTemporaryExprClass: {
1521 auto *MTE = cast<MaterializeTemporaryExpr>(Child);
1522 findConstructionContexts(withExtraLayer(MTE), MTE->getSubExpr());
1526 case Stmt::ConditionalOperatorClass: {
1527 auto *CO = cast<ConditionalOperator>(Child);
1534 assert(!CO->getType()->getAsCXXRecordDecl() || CO->isGLValue() ||
1538 findConstructionContexts(Layer, CO->getLHS());
1539 findConstructionContexts(Layer, CO->getRHS());
1542 case Stmt::InitListExprClass: {
1543 auto *ILE = cast<InitListExpr>(Child);
1544 if (ILE->isTransparent()) {
1545 findConstructionContexts(Layer, ILE->getInit(0));
1551 case Stmt::ParenExprClass: {
1554 auto *PE = cast<ParenExpr>(Child);
1555 findConstructionContexts(Layer, PE->getSubExpr());
1563void CFGBuilder::cleanupConstructionContext(
Expr *
E) {
1565 "We should not be managing construction contexts!");
1566 assert(ConstructionContextMap.count(
E) &&
1567 "Cannot exit construction context without the context!");
1568 ConstructionContextMap.erase(
E);
1576std::unique_ptr<CFG> CFGBuilder::buildCFG(
const Decl *
D,
Stmt *Statement) {
1584 Succ = createBlock();
1585 assert(Succ == &cfg->getExit());
1590 addImplicitDtorsForDestructor(DD);
1610 if (
const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(
D)) {
1612 for (
auto *I : llvm::reverse(CD->inits())) {
1614 I->isBaseInitializer() && I->isBaseVirtual()) {
1618 VBaseSucc = Succ = B ? B : &cfg->getExit();
1619 Block = createBlock();
1621 B = addInitializer(I);
1631 addSuccessor(B,
Block,
true);
1640 for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
1641 E = BackpatchBlocks.end(); I !=
E; ++I ) {
1645 LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
1648 if (LI == LabelMap.end())
1650 JumpTarget JT = LI->second;
1652 CFGBlock *SuccBlk = createScopeChangesHandlingBlock(
1653 I->scopePosition, B, JT.scopePosition, JT.block);
1654 addSuccessor(B, SuccBlk);
1655 }
else if (
auto *G = dyn_cast<GCCAsmStmt>(B->
getTerminator())) {
1656 CFGBlock *Successor = (I+1)->block;
1657 for (
auto *L : G->labels()) {
1658 LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
1661 if (LI == LabelMap.end())
1663 JumpTarget JT = LI->second;
1665 if (JT.block == Successor)
1667 addSuccessor(B, JT.block);
1674 if (
CFGBlock *B = cfg->getIndirectGotoBlock())
1675 for (LabelSetTy::iterator I = AddressTakenLabels.begin(),
1676 E = AddressTakenLabels.end(); I !=
E; ++I ) {
1678 LabelMapTy::iterator LI = LabelMap.find(*I);
1682 if (LI == LabelMap.end())
continue;
1684 addSuccessor(B, LI->second.block);
1688 cfg->setEntry(createBlock());
1691 assert(ConstructionContextMap.empty() &&
1692 "Not all construction contexts were cleaned up!");
1694 return std::move(cfg);
1699CFGBlock *CFGBuilder::createBlock(
bool add_successor) {
1701 if (add_successor && Succ)
1702 addSuccessor(B, Succ);
1709CFGBlock *CFGBuilder::createNoReturnBlock() {
1712 addSuccessor(B, &cfg->getExit(), Succ);
1721 bool HasTemporaries =
false;
1727 HasTemporaries = isa<ExprWithCleanups>(
Init);
1731 TempDtorContext Context;
1732 VisitForTemporaryDtors(cast<ExprWithCleanups>(
Init)->getSubExpr(),
1738 appendInitializer(
Block, I);
1744 dyn_cast<ArrayInitLoopExpr>(
Init));
1746 findConstructionContexts(
1748 AILEInit ? AILEInit :
Init);
1750 if (HasTemporaries) {
1753 return Visit(cast<ExprWithCleanups>(
Init)->getSubExpr());
1777 bool *FoundMTE =
nullptr) {
1784 Init = EWC->getSubExpr();
1790 = dyn_cast<MaterializeTemporaryExpr>(
Init)) {
1791 Init = MTE->getSubExpr();
1798 const Expr *SkippedInit =
Init->skipRValueSubobjectAdjustments();
1799 if (SkippedInit !=
Init) {
1807 return Init->getType();
1812void CFGBuilder::addLoopExit(
const Stmt *LoopStmt){
1816 appendLoopExit(
Block, LoopStmt);
1824void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
1825 LocalScope::const_iterator
E,
1835 if (B.inSameLocalScope(
E)) {
1836 addAutomaticObjDestruction(B,
E, S);
1842 LocalScopeEndMarkers.push_back(B);
1843 for (LocalScope::const_iterator I = B; I !=
E; ++I) {
1844 if (!I.inSameLocalScope(LocalScopeEndMarkers.back()))
1845 LocalScopeEndMarkers.push_back(I);
1847 LocalScopeEndMarkers.push_back(
E);
1851 std::reverse(LocalScopeEndMarkers.begin(), LocalScopeEndMarkers.end());
1853 llvm::zip(LocalScopeEndMarkers, llvm::drop_begin(LocalScopeEndMarkers));
1854 for (
auto [
E, B] : Pairwise) {
1855 if (!B.inSameLocalScope(
E))
1856 addScopeExitHandling(B,
E, S);
1857 addAutomaticObjDestruction(B,
E, S);
1864void CFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
1865 LocalScope::const_iterator
E,
1874 DeclsNeedDestruction.reserve(B.distance(
E));
1876 for (
VarDecl*
D : llvm::make_range(B,
E))
1877 if (needsAutomaticDestruction(
D))
1878 DeclsNeedDestruction.push_back(
D);
1880 for (
VarDecl *VD : llvm::reverse(DeclsNeedDestruction)) {
1893 Block = createNoReturnBlock();
1902 appendLifetimeEnds(
Block, VD, S);
1904 appendAutomaticObjDtor(
Block, VD, S);
1905 if (VD->
hasAttr<CleanupAttr>())
1906 appendCleanupFunction(
Block, VD);
1915void CFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
1916 LocalScope::const_iterator
E,
Stmt *S) {
1917 assert(!B.inSameLocalScope(
E));
1923 appendScopeEnd(
Block, B.getFirstVarInScope(), S);
1931 DeclsTrivial.reserve(B.distance(
E));
1936 for (
VarDecl*
D : llvm::make_range(B,
E))
1937 if (!needsAutomaticDestruction(
D))
1938 DeclsTrivial.push_back(
D);
1940 if (DeclsTrivial.empty())
1944 for (
VarDecl *VD : llvm::reverse(DeclsTrivial))
1945 appendLifetimeEnds(
Block, VD, S);
1953void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
1954 LocalScope::const_iterator DstPos,
1956 assert(
Block &&
"Source block should be always crated");
1962 if (SrcPos == DstPos)
1967 LocalScope::const_iterator BasePos = SrcPos.shared_parent(DstPos);
1970 if (BuildOpts.
AddScopes && !DstPos.inSameLocalScope(BasePos)) {
1971 for (LocalScope::const_iterator I = DstPos; I != BasePos; ++I)
1972 if (I.pointsToFirstDeclaredVar())
1973 appendScopeBegin(
Block, *I, S);
1978 addAutomaticObjHandling(SrcPos, BasePos, S);
1986CFGBlock *CFGBuilder::createScopeChangesHandlingBlock(
1987 LocalScope::const_iterator SrcPos,
CFGBlock *SrcBlk,
1988 LocalScope::const_iterator DstPos,
CFGBlock *DstBlk) {
1989 if (SrcPos == DstPos)
1993 (!BuildOpts.
AddScopes || SrcPos.inSameLocalScope(DstPos)))
2001 Block = createBlock(
false);
2004 addSuccessor(
Block, DstBlk);
2009 assert(
Block &&
"There should be at least one scope changing Block");
2017 "Can be called only when dtors should be added");
2021 for (
const auto &VI : RD->
vbases()) {
2025 const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
2028 appendBaseDtor(
Block, &VI);
2033 for (
const auto &BI : RD->
bases()) {
2034 if (!BI.isVirtual()) {
2035 const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
2038 appendBaseDtor(
Block, &BI);
2044 for (
auto *FI : RD->
fields()) {
2049 if (AT->isZeroSize())
2051 QT = AT->getElementType();
2057 appendMemberDtor(
Block, FI);
2064LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope*
Scope) {
2067 llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
2073void CFGBuilder::addLocalScopeForStmt(
Stmt *S) {
2078 LocalScope *
Scope =
nullptr;
2082 for (
auto *BI : CS->body()) {
2084 if (
DeclStmt *DS = dyn_cast<DeclStmt>(SI))
2092 if (
DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements()))
2093 addLocalScopeForDeclStmt(DS);
2098LocalScope* CFGBuilder::addLocalScopeForDeclStmt(
DeclStmt *DS,
2099 LocalScope*
Scope) {
2104 for (
auto *DI : DS->
decls())
2105 if (
VarDecl *VD = dyn_cast<VarDecl>(DI))
2110bool CFGBuilder::needsAutomaticDestruction(
const VarDecl *VD)
const {
2111 return !hasTrivialDestructor(VD) || VD->
hasAttr<CleanupAttr>();
2114bool CFGBuilder::hasTrivialDestructor(
const VarDecl *VD)
const {
2135 bool FoundMTE =
false;
2143 if (AT->isZeroSize())
2145 QT = AT->getElementType();
2157LocalScope* CFGBuilder::addLocalScopeForVarDecl(
VarDecl *VD,
2158 LocalScope*
Scope) {
2168 !needsAutomaticDestruction(VD)) {
2176 ScopePos =
Scope->begin();
2182void CFGBuilder::addLocalScopeAndDtors(
Stmt *S) {
2183 LocalScope::const_iterator scopeBeginPos = ScopePos;
2184 addLocalScopeForStmt(S);
2185 addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
2191CFGBlock *CFGBuilder::Visit(
Stmt * S, AddStmtChoice asc,
2192 bool ExternallyDestructed) {
2198 if (
Expr *
E = dyn_cast<Expr>(S))
2202 if (
auto *
D = dyn_cast<OMPExecutableDirective>(S))
2203 return VisitOMPExecutableDirective(
D, asc);
2205 switch (S->getStmtClass()) {
2207 return VisitStmt(S, asc);
2209 case Stmt::ImplicitValueInitExprClass:
2212 return VisitStmt(S, asc);
2214 case Stmt::InitListExprClass:
2215 return VisitInitListExpr(cast<InitListExpr>(S), asc);
2217 case Stmt::AttributedStmtClass:
2218 return VisitAttributedStmt(cast<AttributedStmt>(S), asc);
2220 case Stmt::AddrLabelExprClass:
2221 return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
2223 case Stmt::BinaryConditionalOperatorClass:
2224 return VisitConditionalOperator(cast<BinaryConditionalOperator>(S), asc);
2226 case Stmt::BinaryOperatorClass:
2227 return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
2229 case Stmt::BlockExprClass:
2230 return VisitBlockExpr(cast<BlockExpr>(S), asc);
2232 case Stmt::BreakStmtClass:
2233 return VisitBreakStmt(cast<BreakStmt>(S));
2235 case Stmt::CallExprClass:
2236 case Stmt::CXXOperatorCallExprClass:
2237 case Stmt::CXXMemberCallExprClass:
2238 case Stmt::UserDefinedLiteralClass:
2239 return VisitCallExpr(cast<CallExpr>(S), asc);
2241 case Stmt::CaseStmtClass:
2242 return VisitCaseStmt(cast<CaseStmt>(S));
2244 case Stmt::ChooseExprClass:
2245 return VisitChooseExpr(cast<ChooseExpr>(S), asc);
2247 case Stmt::CompoundStmtClass:
2248 return VisitCompoundStmt(cast<CompoundStmt>(S), ExternallyDestructed);
2250 case Stmt::ConditionalOperatorClass:
2251 return VisitConditionalOperator(cast<ConditionalOperator>(S), asc);
2253 case Stmt::ContinueStmtClass:
2254 return VisitContinueStmt(cast<ContinueStmt>(S));
2256 case Stmt::CXXCatchStmtClass:
2257 return VisitCXXCatchStmt(cast<CXXCatchStmt>(S));
2259 case Stmt::ExprWithCleanupsClass:
2260 return VisitExprWithCleanups(cast<ExprWithCleanups>(S),
2261 asc, ExternallyDestructed);
2263 case Stmt::CXXDefaultArgExprClass:
2264 case Stmt::CXXDefaultInitExprClass:
2273 return VisitStmt(S, asc);
2275 case Stmt::CXXBindTemporaryExprClass:
2276 return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc);
2278 case Stmt::CXXConstructExprClass:
2279 return VisitCXXConstructExpr(cast<CXXConstructExpr>(S), asc);
2281 case Stmt::CXXNewExprClass:
2282 return VisitCXXNewExpr(cast<CXXNewExpr>(S), asc);
2284 case Stmt::CXXDeleteExprClass:
2285 return VisitCXXDeleteExpr(cast<CXXDeleteExpr>(S), asc);
2287 case Stmt::CXXFunctionalCastExprClass:
2288 return VisitCXXFunctionalCastExpr(cast<CXXFunctionalCastExpr>(S), asc);
2290 case Stmt::CXXTemporaryObjectExprClass:
2291 return VisitCXXTemporaryObjectExpr(cast<CXXTemporaryObjectExpr>(S), asc);
2293 case Stmt::CXXThrowExprClass:
2294 return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
2296 case Stmt::CXXTryStmtClass:
2297 return VisitCXXTryStmt(cast<CXXTryStmt>(S));
2299 case Stmt::CXXTypeidExprClass:
2300 return VisitCXXTypeidExpr(cast<CXXTypeidExpr>(S), asc);
2302 case Stmt::CXXForRangeStmtClass:
2303 return VisitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
2305 case Stmt::DeclStmtClass:
2306 return VisitDeclStmt(cast<DeclStmt>(S));
2308 case Stmt::DefaultStmtClass:
2309 return VisitDefaultStmt(cast<DefaultStmt>(S));
2311 case Stmt::DoStmtClass:
2312 return VisitDoStmt(cast<DoStmt>(S));
2314 case Stmt::ForStmtClass:
2315 return VisitForStmt(cast<ForStmt>(S));
2317 case Stmt::GotoStmtClass:
2318 return VisitGotoStmt(cast<GotoStmt>(S));
2320 case Stmt::GCCAsmStmtClass:
2321 return VisitGCCAsmStmt(cast<GCCAsmStmt>(S), asc);
2323 case Stmt::IfStmtClass:
2324 return VisitIfStmt(cast<IfStmt>(S));
2326 case Stmt::ImplicitCastExprClass:
2327 return VisitImplicitCastExpr(cast<ImplicitCastExpr>(S), asc);
2329 case Stmt::ConstantExprClass:
2330 return VisitConstantExpr(cast<ConstantExpr>(S), asc);
2332 case Stmt::IndirectGotoStmtClass:
2333 return VisitIndirectGotoStmt(cast<IndirectGotoStmt>(S));
2335 case Stmt::LabelStmtClass:
2336 return VisitLabelStmt(cast<LabelStmt>(S));
2338 case Stmt::LambdaExprClass:
2339 return VisitLambdaExpr(cast<LambdaExpr>(S), asc);
2341 case Stmt::MaterializeTemporaryExprClass:
2342 return VisitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(S),
2345 case Stmt::MemberExprClass:
2346 return VisitMemberExpr(cast<MemberExpr>(S), asc);
2348 case Stmt::NullStmtClass:
2351 case Stmt::ObjCAtCatchStmtClass:
2352 return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
2354 case Stmt::ObjCAutoreleasePoolStmtClass:
2355 return VisitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(S));
2357 case Stmt::ObjCAtSynchronizedStmtClass:
2358 return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S));
2360 case Stmt::ObjCAtThrowStmtClass:
2361 return VisitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(S));
2363 case Stmt::ObjCAtTryStmtClass:
2364 return VisitObjCAtTryStmt(cast<ObjCAtTryStmt>(S));
2366 case Stmt::ObjCForCollectionStmtClass:
2367 return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
2369 case Stmt::ObjCMessageExprClass:
2370 return VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), asc);
2372 case Stmt::OpaqueValueExprClass:
2375 case Stmt::PseudoObjectExprClass:
2376 return VisitPseudoObjectExpr(cast<PseudoObjectExpr>(S));
2378 case Stmt::ReturnStmtClass:
2379 case Stmt::CoreturnStmtClass:
2380 return VisitReturnStmt(S);
2382 case Stmt::CoyieldExprClass:
2383 case Stmt::CoawaitExprClass:
2384 return VisitCoroutineSuspendExpr(cast<CoroutineSuspendExpr>(S), asc);
2386 case Stmt::SEHExceptStmtClass:
2387 return VisitSEHExceptStmt(cast<SEHExceptStmt>(S));
2389 case Stmt::SEHFinallyStmtClass:
2390 return VisitSEHFinallyStmt(cast<SEHFinallyStmt>(S));
2392 case Stmt::SEHLeaveStmtClass:
2393 return VisitSEHLeaveStmt(cast<SEHLeaveStmt>(S));
2395 case Stmt::SEHTryStmtClass:
2396 return VisitSEHTryStmt(cast<SEHTryStmt>(S));
2398 case Stmt::UnaryExprOrTypeTraitExprClass:
2399 return VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
2402 case Stmt::StmtExprClass:
2403 return VisitStmtExpr(cast<StmtExpr>(S), asc);
2405 case Stmt::SwitchStmtClass:
2406 return VisitSwitchStmt(cast<SwitchStmt>(S));
2408 case Stmt::UnaryOperatorClass:
2409 return VisitUnaryOperator(cast<UnaryOperator>(S), asc);
2411 case Stmt::WhileStmtClass:
2412 return VisitWhileStmt(cast<WhileStmt>(S));
2414 case Stmt::ArrayInitLoopExprClass:
2415 return VisitArrayInitLoopExpr(cast<ArrayInitLoopExpr>(S), asc);
2419CFGBlock *CFGBuilder::VisitStmt(
Stmt *S, AddStmtChoice asc) {
2420 if (asc.alwaysAdd(*
this, S)) {
2422 appendStmt(
Block, S);
2425 return VisitChildren(S);
2434 reverse_children RChildren(S);
2435 for (
Stmt *Child : RChildren) {
2444 if (asc.alwaysAdd(*
this, ILE)) {
2446 appendStmt(
Block, ILE);
2450 reverse_children RChildren(ILE);
2451 for (
Stmt *Child : RChildren) {
2457 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(Child))
2458 if (
Stmt *Child = DIE->getExpr())
2467 AddStmtChoice asc) {
2468 AddressTakenLabels.insert(A->
getLabel());
2470 if (asc.alwaysAdd(*
this, A)) {
2472 appendStmt(
Block, A);
2479 bool isFallthrough = hasSpecificAttr<FallThroughAttr>(A->
getAttrs());
2480 assert((!isFallthrough || isa<NullStmt>(A->
getSubStmt())) &&
2481 "expected fallthrough not to have children");
2482 return isFallthrough;
2486 AddStmtChoice asc) {
2497 appendStmt(
Block, A);
2500 return VisitChildren(A);
2504 if (asc.alwaysAdd(*
this,
U)) {
2509 if (
U->getOpcode() == UO_LNot)
2510 tryEvaluateBool(
U->getSubExpr()->IgnoreParens());
2512 return Visit(
U->getSubExpr(), AddStmtChoice());
2517 appendStmt(ConfluenceBlock, B);
2522 return VisitLogicalOperator(B,
nullptr, ConfluenceBlock,
2523 ConfluenceBlock).first;
2526std::pair<CFGBlock*, CFGBlock*>
2539 if (B_RHS->isLogicalOp()) {
2540 std::tie(RHSBlock, ExitBlock) =
2541 VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
2549 ExitBlock = RHSBlock = createBlock(
false);
2554 TryResult KnownVal = tryEvaluateBool(RHS);
2555 if (!KnownVal.isKnown())
2556 KnownVal = tryEvaluateBool(B);
2559 assert(TrueBlock == FalseBlock);
2560 addSuccessor(RHSBlock, TrueBlock);
2564 addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
2565 addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
2569 RHSBlock = addStmt(RHS);
2574 return std::make_pair(
nullptr,
nullptr);
2580 if (B_LHS->isLogicalOp()) {
2582 FalseBlock = RHSBlock;
2584 TrueBlock = RHSBlock;
2589 return VisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock);
2594 CFGBlock *LHSBlock = createBlock(
false);
2598 CFGBlock *EntryLHSBlock = addStmt(LHS);
2601 return std::make_pair(
nullptr,
nullptr);
2604 TryResult KnownVal = tryEvaluateBool(LHS);
2608 addSuccessor(LHSBlock, TrueBlock, !KnownVal.isFalse());
2609 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isTrue());
2612 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isFalse());
2613 addSuccessor(LHSBlock, FalseBlock, !KnownVal.isTrue());
2616 return std::make_pair(EntryLHSBlock, ExitBlock);
2620 AddStmtChoice asc) {
2623 return VisitLogicalOperator(B);
2627 appendStmt(
Block, B);
2629 return addStmt(B->
getLHS());
2633 if (asc.alwaysAdd(*
this, B)) {
2635 appendStmt(
Block, B);
2638 return Visit(B->
getRHS());
2641 if (asc.alwaysAdd(*
this, B)) {
2643 appendStmt(
Block, B);
2654 return (LBlock ? LBlock : RBlock);
2657CFGBlock *CFGBuilder::VisitNoRecurse(
Expr *
E, AddStmtChoice asc) {
2658 if (asc.alwaysAdd(*
this,
E)) {
2672 Block = createBlock(
false);
2677 if (BreakJumpTarget.block) {
2678 addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
2679 addSuccessor(
Block, BreakJumpTarget.block);
2703 QualType calleeType =
C->getCallee()->getType();
2709 if (!boundType.
isNull()) calleeType = boundType;
2715 bool AddEHEdge =
false;
2725 bool OmitArguments =
false;
2732 if (!FD->isVariadic())
2733 findConstructionContextsForArguments(
C);
2735 if (FD->isNoReturn() ||
C->isBuiltinAssumeFalse(*Context))
2737 if (FD->
hasAttr<NoThrowAttr>())
2739 if (FD->getBuiltinID() == Builtin::BI__builtin_object_size ||
2740 FD->getBuiltinID() == Builtin::BI__builtin_dynamic_object_size)
2741 OmitArguments =
true;
2744 if (!
CanThrow(
C->getCallee(), *Context))
2747 if (OmitArguments) {
2748 assert(!NoReturn &&
"noreturn calls with unevaluated args not implemented");
2749 assert(!AddEHEdge &&
"EH calls with unevaluated args not implemented");
2752 return Visit(
C->getCallee());
2755 if (!NoReturn && !AddEHEdge) {
2759 return VisitChildren(
C);
2769 Block = createNoReturnBlock();
2771 Block = createBlock();
2777 if (TryTerminatedBlock)
2778 addSuccessor(
Block, TryTerminatedBlock);
2780 addSuccessor(
Block, &cfg->getExit());
2783 return VisitChildren(
C);
2787 AddStmtChoice asc) {
2789 appendStmt(ConfluenceBlock,
C);
2793 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2794 Succ = ConfluenceBlock;
2796 CFGBlock *LHSBlock = Visit(
C->getLHS(), alwaysAdd);
2800 Succ = ConfluenceBlock;
2802 CFGBlock *RHSBlock = Visit(
C->getRHS(), alwaysAdd);
2806 Block = createBlock(
false);
2808 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2809 addSuccessor(
Block, KnownVal.isFalse() ?
nullptr : LHSBlock);
2810 addSuccessor(
Block, KnownVal.isTrue() ?
nullptr : RHSBlock);
2812 return addStmt(
C->getCond());
2816 bool ExternallyDestructed) {
2817 LocalScope::const_iterator scopeBeginPos = ScopePos;
2818 addLocalScopeForStmt(
C);
2820 if (!
C->body_empty() && !isa<ReturnStmt>(*
C->body_rbegin())) {
2823 addAutomaticObjHandling(ScopePos, scopeBeginPos,
C);
2828 for (
Stmt *S : llvm::reverse(
C->body())) {
2831 CFGBlock *newBlock = Visit(S, AddStmtChoice::AlwaysAdd,
2832 ExternallyDestructed);
2835 LastBlock = newBlock;
2840 ExternallyDestructed =
false;
2847 AddStmtChoice asc) {
2854 appendStmt(ConfluenceBlock,
C);
2858 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2864 Succ = ConfluenceBlock;
2867 const Expr *trueExpr =
C->getTrueExpr();
2868 if (trueExpr != opaqueValue) {
2869 LHSBlock = Visit(
C->getTrueExpr(), alwaysAdd);
2875 LHSBlock = ConfluenceBlock;
2878 Succ = ConfluenceBlock;
2879 CFGBlock *RHSBlock = Visit(
C->getFalseExpr(), alwaysAdd);
2885 dyn_cast<BinaryOperator>(
C->getCond()->IgnoreParens()))
2886 if (Cond->isLogicalOp())
2887 return VisitLogicalOperator(Cond,
C, LHSBlock, RHSBlock).first;
2890 Block = createBlock(
false);
2893 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2894 addSuccessor(
Block, LHSBlock, !KnownVal.isFalse());
2895 addSuccessor(
Block, RHSBlock, !KnownVal.isTrue());
2897 Expr *condExpr =
C->getCond();
2902 if (condExpr != opaqueValue)
2910 return addStmt(condExpr);
2921 return VisitDeclSubExpr(DS);
2935 cfg->addSyntheticDeclStmt(DSNew, DS);
2938 B = VisitDeclSubExpr(DSNew);
2947 assert(DS->
isSingleDecl() &&
"Can handle single declarations only.");
2949 if (
const auto *TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl())) {
2951 const Type *
T = TND->getUnderlyingType().getTypePtr();
2956 appendStmt(
Block, DS);
2960 VA =
FindVA(VA->getElementType().getTypePtr())) {
2961 if (
CFGBlock *NewBlock = addStmt(VA->getSizeExpr()))
2962 LastBlock = NewBlock;
2975 bool HasTemporaries =
false;
2978 CFGBlock *blockAfterStaticInit =
nullptr;
2989 blockAfterStaticInit = Succ;
2996 HasTemporaries = isa<ExprWithCleanups>(
Init);
3000 TempDtorContext Context;
3001 VisitForTemporaryDtors(cast<ExprWithCleanups>(
Init)->getSubExpr(),
3008 if (
const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
3009 for (
auto *BD : llvm::reverse(DD->bindings())) {
3010 if (
auto *VD = BD->getHoldingVar()) {
3014 cfg->addSyntheticDeclStmt(DSNew, DS);
3015 Block = VisitDeclSubExpr(DSNew);
3021 appendStmt(
Block, DS);
3025 const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(
Init);
3027 findConstructionContexts(
3029 AILE ? AILE->getSubExpr() :
Init);
3037 if (HasTemporaries) {
3042 LastBlock = newBlock;
3046 LastBlock = newBlock;
3054 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr())) {
3055 if (
CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
3056 LastBlock = newBlock;
3059 maybeAddScopeBeginForVarDecl(
Block, VD, DS);
3062 if (ScopePos && VD == *ScopePos)
3066 if (blockAfterStaticInit) {
3068 Block = createBlock(
false);
3070 addSuccessor(
Block, blockAfterStaticInit);
3071 addSuccessor(
Block, B);
3092 addLocalScopeForStmt(
Init);
3097 addLocalScopeForVarDecl(VD);
3099 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
3121 if (!isa<CompoundStmt>(Else))
3122 addLocalScopeAndDtors(Else);
3124 ElseBlock = addStmt(Else);
3127 ElseBlock = sv.get();
3144 if (!isa<CompoundStmt>(Then))
3145 addLocalScopeAndDtors(Then);
3147 ThenBlock = addStmt(Then);
3153 ThenBlock = createBlock(
false);
3154 addSuccessor(ThenBlock, sv.get());
3174 LastBlock = VisitLogicalOperator(Cond, I, ThenBlock, ElseBlock).first;
3177 Block = createBlock(
false);
3185 KnownVal = tryEvaluateBool(I->
getCond());
3189 addSuccessor(
Block, ThenBlock, !KnownVal.isFalse());
3190 addSuccessor(
Block, ElseBlock, !KnownVal.isTrue());
3198 LastBlock = addStmt(I->
getCond());
3204 LastBlock = addStmt(
const_cast<DeclStmt *
>(DS));
3211 LastBlock = addStmt(
Init);
3224 assert(isa<ReturnStmt>(S) || isa<CoreturnStmt>(S));
3227 Block = createBlock(
false);
3229 addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), S);
3231 if (
auto *R = dyn_cast<ReturnStmt>(S))
3232 findConstructionContexts(
3239 addSuccessor(
Block, &cfg->getExit());
3242 appendStmt(
Block, S);
3245 if (
ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
3246 if (
Expr *O = RS->getRetValue())
3247 return Visit(O, AddStmtChoice::AlwaysAdd,
true);
3257 if (RV->getType()->isVoidType() && !isa<InitListExpr>(RV))
3266 AddStmtChoice asc) {
3270 if (asc.alwaysAdd(*
this,
E)) {
3275 if (
auto *R = Visit(
E->getResumeExpr()))
3277 if (
auto *R = Visit(
E->getSuspendExpr()))
3279 if (
auto *R = Visit(
E->getReadyExpr()))
3281 if (
auto *R = Visit(
E->getCommonExpr()))
3296 if (!SEHExceptBlock)
3297 SEHExceptBlock = createBlock();
3299 appendStmt(SEHExceptBlock, ES);
3311 return SEHExceptBlock;
3315 return VisitCompoundStmt(FS->getBlock(),
false);
3325 Block = createBlock(
false);
3330 if (SEHLeaveJumpTarget.block) {
3331 addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS);
3332 addSuccessor(
Block, SEHLeaveJumpTarget.block);
3342 CFGBlock *SEHTrySuccessor =
nullptr;
3347 SEHTrySuccessor =
Block;
3348 }
else SEHTrySuccessor = Succ;
3354 CFGBlock *PrevSEHTryTerminatedBlock = TryTerminatedBlock;
3357 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
3364 Succ = SEHTrySuccessor;
3366 CFGBlock *ExceptBlock = VisitSEHExceptStmt(Except);
3371 addSuccessor(NewTryTerminatedBlock, ExceptBlock);
3373 if (PrevSEHTryTerminatedBlock)
3374 addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock);
3376 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
3379 Succ = SEHTrySuccessor;
3382 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
3383 cfg->addTryDispatchBlock(TryTerminatedBlock);
3389 SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
3391 assert(Terminator->
getTryBlock() &&
"__try must contain a non-NULL body");
3402 LabelBlock = createBlock();
3404 assert(!LabelMap.contains(L->
getDecl()) &&
"label already in map");
3405 LabelMap[L->
getDecl()] = JumpTarget(LabelBlock, ScopePos);
3425 CFGBlock *LastBlock = VisitNoRecurse(
E, asc);
3427 if (
Expr *CopyExpr = CI.getCopyExpr()) {
3437 CFGBlock *LastBlock = VisitNoRecurse(
E, asc);
3441 et =
E->capture_init_end();
3442 it != et; ++it, ++Idx) {
3447 dyn_cast<ArrayInitLoopExpr>(
Init));
3450 cfg->getBumpVectorContext(), {E, Idx}),
3451 AILEInit ? AILEInit :
Init);
3465 Block = createBlock(
false);
3469 LabelMapTy::iterator I = LabelMap.find(G->
getLabel());
3471 if (I == LabelMap.end())
3473 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3475 JumpTarget JT = I->second;
3476 addSuccessor(
Block, JT.block);
3477 addScopeChangesHandling(ScopePos, JT.scopePosition, G);
3488 return VisitStmt(G, asc);
3495 Block = createBlock();
3498 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3501 BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
3502 return VisitChildren(G);
3516 addLocalScopeForStmt(
Init);
3517 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3520 addLocalScopeForVarDecl(VD);
3521 LocalScope::const_iterator ContinueScopePos = ScopePos;
3523 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
3532 LoopSuccessor =
Block;
3534 LoopSuccessor = Succ;
3539 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3541 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3554 Block = Succ = TransitionBlock = createBlock(
false);
3555 TransitionBlock->setLoopTarget(F);
3560 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
3570 assert(
Block == Succ);
3578 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
3579 ContinueJumpTarget.block->setLoopTarget(F);
3584 if (!isa<CompoundStmt>(F->
getBody()))
3585 addLocalScopeAndDtors(F->
getBody());
3589 BodyBlock = addStmt(F->
getBody());
3594 BodyBlock = ContinueJumpTarget.block;
3603 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3612 dyn_cast_or_null<BinaryOperator>(
C ?
C->IgnoreParens() :
nullptr))
3614 std::tie(EntryConditionBlock, ExitConditionBlock) =
3615 VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor);
3620 EntryConditionBlock = ExitConditionBlock = createBlock(
false);
3621 ExitConditionBlock->setTerminator(F);
3624 TryResult KnownVal(
true);
3630 Block = ExitConditionBlock;
3631 EntryConditionBlock = addStmt(
C);
3640 findConstructionContexts(
3643 appendStmt(
Block, DS);
3644 EntryConditionBlock = addStmt(
Init);
3645 assert(
Block == EntryConditionBlock);
3646 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3650 if (
Block && badCFG)
3653 KnownVal = tryEvaluateBool(
C);
3657 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
3660 addSuccessor(ExitConditionBlock,
3661 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
3665 addSuccessor(TransitionBlock, EntryConditionBlock);
3668 Succ = EntryConditionBlock;
3674 ScopePos = LoopBeginScopePos;
3675 Block = createBlock();
3682 Succ = EntryConditionBlock;
3683 return EntryConditionBlock;
3688 AddStmtChoice asc) {
3689 findConstructionContexts(
3693 return VisitStmt(MTE, asc);
3697 if (asc.alwaysAdd(*
this, M)) {
3699 appendStmt(
Block, M);
3741 LoopSuccessor =
Block;
3744 LoopSuccessor = Succ;
3747 CFGBlock *ExitConditionBlock = createBlock(
false);
3755 appendStmt(ExitConditionBlock, S);
3756 Block = ExitConditionBlock;
3761 CFGBlock *EntryConditionBlock = Visit(S->getElement(),
3762 AddStmtChoice::NotAlwaysAdd);
3771 Succ = EntryConditionBlock;
3778 save_break(BreakJumpTarget);
3784 Succ = LoopBackBlock = createBlock();
3787 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3788 ContinueJumpTarget = JumpTarget(Succ, ScopePos);
3790 CFGBlock *BodyBlock = addStmt(S->getBody());
3793 BodyBlock = ContinueJumpTarget.block;
3800 addSuccessor(ExitConditionBlock, BodyBlock);
3805 addSuccessor(ExitConditionBlock, LoopSuccessor);
3808 Block = createBlock();
3809 return addStmt(S->getCollection());
3814 return addStmt(S->getSubStmt());
3822 CFGBlock *SyncBlock = addStmt(S->getSynchBody());
3836 appendStmt(
Block, S);
3839 return addStmt(S->getSynchExpr());
3852 for (
unsigned i =
E->getNumSemanticExprs(); i != 0; ) {
3853 Expr *Semantic =
E->getSemanticExpr(--i);
3858 Semantic = OVE->getSourceExpr();
3876 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3878 addLocalScopeForVarDecl(VD);
3879 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
3888 LoopSuccessor =
Block;
3891 LoopSuccessor = Succ;
3894 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3903 save_break(BreakJumpTarget);
3907 Succ = TransitionBlock = createBlock(
false);
3908 TransitionBlock->setLoopTarget(W);
3909 ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
3912 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3915 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
3919 if (!isa<CompoundStmt>(W->
getBody()))
3920 addLocalScopeAndDtors(W->
getBody());
3923 BodyBlock = addStmt(W->
getBody());
3926 BodyBlock = ContinueJumpTarget.block;
3927 else if (
Block && badCFG)
3934 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3941 if (
BinaryOperator *Cond = dyn_cast<BinaryOperator>(
C->IgnoreParens()))
3943 std::tie(EntryConditionBlock, ExitConditionBlock) =
3944 VisitLogicalOperator(Cond, W, BodyBlock, LoopSuccessor);
3949 ExitConditionBlock = createBlock(
false);
3955 Block = ExitConditionBlock;
3956 Block = EntryConditionBlock = addStmt(
C);
3965 findConstructionContexts(
3969 appendStmt(
Block, DS);
3970 EntryConditionBlock = addStmt(
Init);
3971 assert(
Block == EntryConditionBlock);
3972 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3976 if (
Block && badCFG)
3980 const TryResult& KnownVal = tryEvaluateBool(
C);
3983 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
3986 addSuccessor(ExitConditionBlock,
3987 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
3991 addSuccessor(TransitionBlock, EntryConditionBlock);
3998 Succ = EntryConditionBlock;
3999 return EntryConditionBlock;
4003 AddStmtChoice asc) {
4004 if (asc.alwaysAdd(*
this, A)) {
4006 appendStmt(
Block, A);
4015 assert(OVE &&
"ArrayInitLoopExpr->getCommonExpr() should be wrapped in an "
4016 "OpaqueValueExpr!");
4017 if (
CFGBlock *R = Visit(OVE->getSourceExpr()))
4036 CatchBlock = createBlock();
4038 appendStmt(CatchBlock, CS);
4059 Block = createBlock(
false);
4061 if (TryTerminatedBlock)
4063 addSuccessor(
Block, TryTerminatedBlock);
4066 addSuccessor(
Block, &cfg->getExit());
4070 return VisitStmt(S, AddStmtChoice::AlwaysAdd);
4081 TrySuccessor =
Block;
4083 TrySuccessor = Succ;
4089 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4092 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4096 bool HasCatchAll =
false;
4099 Succ = TrySuccessor;
4104 CFGBlock *CatchBlock = VisitObjCAtCatchStmt(CS);
4109 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4114 if (PrevTryTerminatedBlock)
4115 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4117 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4121 Succ = TrySuccessor;
4124 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4125 cfg->addTryDispatchBlock(TryTerminatedBlock);
4127 assert(Terminator->
getTryBody() &&
"try must contain a non-NULL body");
4133 AddStmtChoice asc) {
4134 findConstructionContextsForArguments(ME);
4137 appendObjCMessage(
Block, ME);
4139 return VisitChildren(ME);
4148 Block = createBlock(
false);
4150 if (TryTerminatedBlock)
4152 addSuccessor(
Block, TryTerminatedBlock);
4155 addSuccessor(
Block, &cfg->getExit());
4159 return VisitStmt(
T, AddStmtChoice::AlwaysAdd);
4163 if (asc.alwaysAdd(*
this, S)) {
4165 appendStmt(
Block, S);
4174 if (!S->isTypeDependent() && S->isPotentiallyEvaluated())
4175 return VisitChildren(S);
4191 LoopSuccessor =
Block;
4193 LoopSuccessor = Succ;
4198 CFGBlock *ExitConditionBlock = createBlock(
false);
4199 CFGBlock *EntryConditionBlock = ExitConditionBlock;
4206 if (
Stmt *
C =
D->getCond()) {
4207 Block = ExitConditionBlock;
4208 EntryConditionBlock = addStmt(
C);
4216 Succ = EntryConditionBlock;
4219 const TryResult &KnownVal = tryEvaluateBool(
D->getCond());
4229 save_break(BreakJumpTarget);
4232 ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
4235 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4242 if (!isa<CompoundStmt>(
D->
getBody()))
4243 addLocalScopeAndDtors(
D->
getBody());
4249 BodyBlock = EntryConditionBlock;
4262 CFGBlock *LoopBackBlock = createBlock();
4265 if (!KnownVal.isFalse())
4267 addSuccessor(ExitConditionBlock, LoopBackBlock);
4269 addSuccessor(ExitConditionBlock,
nullptr);
4274 addSuccessor(ExitConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4292 Block = createBlock(
false);
4297 if (ContinueJumpTarget.block) {
4298 addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition,
C);
4299 addSuccessor(
Block, ContinueJumpTarget.block);
4307 AddStmtChoice asc) {
4308 if (asc.alwaysAdd(*
this,
E)) {
4316 if (
E->getKind() != UETT_SizeOf)
4321 if (
E->isArgumentType()) {
4323 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr()))
4324 lastBlock = addStmt(VA->getSizeExpr());
4332 if (asc.alwaysAdd(*
this, SE)) {
4334 appendStmt(
Block, SE);
4336 return VisitCompoundStmt(SE->
getSubStmt(),
true);
4342 CFGBlock *SwitchSuccessor =
nullptr;
4350 addLocalScopeForStmt(
Init);
4355 addLocalScopeForVarDecl(VD);
4357 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
4362 SwitchSuccessor =
Block;
4363 }
else SwitchSuccessor = Succ;
4367 save_default(DefaultCaseBlock);
4373 DefaultCaseBlock = SwitchSuccessor;
4376 SwitchTerminatedBlock = createBlock(
false);
4380 Succ = SwitchSuccessor;
4381 BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
4386 assert(Terminator->
getBody() &&
"switch must contain a non-NULL body");
4391 SaveAndRestore save_switchExclusivelyCovered(switchExclusivelyCovered,
false);
4394 assert(Terminator->
getCond() &&
"switch condition must be non-NULL");
4396 bool b = tryEvaluate(Terminator->
getCond(), result);
4401 if (!isa<CompoundStmt>(Terminator->
getBody()))
4402 addLocalScopeAndDtors(Terminator->
getBody());
4404 addStmt(Terminator->
getBody());
4416 bool SwitchAlwaysHasSuccessor =
false;
4417 SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
4420 addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock,
4421 !SwitchAlwaysHasSuccessor);
4425 Block = SwitchTerminatedBlock;
4434 LastBlock = addStmt(
Init);
4435 maybeAddScopeBeginForVarDecl(LastBlock, VD,
Init);
4442 LastBlock = addStmt(
Init);
4455 bool addCase =
false;
4457 if (!switchExclusivelyCovered) {
4461 const llvm::APSInt &condInt = switchCond->
Val.
getInt();
4463 if (condInt == lhsInt) {
4465 switchExclusivelyCovered =
true;
4467 else if (condInt > lhsInt) {
4471 if (V2 >= condInt) {
4473 switchExclusivelyCovered =
true;
4487 CFGBlock *TopBlock =
nullptr, *LastBlock =
nullptr;
4493 while (isa<CaseStmt>(Sub)) {
4494 CFGBlock *currentBlock = createBlock(
false);
4498 addSuccessor(LastBlock, currentBlock);
4500 TopBlock = currentBlock;
4502 addSuccessor(SwitchTerminatedBlock,
4505 ? currentBlock :
nullptr);
4507 LastBlock = currentBlock;
4508 CS = cast<CaseStmt>(Sub);
4517 CaseBlock = createBlock();
4528 assert(SwitchTerminatedBlock);
4529 addSuccessor(SwitchTerminatedBlock, CaseBlock,
4537 addSuccessor(LastBlock, CaseBlock);
4551 DefaultCaseBlock =
Block;
4553 if (!DefaultCaseBlock)
4554 DefaultCaseBlock = createBlock();
4558 DefaultCaseBlock->
setLabel(Terminator);
4573 Succ = DefaultCaseBlock;
4575 return DefaultCaseBlock;
4586 TrySuccessor =
Block;
4588 TrySuccessor = Succ;
4590 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4593 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4597 bool HasCatchAll =
false;
4600 Succ = TrySuccessor;
4606 CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
4611 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4614 if (PrevTryTerminatedBlock)
4615 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4617 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4621 Succ = TrySuccessor;
4624 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4625 cfg->addTryDispatchBlock(TryTerminatedBlock);
4627 assert(Terminator->
getTryBlock() &&
"try must contain a non-NULL body");
4643 LocalScope::const_iterator BeginScopePos = ScopePos;
4644 addLocalScopeForVarDecl(VD);
4645 addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
4653 CatchBlock = createBlock();
4659 appendStmt(CatchBlock, CS);
4694 addLocalScopeForStmt(
Range);
4696 addLocalScopeForStmt(
Begin);
4697 if (
Stmt *End = S->getEndStmt())
4698 addLocalScopeForStmt(End);
4699 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
4701 LocalScope::const_iterator ContinueScopePos = ScopePos;
4709 LoopSuccessor =
Block;
4711 LoopSuccessor = Succ;
4716 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4719 CFGBlock *ConditionBlock = createBlock(
false);
4723 if (
Expr *
C = S->getCond()) {
4724 Block = ConditionBlock;
4725 CFGBlock *BeginConditionBlock = addStmt(
C);
4728 assert(BeginConditionBlock == ConditionBlock &&
4729 "condition block in for-range was unexpectedly complex");
4730 (void)BeginConditionBlock;
4735 Succ = ConditionBlock;
4738 TryResult KnownVal(
true);
4741 KnownVal = tryEvaluateBool(S->getCond());
4745 assert(S->getBody());
4754 Succ = addStmt(S->getInc());
4757 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
4761 ContinueJumpTarget.block->setLoopTarget(S);
4770 addLocalScopeAndDtors(S->getLoopVarStmt());
4774 if (!isa<CompoundStmt>(S->getBody()))
4775 addLocalScopeAndDtors(S->getBody());
4778 addStmt(S->getBody());
4782 CFGBlock *LoopVarStmtBlock = addStmt(S->getLoopVarStmt());
4787 addSuccessor(ConditionBlock,
4788 KnownVal.isFalse() ?
nullptr : LoopVarStmtBlock);
4793 addSuccessor(ConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4796 Block = createBlock();
4797 addStmt(S->getBeginStmt());
4798 addStmt(S->getEndStmt());
4799 CFGBlock *Head = addStmt(S->getRangeStmt());
4801 Head = addStmt(S->getInit());
4806 AddStmtChoice asc,
bool ExternallyDestructed) {
4810 TempDtorContext Context;
4811 VisitForTemporaryDtors(
E->getSubExpr(), ExternallyDestructed, Context);
4815 asc = asc.withAlwaysAdd(
true);
4817 return Visit(
E->getSubExpr(), asc);
4821 AddStmtChoice asc) {
4822 if (asc.alwaysAdd(*
this,
E)) {
4826 findConstructionContexts(
4831 asc = asc.withAlwaysAdd(
false);
4833 return Visit(
E->getSubExpr(), asc);
4837 AddStmtChoice asc) {
4841 findConstructionContextsForArguments(
C);
4842 appendConstructor(
C);
4844 return VisitChildren(
C);
4848 AddStmtChoice asc) {
4850 appendStmt(
Block, NE);
4852 findConstructionContexts(
4856 if (
NE->getInitializer())
4857 Block = Visit(
NE->getInitializer());
4860 appendNewAllocator(
Block, NE);
4862 if (
NE->isArray() && *
NE->getArraySize())
4863 Block = Visit(*
NE->getArraySize());
4866 E =
NE->placement_arg_end(); I !=
E; ++I)
4873 AddStmtChoice asc) {
4875 appendStmt(
Block, DE);
4882 appendDeleteDtor(
Block, RD, DE);
4886 return VisitChildren(DE);
4890 AddStmtChoice asc) {
4891 if (asc.alwaysAdd(*
this,
E)) {
4895 asc = asc.withAlwaysAdd(
false);
4897 return Visit(
E->getSubExpr(), asc);
4901 AddStmtChoice asc) {
4905 findConstructionContextsForArguments(
E);
4906 appendConstructor(
E);
4908 return VisitChildren(
E);
4912 AddStmtChoice asc) {
4913 if (asc.alwaysAdd(*
this,
E)) {
4918 if (
E->getCastKind() == CK_IntegralToBoolean)
4921 return Visit(
E->getSubExpr(), AddStmtChoice());
4925 return Visit(
E->getSubExpr(), AddStmtChoice());
4930 CFGBlock *IBlock = cfg->getIndirectGotoBlock();
4933 IBlock = createBlock(
false);
4934 cfg->setIndirectGotoBlock(IBlock);
4942 Block = createBlock(
false);
4944 addSuccessor(
Block, IBlock);
4948CFGBlock *CFGBuilder::VisitForTemporaryDtors(
Stmt *
E,
bool ExternallyDestructed,
4949 TempDtorContext &Context) {
4959 return VisitChildrenForTemporaryDtors(
E,
false, Context);
4961 case Stmt::InitListExprClass:
4962 return VisitChildrenForTemporaryDtors(
E, ExternallyDestructed, Context);
4964 case Stmt::BinaryOperatorClass:
4965 return VisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(
E),
4966 ExternallyDestructed,
4969 case Stmt::CXXBindTemporaryExprClass:
4970 return VisitCXXBindTemporaryExprForTemporaryDtors(
4971 cast<CXXBindTemporaryExpr>(
E), ExternallyDestructed, Context);
4973 case Stmt::BinaryConditionalOperatorClass:
4974 case Stmt::ConditionalOperatorClass:
4975 return VisitConditionalOperatorForTemporaryDtors(
4976 cast<AbstractConditionalOperator>(
E), ExternallyDestructed, Context);
4978 case Stmt::ImplicitCastExprClass:
4980 E = cast<CastExpr>(
E)->getSubExpr();
4983 case Stmt::CXXFunctionalCastExprClass:
4985 E = cast<CXXFunctionalCastExpr>(
E)->getSubExpr();
4988 case Stmt::ConstantExprClass:
4989 E = cast<ConstantExpr>(
E)->getSubExpr();
4992 case Stmt::ParenExprClass:
4993 E = cast<ParenExpr>(
E)->getSubExpr();
4996 case Stmt::MaterializeTemporaryExprClass: {
5002 E =
const_cast<Expr *
>(
5003 cast<MaterializeTemporaryExpr>(
E)
5005 ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
5007 for (
const Expr *CommaLHS : CommaLHSs) {
5008 VisitForTemporaryDtors(
const_cast<Expr *
>(CommaLHS),
5014 case Stmt::BlockExprClass:
5019 case Stmt::LambdaExprClass: {
5022 auto *
LE = cast<LambdaExpr>(
E);
5026 if (
CFGBlock *R = VisitForTemporaryDtors(
5027 Init,
true, Context))
5034 case Stmt::StmtExprClass:
5039 case Stmt::CXXDefaultArgExprClass:
5040 E = cast<CXXDefaultArgExpr>(
E)->getExpr();
5043 case Stmt::CXXDefaultInitExprClass:
5044 E = cast<CXXDefaultInitExpr>(
E)->getExpr();
5049CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(
Stmt *
E,
5050 bool ExternallyDestructed,
5051 TempDtorContext &Context) {
5052 if (isa<LambdaExpr>(
E)) {
5064 if (
CFGBlock *R = VisitForTemporaryDtors(Child, ExternallyDestructed, Context))
5070CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
5071 BinaryOperator *
E,
bool ExternallyDestructed, TempDtorContext &Context) {
5072 if (
E->isCommaOp()) {
5075 CFGBlock *LHSBlock = VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5076 CFGBlock *RHSBlock = VisitForTemporaryDtors(
E->getRHS(), ExternallyDestructed, Context);
5077 return RHSBlock ? RHSBlock : LHSBlock;
5080 if (
E->isLogicalOp()) {
5081 VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5082 TryResult RHSExecuted = tryEvaluateBool(
E->getLHS());
5083 if (RHSExecuted.isKnown() &&
E->getOpcode() == BO_LOr)
5084 RHSExecuted.negate();
5089 TempDtorContext RHSContext(
5091 VisitForTemporaryDtors(
E->getRHS(),
false, RHSContext);
5092 InsertTempDtorDecisionBlock(RHSContext);
5097 if (
E->isAssignmentOp()) {
5100 CFGBlock *RHSBlock = VisitForTemporaryDtors(
E->getRHS(),
false, Context);
5101 CFGBlock *LHSBlock = VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5102 return LHSBlock ? LHSBlock : RHSBlock;
5106 return VisitChildrenForTemporaryDtors(
E, ExternallyDestructed, Context);
5109CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
5113 CFGBlock *B = VisitForTemporaryDtors(
E->getSubExpr(),
true, Context);
5114 if (!ExternallyDestructed) {
5126 Block = createNoReturnBlock();
5127 }
else if (Context.needsTempDtorBranch()) {
5131 Block = createBlock();
5135 if (Context.needsTempDtorBranch()) {
5136 Context.setDecisionPoint(Succ,
E);
5138 appendTemporaryDtor(
Block,
E);
5145void CFGBuilder::InsertTempDtorDecisionBlock(
const TempDtorContext &Context,
5147 if (!Context.TerminatorExpr) {
5151 assert(Context.TerminatorExpr);
5152 CFGBlock *Decision = createBlock(
false);
5155 addSuccessor(Decision,
Block, !Context.KnownExecuted.isFalse());
5156 addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
5157 !Context.KnownExecuted.isTrue());
5161CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
5163 TempDtorContext &Context) {
5164 VisitForTemporaryDtors(
E->getCond(),
false, Context);
5167 TryResult ConditionVal = tryEvaluateBool(
E->getCond());
5168 TryResult NegatedVal = ConditionVal;
5169 if (NegatedVal.isKnown()) NegatedVal.negate();
5171 TempDtorContext TrueContext(
5173 VisitForTemporaryDtors(
E->getTrueExpr(), ExternallyDestructed, TrueContext);
5176 Block = ConditionBlock;
5177 Succ = ConditionSucc;
5178 TempDtorContext FalseContext(
5180 VisitForTemporaryDtors(
E->getFalseExpr(), ExternallyDestructed, FalseContext);
5182 if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
5183 InsertTempDtorDecisionBlock(FalseContext, TrueBlock);
5184 }
else if (TrueContext.TerminatorExpr) {
5186 InsertTempDtorDecisionBlock(TrueContext);
5188 InsertTempDtorDecisionBlock(FalseContext);
5194 AddStmtChoice asc) {
5195 if (asc.alwaysAdd(*
this,
D)) {
5207 for (
Stmt *S : llvm::reverse(
Used)) {
5208 assert(S &&
"Expected non-null used-in-clause child.");
5213 if (!
D->isStandaloneDirective()) {
5214 Stmt *S =
D->getRawStmt();
5215 if (!isa<CompoundStmt>(S))
5216 addLocalScopeAndDtors(S);
5228 bool first_block =
begin() ==
end();
5236 Entry = Exit = &
back();
5245 CFGBuilder Builder(
C, BO);
5246 return Builder.buildCFG(
D, Statement);
5261 auto IteratorAndFlag =
Visited.insert(B);
5262 if (!IteratorAndFlag.second) {
5268 const CFGBlock *FirstReachableB =
nullptr;
5270 if (!AB.isReachable())
5273 if (FirstReachableB ==
nullptr) {
5274 FirstReachableB = &*AB;
5281 if (!FirstReachableB) {
5287 B = FirstReachableB;
5307 llvm_unreachable(
"getDestructorDecl should only be used with "
5310 const VarDecl *var = castAs<CFGAutomaticObjDtor>().getVarDecl();
5318 if (
const Expr *
Init = var->getInit()) {
5336 const CXXDeleteExpr *DE = castAs<CFGDeleteDtor>().getDeleteExpr();
5345 castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
5350 const FieldDecl *field = castAs<CFGMemberDtor>().getFieldDecl();
5365 llvm_unreachable(
"getKind() returned bogus value");
5373 : ReachableBlock(IsReachable ? B : nullptr),
5374 UnreachableBlock(!IsReachable ? B : nullptr,
5375 B && IsReachable ? AB_Normal : AB_Unreachable) {}
5378 : ReachableBlock(B),
5379 UnreachableBlock(B == AlternateBlock ? nullptr : AlternateBlock,
5380 B == AlternateBlock ? AB_Alternate : AB_Normal) {}
5403 if (S->isAllEnumCasesCovered()) {
5405 if (!L || !isa<CaseStmt>(L))
5421 using StmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>;
5422 using DeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>;
5426 signed currentBlock = 0;
5427 unsigned currStmt = 0;
5438 BI != BEnd; ++BI, ++j ) {
5439 if (std::optional<CFGStmt> SE = BI->getAs<
CFGStmt>()) {
5441 std::pair<unsigned, unsigned>
P((*I)->getBlockID(), j);
5444 switch (
stmt->getStmtClass()) {
5445 case Stmt::DeclStmtClass:
5446 DeclMap[cast<DeclStmt>(
stmt)->getSingleDecl()] =
P;
5448 case Stmt::IfStmtClass: {
5449 const VarDecl *var = cast<IfStmt>(
stmt)->getConditionVariable();
5454 case Stmt::ForStmtClass: {
5455 const VarDecl *var = cast<ForStmt>(
stmt)->getConditionVariable();
5460 case Stmt::WhileStmtClass: {
5462 cast<WhileStmt>(
stmt)->getConditionVariable();
5467 case Stmt::SwitchStmtClass: {
5469 cast<SwitchStmt>(
stmt)->getConditionVariable();
5474 case Stmt::CXXCatchStmtClass: {
5476 cast<CXXCatchStmt>(
stmt)->getExceptionDecl();
5489 ~StmtPrinterHelper()
override =
default;
5491 const LangOptions &getLangOpts()
const {
return LangOpts; }
5492 void setBlockID(
signed i) { currentBlock = i; }
5493 void setStmtID(
unsigned i) { currStmt = i; }
5495 bool handledStmt(
Stmt *S, raw_ostream &OS)
override {
5496 StmtMapTy::iterator I = StmtMap.find(S);
5498 if (I == StmtMap.end())
5501 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5502 && I->second.second == currStmt) {
5506 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5510 bool handleDecl(
const Decl *
D, raw_ostream &OS) {
5511 DeclMapTy::iterator I = DeclMap.find(
D);
5513 if (I == DeclMap.end())
5516 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5517 && I->second.second == currStmt) {
5521 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5526class CFGBlockTerminatorPrint
5527 :
public StmtVisitor<CFGBlockTerminatorPrint,void> {
5529 StmtPrinterHelper* Helper;
5533 CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
5535 : OS(os), Helper(helper), Policy(Policy) {
5539 void VisitIfStmt(
IfStmt *I) {
5542 C->printPretty(OS, Helper, Policy);
5546 void VisitStmt(
Stmt *Terminator) {
5552 OS <<
"static init " << VD->
getName();
5555 void VisitForStmt(
ForStmt *F) {
5561 C->printPretty(OS, Helper, Policy);
5571 C->printPretty(OS, Helper, Policy);
5575 OS <<
"do ... while ";
5576 if (
Stmt *
C =
D->getCond())
5577 C->printPretty(OS, Helper, Policy);
5580 void VisitSwitchStmt(
SwitchStmt *Terminator) {
5585 void VisitCXXTryStmt(
CXXTryStmt *) { OS <<
"try ..."; }
5587 void VisitObjCAtTryStmt(
ObjCAtTryStmt *) { OS <<
"@try ..."; }
5589 void VisitSEHTryStmt(
SEHTryStmt *CS) { OS <<
"__try ..."; }
5592 if (
Stmt *Cond =
C->getCond())
5594 OS <<
" ? ... : ...";
5598 OS <<
"__builtin_choose_expr( ";
5599 if (
Stmt *Cond =
C->getCond())
5607 T->printPretty(OS, Helper, Policy);
5627 llvm_unreachable(
"Invalid logical operator.");
5631 void VisitExpr(
Expr *
E) {
5637 switch (
T.getKind()) {
5642 OS <<
"(Temp Dtor) ";
5646 OS <<
"(See if most derived ctor has already initialized vbases)";
5664 IE->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
5668 OS <<
" (Base initializer)";
5670 OS <<
" (Delegating initializer)";
5672 OS <<
" (Member initializer)";
5676 StmtPrinterHelper &Helper,
5682 const auto *SICC = cast<SimpleConstructorInitializerConstructionContext>(CC);
5689 cast<CXX17ElidedCopyConstructorInitializerConstructionContext>(CC);
5691 Stmts.push_back(CICC->getCXXBindTemporaryExpr());
5695 const auto *SDSCC = cast<SimpleVariableConstructionContext>(CC);
5696 Stmts.push_back(SDSCC->getDeclStmt());
5700 const auto *CDSCC = cast<CXX17ElidedCopyVariableConstructionContext>(CC);
5701 Stmts.push_back(CDSCC->getDeclStmt());
5702 Stmts.push_back(CDSCC->getCXXBindTemporaryExpr());
5706 const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
5707 Stmts.push_back(NECC->getCXXNewExpr());
5711 const auto *RSCC = cast<SimpleReturnedValueConstructionContext>(CC);
5712 Stmts.push_back(RSCC->getReturnStmt());
5717 cast<CXX17ElidedCopyReturnedValueConstructionContext>(CC);
5718 Stmts.push_back(RSCC->getReturnStmt());
5719 Stmts.push_back(RSCC->getCXXBindTemporaryExpr());
5723 const auto *TOCC = cast<SimpleTemporaryObjectConstructionContext>(CC);
5724 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5725 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5729 const auto *TOCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
5730 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5731 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5732 Stmts.push_back(TOCC->getConstructorAfterElision());
5736 const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
5737 Helper.handledStmt(
const_cast<LambdaExpr *
>(LCC->getLambdaExpr()), OS);
5738 OS <<
"+" << LCC->getIndex();
5742 const auto *ACC = cast<ArgumentConstructionContext>(CC);
5743 if (
const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
5745 Helper.handledStmt(
const_cast<Stmt *
>(BTE), OS);
5748 Helper.handledStmt(
const_cast<Expr *
>(ACC->getCallLikeExpr()), OS);
5749 OS <<
"+" << ACC->getIndex();
5756 Helper.handledStmt(
const_cast<Stmt *
>(I), OS);
5760static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5765 StmtPrinterHelper Helper(
nullptr, LangOpts);
5769static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5771 switch (
E.getKind()) {
5777 assert(S !=
nullptr &&
"Expecting non-null Stmt");
5780 if (
const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
5783 auto Children = Sub->children();
5784 if (Children.begin() != Children.end()) {
5795 Helper.handledStmt(B->
getRHS(),OS);
5800 S->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
5803 if (isa<CXXOperatorCallExpr>(S))
5804 OS <<
" (OperatorCall)";
5805 OS <<
" (CXXRecordTypedCall";
5808 }
else if (isa<CXXOperatorCallExpr>(S)) {
5809 OS <<
" (OperatorCall)";
5810 }
else if (isa<CXXBindTemporaryExpr>(S)) {
5811 OS <<
" (BindTemporary)";
5813 OS <<
" (CXXConstructExpr";
5817 OS <<
", " << CCE->getType() <<
")";
5818 }
else if (
const CastExpr *CE = dyn_cast<CastExpr>(S)) {
5820 <<
", " << CE->
getType() <<
")";
5838 Helper.handleDecl(VD, OS);
5845 T.getUnqualifiedType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5846 OS <<
"() (Implicit destructor)\n";
5851 OS <<
"CleanupFunction ("
5857 OS <<
" (Lifetime ends)\n";
5861 OS <<
E.castAs<
CFGLoopExit>().getLoopStmt()->getStmtClassName() <<
" (LoopExit)\n";
5865 OS <<
"CFGScopeBegin(";
5872 OS <<
"CFGScopeEnd(";
5879 OS <<
"CFGNewAllocator(";
5881 AllocExpr->getType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5892 Helper.handledStmt(cast<Stmt>(DelExpr->
getArgument()), OS);
5893 OS <<
"->~" << RD->getName().str() <<
"()";
5894 OS <<
" (Implicit destructor)\n";
5901 OS <<
" (Base object destructor)\n";
5908 OS <<
"this->" << FD->
getName();
5910 OS <<
" (Member object destructor)\n";
5919 OS <<
"() (Temporary object destructor)\n";
5927 StmtPrinterHelper &Helper,
bool print_edges,
5933 OS.changeColor(raw_ostream::YELLOW,
true);
5938 OS <<
" (ENTRY)]\n";
5939 else if (&B == &cfg->
getExit())
5942 OS <<
" (INDIRECT GOTO DISPATCH)]\n";
5944 OS <<
" (NORETURN)]\n";
5960 if (
const Expr *LHS =
C->getLHS())
5962 if (
const Expr *RHS =
C->getRHS()) {
5966 }
else if (isa<DefaultStmt>(
Label))
5977 if (
const VarDecl *PD = CS->getCatchParamDecl())
5988 llvm_unreachable(
"Invalid label statement in CFGBlock.");
5997 I !=
E ; ++I, ++j ) {
6002 OS << llvm::format(
"%3d", j) <<
": ";
6004 Helper.setStmtID(j);
6012 OS.changeColor(raw_ostream::GREEN);
6016 Helper.setBlockID(-1);
6019 CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
6030 const raw_ostream::Colors Color = raw_ostream::BLUE;
6032 OS.changeColor(Color);
6040 OS.changeColor(Color);
6048 bool Reachable =
true;
6051 B = I->getPossiblyUnreachableBlock();
6056 OS <<
"(Unreachable)";
6067 const raw_ostream::Colors Color = raw_ostream::MAGENTA;
6069 OS.changeColor(Color);
6077 OS.changeColor(Color);
6086 bool Reachable =
true;
6089 B = I->getPossiblyUnreachableBlock();
6095 OS <<
"(Unreachable)";
6116 StmtPrinterHelper Helper(
this, LO);
6124 if (&(**I) == &getEntry() || &(**I) == &getExit())
6154 StmtPrinterHelper Helper(cfg, LO);
6162 CFGBlockTerminatorPrint TPrinter(OS,
nullptr,
PrintingPolicy(LO));
6168 bool AddQuotes)
const {
6170 llvm::raw_string_ostream TempOut(Buf);
6193 if (llvm::any_of(*Blk, [](
const CFGElement &Elm) {
6194 if (std::optional<CFGStmt> StmtElm = Elm.
getAs<
CFGStmt>())
6195 if (isa<CXXThrowExpr>(StmtElm->getStmt()))
6214 DFSWorkList.push_back(StartBlk);
6215 while (!DFSWorkList.empty()) {
6216 const CFGBlock *Blk = DFSWorkList.back();
6217 DFSWorkList.pop_back();
6227 for (
const auto &Succ : Blk->
succs()) {
6228 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
6232 DFSWorkList.push_back(SuccBlk);
6261 const Stmt *Cond = StmtElem->getStmt();
6262 if (isa<ObjCForCollectionStmt>(Cond) || isa<DeclStmt>(Cond))
6281 case Stmt::CXXForRangeStmtClass:
6285 case Stmt::ForStmtClass:
6289 case Stmt::WhileStmtClass:
6293 case Stmt::DoStmtClass:
6297 case Stmt::IfStmtClass:
6301 case Stmt::ChooseExprClass:
6305 case Stmt::IndirectGotoStmtClass:
6306 E = cast<IndirectGotoStmt>(
Terminator)->getTarget();
6309 case Stmt::SwitchStmtClass:
6313 case Stmt::BinaryConditionalOperatorClass:
6314 E = cast<BinaryConditionalOperator>(
Terminator)->getCond();
6317 case Stmt::ConditionalOperatorClass:
6318 E = cast<ConditionalOperator>(
Terminator)->getCond();
6321 case Stmt::BinaryOperatorClass:
6325 case Stmt::ObjCForCollectionStmtClass:
6342 StmtPrinterHelper H(
this, LO);
6344 llvm::ViewGraph(
this,
"CFG");
6356 llvm::raw_string_ostream Out(OutStr);
6359 if (OutStr[0] ==
'\n') OutStr.erase(OutStr.begin());
6362 for (
unsigned i = 0; i != OutStr.length(); ++i)
6363 if (OutStr[i] ==
'\n') {
6365 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.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Represents a C++ constructor within a class.
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)