;
67 if(
VarDecl*VD = dyn_cast<VarDecl>(
D))
68 if(
Expr*Ex = VD->getInit())
69 returnEx->getSourceRange().getEnd();
84 if(
const auto*CE = dyn_cast<CastExpr>(
E)) {
85 if(CE->getCastKind() != CK_IntegralCast)
91 if(
const auto*UO = dyn_cast<UnaryOperator>(
E)) {
92 if(UO->getOpcode() != UO_Minus)
97 returnisa<IntegerLiteral>(
E);
108 returnisa<EnumConstantDecl>(DR->getDecl()) ? DR :
nullptr;
117staticstd::tuple<const Expr *, BinaryOperatorKind, const Expr *>
124 if(Constant ==
nullptr) {
128 else if(Op == BO_GE)
130 else if(Op == BO_LT)
132 else if(Op == BO_LE)
135MaybeDecl = B->
getRHS();
139 returnstd::make_tuple(MaybeDecl, Op, Constant);
151 if(isa<DeclRefExpr>(E1) != isa<DeclRefExpr>(E2))
155 if(!isa<DeclRefExpr>(E1))
160assert(isa<DeclRefExpr>(E1) && isa<DeclRefExpr>(E2));
161 auto*Decl1 = cast<DeclRefExpr>(E1)->getDecl();
162 auto*Decl2 = cast<DeclRefExpr>(E2)->getDecl();
164assert(isa<EnumConstantDecl>(Decl1) && isa<EnumConstantDecl>(Decl2));
168assert(isa<EnumDecl>(DC1) && isa<EnumDecl>(DC2));
190 enum Kind{ NotAlwaysAdd = 0, AlwaysAdd = 1 };
192AddStmtChoice(Kind a_kind = NotAlwaysAdd) :
kind(a_kind) {}
194 boolalwaysAdd(CFGBuilder &builder,
199AddStmtChoice withAlwaysAdd(
boolalwaysAdd)
const{
200 returnAddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd);
234 classconst_iterator {
235 constLocalScope*
Scope=
nullptr;
239 unsignedVarIter = 0;
245const_iterator() =
default;
249const_iterator(
constLocalScope& S,
unsignedI)
250:
Scope(&S), VarIter(I) {
253 if(VarIter == 0 &&
Scope)
254*
this=
Scope->Prev;
257 VarDecl*
const* operator->()
const{
258assert(
Scope&&
"Dereferencing invalid iterator is not allowed");
259assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
260 return&
Scope->Vars[VarIter - 1];
263 const VarDecl*getFirstVarInScope()
const{
264assert(
Scope&&
"Dereferencing invalid iterator is not allowed");
265assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
266 return Scope->Vars[0];
270 return*this->operator->();
273const_iterator &operator++() {
277assert(VarIter != 0 &&
"Iterator has invalid value of VarIter member");
280*
this=
Scope->Prev;
283const_iterator operator++(
int) {
284const_iterator
P= *
this;
289 bool operator==(
constconst_iterator &rhs)
const{
290 return Scope== rhs.
Scope&& VarIter == rhs.VarIter;
292 bool operator!=(
constconst_iterator &rhs)
const{
293 return!(*
this== rhs);
296 explicit operator bool()
const{
297 return*
this!= const_iterator();
301const_iterator shared_parent(const_iterator L);
302 boolpointsToFirstDeclaredVar() {
returnVarIter == 1; }
303 boolinSameLocalScope(const_iterator rhs) {
return Scope== rhs.
Scope; }
310AutomaticVarsTy Vars;
319: ctx(
std::move(ctx)), Vars(this->ctx, 4), Prev(
P) {}
322const_iterator begin()
const{
returnconst_iterator(*
this, Vars.size()); }
325Vars.push_back(VD, ctx);
334intLocalScope::const_iterator::distance(LocalScope::const_iterator L) {
336const_iterator F = *
this;
337 while(F.Scope != L.Scope) {
338assert(F != const_iterator() &&
339 "L iterator is not reachable from F iterator.");
343 D+= F.VarIter - L.VarIter;
351LocalScope::const_iterator
352LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) {
355 if((*
this== const_iterator()) || (L == const_iterator())) {
356 returnconst_iterator();
359const_iterator F = *
this;
360 if(F.inSameLocalScope(L)) {
362F.VarIter = std::min(F.VarIter, L.VarIter);
366llvm::SmallDenseMap<const LocalScope *, unsigned, 4> ScopesOfL;
368ScopesOfL.try_emplace(L.Scope, L.VarIter);
369 if(L == const_iterator())
375 if(
autoLIt = ScopesOfL.find(F.Scope); LIt != ScopesOfL.end()) {
377F.VarIter = std::min(F.VarIter, LIt->getSecond());
380assert(F != const_iterator() &&
381 "L iterator is not reachable from F iterator.");
391structBlockScopePosPair {
393LocalScope::const_iterator scopePosition;
395BlockScopePosPair() =
default;
396BlockScopePosPair(
CFGBlock*
b, LocalScope::const_iterator scopePos)
397: block(
b), scopePosition(scopePos) {}
408TryResult() =
default;
409TryResult(
bool b) :
X(
b? 1 : 0) {}
411 boolisTrue()
const{
return X== 1; }
412 boolisFalse()
const{
return X== 0; }
413 boolisKnown()
const{
return X>= 0; }
424 if(!R1.isKnown() || !R2.isKnown())
426 returnTryResult(R1.isTrue() && R2.isTrue());
431classreverse_children {
436reverse_children(
Stmt*S);
440iterator begin()
const{
returnchildren.rbegin(); }
441iterator end()
const{
returnchildren.rend(); }
446reverse_children::reverse_children(
Stmt*S) {
447 if(
CallExpr*CE = dyn_cast<CallExpr>(S)) {
448children = CE->getRawSubExprs();
451 switch(S->getStmtClass()) {
453 caseStmt::InitListExprClass: {
464llvm::append_range(childrenBuf, S->children());
467children = childrenBuf;
486 usingJumpTarget = BlockScopePosPair;
487 usingJumpSource = BlockScopePosPair;
490std::unique_ptr<CFG> cfg;
498JumpTarget ContinueJumpTarget;
499JumpTarget BreakJumpTarget;
500JumpTarget SEHLeaveJumpTarget;
501 CFGBlock*SwitchTerminatedBlock =
nullptr;
502 CFGBlock*DefaultCaseBlock =
nullptr;
508 CFGBlock*TryTerminatedBlock =
nullptr;
511LocalScope::const_iterator ScopePos;
514 usingLabelMapTy = llvm::DenseMap<LabelDecl *, JumpTarget>;
519 usingBackpatchBlocksTy = std::vector<JumpSource>;
520BackpatchBlocksTy BackpatchBlocks;
524LabelSetTy AddressTakenLabels;
529llvm::DenseMap<Expr *, const ConstructionContextLayer *>
530ConstructionContextMap;
532 boolbadCFG =
false;
536 boolswitchExclusivelyCovered =
false;
539CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry =
nullptr;
540 const Stmt*lastLookup =
nullptr;
544 usingCachedBoolEvalsTy = llvm::DenseMap<Expr *, TryResult>;
545CachedBoolEvalsTy CachedBoolEvals;
550: Context(astContext), cfg(new
CFG()), BuildOpts(buildOpts) {}
553std::unique_ptr<CFG> buildCFG(
const Decl*
D,
Stmt*Statement);
555 boolalwaysAdd(
const Stmt*
stmt);
590AddStmtChoice asc,
boolExternallyDestructed);
602std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(
BinaryOperator*B,
632 CFGBlock*Visit(
Stmt*S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd,
633 boolExternallyDestructed =
false);
642 if(ScopePos && (VD == ScopePos.getFirstVarInScope()))
643appendScopeBegin(B, VD, S);
674 structTempDtorContext {
675TempDtorContext() =
default;
676TempDtorContext(TryResult KnownExecuted)
677: IsConditional(
true), KnownExecuted(KnownExecuted) {}
685 boolneedsTempDtorBranch()
const{
686 returnIsConditional && !TerminatorExpr;
696 const boolIsConditional =
false;
697 constTryResult KnownExecuted =
true;
704 CFGBlock*VisitForTemporaryDtors(
Stmt*
E,
boolExternallyDestructed,
705TempDtorContext &Context);
706 CFGBlock*VisitChildrenForTemporaryDtors(
Stmt*
E,
boolExternallyDestructed,
707TempDtorContext &Context);
709 boolExternallyDestructed,
710TempDtorContext &Context);
711 CFGBlock*VisitCXXBindTemporaryExprForTemporaryDtors(
713 CFGBlock*VisitConditionalOperatorForTemporaryDtors(
715TempDtorContext &Context);
716 voidInsertTempDtorDecisionBlock(
constTempDtorContext &Context,
741 template<
typenameCallLikeExpr,
742 typename= std::enable_if_t<
743std::is_base_of_v<CallExpr, CallLikeExpr> ||
744std::is_base_of_v<CXXConstructExpr, CallLikeExpr> ||
745std::is_base_of_v<ObjCMessageExpr, CallLikeExpr>>>
746 voidfindConstructionContextsForArguments(CallLikeExpr *
E) {
747 for(
unsignedi = 0, e =
E->getNumArgs(); i != e; ++i) {
748 Expr*Arg =
E->getArg(i);
750findConstructionContexts(
760 voidcleanupConstructionContext(
Expr*
E);
762 voidautoCreateBlock() {
if(!Block)
Block= createBlock(); }
764 CFGBlock*createBlock(
booladd_successor =
true);
768 returnVisit(S, AddStmtChoice::AlwaysAdd);
772 voidaddLoopExit(
const Stmt*LoopStmt);
773 voidaddAutomaticObjHandling(LocalScope::const_iterator B,
774LocalScope::const_iterator
E,
Stmt*S);
775 voidaddAutomaticObjDestruction(LocalScope::const_iterator B,
776LocalScope::const_iterator
E,
Stmt*S);
777 voidaddScopeExitHandling(LocalScope::const_iterator B,
778LocalScope::const_iterator
E,
Stmt*S);
780 voidaddScopeChangesHandling(LocalScope::const_iterator SrcPos,
781LocalScope::const_iterator DstPos,
783 CFGBlock*createScopeChangesHandlingBlock(LocalScope::const_iterator SrcPos,
785LocalScope::const_iterator DstPost,
789LocalScope* createOrReuseLocalScope(LocalScope*
Scope);
791 voidaddLocalScopeForStmt(
Stmt*S);
792LocalScope* addLocalScopeForDeclStmt(
DeclStmt*DS,
793LocalScope*
Scope=
nullptr);
794LocalScope* addLocalScopeForVarDecl(
VarDecl*VD, LocalScope*
Scope=
nullptr);
796 voidaddLocalScopeAndDtors(
Stmt*S);
806cleanupConstructionContext(
E);
814 if(alwaysAdd(S) && cachedEntry)
815cachedEntry->second = B;
818assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S);
819B->
appendStmt(
const_cast<Stmt*
>(S), cfg->getBumpVectorContext());
824 if(
C&&
C->isNoReturn())
825 Block= createNoReturnBlock();
830retrieveAndCleanupConstructionContext(CE)) {
840 if(alwaysAdd(CE) && cachedEntry)
841cachedEntry->second = B;
844retrieveAndCleanupConstructionContext(CE)) {
850B->
appendStmt(CE, cfg->getBumpVectorContext());
870 if(alwaysAdd(ME) && cachedEntry)
871cachedEntry->second = B;
874retrieveAndCleanupConstructionContext(ME)) {
880cfg->getBumpVectorContext());
899 voidappendLoopExit(
CFGBlock*B,
const Stmt*LoopStmt) {
909cfg->getBumpVectorContext());
916cfg->getBumpVectorContext());
932TryResult checkIncorrectRelationalOperator(
const BinaryOperator*B) {
936 const IntegerLiteral*IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
937 const Expr*BoolExpr = RHSExpr;
938 boolIntFirst =
true;
940IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
948llvm::APInt IntValue = IntLiteral->
getValue();
949 if((IntValue == 1) || (IntValue == 0))
953!IntValue.isNegative();
956 if(Bok == BO_GT || Bok == BO_GE) {
959 returnTryResult(IntFirst == IntLarger);
963 returnTryResult(IntFirst != IntLarger);
971TryResult checkIncorrectEqualityOperator(
const BinaryOperator*B) {
975std::optional<llvm::APInt> IntLiteral1 =
976getIntegerLiteralSubexpressionValue(LHSExpr);
977 const Expr*BoolExpr = RHSExpr;
980IntLiteral1 = getIntegerLiteralSubexpressionValue(RHSExpr);
988 if(BitOp && (BitOp->
getOpcode() == BO_And ||
993std::optional<llvm::APInt> IntLiteral2 =
994getIntegerLiteralSubexpressionValue(LHSExpr2);
997IntLiteral2 = getIntegerLiteralSubexpressionValue(RHSExpr2);
1003(*IntLiteral2 & *IntLiteral1) != *IntLiteral1) ||
1005(*IntLiteral2 | *IntLiteral1) != *IntLiteral1)) {
1009 returnTryResult(B->
getOpcode() != BO_EQ);
1012 if((*IntLiteral1 == 1) || (*IntLiteral1 == 0)) {
1015 returnTryResult(B->
getOpcode() != BO_EQ);
1027std::optional<llvm::APInt>
1028getIntegerLiteralSubexpressionValue(
const Expr*
E) {
1031 if(
const auto*UnOp = dyn_cast<UnaryOperator>(
E->
IgnoreParens())) {
1036 if(
const auto*IntLiteral = dyn_cast<IntegerLiteral>(SubExpr)) {
1041 switch(UnOp->getOpcode()) {
1051assert(
false&&
"Unexpected unary operator!");
1052 returnstd::nullopt;
1055}
else if(
const auto*IntLiteral =
1059 returnstd::nullopt;
1063 constllvm::APSInt &Value1,
1064 constllvm::APSInt &Value2) {
1065assert(Value1.isSigned() == Value2.isSigned());
1070 returnTryResult(Value1 == Value2);
1072 returnTryResult(Value1 != Value2);
1074 returnTryResult(Value1 < Value2);
1076 returnTryResult(Value1 <= Value2);
1078 returnTryResult(Value1 > Value2);
1080 returnTryResult(Value1 >= Value2);
1091TryResult checkIncorrectLogicOperator(
const BinaryOperator*B) {
1096 autoCheckLogicalOpWithNegatedVariable = [
this, B](
const Expr*E1,
1098 if(
const auto*Negate = dyn_cast<UnaryOperator>(E1)) {
1099 if(Negate->getOpcode() == UO_LNot &&
1101 boolAlwaysTrue = B->
getOpcode() == BO_LOr;
1104 returnTryResult(AlwaysTrue);
1110TryResult Result = CheckLogicalOpWithNegatedVariable(LHSExpr, RHSExpr);
1111 if(Result.isKnown())
1113Result = CheckLogicalOpWithNegatedVariable(RHSExpr, LHSExpr);
1114 if(Result.isKnown())
1117 const auto*LHS = dyn_cast<BinaryOperator>(LHSExpr);
1118 const auto*RHS = dyn_cast<BinaryOperator>(RHSExpr);
1122 if(!LHS->isComparisonOp() || !RHS->isComparisonOp())
1125 const Expr*DeclExpr1;
1126 const Expr*NumExpr1;
1130 if(!DeclExpr1 || !NumExpr1)
1133 const Expr*DeclExpr2;
1134 const Expr*NumExpr2;
1138 if(!DeclExpr2 || !NumExpr2)
1155llvm::APSInt L1 = L1Result.
Val.
getInt();
1156llvm::APSInt L2 = L2Result.
Val.
getInt();
1159 if(L1.isSigned() != L2.isSigned() || L1.getBitWidth() != L2.getBitWidth())
1164 constllvm::APSInt Values[] = {
1166llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
1170((L1 < L2) ? L1 : L2) + llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1),
1175llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
1184 boolAlwaysTrue =
true, AlwaysFalse =
true;
1187 boolLHSAlwaysTrue =
true, LHSAlwaysFalse =
true;
1188 boolRHSAlwaysTrue =
true, RHSAlwaysFalse =
true;
1189 for(
constllvm::APSInt &
Value: Values) {
1190TryResult Res1, Res2;
1191Res1 = analyzeLogicOperatorCondition(BO1,
Value, L1);
1192Res2 = analyzeLogicOperatorCondition(BO2,
Value, L2);
1194 if(!Res1.isKnown() || !Res2.isKnown())
1198AlwaysTrue &= (Res1.isTrue() && Res2.isTrue());
1199AlwaysFalse &= !(Res1.isTrue() && Res2.isTrue());
1201AlwaysTrue &= (Res1.isTrue() || Res2.isTrue());
1202AlwaysFalse &= !(Res1.isTrue() || Res2.isTrue());
1205LHSAlwaysTrue &= Res1.isTrue();
1206LHSAlwaysFalse &= Res1.isFalse();
1207RHSAlwaysTrue &= Res2.isTrue();
1208RHSAlwaysFalse &= Res2.isFalse();
1211 if(AlwaysTrue || AlwaysFalse) {
1212 if(!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
1213!RHSAlwaysFalse && BuildOpts.
Observer)
1215 returnTryResult(AlwaysTrue);
1221TryResult checkIncorrectBitwiseOrOperator(
const BinaryOperator*B) {
1222 const Expr*LHSConstant =
1224 const Expr*RHSConstant =
1227 if((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant))
1230 const Expr*Constant = LHSConstant ? LHSConstant : RHSConstant;
1236 if(Result.Val.getInt() == 0)
1242 returnTryResult(
true);
1249 return!S->isTypeDependent() &&
1250!S->isValueDependent() &&
1251S->EvaluateAsRValue(outResult, *Context);
1256TryResult tryEvaluateBool(
Expr*S) {
1258S->isTypeDependent() || S->isValueDependent())
1262 if(Bop->isLogicalOp() || Bop->isEqualityOp()) {
1264CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S);
1265 if(I != CachedBoolEvals.end())
1269TryResult Result = evaluateAsBooleanConditionNoCache(S);
1270CachedBoolEvals[S] = Result;
1274 switch(Bop->getOpcode()) {
1283 if(Bop->getLHS()->EvaluateAsInt(LHSResult, *Context)) {
1284llvm::APSInt IntVal = LHSResult.
Val.
getInt();
1285 if(!IntVal.getBoolValue()) {
1286 returnTryResult(
false);
1290 if(Bop->getRHS()->EvaluateAsInt(RHSResult, *Context)) {
1291llvm::APSInt IntVal = RHSResult.
Val.
getInt();
1292 if(!IntVal.getBoolValue()) {
1293 returnTryResult(
false);
1302 returnevaluateAsBooleanConditionNoCache(S);
1306TryResult evaluateAsBooleanConditionNoCache(
Expr*
E) {
1308 if(Bop->isLogicalOp()) {
1309TryResult LHS = tryEvaluateBool(Bop->getLHS());
1310 if(LHS.isKnown()) {
1313 if(LHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1314 returnLHS.isTrue();
1316TryResult RHS = tryEvaluateBool(Bop->getRHS());
1317 if(RHS.isKnown()) {
1318 if(Bop->getOpcode() == BO_LOr)
1319 returnLHS.isTrue() || RHS.isTrue();
1321 returnLHS.isTrue() && RHS.isTrue();
1324TryResult RHS = tryEvaluateBool(Bop->getRHS());
1325 if(RHS.isKnown()) {
1328 if(RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
1329 returnRHS.isTrue();
1331TryResult BopRes = checkIncorrectLogicOperator(Bop);
1332 if(BopRes.isKnown())
1333 returnBopRes.isTrue();
1338}
else if(Bop->isEqualityOp()) {
1339TryResult BopRes = checkIncorrectEqualityOperator(Bop);
1340 if(BopRes.isKnown())
1341 returnBopRes.isTrue();
1342}
else if(Bop->isRelationalOp()) {
1343TryResult BopRes = checkIncorrectRelationalOperator(Bop);
1344 if(BopRes.isKnown())
1345 returnBopRes.isTrue();
1346}
else if(Bop->getOpcode() == BO_Or) {
1347TryResult BopRes = checkIncorrectBitwiseOrOperator(Bop);
1348 if(BopRes.isKnown())
1349 returnBopRes.isTrue();
1360 boolhasTrivialDestructor(
const VarDecl*VD)
const;
1361 boolneedsAutomaticDestruction(
const VarDecl*VD)
const;
1372 while(
const auto*
E= dyn_cast<ArrayInitLoopExpr>(AILEInit))
1373AILEInit =
E->getSubExpr();
1378inline boolAddStmtChoice::alwaysAdd(CFGBuilder &builder,
1380 returnbuilder.alwaysAdd(
stmt) || kind == AlwaysAdd;
1383boolCFGBuilder::alwaysAdd(
const Stmt*
stmt) {
1389 if(lastLookup ==
stmt) {
1391assert(cachedEntry->first ==
stmt);
1404assert(!cachedEntry);
1408CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(
stmt);
1409 if(itr == fb->end()) {
1410cachedEntry =
nullptr;
1414cachedEntry = &*itr;
1421 while(
const ArrayType*vt = dyn_cast<ArrayType>(t)) {
1423 if(vat->getSizeExpr())
1426t = vt->getElementType().getTypePtr();
1432voidCFGBuilder::consumeConstructionContext(
1434assert((isa<CXXConstructExpr>(
E) || isa<CallExpr>(
E) ||
1435isa<ObjCMessageExpr>(
E)) &&
"Expression cannot construct an object!");
1437ConstructionContextMap.lookup(
E)) {
1438(void)PreviouslyStoredLayer;
1441assert(PreviouslyStoredLayer->isStrictlyMoreSpecificThan(Layer) &&
1442 "Already within a different construction context!");
1444ConstructionContextMap[
E] = Layer;
1448voidCFGBuilder::findConstructionContexts(
1461 switch(Child->getStmtClass()) {
1462 caseStmt::CXXConstructExprClass:
1463 caseStmt::CXXTemporaryObjectExprClass: {
1465 auto*CE = cast<CXXConstructExpr>(Child);
1467findConstructionContexts(withExtraLayer(CE), CE->
getArg(0));
1470consumeConstructionContext(Layer, CE);
1476 caseStmt::CallExprClass:
1477 caseStmt::CXXMemberCallExprClass:
1478 caseStmt::CXXOperatorCallExprClass:
1479 caseStmt::UserDefinedLiteralClass:
1480 caseStmt::ObjCMessageExprClass: {
1481 auto*
E= cast<Expr>(Child);
1483consumeConstructionContext(Layer,
E);
1486 caseStmt::ExprWithCleanupsClass: {
1487 auto*Cleanups = cast<ExprWithCleanups>(Child);
1488findConstructionContexts(Layer, Cleanups->getSubExpr());
1491 caseStmt::CXXFunctionalCastExprClass: {
1492 auto*
Cast= cast<CXXFunctionalCastExpr>(Child);
1493findConstructionContexts(Layer,
Cast->getSubExpr());
1496 caseStmt::ImplicitCastExprClass: {
1497 auto*
Cast= cast<ImplicitCastExpr>(Child);
1499 switch(
Cast->getCastKind()) {
1501 caseCK_ConstructorConversion:
1502findConstructionContexts(Layer,
Cast->getSubExpr());
1509 caseStmt::CXXBindTemporaryExprClass: {
1510 auto*BTE = cast<CXXBindTemporaryExpr>(Child);
1511findConstructionContexts(withExtraLayer(BTE), BTE->getSubExpr());
1514 caseStmt::MaterializeTemporaryExprClass: {
1521 auto*MTE = cast<MaterializeTemporaryExpr>(Child);
1522findConstructionContexts(withExtraLayer(MTE), MTE->getSubExpr());
1526 caseStmt::ConditionalOperatorClass: {
1527 auto*CO = cast<ConditionalOperator>(Child);
1534assert(!CO->getType()->getAsCXXRecordDecl() || CO->isGLValue() ||
1538findConstructionContexts(Layer, CO->getLHS());
1539findConstructionContexts(Layer, CO->getRHS());
1542 caseStmt::InitListExprClass: {
1543 auto*ILE = cast<InitListExpr>(Child);
1544 if(ILE->isTransparent()) {
1545findConstructionContexts(Layer, ILE->getInit(0));
1551 caseStmt::ParenExprClass: {
1554 auto*PE = cast<ParenExpr>(Child);
1555findConstructionContexts(Layer, PE->getSubExpr());
1563voidCFGBuilder::cleanupConstructionContext(
Expr*
E) {
1565 "We should not be managing construction contexts!");
1566assert(ConstructionContextMap.count(
E) &&
1567 "Cannot exit construction context without the context!");
1568ConstructionContextMap.erase(
E);
1576std::unique_ptr<CFG> CFGBuilder::buildCFG(
const Decl*
D,
Stmt*Statement) {
1584Succ = createBlock();
1585assert(Succ == &cfg->getExit());
1590addImplicitDtorsForDestructor(DD);
1610 if(
const auto*CD = dyn_cast_or_null<CXXConstructorDecl>(
D)) {
1612 for(
auto*I : llvm::reverse(CD->inits())) {
1614I->isBaseInitializer() && I->isBaseVirtual()) {
1618VBaseSucc = Succ = B ? B : &cfg->getExit();
1619 Block= createBlock();
1621B = addInitializer(I);
1631addSuccessor(B,
Block,
true);
1640 for(BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
1641 E= BackpatchBlocks.end(); I !=
E; ++I ) {
1645LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
1648 if(LI == LabelMap.end())
1650JumpTarget JT = LI->second;
1652 CFGBlock*SuccBlk = createScopeChangesHandlingBlock(
1653I->scopePosition, B, JT.scopePosition, JT.block);
1654addSuccessor(B, SuccBlk);
1655}
else if(
auto*G = dyn_cast<GCCAsmStmt>(B->
getTerminator())) {
1656 CFGBlock*Successor = (I+1)->block;
1657 for(
auto*L : G->labels()) {
1658LabelMapTy::iterator LI = LabelMap.find(L->getLabel());
1661 if(LI == LabelMap.end())
1663JumpTarget JT = LI->second;
1665 if(JT.block == Successor)
1667addSuccessor(B, JT.block);
1674 if(
CFGBlock*B = cfg->getIndirectGotoBlock())
1675 for(LabelSetTy::iterator I = AddressTakenLabels.begin(),
1676 E= AddressTakenLabels.end(); I !=
E; ++I ) {
1678LabelMapTy::iterator LI = LabelMap.find(*I);
1682 if(LI == LabelMap.end())
continue;
1684addSuccessor(B, LI->second.block);
1688cfg->setEntry(createBlock());
1691assert(ConstructionContextMap.empty() &&
1692 "Not all construction contexts were cleaned up!");
1694 returnstd::move(cfg);
1699CFGBlock*CFGBuilder::createBlock(
booladd_successor) {
1701 if(add_successor && Succ)
1702addSuccessor(B, Succ);
1709CFGBlock*CFGBuilder::createNoReturnBlock() {
1710 CFGBlock*B = createBlock(
false);
1712addSuccessor(B, &cfg->getExit(), Succ);
1721 boolHasTemporaries =
false;
1727HasTemporaries = isa<ExprWithCleanups>(
Init);
1731TempDtorContext Context;
1732VisitForTemporaryDtors(cast<ExprWithCleanups>(
Init)->getSubExpr(),
1738appendInitializer(
Block, I);
1744dyn_cast<ArrayInitLoopExpr>(
Init));
1746findConstructionContexts(
1748AILEInit ? AILEInit :
Init);
1750 if(HasTemporaries) {
1753 returnVisit(cast<ExprWithCleanups>(
Init)->getSubExpr());
1768 returnVisit(
Init);
1777 bool*FoundMTE =
nullptr) {
1784 Init= EWC->getSubExpr();
1790= dyn_cast<MaterializeTemporaryExpr>(
Init)) {
1791 Init= MTE->getSubExpr();
1798 const Expr*SkippedInit =
Init->skipRValueSubobjectAdjustments();
1799 if(SkippedInit !=
Init) {
1807 return Init->getType();
1812voidCFGBuilder::addLoopExit(
const Stmt*LoopStmt){
1816appendLoopExit(
Block, LoopStmt);
1824voidCFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
1825LocalScope::const_iterator
E,
1835 if(B.inSameLocalScope(
E)) {
1836addAutomaticObjDestruction(B,
E, S);
1842LocalScopeEndMarkers.push_back(B);
1843 for(LocalScope::const_iterator I = B; I !=
E; ++I) {
1844 if(!I.inSameLocalScope(LocalScopeEndMarkers.back()))
1845LocalScopeEndMarkers.push_back(I);
1847LocalScopeEndMarkers.push_back(
E);
1851std::reverse(LocalScopeEndMarkers.begin(), LocalScopeEndMarkers.end());
1853llvm::zip(LocalScopeEndMarkers, llvm::drop_begin(LocalScopeEndMarkers));
1854 for(
auto[
E, B] : Pairwise) {
1855 if(!B.inSameLocalScope(
E))
1856addScopeExitHandling(B,
E, S);
1857addAutomaticObjDestruction(B,
E, S);
1864voidCFGBuilder::addAutomaticObjDestruction(LocalScope::const_iterator B,
1865LocalScope::const_iterator
E,
1874DeclsNeedDestruction.reserve(B.distance(
E));
1876 for(
VarDecl*
D: llvm::make_range(B,
E))
1877 if(needsAutomaticDestruction(
D))
1878DeclsNeedDestruction.push_back(
D);
1880 for(
VarDecl*VD : llvm::reverse(DeclsNeedDestruction)) {
1893 Block= createNoReturnBlock();
1902appendLifetimeEnds(
Block, VD, S);
1904appendAutomaticObjDtor(
Block, VD, S);
1905 if(VD->
hasAttr<CleanupAttr>())
1906appendCleanupFunction(
Block, VD);
1915voidCFGBuilder::addScopeExitHandling(LocalScope::const_iterator B,
1916LocalScope::const_iterator
E,
Stmt*S) {
1917assert(!B.inSameLocalScope(
E));
1923appendScopeEnd(
Block, B.getFirstVarInScope(), S);
1931DeclsTrivial.reserve(B.distance(
E));
1936 for(
VarDecl*
D: llvm::make_range(B,
E))
1937 if(!needsAutomaticDestruction(
D))
1938DeclsTrivial.push_back(
D);
1940 if(DeclsTrivial.empty())
1944 for(
VarDecl*VD : llvm::reverse(DeclsTrivial))
1945appendLifetimeEnds(
Block, VD, S);
1953voidCFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos,
1954LocalScope::const_iterator DstPos,
1956assert(
Block&&
"Source block should be always crated");
1962 if(SrcPos == DstPos)
1967LocalScope::const_iterator BasePos = SrcPos.shared_parent(DstPos);
1970 if(BuildOpts.
AddScopes&& !DstPos.inSameLocalScope(BasePos)) {
1971 for(LocalScope::const_iterator I = DstPos; I != BasePos; ++I)
1972 if(I.pointsToFirstDeclaredVar())
1973appendScopeBegin(
Block, *I, S);
1978addAutomaticObjHandling(SrcPos, BasePos, S);
1986CFGBlock*CFGBuilder::createScopeChangesHandlingBlock(
1987LocalScope::const_iterator SrcPos,
CFGBlock*SrcBlk,
1988LocalScope::const_iterator DstPos,
CFGBlock*DstBlk) {
1989 if(SrcPos == DstPos)
1993(!BuildOpts.
AddScopes|| SrcPos.inSameLocalScope(DstPos)))
2001 Block= createBlock(
false);
2004addSuccessor(
Block, DstBlk);
2009assert(
Block&&
"There should be at least one scope changing Block");
2017 "Can be called only when dtors should be added");
2021 for(
const auto&VI : RD->
vbases()) {
2025 const CXXRecordDecl*CD = VI.getType()->getAsCXXRecordDecl();
2028appendBaseDtor(
Block, &VI);
2033 for(
const auto&BI : RD->
bases()) {
2034 if(!BI.isVirtual()) {
2035 const CXXRecordDecl*CD = BI.getType()->getAsCXXRecordDecl();
2038appendBaseDtor(
Block, &BI);
2044 for(
auto*FI : RD->
fields()) {
2049 if(AT->isZeroSize())
2051QT = AT->getElementType();
2057appendMemberDtor(
Block, FI);
2064LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope*
Scope) {
2067llvm::BumpPtrAllocator &alloc = cfg->getAllocator();
2073voidCFGBuilder::addLocalScopeForStmt(
Stmt*S) {
2078LocalScope *
Scope=
nullptr;
2082 for(
auto*BI : CS->body()) {
2084 if(
DeclStmt*DS = dyn_cast<DeclStmt>(SI))
2085 Scope= addLocalScopeForDeclStmt(DS,
Scope);
2092 if(
DeclStmt*DS = dyn_cast<DeclStmt>(S->stripLabelLikeStatements()))
2093addLocalScopeForDeclStmt(DS);
2098LocalScope* CFGBuilder::addLocalScopeForDeclStmt(
DeclStmt*DS,
2099LocalScope*
Scope) {
2104 for(
auto*DI : DS->
decls())
2105 if(
VarDecl*VD = dyn_cast<VarDecl>(DI))
2110boolCFGBuilder::needsAutomaticDestruction(
const VarDecl*VD)
const{
2111 return!hasTrivialDestructor(VD) || VD->
hasAttr<CleanupAttr>();
2114boolCFGBuilder::hasTrivialDestructor(
const VarDecl*VD)
const{
2135 boolFoundMTE =
false;
2143 if(AT->isZeroSize())
2145QT = AT->getElementType();
2157LocalScope* CFGBuilder::addLocalScopeForVarDecl(
VarDecl*VD,
2158LocalScope*
Scope) {
2168!needsAutomaticDestruction(VD)) {
2176ScopePos =
Scope->begin();
2182voidCFGBuilder::addLocalScopeAndDtors(
Stmt*S) {
2183LocalScope::const_iterator scopeBeginPos = ScopePos;
2184addLocalScopeForStmt(S);
2185addAutomaticObjHandling(ScopePos, scopeBeginPos, S);
2191CFGBlock*CFGBuilder::Visit(
Stmt* S, AddStmtChoice asc,
2192 boolExternallyDestructed) {
2198 if(
Expr*
E= dyn_cast<Expr>(S))
2202 if(
auto*
D= dyn_cast<OMPExecutableDirective>(S))
2203 returnVisitOMPExecutableDirective(
D, asc);
2205 switch(S->getStmtClass()) {
2207 returnVisitStmt(S, asc);
2209 caseStmt::ImplicitValueInitExprClass:
2212 returnVisitStmt(S, asc);
2214 caseStmt::InitListExprClass:
2215 returnVisitInitListExpr(cast<InitListExpr>(S), asc);
2217 caseStmt::AttributedStmtClass:
2218 returnVisitAttributedStmt(cast<AttributedStmt>(S), asc);
2220 caseStmt::AddrLabelExprClass:
2221 returnVisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
2223 caseStmt::BinaryConditionalOperatorClass:
2224 returnVisitConditionalOperator(cast<BinaryConditionalOperator>(S), asc);
2226 caseStmt::BinaryOperatorClass:
2227 returnVisitBinaryOperator(cast<BinaryOperator>(S), asc);
2229 caseStmt::BlockExprClass:
2230 returnVisitBlockExpr(cast<BlockExpr>(S), asc);
2232 caseStmt::BreakStmtClass:
2233 returnVisitBreakStmt(cast<BreakStmt>(S));
2235 caseStmt::CallExprClass:
2236 caseStmt::CXXOperatorCallExprClass:
2237 caseStmt::CXXMemberCallExprClass:
2238 caseStmt::UserDefinedLiteralClass:
2239 returnVisitCallExpr(cast<CallExpr>(S), asc);
2241 caseStmt::CaseStmtClass:
2242 returnVisitCaseStmt(cast<CaseStmt>(S));
2244 caseStmt::ChooseExprClass:
2245 returnVisitChooseExpr(cast<ChooseExpr>(S), asc);
2247 caseStmt::CompoundStmtClass:
2248 returnVisitCompoundStmt(cast<CompoundStmt>(S), ExternallyDestructed);
2250 caseStmt::ConditionalOperatorClass:
2251 returnVisitConditionalOperator(cast<ConditionalOperator>(S), asc);
2253 caseStmt::ContinueStmtClass:
2254 returnVisitContinueStmt(cast<ContinueStmt>(S));
2256 caseStmt::CXXCatchStmtClass:
2257 returnVisitCXXCatchStmt(cast<CXXCatchStmt>(S));
2259 caseStmt::ExprWithCleanupsClass:
2260 returnVisitExprWithCleanups(cast<ExprWithCleanups>(S),
2261asc, ExternallyDestructed);
2263 caseStmt::CXXDefaultArgExprClass:
2264 caseStmt::CXXDefaultInitExprClass:
2273 returnVisitStmt(S, asc);
2275 caseStmt::CXXBindTemporaryExprClass:
2276 returnVisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc);
2278 caseStmt::CXXConstructExprClass:
2279 returnVisitCXXConstructExpr(cast<CXXConstructExpr>(S), asc);
2281 caseStmt::CXXNewExprClass:
2282 returnVisitCXXNewExpr(cast<CXXNewExpr>(S), asc);
2284 caseStmt::CXXDeleteExprClass:
2285 returnVisitCXXDeleteExpr(cast<CXXDeleteExpr>(S), asc);
2287 caseStmt::CXXFunctionalCastExprClass:
2288 returnVisitCXXFunctionalCastExpr(cast<CXXFunctionalCastExpr>(S), asc);
2290 caseStmt::CXXTemporaryObjectExprClass:
2291 returnVisitCXXTemporaryObjectExpr(cast<CXXTemporaryObjectExpr>(S), asc);
2293 caseStmt::CXXThrowExprClass:
2294 returnVisitCXXThrowExpr(cast<CXXThrowExpr>(S));
2296 caseStmt::CXXTryStmtClass:
2297 returnVisitCXXTryStmt(cast<CXXTryStmt>(S));
2299 caseStmt::CXXTypeidExprClass:
2300 returnVisitCXXTypeidExpr(cast<CXXTypeidExpr>(S), asc);
2302 caseStmt::CXXForRangeStmtClass:
2303 returnVisitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
2305 caseStmt::DeclStmtClass:
2306 returnVisitDeclStmt(cast<DeclStmt>(S));
2308 caseStmt::DefaultStmtClass:
2309 returnVisitDefaultStmt(cast<DefaultStmt>(S));
2311 caseStmt::DoStmtClass:
2312 returnVisitDoStmt(cast<DoStmt>(S));
2314 caseStmt::ForStmtClass:
2315 returnVisitForStmt(cast<ForStmt>(S));
2317 caseStmt::GotoStmtClass:
2318 returnVisitGotoStmt(cast<GotoStmt>(S));
2320 caseStmt::GCCAsmStmtClass:
2321 returnVisitGCCAsmStmt(cast<GCCAsmStmt>(S), asc);
2323 caseStmt::IfStmtClass:
2324 returnVisitIfStmt(cast<IfStmt>(S));
2326 caseStmt::ImplicitCastExprClass:
2327 returnVisitImplicitCastExpr(cast<ImplicitCastExpr>(S), asc);
2329 caseStmt::ConstantExprClass:
2330 returnVisitConstantExpr(cast<ConstantExpr>(S), asc);
2332 caseStmt::IndirectGotoStmtClass:
2333 returnVisitIndirectGotoStmt(cast<IndirectGotoStmt>(S));
2335 caseStmt::LabelStmtClass:
2336 returnVisitLabelStmt(cast<LabelStmt>(S));
2338 caseStmt::LambdaExprClass:
2339 returnVisitLambdaExpr(cast<LambdaExpr>(S), asc);
2341 caseStmt::MaterializeTemporaryExprClass:
2342 returnVisitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(S),
2345 caseStmt::MemberExprClass:
2346 returnVisitMemberExpr(cast<MemberExpr>(S), asc);
2348 caseStmt::NullStmtClass:
2351 caseStmt::ObjCAtCatchStmtClass:
2352 returnVisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
2354 caseStmt::ObjCAutoreleasePoolStmtClass:
2355 returnVisitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(S));
2357 caseStmt::ObjCAtSynchronizedStmtClass:
2358 returnVisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S));
2360 caseStmt::ObjCAtThrowStmtClass:
2361 returnVisitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(S));
2363 caseStmt::ObjCAtTryStmtClass:
2364 returnVisitObjCAtTryStmt(cast<ObjCAtTryStmt>(S));
2366 caseStmt::ObjCForCollectionStmtClass:
2367 returnVisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
2369 caseStmt::ObjCMessageExprClass:
2370 returnVisitObjCMessageExpr(cast<ObjCMessageExpr>(S), asc);
2372 caseStmt::OpaqueValueExprClass:
2375 caseStmt::PseudoObjectExprClass:
2376 returnVisitPseudoObjectExpr(cast<PseudoObjectExpr>(S));
2378 caseStmt::ReturnStmtClass:
2379 caseStmt::CoreturnStmtClass:
2380 returnVisitReturnStmt(S);
2382 caseStmt::CoyieldExprClass:
2383 caseStmt::CoawaitExprClass:
2384 returnVisitCoroutineSuspendExpr(cast<CoroutineSuspendExpr>(S), asc);
2386 caseStmt::SEHExceptStmtClass:
2387 returnVisitSEHExceptStmt(cast<SEHExceptStmt>(S));
2389 caseStmt::SEHFinallyStmtClass:
2390 returnVisitSEHFinallyStmt(cast<SEHFinallyStmt>(S));
2392 caseStmt::SEHLeaveStmtClass:
2393 returnVisitSEHLeaveStmt(cast<SEHLeaveStmt>(S));
2395 caseStmt::SEHTryStmtClass:
2396 returnVisitSEHTryStmt(cast<SEHTryStmt>(S));
2398 caseStmt::UnaryExprOrTypeTraitExprClass:
2399 returnVisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
2402 caseStmt::StmtExprClass:
2403 returnVisitStmtExpr(cast<StmtExpr>(S), asc);
2405 caseStmt::SwitchStmtClass:
2406 returnVisitSwitchStmt(cast<SwitchStmt>(S));
2408 caseStmt::UnaryOperatorClass:
2409 returnVisitUnaryOperator(cast<UnaryOperator>(S), asc);
2411 caseStmt::WhileStmtClass:
2412 returnVisitWhileStmt(cast<WhileStmt>(S));
2414 caseStmt::ArrayInitLoopExprClass:
2415 returnVisitArrayInitLoopExpr(cast<ArrayInitLoopExpr>(S), asc);
2419CFGBlock*CFGBuilder::VisitStmt(
Stmt*S, AddStmtChoice asc) {
2420 if(asc.alwaysAdd(*
this, S)) {
2422appendStmt(
Block, S);
2425 returnVisitChildren(S);
2434reverse_children RChildren(S);
2435 for(
Stmt*Child : RChildren) {
2444 if(asc.alwaysAdd(*
this, ILE)) {
2446appendStmt(
Block, ILE);
2450reverse_children RChildren(ILE);
2451 for(
Stmt*Child : RChildren) {
2457 if(
auto*DIE = dyn_cast<CXXDefaultInitExpr>(Child))
2458 if(
Stmt*Child = DIE->getExpr())
2467AddStmtChoice asc) {
2468AddressTakenLabels.insert(A->
getLabel());
2470 if(asc.alwaysAdd(*
this, A)) {
2472appendStmt(
Block, A);
2479 boolisFallthrough = hasSpecificAttr<FallThroughAttr>(A->
getAttrs());
2480assert((!isFallthrough || isa<NullStmt>(A->
getSubStmt())) &&
2481 "expected fallthrough not to have children");
2482 returnisFallthrough;
2486AddStmtChoice asc) {
2497appendStmt(
Block, A);
2500 returnVisitChildren(A);
2504 if(asc.alwaysAdd(*
this,
U)) {
2509 if(
U->getOpcode() == UO_LNot)
2510tryEvaluateBool(
U->getSubExpr()->IgnoreParens());
2512 returnVisit(
U->getSubExpr(), AddStmtChoice());
2517appendStmt(ConfluenceBlock, B);
2522 returnVisitLogicalOperator(B,
nullptr, ConfluenceBlock,
2523ConfluenceBlock).first;
2526std::pair<CFGBlock*, CFGBlock*>
2539 if(B_RHS->isLogicalOp()) {
2540std::tie(RHSBlock, ExitBlock) =
2541VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
2549ExitBlock = RHSBlock = createBlock(
false);
2554TryResult KnownVal = tryEvaluateBool(RHS);
2555 if(!KnownVal.isKnown())
2556KnownVal = tryEvaluateBool(B);
2559assert(TrueBlock == FalseBlock);
2560addSuccessor(RHSBlock, TrueBlock);
2564addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
2565addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
2569RHSBlock = addStmt(RHS);
2574 returnstd::make_pair(
nullptr,
nullptr);
2580 if(B_LHS->isLogicalOp()) {
2582FalseBlock = RHSBlock;
2584TrueBlock = RHSBlock;
2589 returnVisitLogicalOperator(B_LHS, B, TrueBlock, FalseBlock);
2594 CFGBlock*LHSBlock = createBlock(
false);
2598 CFGBlock*EntryLHSBlock = addStmt(LHS);
2601 returnstd::make_pair(
nullptr,
nullptr);
2604TryResult KnownVal = tryEvaluateBool(LHS);
2608addSuccessor(LHSBlock, TrueBlock, !KnownVal.isFalse());
2609addSuccessor(LHSBlock, RHSBlock, !KnownVal.isTrue());
2612addSuccessor(LHSBlock, RHSBlock, !KnownVal.isFalse());
2613addSuccessor(LHSBlock, FalseBlock, !KnownVal.isTrue());
2616 returnstd::make_pair(EntryLHSBlock, ExitBlock);
2620AddStmtChoice asc) {
2623 returnVisitLogicalOperator(B);
2627appendStmt(
Block, B);
2629 returnaddStmt(B->
getLHS());
2633 if(asc.alwaysAdd(*
this, B)) {
2635appendStmt(
Block, B);
2638 returnVisit(B->
getRHS());
2641 if(asc.alwaysAdd(*
this, B)) {
2643appendStmt(
Block, B);
2654 return(LBlock ? LBlock : RBlock);
2657CFGBlock*CFGBuilder::VisitNoRecurse(
Expr*
E, AddStmtChoice asc) {
2658 if(asc.alwaysAdd(*
this,
E)) {
2672 Block= createBlock(
false);
2677 if(BreakJumpTarget.block) {
2678addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B);
2679addSuccessor(
Block, BreakJumpTarget.block);
2703 QualTypecalleeType =
C->getCallee()->getType();
2709 if(!boundType.
isNull()) calleeType = boundType;
2715 boolAddEHEdge =
false;
2725 boolOmitArguments =
false;
2732 if(!FD->isVariadic())
2733findConstructionContextsForArguments(
C);
2735 if(FD->isNoReturn() ||
C->isBuiltinAssumeFalse(*Context))
2737 if(FD->
hasAttr<NoThrowAttr>())
2739 if(FD->getBuiltinID() == Builtin::BI__builtin_object_size ||
2740FD->getBuiltinID() == Builtin::BI__builtin_dynamic_object_size)
2741OmitArguments =
true;
2744 if(!
CanThrow(
C->getCallee(), *Context))
2747 if(OmitArguments) {
2748assert(!NoReturn &&
"noreturn calls with unevaluated args not implemented");
2749assert(!AddEHEdge &&
"EH calls with unevaluated args not implemented");
2752 returnVisit(
C->getCallee());
2755 if(!NoReturn && !AddEHEdge) {
2759 returnVisitChildren(
C);
2769 Block= createNoReturnBlock();
2771 Block= createBlock();
2777 if(TryTerminatedBlock)
2778addSuccessor(
Block, TryTerminatedBlock);
2780addSuccessor(
Block, &cfg->getExit());
2783 returnVisitChildren(
C);
2787AddStmtChoice asc) {
2789appendStmt(ConfluenceBlock,
C);
2793AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2794Succ = ConfluenceBlock;
2796 CFGBlock*LHSBlock = Visit(
C->getLHS(), alwaysAdd);
2800Succ = ConfluenceBlock;
2802 CFGBlock*RHSBlock = Visit(
C->getRHS(), alwaysAdd);
2806 Block= createBlock(
false);
2808 constTryResult& KnownVal = tryEvaluateBool(
C->getCond());
2809addSuccessor(
Block, KnownVal.isFalse() ?
nullptr: LHSBlock);
2810addSuccessor(
Block, KnownVal.isTrue() ?
nullptr: RHSBlock);
2812 returnaddStmt(
C->getCond());
2816 boolExternallyDestructed) {
2817LocalScope::const_iterator scopeBeginPos = ScopePos;
2818addLocalScopeForStmt(
C);
2820 if(!
C->body_empty() && !isa<ReturnStmt>(*
C->body_rbegin())) {
2823addAutomaticObjHandling(ScopePos, scopeBeginPos,
C);
2828 for(
Stmt*S : llvm::reverse(
C->body())) {
2831 CFGBlock*newBlock = Visit(S, AddStmtChoice::AlwaysAdd,
2832ExternallyDestructed);
2835LastBlock = newBlock;
2840ExternallyDestructed =
false;
2847AddStmtChoice asc) {
2854appendStmt(ConfluenceBlock,
C);
2858AddStmtChoice alwaysAdd = asc.withAlwaysAdd(
true);
2864Succ = ConfluenceBlock;
2867 const Expr*trueExpr =
C->getTrueExpr();
2868 if(trueExpr != opaqueValue) {
2869LHSBlock = Visit(
C->getTrueExpr(), alwaysAdd);
2875LHSBlock = ConfluenceBlock;
2878Succ = ConfluenceBlock;
2879 CFGBlock*RHSBlock = Visit(
C->getFalseExpr(), alwaysAdd);
2885dyn_cast<BinaryOperator>(
C->getCond()->IgnoreParens()))
2886 if(Cond->isLogicalOp())
2887 returnVisitLogicalOperator(Cond,
C, LHSBlock, RHSBlock).first;
2890 Block= createBlock(
false);
2893 constTryResult& KnownVal = tryEvaluateBool(
C->getCond());
2894addSuccessor(
Block, LHSBlock, !KnownVal.isFalse());
2895addSuccessor(
Block, RHSBlock, !KnownVal.isTrue());
2897 Expr*condExpr =
C->getCond();
2902 if(condExpr != opaqueValue)
2910 returnaddStmt(condExpr);
2921 returnVisitDeclSubExpr(DS);
2935cfg->addSyntheticDeclStmt(DSNew, DS);
2938B = VisitDeclSubExpr(DSNew);
2947assert(DS->
isSingleDecl() &&
"Can handle single declarations only.");
2949 if(
const auto*TND = dyn_cast<TypedefNameDecl>(DS->
getSingleDecl())) {
2951 const Type*
T= TND->getUnderlyingType().getTypePtr();
2956appendStmt(
Block, DS);
2960VA =
FindVA(VA->getElementType().getTypePtr())) {
2961 if(
CFGBlock*NewBlock = addStmt(VA->getSizeExpr()))
2962LastBlock = NewBlock;
2975 boolHasTemporaries =
false;
2978 CFGBlock*blockAfterStaticInit =
nullptr;
2989blockAfterStaticInit = Succ;
2996HasTemporaries = isa<ExprWithCleanups>(
Init);
3000TempDtorContext Context;
3001VisitForTemporaryDtors(cast<ExprWithCleanups>(
Init)->getSubExpr(),
3008 if(
const auto*DD = dyn_cast<DecompositionDecl>(VD)) {
3009 for(
auto*BD : llvm::reverse(DD->bindings())) {
3010 if(
auto*VD = BD->getHoldingVar()) {
3014cfg->addSyntheticDeclStmt(DSNew, DS);
3015 Block= VisitDeclSubExpr(DSNew);
3021appendStmt(
Block, DS);
3025 const auto*AILE = dyn_cast_or_null<ArrayInitLoopExpr>(
Init);
3027findConstructionContexts(
3029AILE ? AILE->getSubExpr() :
Init);
3037 if(HasTemporaries) {
3042LastBlock = newBlock;
3046LastBlock = newBlock;
3054VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr())) {
3055 if(
CFGBlock*newBlock = addStmt(VA->getSizeExpr()))
3056LastBlock = newBlock;
3059maybeAddScopeBeginForVarDecl(
Block, VD, DS);
3062 if(ScopePos && VD == *ScopePos)
3066 if(blockAfterStaticInit) {
3068 Block= createBlock(
false);
3070addSuccessor(
Block, blockAfterStaticInit);
3071addSuccessor(
Block, B);
3092addLocalScopeForStmt(
Init);
3097addLocalScopeForVarDecl(VD);
3099addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I);
3121 if(!isa<CompoundStmt>(Else))
3122addLocalScopeAndDtors(Else);
3124ElseBlock = addStmt(Else);
3127ElseBlock = sv.get();
3144 if(!isa<CompoundStmt>(Then))
3145addLocalScopeAndDtors(Then);
3147ThenBlock = addStmt(Then);
3153ThenBlock = createBlock(
false);
3154addSuccessor(ThenBlock, sv.get());
3155}
else if(
Block) {
3174LastBlock = VisitLogicalOperator(Cond, I, ThenBlock, ElseBlock).first;
3177 Block= createBlock(
false);
3185KnownVal = tryEvaluateBool(I->
getCond());
3189addSuccessor(
Block, ThenBlock,
!KnownVal.isFalse());
3190addSuccessor(
Block, ElseBlock,
!KnownVal.isTrue());
3198LastBlock = addStmt(I->
getCond());
3204LastBlock = addStmt(
const_cast<DeclStmt*
>(DS));
3211LastBlock = addStmt(
Init);
3224assert(isa<ReturnStmt>(S) || isa<CoreturnStmt>(S));
3227 Block= createBlock(
false);
3229addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), S);
3231 if(
auto*R = dyn_cast<ReturnStmt>(S))
3232findConstructionContexts(
3239addSuccessor(
Block, &cfg->getExit());
3242appendStmt(
Block, S);
3245 if(
ReturnStmt*RS = dyn_cast<ReturnStmt>(S)) {
3246 if(
Expr*O = RS->getRetValue())
3247 returnVisit(O, AddStmtChoice::AlwaysAdd,
true);
3257 if(RV->getType()->isVoidType() && !isa<InitListExpr>(RV))
3266AddStmtChoice asc) {
3270 if(asc.alwaysAdd(*
this,
E)) {
3275 if(
auto*R = Visit(
E->getResumeExpr()))
3277 if(
auto*R = Visit(
E->getSuspendExpr()))
3279 if(
auto*R = Visit(
E->getReadyExpr()))
3281 if(
auto*R = Visit(
E->getCommonExpr()))
3296 if(!SEHExceptBlock)
3297SEHExceptBlock = createBlock();
3299appendStmt(SEHExceptBlock, ES);
3311 returnSEHExceptBlock;
3315 returnVisitCompoundStmt(FS->getBlock(),
false);
3325 Block= createBlock(
false);
3330 if(SEHLeaveJumpTarget.block) {
3331addAutomaticObjHandling(ScopePos, SEHLeaveJumpTarget.scopePosition, LS);
3332addSuccessor(
Block, SEHLeaveJumpTarget.block);
3342 CFGBlock*SEHTrySuccessor =
nullptr;
3347SEHTrySuccessor =
Block;
3348}
elseSEHTrySuccessor = Succ;
3354 CFGBlock*PrevSEHTryTerminatedBlock = TryTerminatedBlock;
3357 CFGBlock*NewTryTerminatedBlock = createBlock(
false);
3364Succ = SEHTrySuccessor;
3366 CFGBlock*ExceptBlock = VisitSEHExceptStmt(Except);
3371addSuccessor(NewTryTerminatedBlock, ExceptBlock);
3373 if(PrevSEHTryTerminatedBlock)
3374addSuccessor(NewTryTerminatedBlock, PrevSEHTryTerminatedBlock);
3376addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
3379Succ = SEHTrySuccessor;
3382 SaveAndRestoreSaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
3383cfg->addTryDispatchBlock(TryTerminatedBlock);
3389SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
3391assert(Terminator->
getTryBlock() &&
"__try must contain a non-NULL body");
3402LabelBlock = createBlock();
3404assert(!LabelMap.contains(L->
getDecl()) &&
"label already in map");
3405LabelMap[L->
getDecl()] = JumpTarget(LabelBlock, ScopePos);
3425 CFGBlock*LastBlock = VisitNoRecurse(
E, asc);
3427 if(
Expr*CopyExpr = CI.getCopyExpr()) {
3437 CFGBlock*LastBlock = VisitNoRecurse(
E, asc);
3441et =
E->capture_init_end();
3442it != et; ++it, ++Idx) {
3447dyn_cast<ArrayInitLoopExpr>(
Init));
3450cfg->getBumpVectorContext(), {E, Idx}),
3451AILEInit ? AILEInit :
Init);
3465 Block= createBlock(
false);
3469LabelMapTy::iterator I = LabelMap.find(G->
getLabel());
3471 if(I == LabelMap.end())
3473BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3475JumpTarget JT = I->second;
3476addSuccessor(
Block, JT.block);
3477addScopeChangesHandling(ScopePos, JT.scopePosition, G);
3488 returnVisitStmt(G, asc);
3495 Block= createBlock();
3498BackpatchBlocks.push_back(JumpSource(
Block, ScopePos));
3501BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
3502 returnVisitChildren(G);
3506 CFGBlock*LoopSuccessor =
nullptr;
3516addLocalScopeForStmt(
Init);
3517LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3520addLocalScopeForVarDecl(VD);
3521LocalScope::const_iterator ContinueScopePos = ScopePos;
3523addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
3532LoopSuccessor =
Block;
3534LoopSuccessor = Succ;
3539BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3541 CFGBlock*BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3554 Block= Succ = TransitionBlock = createBlock(
false);
3555TransitionBlock->setLoopTarget(F);
3560addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F);
3570assert(
Block== Succ);
3578ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
3579ContinueJumpTarget.block->setLoopTarget(F);
3584 if(!isa<CompoundStmt>(F->
getBody()))
3585addLocalScopeAndDtors(F->
getBody());
3589BodyBlock = addStmt(F->
getBody());
3594BodyBlock = ContinueJumpTarget.block;
3603 CFGBlock*EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3612dyn_cast_or_null<BinaryOperator>(
C?
C->IgnoreParens() :
nullptr))
3614std::tie(EntryConditionBlock, ExitConditionBlock) =
3615VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor);
3620EntryConditionBlock = ExitConditionBlock = createBlock(
false);
3621ExitConditionBlock->setTerminator(F);
3624TryResult KnownVal(
true);
3630 Block= ExitConditionBlock;
3631EntryConditionBlock = addStmt(
C);
3640findConstructionContexts(
3643appendStmt(
Block, DS);
3644EntryConditionBlock = addStmt(
Init);
3645assert(
Block== EntryConditionBlock);
3646maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3650 if(
Block&& badCFG)
3653KnownVal = tryEvaluateBool(
C);
3657addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr: BodyBlock);
3660addSuccessor(ExitConditionBlock,
3661KnownVal.isTrue() ?
nullptr: LoopSuccessor);
3665addSuccessor(TransitionBlock, EntryConditionBlock);
3668Succ = EntryConditionBlock;
3674ScopePos = LoopBeginScopePos;
3675 Block= createBlock();
3682Succ = EntryConditionBlock;
3683 returnEntryConditionBlock;
3688AddStmtChoice asc) {
3689findConstructionContexts(
3693 returnVisitStmt(MTE, asc);
3697 if(asc.alwaysAdd(*
this, M)) {
3699appendStmt(
Block, M);
3736 CFGBlock*LoopSuccessor =
nullptr;
3741LoopSuccessor =
Block;
3744LoopSuccessor = Succ;
3747 CFGBlock*ExitConditionBlock = createBlock(
false);
3755appendStmt(ExitConditionBlock, S);
3756 Block= ExitConditionBlock;
3761 CFGBlock*EntryConditionBlock = Visit(S->getElement(),
3762AddStmtChoice::NotAlwaysAdd);
3771Succ = EntryConditionBlock;
3778save_break(BreakJumpTarget);
3783 CFGBlock*LoopBackBlock =
nullptr;
3784Succ = LoopBackBlock = createBlock();
3787BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3788ContinueJumpTarget = JumpTarget(Succ, ScopePos);
3790 CFGBlock*BodyBlock = addStmt(S->getBody());
3793BodyBlock = ContinueJumpTarget.block;
3800addSuccessor(ExitConditionBlock, BodyBlock);
3805addSuccessor(ExitConditionBlock, LoopSuccessor);
3808 Block= createBlock();
3809 returnaddStmt(S->getCollection());
3814 returnaddStmt(S->getSubStmt());
3822 CFGBlock*SyncBlock = addStmt(S->getSynchBody());
3836appendStmt(
Block, S);
3839 returnaddStmt(S->getSynchExpr());
3852 for(
unsignedi =
E->getNumSemanticExprs(); i != 0; ) {
3853 Expr*Semantic =
E->getSemanticExpr(--i);
3858Semantic = OVE->getSourceExpr();
3860 if(
CFGBlock*B = Visit(Semantic))
3868 CFGBlock*LoopSuccessor =
nullptr;
3876LocalScope::const_iterator LoopBeginScopePos = ScopePos;
3878addLocalScopeForVarDecl(VD);
3879addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
3888LoopSuccessor =
Block;
3891LoopSuccessor = Succ;
3894 CFGBlock*BodyBlock =
nullptr, *TransitionBlock =
nullptr;
3903save_break(BreakJumpTarget);
3907Succ = TransitionBlock = createBlock(
false);
3908TransitionBlock->setLoopTarget(W);
3909ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
3912BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
3915addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
3919 if(!isa<CompoundStmt>(W->
getBody()))
3920addLocalScopeAndDtors(W->
getBody());
3923BodyBlock = addStmt(W->
getBody());
3926BodyBlock = ContinueJumpTarget.block;
3927 else if(
Block&& badCFG)
3934 CFGBlock*EntryConditionBlock =
nullptr, *ExitConditionBlock =
nullptr;
3941 if(
BinaryOperator*Cond = dyn_cast<BinaryOperator>(
C->IgnoreParens()))
3943std::tie(EntryConditionBlock, ExitConditionBlock) =
3944VisitLogicalOperator(Cond, W, BodyBlock, LoopSuccessor);
3949ExitConditionBlock = createBlock(
false);
3955 Block= ExitConditionBlock;
3956 Block= EntryConditionBlock = addStmt(
C);
3965findConstructionContexts(
3969appendStmt(
Block, DS);
3970EntryConditionBlock = addStmt(
Init);
3971assert(
Block== EntryConditionBlock);
3972maybeAddScopeBeginForVarDecl(EntryConditionBlock, VD,
C);
3976 if(
Block&& badCFG)
3980 constTryResult& KnownVal = tryEvaluateBool(
C);
3983addSuccessor(ExitConditionBlock, KnownVal.isFalse() ?
nullptr: BodyBlock);
3986addSuccessor(ExitConditionBlock,
3987KnownVal.isTrue() ?
nullptr: LoopSuccessor);
3991addSuccessor(TransitionBlock, EntryConditionBlock);
3998Succ = EntryConditionBlock;
3999 returnEntryConditionBlock;
4003AddStmtChoice asc) {
4004 if(asc.alwaysAdd(*
this, A)) {
4006appendStmt(
Block, A);
4014 auto*OVE = dyn_cast<OpaqueValueExpr>(A->
getCommonExpr());
4015assert(OVE &&
"ArrayInitLoopExpr->getCommonExpr() should be wrapped in an " 4016 "OpaqueValueExpr!");
4017 if(
CFGBlock*R = Visit(OVE->getSourceExpr()))
4036CatchBlock = createBlock();
4038appendStmt(CatchBlock, CS);
4059 Block= createBlock(
false);
4061 if(TryTerminatedBlock)
4063addSuccessor(
Block, TryTerminatedBlock);
4066addSuccessor(
Block, &cfg->getExit());
4070 returnVisitStmt(S, AddStmtChoice::AlwaysAdd);
4081TrySuccessor =
Block;
4083TrySuccessor = Succ;
4089 CFGBlock*PrevTryTerminatedBlock = TryTerminatedBlock;
4092 CFGBlock*NewTryTerminatedBlock = createBlock(
false);
4096 boolHasCatchAll =
false;
4099Succ = TrySuccessor;
4101HasCatchAll =
true;
4104 CFGBlock*CatchBlock = VisitObjCAtCatchStmt(CS);
4109addSuccessor(NewTryTerminatedBlock, CatchBlock);
4114 if(PrevTryTerminatedBlock)
4115addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4117addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4121Succ = TrySuccessor;
4124 SaveAndRestoreSaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4125cfg->addTryDispatchBlock(TryTerminatedBlock);
4127assert(Terminator->
getTryBody() &&
"try must contain a non-NULL body");
4133AddStmtChoice asc) {
4134findConstructionContextsForArguments(ME);
4137appendObjCMessage(
Block, ME);
4139 returnVisitChildren(ME);
4148 Block= createBlock(
false);
4150 if(TryTerminatedBlock)
4152addSuccessor(
Block, TryTerminatedBlock);
4155addSuccessor(
Block, &cfg->getExit());
4159 returnVisitStmt(
T, AddStmtChoice::AlwaysAdd);
4163 if(asc.alwaysAdd(*
this, S)) {
4165appendStmt(
Block, S);
4174 if(!S->isTypeDependent() && S->isPotentiallyEvaluated())
4175 returnVisitChildren(S);
4182 CFGBlock*LoopSuccessor =
nullptr;
4191LoopSuccessor =
Block;
4193LoopSuccessor = Succ;
4198 CFGBlock*ExitConditionBlock = createBlock(
false);
4199 CFGBlock*EntryConditionBlock = ExitConditionBlock;
4206 if(
Stmt*
C=
D->getCond()) {
4207 Block= ExitConditionBlock;
4208EntryConditionBlock = addStmt(
C);
4216Succ = EntryConditionBlock;
4219 constTryResult &KnownVal = tryEvaluateBool(
D->getCond());
4229save_break(BreakJumpTarget);
4232ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
4235BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4242 if(!isa<CompoundStmt>(
D->
getBody()))
4243addLocalScopeAndDtors(
D->
getBody());
4246BodyBlock = addStmt(
D->
getBody());
4249BodyBlock = EntryConditionBlock;
4262 CFGBlock*LoopBackBlock = createBlock();
4265 if(!KnownVal.isFalse())
4267addSuccessor(ExitConditionBlock, LoopBackBlock);
4269addSuccessor(ExitConditionBlock,
nullptr);
4274addSuccessor(ExitConditionBlock, KnownVal.isTrue() ?
nullptr: LoopSuccessor);
4292 Block= createBlock(
false);
4297 if(ContinueJumpTarget.block) {
4298addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition,
C);
4299addSuccessor(
Block, ContinueJumpTarget.block);
4307AddStmtChoice asc) {
4308 if(asc.alwaysAdd(*
this,
E)) {
4316 if(
E->getKind() != UETT_SizeOf)
4321 if(
E->isArgumentType()) {
4323VA !=
nullptr; VA =
FindVA(VA->getElementType().getTypePtr()))
4324lastBlock = addStmt(VA->getSizeExpr());
4332 if(asc.alwaysAdd(*
this, SE)) {
4334appendStmt(
Block, SE);
4336 returnVisitCompoundStmt(SE->
getSubStmt(),
true);
4342 CFGBlock*SwitchSuccessor =
nullptr;
4350addLocalScopeForStmt(
Init);
4355addLocalScopeForVarDecl(VD);
4357addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator);
4362SwitchSuccessor =
Block;
4363}
elseSwitchSuccessor = Succ;
4367save_default(DefaultCaseBlock);
4373DefaultCaseBlock = SwitchSuccessor;
4376SwitchTerminatedBlock = createBlock(
false);
4380Succ = SwitchSuccessor;
4381BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
4386assert(Terminator->
getBody() &&
"switch must contain a non-NULL body");
4391 SaveAndRestoresave_switchExclusivelyCovered(switchExclusivelyCovered,
false);
4394assert(Terminator->
getCond() &&
"switch condition must be non-NULL");
4396 bool b= tryEvaluate(Terminator->
getCond(), result);
4401 if(!isa<CompoundStmt>(Terminator->
getBody()))
4402addLocalScopeAndDtors(Terminator->
getBody());
4404addStmt(Terminator->
getBody());
4416 boolSwitchAlwaysHasSuccessor =
false;
4417SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
4420addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock,
4421!SwitchAlwaysHasSuccessor);
4425 Block= SwitchTerminatedBlock;
4434LastBlock = addStmt(
Init);
4435maybeAddScopeBeginForVarDecl(LastBlock, VD,
Init);
4442LastBlock = addStmt(
Init);
4455 booladdCase =
false;
4457 if(!switchExclusivelyCovered) {
4461 constllvm::APSInt &condInt = switchCond->
Val.
getInt();
4463 if(condInt == lhsInt) {
4465switchExclusivelyCovered =
true;
4467 else if(condInt > lhsInt) {
4471 if(V2 >= condInt) {
4473switchExclusivelyCovered =
true;
4487 CFGBlock*TopBlock =
nullptr, *LastBlock =
nullptr;
4493 while(isa<CaseStmt>(Sub)) {
4494 CFGBlock*currentBlock = createBlock(
false);
4498addSuccessor(LastBlock, currentBlock);
4500TopBlock = currentBlock;
4502addSuccessor(SwitchTerminatedBlock,
4505? currentBlock :
nullptr);
4507LastBlock = currentBlock;
4508CS = cast<CaseStmt>(Sub);
4517CaseBlock = createBlock();
4528assert(SwitchTerminatedBlock);
4529addSuccessor(SwitchTerminatedBlock, CaseBlock,
4537addSuccessor(LastBlock, CaseBlock);
4551DefaultCaseBlock =
Block;
4553 if(!DefaultCaseBlock)
4554DefaultCaseBlock = createBlock();
4558DefaultCaseBlock->
setLabel(Terminator);
4573Succ = DefaultCaseBlock;
4575 returnDefaultCaseBlock;
4586TrySuccessor =
Block;
4588TrySuccessor = Succ;
4590 CFGBlock*PrevTryTerminatedBlock = TryTerminatedBlock;
4593 CFGBlock*NewTryTerminatedBlock = createBlock(
false);
4597 boolHasCatchAll =
false;
4600Succ = TrySuccessor;
4603HasCatchAll =
true;
4606 CFGBlock*CatchBlock = VisitCXXCatchStmt(CS);
4611addSuccessor(NewTryTerminatedBlock, CatchBlock);
4614 if(PrevTryTerminatedBlock)
4615addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
4617addSuccessor(NewTryTerminatedBlock, &cfg->getExit());
4621Succ = TrySuccessor;
4624 SaveAndRestoreSaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
4625cfg->addTryDispatchBlock(TryTerminatedBlock);
4627assert(Terminator->
getTryBlock() &&
"try must contain a non-NULL body");
4643LocalScope::const_iterator BeginScopePos = ScopePos;
4644addLocalScopeForVarDecl(VD);
4645addAutomaticObjHandling(ScopePos, BeginScopePos, CS);
4653CatchBlock = createBlock();
4659appendStmt(CatchBlock, CS);
4694addLocalScopeForStmt(
Range);
4696addLocalScopeForStmt(
Begin);
4697 if(
Stmt*End = S->getEndStmt())
4698addLocalScopeForStmt(End);
4699addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S);
4701LocalScope::const_iterator ContinueScopePos = ScopePos;
4705 CFGBlock*LoopSuccessor =
nullptr;
4709LoopSuccessor =
Block;
4711LoopSuccessor = Succ;
4716BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
4719 CFGBlock*ConditionBlock = createBlock(
false);
4723 if(
Expr*
C= S->getCond()) {
4724 Block= ConditionBlock;
4725 CFGBlock*BeginConditionBlock = addStmt(
C);
4728assert(BeginConditionBlock == ConditionBlock &&
4729 "condition block in for-range was unexpectedly complex");
4730(void)BeginConditionBlock;
4735Succ = ConditionBlock;
4738TryResult KnownVal(
true);
4741KnownVal = tryEvaluateBool(S->getCond());
4745assert(S->getBody());
4754Succ = addStmt(S->getInc());
4757ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
4761ContinueJumpTarget.block->setLoopTarget(S);
4770addLocalScopeAndDtors(S->getLoopVarStmt());
4774 if(!isa<CompoundStmt>(S->getBody()))
4775addLocalScopeAndDtors(S->getBody());
4778addStmt(S->getBody());
4782 CFGBlock*LoopVarStmtBlock = addStmt(S->getLoopVarStmt());
4787addSuccessor(ConditionBlock,
4788KnownVal.isFalse() ?
nullptr: LoopVarStmtBlock);
4793addSuccessor(ConditionBlock, KnownVal.isTrue() ?
nullptr: LoopSuccessor);
4796 Block= createBlock();
4797addStmt(S->getBeginStmt());
4798addStmt(S->getEndStmt());
4799 CFGBlock*Head = addStmt(S->getRangeStmt());
4801Head = addStmt(S->getInit());
4806AddStmtChoice asc,
boolExternallyDestructed) {
4810TempDtorContext Context;
4811VisitForTemporaryDtors(
E->getSubExpr(), ExternallyDestructed, Context);
4815asc = asc.withAlwaysAdd(
true);
4817 returnVisit(
E->getSubExpr(), asc);
4821AddStmtChoice asc) {
4822 if(asc.alwaysAdd(*
this,
E)) {
4826findConstructionContexts(
4831asc = asc.withAlwaysAdd(
false);
4833 returnVisit(
E->getSubExpr(), asc);
4837AddStmtChoice asc) {
4841findConstructionContextsForArguments(
C);
4842appendConstructor(
C);
4844 returnVisitChildren(
C);
4848AddStmtChoice asc) {
4850appendStmt(
Block, NE);
4852findConstructionContexts(
4856 if(
NE->getInitializer())
4857 Block= Visit(
NE->getInitializer());
4860appendNewAllocator(
Block, NE);
4862 if(
NE->isArray() && *
NE->getArraySize())
4863 Block= Visit(*
NE->getArraySize());
4866 E=
NE->placement_arg_end(); I !=
E; ++I)
4873AddStmtChoice asc) {
4875appendStmt(
Block, DE);
4882appendDeleteDtor(
Block, RD, DE);
4886 returnVisitChildren(DE);
4890AddStmtChoice asc) {
4891 if(asc.alwaysAdd(*
this,
E)) {
4895asc = asc.withAlwaysAdd(
false);
4897 returnVisit(
E->getSubExpr(), asc);
4901AddStmtChoice asc) {
4905findConstructionContextsForArguments(
E);
4906appendConstructor(
E);
4908 returnVisitChildren(
E);
4912AddStmtChoice asc) {
4913 if(asc.alwaysAdd(*
this,
E)) {
4918 if(
E->getCastKind() == CK_IntegralToBoolean)
4921 returnVisit(
E->getSubExpr(), AddStmtChoice());
4925 returnVisit(
E->getSubExpr(), AddStmtChoice());
4930 CFGBlock*IBlock = cfg->getIndirectGotoBlock();
4933IBlock = createBlock(
false);
4934cfg->setIndirectGotoBlock(IBlock);
4942 Block= createBlock(
false);
4944addSuccessor(
Block, IBlock);
4948CFGBlock*CFGBuilder::VisitForTemporaryDtors(
Stmt*
E,
boolExternallyDestructed,
4949TempDtorContext &Context) {
4959 returnVisitChildrenForTemporaryDtors(
E,
false, Context);
4961 caseStmt::InitListExprClass:
4962 returnVisitChildrenForTemporaryDtors(
E, ExternallyDestructed, Context);
4964 caseStmt::BinaryOperatorClass:
4965 returnVisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(
E),
4966ExternallyDestructed,
4969 caseStmt::CXXBindTemporaryExprClass:
4970 returnVisitCXXBindTemporaryExprForTemporaryDtors(
4971cast<CXXBindTemporaryExpr>(
E), ExternallyDestructed, Context);
4973 caseStmt::BinaryConditionalOperatorClass:
4974 caseStmt::ConditionalOperatorClass:
4975 returnVisitConditionalOperatorForTemporaryDtors(
4976cast<AbstractConditionalOperator>(
E), ExternallyDestructed, Context);
4978 caseStmt::ImplicitCastExprClass:
4980 E= cast<CastExpr>(
E)->getSubExpr();
4983 caseStmt::CXXFunctionalCastExprClass:
4985 E= cast<CXXFunctionalCastExpr>(
E)->getSubExpr();
4988 caseStmt::ConstantExprClass:
4989 E= cast<ConstantExpr>(
E)->getSubExpr();
4992 caseStmt::ParenExprClass:
4993 E= cast<ParenExpr>(
E)->getSubExpr();
4996 caseStmt::MaterializeTemporaryExprClass: {
5002 E=
const_cast<Expr*
>(
5003cast<MaterializeTemporaryExpr>(
E)
5005->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
5007 for(
const Expr*CommaLHS : CommaLHSs) {
5008VisitForTemporaryDtors(
const_cast<Expr*
>(CommaLHS),
5014 caseStmt::BlockExprClass:
5019 caseStmt::LambdaExprClass: {
5022 auto*
LE= cast<LambdaExpr>(
E);
5026 if(
CFGBlock*R = VisitForTemporaryDtors(
5027 Init,
true, Context))
5034 caseStmt::StmtExprClass:
5039 caseStmt::CXXDefaultArgExprClass:
5040 E= cast<CXXDefaultArgExpr>(
E)->getExpr();
5043 caseStmt::CXXDefaultInitExprClass:
5044 E= cast<CXXDefaultInitExpr>(
E)->getExpr();
5049CFGBlock*CFGBuilder::VisitChildrenForTemporaryDtors(
Stmt*
E,
5050 boolExternallyDestructed,
5051TempDtorContext &Context) {
5052 if(isa<LambdaExpr>(
E)) {
5064 if(
CFGBlock*R = VisitForTemporaryDtors(Child, ExternallyDestructed, Context))
5070CFGBlock*CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
5071 BinaryOperator*
E,
boolExternallyDestructed, TempDtorContext &Context) {
5072 if(
E->isCommaOp()) {
5075 CFGBlock*LHSBlock = VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5076 CFGBlock*RHSBlock = VisitForTemporaryDtors(
E->getRHS(), ExternallyDestructed, Context);
5077 returnRHSBlock ? RHSBlock : LHSBlock;
5080 if(
E->isLogicalOp()) {
5081VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5082TryResult RHSExecuted = tryEvaluateBool(
E->getLHS());
5083 if(RHSExecuted.isKnown() &&
E->getOpcode() == BO_LOr)
5084RHSExecuted.negate();
5089TempDtorContext RHSContext(
5091VisitForTemporaryDtors(
E->getRHS(),
false, RHSContext);
5092InsertTempDtorDecisionBlock(RHSContext);
5097 if(
E->isAssignmentOp()) {
5100 CFGBlock*RHSBlock = VisitForTemporaryDtors(
E->getRHS(),
false, Context);
5101 CFGBlock*LHSBlock = VisitForTemporaryDtors(
E->getLHS(),
false, Context);
5102 returnLHSBlock ? LHSBlock : RHSBlock;
5106 returnVisitChildrenForTemporaryDtors(
E, ExternallyDestructed, Context);
5109CFGBlock*CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
5113 CFGBlock*B = VisitForTemporaryDtors(
E->getSubExpr(),
true, Context);
5114 if(!ExternallyDestructed) {
5126 Block= createNoReturnBlock();
5127}
else if(Context.needsTempDtorBranch()) {
5131 Block= createBlock();
5135 if(Context.needsTempDtorBranch()) {
5136Context.setDecisionPoint(Succ,
E);
5138appendTemporaryDtor(
Block,
E);
5145voidCFGBuilder::InsertTempDtorDecisionBlock(
constTempDtorContext &Context,
5147 if(!Context.TerminatorExpr) {
5151assert(Context.TerminatorExpr);
5152 CFGBlock*Decision = createBlock(
false);
5155addSuccessor(Decision,
Block, !Context.KnownExecuted.isFalse());
5156addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
5157!Context.KnownExecuted.isTrue());
5161CFGBlock*CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
5163TempDtorContext &Context) {
5164VisitForTemporaryDtors(
E->getCond(),
false, Context);
5167TryResult ConditionVal = tryEvaluateBool(
E->getCond());
5168TryResult NegatedVal = ConditionVal;
5169 if(NegatedVal.isKnown()) NegatedVal.negate();
5171TempDtorContext TrueContext(
5173VisitForTemporaryDtors(
E->getTrueExpr(), ExternallyDestructed, TrueContext);
5176 Block= ConditionBlock;
5177Succ = ConditionSucc;
5178TempDtorContext FalseContext(
5180VisitForTemporaryDtors(
E->getFalseExpr(), ExternallyDestructed, FalseContext);
5182 if(TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
5183InsertTempDtorDecisionBlock(FalseContext, TrueBlock);
5184}
else if(TrueContext.TerminatorExpr) {
5186InsertTempDtorDecisionBlock(TrueContext);
5188InsertTempDtorDecisionBlock(FalseContext);
5194AddStmtChoice asc) {
5195 if(asc.alwaysAdd(*
this,
D)) {
5207 for(
Stmt*S : llvm::reverse(
Used)) {
5208assert(S &&
"Expected non-null used-in-clause child.");
5213 if(!
D->isStandaloneDirective()) {
5214 Stmt*S =
D->getRawStmt();
5215 if(!isa<CompoundStmt>(S))
5216addLocalScopeAndDtors(S);
5228 boolfirst_block =
begin() ==
end();
5236Entry = Exit = &
back();
5245CFGBuilder Builder(
C, BO);
5246 returnBuilder.buildCFG(
D, Statement);
5261 autoIteratorAndFlag =
Visited.insert(B);
5262 if(!IteratorAndFlag.second) {
5268 const CFGBlock*FirstReachableB =
nullptr;
5270 if(!AB.isReachable())
5273 if(FirstReachableB ==
nullptr) {
5274FirstReachableB = &*AB;
5281 if(!FirstReachableB) {
5287B = FirstReachableB;
5307llvm_unreachable(
"getDestructorDecl should only be used with " 5310 const VarDecl*var = castAs<CFGAutomaticObjDtor>().getVarDecl();
5318 if(
const Expr*
Init= var->getInit()) {
5336 const CXXDeleteExpr*DE = castAs<CFGDeleteDtor>().getDeleteExpr();
5345castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
5350 const FieldDecl*field = castAs<CFGMemberDtor>().getFieldDecl();
5365llvm_unreachable(
"getKind() returned bogus value");
5373: ReachableBlock(IsReachable ? B : nullptr),
5374UnreachableBlock(!IsReachable ? B : nullptr,
5375B && IsReachable ? AB_Normal : AB_Unreachable) {}
5378: ReachableBlock(B),
5379UnreachableBlock(B == AlternateBlock ? nullptr : AlternateBlock,
5380B == AlternateBlock ? AB_Alternate : AB_Normal) {}
5388UnreachableB->Preds.push_back(
AdjacentBlock(
this,
false),
C);
5403 if(S->isAllEnumCasesCovered()) {
5405 if(!L || !isa<CaseStmt>(L))
5421 usingStmtMapTy = llvm::DenseMap<const Stmt *, std::pair<unsigned, unsigned>>;
5422 usingDeclMapTy = llvm::DenseMap<const Decl *, std::pair<unsigned, unsigned>>;
5426 signedcurrentBlock = 0;
5427 unsignedcurrStmt = 0;
5438BI != BEnd; ++BI, ++j ) {
5439 if(std::optional<CFGStmt> SE = BI->getAs<
CFGStmt>()) {
5441std::pair<unsigned, unsigned>
P((*I)->getBlockID(), j);
5442StmtMap[
stmt] =
P;
5444 switch(
stmt->getStmtClass()) {
5445 caseStmt::DeclStmtClass:
5446DeclMap[cast<DeclStmt>(
stmt)->getSingleDecl()] =
P;
5448 caseStmt::IfStmtClass: {
5449 const VarDecl*var = cast<IfStmt>(
stmt)->getConditionVariable();
5454 caseStmt::ForStmtClass: {
5455 const VarDecl*var = cast<ForStmt>(
stmt)->getConditionVariable();
5460 caseStmt::WhileStmtClass: {
5462cast<WhileStmt>(
stmt)->getConditionVariable();
5464DeclMap[
var] =
P;
5467 caseStmt::SwitchStmtClass: {
5469cast<SwitchStmt>(
stmt)->getConditionVariable();
5471DeclMap[
var] =
P;
5474 caseStmt::CXXCatchStmtClass: {
5476cast<CXXCatchStmt>(
stmt)->getExceptionDecl();
5478DeclMap[
var] =
P;
5489~StmtPrinterHelper()
override=
default;
5491 const LangOptions&getLangOpts()
const{
returnLangOpts; }
5492 voidsetBlockID(
signedi) { currentBlock = i; }
5493 voidsetStmtID(
unsignedi) { currStmt = i; }
5495 boolhandledStmt(
Stmt*S, raw_ostream &OS)
override{
5496StmtMapTy::iterator I = StmtMap.find(S);
5498 if(I == StmtMap.end())
5501 if(currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5502&& I->second.second == currStmt) {
5506OS <<
"[B"<< I->second.first <<
"."<< I->second.second <<
"]";
5510 boolhandleDecl(
const Decl*
D, raw_ostream &OS) {
5511DeclMapTy::iterator I = DeclMap.find(
D);
5513 if(I == DeclMap.end())
5516 if(currentBlock >= 0 && I->second.first == (
unsigned) currentBlock
5517&& I->second.second == currStmt) {
5521OS <<
"[B"<< I->second.first <<
"."<< I->second.second <<
"]";
5526classCFGBlockTerminatorPrint
5527:
public StmtVisitor<CFGBlockTerminatorPrint,void> {
5529StmtPrinterHelper* Helper;
5533CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
5535: OS(os), Helper(helper), Policy(Policy) {
5539 voidVisitIfStmt(
IfStmt*I) {
5542 C->printPretty(OS, Helper, Policy);
5546 voidVisitStmt(
Stmt*Terminator) {
5550 voidVisitDeclStmt(
DeclStmt*DS) {
5552OS <<
"static init "<< VD->
getName();
5555 voidVisitForStmt(
ForStmt*F) {
5561 C->printPretty(OS, Helper, Policy);
5571 C->printPretty(OS, Helper, Policy);
5574 voidVisitDoStmt(
DoStmt*
D) {
5575OS <<
"do ... while ";
5576 if(
Stmt*
C=
D->getCond())
5577 C->printPretty(OS, Helper, Policy);
5580 voidVisitSwitchStmt(
SwitchStmt*Terminator) {
5585 voidVisitCXXTryStmt(
CXXTryStmt*) { OS <<
"try ..."; }
5587 voidVisitObjCAtTryStmt(
ObjCAtTryStmt*) { OS <<
"@try ..."; }
5589 voidVisitSEHTryStmt(
SEHTryStmt*CS) { OS <<
"__try ..."; }
5592 if(
Stmt*Cond =
C->getCond())
5594OS <<
" ? ... : ...";
5598OS <<
"__builtin_choose_expr( ";
5599 if(
Stmt*Cond =
C->getCond())
5607 T->printPretty(OS, Helper, Policy);
5627llvm_unreachable(
"Invalid logical operator.");
5631 voidVisitExpr(
Expr*
E) {
5637 switch(
T.getKind()) {
5639Visit(
T.getStmt());
5642OS <<
"(Temp Dtor) ";
5643Visit(
T.getStmt());
5646OS <<
"(See if most derived ctor has already initialized vbases)";
5664IE->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
5668OS <<
" (Base initializer)";
5670OS <<
" (Delegating initializer)";
5672OS <<
" (Member initializer)";
5676StmtPrinterHelper &Helper,
5682 const auto*SICC = cast<SimpleConstructorInitializerConstructionContext>(CC);
5689cast<CXX17ElidedCopyConstructorInitializerConstructionContext>(CC);
5691Stmts.push_back(CICC->getCXXBindTemporaryExpr());
5695 const auto*SDSCC = cast<SimpleVariableConstructionContext>(CC);
5696Stmts.push_back(SDSCC->getDeclStmt());
5700 const auto*CDSCC = cast<CXX17ElidedCopyVariableConstructionContext>(CC);
5701Stmts.push_back(CDSCC->getDeclStmt());
5702Stmts.push_back(CDSCC->getCXXBindTemporaryExpr());
5706 const auto*NECC = cast<NewAllocatedObjectConstructionContext>(CC);
5707Stmts.push_back(NECC->getCXXNewExpr());
5711 const auto*RSCC = cast<SimpleReturnedValueConstructionContext>(CC);
5712Stmts.push_back(RSCC->getReturnStmt());
5717cast<CXX17ElidedCopyReturnedValueConstructionContext>(CC);
5718Stmts.push_back(RSCC->getReturnStmt());
5719Stmts.push_back(RSCC->getCXXBindTemporaryExpr());
5723 const auto*TOCC = cast<SimpleTemporaryObjectConstructionContext>(CC);
5724Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5725Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5729 const auto*TOCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
5730Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
5731Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
5732Stmts.push_back(TOCC->getConstructorAfterElision());
5736 const auto*LCC = cast<LambdaCaptureConstructionContext>(CC);
5737Helper.handledStmt(
const_cast<LambdaExpr*
>(LCC->getLambdaExpr()), OS);
5738OS <<
"+"<< LCC->getIndex();
5742 const auto*ACC = cast<ArgumentConstructionContext>(CC);
5743 if(
const Stmt*BTE = ACC->getCXXBindTemporaryExpr()) {
5745Helper.handledStmt(
const_cast<Stmt*
>(BTE), OS);
5748Helper.handledStmt(
const_cast<Expr*
>(ACC->getCallLikeExpr()), OS);
5749OS <<
"+"<< ACC->getIndex();
5753 for(
autoI: Stmts)
5756Helper.handledStmt(
const_cast<Stmt*
>(I), OS);
5760static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5765StmtPrinterHelper Helper(
nullptr, LangOpts);
5769static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
5771 switch(
E.getKind()) {
5777assert(S !=
nullptr&&
"Expecting non-null Stmt");
5780 if(
const StmtExpr*SE = dyn_cast<StmtExpr>(S)) {
5783 autoChildren = Sub->children();
5784 if(Children.begin() != Children.end()) {
5795Helper.handledStmt(B->
getRHS(),OS);
5800S->printPretty(OS, &Helper,
PrintingPolicy(Helper.getLangOpts()));
5803 if(isa<CXXOperatorCallExpr>(S))
5804OS <<
" (OperatorCall)";
5805OS <<
" (CXXRecordTypedCall";
5808}
else if(isa<CXXOperatorCallExpr>(S)) {
5809OS <<
" (OperatorCall)";
5810}
else if(isa<CXXBindTemporaryExpr>(S)) {
5811OS <<
" (BindTemporary)";
5813OS <<
" (CXXConstructExpr";
5814 if(std::optional<CFGConstructor> CE =
E.getAs<
CFGConstructor>()) {
5817OS <<
", "<< CCE->getType() <<
")";
5818}
else if(
const CastExpr*CE = dyn_cast<CastExpr>(S)) {
5820<<
", "<< CE->
getType() <<
")";
5838Helper.handleDecl(VD, OS);
5845 T.getUnqualifiedType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5846OS <<
"() (Implicit destructor)\n";
5851OS <<
"CleanupFunction (" 5857OS <<
" (Lifetime ends)\n";
5861OS <<
E.castAs<
CFGLoopExit>().getLoopStmt()->getStmtClassName() <<
" (LoopExit)\n";
5865OS <<
"CFGScopeBegin(";
5872OS <<
"CFGScopeEnd(";
5879OS <<
"CFGNewAllocator(";
5881AllocExpr->getType().print(OS,
PrintingPolicy(Helper.getLangOpts()));
5892Helper.handledStmt(cast<Stmt>(DelExpr->
getArgument()), OS);
5893OS <<
"->~"<< RD->getName().str() <<
"()";
5894OS <<
" (Implicit destructor)\n";
5901OS <<
" (Base object destructor)\n";
5908OS <<
"this->"<< FD->
getName();
5910OS <<
" (Member object destructor)\n";
5919OS <<
"() (Temporary object destructor)\n";
5927StmtPrinterHelper &Helper,
boolprint_edges,
5933OS.changeColor(raw_ostream::YELLOW,
true);
5938OS <<
" (ENTRY)]\n";
5939 else if(&B == &cfg->
getExit())
5940OS <<
" (EXIT)]\n";
5942OS <<
" (INDIRECT GOTO DISPATCH)]\n";
5944OS <<
" (NORETURN)]\n";
5960 if(
const Expr*LHS =
C->getLHS())
5962 if(
const Expr*RHS =
C->getRHS()) {
5966}
else if(isa<DefaultStmt>(
Label))
5977 if(
const VarDecl*PD = CS->getCatchParamDecl())
5983OS <<
"__except (";
5988llvm_unreachable(
"Invalid label statement in CFGBlock.");
5997I !=
E; ++I, ++j ) {
6002OS << llvm::format(
"%3d", j) <<
": ";
6004Helper.setStmtID(j);
6012OS.changeColor(raw_ostream::GREEN);
6016Helper.setBlockID(-1);
6019CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
6030 constraw_ostream::Colors Color = raw_ostream::BLUE;
6032OS.changeColor(Color);
6040OS.changeColor(Color);
6043I !=
E; ++I, ++i) {
6048 boolReachable =
true;
6051B = I->getPossiblyUnreachableBlock();
6056OS <<
"(Unreachable)";
6067 constraw_ostream::Colors Color = raw_ostream::MAGENTA;
6069OS.changeColor(Color);
6077OS.changeColor(Color);
6080I !=
E; ++I, ++i) {
6086 boolReachable =
true;
6089B = I->getPossiblyUnreachableBlock();
6095OS <<
"(Unreachable)";
6116StmtPrinterHelper Helper(
this, LO);
6122 for(
const_iteratorI = Blocks.begin(),
E= Blocks.end() ; I !=
E; ++I) {
6124 if(&(**I) == &getEntry() || &(**I) == &getExit())
6154StmtPrinterHelper Helper(cfg, LO);
6162CFGBlockTerminatorPrint TPrinter(OS,
nullptr,
PrintingPolicy(LO));
6168 boolAddQuotes)
const{
6170llvm::raw_string_ostream TempOut(Buf);
6193 if(llvm::any_of(*Blk, [](
const CFGElement&Elm) {
6194 if(std::optional<CFGStmt> StmtElm = Elm.
getAs<
CFGStmt>())
6195 if(isa<CXXThrowExpr>(StmtElm->getStmt()))
6214DFSWorkList.push_back(StartBlk);
6215 while(!DFSWorkList.empty()) {
6216 const CFGBlock*Blk = DFSWorkList.back();
6217DFSWorkList.pop_back();
6227 for(
const auto&Succ : Blk->
succs()) {
6228 if(
const CFGBlock*SuccBlk = Succ.getReachableBlock()) {
6232DFSWorkList.push_back(SuccBlk);
6261 const Stmt*Cond = StmtElem->getStmt();
6262 if(isa<ObjCForCollectionStmt>(Cond) || isa<DeclStmt>(Cond))
6275 Expr*
E=
nullptr;
6281 caseStmt::CXXForRangeStmtClass:
6282 E= cast<CXXForRangeStmt>(
Terminator)->getCond();
6285 caseStmt::ForStmtClass:
6289 caseStmt::WhileStmtClass:
6293 caseStmt::DoStmtClass:
6297 caseStmt::IfStmtClass:
6301 caseStmt::ChooseExprClass:
6305 caseStmt::IndirectGotoStmtClass:
6306 E= cast<IndirectGotoStmt>(
Terminator)->getTarget();
6309 caseStmt::SwitchStmtClass:
6313 caseStmt::BinaryConditionalOperatorClass:
6314 E= cast<BinaryConditionalOperator>(
Terminator)->getCond();
6317 caseStmt::ConditionalOperatorClass:
6318 E= cast<ConditionalOperator>(
Terminator)->getCond();
6321 caseStmt::BinaryOperatorClass:
6325 caseStmt::ObjCForCollectionStmtClass:
6342StmtPrinterHelper H(
this, LO);
6344llvm::ViewGraph(
this,
"CFG");
6356llvm::raw_string_ostream Out(OutStr);
6359 if(OutStr[0] ==
'\n') OutStr.erase(OutStr.begin());
6362 for(
unsignedi = 0; i != OutStr.length(); ++i)
6363 if(OutStr[i] ==
'\n') {
6365OutStr.insert(OutStr.begin()+i+1,
'l');
Defines the clang::ASTContext interface.
Defines enum values for all the target-independent builtin functions.
static StmtPrinterHelper * GraphHelper
static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, const CFGElement &E)
static const Expr * tryTransformToIntOrEnumConstant(const Expr *E)
Helper for tryNormalizeBinaryOperator.
static void print_initializer(raw_ostream &OS, StmtPrinterHelper &Helper, const CXXCtorInitializer *I)
static bool IsIntegerLiteralConstantExpr(const Expr *E)
Returns true on constant values based around a single IntegerLiteral.
static SourceLocation GetEndLoc(Decl *D)
static bool CanThrow(Expr *E, ASTContext &Ctx)
static bool isFallthroughStatement(const AttributedStmt *A)
static void print_block(raw_ostream &OS, const CFG *cfg, const CFGBlock &B, StmtPrinterHelper &Helper, bool print_edges, bool ShowColors)
static bool isImmediateSinkBlock(const CFGBlock *Blk)
static QualType getReferenceInitTemporaryType(const Expr *Init, bool *FoundMTE=nullptr)
Retrieve the type of the temporary object whose lifetime was extended by a local reference with the g...
static const VariableArrayType * FindVA(const Type *t)
static std::tuple< const Expr *, BinaryOperatorKind, const Expr * > tryNormalizeBinaryOperator(const BinaryOperator *B)
Tries to interpret a binary operator into Expr Op NumExpr form, if NumExpr is an integer literal or a...
static void print_construction_context(raw_ostream &OS, StmtPrinterHelper &Helper, const ConstructionContext *CC)
static bool shouldAddCase(bool &switchExclusivelyCovered, const Expr::EvalResult *switchCond, const CaseStmt *CS, ASTContext &Ctx)
static bool areExprTypesCompatible(const Expr *E1, const Expr *E2)
For an expression x == Foo && x == Bar, this determines whether the Foo and Bar are either of the sam...
static TryResult bothKnownTrue(TryResult R1, TryResult R2)
clang::CharUnits operator*(clang::CharUnits::QuantityType Scale, const clang::CharUnits &CU)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the ExceptionSpecificationType enumeration and various utility functions.
Defines the clang::Expr interface and subclasses for C++ expressions.
llvm::DenseSet< const void * > Visited
static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::LangOptions interface.
Defines the clang::SourceLocation class and associated facilities.
Defines various enumerations that describe declaration and type specifiers.
Defines the Objective-C statement AST node classes.
C Language Family Type Representation.
llvm::APInt getValue() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const ConstantArrayType * getAsConstantArrayType(QualType T) const
const LangOptions & getLangOpts() const
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
CanQualType BoundMemberTy
const ArrayType * getAsArrayType(QualType T) const
Type Query functions.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
AddrLabelExpr - The GNU address of label extension, representing &&label.
LabelDecl * getLabel() const
Represents a loop initializing the elements of an array.
OpaqueValueExpr * getCommonExpr() const
Get the common subexpression shared by all initializations (the source array).
Expr * getSubExpr() const
Get the initializer to use for each array element.
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Represents an attribute applied to a statement.
ArrayRef< const Attr * > getAttrs() const
BinaryConditionalOperator - The GNU extension to the conditional operator which allows the middle ope...
OpaqueValueExpr * getOpaqueValue() const
getOpaqueValue - Return the opaque value placeholder.
Expr * getCommon() const
getCommon - Return the common expression, written to the left of the condition.
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isLogicalOp(Opcode Opc)
static bool isRelationalOp(Opcode Opc)
static bool isAssignmentOp(Opcode Opc)
static bool isEqualityOp(Opcode Opc)
A class which contains all the information about a particular captured value.
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
BreakStmt - This represents a break.
void push_back(const_reference Elt, BumpVectorContext &C)
Represents C++ object destructor implicitly generated for automatic object or temporary bound to cons...
const VarDecl * getVarDecl() const
Represents C++ object destructor implicitly generated for base object in destructor.
This class represents a potential adjacent block in the CFG.
AdjacentBlock(CFGBlock *B, bool IsReachable)
Construct an AdjacentBlock with a possibly unreachable block.
CFGBlock * getReachableBlock() const
Get the reachable block, if one exists.
CFGBlock * getPossiblyUnreachableBlock() const
Get the potentially unreachable block.
unsigned IgnoreNullPredecessors
unsigned IgnoreDefaultsWithCoveredEnums
Represents a single basic block in a source-level CFG.
void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C)
void printTerminator(raw_ostream &OS, const LangOptions &LO) const
printTerminator - A simple pretty printer of the terminator of a CFGBlock.
void setLoopTarget(const Stmt *loopTarget)
bool isInevitablySinking() const
Returns true if the block would eventually end with a sink (a noreturn node).
size_t getIndexInCFG() const
void appendScopeBegin(const VarDecl *VD, const Stmt *S, BumpVectorContext &C)
static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src, const CFGBlock *Dst)
reverse_iterator rbegin()
void setTerminator(CFGTerminator Term)
void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C)
void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C)
void print(raw_ostream &OS, const CFG *cfg, const LangOptions &LO, bool ShowColors) const
print - A simple pretty printer of a CFGBlock that outputs to an ostream.
ElementList::const_iterator const_iterator
bool hasNoReturnElement() const
void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C)
void appendScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C)
void appendInitializer(CXXCtorInitializer *initializer, BumpVectorContext &C)
void printTerminatorJson(raw_ostream &Out, const LangOptions &LO, bool AddQuotes) const
printTerminatorJson - Pretty-prints the terminator in JSON format.
void appendNewAllocator(CXXNewExpr *NE, BumpVectorContext &C)
Stmt * Label
An (optional) label that prefixes the executable statements in the block.
CFGTerminator getTerminator() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C)
AdjacentBlocks::const_iterator const_pred_iterator
unsigned pred_size() const
void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C)
void appendCXXRecordTypedCall(Expr *E, const ConstructionContext *CC, BumpVectorContext &C)
pred_iterator pred_begin()
void appendCleanupFunction(const VarDecl *VD, BumpVectorContext &C)
void setLabel(Stmt *Statement)
unsigned getBlockID() const
void appendStmt(Stmt *statement, BumpVectorContext &C)
void setHasNoReturnElement()
const Expr * getLastCondition() const
void appendConstructor(CXXConstructExpr *CE, const ConstructionContext *CC, BumpVectorContext &C)
Stmt * getTerminatorCondition(bool StripParens=true)
void addSuccessor(AdjacentBlock Succ, BumpVectorContext &C)
Adds a (potentially unreachable) successor block to the current block.
void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C)
AdjacentBlocks::const_iterator const_succ_iterator
CFGTerminator Terminator
The terminator for a basic block that indicates the type of control-flow that occurs between a block ...
unsigned succ_size() const
Represents a function call that returns a C++ object by value.
static bool isCXXRecordTypedCall(const Expr *E)
Returns true when call expression CE needs to be represented by CFGCXXRecordTypedCall,...
virtual void compareBitwiseEquality(const BinaryOperator *B, bool isAlwaysTrue)
virtual void logicAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue)
virtual void compareBitwiseOr(const BinaryOperator *B)
Represents C++ constructor call.
Represents C++ object destructor generated from a call to delete.
const CXXDeleteExpr * getDeleteExpr() const
const CXXRecordDecl * getCXXRecordDecl() const
Represents a top-level expression in a basic block.
void dumpToStream(llvm::raw_ostream &OS) const
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
const CXXDestructorDecl * getDestructorDecl(ASTContext &astContext) const
Represents C++ base or member initializer from constructor's initialization list.
CXXCtorInitializer * getInitializer() const
Represents the point where the lifetime of an automatic object ends.
const VarDecl * getVarDecl() const
Represents the point where a loop ends.
Represents C++ object destructor implicitly generated for member object in destructor.
Represents C++ allocator call.
const CXXNewExpr * getAllocatorExpr() const
Represents beginning of a scope implicitly generated by the compiler on encountering a CompoundStmt.
const VarDecl * getVarDecl() const
Represents end of a scope implicitly generated by the compiler after the last Stmt in a CompoundStmt'...
const VarDecl * getVarDecl() const
const Stmt * getStmt() const
Represents C++ object destructor implicitly generated at the end of full expression for temporary obj...
Represents CFGBlock terminator statement.
@ TemporaryDtorsBranch
A branch in control flow of destructors of temporaries.
@ VirtualBaseBranch
A shortcut around virtual base initializers.
@ StmtBranch
A branch that corresponds to a statement in the code, such as an if-statement.
bool PruneTriviallyFalseEdges
bool AddStaticInitBranches
bool OmitImplicitValueInitializers
ForcedBlkExprs ** forcedBlkExprs
bool AddCXXDefaultInitExprInAggregates
bool AddCXXDefaultInitExprInCtors
bool alwaysAdd(const Stmt *stmt) const
bool AddRichCXXConstructors
bool AddVirtualBaseBranches
llvm::DenseMap< const Stmt *, const CFGBlock * > ForcedBlkExprs
bool MarkElidedCXXConstructors
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
unsigned size() const
Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...
void print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const
print - A simple pretty printer of a CFG that outputs to an ostream.
bool isLinear() const
Returns true if the CFG has no branches.
static std::unique_ptr< CFG > buildCFG(const Decl *D, Stmt *AST, ASTContext *C, const BuildOptions &BO)
Builds a CFG from an AST.
llvm::BumpPtrAllocator & getAllocator()
CFGBlock * createBlock()
Create a new block in the CFG.
CFGBlock * getIndirectGotoBlock()
void dump(const LangOptions &LO, bool ShowColors) const
dump - A simple pretty printer of a CFG that outputs to stderr.
void viewCFG(const LangOptions &LO) const
Represents a base class of a C++ class.
QualType getType() const
Retrieves the type of the base class.
Represents binding an expression to a temporary.
CXXTemporary * getTemporary()
CXXCatchStmt - This represents a C++ catch block.
Stmt * getHandlerBlock() const
VarDecl * getExceptionDecl() const
Represents a call to a C++ constructor.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Represents a C++ constructor within a class.
Represents a C++ base or member initializer.
bool isDelegatingInitializer() const
Determine whether this initializer is creating a delegating constructor.
Expr * getInit() const
Get the initializer.
TypeSourceInfo * getTypeSourceInfo() const
Returns the declarator information for a base class or delegating initializer.
bool isBaseInitializer() const
Determine whether this initializer is initializing a base class.
const Type * getBaseClass() const
If this is a base class initializer, returns the type of the base class.
FieldDecl * getAnyMember() const
A use of a default initializer in a constructor or in aggregate initialization.
Represents a delete expression for memory deallocation and destructor calls, e.g.
QualType getDestroyedType() const
Retrieve the type being destroyed.
Represents a C++ destructor within a class.
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Represents an explicit C++ type conversion that uses "functional" notation (C++ [expr....
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Represents a C++ struct/union/class.
bool hasTrivialDestructor() const
Determine whether this class has a trivial destructor (C++ [class.dtor]p3)
base_class_range vbases()
bool hasDefinition() const
CXXDestructorDecl * getDestructor() const
Returns the destructor decl for this class.
bool isAnyDestructorNoReturn() const
Returns true if the class destructor, or any implicitly invoked destructors are marked noreturn.
Represents a C++ functional cast expression that builds a temporary object.
Represents a C++ temporary.
const CXXDestructorDecl * getDestructor() const
A C++ throw-expression (C++ [except.throw]).
CXXTryStmt - A C++ try block, including all handlers.
CXXCatchStmt * getHandler(unsigned i)
unsigned getNumHandlers() const
CompoundStmt * getTryBlock()
A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
CaseStmt - Represent a case statement.
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
ChooseExpr - GNU builtin-in function __builtin_choose_expr.
CompoundStmt - This represents a group of statements like { stmt stmt }.
reverse_body_iterator body_rbegin()
Represents the canonical version of C arrays with a specified constant size.
ConstantExpr - An expression that occurs in a constant context and optionally the result of evaluatin...
Represents a single point (AST node) in the program that requires attention during construction of an...
@ ElidableConstructorKind
Construction context can be seen as a linked list of multiple layers.
static const ConstructionContextLayer * create(BumpVectorContext &C, const ConstructionContextItem &Item, const ConstructionContextLayer *Parent=nullptr)
const ConstructionContextItem & getItem() const
ConstructionContext's subclasses describe different ways of constructing an object in C++.
static const ConstructionContext * createFromLayers(BumpVectorContext &C, const ConstructionContextLayer *TopLayer)
Consume the construction context layer, together with its parent layers, and wrap it up into a comple...
@ CXX17ElidedCopyVariableKind
@ ElidedTemporaryObjectKind
@ SimpleTemporaryObjectKind
@ CXX17ElidedCopyConstructorInitializerKind
@ SimpleConstructorInitializerKind
@ SimpleReturnedValueKind
@ CXX17ElidedCopyReturnedValueKind
ContinueStmt - This represents a continue.
Represents a 'co_return' statement in the C++ Coroutines TS.
Expr * getOperand() const
Retrieve the operand of the 'co_return' statement.
Expr * getPromiseCall() const
Retrieve the promise call that results from this 'co_return' statement.
Represents an expression that might suspend coroutine execution; either a co_await or co_yield expres...
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
std::reverse_iterator< decl_iterator > reverse_decl_iterator
bool isSingleDecl() const
isSingleDecl - This method returns true if this DeclStmt refers to a single Decl.
decl_iterator decl_begin()
const Decl * getSingleDecl() const
reverse_decl_iterator decl_rend()
reverse_decl_iterator decl_rbegin()
Decl - This represents one declaration (or definition), e.g.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
SourceLocation getLocation() const
DoStmt - This represents a 'do/while' stmt.
Represents an expression â generally a full-expression â that introduces cleanups to be run at the en...
This represents one expression.
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
static QualType findBoundMemberType(const Expr *expr)
Given an expression of bound-member type, find the type of the member.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, SmallVectorImpl< PartialDiagnosticAt > *Diag=nullptr) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsBooleanCondition - Return true if this is a constant which we can fold and convert to a boo...
static bool isSameComparisonOperand(const Expr *E1, const Expr *E2)
Checks that the two Expr's will refer to the same value as a comparison operand.
bool isKnownToHaveBooleanValue(bool Semantic=true) const
isKnownToHaveBooleanValue - Return true if this is an integer expression that is known to return 0 or...
Represents a member of a struct/union/class.
ForStmt - This represents a 'for (init;cond;inc)' stmt.
VarDecl * getConditionVariable() const
Retrieve the variable declared in this "for" statement, if any.
DeclStmt * getConditionVariableDeclStmt()
If this ForStmt has a condition variable, return the faux DeclStmt associated with the creation of th...
const Expr * getSubExpr() const
Represents a function declaration or definition.
Represents a prototype with parameter type info, e.g.
FunctionType - C99 6.7.5.3 - Function Declarators.
This represents a GCC inline-assembly statement extension.
GotoStmt - This represents a direct goto.
LabelDecl * getLabel() const
IfStmt - This represents an if/then/else.
DeclStmt * getConditionVariableDeclStmt()
If this IfStmt has a condition variable, return the faux DeclStmt associated with the creation of tha...
VarDecl * getConditionVariable()
Retrieve the variable declared in this "if" statement, if any.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
IndirectGotoStmt - This represents an indirect goto.
Describes an C or C++ initializer list.
unsigned getNumInits() const
Expr ** getInits()
Retrieve the set of initializers.
LabelStmt - Represents a label, which has a substatement.
LabelDecl * getDecl() const
const char * getName() const
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
StorageDuration getStorageDuration() const
Retrieve the storage duration for the materialized temporary.
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getQualifiedNameAsString() const
This is a basic class for representing single OpenMP executable directive.
static llvm::iterator_range< used_clauses_child_iterator > used_clauses_children(ArrayRef< OMPClause * > Clauses)
Represents Objective-C's @catch statement.
const Stmt * getCatchBody() const
Represents Objective-C's @synchronized statement.
Represents Objective-C's @throw statement.
Represents Objective-C's @try ... @catch ... @finally statement.
const ObjCAtFinallyStmt * getFinallyStmt() const
Retrieve the @finally statement, if any.
const Stmt * getTryBody() const
Retrieve the @try body.
catch_range catch_stmts()
Represents Objective-C's @autoreleasepool Statement.
Represents Objective-C's collection statement.
An expression that sends a message to the given Objective-C object or class.
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
field_range fields() const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
CompoundStmt * getBlock() const
Expr * getFilterExpr() const
Represents a __leave statement.
CompoundStmt * getTryBlock() const
SEHFinallyStmt * getFinallyHandler() const
SEHExceptStmt * getExceptHandler() const
Returns 0 if not defined.
Scope - A scope is a transient data structure that is used while parsing the program.
Scope(Scope *Parent, unsigned ScopeFlags, DiagnosticsEngine &Diag)
Encodes a location in the source.
StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
CompoundStmt * getSubStmt()
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Stmt - This represents one statement.
void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation=0, StringRef NewlineSymbol="\n", const ASTContext *Context=nullptr) const
const Stmt * stripLabelLikeStatements() const
Strip off all label-like statements.
StmtClass getStmtClass() const
const char * getStmtClassName() const
SwitchStmt - This represents a 'switch' stmt.
bool isAllEnumCasesCovered() const
Returns true if the SwitchStmt is a switch of an enum value and all cases have been explicitly covere...
VarDecl * getConditionVariable()
Retrieve the variable declared in this "switch" statement, if any.
SwitchCase * getSwitchCaseList()
DeclStmt * getConditionVariableDeclStmt()
If this SwitchStmt has a condition variable, return the faux DeclStmt associated with the creation of...
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
QualType getType() const
Return the type wrapped by this type source info.
The base class of the type hierarchy.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isBlockPointerType() const
bool isFunctionPointerType() const
bool isReferenceType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const Type * getBaseElementTypeUnsafe() const
Get the base element type of this type, potentially discarding type qualifiers.
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
const T * getAs() const
Member-template getAs<specific type>'.
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
const Expr * getInit() const
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Represents a C array with a specified size that is not an integer-constant-expression.
WhileStmt - This represents a 'while' stmt.
DeclStmt * getConditionVariableDeclStmt()
If this WhileStmt has a condition variable, return the faux DeclStmt associated with the creation of ...
VarDecl * getConditionVariable()
Retrieve the variable declared in this "while" statement, if any.
const AstTypeMatcher< ArrayType > arrayType
Matches all kinds of arrays.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
constexpr Variable var(Literal L)
Returns the variable of L.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
bool Sub(InterpState &S, CodePtr OpPC)
bool NE(InterpState &S, CodePtr OpPC)
bool LE(InterpState &S, CodePtr OpPC)
bool Cast(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType)
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
@ SD_FullExpression
Full-expression storage duration (for temporaries).
std::string JsonFormat(StringRef RawSR, bool AddQuotes)
bool operator!=(CanQual< T > x, CanQual< U > y)
const FunctionProtoType * T
Expr * extractElementInitializerFromNestedAILE(const ArrayInitLoopExpr *AILE)
Diagnostic wrappers for TextAPI types for error reporting.
float __ovld __cnfn distance(float, float)
Returns the distance between p0 and p1.
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.
Describes how types, statements, expressions, and declarations should be printed.
unsigned IncludeNewlines
When true, include newlines after statements like "break", etc.
Iterator for iterating over Stmt * arrays that contain only T *.
DOTGraphTraits(bool isSimple=false)
static std::string getNodeLabel(const CFGBlock *Node, const CFG *Graph)
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4