26#include "llvm/ADT/DenseMap.h"
27#include "llvm/ADT/DenseSet.h"
28#include "llvm/ADT/MapVector.h"
29#include "llvm/ADT/PointerUnion.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);
107 switch (Model.
compare(
Type, Val1, Env1, Val2, Env2)) {
115 llvm_unreachable(
"All cases covered in switch");
129 if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
143 auto &Expr1 = cast<BoolValue>(Val1).formula();
144 auto &Expr2 = cast<BoolValue>(Val2).formula();
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);
167 if (isa<BoolValue>(Prev) && isa<BoolValue>(Current)) {
171 auto &PrevBool = cast<BoolValue>(Prev);
172 auto &CurBool = cast<BoolValue>(Current);
174 if (isa<TopBoolValue>(Prev))
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)) {
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()) {
327 PropagateResultObject(InitExpr, cast<RecordStorageLocation>(
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(
348 &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*VD)));
352 bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE)
override {
353 if (MTE->getType()->isRecordType())
354 PropagateResultObject(
356 &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*MTE)));
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(
377 E, &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*
E)));
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(
399 Init, cast<RecordStorageLocation>(
Loc->getChild(*Field)));
406 void PropagateResultObject(Expr *
E, RecordStorageLocation *
Loc) {
407 if (!
E->isPRValue() || !
E->getType()->isRecordType()) {
414 ResultObjectMap[
E] =
Loc;
419 if (isa<CXXConstructExpr>(
E) || isa<CallExpr>(
E) || isa<LambdaExpr>(
E) ||
420 isa<CXXDefaultArgExpr>(
E) || isa<CXXStdInitializerListExpr>(
E) ||
421 isa<AtomicExpr>(
E) || isa<CXXInheritedCtorInitExpr>(
E) ||
425 isa<BuiltinBitCastExpr>(
E)) {
428 if (
auto *Op = dyn_cast<BinaryOperator>(
E);
429 Op && Op->getOpcode() == BO_Cmp) {
434 if (
auto *InitList = dyn_cast<InitListExpr>(
E)) {
435 if (!InitList->isSemanticForm())
437 if (InitList->isTransparent()) {
438 PropagateResultObject(InitList->getInit(0),
Loc);
442 PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList),
447 if (
auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(
E)) {
448 PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList),
453 if (
auto *Op = dyn_cast<BinaryOperator>(
E); Op && Op->isCommaOp()) {
454 PropagateResultObject(Op->getRHS(),
Loc);
458 if (
auto *Cond = dyn_cast<AbstractConditionalOperator>(
E)) {
459 PropagateResultObject(Cond->getTrueExpr(),
Loc);
460 PropagateResultObject(Cond->getFalseExpr(),
Loc);
464 if (
auto *SE = dyn_cast<StmtExpr>(
E)) {
465 PropagateResultObject(cast<Expr>(SE->getSubStmt()->body_back()),
Loc);
469 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(
E)) {
470 PropagateResultObject(DIE->getExpr(),
Loc);
476 SmallVector<Stmt *, 1> Children(
E->child_begin(),
E->child_end());
478 if (Children.size() != 1)
481 assert(Children.size() == 1);
482 for (Stmt *S : Children)
483 PropagateResultObject(cast<Expr>(S),
Loc);
487 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;
488 RecordStorageLocation *LocForRecordReturnVal;
489 DataflowAnalysisContext &DACtx;
495 if (InitialTargetStmt ==
nullptr)
498 if (InitialTargetFunc ==
nullptr) {
501 std::make_shared<PrValueToResultObject>(buildResultObjectMap(
509 for (
const auto *ParamDecl : InitialTargetFunc->
parameters()) {
510 assert(ParamDecl !=
nullptr);
515 LocForRecordReturnVal = &cast<RecordStorageLocation>(
518 if (
const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) {
519 auto *
Parent = MethodDecl->getParent();
520 assert(
Parent !=
nullptr);
524 if (
Capture.capturesVariable()) {
528 }
else if (
Capture.capturesThis()) {
530 const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor);
532 SurroundingMethodDecl->getFunctionObjectParameterType();
534 cast<RecordStorageLocation>(
createObject(ThisPointeeType)));
535 }
else if (
auto *FieldBeingInitialized =
536 dyn_cast<FieldDecl>(
Parent->getLambdaContextDecl())) {
540 FieldBeingInitialized->getParent()->getTypeForDecl(), 0))));
542 assert(
false &&
"Unexpected this-capturing lambda context.");
546 }
else if (MethodDecl->isImplicitObjectMemberFunction()) {
547 QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
554 if (!isa<CXXConstructorDecl>(MethodDecl))
562 std::make_shared<PrValueToResultObject>(buildResultObjectMap(
564 LocForRecordReturnVal));
570void Environment::initFieldsGlobalsAndFuncs(
const ReferencedDecls &Referenced) {
573 DACtx->addModeledFields(Referenced.
Fields);
603 return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
609 if (
const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(
Call)) {
610 if (
const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
611 if (!isa<CXXThisExpr>(Arg))
619 if (
Call->getType()->isRecordType() &&
Call->isPRValue())
620 Env.LocForRecordReturnVal = &
Env.getResultObjectLocation(*
Call);
622 Env.pushCallInternal(
Call->getDirectCallee(),
631 Env.ThisPointeeLoc = &
Env.getResultObjectLocation(*
Call);
632 Env.LocForRecordReturnVal = &
Env.getResultObjectLocation(*
Call);
634 Env.pushCallInternal(
Call->getConstructor(),
640void Environment::pushCallInternal(
const FunctionDecl *FuncDecl,
648 CallStack.push_back(FuncDecl);
656 for (
unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
657 assert(ParamIt != FuncDecl->
param_end());
658 const VarDecl *Param = *ParamIt;
662 ResultObjectMap = std::make_shared<PrValueToResultObject>(
664 LocForRecordReturnVal));
675 this->LocToVal = std::move(CalleeEnv.LocToVal);
676 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
678 if (
Call->isGLValue()) {
679 if (CalleeEnv.ReturnLoc !=
nullptr)
681 }
else if (!
Call->getType()->isVoidType()) {
682 if (CalleeEnv.ReturnVal !=
nullptr)
690 this->LocToVal = std::move(CalleeEnv.LocToVal);
691 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
696 assert(DACtx ==
Other.DACtx);
698 if (ReturnVal !=
Other.ReturnVal)
701 if (ReturnLoc !=
Other.ReturnLoc)
704 if (LocForRecordReturnVal !=
Other.LocForRecordReturnVal)
707 if (ThisPointeeLoc !=
Other.ThisPointeeLoc)
710 if (DeclToLoc !=
Other.DeclToLoc)
713 if (ExprToLoc !=
Other.ExprToLoc)
727 assert(DACtx == PrevEnv.DACtx);
728 assert(ReturnVal == PrevEnv.ReturnVal);
729 assert(ReturnLoc == PrevEnv.ReturnLoc);
730 assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal);
731 assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
732 assert(CallStack == PrevEnv.CallStack);
733 assert(ResultObjectMap == PrevEnv.ResultObjectMap);
734 assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
735 assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);
745 assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
746 assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());
747 assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
754 if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
755 ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
756 ExprToVal.size() != PrevEnv.ExprToVal.size() ||
757 LocToVal.size() != PrevEnv.LocToVal.size())
766 assert(EnvA.DACtx == EnvB.DACtx);
767 assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal);
768 assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
769 assert(EnvA.CallStack == EnvB.CallStack);
770 assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
771 assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
772 assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);
776 JoinedEnv.CallStack = EnvA.CallStack;
777 JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
778 JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
779 JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
780 JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
781 JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;
785 JoinedEnv.ReturnVal =
nullptr;
787 JoinedEnv.ReturnVal =
788 joinValues(
Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
789 EnvB, JoinedEnv, Model);
792 if (EnvA.ReturnLoc == EnvB.ReturnLoc)
793 JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
795 JoinedEnv.ReturnLoc =
nullptr;
802 EnvA.FlowConditionToken, EnvB.FlowConditionToken);
805 joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);
808 JoinedEnv.ExprToVal =
joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);
809 JoinedEnv.ExprToLoc =
joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
819 if (Val1 ==
nullptr || Val2 ==
nullptr)
852 assert(!DeclToLoc.contains(&
D));
857 assert(
D.getType()->isReferenceType() || isa<BindingDecl>(
D) ||
859 DeclToLoc[&
D] = &
Loc;
863 auto It = DeclToLoc.find(&
D);
864 if (It == DeclToLoc.end())
878 assert(
E.isGLValue() ||
879 E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
881 assert(!ExprToLoc.contains(&CanonE));
882 ExprToLoc[&CanonE] = &
Loc;
887 assert(
E.isGLValue() ||
888 E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
890 return It == ExprToLoc.end() ? nullptr : &*It->second;
898 assert(ResultObjectMap !=
nullptr);
900 assert(
Loc !=
nullptr);
904 return cast<RecordStorageLocation>(
915 llvm::DenseSet<QualType>
Visited;
916 int CreatedValuesCount = 0;
919 llvm::errs() <<
"Attempting to initialize a huge value of type: " <<
Type
926 assert(!isa<RecordStorageLocation>(
Loc));
927 LocToVal[&
Loc] = &Val;
936 ExprToVal[&CanonE] = &Val;
941 assert(!isa<RecordStorageLocation>(
Loc));
942 return LocToVal.lookup(&
Loc);
954 assert(!
E.getType()->isRecordType());
958 return It == ExprToVal.end() ? nullptr : It->second;
962 if (It == ExprToLoc.end())
968 llvm::DenseSet<QualType>
Visited;
969 int CreatedValuesCount = 0;
973 llvm::errs() <<
"Attempting to initialize a huge value of type: " <<
Type
979Value *Environment::createValueUnlessSelfReferential(
981 int &CreatedValuesCount) {
982 assert(!
Type.isNull());
992 CreatedValuesCount++;
1000 CreatedValuesCount++;
1004 if (
Type->isPointerType()) {
1005 CreatedValuesCount++;
1006 QualType PointeeType =
Type->getPointeeType();
1007 StorageLocation &PointeeLoc =
1008 createLocAndMaybeValue(PointeeType,
Visited, Depth, CreatedValuesCount);
1017Environment::createLocAndMaybeValue(QualType Ty,
1018 llvm::DenseSet<QualType> &
Visited,
1019 int Depth,
int &CreatedValuesCount) {
1020 if (!
Visited.insert(Ty.getCanonicalType()).second)
1022 auto EraseVisited = llvm::make_scope_exit(
1025 Ty = Ty.getNonReferenceType();
1027 if (Ty->isRecordType()) {
1035 if (
Value *Val = createValueUnlessSelfReferential(Ty,
Visited, Depth,
1036 CreatedValuesCount))
1044 llvm::DenseSet<QualType> &
Visited,
1046 int &CreatedValuesCount) {
1047 auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
1048 if (FieldType->isRecordType()) {
1049 auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc);
1051 Visited, Depth + 1, CreatedValuesCount);
1055 if (!
Visited.insert(FieldType.getCanonicalType()).second)
1057 if (
Value *Val = createValueUnlessSelfReferential(
1058 FieldType,
Visited, Depth + 1, CreatedValuesCount))
1060 Visited.erase(FieldType.getCanonicalType());
1065 assert(Field !=
nullptr);
1066 QualType FieldType =
Field->getType();
1068 if (FieldType->isReferenceType()) {
1069 Loc.setChild(*Field,
1070 &createLocAndMaybeValue(FieldType,
Visited, Depth + 1,
1071 CreatedValuesCount));
1073 StorageLocation *FieldLoc =
Loc.getChild(*Field);
1074 assert(FieldLoc !=
nullptr);
1081 assert(!FieldType->isReferenceType());
1082 initField(FieldType,
Loc.getSyntheticField(FieldName));
1086StorageLocation &Environment::createObjectInternal(
const ValueDecl *
D,
1088 const Expr *InitExpr) {
1089 if (Ty->isReferenceType()) {
1095 return *InitExprLoc;
1102 return createObjectInternal(
D, Ty.getNonReferenceType(),
nullptr);
1105 StorageLocation &
Loc =
1108 if (Ty->isRecordType()) {
1113 Value *Val =
nullptr;
1151 llvm::DenseMap<const StorageLocation *, std::string> LocToName;
1152 if (LocForRecordReturnVal !=
nullptr)
1153 LocToName[LocForRecordReturnVal] =
"(returned record)";
1154 if (ThisPointeeLoc !=
nullptr)
1155 LocToName[ThisPointeeLoc] =
"this";
1157 OS <<
"DeclToLoc:\n";
1158 for (
auto [
D, L] : DeclToLoc) {
1159 auto Iter = LocToName.insert({L,
D->getNameAsString()}).first;
1160 OS <<
" [" <<
Iter->second <<
", " << L <<
"]\n";
1162 OS <<
"ExprToLoc:\n";
1163 for (
auto [
E, L] : ExprToLoc)
1164 OS <<
" [" <<
E <<
", " << L <<
"]\n";
1166 OS <<
"ExprToVal:\n";
1167 for (
auto [
E,
V] : ExprToVal)
1168 OS <<
" [" <<
E <<
", " <<
V <<
": " << *
V <<
"]\n";
1170 OS <<
"LocToVal:\n";
1171 for (
auto [L,
V] : LocToVal) {
1173 if (
auto Iter = LocToName.find(L);
Iter != LocToName.end())
1174 OS <<
" (" <<
Iter->second <<
")";
1175 OS <<
", " <<
V <<
": " << *
V <<
"]\n";
1179 if (
Func->getReturnType()->isReferenceType()) {
1180 OS <<
"ReturnLoc: " << ReturnLoc;
1181 if (
auto Iter = LocToName.find(ReturnLoc);
Iter != LocToName.end())
1182 OS <<
" (" <<
Iter->second <<
")";
1184 }
else if (
Func->getReturnType()->isRecordType() ||
1185 isa<CXXConstructorDecl>(
Func)) {
1186 OS <<
"LocForRecordReturnVal: " << LocForRecordReturnVal <<
"\n";
1187 }
else if (!
Func->getReturnType()->isVoidType()) {
1188 if (ReturnVal ==
nullptr)
1189 OS <<
"ReturnVal: nullptr\n";
1191 OS <<
"ReturnVal: " << *ReturnVal <<
"\n";
1194 if (isa<CXXMethodDecl>(
Func)) {
1195 OS <<
"ThisPointeeLoc: " << ThisPointeeLoc <<
"\n";
1205Environment::PrValueToResultObject Environment::buildResultObjectMap(
1211 PrValueToResultObject Map = buildResultObjectMap(
1212 DACtx, FuncDecl->
getBody(), ThisPointeeLoc, LocForRecordReturnVal);
1214 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1215 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl))
1216 Visitor.traverseConstructorInits(Ctor, ThisPointeeLoc);
1221Environment::PrValueToResultObject Environment::buildResultObjectMap(
1222 DataflowAnalysisContext *DACtx,
Stmt *S,
1223 RecordStorageLocation *ThisPointeeLoc,
1224 RecordStorageLocation *LocForRecordReturnVal) {
1225 PrValueToResultObject Map;
1226 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1227 Visitor.TraverseStmt(S);
1234 if (ImplicitObject ==
nullptr)
1238 return &cast<RecordStorageLocation>(Val->getPointeeLoc());
1241 return cast_or_null<RecordStorageLocation>(
1248 if (
Base ==
nullptr)
1252 return &cast<RecordStorageLocation>(Val->getPointeeLoc());
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 IsActive, bool IsUnionField, bool InUnion, const Descriptor *D, unsigned FieldOffset)
Defines the clang::Expr interface and subclasses for C++ expressions.
llvm::DenseSet< const void * > Visited
static bool RetValue(InterpState &S, CodePtr &Pt)
llvm::MachO::RecordLoc RecordLoc
C Language Family Type Representation.
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]).
Decl * getNonClosureAncestor()
Find the nearest non-closure ancestor of this context, i.e.
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()
QualType getReturnType() const
ArrayRef< ParmVarDecl * > parameters() const
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.
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 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...
void addFlowConditionConstraint(Atom Token, const Formula &Constraint)
Adds Constraint to the flow condition identified by Token.
Atom forkFlowCondition(Atom Token)
Creates a new flow condition with the same constraints as the flow condition identified by Token and ...
StorageLocation & getStableStorageLocation(const ValueDecl &D)
Returns a stable storage location for D.
bool flowConditionImplies(Atom Token, const Formula &F)
Returns true if the constraints of the flow condition identified by Token imply that F is true.
bool flowConditionAllows(Atom Token, const Formula &F)
Returns true if the constraints of the flow condition identified by Token still allow F to be true.
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
llvm::StringMap< QualType > getSyntheticFields(QualType Type)
Returns the names and types of the synthetic fields for the given record type.
StorageLocation & createStorageLocation(QualType Type)
Returns a new storage location appropriate for Type.
FieldSet getModeledFields(QualType Type)
Returns the fields of Type, limited to the set of fields modeled by this context.
LLVM_DUMP_METHOD void dumpFlowCondition(Atom Token, llvm::raw_ostream &OS=llvm::dbgs())
Supplements Environment with non-standard comparison and join operations.
virtual std::optional< WidenResult > widen(QualType Type, Value &Prev, const Environment &PrevEnv, Value &Current, Environment &CurrentEnv)
This function may widen the current value – replace it with an approximation that can reach a fixed p...
virtual void join(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2, Value &JoinedVal, Environment &JoinedEnv)
Modifies JoinedVal to approximate both Val1 and Val2.
virtual ComparisonResult compare(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2)
Returns: Same: Val1 is equivalent to Val2, according to the model.
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.
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.
@ Result
The result type of a method or function.
@ Other
Other implicit parameter.
A collection of several types of declarations, all referenced from the same function.
llvm::DenseSet< const VarDecl * > Globals
All variables with static storage duration, notably including static member variables and static vari...
llvm::DenseSet< const FunctionDecl * > Functions
Free functions and member functions which are referenced (but not necessarily called).
FieldSet Fields
Non-static member variables.
The result of a widen operation.