27#include "llvm/ADT/DenseMap.h"
28#include "llvm/ADT/DenseSet.h"
29#include "llvm/ADT/MapVector.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/ScopeExit.h"
32#include "llvm/Support/ErrorHandling.h"
38#define DEBUG_TYPE "dataflow"
51 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1,
52 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) {
53 llvm::DenseMap<const ValueDecl *, StorageLocation *>
Result;
54 for (
auto &Entry : DeclToLoc1) {
55 auto It = DeclToLoc2.find(Entry.first);
56 if (It != DeclToLoc2.end() && Entry.second == It->second)
57 Result.insert({Entry.first, Entry.second});
67template <
typename MapT>
71 for (
const auto &Entry : Map2) {
72 [[maybe_unused]]
auto [It, Inserted] =
Result.insert(Entry);
75 assert(It->second == Entry.second);
89 case Value::Kind::Integer:
90 case Value::Kind::Pointer:
107 switch (Model.compare(
Type, Val1, Env1, Val2, Env2)) {
115 llvm_unreachable(
"All cases covered in switch");
145 auto &A = JoinedEnv.
arena();
149 A.makeEquals(JoinedVal, Expr1)),
151 A.makeEquals(JoinedVal, Expr2))));
152 return &A.makeBoolValue(JoinedVal);
157 Model.join(
Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);
182 bool TruePrev = PrevEnv.
proves(PrevBool.formula());
183 bool TrueCur = CurrentEnv.
proves(CurBool.formula());
184 if (TruePrev && TrueCur)
186 if (!TruePrev && !TrueCur &&
197 if (
auto Result = Model.widen(
Type, Prev, PrevEnv, Current, CurrentEnv))
207template <
typename Key>
209 const llvm::MapVector<Key, Value *> &Map2,
213 for (
auto &Entry : Map1) {
215 assert(K !=
nullptr);
217 Value *Val = Entry.second;
218 assert(Val !=
nullptr);
220 auto It = Map2.find(K);
221 if (It == Map2.end())
223 assert(It->second !=
nullptr);
235static llvm::MapVector<const StorageLocation *, Value *>
236joinLocToVal(
const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
237 const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2,
240 llvm::MapVector<const StorageLocation *, Value *>
Result;
241 for (
auto &Entry : LocToVal) {
243 assert(Loc !=
nullptr);
245 Value *Val = Entry.second;
246 assert(Val !=
nullptr);
248 auto It = LocToVal2.find(Loc);
249 if (It == LocToVal2.end())
251 assert(It->second !=
nullptr);
254 Loc->
getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) {
255 Result.insert({Loc, JoinedVal});
264template <
typename Key>
265static llvm::MapVector<Key, Value *>
267 const llvm::MapVector<Key, Value *> &PrevMap,
270 llvm::MapVector<Key, Value *> WidenedMap;
271 for (
auto &Entry : CurMap) {
273 assert(K !=
nullptr);
275 Value *Val = Entry.second;
276 assert(Val !=
nullptr);
278 auto PrevIt = PrevMap.find(K);
279 if (PrevIt == PrevMap.end())
281 assert(PrevIt->second !=
nullptr);
284 WidenedMap.insert({K, Val});
289 K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model);
290 WidenedMap.insert({K, WidenedVal});
303class ResultObjectVisitor :
public AnalysisASTVisitor {
309 explicit ResultObjectVisitor(
310 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap,
311 RecordStorageLocation *LocForRecordReturnVal,
312 DataflowAnalysisContext &DACtx)
313 : ResultObjectMap(ResultObjectMap),
314 LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {}
320 void traverseConstructorInits(
const CXXConstructorDecl *Ctor,
321 RecordStorageLocation *ThisPointeeLoc) {
322 assert(ThisPointeeLoc !=
nullptr);
323 for (
const CXXCtorInitializer *Init : Ctor->inits()) {
324 Expr *InitExpr = Init->getInit();
325 if (
FieldDecl *Field = Init->getMember();
326 Field !=
nullptr && Field->getType()->isRecordType()) {
328 ThisPointeeLoc->getChild(*Field)));
329 }
else if (
Init->getBaseClass()) {
330 PropagateResultObject(InitExpr, ThisPointeeLoc);
335 TraverseStmt(InitExpr);
339 if (
auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr))
340 TraverseStmt(DefaultInit->getExpr());
344 bool VisitVarDecl(VarDecl *VD)
override {
345 if (VD->getType()->isRecordType() && VD->hasInit())
346 PropagateResultObject(
352 bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE)
override {
353 if (MTE->getType()->isRecordType())
354 PropagateResultObject(
360 bool VisitReturnStmt(ReturnStmt *Return)
override {
361 Expr *
RetValue = Return->getRetValue();
364 PropagateResultObject(
RetValue, LocForRecordReturnVal);
368 bool VisitExpr(Expr *E)
override {
374 if (E->isPRValue() && E->getType()->isRecordType() &&
375 !ResultObjectMap.contains(E))
376 PropagateResultObject(
382 PropagateResultObjectToRecordInitList(
const RecordInitListHelper &InitList,
383 RecordStorageLocation *Loc) {
384 for (
auto [Base,
Init] : InitList.base_inits()) {
385 assert(
Base->getType().getCanonicalType() ==
386 Init->getType().getCanonicalType());
391 PropagateResultObject(
Init, Loc);
394 for (
auto [Field,
Init] : InitList.field_inits()) {
397 if (
Field->getType()->isRecordType())
398 PropagateResultObject(
406 void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) {
407 if (!E->isPRValue() || !E->getType()->isRecordType()) {
414 ResultObjectMap[E] = Loc;
433 if (
auto *Op = dyn_cast<BinaryOperator>(E);
434 Op && Op->getOpcode() == BO_Cmp) {
439 if (
auto *InitList = dyn_cast<InitListExpr>(E)) {
440 if (!InitList->isSemanticForm())
442 if (InitList->isTransparent()) {
443 PropagateResultObject(InitList->getInit(0), Loc);
447 PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList),
452 if (
auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(E)) {
453 PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList),
458 if (
auto *Op = dyn_cast<BinaryOperator>(E); Op && Op->isCommaOp()) {
459 PropagateResultObject(Op->getRHS(), Loc);
463 if (
auto *Cond = dyn_cast<AbstractConditionalOperator>(E)) {
464 PropagateResultObject(Cond->getTrueExpr(), Loc);
465 PropagateResultObject(Cond->getFalseExpr(), Loc);
469 if (
auto *SE = dyn_cast<StmtExpr>(E)) {
470 PropagateResultObject(
cast<Expr>(SE->getSubStmt()->body_back()), Loc);
474 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(E)) {
475 PropagateResultObject(DIE->getExpr(), Loc);
481 SmallVector<Stmt *, 1>
Children(E->child_begin(), E->child_end());
492 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;
493 RecordStorageLocation *LocForRecordReturnVal;
494 DataflowAnalysisContext &DACtx;
500 using BaseVisitor = AnalysisASTVisitor;
503 ThisExprOverridesVisitor(
504 RecordStorageLocation *ThisPointeeLoc,
505 const llvm::DenseMap<const Expr *, RecordStorageLocation *>
507 llvm::DenseMap<const CXXThisExpr *, RecordStorageLocation *>
509 : DefaultThisPointeeLoc(ThisPointeeLoc), ResultObjectMap(ResultObjectMap),
510 ThisExprOverrides(ThisExprOverrides) {
511 ThisLocations.push(DefaultThisPointeeLoc);
514 void traverseConstructorInits(
const CXXConstructorDecl *Ctor) {
515 for (
const CXXCtorInitializer *
Init : Ctor->inits()) {
516 TraverseStmt(
Init->getInit());
520 bool TraverseInitListExpr(InitListExpr *ILE)
override {
521 if (!ILE->isSemanticForm() || ILE->isTransparent()) {
522 BaseVisitor::TraverseInitListExpr(ILE);
525 bool IsRecordType = ILE->getType()->isRecordType();
527 auto It = ResultObjectMap.find(ILE);
528 if (It == ResultObjectMap.end()) {
529 llvm_unreachable(
"InitListExpr not found in ResultObjectMap");
532 InitListLocations.push(It->second);
534 BaseVisitor::TraverseInitListExpr(ILE);
536 InitListLocations.pop();
540 bool TraverseCXXParenListInitExpr(CXXParenListInitExpr *PLIE)
override {
541 auto It = ResultObjectMap.find(PLIE);
542 if (It == ResultObjectMap.end()) {
543 llvm_unreachable(
"CXXParenListInitExpr not found in ResultObjectMap");
546 InitListLocations.push(It->second);
547 BaseVisitor::TraverseCXXParenListInitExpr(PLIE);
548 InitListLocations.pop();
552 bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *CDIE)
override {
553 bool HasInitListLocations = !InitListLocations.empty();
554 if (HasInitListLocations) {
555 auto *Loc = InitListLocations.top();
556 ThisLocations.push(Loc);
558 BaseVisitor::TraverseCXXDefaultInitExpr(CDIE);
559 if (HasInitListLocations)
564 bool TraverseCXXThisExpr(CXXThisExpr *This)
override {
565 assert(!ThisLocations.empty());
566 auto *Loc = ThisLocations.top();
567 if (Loc != DefaultThisPointeeLoc)
568 ThisExprOverrides[
This] = Loc;
573 RecordStorageLocation *DefaultThisPointeeLoc;
575 std::stack<RecordStorageLocation *> ThisLocations;
578 std::stack<RecordStorageLocation *> InitListLocations;
581 const llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;
584 llvm::DenseMap<const CXXThisExpr *, RecordStorageLocation *>
591 if (InitialTargetStmt ==
nullptr)
594 if (InitialTargetFunc ==
nullptr) {
597 std::make_shared<PrValueToResultObject>(buildResultObjectMap(
602 std::make_shared<ThisExprOverridesMap>(buildThisExprOverridesMap(
610 for (
const auto *ParamDecl : InitialTargetFunc->parameters()) {
611 assert(ParamDecl !=
nullptr);
615 if (InitialTargetFunc->getReturnType()->isRecordType())
619 if (
const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) {
620 auto *Parent = MethodDecl->getParent();
621 assert(Parent !=
nullptr);
623 if (Parent->isLambda()) {
624 for (
const auto &
Capture : Parent->captures()) {
625 if (
Capture.capturesVariable()) {
629 }
else if (
Capture.capturesThis()) {
630 if (
auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {
633 SurroundingMethodDecl->getFunctionObjectParameterType();
636 }
else if (
auto *FieldBeingInitialized =
637 dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) {
645 assert(
false &&
"Unexpected this-capturing lambda context.");
649 }
else if (MethodDecl->isImplicitObjectMemberFunction()) {
650 QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
665 std::make_shared<PrValueToResultObject>(buildResultObjectMap(
667 LocForRecordReturnVal));
670 std::make_shared<ThisExprOverridesMap>(buildThisExprOverridesMap(
678void Environment::initFieldsGlobalsAndFuncs(
const ReferencedDecls &Referenced) {
681 DACtx->addModeledFields(Referenced.
Fields);
705 Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken);
711 return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
717 if (
const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(
Call)) {
718 if (
const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
727 if (
Call->getType()->isRecordType() &&
Call->isPRValue())
730 Env.pushCallInternal(
Call->getDirectCallee(),
742 Env.pushCallInternal(
Call->getConstructor(),
748void Environment::pushCallInternal(
const FunctionDecl *FuncDecl,
756 CallStack.push_back(FuncDecl);
764 for (
unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
765 assert(ParamIt != FuncDecl->
param_end());
766 const VarDecl *Param = *ParamIt;
770 ResultObjectMap = std::make_shared<PrValueToResultObject>(
772 LocForRecordReturnVal));
774 std::make_shared<ThisExprOverridesMap>(buildThisExprOverridesMap(
786 this->LocToVal = std::move(CalleeEnv.LocToVal);
787 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
789 if (
Call->isGLValue()) {
790 if (CalleeEnv.ReturnLoc !=
nullptr)
792 }
else if (!
Call->getType()->isVoidType()) {
793 if (CalleeEnv.ReturnVal !=
nullptr)
801 this->LocToVal = std::move(CalleeEnv.LocToVal);
802 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
807 assert(DACtx ==
Other.DACtx);
809 if (ReturnVal !=
Other.ReturnVal)
812 if (ReturnLoc !=
Other.ReturnLoc)
815 if (LocForRecordReturnVal !=
Other.LocForRecordReturnVal)
818 if (ThisPointeeLoc !=
Other.ThisPointeeLoc)
821 if (DeclToLoc !=
Other.DeclToLoc)
824 if (ExprToLoc !=
Other.ExprToLoc)
838 assert(DACtx == PrevEnv.DACtx);
839 assert(ReturnVal == PrevEnv.ReturnVal);
840 assert(ReturnLoc == PrevEnv.ReturnLoc);
841 assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal);
842 assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
843 assert(ThisExprOverrides == PrevEnv.ThisExprOverrides);
844 assert(CallStack == PrevEnv.CallStack);
845 assert(ResultObjectMap == PrevEnv.ResultObjectMap);
846 assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
847 assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);
857 assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
858 assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());
859 assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
866 if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
867 ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
868 ExprToVal.size() != PrevEnv.ExprToVal.size() ||
869 LocToVal.size() != PrevEnv.LocToVal.size())
878 assert(EnvA.DACtx == EnvB.DACtx);
879 assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal);
880 assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
881 assert(EnvA.ThisExprOverrides == EnvB.ThisExprOverrides);
882 assert(EnvA.CallStack == EnvB.CallStack);
883 assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
884 assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
885 assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);
889 JoinedEnv.CallStack = EnvA.CallStack;
890 JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
891 JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
892 JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
893 JoinedEnv.ThisExprOverrides = EnvA.ThisExprOverrides;
894 JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
895 JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;
899 JoinedEnv.ReturnVal =
nullptr;
901 JoinedEnv.ReturnVal =
902 joinValues(
Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
903 EnvB, JoinedEnv, Model);
906 if (EnvA.ReturnLoc == EnvB.ReturnLoc)
907 JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
909 JoinedEnv.ReturnLoc =
nullptr;
916 EnvA.FlowConditionToken, EnvB.FlowConditionToken);
919 joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);
922 JoinedEnv.ExprToVal =
joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);
923 JoinedEnv.ExprToLoc =
joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
933 if (Val1 ==
nullptr || Val2 ==
nullptr)
948 return DACtx->createStorageLocation(
Type);
955 return DACtx->getStableStorageLocation(D);
962 return DACtx->getStableStorageLocation(E);
966 assert(!DeclToLoc.contains(&D));
973 DeclToLoc[&D] = &Loc;
977 auto It = DeclToLoc.find(&D);
978 if (It == DeclToLoc.end())
995 assert(!ExprToLoc.contains(&CanonE));
996 ExprToLoc[&CanonE] = &Loc;
1004 return It == ExprToLoc.end() ?
nullptr : &*It->second;
1012 assert(ResultObjectMap !=
nullptr);
1014 assert(Loc !=
nullptr);
1019 DACtx->getStableStorageLocation(RecordPRValue));
1024 return DACtx->getOrCreateNullPointerValue(PointeeType);
1029 llvm::DenseSet<QualType> Visited;
1030 int CreatedValuesCount = 0;
1033 llvm::errs() <<
"Attempting to initialize a huge value of type: " <<
Type
1041 LocToVal[&Loc] = &Val;
1050 ExprToVal[&CanonE] = &Val;
1056 return LocToVal.lookup(&Loc);
1072 return It == ExprToVal.end() ?
nullptr : It->second;
1076 if (It == ExprToLoc.end())
1082 llvm::DenseSet<QualType> Visited;
1083 int CreatedValuesCount = 0;
1084 Value *Val = createValueUnlessSelfReferential(
Type, Visited, 0,
1085 CreatedValuesCount);
1087 llvm::errs() <<
"Attempting to initialize a huge value of type: " <<
Type
1093Value *Environment::createValueUnlessSelfReferential(
1094 QualType Type, llvm::DenseSet<QualType> &Visited,
int Depth,
1095 int &CreatedValuesCount) {
1096 assert(!
Type.isNull());
1106 CreatedValuesCount++;
1114 CreatedValuesCount++;
1118 if (Type->isPointerType()) {
1119 CreatedValuesCount++;
1120 QualType PointeeType = Type->getPointeeType();
1121 StorageLocation &PointeeLoc =
1122 createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount);
1131Environment::createLocAndMaybeValue(QualType Ty,
1132 llvm::DenseSet<QualType> &Visited,
1133 int Depth,
int &CreatedValuesCount) {
1134 if (!Visited.insert(Ty.getCanonicalType()).second)
1136 llvm::scope_exit EraseVisited(
1137 [&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); });
1139 Ty = Ty.getNonReferenceType();
1141 if (Ty->isRecordType()) {
1149 if (
Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth,
1150 CreatedValuesCount))
1158 llvm::DenseSet<QualType> &Visited,
1160 int &CreatedValuesCount) {
1161 auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
1162 if (FieldType->isRecordType()) {
1165 Visited, Depth + 1, CreatedValuesCount);
1169 if (!Visited.insert(FieldType.getCanonicalType()).second)
1171 if (
Value *Val = createValueUnlessSelfReferential(
1172 FieldType, Visited, Depth + 1, CreatedValuesCount))
1174 Visited.erase(FieldType.getCanonicalType());
1178 for (
const FieldDecl *Field : DACtx->getModeledFields(
Type)) {
1179 assert(Field !=
nullptr);
1180 QualType FieldType =
Field->getType();
1182 if (FieldType->isReferenceType()) {
1183 Loc.setChild(*Field,
1184 &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
1185 CreatedValuesCount));
1187 StorageLocation *FieldLoc = Loc.getChild(*Field);
1188 assert(FieldLoc !=
nullptr);
1192 for (
const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(
Type)) {
1195 assert(!FieldType->isReferenceType());
1196 initField(FieldType, Loc.getSyntheticField(FieldName));
1202 const Expr *InitExpr) {
1203 if (Ty->isReferenceType()) {
1209 return *InitExprLoc;
1216 return createObjectInternal(D, Ty.getNonReferenceType(),
nullptr);
1219 StorageLocation &Loc =
1222 if (Ty->isRecordType()) {
1223 auto &RecordLoc = cast<RecordStorageLocation>(Loc);
1225 initializeFieldsWithValues(RecordLoc);
1227 Value *Val = nullptr;
1242 Val = getValue(*InitExpr);
1244 Val = createValue(Ty);
1246 setValue(Loc, *Val);
1253 DACtx->addFlowConditionConstraint(FlowConditionToken, F);
1257 return DACtx->flowConditionImplies(FlowConditionToken, F);
1261 return DACtx->flowConditionAllows(FlowConditionToken, F);
1265 llvm::DenseMap<const StorageLocation *, std::string> LocToName;
1266 if (LocForRecordReturnVal !=
nullptr)
1267 LocToName[LocForRecordReturnVal] =
"(returned record)";
1268 if (ThisPointeeLoc !=
nullptr)
1269 LocToName[ThisPointeeLoc] =
"this";
1271 OS <<
"DeclToLoc:\n";
1272 for (
auto [D, L] : DeclToLoc) {
1273 auto Iter = LocToName.insert({L, D->getNameAsString()}).first;
1274 OS <<
" [" << Iter->second <<
", " << L <<
"]\n";
1276 OS <<
"ExprToLoc:\n";
1277 for (
auto [E, L] : ExprToLoc)
1278 OS <<
" [" << E <<
", " << L <<
"]\n";
1280 OS <<
"ExprToVal:\n";
1281 for (
auto [E,
V] : ExprToVal)
1282 OS <<
" [" << E <<
", " <<
V <<
": " << *
V <<
"]\n";
1284 OS <<
"LocToVal:\n";
1285 for (
auto [L,
V] : LocToVal) {
1287 if (
auto Iter = LocToName.find(L); Iter != LocToName.end())
1288 OS <<
" (" << Iter->second <<
")";
1289 OS <<
", " <<
V <<
": " << *
V <<
"]\n";
1293 if (
Func->getReturnType()->isReferenceType()) {
1294 OS <<
"ReturnLoc: " << ReturnLoc;
1295 if (
auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end())
1296 OS <<
" (" << Iter->second <<
")";
1298 }
else if (
Func->getReturnType()->isRecordType() ||
1300 OS <<
"LocForRecordReturnVal: " << LocForRecordReturnVal <<
"\n";
1301 }
else if (!
Func->getReturnType()->isVoidType()) {
1302 if (ReturnVal ==
nullptr)
1303 OS <<
"ReturnVal: nullptr\n";
1305 OS <<
"ReturnVal: " << *ReturnVal <<
"\n";
1309 OS <<
"ThisPointeeLoc: " << ThisPointeeLoc <<
"\n";
1314 DACtx->dumpFlowCondition(FlowConditionToken, OS);
1319Environment::PrValueToResultObject Environment::buildResultObjectMap(
1325 PrValueToResultObject Map = buildResultObjectMap(
1326 DACtx, FuncDecl->
getBody(), ThisPointeeLoc, LocForRecordReturnVal);
1328 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1329 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl))
1330 Visitor.traverseConstructorInits(Ctor, ThisPointeeLoc);
1335Environment::PrValueToResultObject Environment::buildResultObjectMap(
1336 DataflowAnalysisContext *DACtx,
Stmt *S,
1337 RecordStorageLocation *ThisPointeeLoc,
1338 RecordStorageLocation *LocForRecordReturnVal) {
1339 PrValueToResultObject Map;
1340 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1341 Visitor.TraverseStmt(S);
1345Environment::ThisExprOverridesMap Environment::buildThisExprOverridesMap(
1346 const FunctionDecl *FuncDecl, RecordStorageLocation *ThisPointeeLoc,
1347 const PrValueToResultObject &ResultObjectMap) {
1348 assert(FuncDecl->doesThisDeclarationHaveABody());
1350 ThisExprOverridesMap Map = buildThisExprOverridesMap(
1351 FuncDecl->getBody(), ThisPointeeLoc, ResultObjectMap);
1353 ThisExprOverridesVisitor Visitor(ThisPointeeLoc, ResultObjectMap, Map);
1354 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
1355 Visitor.traverseConstructorInits(Ctor);
1360Environment::ThisExprOverridesMap Environment::buildThisExprOverridesMap(
1362 const PrValueToResultObject &ResultObjectMap) {
1363 ThisExprOverridesMap Map;
1364 ThisExprOverridesVisitor Visitor(ThisPointeeLoc, ResultObjectMap, Map);
1365 Visitor.TraverseStmt(S);
1372 if (ImplicitObject ==
nullptr)
1379 return cast_or_null<RecordStorageLocation>(
1386 if (
Base ==
nullptr)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool IsUnionField, bool InUnion, const Descriptor *D, unsigned FieldOffset)
Defines the clang::Expr interface and subclasses for C++ expressions.
static PRESERVE_NONE bool RetValue(InterpState &S)
C Language Family Type Representation.
Represents a member of a struct/union/class.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
CanQualType getCanonicalTagType(const TagDecl *TD) const
Represents a call to a C++ constructor.
Represents a call to a member function that may be written either with member call syntax (e....
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
DeclContext * getParent()
getParent - Returns the containing DeclContext.
ASTContext & getASTContext() const LLVM_READONLY
This represents one expression.
Represents a function declaration or definition.
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
param_iterator param_end()
param_iterator param_begin()
bool doesThisDeclarationHaveABody() const
Returns whether this specific declaration of the function has a body.
FunctionDecl * getDefinition()
Get the definition for this declaration.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
A (possibly-)qualified type.
Represents a struct/union/class.
Stmt - This represents one statement.
The base class of the type hierarchy.
bool isBooleanType() const
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
bool isReferenceType() const
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
bool isRecordType() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
Specialization of RecursiveASTVisitor that visits those nodes that are relevant to the dataflow analy...
const Formula & makeAtomRef(Atom A)
Returns a formula for the variable A.
const Formula & makeNot(const Formula &Val)
Returns a formula for the negation of Val.
std::enable_if_t< std::is_base_of< StorageLocation, T >::value, T & > create(Args &&...args)
Creates a T (some subclass of StorageLocation), forwarding args to the constructor,...
Owns objects that encompass the state of a program and stores context that is used during dataflow an...
Atom joinFlowConditions(Atom FirstToken, Atom SecondToken)
Creates a new flow condition that represents the disjunction of the flow conditions identified by Fir...
Supplements Environment with non-standard comparison and join operations.
Holds the state of the program (store and heap) at a given program point.
bool allows(const Formula &) const
Returns true if the formula may be true when this point is reached.
LatticeEffect widen(const Environment &PrevEnv, Environment::ValueModel &Model)
Widens the environment point-wise, using PrevEnv as needed to inform the approximation.
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
RecordStorageLocation * getThisPointeeStorageLocation() const
Returns the storage location assigned to the this pointee in the environment or null if the this poin...
Environment pushCall(const CallExpr *Call) const
Creates and returns an environment to use for an inline analysis of the callee.
StorageLocation * getStorageLocation(const ValueDecl &D) const
Returns the storage location assigned to D in the environment, or null if D isn't assigned a storage ...
LLVM_DUMP_METHOD void dump() const
BoolValue & makeTopBoolValue() const
Returns a unique instance of boolean Top.
void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type)
Initializes the fields (including synthetic fields) of Loc with values, unless values of the field ty...
StorageLocation & createStorageLocation(QualType Type)
Creates a storage location appropriate for Type.
Environment fork() const
Returns a new environment that is a copy of this one.
void popCall(const CallExpr *Call, const Environment &CalleeEnv)
Moves gathered information back into this from a CalleeEnv created via pushCall.
bool equivalentTo(const Environment &Other, Environment::ValueModel &Model) const
Returns true if and only if the environment is equivalent to Other, i.e the two environments:
BoolValue & makeAtomicBoolValue() const
Returns an atomic boolean value.
bool proves(const Formula &) const
Returns true if the formula is always true when this point is reached.
Value * getValue(const StorageLocation &Loc) const
Returns the value assigned to Loc in the environment or null if Loc isn't assigned a value in the env...
const FunctionDecl * getCurrentFunc() const
Returns the function currently being analyzed, or null if the code being analyzed isn't part of a fun...
BoolValue & getBoolLiteralValue(bool Value) const
Returns a symbolic boolean value that models a boolean literal equal to Value
StorageLocation & createObject(QualType Ty, const Expr *InitExpr=nullptr)
Creates an object (i.e.
void assume(const Formula &)
Record a fact that must be true if this point in the program is reached.
Environment(DataflowAnalysisContext &DACtx, Atom FlowConditionToken)
Creates an environment that uses DACtx to store objects that encompass the state of a program.
static Value * joinValues(QualType Ty, Value *Val1, const Environment &Env1, Value *Val2, const Environment &Env2, Environment &JoinedEnv, Environment::ValueModel &Model)
Returns a value that approximates both Val1 and Val2, or null if no such value can be produced.
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc)
Assigns Loc as the storage location of D in the environment.
void removeDecl(const ValueDecl &D)
Removes the location assigned to D in the environment (if any).
RecordStorageLocation & getResultObjectLocation(const Expr &RecordPRValue) const
Returns the location of the result object for a record-type prvalue.
ExprJoinBehavior
How to treat expression state (ExprToLoc and ExprToVal) in a join.
static Environment join(const Environment &EnvA, const Environment &EnvB, Environment::ValueModel &Model, ExprJoinBehavior ExprBehavior)
Joins two environments by taking the intersection of storage locations and values that are stored in ...
Value * createValue(QualType Type)
Creates a value appropriate for Type, if Type is supported, otherwise returns null.
void setValue(const StorageLocation &Loc, Value &Val)
Assigns Val as the value of Loc in the environment.
void setThisPointeeStorageLocation(RecordStorageLocation &Loc)
Sets the storage location assigned to the this pointee in the environment.
Atom getFlowConditionToken() const
Returns a boolean variable that identifies the flow condition (FC).
bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const
Returns whether this Environment can be extended to analyze the given Callee (i.e.
std::enable_if_t< std::is_base_of_v< StorageLocation, T >, T * > get(const ValueDecl &D) const
Returns the result of casting getStorageLocation(...) to a subclass of StorageLocation (using cast_or...
void initialize()
Assigns storage locations and values to all parameters, captures, global variables,...
Models a symbolic pointer. Specifically, any value of type T*.
A storage location for a record (struct, class, or union).
Base class for elements of the local variable store and of the heap.
Base class for all values computed by abstract interpretation.
static bool compareKeyToValueMaps(const llvm::MapVector< Key, Value * > &Map1, const llvm::MapVector< Key, Value * > &Map2, const Environment &Env1, const Environment &Env2, Environment::ValueModel &Model)
static llvm::DenseMap< const ValueDecl *, StorageLocation * > intersectDeclToLoc(const llvm::DenseMap< const ValueDecl *, StorageLocation * > &DeclToLoc1, const llvm::DenseMap< const ValueDecl *, StorageLocation * > &DeclToLoc2)
Returns a map consisting of key-value entries that are present in both maps.
static bool equateUnknownValues(Value::Kind K)
bool areEquivalentValues(const Value &Val1, const Value &Val2)
An equivalence relation for values.
static llvm::MapVector< Key, Value * > widenKeyToValueMap(const llvm::MapVector< Key, Value * > &CurMap, const llvm::MapVector< Key, Value * > &PrevMap, Environment &CurEnv, const Environment &PrevEnv, Environment::ValueModel &Model, LatticeEffect &Effect)
static constexpr int MaxCompositeValueDepth
static constexpr int MaxCompositeValueSize
ReferencedDecls getReferencedDecls(const FunctionDecl &FD)
Returns declarations that are declared in or referenced from FD.
RecordStorageLocation * getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env)
Returns the storage location for the implicit object of a CXXMemberCallExpr, or null if none is defin...
static WidenResult widenDistinctValues(QualType Type, Value &Prev, const Environment &PrevEnv, Value &Current, Environment &CurrentEnv, Environment::ValueModel &Model)
const Expr & ignoreCFGOmittedNodes(const Expr &E)
Skip past nodes that the CFG does not emit.
static llvm::MapVector< const StorageLocation *, Value * > joinLocToVal(const llvm::MapVector< const StorageLocation *, Value * > &LocToVal, const llvm::MapVector< const StorageLocation *, Value * > &LocToVal2, const Environment &Env1, const Environment &Env2, Environment &JoinedEnv, Environment::ValueModel &Model)
static MapT joinExprMaps(const MapT &Map1, const MapT &Map2)
static bool compareDistinctValues(QualType Type, Value &Val1, const Environment &Env1, Value &Val2, const Environment &Env2, Environment::ValueModel &Model)
RecordStorageLocation * getBaseObjectLocation(const MemberExpr &ME, const Environment &Env)
Returns the storage location for the base object of a MemberExpr, or null if none is defined in the e...
static Value * joinDistinctValues(QualType Type, Value &Val1, const Environment &Env1, Value &Val2, const Environment &Env2, Environment &JoinedEnv, Environment::ValueModel &Model)
Attempts to join distinct values Val1 and Val2 in Env1 and Env2, respectively, of the same type Type.
LatticeEffect
Effect indicating whether a lattice operation resulted in a new value.
bool This(InterpState &S, CodePtr OpPC)
Top level wrappers for InstallAPI frontend operations.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Result
The result type of a method or function.
const FunctionProtoType * T
@ Type
The name was classified as a type.
U cast(CodeGen::Address addr)
@ Other
Other implicit parameter.
A collection of several types of declarations, all referenced from the same function.
llvm::SetVector< const VarDecl * > Globals
All variables with static storage duration, notably including static member variables and static vari...
FieldSet Fields
Non-static member variables.
llvm::SetVector< const FunctionDecl * > Functions
Free functions and member functions which are referenced (but not necessarily called).
The result of a widen operation.