25#include "llvm/ADT/DenseMap.h"
26#include "llvm/ADT/DenseSet.h"
27#include "llvm/ADT/MapVector.h"
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/ScopeExit.h"
30#include "llvm/Support/ErrorHandling.h"
35#define DEBUG_TYPE "dataflow"
48 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1,
49 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) {
50 llvm::DenseMap<const ValueDecl *, StorageLocation *>
Result;
51 for (
auto &Entry : DeclToLoc1) {
52 auto It = DeclToLoc2.find(Entry.first);
53 if (It != DeclToLoc2.end() && Entry.second == It->second)
54 Result.insert({Entry.first, Entry.second});
64template <
typename MapT>
68 for (
const auto &Entry : Map2) {
69 [[maybe_unused]]
auto [It, Inserted] =
Result.insert(Entry);
72 assert(It->second == Entry.second);
104 switch (Model.compare(
Type, Val1, Env1, Val2, Env2)) {
112 llvm_unreachable(
"All cases covered in switch");
142 auto &A = JoinedEnv.
arena();
146 A.makeEquals(JoinedVal, Expr1)),
148 A.makeEquals(JoinedVal, Expr2))));
149 return &A.makeBoolValue(JoinedVal);
154 Model.join(
Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);
179 bool TruePrev = PrevEnv.
proves(PrevBool.formula());
180 bool TrueCur = CurrentEnv.
proves(CurBool.formula());
181 if (TruePrev && TrueCur)
183 if (!TruePrev && !TrueCur &&
194 if (
auto Result = Model.widen(
Type, Prev, PrevEnv, Current, CurrentEnv))
204template <
typename Key>
206 const llvm::MapVector<Key, Value *> &Map2,
210 for (
auto &Entry : Map1) {
212 assert(K !=
nullptr);
214 Value *Val = Entry.second;
215 assert(Val !=
nullptr);
217 auto It = Map2.find(K);
218 if (It == Map2.end())
220 assert(It->second !=
nullptr);
232static llvm::MapVector<const StorageLocation *, Value *>
233joinLocToVal(
const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
234 const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2,
237 llvm::MapVector<const StorageLocation *, Value *>
Result;
238 for (
auto &Entry : LocToVal) {
240 assert(Loc !=
nullptr);
242 Value *Val = Entry.second;
243 assert(Val !=
nullptr);
245 auto It = LocToVal2.find(Loc);
246 if (It == LocToVal2.end())
248 assert(It->second !=
nullptr);
251 Loc->
getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) {
252 Result.insert({Loc, JoinedVal});
261template <
typename Key>
262static llvm::MapVector<Key, Value *>
264 const llvm::MapVector<Key, Value *> &PrevMap,
267 llvm::MapVector<Key, Value *> WidenedMap;
268 for (
auto &Entry : CurMap) {
270 assert(K !=
nullptr);
272 Value *Val = Entry.second;
273 assert(Val !=
nullptr);
275 auto PrevIt = PrevMap.find(K);
276 if (PrevIt == PrevMap.end())
278 assert(PrevIt->second !=
nullptr);
281 WidenedMap.insert({K, Val});
286 K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model);
287 WidenedMap.insert({K, WidenedVal});
300class ResultObjectVisitor :
public AnalysisASTVisitor {
306 explicit ResultObjectVisitor(
307 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap,
308 RecordStorageLocation *LocForRecordReturnVal,
309 DataflowAnalysisContext &DACtx)
310 : ResultObjectMap(ResultObjectMap),
311 LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {}
317 void traverseConstructorInits(
const CXXConstructorDecl *Ctor,
318 RecordStorageLocation *ThisPointeeLoc) {
319 assert(ThisPointeeLoc !=
nullptr);
320 for (
const CXXCtorInitializer *Init : Ctor->inits()) {
321 Expr *InitExpr = Init->getInit();
322 if (
FieldDecl *Field = Init->getMember();
323 Field !=
nullptr && Field->getType()->isRecordType()) {
325 ThisPointeeLoc->getChild(*Field)));
326 }
else if (
Init->getBaseClass()) {
327 PropagateResultObject(InitExpr, ThisPointeeLoc);
332 TraverseStmt(InitExpr);
336 if (
auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr))
337 TraverseStmt(DefaultInit->getExpr());
341 bool VisitVarDecl(VarDecl *VD)
override {
342 if (VD->getType()->isRecordType() && VD->hasInit())
343 PropagateResultObject(
349 bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE)
override {
350 if (MTE->getType()->isRecordType())
351 PropagateResultObject(
357 bool VisitReturnStmt(ReturnStmt *Return)
override {
358 Expr *
RetValue = Return->getRetValue();
361 PropagateResultObject(
RetValue, LocForRecordReturnVal);
365 bool VisitExpr(Expr *E)
override {
371 if (E->isPRValue() && E->getType()->isRecordType() &&
372 !ResultObjectMap.contains(E))
373 PropagateResultObject(
379 PropagateResultObjectToRecordInitList(
const RecordInitListHelper &InitList,
380 RecordStorageLocation *Loc) {
381 for (
auto [Base,
Init] : InitList.base_inits()) {
382 assert(
Base->getType().getCanonicalType() ==
383 Init->getType().getCanonicalType());
388 PropagateResultObject(
Init, Loc);
391 for (
auto [Field,
Init] : InitList.field_inits()) {
394 if (
Field->getType()->isRecordType())
395 PropagateResultObject(
403 void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) {
404 if (!E->isPRValue() || !E->getType()->isRecordType()) {
411 ResultObjectMap[E] = Loc;
430 if (
auto *Op = dyn_cast<BinaryOperator>(E);
431 Op && Op->getOpcode() == BO_Cmp) {
436 if (
auto *InitList = dyn_cast<InitListExpr>(E)) {
437 if (!InitList->isSemanticForm())
439 if (InitList->isTransparent()) {
440 PropagateResultObject(InitList->getInit(0), Loc);
444 PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList),
449 if (
auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(E)) {
450 PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList),
455 if (
auto *Op = dyn_cast<BinaryOperator>(E); Op && Op->isCommaOp()) {
456 PropagateResultObject(Op->getRHS(), Loc);
460 if (
auto *
Cond = dyn_cast<AbstractConditionalOperator>(E)) {
461 PropagateResultObject(
Cond->getTrueExpr(), Loc);
462 PropagateResultObject(
Cond->getFalseExpr(), Loc);
466 if (
auto *SE = dyn_cast<StmtExpr>(E)) {
467 PropagateResultObject(
cast<Expr>(SE->getSubStmt()->body_back()), Loc);
471 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(E)) {
472 PropagateResultObject(DIE->getExpr(), Loc);
478 SmallVector<Stmt *, 1>
Children(E->child_begin(), E->child_end());
489 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;
490 RecordStorageLocation *LocForRecordReturnVal;
491 DataflowAnalysisContext &DACtx;
497 if (InitialTargetStmt ==
nullptr)
500 if (InitialTargetFunc ==
nullptr) {
503 std::make_shared<PrValueToResultObject>(buildResultObjectMap(
511 for (
const auto *ParamDecl : InitialTargetFunc->parameters()) {
512 assert(ParamDecl !=
nullptr);
516 if (InitialTargetFunc->getReturnType()->isRecordType())
520 if (
const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) {
521 auto *Parent = MethodDecl->getParent();
522 assert(Parent !=
nullptr);
524 if (Parent->isLambda()) {
525 for (
const auto &
Capture : Parent->captures()) {
526 if (
Capture.capturesVariable()) {
530 }
else if (
Capture.capturesThis()) {
531 if (
auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {
534 SurroundingMethodDecl->getFunctionObjectParameterType();
537 }
else if (
auto *FieldBeingInitialized =
538 dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) {
546 assert(
false &&
"Unexpected this-capturing lambda context.");
550 }
else if (MethodDecl->isImplicitObjectMemberFunction()) {
551 QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
566 std::make_shared<PrValueToResultObject>(buildResultObjectMap(
568 LocForRecordReturnVal));
574void Environment::initFieldsGlobalsAndFuncs(
const ReferencedDecls &Referenced) {
577 DACtx->addModeledFields(Referenced.
Fields);
601 Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken);
607 return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
613 if (
const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(
Call)) {
614 if (
const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
623 if (
Call->getType()->isRecordType() &&
Call->isPRValue())
626 Env.pushCallInternal(
Call->getDirectCallee(),
638 Env.pushCallInternal(
Call->getConstructor(),
644void Environment::pushCallInternal(
const FunctionDecl *FuncDecl,
652 CallStack.push_back(FuncDecl);
660 for (
unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
661 assert(ParamIt != FuncDecl->
param_end());
662 const VarDecl *Param = *ParamIt;
666 ResultObjectMap = std::make_shared<PrValueToResultObject>(
668 LocForRecordReturnVal));
679 this->LocToVal = std::move(CalleeEnv.LocToVal);
680 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
682 if (
Call->isGLValue()) {
683 if (CalleeEnv.ReturnLoc !=
nullptr)
685 }
else if (!
Call->getType()->isVoidType()) {
686 if (CalleeEnv.ReturnVal !=
nullptr)
694 this->LocToVal = std::move(CalleeEnv.LocToVal);
695 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
700 assert(DACtx ==
Other.DACtx);
702 if (ReturnVal !=
Other.ReturnVal)
705 if (ReturnLoc !=
Other.ReturnLoc)
708 if (LocForRecordReturnVal !=
Other.LocForRecordReturnVal)
711 if (ThisPointeeLoc !=
Other.ThisPointeeLoc)
714 if (DeclToLoc !=
Other.DeclToLoc)
717 if (ExprToLoc !=
Other.ExprToLoc)
731 assert(DACtx == PrevEnv.DACtx);
732 assert(ReturnVal == PrevEnv.ReturnVal);
733 assert(ReturnLoc == PrevEnv.ReturnLoc);
734 assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal);
735 assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
736 assert(CallStack == PrevEnv.CallStack);
737 assert(ResultObjectMap == PrevEnv.ResultObjectMap);
738 assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
739 assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);
749 assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
750 assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());
751 assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
758 if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
759 ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
760 ExprToVal.size() != PrevEnv.ExprToVal.size() ||
761 LocToVal.size() != PrevEnv.LocToVal.size())
770 assert(EnvA.DACtx == EnvB.DACtx);
771 assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal);
772 assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
773 assert(EnvA.CallStack == EnvB.CallStack);
774 assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
775 assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
776 assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);
780 JoinedEnv.CallStack = EnvA.CallStack;
781 JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
782 JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
783 JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
784 JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
785 JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;
789 JoinedEnv.ReturnVal =
nullptr;
791 JoinedEnv.ReturnVal =
792 joinValues(
Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
793 EnvB, JoinedEnv, Model);
796 if (EnvA.ReturnLoc == EnvB.ReturnLoc)
797 JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
799 JoinedEnv.ReturnLoc =
nullptr;
806 EnvA.FlowConditionToken, EnvB.FlowConditionToken);
809 joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);
812 JoinedEnv.ExprToVal =
joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);
813 JoinedEnv.ExprToLoc =
joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
823 if (Val1 ==
nullptr || Val2 ==
nullptr)
838 return DACtx->createStorageLocation(
Type);
845 return DACtx->getStableStorageLocation(D);
852 return DACtx->getStableStorageLocation(E);
856 assert(!DeclToLoc.contains(&D));
863 DeclToLoc[&D] = &Loc;
867 auto It = DeclToLoc.find(&D);
868 if (It == DeclToLoc.end())
885 assert(!ExprToLoc.contains(&CanonE));
886 ExprToLoc[&CanonE] = &Loc;
894 return It == ExprToLoc.end() ?
nullptr : &*It->second;
902 assert(ResultObjectMap !=
nullptr);
904 assert(Loc !=
nullptr);
909 DACtx->getStableStorageLocation(RecordPRValue));
914 return DACtx->getOrCreateNullPointerValue(PointeeType);
919 llvm::DenseSet<QualType> Visited;
920 int CreatedValuesCount = 0;
923 llvm::errs() <<
"Attempting to initialize a huge value of type: " <<
Type
931 LocToVal[&Loc] = &Val;
940 ExprToVal[&CanonE] = &Val;
946 return LocToVal.lookup(&Loc);
962 return It == ExprToVal.end() ?
nullptr : It->second;
966 if (It == ExprToLoc.end())
972 llvm::DenseSet<QualType> Visited;
973 int CreatedValuesCount = 0;
974 Value *Val = createValueUnlessSelfReferential(
Type, Visited, 0,
977 llvm::errs() <<
"Attempting to initialize a huge value of type: " <<
Type
983Value *Environment::createValueUnlessSelfReferential(
984 QualType Type, llvm::DenseSet<QualType> &Visited,
int Depth,
985 int &CreatedValuesCount) {
986 assert(!
Type.isNull());
996 CreatedValuesCount++;
1004 CreatedValuesCount++;
1008 if (Type->isPointerType()) {
1009 CreatedValuesCount++;
1010 QualType PointeeType = Type->getPointeeType();
1011 StorageLocation &PointeeLoc =
1012 createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount);
1021Environment::createLocAndMaybeValue(QualType Ty,
1022 llvm::DenseSet<QualType> &Visited,
1023 int Depth,
int &CreatedValuesCount) {
1024 if (!Visited.insert(Ty.getCanonicalType()).second)
1026 llvm::scope_exit EraseVisited(
1027 [&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); });
1029 Ty = Ty.getNonReferenceType();
1031 if (Ty->isRecordType()) {
1039 if (
Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth,
1040 CreatedValuesCount))
1048 llvm::DenseSet<QualType> &Visited,
1050 int &CreatedValuesCount) {
1051 auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
1052 if (FieldType->isRecordType()) {
1055 Visited, Depth + 1, CreatedValuesCount);
1059 if (!Visited.insert(FieldType.getCanonicalType()).second)
1061 if (
Value *Val = createValueUnlessSelfReferential(
1062 FieldType, Visited, Depth + 1, CreatedValuesCount))
1064 Visited.erase(FieldType.getCanonicalType());
1068 for (
const FieldDecl *Field : DACtx->getModeledFields(
Type)) {
1069 assert(Field !=
nullptr);
1070 QualType FieldType =
Field->getType();
1072 if (FieldType->isReferenceType()) {
1073 Loc.setChild(*Field,
1074 &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
1075 CreatedValuesCount));
1077 StorageLocation *FieldLoc = Loc.getChild(*Field);
1078 assert(FieldLoc !=
nullptr);
1082 for (
const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(
Type)) {
1085 assert(!FieldType->isReferenceType());
1086 initField(FieldType, Loc.getSyntheticField(FieldName));
1092 const Expr *InitExpr) {
1093 if (Ty->isReferenceType()) {
1099 return *InitExprLoc;
1106 return createObjectInternal(D, Ty.getNonReferenceType(),
nullptr);
1109 StorageLocation &Loc =
1112 if (Ty->isRecordType()) {
1113 auto &RecordLoc = cast<RecordStorageLocation>(Loc);
1115 initializeFieldsWithValues(RecordLoc);
1117 Value *Val = nullptr;
1132 Val = getValue(*InitExpr);
1134 Val = createValue(Ty);
1136 setValue(Loc, *Val);
1143 DACtx->addFlowConditionConstraint(FlowConditionToken, F);
1147 return DACtx->flowConditionImplies(FlowConditionToken, F);
1151 return DACtx->flowConditionAllows(FlowConditionToken, F);
1155 llvm::DenseMap<const StorageLocation *, std::string> LocToName;
1156 if (LocForRecordReturnVal !=
nullptr)
1157 LocToName[LocForRecordReturnVal] =
"(returned record)";
1158 if (ThisPointeeLoc !=
nullptr)
1159 LocToName[ThisPointeeLoc] =
"this";
1161 OS <<
"DeclToLoc:\n";
1162 for (
auto [D, L] : DeclToLoc) {
1163 auto Iter = LocToName.insert({L, D->getNameAsString()}).first;
1164 OS <<
" [" << Iter->second <<
", " << L <<
"]\n";
1166 OS <<
"ExprToLoc:\n";
1167 for (
auto [E, L] : ExprToLoc)
1168 OS <<
" [" << E <<
", " << L <<
"]\n";
1170 OS <<
"ExprToVal:\n";
1171 for (
auto [E,
V] : ExprToVal)
1172 OS <<
" [" << E <<
", " <<
V <<
": " << *
V <<
"]\n";
1174 OS <<
"LocToVal:\n";
1175 for (
auto [L,
V] : LocToVal) {
1177 if (
auto Iter = LocToName.find(L); Iter != LocToName.end())
1178 OS <<
" (" << Iter->second <<
")";
1179 OS <<
", " <<
V <<
": " << *
V <<
"]\n";
1183 if (
Func->getReturnType()->isReferenceType()) {
1184 OS <<
"ReturnLoc: " << ReturnLoc;
1185 if (
auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end())
1186 OS <<
" (" << Iter->second <<
")";
1188 }
else if (
Func->getReturnType()->isRecordType() ||
1190 OS <<
"LocForRecordReturnVal: " << LocForRecordReturnVal <<
"\n";
1191 }
else if (!
Func->getReturnType()->isVoidType()) {
1192 if (ReturnVal ==
nullptr)
1193 OS <<
"ReturnVal: nullptr\n";
1195 OS <<
"ReturnVal: " << *ReturnVal <<
"\n";
1199 OS <<
"ThisPointeeLoc: " << ThisPointeeLoc <<
"\n";
1204 DACtx->dumpFlowCondition(FlowConditionToken, OS);
1209Environment::PrValueToResultObject Environment::buildResultObjectMap(
1215 PrValueToResultObject Map = buildResultObjectMap(
1216 DACtx, FuncDecl->
getBody(), ThisPointeeLoc, LocForRecordReturnVal);
1218 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1219 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl))
1220 Visitor.traverseConstructorInits(Ctor, ThisPointeeLoc);
1225Environment::PrValueToResultObject Environment::buildResultObjectMap(
1226 DataflowAnalysisContext *DACtx,
Stmt *S,
1227 RecordStorageLocation *ThisPointeeLoc,
1228 RecordStorageLocation *LocForRecordReturnVal) {
1229 PrValueToResultObject Map;
1230 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1231 Visitor.TraverseStmt(S);
1238 if (ImplicitObject ==
nullptr)
1245 return cast_or_null<RecordStorageLocation>(
1252 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 bool RetValue(InterpState &S, CodePtr &Pt)
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.
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.
The JSON file list parser is used to communicate input to InstallAPI.
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.
@ 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.