39#include "llvm/ADT/APFloat.h"
40#include "llvm/ADT/APInt.h"
41#include "llvm/ADT/APSInt.h"
42#include "llvm/ADT/ArrayRef.h"
43#include "llvm/ADT/DenseMap.h"
44#include "llvm/ADT/STLExtras.h"
45#include "llvm/ADT/SetVector.h"
46#include "llvm/ADT/SmallPtrSet.h"
47#include "llvm/ADT/SmallVector.h"
48#include "llvm/Support/Allocator.h"
49#include "llvm/Support/Compiler.h"
50#include "llvm/Support/DOTGraphTraits.h"
51#include "llvm/Support/ErrorHandling.h"
52#include "llvm/Support/Format.h"
53#include "llvm/Support/GraphWriter.h"
54#include "llvm/Support/SaveAndRestore.h"
55#include "llvm/Support/raw_ostream.h"
67 if (
VarDecl *VD = dyn_cast<VarDecl>(
D))
68 if (
Expr *Ex = VD->getInit())
69 return Ex->getSourceRange().getEnd();
83 if (
const auto *CE = dyn_cast<CastExpr>(
E)) {
84 if (CE->getCastKind() != CK_IntegralCast &&
85 CE->getCastKind() != CK_IntegralToFloating)
91 if (
const auto *UO = dyn_cast<UnaryOperator>(
E)) {
92 if (UO->getOpcode() != UO_Minus)
96 return isa<IntegerLiteral, CharacterLiteral, FloatingLiteral>(
E);
107 return isa<EnumConstantDecl>(DR->getDecl()) ? DR :
nullptr;
116static std::tuple<const Expr *, BinaryOperatorKind, const Expr *>
123 if (Constant ==
nullptr) {
127 else if (Op == BO_GE)
129 else if (Op == BO_LT)
131 else if (Op == BO_LE)
138 return std::make_tuple(MaybeDecl, Op, Constant);
150 if (isa<DeclRefExpr>(E1) != isa<DeclRefExpr>(E2))
154 if (!isa<DeclRefExpr>(E1))
159 assert(isa<DeclRefExpr>(E1) && isa<DeclRefExpr>(E2));
160 auto *Decl1 = cast<DeclRefExpr>(E1)->getDecl();
161 auto *Decl2 = cast<DeclRefExpr>(E2)->getDecl();
163 assert(isa<EnumConstantDecl>(Decl1) && isa<EnumConstantDecl>(Decl2));
167 assert(isa<EnumDecl>(DC1) && isa<EnumDecl>(DC2));
189 enum Kind { NotAlwaysAdd = 0, AlwaysAdd = 1 };
191 AddStmtChoice(Kind a_kind = NotAlwaysAdd) :
kind(a_kind) {}
193 bool alwaysAdd(CFGBuilder &builder,
198 AddStmtChoice withAlwaysAdd(
bool alwaysAdd)
const {
199 return AddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd);
233 class const_iterator {
234 const LocalScope*
Scope =
nullptr;
238 unsigned VarIter = 0;
244 const_iterator() =
default;
248 const_iterator(
const LocalScope& S,
unsigned I)
249 :
Scope(&S), VarIter(I) {
252 if (VarIter == 0 &&
Scope)
256 VarDecl *
const* operator->()
const {
257 assert(
Scope &&
"Dereferencing invalid iterator is not allowed");
258 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
259 return &
Scope->Vars[VarIter - 1];
262 const VarDecl *getFirstVarInScope()
const {
263 assert(
Scope &&
"Dereferencing invalid iterator is not allowed");
264 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
265 return Scope->Vars[0];
269 return *this->operator->();
272 const_iterator &operator++() {
276 assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
282 const_iterator operator++(
int) {
283 const_iterator
P = *
this;
288 bool operator==(
const const_iterator &rhs)
const {
289 return Scope == rhs.
Scope && VarIter == rhs.VarIter;
291 bool operator!=(
const const_iterator &rhs)
const {
292 return !(*
this == rhs);
295 explicit operator bool()
const {
296 return *
this != const_iterator();
300 const_iterator shared_parent(const_iterator L);
301 bool pointsToFirstDeclaredVar() {
return VarIter == 1; }
302 bool inSameLocalScope(const_iterator rhs) {
return Scope == rhs.
Scope; }
309 AutomaticVarsTy Vars;
318 : ctx(
std::move(ctx)), Vars(this->ctx, 4), Prev(
P) {}
321 const_iterator begin()
const {
return const_iterator(*
this, Vars.size()); }
324 Vars.push_back(VD, ctx);
333int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
335 const_iterator F = *
this;
336 while (F.Scope != L.Scope) {
337 assert(F != const_iterator() &&
338 "L iterator is not reachable from F iterator.");
342 D += F.VarIter - L.VarIter;
350LocalScope::const_iterator
351LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
354 if ((*
this == const_iterator()) || (L == const_iterator())) {
355 return const_iterator();
358 const_iterator F = *
this;
359 if (F.inSameLocalScope(L)) {
361 F.VarIter = std::min(F.VarIter, L.VarIter);
365 llvm::SmallDenseMap<const LocalScope *, unsigned, 4> ScopesOfL;
367 ScopesOfL.try_emplace(L.Scope, L.VarIter);
368 if (L == const_iterator())
374 if (
auto LIt = ScopesOfL.find(F.Scope); LIt != ScopesOfL.end()) {
376 F.VarIter = std::min(F.VarIter, LIt->getSecond());
379 assert(F != const_iterator() &&
380 "L iterator is not reachable from F iterator.");
390struct BlockScopePosPair {
392 LocalScope::const_iterator scopePosition;
394 BlockScopePosPair() =
default;
395 BlockScopePosPair(
CFGBlock *
b, LocalScope::const_iterator scopePos)
396 : block(
b), scopePosition(scopePos) {}
407 TryResult() =
default;
408 TryResult(
bool b) :
X(
b ? 1 : 0) {}
410 bool isTrue()
const {
return X == 1; }
411 bool isFalse()
const {
return X == 0; }
412 bool isKnown()
const {
return X >= 0; }
423 if (!R1.isKnown() || !R2.isKnown())
425 return TryResult(R1.isTrue() && R2.isTrue());
430class reverse_children {
439 iterator begin()
const {
return children.rbegin(); }
440 iterator end()
const {
return children.rend(); }
446 if (
CallExpr *CE = dyn_cast<CallExpr>(S)) {
447 children = CE->getRawSubExprs();
451 switch (S->getStmtClass()) {
453 case Stmt::InitListExprClass: {
460 case Stmt::AttributedStmtClass: {
465 auto *AS = cast<AttributedStmt>(S);
466 for (
const auto *
Attr : AS->getAttrs()) {
467 if (
const auto *AssumeAttr = dyn_cast<CXXAssumeAttr>(
Attr)) {
468 Expr *AssumeExpr = AssumeAttr->getAssumption();
470 childrenBuf.push_back(AssumeExpr);
477 llvm::append_range(childrenBuf, AS->children());
478 children = childrenBuf;
486 llvm::append_range(childrenBuf, S->children());
489 children = childrenBuf;
508 using JumpTarget = BlockScopePosPair;
509 using JumpSource = BlockScopePosPair;
512 std::unique_ptr<CFG> cfg;
520 JumpTarget ContinueJumpTarget;
521 JumpTarget BreakJumpTarget;
522 JumpTarget SEHLeaveJumpTarget;
523 CFGBlock *SwitchTerminatedBlock =
nullptr;
524 CFGBlock *DefaultCaseBlock =
nullptr;
530 CFGBlock *TryTerminatedBlock =
nullptr;
533 LocalScope::const_iterator ScopePos;
536 using LabelMapTy = llvm::DenseMap<LabelDecl *, JumpTarget>;
541 using BackpatchBlocksTy = std::vector<JumpSource>;
542 BackpatchBlocksTy BackpatchBlocks;
546 LabelSetTy AddressTakenLabels;
551 llvm::DenseMap<Expr *, const ConstructionContextLayer *>
552 ConstructionContextMap;
558 bool switchExclusivelyCovered =
false;
561 CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry =
nullptr;
562 const Stmt *lastLookup =
nullptr;
566 using CachedBoolEvalsTy = llvm::DenseMap<Expr *, TryResult>;
567 CachedBoolEvalsTy CachedBoolEvals;
572 : Context(astContext), cfg(new
CFG()), BuildOpts(buildOpts) {}
575 std::unique_ptr<CFG> buildCFG(
const Decl *
D,
Stmt *Statement);
612 AddStmtChoice asc,
bool ExternallyDestructed);
624 std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(
BinaryOperator *B,
654 CFGBlock *Visit(
Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd,
655 bool ExternallyDestructed =
false);
664 if (ScopePos && (VD == ScopePos.getFirstVarInScope()))
665 appendScopeBegin(B, VD, S);
696 struct TempDtorContext {
697 TempDtorContext() =
default;
698 TempDtorContext(TryResult KnownExecuted)
699 : IsConditional(
true), KnownExecuted(KnownExecuted) {}
707 bool needsTempDtorBranch()
const {
708 return IsConditional && !TerminatorExpr;
718 const bool IsConditional =
false;
719 const TryResult KnownExecuted =
true;
726 CFGBlock *VisitForTemporaryDtors(
Stmt *
E,
bool ExternallyDestructed,
727 TempDtorContext &Context);
728 CFGBlock *VisitChildrenForTemporaryDtors(
Stmt *
E,
bool ExternallyDestructed,
729 TempDtorContext &Context);
731 bool ExternallyDestructed,
732 TempDtorContext &Context);
733 CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(
735 CFGBlock *VisitConditionalOperatorForTemporaryDtors(
737 TempDtorContext &Context);
738 void InsertTempDtorDecisionBlock(
const TempDtorContext &Context,
763 template <
typename CallLikeExpr,
764 typename = std::enable_if_t<
765 std::is_base_of_v<CallExpr, CallLikeExpr> ||
766 std::is_base_of_v<CXXConstructExpr, CallLikeExpr> ||
767 std::is_base_of_v<ObjCMessageExpr, CallLikeExpr>>>
768 void findConstructionContextsForArguments(CallLikeExpr *
E) {
769 for (
unsigned i = 0, e =
E->getNumArgs(); i != e; ++i) {
770 Expr *Arg =
E->getArg(i);
772 findConstructionContexts(
782 void cleanupConstructionContext(
Expr *
E);
784 void autoCreateBlock() {
if (!Block)
Block = createBlock(); }
786 CFGBlock *createBlock(
bool add_successor =
true);
790 return Visit(S, AddStmtChoice::AlwaysAdd);
794 void addLoopExit(
const Stmt *LoopStmt);
795 void addAutomaticObjHandling(LocalScope::const_iterator B,
796 LocalScope::const_iterator
E,
Stmt *S);
797 void addAutomaticObjDestruction(LocalScope::const_iterator B,
798 LocalScope::const_iterator
E,
Stmt *S);
799 void addScopeExitHandling(LocalScope::const_iterator B,
800 LocalScope::const_iterator
E,
Stmt *S);
802 void addScopeChangesHandling(LocalScope::const_iterator SrcPos,
803 LocalScope::const_iterator DstPos,
805 CFGBlock *createScopeChangesHandlingBlock(LocalScope::const_iterator SrcPos,
807 LocalScope::const_iterator DstPost,
811 LocalScope* createOrReuseLocalScope(LocalScope*
Scope);
813 void addLocalScopeForStmt(
Stmt *S);
814 LocalScope* addLocalScopeForDeclStmt(
DeclStmt *DS,
815 LocalScope*
Scope =
nullptr);
816 LocalScope* addLocalScopeForVarDecl(
VarDecl *VD, LocalScope*
Scope =
nullptr);
818 void addLocalScopeAndDtors(
Stmt *S);
828 cleanupConstructionContext(
E);
836 if (alwaysAdd(S) && cachedEntry)
837 cachedEntry->second = B;
840 assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S);
846 if (
C &&
C->isNoReturn())
847 Block = createNoReturnBlock();
852 retrieveAndCleanupConstructionContext(CE)) {
862 if (alwaysAdd(CE) && cachedEntry)
863 cachedEntry->second = B;
866 retrieveAndCleanupConstructionContext(CE)) {
872 B->
appendStmt(CE, cfg->getBumpVectorContext());
892 if (alwaysAdd(ME) && cachedEntry)
893 cachedEntry->second = B;
896 retrieveAndCleanupConstructionContext(ME)) {
901 B->
appendStmt(ME, cfg->getBumpVectorContext());
920 void appendLoopExit(
CFGBlock *B,
const Stmt *LoopStmt) {
930 cfg->getBumpVectorContext());
937 cfg->getBumpVectorContext());
953 TryResult checkIncorrectRelationalOperator(
const BinaryOperator *B) {
957 const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
958 const Expr *BoolExpr = RHSExpr;
959 bool IntFirst =
true;
961 IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
969 llvm::APInt IntValue = IntLiteral->
getValue();
970 if ((IntValue == 1) || (IntValue == 0))
974 !IntValue.isNegative();
977 if (Bok == BO_GT || Bok == BO_GE) {
980 return TryResult(IntFirst == IntLarger);
984 return TryResult(IntFirst != IntLarger);
992 TryResult checkIncorrectEqualityOperator(
const BinaryOperator *B) {
996 std::optional<llvm::APInt> IntLiteral1 =
997 getIntegerLiteralSubexpressionValue(LHSExpr);
998 const Expr *BoolExpr = RHSExpr;
1001 IntLiteral1 = getIntegerLiteralSubexpressionValue(RHSExpr);
1008 const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
1009 if (BitOp && (BitOp->
getOpcode() == BO_And ||
1014 std::optional<llvm::APInt> IntLiteral2 =
1015 getIntegerLiteralSubexpressionValue(LHSExpr2);
1018 IntLiteral2 = getIntegerLiteralSubexpressionValue(RHSExpr2);
1024 (*IntLiteral2 & *IntLiteral1) != *IntLiteral1) ||
1026 (*IntLiteral2 | *IntLiteral1) != *IntLiteral1)) {
1030 return TryResult(B->
getOpcode() != BO_EQ);
1033 if ((*IntLiteral1 == 1) || (*IntLiteral1 == 0)) {
1036 return TryResult(B->
getOpcode() != BO_EQ);
1048 std::optional<llvm::APInt>
1049 getIntegerLiteralSubexpressionValue(
const Expr *
E) {
1052 if (
const auto *UnOp = dyn_cast<UnaryOperator>(
E->
IgnoreParens())) {
1057 if (
const auto *IntLiteral = dyn_cast<IntegerLiteral>(SubExpr)) {
1062 switch (UnOp->getOpcode()) {
1072 assert(
false &&
"Unexpected unary operator!");
1073 return std::nullopt;
1076 }
else if (
const auto *IntLiteral =
1080 return std::nullopt;
1083 template <
typename APFloatOrInt>
1085 const APFloatOrInt &Value1,
1086 const APFloatOrInt &Value2) {
1091 return TryResult(Value1 == Value2);
1093 return TryResult(Value1 != Value2);
1095 return TryResult(Value1 < Value2);
1097 return TryResult(Value1 <= Value2);
1099 return TryResult(Value1 > Value2);
1101 return TryResult(Value1 >= Value2);
1117 auto CheckLogicalOpWithNegatedVariable = [
this, B](
const Expr *E1,
1119 if (
const auto *Negate = dyn_cast<UnaryOperator>(E1)) {
1120 if (Negate->getOpcode() == UO_LNot &&
1122 bool AlwaysTrue = B->
getOpcode() == BO_LOr;
1125 return TryResult(AlwaysTrue);
1131 TryResult Result = CheckLogicalOpWithNegatedVariable(LHSExpr, RHSExpr);
1132 if (Result.isKnown())
1134 Result = CheckLogicalOpWithNegatedVariable(RHSExpr, LHSExpr);
1135 if (Result.isKnown())
1138 const auto *LHS = dyn_cast<BinaryOperator>(LHSExpr);
1139 const auto *RHS = dyn_cast<BinaryOperator>(RHSExpr);
1143 if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
1146 const Expr *DeclExpr1;
1147 const Expr *NumExpr1;
1151 if (!DeclExpr1 || !NumExpr1)
1154 const Expr *DeclExpr2;
1155 const Expr *NumExpr2;
1159 if (!DeclExpr2 || !NumExpr2)
1187 auto AnalyzeConditions = [&](
const auto &Values,
1190 bool AlwaysTrue =
true, AlwaysFalse =
true;
1193 bool LHSAlwaysTrue =
true, LHSAlwaysFalse =
true;
1194 bool RHSAlwaysTrue =
true, RHSAlwaysFalse =
true;
1196 for (
const auto &
Value : Values) {
1198 analyzeLogicOperatorCondition(*BO1,
Value, Values[1] );
1200 analyzeLogicOperatorCondition(*BO2,
Value, Values[3] );
1202 if (!Res1.isKnown() || !Res2.isKnown())
1205 const bool IsAnd = B->
getOpcode() == BO_LAnd;
1206 const bool Combine = IsAnd ? (Res1.isTrue() && Res2.isTrue())
1207 : (Res1.isTrue() || Res2.isTrue());
1209 AlwaysTrue &= Combine;
1210 AlwaysFalse &= !Combine;
1212 LHSAlwaysTrue &= Res1.isTrue();
1213 LHSAlwaysFalse &= Res1.isFalse();
1214 RHSAlwaysTrue &= Res2.isTrue();
1215 RHSAlwaysFalse &= Res2.isFalse();
1218 if (AlwaysTrue || AlwaysFalse) {
1219 if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
1220 !RHSAlwaysFalse && BuildOpts.
Observer) {
1223 return TryResult(AlwaysTrue);
1231 llvm::APSInt L1 = L1Result.
Val.
getInt();
1232 llvm::APSInt L2 = L2Result.
Val.
getInt();
1235 if (L1.isSigned() != L2.isSigned() ||
1236 L1.getBitWidth() != L2.getBitWidth())
1241 const llvm::APSInt Values[] = {
1243 llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
1247 ((L1 < L2) ? L1 : L2) +
1248 llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1), L1.isUnsigned()),
1252 llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
1255 return AnalyzeConditions(Values, &BO1, &BO2);
1274 if (llvm::APFloat::opOK !=
1275 L2.convert(L1.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
1278 }
else if (Order < 0)
1280 if (llvm::APFloat::opOK !=
1281 L1.convert(L2.getSemantics(), llvm::APFloat::rmNearestTiesToEven,
1285 llvm::APFloat MidValue = L1;
1286 MidValue.add(L2, llvm::APFloat::rmNearestTiesToEven);
1287 MidValue.divide(llvm::APFloat(MidValue.getSemantics(),
"2.0"),
1288 llvm::APFloat::rmNearestTiesToEven);
1290 const llvm::APFloat Values[] = {
1291 llvm::APFloat::getSmallest(L1.getSemantics(),
true), L1, MidValue, L2,
1292 llvm::APFloat::getLargest(L2.getSemantics(),
false),
1295 return AnalyzeConditions(Values, &BO1, &BO2);
1302 TryResult checkIncorrectBitwiseOrOperator(
const BinaryOperator *B) {
1303 const Expr *LHSConstant =
1305 const Expr *RHSConstant =
1308 if ((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant))
1311 const Expr *Constant = LHSConstant ? LHSConstant : RHSConstant;
1317 if (Result.Val.getInt() == 0)
1323 return TryResult(
true);
1330 return !S->isTypeDependent() &&
1331 !S->isValueDependent() &&
1332 S->EvaluateAsRValue(outResult, *Context);
1337 TryResult tryEvaluateBool(
Expr *S) {
1339 S->isTypeDependent() || S->isValueDependent())
1343 if (Bop->isLogicalOp() || Bop->isEqualityOp()) {
1345 CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S);
1346 if (I != CachedBoolEvals.end())
1350 TryResult Result = evaluateAsBooleanConditionNoCache(S);
1351 CachedBoolEvals[S] = Result;
1355 switch (Bop->getOpcode()) {
1364 if (Bop->getLHS()->EvaluateAsInt(LHSResult, *Context)) {
1365 llvm::APSInt IntVal = LHSResult.
Val.
getInt();
1366 if (!IntVal.getBoolValue()) {
1367 return TryResult(
false);
1371 if (Bop->getRHS()->EvaluateAsInt(RHSResult, *Context)) {
1372 llvm::APSInt IntVal = RHSResult.
Val.
getInt();
1373 if (!IntVal.getBoolValue()) {
1374 return TryResult(
false);
1383 return evaluateAsBooleanConditionNoCache(S);
1387 TryResult evaluateAsBooleanConditionNoCache(
Expr *
E) {
1389 if (Bop->isLogicalOp()) {
1390 TryResult LHS = tryEvaluateBool(Bop->getLHS());
1391 if (LHS.isKnown()) {
1394 if (LHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1395 return LHS.isTrue();
1397 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1398 if (RHS.isKnown()) {
1399 if (Bop->getOpcode() == BO_LOr)
1400 return LHS.isTrue() || RHS.isTrue();
1402 return LHS.isTrue() && RHS.isTrue();
1405 TryResult RHS = tryEvaluateBool(Bop->getRHS());
1406 if (RHS.isKnown()) {
1409 if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1410 return RHS.isTrue();
1412 TryResult BopRes = checkIncorrectLogicOperator(Bop);
1413 if (BopRes.isKnown())
1414 return BopRes.isTrue();
1419 }
else if (Bop->isEqualityOp()) {
1420 TryResult BopRes = checkIncorrectEqualityOperator(Bop);
1421 if (BopRes.isKnown())
1422 return BopRes.isTrue();
1423 }
else if (Bop->isRelationalOp()) {
1424 TryResult BopRes = checkIncorrectRelationalOperator(Bop);
1425 if (BopRes.isKnown())
1426 return BopRes.isTrue();
1427 }
else if (Bop->getOpcode() == BO_Or) {
1428 TryResult BopRes = checkIncorrectBitwiseOrOperator(Bop);
1429 if (BopRes.isKnown())
1430 return BopRes.isTrue();
1441 bool hasTrivialDestructor(
const VarDecl *VD)
const;
1442 bool needsAutomaticDestruction(
const VarDecl *VD)
const;
1453 while (
const auto *
E = dyn_cast<ArrayInitLoopExpr>(AILEInit))
1454 AILEInit =
E->getSubExpr();
1459inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
1461 return builder.alwaysAdd(
stmt) || kind == AlwaysAdd;
1464bool CFGBuilder::alwaysAdd(
const Stmt *
stmt) {
1470 if (lastLookup ==
stmt) {
1472 assert(cachedEntry->first ==
stmt);
1485 assert(!cachedEntry);
1489 CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(
stmt);
1490 if (itr == fb->end()) {
1491 cachedEntry =
nullptr;
1495 cachedEntry = &*itr;
1502 while (
const ArrayType *vt = dyn_cast<ArrayType>(t)) {
1504 if (vat->getSizeExpr())
1507 t = vt->getElementType().getTypePtr();
1513void CFGBuilder::consumeConstructionContext(
1515 assert((isa<CXXConstructExpr>(
E) || isa<CallExpr>(
E) ||
1516 isa<ObjCMessageExpr>(
E)) &&
"Expression cannot construct an object!");
1518 ConstructionContextMap.lookup(
E)) {
1519 (void)PreviouslyStoredLayer;
1522 assert(PreviouslyStoredLayer->isStrictlyMoreSpecificThan(Layer) &&
1523 "Already within a different construction context!");
1525 ConstructionContextMap[
E] = Layer;
1529void CFGBuilder::findConstructionContexts(
1542 switch(Child->getStmtClass()) {
1543 case Stmt::CXXConstructExprClass:
1544 case Stmt::CXXTemporaryObjectExprClass: {
1546 auto *CE = cast<CXXConstructExpr>(Child);
1548 findConstructionContexts(withExtraLayer(CE), CE->
getArg(0));
1551 consumeConstructionContext(Layer, CE);
1557 case Stmt::CallExprClass:
1558 case Stmt::CXXMemberCallExprClass:
1559 case Stmt::CXXOperatorCallExprClass:
1560 case Stmt::UserDefinedLiteralClass:
1561 case Stmt::ObjCMessageExprClass: {
1562 auto *
E = cast<Expr>(Child);
1564 consumeConstructionContext(Layer,
E);
1567 case Stmt::ExprWithCleanupsClass: {
1568 auto *Cleanups = cast<ExprWithCleanups>(Child);
1569 findConstructionContexts(Layer, Cleanups->getSubExpr());
1572 case Stmt::CXXFunctionalCastExprClass: {
1573 auto *
Cast = cast<CXXFunctionalCastExpr>(Child);
1574 findConstructionContexts(Layer,
Cast->getSubExpr());
1577 case Stmt::ImplicitCastExprClass: {
1578 auto *
Cast = cast<ImplicitCastExpr>(Child);
1580 switch (
Cast->getCastKind()) {
1582 case CK_ConstructorConversion:
1583 findConstructionContexts(Layer,
Cast->getSubExpr());
1590 case Stmt::CXXBindTemporaryExprClass: {
1591 auto *BTE = cast<CXXBindTemporaryExpr>(Child);
1592 findConstructionContexts(withExtraLayer(BTE), BTE->getSubExpr());
1595 case Stmt::MaterializeTemporaryExprClass: {
1602 auto *MTE = cast<MaterializeTemporaryExpr>(Child);
1603 findConstructionContexts(withExtraLayer(MTE), MTE->getSubExpr());
1607 case Stmt::ConditionalOperatorClass: {
1608 auto *CO = cast<ConditionalOperator>(Child);
1615 assert(!CO->getType()->getAsCXXRecordDecl() || CO->isGLValue() ||
1619 findConstructionContexts(Layer, CO->getLHS());
1620 findConstructionContexts(Layer, CO->getRHS());
1623 case Stmt::InitListExprClass: {
1624 auto *ILE = cast<InitListExpr>(Child);
1625 if (ILE->isTransparent()) {
1626 findConstructionContexts(Layer, ILE->getInit(0));
1632 case Stmt::ParenExprClass: {
1635 auto *PE = cast<ParenExpr>(Child);
1636 findConstructionContexts(Layer, PE->getSubExpr());
1644void CFGBuilder::cleanupConstructionContext(
Expr *
E) {
1646 "We should not be managing construction contexts!");
1647 assert(ConstructionContextMap.count(
E) &&
1648 "Cannot exit construction context without the context!");
1649 ConstructionContextMap.erase(
E);
1657std::unique_ptr<CFG> CFGBuilder::buildCFG(
const Decl *
D,
Stmt *Statement) {
1665 Succ = createBlock();
1666 assert(Succ == &cfg->getExit());
1671 addImplicitDtorsForDestructor(DD);
1691 if (
const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(
D)) {
1693 for (
auto *I : llvm::reverse(CD->inits())) {
1695 I->isBaseInitializer() && I->isBaseVirtual()) {
1699 VBaseSucc = Succ = B ? B : &cfg->getExit();
1700 Block = createBlock();
1702 B = addInitializer(I);
1712 addSuccessor(B,
Block,
true);
1721 for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
1722 E = BackpatchBlocks.end(); I !=
E; ++I ) {
1726 LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
1729 if (LI == LabelMap.end())
1731 JumpTarget JT = LI->second;
1733 CFGBlock *SuccBlk = createScopeChangesHandlingBlock(
1734 I->scopePosition, B, JT.scopePosition, JT.block);
1735 addSuccessor(B, SuccBlk);
1736 }
else if (
auto *G = dyn_cast<GCCAsmStmt>(B->
getTerminator())) {
1737 CFGBlock *Successor = (I+1)->block;
1738 for (
auto *L : G->labels()) {
1739 LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
1742 if (LI == LabelMap.end())
1744 JumpTarget JT = LI->second;
1746 if (JT.block == Successor)
1748 addSuccessor(B, JT.block);
1755 if (
CFGBlock *B = cfg->getIndirectGotoBlock())
1756 for (
LabelDecl *LD : AddressTakenLabels) {
1758 LabelMapTy::iterator LI = LabelMap.find(LD);
1762 if (LI == LabelMap.end())
continue;
1764 addSuccessor(B, LI->second.block);
1768 cfg->setEntry(createBlock());
1771 assert(ConstructionContextMap.empty() &&
1772 "Not all construction contexts were cleaned up!");
1774 return std::move(cfg);
1779CFGBlock *CFGBuilder::createBlock(
bool add_successor) {
1781 if (add_successor && Succ)
1782 addSuccessor(B, Succ);
1789CFGBlock *CFGBuilder::createNoReturnBlock() {
1792 addSuccessor(B, &cfg->getExit(), Succ);
1801 bool HasTemporaries =
false;
1807 HasTemporaries = isa<ExprWithCleanups>(
Init);
1811 TempDtorContext Context;
1812 VisitForTemporaryDtors(cast<ExprWithCleanups>(
Init)->getSubExpr(),
1818 appendInitializer(
Block, I);
1824 dyn_cast<ArrayInitLoopExpr>(
Init));
1826 findConstructionContexts(
1828 AILEInit ? AILEInit :
Init);
1830 if (HasTemporaries) {
1833 return Visit(cast<ExprWithCleanups>(
Init)->getSubExpr());
1857 bool *FoundMTE =
nullptr) {
1864 Init = EWC->getSubExpr();
1870 = dyn_cast<MaterializeTemporaryExpr>(
Init)) {
1871 Init = MTE->getSubExpr();
1878 const Expr *SkippedInit =
Init->skipRValueSubobjectAdjustments();
1879 if (SkippedInit !=
Init) {
1887 return Init->getType();
1892void CFGBuilder::addLoopExit(
const Stmt *LoopStmt){
1896 appendLoopExit(
Block, LoopStmt);
1904void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
1905 LocalScope::const_iterator
E,
1915 if (B.inSameLocalScope(
E)) {
1916 addAutomaticObjDestruction(B,
E, S);
1922 LocalScopeEndMarkers.push_back(B);
1923 for (LocalScope::const_iterator I = B; I !=
E; ++I) {
1924 if (!I.inSameLocalScope(LocalScopeEndMarkers.back()))
1925 LocalScopeEndMarkers.push_back(I);
1927 LocalScopeEndMarkers.push_back(
E);
1931 std::reverse(LocalScopeEndMarkers.begin(), LocalScopeEndMarkers.end());
1933 llvm::zip(LocalScopeEndMarkers, llvm::drop_begin(LocalScopeEndMarkers));
1934 for (
auto [
E, B] : Pairwise) {
1935 if (!B.inSameLocalScope(
E))
1936 addScopeExitHandling(B,
E, S);
1937 addAutomaticObjDestruction(B,
E, S);
1944void CFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
1945 LocalScope::const_iterator
E,
1954 DeclsNeedDestruction.reserve(B.distance(
E));
1956 for (
VarDecl*
D : llvm::make_range(B,
E))
1957 if (needsAutomaticDestruction(
D))
1958 DeclsNeedDestruction.push_back(
D);
1960 for (
VarDecl *VD : llvm::reverse(DeclsNeedDestruction)) {
1973 Block = createNoReturnBlock();
1982 appendLifetimeEnds(
Block, VD, S);
1984 appendAutomaticObjDtor(
Block, VD, S);
1985 if (VD->
hasAttr<CleanupAttr>())
1986 appendCleanupFunction(
Block, VD);
1995void CFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
1996 LocalScope::const_iterator
E,
Stmt *S) {
1997 assert(!B.inSameLocalScope(
E));
2003 appendScopeEnd(
Block, B.getFirstVarInScope(), S);
2011 DeclsTrivial.reserve(B.distance(
E));
2016 for (
VarDecl*
D : llvm::make_range(B,
E))
2017 if (!needsAutomaticDestruction(
D))
2018 DeclsTrivial.push_back(
D);
2020 if (DeclsTrivial.empty())
2024 for (
VarDecl *VD : llvm::reverse(DeclsTrivial))
2025 appendLifetimeEnds(
Block, VD, S);
2033void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
2034 LocalScope::const_iterator DstPos,
2036 assert(
Block &&
"Source block should be always crated");
2042 if (SrcPos == DstPos)
2047 LocalScope::const_iterator BasePos = SrcPos.shared_parent(DstPos);
2050 if (BuildOpts.
AddScopes && !DstPos.inSameLocalScope(BasePos)) {
2051 for (LocalScope::const_iterator I = DstPos; I != BasePos; ++I)
2052 if (I.pointsToFirstDeclaredVar())
2053 appendScopeBegin(
Block, *I, S);
2058 addAutomaticObjHandling(SrcPos, BasePos, S);
2066CFGBlock *CFGBuilder::createScopeChangesHandlingBlock(
2067 LocalScope::const_iterator SrcPos,
CFGBlock *SrcBlk,
2068 LocalScope::const_iterator DstPos,
CFGBlock *DstBlk) {
2069 if (SrcPos == DstPos)
2073 (!BuildOpts.
AddScopes || SrcPos.inSameLocalScope(DstPos)))
2081 Block = createBlock(
false);
2084 addSuccessor(
Block, DstBlk);
2089 assert(
Block &&
"There should be at least one scope changing Block");
2097 "Can be called only when dtors should be added");
2101 for (
const auto &VI : RD->
vbases()) {
2105 const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
2108 appendBaseDtor(
Block, &VI);
2113 for (
const auto &BI : RD->
bases()) {
2114 if (!BI.isVirtual()) {
2115 const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
2118 appendBaseDtor(
Block, &BI);
2126 for (
auto *FI : RD->
fields()) {
2131 if (AT->isZeroSize())
2133 QT = AT->getElementType();
2139 appendMemberDtor(
Block, FI);
2146LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope*
Scope) {
2149 llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
2155void CFGBuilder::addLocalScopeForStmt(
Stmt *S) {
2160 LocalScope *
Scope =
nullptr;
2164 for (
auto *BI : CS->body()) {
2166 if (
DeclStmt *DS = dyn_cast<DeclStmt>(SI))
2174 if (
DeclStmt *DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements()))
2175 addLocalScopeForDeclStmt(DS);
2180LocalScope* CFGBuilder::addLocalScopeForDeclStmt(
DeclStmt *DS,
2181 LocalScope*
Scope) {
2186 for (
auto *DI : DS->
decls())
2187 if (
VarDecl *VD = dyn_cast<VarDecl>(DI))
2192bool CFGBuilder::needsAutomaticDestruction(
const VarDecl *VD)
const {
2193 return !hasTrivialDestructor(VD) || VD->
hasAttr<CleanupAttr>();
2196bool CFGBuilder::hasTrivialDestructor(
const VarDecl *VD)
const {
2217 bool FoundMTE =
false;
2225 if (AT->isZeroSize())
2227 QT = AT->getElementType();
2239LocalScope* CFGBuilder::addLocalScopeForVarDecl(
VarDecl *VD,
2240 LocalScope*
Scope) {
2250 !needsAutomaticDestruction(VD)) {
2258 ScopePos =
Scope->begin();
2264void CFGBuilder::addLocalScopeAndDtors(
Stmt *S) {
2265 LocalScope::const_iterator scopeBeginPos = ScopePos;
2266 addLocalScopeForStmt(S);
2267 addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
2273CFGBlock *CFGBuilder::Visit(
Stmt * S, AddStmtChoice asc,
2274 bool ExternallyDestructed) {
2280 if (
Expr *
E = dyn_cast<Expr>(S))
2284 if (
auto *
D = dyn_cast<OMPExecutableDirective>(S))
2285 return VisitOMPExecutableDirective(
D, asc);
2287 switch (S->getStmtClass()) {
2289 return VisitStmt(S, asc);
2291 case Stmt::ImplicitValueInitExprClass:
2294 return VisitStmt(S, asc);
2296 case Stmt::InitListExprClass:
2297 return VisitInitListExpr(cast<InitListExpr>(S), asc);
2299 case Stmt::AttributedStmtClass:
2300 return VisitAttributedStmt(cast<AttributedStmt>(S), asc);
2302 case Stmt::AddrLabelExprClass:
2303 return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
2305 case Stmt::BinaryConditionalOperatorClass:
2306 return VisitConditionalOperator(cast<BinaryConditionalOperator>(S), asc);
2308 case Stmt::BinaryOperatorClass:
2309 return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
2311 case Stmt::BlockExprClass:
2312 return VisitBlockExpr(cast<BlockExpr>(S), asc);
2314 case Stmt::BreakStmtClass:
2315 return VisitBreakStmt(cast<BreakStmt>(S));
2317 case Stmt::CallExprClass:
2318 case Stmt::CXXOperatorCallExprClass:
2319 case Stmt::CXXMemberCallExprClass:
2320 case Stmt::UserDefinedLiteralClass:
2321 return VisitCallExpr(cast<CallExpr>(S), asc);
2323 case Stmt::CaseStmtClass:
2324 return VisitCaseStmt(cast<CaseStmt>(S));
2326 case Stmt::ChooseExprClass:
2327 return VisitChooseExpr(cast<ChooseExpr>(S), asc);
2329 case Stmt::CompoundStmtClass:
2330 return VisitCompoundStmt(cast<CompoundStmt>(S), ExternallyDestructed);
2332 case Stmt::ConditionalOperatorClass:
2333 return VisitConditionalOperator(cast<ConditionalOperator>(S), asc);
2335 case Stmt::ContinueStmtClass:
2336 return VisitContinueStmt(cast<ContinueStmt>(S));
2338 case Stmt::CXXCatchStmtClass:
2339 return VisitCXXCatchStmt(cast<CXXCatchStmt>(S));
2341 case Stmt::ExprWithCleanupsClass:
2342 return VisitExprWithCleanups(cast<ExprWithCleanups>(S),
2343 asc, ExternallyDestructed);
2345 case Stmt::CXXDefaultArgExprClass:
2346 case Stmt::CXXDefaultInitExprClass:
2355 return VisitStmt(S, asc);
2357 case Stmt::CXXBindTemporaryExprClass:
2358 return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc);
2360 case Stmt::CXXConstructExprClass:
2361 return VisitCXXConstructExpr(cast<CXXConstructExpr>(S), asc);
2363 case Stmt::CXXNewExprClass:
2364 return VisitCXXNewExpr(cast<CXXNewExpr>(S), asc);
2366 case Stmt::CXXDeleteExprClass:
2367 return VisitCXXDeleteExpr(cast<CXXDeleteExpr>(S), asc);
2369 case Stmt::CXXFunctionalCastExprClass:
2370 return VisitCXXFunctionalCastExpr(cast<CXXFunctionalCastExpr>(S), asc);
2372 case Stmt::CXXTemporaryObjectExprClass:
2373 return VisitCXXTemporaryObjectExpr(cast<CXXTemporaryObjectExpr>(S), asc);
2375 case Stmt::CXXThrowExprClass:
2376 return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
2378 case Stmt::CXXTryStmtClass:
2379 return VisitCXXTryStmt(cast<CXXTryStmt>(S));
2381 case Stmt::CXXTypeidExprClass:
2382 return VisitCXXTypeidExpr(cast<CXXTypeidExpr>(S), asc);
2384 case Stmt::CXXForRangeStmtClass:
2385 return VisitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
2387 case Stmt::DeclStmtClass:
2388 return VisitDeclStmt(cast<DeclStmt>(S));
2390 case Stmt::DefaultStmtClass:
2391 return VisitDefaultStmt(cast<DefaultStmt>(S));
2393 case Stmt::DoStmtClass:
2394 return VisitDoStmt(cast<DoStmt>(S));
2396 case Stmt::ForStmtClass:
2397 return VisitForStmt(cast<ForStmt>(S));
2399 case Stmt::GotoStmtClass:
2400 return VisitGotoStmt(cast<GotoStmt>(S));
2402 case Stmt::GCCAsmStmtClass:
2403 return VisitGCCAsmStmt(cast<GCCAsmStmt>(S), asc);
2405 case Stmt::IfStmtClass:
2406 return VisitIfStmt(cast<IfStmt>(S));
2408 case Stmt::ImplicitCastExprClass:
2409 return VisitImplicitCastExpr(cast<ImplicitCastExpr>(S), asc);
2411 case Stmt::ConstantExprClass:
2412 return VisitConstantExpr(cast<ConstantExpr>(S), asc);
2414 case Stmt::IndirectGotoStmtClass:
2415 return VisitIndirectGotoStmt(cast<IndirectGotoStmt>(S));
2417 case Stmt::LabelStmtClass:
2418 return VisitLabelStmt(cast<LabelStmt>(S));
2420 case Stmt::LambdaExprClass:
2421 return VisitLambdaExpr(cast<LambdaExpr>(S), asc);
2423 case Stmt::MaterializeTemporaryExprClass:
2424 return VisitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(S),
2427 case Stmt::MemberExprClass:
2428 return VisitMemberExpr(cast<MemberExpr>(S), asc);
2430 case Stmt::NullStmtClass:
2433 case Stmt::ObjCAtCatchStmtClass:
2434 return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
2436 case Stmt::ObjCAutoreleasePoolStmtClass:
2437 return VisitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(S));
2439 case Stmt::ObjCAtSynchronizedStmtClass:
2440 return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S));
2442 case Stmt::ObjCAtThrowStmtClass:
2443 return VisitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(S));
2445 case Stmt::ObjCAtTryStmtClass:
2446 return VisitObjCAtTryStmt(cast<ObjCAtTryStmt>(S));
2448 case Stmt::ObjCForCollectionStmtClass:
2449 return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
2451 case Stmt::ObjCMessageExprClass:
2452 return VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), asc);
2454 case Stmt::OpaqueValueExprClass:
2457 case Stmt::PseudoObjectExprClass:
2458 return VisitPseudoObjectExpr(cast<PseudoObjectExpr>(S));
2460 case Stmt::ReturnStmtClass:
2461 case Stmt::CoreturnStmtClass:
2462 return VisitReturnStmt(S);
2464 case Stmt::CoyieldExprClass:
2465 case Stmt::CoawaitExprClass:
2466 return VisitCoroutineSuspendExpr(cast<CoroutineSuspendExpr>(S), asc);
2468 case Stmt::SEHExceptStmtClass:
2469 return VisitSEHExceptStmt(cast<SEHExceptStmt>(S));
2471 case Stmt::SEHFinallyStmtClass:
2472 return VisitSEHFinallyStmt(cast<SEHFinallyStmt>(S));
2474 case Stmt::SEHLeaveStmtClass:
2475 return VisitSEHLeaveStmt(cast<SEHLeaveStmt>(S));
2477 case Stmt::SEHTryStmtClass:
2478 return VisitSEHTryStmt(cast<SEHTryStmt>(S));
2480 case Stmt::UnaryExprOrTypeTraitExprClass:
2481 return VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
2484 case Stmt::StmtExprClass:
2485 return VisitStmtExpr(cast<StmtExpr>(S), asc);
2487 case Stmt::SwitchStmtClass:
2488 return VisitSwitchStmt(cast<SwitchStmt>(S));
2490 case Stmt::UnaryOperatorClass:
2491 return VisitUnaryOperator(cast<UnaryOperator>(S), asc);
2493 case Stmt::WhileStmtClass:
2494 return VisitWhileStmt(cast<WhileStmt>(S));
2496 case Stmt::ArrayInitLoopExprClass:
2497 return VisitArrayInitLoopExpr(cast<ArrayInitLoopExpr>(S), asc);
2501CFGBlock *CFGBuilder::VisitStmt(
Stmt *S, AddStmtChoice asc) {
2502 if (asc.alwaysAdd(*
this, S)) {
2504 appendStmt(
Block, S);
2507 return VisitChildren(S);
2516 reverse_children RChildren(S, *Context);
2517 for (
Stmt *Child : RChildren) {
2526 if (asc.alwaysAdd(*
this, ILE)) {
2528 appendStmt(
Block, ILE);
2532 reverse_children RChildren(ILE, *Context);
2533 for (
Stmt *Child : RChildren) {
2539 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(Child))
2540 if (
Stmt *Child = DIE->getExpr())
2549 AddStmtChoice asc) {
2550 AddressTakenLabels.insert(A->
getLabel());
2552 if (asc.alwaysAdd(*
this, A)) {
2554 appendStmt(
Block, A);
2561 bool isFallthrough = hasSpecificAttr<FallThroughAttr>(A->
getAttrs());
2562 assert((!isFallthrough || isa<NullStmt>(A->
getSubStmt())) &&
2563 "expected fallthrough not to have children");
2564 return isFallthrough;
2568 bool hasAssumeAttr = hasSpecificAttr<CXXAssumeAttr>(A->
getAttrs());
2570 assert((!hasAssumeAttr || isa<NullStmt>(A->
getSubStmt())) &&
2571 "expected [[assume]] not to have children");
2572 return hasAssumeAttr;
2576 AddStmtChoice asc) {
2586 if (isInterestingAttribute && asc.alwaysAdd(*
this, A)) {
2588 appendStmt(
Block, A);
2591 return VisitChildren(A);
2595 if (asc.alwaysAdd(*
this,
U)) {
2600 if (
U->getOpcode() == UO_LNot)
2601 tryEvaluateBool(
U->getSubExpr()->IgnoreParens());
2603 return Visit(
U->getSubExpr(), AddStmtChoice());
2608 appendStmt(ConfluenceBlock, B);
2613 return VisitLogicalOperator(B,
nullptr, ConfluenceBlock,
2614 ConfluenceBlock).first;
2617std::pair<CFGBlock*, CFGBlock*>
2630 if (B_RHS->isLogicalOp()) {
2631 std::tie(RHSBlock, ExitBlock) =
2632 VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
2640 ExitBlock = RHSBlock = createBlock(
false);
2645 TryResult KnownVal = tryEvaluateBool(RHS);
2646 if (!KnownVal.isKnown())
2647 KnownVal = tryEvaluateBool(B);
2650 assert(TrueBlock == FalseBlock);
2651 addSuccessor(RHSBlock, TrueBlock);
2655 addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
2656 addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
2660 RHSBlock = addStmt(RHS);
2665 return std::make_pair(
nullptr,
nullptr);
2671 if (B_LHS->isLogicalOp()) {
2673 FalseBlock = RHSBlock;
2675 TrueBlock = RHSBlock;
2680 return VisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock);
2685 CFGBlock *LHSBlock = createBlock(
false);
2689 CFGBlock *EntryLHSBlock = addStmt(LHS);
2692 return std::make_pair(
nullptr,
nullptr);
2695 TryResult KnownVal = tryEvaluateBool(LHS);
2699 addSuccessor(LHSBlock, TrueBlock, !KnownVal.isFalse());
2700 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isTrue());
2703 addSuccessor(LHSBlock, RHSBlock, !KnownVal.isFalse());
2704 addSuccessor(LHSBlock, FalseBlock, !KnownVal.isTrue());
2707 return std::make_pair(EntryLHSBlock, ExitBlock);
2711 AddStmtChoice asc) {
2714 return VisitLogicalOperator(B);
2718 appendStmt(
Block, B);
2720 return addStmt(B->
getLHS());
2724 if (asc.alwaysAdd(*
this, B)) {
2726 appendStmt(
Block, B);
2729 return Visit(B->
getRHS());
2732 if (asc.alwaysAdd(*
this, B)) {
2734 appendStmt(
Block, B);
2745 return (LBlock ? LBlock : RBlock);
2748CFGBlock *CFGBuilder::VisitNoRecurse(
Expr *
E, AddStmtChoice asc) {
2749 if (asc.alwaysAdd(*
this,
E)) {
2763 Block = createBlock(
false);
2768 if (BreakJumpTarget.block) {
2769 addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
2770 addSuccessor(
Block, BreakJumpTarget.block);
2795 if (BuiltinID != Builtin::BI__assume &&
2796 BuiltinID != Builtin::BI__builtin_assume)
2804 QualType calleeType =
C->getCallee()->getType();
2810 if (!boundType.
isNull()) calleeType = boundType;
2816 bool AddEHEdge =
false;
2826 bool OmitArguments =
false;
2833 if (!FD->isVariadic())
2834 findConstructionContextsForArguments(
C);
2836 if (FD->isNoReturn() || FD->isAnalyzerNoReturn() ||
2837 C->isBuiltinAssumeFalse(*Context))
2839 if (FD->
hasAttr<NoThrowAttr>())
2842 FD->getBuiltinID() == Builtin::BI__builtin_object_size ||
2843 FD->getBuiltinID() == Builtin::BI__builtin_dynamic_object_size)
2844 OmitArguments =
true;
2847 if (!
CanThrow(
C->getCallee(), *Context))
2850 if (OmitArguments) {
2851 assert(!NoReturn &&
"noreturn calls with unevaluated args not implemented");
2852 assert(!AddEHEdge &&
"EH calls with unevaluated args not implemented");
2855 return Visit(
C->getCallee());
2858 if (!NoReturn && !AddEHEdge) {
2862 return VisitChildren(
C);
2872 Block = createNoReturnBlock();
2874 Block = createBlock();
2880 if (TryTerminatedBlock)
2881 addSuccessor(
Block, TryTerminatedBlock);
2883 addSuccessor(
Block, &cfg->getExit());
2886 return VisitChildren(
C);
2890 AddStmtChoice asc) {
2892 appendStmt(ConfluenceBlock,
C);
2896 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2897 Succ = ConfluenceBlock;
2899 CFGBlock *LHSBlock = Visit(
C->getLHS(), alwaysAdd);
2903 Succ = ConfluenceBlock;
2905 CFGBlock *RHSBlock = Visit(
C->getRHS(), alwaysAdd);
2909 Block = createBlock(
false);
2911 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2912 addSuccessor(
Block, KnownVal.isFalse() ?
nullptr : LHSBlock);
2913 addSuccessor(
Block, KnownVal.isTrue() ?
nullptr : RHSBlock);
2915 return addStmt(
C->getCond());
2919 bool ExternallyDestructed) {
2920 LocalScope::const_iterator scopeBeginPos = ScopePos;
2921 addLocalScopeForStmt(
C);
2923 if (!
C->body_empty() && !isa<ReturnStmt>(*
C->body_rbegin())) {
2926 addAutomaticObjHandling(ScopePos, scopeBeginPos,
C);
2931 for (
Stmt *S : llvm::reverse(
C->body())) {
2934 CFGBlock *newBlock = Visit(S, AddStmtChoice::AlwaysAdd,
2935 ExternallyDestructed);
2938 LastBlock = newBlock;
2943 ExternallyDestructed =
false;
2950 AddStmtChoice asc) {
2957 appendStmt(ConfluenceBlock,
C);
2961 AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2967 Succ = ConfluenceBlock;
2970 const Expr *trueExpr =
C->getTrueExpr();
2971 if (trueExpr != opaqueValue) {
2972 LHSBlock = Visit(
C->getTrueExpr(), alwaysAdd);
2978 LHSBlock = ConfluenceBlock;
2981 Succ = ConfluenceBlock;
2982 CFGBlock *RHSBlock = Visit(
C->getFalseExpr(), alwaysAdd);
2988 dyn_cast<BinaryOperator>(
C->getCond()->IgnoreParens()))
2989 if (Cond->isLogicalOp())
2990 return VisitLogicalOperator(Cond,
C, LHSBlock, RHSBlock).first;
2993 Block = createBlock(
false);
2996 const TryResult& KnownVal = tryEvaluateBool(
C->getCond());
2997 addSuccessor(
Block, LHSBlock, !KnownVal.isFalse());
2998 addSuccessor(
Block, RHSBlock, !KnownVal.isTrue());
3000 Expr *condExpr =
C->getCond();
3005 if (condExpr != opaqueValue)
3013 return addStmt(condExpr);
3024 return VisitDeclSubExpr(DS);
3038 cfg->addSyntheticDeclStmt(DSNew, DS);
3041 B = VisitDeclSubExpr(DSNew);
3050 assert(DS->
isSingleDecl() &&
"Can handle single declarations only.");
3052 if (
const auto *TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl())) {
3054 const Type *
T = TND->getUnderlyingType().getTypePtr();
3059 appendStmt(
Block, DS);
3063 VA =
FindVA(VA->getElementType().getTypePtr())) {
3064 if (
CFGBlock *NewBlock = addStmt(VA->getSizeExpr()))
3065 LastBlock = NewBlock;
3078 bool HasTemporaries =
false;
3081 CFGBlock *blockAfterStaticInit =
nullptr;
3092 blockAfterStaticInit = Succ;
3099 HasTemporaries = isa<ExprWithCleanups>(
Init);
3103 TempDtorContext Context;
3104 VisitForTemporaryDtors(cast<ExprWithCleanups>(
Init)->getSubExpr(),
3111 if (
const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
3112 for (
auto *BD : llvm::reverse(DD->bindings())) {
3113 if (
auto *VD = BD->getHoldingVar()) {
3117 cfg->addSyntheticDeclStmt(DSNew, DS);
3118 Block = VisitDeclSubExpr(DSNew);
3124 appendStmt(
Block, DS);
3128 const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(
Init);
3130 findConstructionContexts(
3132 AILE ? AILE->getSubExpr() :
Init);
3140 if (HasTemporaries) {
3145 LastBlock = newBlock;
3149 LastBlock = newBlock;
3157 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr())) {
3158 if (
CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
3159 LastBlock = newBlock;
3162 maybeAddScopeBeginForVarDecl(
Block, VD, DS);
3165 if (ScopePos && VD == *ScopePos)
3169 if (blockAfterStaticInit) {
3171 Block = createBlock(
false);
3173 addSuccessor(
Block, blockAfterStaticInit);
3174 addSuccessor(
Block, B);
3195 addLocalScopeForStmt(
Init);
3200 addLocalScopeForVarDecl(VD);
3202 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
3224 if (!isa<CompoundStmt>(Else))
3225 addLocalScopeAndDtors(Else);
3227 ElseBlock = addStmt(Else);
3230 ElseBlock = sv.get();
3247 if (!isa<CompoundStmt>(Then))
3248 addLocalScopeAndDtors(Then);
3250 ThenBlock = addStmt(Then);
3256 ThenBlock = createBlock(
false);
3257 addSuccessor(ThenBlock, sv.get());
3277 LastBlock = VisitLogicalOperator(Cond, I, ThenBlock, ElseBlock).first;
3280 Block = createBlock(
false);
3288 KnownVal = tryEvaluateBool(I->
getCond());
3292 addSuccessor(
Block, ThenBlock, !KnownVal.isFalse());
3293 addSuccessor(
Block, ElseBlock, !KnownVal.isTrue());
3301 LastBlock = addStmt(I->
getCond());
3307 LastBlock = addStmt(
const_cast<DeclStmt *
>(DS));
3314 LastBlock = addStmt(
Init);
3327 assert(isa<ReturnStmt>(S) || isa<CoreturnStmt>(S));
3330 Block = createBlock(
false);
3332 addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), S);
3334 if (
auto *R = dyn_cast<ReturnStmt>(S))
3335 findConstructionContexts(
3342 addSuccessor(
Block, &cfg->getExit());
3345 appendStmt(
Block, S);
3348 if (
ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
3349 if (
Expr *O = RS->getRetValue())
3350 return Visit(O, AddStmtChoice::AlwaysAdd,
true);
3360 if (RV->getType()->isVoidType() && !isa<InitListExpr>(RV))
3369 AddStmtChoice asc) {
3373 if (asc.alwaysAdd(*
this,
E)) {
3378 if (
auto *R = Visit(
E->getResumeExpr()))
3380 if (
auto *R = Visit(
E->getSuspendExpr()))
3382 if (
auto *R = Visit(
E->getReadyExpr()))
3384 if (
auto *R = Visit(
E->getCommonExpr()))
3399 if (!SEHExceptBlock)
3400 SEHExceptBlock = createBlock();
3402 appendStmt(SEHExceptBlock, ES);
3414 return SEHExceptBlock;
3418 return VisitCompoundStmt(FS->getBlock(),
false);
3428 Block = createBlock(
false);
3433 if (SEHLeaveJumpTarget.block) {
3434 addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS);
3435 addSuccessor(
Block, SEHLeaveJumpTarget.block);
3445 CFGBlock *SEHTrySuccessor =
nullptr;
3450 SEHTrySuccessor =
Block;
3451 }
else SEHTrySuccessor = Succ;
3457 CFGBlock *PrevSEHTryTerminatedBlock = TryTerminatedBlock;
3460 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
3467 Succ = SEHTrySuccessor;
3469 CFGBlock *ExceptBlock = VisitSEHExceptStmt(Except);
3474 addSuccessor(NewTryTerminatedBlock, ExceptBlock);
3476 if (PrevSEHTryTerminatedBlock)
3477 addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock);
3479 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
3482 Succ = SEHTrySuccessor;
3485 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
3486 cfg->addTryDispatchBlock(TryTerminatedBlock);
3492 SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
3494 assert(Terminator->
getTryBlock() &&
"__try must contain a non-NULL body");
3505 LabelBlock = createBlock();
3507 assert(!LabelMap.contains(L->
getDecl()) &&
"label already in map");
3508 LabelMap[L->
getDecl()] = JumpTarget(LabelBlock, ScopePos);
3528 CFGBlock *LastBlock = VisitNoRecurse(
E, asc);
3530 if (
Expr *CopyExpr = CI.getCopyExpr()) {
3540 CFGBlock *LastBlock = VisitNoRecurse(
E, asc);
3544 et =
E->capture_init_end();
3545 it != et; ++it, ++Idx) {
3550 dyn_cast<ArrayInitLoopExpr>(
Init));
3553 cfg->getBumpVectorContext(), {E, Idx}),
3554 AILEInit ? AILEInit :
Init);
3568 Block = createBlock(
false);
3572 LabelMapTy::iterator I = LabelMap.find(G->
getLabel());
3574 if (I == LabelMap.end())
3576 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3578 JumpTarget JT = I->second;
3579 addSuccessor(
Block, JT.block);
3580 addScopeChangesHandling(ScopePos, JT.scopePosition, G);
3591 return VisitStmt(G, asc);
3598 Block = createBlock();
3601 BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3604 BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
3605 return VisitChildren(G);
3619 addLocalScopeForStmt(
Init);
3620 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3623 addLocalScopeForVarDecl(VD);
3624 LocalScope::const_iterator ContinueScopePos = ScopePos;
3626 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
3635 LoopSuccessor =
Block;
3637 LoopSuccessor = Succ;
3642 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3644 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3657 Block = Succ = TransitionBlock = createBlock(
false);
3658 TransitionBlock->setLoopTarget(F);
3663 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
3673 assert(
Block == Succ);
3681 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
3682 ContinueJumpTarget.block->setLoopTarget(F);
3687 if (!isa<CompoundStmt>(F->
getBody()))
3688 addLocalScopeAndDtors(F->
getBody());
3692 BodyBlock = addStmt(F->
getBody());
3697 BodyBlock = ContinueJumpTarget.block;
3706 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3715 dyn_cast_or_null<BinaryOperator>(
C ?
C->IgnoreParens() :
nullptr))
3717 std::tie(EntryConditionBlock, ExitConditionBlock) =
3718 VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor);
3723 EntryConditionBlock = ExitConditionBlock = createBlock(
false);
3724 ExitConditionBlock->setTerminator(F);
3727 TryResult KnownVal(
true);
3733 Block = ExitConditionBlock;
3734 EntryConditionBlock = addStmt(
C);
3743 findConstructionContexts(
3746 appendStmt(
Block, DS);
3747 EntryConditionBlock = addStmt(
Init);
3748 assert(
Block == EntryConditionBlock);
3749 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3753 if (
Block && badCFG)
3756 KnownVal = tryEvaluateBool(
C);
3760 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
3763 addSuccessor(ExitConditionBlock,
3764 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
3768 addSuccessor(TransitionBlock, EntryConditionBlock);
3771 Succ = EntryConditionBlock;
3777 ScopePos = LoopBeginScopePos;
3778 Block = createBlock();
3785 Succ = EntryConditionBlock;
3786 return EntryConditionBlock;
3791 AddStmtChoice asc) {
3792 findConstructionContexts(
3796 return VisitStmt(MTE, asc);
3800 if (asc.alwaysAdd(*
this, M)) {
3802 appendStmt(
Block, M);
3844 LoopSuccessor =
Block;
3847 LoopSuccessor = Succ;
3850 CFGBlock *ExitConditionBlock = createBlock(
false);
3858 appendStmt(ExitConditionBlock, S);
3859 Block = ExitConditionBlock;
3864 CFGBlock *EntryConditionBlock = Visit(S->getElement(),
3865 AddStmtChoice::NotAlwaysAdd);
3874 Succ = EntryConditionBlock;
3881 save_break(BreakJumpTarget);
3887 Succ = LoopBackBlock = createBlock();
3890 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3891 ContinueJumpTarget = JumpTarget(Succ, ScopePos);
3893 CFGBlock *BodyBlock = addStmt(S->getBody());
3896 BodyBlock = ContinueJumpTarget.block;
3903 addSuccessor(ExitConditionBlock, BodyBlock);
3908 addSuccessor(ExitConditionBlock, LoopSuccessor);
3911 Block = createBlock();
3912 return addStmt(S->getCollection());
3917 return addStmt(S->getSubStmt());
3925 CFGBlock *SyncBlock = addStmt(S->getSynchBody());
3939 appendStmt(
Block, S);
3942 return addStmt(S->getSynchExpr());
3955 for (
unsigned i =
E->getNumSemanticExprs(); i != 0; ) {
3956 Expr *Semantic =
E->getSemanticExpr(--i);
3961 Semantic = OVE->getSourceExpr();
3979 LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3981 addLocalScopeForVarDecl(VD);
3982 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
3991 LoopSuccessor =
Block;
3994 LoopSuccessor = Succ;
3997 CFGBlock *BodyBlock =
nullptr, *TransitionBlock =
nullptr;
4006 save_break(BreakJumpTarget);
4010 Succ = TransitionBlock = createBlock(
false);
4011 TransitionBlock->setLoopTarget(W);
4012 ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
4015 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4018 addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
4022 if (!isa<CompoundStmt>(W->
getBody()))
4023 addLocalScopeAndDtors(W->
getBody());
4026 BodyBlock = addStmt(W->
getBody());
4029 BodyBlock = ContinueJumpTarget.block;
4030 else if (
Block && badCFG)
4037 CFGBlock *EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
4044 if (
BinaryOperator *Cond = dyn_cast<BinaryOperator>(
C->IgnoreParens()))
4046 std::tie(EntryConditionBlock, ExitConditionBlock) =
4047 VisitLogicalOperator(Cond, W, BodyBlock, LoopSuccessor);
4052 ExitConditionBlock = createBlock(
false);
4058 Block = ExitConditionBlock;
4059 Block = EntryConditionBlock = addStmt(
C);
4068 findConstructionContexts(
4072 appendStmt(
Block, DS);
4073 EntryConditionBlock = addStmt(
Init);
4074 assert(
Block == EntryConditionBlock);
4075 maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
4079 if (
Block && badCFG)
4083 const TryResult& KnownVal = tryEvaluateBool(
C);
4086 addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr : BodyBlock);
4089 addSuccessor(ExitConditionBlock,
4090 KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4094 addSuccessor(TransitionBlock, EntryConditionBlock);
4101 Succ = EntryConditionBlock;
4102 return EntryConditionBlock;
4106 AddStmtChoice asc) {
4107 if (asc.alwaysAdd(*
this, A)) {
4109 appendStmt(
Block, A);
4118 assert(OVE &&
"ArrayInitLoopExpr->getCommonExpr() should be wrapped in an "
4119 "OpaqueValueExpr!");
4120 if (
CFGBlock *R = Visit(OVE->getSourceExpr()))
4139 CatchBlock = createBlock();
4141 appendStmt(CatchBlock, CS);
4162 Block = createBlock(
false);
4164 if (TryTerminatedBlock)
4166 addSuccessor(
Block, TryTerminatedBlock);
4169 addSuccessor(
Block, &cfg->getExit());
4173 return VisitStmt(S, AddStmtChoice::AlwaysAdd);
4184 TrySuccessor =
Block;
4186 TrySuccessor = Succ;
4192 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4195 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4199 bool HasCatchAll =
false;
4202 Succ = TrySuccessor;
4207 CFGBlock *CatchBlock = VisitObjCAtCatchStmt(CS);
4212 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4217 if (PrevTryTerminatedBlock)
4218 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4220 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4224 Succ = TrySuccessor;
4227 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4228 cfg->addTryDispatchBlock(TryTerminatedBlock);
4230 assert(Terminator->
getTryBody() &&
"try must contain a non-NULL body");
4236 AddStmtChoice asc) {
4237 findConstructionContextsForArguments(ME);
4240 appendObjCMessage(
Block, ME);
4242 return VisitChildren(ME);
4251 Block = createBlock(
false);
4253 if (TryTerminatedBlock)
4255 addSuccessor(
Block, TryTerminatedBlock);
4258 addSuccessor(
Block, &cfg->getExit());
4262 return VisitStmt(
T, AddStmtChoice::AlwaysAdd);
4266 if (asc.alwaysAdd(*
this, S)) {
4268 appendStmt(
Block, S);
4277 if (!S->isTypeDependent() && S->isPotentiallyEvaluated())
4278 return VisitChildren(S);
4294 LoopSuccessor =
Block;
4296 LoopSuccessor = Succ;
4301 CFGBlock *ExitConditionBlock = createBlock(
false);
4302 CFGBlock *EntryConditionBlock = ExitConditionBlock;
4309 if (
Stmt *
C =
D->getCond()) {
4310 Block = ExitConditionBlock;
4311 EntryConditionBlock = addStmt(
C);
4319 Succ = EntryConditionBlock;
4322 const TryResult &KnownVal = tryEvaluateBool(
D->getCond());
4332 save_break(BreakJumpTarget);
4335 ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
4338 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4345 if (!isa<CompoundStmt>(
D->
getBody()))
4346 addLocalScopeAndDtors(
D->
getBody());
4352 BodyBlock = EntryConditionBlock;
4365 CFGBlock *LoopBackBlock = createBlock();
4368 if (!KnownVal.isFalse())
4370 addSuccessor(ExitConditionBlock, LoopBackBlock);
4372 addSuccessor(ExitConditionBlock,
nullptr);
4377 addSuccessor(ExitConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4395 Block = createBlock(
false);
4400 if (ContinueJumpTarget.block) {
4401 addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition,
C);
4402 addSuccessor(
Block, ContinueJumpTarget.block);
4410 AddStmtChoice asc) {
4411 if (asc.alwaysAdd(*
this,
E)) {
4419 if (
E->getKind() != UETT_SizeOf)
4424 if (
E->isArgumentType()) {
4426 VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr()))
4427 lastBlock = addStmt(VA->getSizeExpr());
4435 if (asc.alwaysAdd(*
this, SE)) {
4437 appendStmt(
Block, SE);
4439 return VisitCompoundStmt(SE->
getSubStmt(),
true);
4445 CFGBlock *SwitchSuccessor =
nullptr;
4453 addLocalScopeForStmt(
Init);
4458 addLocalScopeForVarDecl(VD);
4460 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
4465 SwitchSuccessor =
Block;
4466 }
else SwitchSuccessor = Succ;
4470 save_default(DefaultCaseBlock);
4476 DefaultCaseBlock = SwitchSuccessor;
4479 SwitchTerminatedBlock = createBlock(
false);
4483 Succ = SwitchSuccessor;
4484 BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
4489 assert(Terminator->
getBody() &&
"switch must contain a non-NULL body");
4494 SaveAndRestore save_switchExclusivelyCovered(switchExclusivelyCovered,
false);
4497 assert(Terminator->
getCond() &&
"switch condition must be non-NULL");
4499 bool b = tryEvaluate(Terminator->
getCond(), result);
4504 if (!isa<CompoundStmt>(Terminator->
getBody()))
4505 addLocalScopeAndDtors(Terminator->
getBody());
4507 addStmt(Terminator->
getBody());
4519 bool SwitchAlwaysHasSuccessor =
false;
4520 SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
4523 addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock,
4524 !SwitchAlwaysHasSuccessor);
4528 Block = SwitchTerminatedBlock;
4537 LastBlock = addStmt(
Init);
4538 maybeAddScopeBeginForVarDecl(LastBlock, VD,
Init);
4545 LastBlock = addStmt(
Init);
4558 bool addCase =
false;
4560 if (!switchExclusivelyCovered) {
4564 const llvm::APSInt &condInt = switchCond->
Val.
getInt();
4566 if (condInt == lhsInt) {
4568 switchExclusivelyCovered =
true;
4570 else if (condInt > lhsInt) {
4574 if (V2 >= condInt) {
4576 switchExclusivelyCovered =
true;
4590 CFGBlock *TopBlock =
nullptr, *LastBlock =
nullptr;
4596 while (isa<CaseStmt>(Sub)) {
4597 CFGBlock *currentBlock = createBlock(
false);
4601 addSuccessor(LastBlock, currentBlock);
4603 TopBlock = currentBlock;
4605 addSuccessor(SwitchTerminatedBlock,
4608 ? currentBlock :
nullptr);
4610 LastBlock = currentBlock;
4611 CS = cast<CaseStmt>(Sub);
4620 CaseBlock = createBlock();
4631 assert(SwitchTerminatedBlock);
4632 addSuccessor(SwitchTerminatedBlock, CaseBlock,
4640 addSuccessor(LastBlock, CaseBlock);
4654 DefaultCaseBlock =
Block;
4656 if (!DefaultCaseBlock)
4657 DefaultCaseBlock = createBlock();
4661 DefaultCaseBlock->
setLabel(Terminator);
4676 Succ = DefaultCaseBlock;
4678 return DefaultCaseBlock;
4689 TrySuccessor =
Block;
4691 TrySuccessor = Succ;
4693 CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
4696 CFGBlock *NewTryTerminatedBlock = createBlock(
false);
4700 bool HasCatchAll =
false;
4703 Succ = TrySuccessor;
4709 CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
4714 addSuccessor(NewTryTerminatedBlock, CatchBlock);
4717 if (PrevTryTerminatedBlock)
4718 addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4720 addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4724 Succ = TrySuccessor;
4727 SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4728 cfg->addTryDispatchBlock(TryTerminatedBlock);
4730 assert(Terminator->
getTryBlock() &&
"try must contain a non-NULL body");
4746 LocalScope::const_iterator BeginScopePos = ScopePos;
4747 addLocalScopeForVarDecl(VD);
4748 addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
4756 CatchBlock = createBlock();
4762 appendStmt(CatchBlock, CS);
4797 addLocalScopeForStmt(
Range);
4799 addLocalScopeForStmt(
Begin);
4800 if (
Stmt *End = S->getEndStmt())
4801 addLocalScopeForStmt(End);
4802 addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
4804 LocalScope::const_iterator ContinueScopePos = ScopePos;
4812 LoopSuccessor =
Block;
4814 LoopSuccessor = Succ;
4819 BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4822 CFGBlock *ConditionBlock = createBlock(
false);
4826 if (
Expr *
C = S->getCond()) {
4827 Block = ConditionBlock;
4828 CFGBlock *BeginConditionBlock = addStmt(
C);
4831 assert(BeginConditionBlock == ConditionBlock &&
4832 "condition block in for-range was unexpectedly complex");
4833 (void)BeginConditionBlock;
4838 Succ = ConditionBlock;
4841 TryResult KnownVal(
true);
4844 KnownVal = tryEvaluateBool(S->getCond());
4848 assert(S->getBody());
4857 Succ = addStmt(S->getInc());
4860 ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
4864 ContinueJumpTarget.block->setLoopTarget(S);
4873 addLocalScopeAndDtors(S->getLoopVarStmt());
4877 if (!isa<CompoundStmt>(S->getBody()))
4878 addLocalScopeAndDtors(S->getBody());
4881 addStmt(S->getBody());
4885 CFGBlock *LoopVarStmtBlock = addStmt(S->getLoopVarStmt());
4890 addSuccessor(ConditionBlock,
4891 KnownVal.isFalse() ?
nullptr : LoopVarStmtBlock);
4896 addSuccessor(ConditionBlock, KnownVal.isTrue() ?
nullptr : LoopSuccessor);
4899 Block = createBlock();
4900 addStmt(S->getBeginStmt());
4901 addStmt(S->getEndStmt());
4902 CFGBlock *Head = addStmt(S->getRangeStmt());
4904 Head = addStmt(S->getInit());
4909 AddStmtChoice asc,
bool ExternallyDestructed) {
4913 TempDtorContext Context;
4914 VisitForTemporaryDtors(
E->getSubExpr(), ExternallyDestructed, Context);
4918 asc = asc.withAlwaysAdd(
true);
4920 return Visit(
E->getSubExpr(), asc);
4924 AddStmtChoice asc) {
4925 if (asc.alwaysAdd(*
this,
E)) {
4929 findConstructionContexts(
4934 asc = asc.withAlwaysAdd(
false);
4936 return Visit(
E->getSubExpr(), asc);
4940 AddStmtChoice asc) {
4944 findConstructionContextsForArguments(
C);
4945 appendConstructor(
C);
4947 return VisitChildren(
C);
4951 AddStmtChoice asc) {
4953 appendStmt(
Block, NE);
4955 findConstructionContexts(
4959 if (
NE->getInitializer())
4960 Block = Visit(
NE->getInitializer());
4963 appendNewAllocator(
Block, NE);
4965 if (
NE->isArray() && *
NE->getArraySize())
4966 Block = Visit(*
NE->getArraySize());
4969 E =
NE->placement_arg_end(); I !=
E; ++I)
4976 AddStmtChoice asc) {
4978 appendStmt(
Block, DE);
4985 appendDeleteDtor(
Block, RD, DE);
4989 return VisitChildren(DE);
4993 AddStmtChoice asc) {
4994 if (asc.alwaysAdd(*
this,
E)) {
4998 asc = asc.withAlwaysAdd(
false);
5000 return Visit(
E->getSubExpr(), asc);
5004 AddStmtChoice asc) {
5008 findConstructionContextsForArguments(
E);
5009 appendConstructor(
E);
5011 return VisitChildren(
E);
5015 AddStmtChoice asc) {
5016 if (asc.alwaysAdd(*
this,
E)) {
5021 if (
E->getCastKind() == CK_IntegralToBoolean)
5024 return Visit(
E->getSubExpr(), AddStmtChoice());
5028 return Visit(
E->getSubExpr(), AddStmtChoice());
5033 CFGBlock *IBlock = cfg->getIndirectGotoBlock();
5036 IBlock = createBlock(
false);
5037 cfg->setIndirectGotoBlock(IBlock);
5045 Block = createBlock(
false);
5047 addSuccessor(
Block, IBlock);
5051CFGBlock *CFGBuilder::VisitForTemporaryDtors(
Stmt *
E,
bool ExternallyDestructed,
5052 TempDtorContext &Context) {
5062 return VisitChildrenForTemporaryDtors(
E,
false, Context);
5064 case Stmt::InitListExprClass:
5065 return VisitChildrenForTemporaryDtors(
E, ExternallyDestructed, Context);
5067 case Stmt::BinaryOperatorClass:
5068 return VisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(
E),
5069 ExternallyDestructed,
5072 case Stmt::CXXBindTemporaryExprClass:
5073 return VisitCXXBindTemporaryExprForTemporaryDtors(
5074 cast<CXXBindTemporaryExpr>(
E), ExternallyDestructed, Context);
5076 case Stmt::BinaryConditionalOperatorClass:
5077 case Stmt::ConditionalOperatorClass:
5078 return VisitConditionalOperatorForTemporaryDtors(
5079 cast<AbstractConditionalOperator>(
E), ExternallyDestructed, Context);
5081 case Stmt::ImplicitCastExprClass:
5083 E = cast<CastExpr>(
E)->getSubExpr();
5086 case Stmt::CXXFunctionalCastExprClass:
5088 E = cast<CXXFunctionalCastExpr>(
E)->getSubExpr();
5091 case Stmt::ConstantExprClass:
5092 E = cast<ConstantExpr>(
E)->getSubExpr();
5095 case Stmt::ParenExprClass:
5096 E = cast<ParenExpr>(
E)->getSubExpr();
5099 case Stmt::MaterializeTemporaryExprClass: {
5105 E =
const_cast<Expr *
>(
5106 cast<MaterializeTemporaryExpr>(
E)
5108 ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
5110 for (
const Expr *CommaLHS : CommaLHSs) {
5111 VisitForTemporaryDtors(
const_cast<Expr *
>(CommaLHS),
5117 case Stmt::BlockExprClass:
5122 case Stmt::LambdaExprClass: {
5125 auto *
LE = cast<LambdaExpr>(
E);
5129 if (
CFGBlock *R = VisitForTemporaryDtors(
5130 Init,
true, Context))
5137 case Stmt::StmtExprClass:
5142 case Stmt::CXXDefaultArgExprClass:
5143 E = cast<CXXDefaultArgExpr>(
E)->getExpr();
5146 case Stmt::CXXDefaultInitExprClass:
5147 E = cast<CXXDefaultInitExpr>(
E)->getExpr();
5152CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(
Stmt *
E,
5153 bool ExternallyDestructed,
5154 TempDtorContext &Context) {
5155 if (isa<LambdaExpr>(
E)) {
5167 if (
CFGBlock *R = VisitForTemporaryDtors(Child, ExternallyDestructed, Context))
5173CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
5174 BinaryOperator *
E,
bool ExternallyDestructed, TempDtorContext &Context) {
5175 if (
E->isCommaOp()) {
5178 CFGBlock *LHSBlock = VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5179 CFGBlock *RHSBlock = VisitForTemporaryDtors(
E->getRHS(), ExternallyDestructed, Context);
5180 return RHSBlock ? RHSBlock : LHSBlock;
5183 if (
E->isLogicalOp()) {
5184 VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5185 TryResult RHSExecuted = tryEvaluateBool(
E->getLHS());
5186 if (RHSExecuted.isKnown() &&
E->getOpcode() == BO_LOr)
5187 RHSExecuted.negate();
5192 TempDtorContext RHSContext(
5194 VisitForTemporaryDtors(
E->getRHS(),
false, RHSContext);
5195 InsertTempDtorDecisionBlock(RHSContext);
5200 if (
E->isAssignmentOp()) {
5203 CFGBlock *RHSBlock = VisitForTemporaryDtors(
E->getRHS(),
false, Context);
5204 CFGBlock *LHSBlock = VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5205 return LHSBlock ? LHSBlock : RHSBlock;
5209 return VisitChildrenForTemporaryDtors(
E, ExternallyDestructed, Context);
5212CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
5216 CFGBlock *B = VisitForTemporaryDtors(
E->getSubExpr(),
true, Context);
5217 if (!ExternallyDestructed) {
5229 Block = createNoReturnBlock();
5230 }
else if (Context.needsTempDtorBranch()) {
5234 Block = createBlock();
5238 if (Context.needsTempDtorBranch()) {
5239 Context.setDecisionPoint(Succ,
E);
5241 appendTemporaryDtor(
Block,
E);
5248void CFGBuilder::InsertTempDtorDecisionBlock(
const TempDtorContext &Context,
5250 if (!Context.TerminatorExpr) {
5254 assert(Context.TerminatorExpr);
5255 CFGBlock *Decision = createBlock(
false);
5258 addSuccessor(Decision,
Block, !Context.KnownExecuted.isFalse());
5259 addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
5260 !Context.KnownExecuted.isTrue());
5264CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
5266 TempDtorContext &Context) {
5267 VisitForTemporaryDtors(
E->getCond(),
false, Context);
5270 TryResult ConditionVal = tryEvaluateBool(
E->getCond());
5271 TryResult NegatedVal = ConditionVal;
5272 if (NegatedVal.isKnown()) NegatedVal.negate();
5274 TempDtorContext TrueContext(
5276 VisitForTemporaryDtors(
E->getTrueExpr(), ExternallyDestructed, TrueContext);
5279 Block = ConditionBlock;
5280 Succ = ConditionSucc;
5281 TempDtorContext FalseContext(
5283 VisitForTemporaryDtors(
E->getFalseExpr(), ExternallyDestructed, FalseContext);
5285 if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
5286 InsertTempDtorDecisionBlock(FalseContext, TrueBlock);
5287 }
else if (TrueContext.TerminatorExpr) {
5289 InsertTempDtorDecisionBlock(TrueContext);
5291 InsertTempDtorDecisionBlock(FalseContext);
5297 AddStmtChoice asc) {
5298 if (asc.alwaysAdd(*
this,
D)) {
5310 for (
Stmt *S : llvm::reverse(
Used)) {
5311 assert(S &&
"Expected non-null used-in-clause child.");
5316 if (!
D->isStandaloneDirective()) {
5317 Stmt *S =
D->getRawStmt();
5318 if (!isa<CompoundStmt>(S))
5319 addLocalScopeAndDtors(S);
5331 bool first_block =
begin() ==
end();
5339 Entry = Exit = &
back();
5348 CFGBuilder Builder(
C, BO);
5349 return Builder.buildCFG(
D, Statement);
5364 auto IteratorAndFlag =
Visited.insert(B);
5365 if (!IteratorAndFlag.second) {
5371 const CFGBlock *FirstReachableB =
nullptr;
5373 if (!AB.isReachable())
5376 if (FirstReachableB ==
nullptr) {
5377 FirstReachableB = &*AB;
5384 if (!FirstReachableB) {
5390 B = FirstReachableB;
5410 llvm_unreachable(
"getDestructorDecl should only be used with "
5413 const VarDecl *var = castAs<CFGAutomaticObjDtor>().getVarDecl();
5421 if (
const Expr *
Init = var->getInit()) {
5439 const CXXDeleteExpr *DE = castAs<CFGDeleteDtor>().getDeleteExpr();
5448 castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
5453 const FieldDecl *field = castAs<CFGMemberDtor>().getFieldDecl();
5468 llvm_unreachable(
"getKind() returned bogus value");
5476 : ReachableBlock(IsReachable ? B : nullptr),
5477 UnreachableBlock(!IsReachable ? B : nullptr,
5478 B && IsReachable ? AB_Normal : AB_Unreachable) {}
5481 : ReachableBlock(B),
5482 UnreachableBlock(B == AlternateBlock ? nullptr : AlternateBlock,
5483 B == AlternateBlock ? AB_Alternate : AB_Normal) {}
5506 if (S->isAllEnumCasesCovered()) {
5508 if (!L || !isa<CaseStmt>(L))
5524 using StmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>;
5525 using DeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>;
5529 signed currentBlock = 0;
5530 unsigned currStmt = 0;
5541 BI != BEnd; ++BI, ++j ) {
5542 if (std::optional<CFGStmt> SE = BI->getAs<
CFGStmt>()) {
5544 std::pair<unsigned, unsigned>
P((*I)->getBlockID(), j);
5547 switch (
stmt->getStmtClass()) {
5548 case Stmt::DeclStmtClass:
5549 DeclMap[cast<DeclStmt>(
stmt)->getSingleDecl()] =
P;
5551 case Stmt::IfStmtClass: {
5552 const VarDecl *var = cast<IfStmt>(
stmt)->getConditionVariable();
5557 case Stmt::ForStmtClass: {
5558 const VarDecl *var = cast<ForStmt>(
stmt)->getConditionVariable();
5563 case Stmt::WhileStmtClass: {
5565 cast<WhileStmt>(
stmt)->getConditionVariable();
5570 case Stmt::SwitchStmtClass: {
5572 cast<SwitchStmt>(
stmt)->getConditionVariable();
5577 case Stmt::CXXCatchStmtClass: {
5579 cast<CXXCatchStmt>(
stmt)->getExceptionDecl();
5592 ~StmtPrinterHelper()
override =
default;
5594 const LangOptions &getLangOpts()
const {
return LangOpts; }
5595 void setBlockID(
signed i) { currentBlock = i; }
5596 void setStmtID(
unsigned i) { currStmt = i; }
5598 bool handledStmt(
Stmt *S, raw_ostream &OS)
override {
5599 StmtMapTy::iterator I = StmtMap.find(S);
5601 if (I == StmtMap.end())
5604 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5605 && I->second.second == currStmt) {
5609 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5613 bool handleDecl(
const Decl *
D, raw_ostream &OS) {
5614 DeclMapTy::iterator I = DeclMap.find(
D);
5616 if (I == DeclMap.end())
5619 if (currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5620 && I->second.second == currStmt) {
5624 OS <<
"[B" << I->second.first <<
"." << I->second.second <<
"]";
5629class CFGBlockTerminatorPrint
5630 :
public StmtVisitor<CFGBlockTerminatorPrint,void> {
5632 StmtPrinterHelper* Helper;
5636 CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
5638 : OS(os), Helper(helper), Policy(Policy) {
5642 void VisitIfStmt(
IfStmt *I) {
5645 C->printPretty(OS, Helper, Policy);
5649 void VisitStmt(
Stmt *Terminator) {
5655 OS <<
"static init " << VD->
getName();
5658 void VisitForStmt(
ForStmt *F) {
5664 C->printPretty(OS, Helper, Policy);
5674 C->printPretty(OS, Helper, Policy);
5678 OS <<
"do ... while ";
5679 if (
Stmt *
C =
D->getCond())
5680 C->printPretty(OS, Helper, Policy);
5683 void VisitSwitchStmt(
SwitchStmt *Terminator) {
5688 void VisitCXXTryStmt(
CXXTryStmt *) { OS <<
"try ..."; }
5690 void VisitObjCAtTryStmt(
ObjCAtTryStmt *) { OS <<
"@try ..."; }
5692 void VisitSEHTryStmt(
SEHTryStmt *CS) { OS <<
"__try ..."; }
5695 if (
Stmt *Cond =
C->getCond())
5697 OS <<
" ? ... : ...";
5701 OS <<
"__builtin_choose_expr( ";
5702 if (
Stmt *Cond =
C->getCond())
5710 T->printPretty(OS, Helper, Policy);
5730 llvm_unreachable(
"Invalid logical operator.");
5734 void VisitExpr(
Expr *
E) {
5740 switch (
T.getKind()) {
5745 OS <<
"(Temp Dtor) ";
5749 OS <<
"(See if most derived ctor has already initialized vbases)";
5771 OS <<
" (Base initializer)";
5773 OS <<
" (Delegating initializer)";
5775 OS <<
" (Member initializer)";
5779 StmtPrinterHelper &Helper,
5785 const auto *SICC = cast<SimpleConstructorInitializerConstructionContext>(CC);
5792 cast<CXX17ElidedCopyConstructorInitializerConstructionContext>(CC);
5794 Stmts.push_back(CICC->getCXXBindTemporaryExpr());
5798 const auto *SDSCC = cast<SimpleVariableConstructionContext>(CC);
5799 Stmts.push_back(SDSCC->getDeclStmt());
5803 const auto *CDSCC = cast<CXX17ElidedCopyVariableConstructionContext>(CC);
5804 Stmts.push_back(CDSCC->getDeclStmt());
5805 Stmts.push_back(CDSCC->getCXXBindTemporaryExpr());
5809 const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
5810 Stmts.push_back(NECC->getCXXNewExpr());
5814 const auto *RSCC = cast<SimpleReturnedValueConstructionContext>(CC);
5815 Stmts.push_back(RSCC->getReturnStmt());
5820 cast<CXX17ElidedCopyReturnedValueConstructionContext>(CC);
5821 Stmts.push_back(RSCC->getReturnStmt());
5822 Stmts.push_back(RSCC->getCXXBindTemporaryExpr());
5826 const auto *TOCC = cast<SimpleTemporaryObjectConstructionContext>(CC);
5827 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5828 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5832 const auto *TOCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
5833 Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5834 Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5835 Stmts.push_back(TOCC->getConstructorAfterElision());
5839 const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
5840 Helper.handledStmt(
const_cast<LambdaExpr *
>(LCC->getLambdaExpr()), OS);
5841 OS <<
"+" << LCC->getIndex();
5845 const auto *ACC = cast<ArgumentConstructionContext>(CC);
5846 if (
const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
5848 Helper.handledStmt(
const_cast<Stmt *
>(BTE), OS);
5851 Helper.handledStmt(
const_cast<Expr *
>(ACC->getCallLikeExpr()), OS);
5852 OS <<
"+" << ACC->getIndex();
5859 Helper.handledStmt(
const_cast<Stmt *
>(I), OS);
5863static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5864 const CFGElement &
E,
bool TerminateWithNewLine =
true);
5867 bool TerminateWithNewLine)
const {
5869 StmtPrinterHelper Helper(
nullptr, LangOpts);
5870 print_elem(OS, Helper, *
this, TerminateWithNewLine);
5873static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5875 switch (
E.getKind()) {
5881 assert(S !=
nullptr &&
"Expecting non-null Stmt");
5884 if (
const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
5887 auto Children = Sub->children();
5888 if (Children.begin() != Children.end()) {
5892 if (TerminateWithNewLine)
5901 Helper.handledStmt(B->
getRHS(),OS);
5902 if (TerminateWithNewLine)
5907 S->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
5910 if (isa<CXXOperatorCallExpr>(S))
5911 OS <<
" (OperatorCall)";
5912 OS <<
" (CXXRecordTypedCall";
5915 }
else if (isa<CXXOperatorCallExpr>(S)) {
5916 OS <<
" (OperatorCall)";
5917 }
else if (isa<CXXBindTemporaryExpr>(S)) {
5918 OS <<
" (BindTemporary)";
5920 OS <<
" (CXXConstructExpr";
5924 OS <<
", " << CCE->getType() <<
")";
5925 }
else if (
const CastExpr *CE = dyn_cast<CastExpr>(S)) {
5927 <<
", " << CE->
getType() <<
")";
5931 if (isa<Expr>(S) && TerminateWithNewLine)
5944 Helper.handleDecl(VD, OS);
5951 T.getUnqualifiedType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5952 OS <<
"() (Implicit destructor)";
5957 OS <<
"CleanupFunction ("
5963 OS <<
" (Lifetime ends)";
5967 OS <<
E.castAs<
CFGLoopExit>().getLoopStmt()->getStmtClassName()
5972 OS <<
"CFGScopeBegin(";
5979 OS <<
"CFGScopeEnd(";
5986 OS <<
"CFGNewAllocator(";
5988 AllocExpr->getType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5999 Helper.handledStmt(cast<Stmt>(DelExpr->
getArgument()), OS);
6000 OS <<
"->~" << RD->getName().str() <<
"()";
6001 OS <<
" (Implicit destructor)";
6008 OS <<
" (Base object destructor)";
6015 OS <<
"this->" << FD->
getName();
6017 OS <<
" (Member object destructor)";
6026 OS <<
"() (Temporary object destructor)";
6030 if (TerminateWithNewLine)
6036 StmtPrinterHelper &Helper,
bool print_edges,
6042 OS.changeColor(raw_ostream::YELLOW,
true);
6047 OS <<
" (ENTRY)]\n";
6048 else if (&B == &cfg->
getExit())
6051 OS <<
" (INDIRECT GOTO DISPATCH)]\n";
6053 OS <<
" (NORETURN)]\n";
6069 if (
const Expr *LHS =
C->getLHS())
6071 if (
const Expr *RHS =
C->getRHS()) {
6075 }
else if (isa<DefaultStmt>(
Label))
6086 if (
const VarDecl *PD = CS->getCatchParamDecl())
6097 llvm_unreachable(
"Invalid label statement in CFGBlock.");
6106 I !=
E ; ++I, ++j ) {
6111 OS << llvm::format(
"%3d", j) <<
": ";
6113 Helper.setStmtID(j);
6121 OS.changeColor(raw_ostream::GREEN);
6125 Helper.setBlockID(-1);
6128 CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
6139 const raw_ostream::Colors Color = raw_ostream::BLUE;
6141 OS.changeColor(Color);
6149 OS.changeColor(Color);
6157 bool Reachable =
true;
6160 B = I->getPossiblyUnreachableBlock();
6165 OS <<
"(Unreachable)";
6176 const raw_ostream::Colors Color = raw_ostream::MAGENTA;
6178 OS.changeColor(Color);
6186 OS.changeColor(Color);
6195 bool Reachable =
true;
6198 B = I->getPossiblyUnreachableBlock();
6204 OS <<
"(Unreachable)";
6225 StmtPrinterHelper Helper(
this, LO);
6233 if (&(**I) == &getEntry() || &(**I) == &getExit())
6263 StmtPrinterHelper Helper(cfg, LO);
6271 CFGBlockTerminatorPrint TPrinter(OS,
nullptr,
PrintingPolicy(LO));
6277 bool AddQuotes)
const {
6279 llvm::raw_string_ostream TempOut(Buf);
6302 if (llvm::any_of(*Blk, [](
const CFGElement &Elm) {
6303 if (std::optional<CFGStmt> StmtElm = Elm.
getAs<
CFGStmt>())
6304 if (isa<CXXThrowExpr>(StmtElm->getStmt()))
6323 DFSWorkList.push_back(StartBlk);
6324 while (!DFSWorkList.empty()) {
6325 const CFGBlock *Blk = DFSWorkList.pop_back_val();
6335 for (
const auto &Succ : Blk->
succs()) {
6336 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
6340 DFSWorkList.push_back(SuccBlk);
6369 const Stmt *Cond = StmtElem->getStmt();
6370 if (isa<ObjCForCollectionStmt>(Cond) || isa<DeclStmt>(Cond))
6389 case Stmt::CXXForRangeStmtClass:
6393 case Stmt::ForStmtClass:
6397 case Stmt::WhileStmtClass:
6401 case Stmt::DoStmtClass:
6405 case Stmt::IfStmtClass:
6409 case Stmt::ChooseExprClass:
6413 case Stmt::IndirectGotoStmtClass:
6414 E = cast<IndirectGotoStmt>(
Terminator)->getTarget();
6417 case Stmt::SwitchStmtClass:
6421 case Stmt::BinaryConditionalOperatorClass:
6422 E = cast<BinaryConditionalOperator>(
Terminator)->getCond();
6425 case Stmt::ConditionalOperatorClass:
6426 E = cast<ConditionalOperator>(
Terminator)->getCond();
6429 case Stmt::BinaryOperatorClass:
6433 case Stmt::ObjCForCollectionStmtClass:
6450 StmtPrinterHelper H(
this, LO);
6452 llvm::ViewGraph(
this,
"CFG");
6464 llvm::raw_string_ostream Out(OutStr);
6467 if (OutStr[0] ==
'\n') OutStr.erase(OutStr.begin());
6470 for (
unsigned i = 0; i != OutStr.length(); ++i)
6471 if (OutStr[i] ==
'\n') {
6473 OutStr.insert(OutStr.begin()+i+1,
'l');
Defines the clang::ASTContext interface.
Defines enum values for all the target-independent builtin functions.
static StmtPrinterHelper * GraphHelper
static bool isCXXAssumeAttr(const AttributedStmt *A)
static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const CFGElement &E, bool TerminateWithNewLine=true)
static void print_initializer(raw_ostream &OS, StmtPrinterHelper &Helper, const CXXCtorInitializer *I)
static SourceLocation GetEndLoc(Decl *D)
static bool isBuiltinAssumeWithSideEffects(const ASTContext &Ctx, const CallExpr *CE)
static bool CanThrow(Expr *E, ASTContext &Ctx)
static bool isFallthroughStatement(const AttributedStmt *A)
static void print_block(raw_ostream &OS, const CFG *cfg, const CFGBlock &B, StmtPrinterHelper &Helper, bool print_edges, bool ShowColors)
static bool isImmediateSinkBlock(const CFGBlock *Blk)
static const Expr * tryTransformToLiteralConstant(const Expr *E)
Helper for tryNormalizeBinaryOperator.
static QualType getReferenceInitTemporaryType(const Expr *Init, bool *FoundMTE=nullptr)
Retrieve the type of the temporary object whose lifetime was extended by a local reference with the g...
static const VariableArrayType * FindVA(const Type *t)
static std::tuple< const Expr *, BinaryOperatorKind, const Expr * > tryNormalizeBinaryOperator(const BinaryOperator *B)
Tries to interpret a binary operator into Expr Op NumExpr form, if NumExpr is an integer literal or a...
static bool IsLiteralConstantExpr(const Expr *E)
Returns true on constant values based around a single IntegerLiteral, CharacterLiteral,...
static void print_construction_context(raw_ostream &OS, StmtPrinterHelper &Helper, const ConstructionContext *CC)
static bool shouldAddCase(bool &switchExclusivelyCovered, const Expr::EvalResult *switchCond, const CaseStmt *CS, ASTContext &Ctx)
static bool areExprTypesCompatible(const Expr *E1, const Expr *E2)
For an expression x == Foo && x == Bar, this determines whether the Foo and Bar are either of the sam...
static TryResult bothKnownTrue(TryResult R1, TryResult R2)
clang::CharUnits operator*(clang::CharUnits::QuantityType Scale, const clang::CharUnits &CU)
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
ValueKind getKind() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const ConstantArrayType * getAsConstantArrayType(QualType T) const
const LangOptions & getLangOpts() const
int getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const
Compare the rank of two floating point types as above, but compare equal if both types have the same ...
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
CanQualType BoundMemberTy
const ArrayType * getAsArrayType(QualType T) const
Type Query functions.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
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.
Attr - This represents one attribute.
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, bool TerminateWithNewLine=true) const
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
const CXXDestructorDecl * getDestructorDecl(ASTContext &astContext) const
Represents C++ base or member initializer from constructor's initialization list.
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.
unsigned getBuiltinCallee() const
getBuiltinCallee - If this is a call to a builtin, return the builtin ID of the callee.
CaseStmt - Represent a case statement.
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
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.
ASTContext & getASTContext() const LLVM_READONLY
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 EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsRValue - Return true if this is a constant which we can fold to an rvalue using any crazy t...
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsBooleanCondition - Return true if this is a constant which we can fold and convert to a boo...
static bool isSameComparisonOperand(const Expr *E1, const Expr *E2)
Checks that the two Expr's will refer to the same value as a comparison operand.
bool isKnownToHaveBooleanValue(bool Semantic=true) const
isKnownToHaveBooleanValue - Return true if this is an integer expression that is known to return 0 or...
Represents a member of a struct/union/class.
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.
Represents the declaration of a label.
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.
bool isBlockPointerType() const
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isFunctionPointerType() const
bool isReferenceType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const Type * getBaseElementTypeUnsafe() const
Get the base element type of this type, potentially discarding type qualifiers.
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
const T * getAs() const
Member-template getAs<specific type>'.
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)