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");
126 if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
140 auto &Expr1 = cast<BoolValue>(Val1).formula();
141 auto &Expr2 = cast<BoolValue>(Val2).formula();
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);
164 if (isa<BoolValue>(Prev) && isa<BoolValue>(Current)) {
168 auto &PrevBool = cast<BoolValue>(Prev);
169 auto &CurBool = cast<BoolValue>(Current);
171 if (isa<TopBoolValue>(Prev))
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)) {
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()) {
324 PropagateResultObject(InitExpr, cast<RecordStorageLocation>(
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(
345 &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*VD)));
349 bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE)
override {
350 if (MTE->getType()->isRecordType())
351 PropagateResultObject(
353 &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*MTE)));
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(
374 E, &cast<RecordStorageLocation>(DACtx.getStableStorageLocation(*
E)));
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(
396 Init, cast<RecordStorageLocation>(
Loc->getChild(*Field)));
403 void PropagateResultObject(Expr *
E, RecordStorageLocation *
Loc) {
404 if (!
E->isPRValue() || !
E->getType()->isRecordType()) {
411 ResultObjectMap[
E] =
Loc;
416 if (isa<CXXConstructExpr>(
E) || isa<CallExpr>(
E) || isa<LambdaExpr>(
E) ||
417 isa<CXXDefaultArgExpr>(
E) || isa<CXXStdInitializerListExpr>(
E) ||
418 isa<AtomicExpr>(
E) || isa<CXXInheritedCtorInitExpr>(
E) ||
422 isa<BuiltinBitCastExpr>(
E)) {
425 if (
auto *Op = dyn_cast<BinaryOperator>(
E);
426 Op && Op->getOpcode() == BO_Cmp) {
431 if (
auto *InitList = dyn_cast<InitListExpr>(
E)) {
432 if (!InitList->isSemanticForm())
434 if (InitList->isTransparent()) {
435 PropagateResultObject(InitList->getInit(0),
Loc);
439 PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList),
444 if (
auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(
E)) {
445 PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList),
450 if (
auto *Op = dyn_cast<BinaryOperator>(
E); Op && Op->isCommaOp()) {
451 PropagateResultObject(Op->getRHS(),
Loc);
455 if (
auto *Cond = dyn_cast<AbstractConditionalOperator>(
E)) {
456 PropagateResultObject(Cond->getTrueExpr(),
Loc);
457 PropagateResultObject(Cond->getFalseExpr(),
Loc);
461 if (
auto *SE = dyn_cast<StmtExpr>(
E)) {
462 PropagateResultObject(cast<Expr>(SE->getSubStmt()->body_back()),
Loc);
466 if (
auto *DIE = dyn_cast<CXXDefaultInitExpr>(
E)) {
467 PropagateResultObject(DIE->getExpr(),
Loc);
473 SmallVector<Stmt *, 1> Children(
E->child_begin(),
E->child_end());
475 if (Children.size() != 1)
478 assert(Children.size() == 1);
479 for (Stmt *S : Children)
480 PropagateResultObject(cast<Expr>(S),
Loc);
484 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;
485 RecordStorageLocation *LocForRecordReturnVal;
486 DataflowAnalysisContext &DACtx;
492 if (InitialTargetStmt ==
nullptr)
495 if (InitialTargetFunc ==
nullptr) {
498 std::make_shared<PrValueToResultObject>(buildResultObjectMap(
506 for (
const auto *ParamDecl : InitialTargetFunc->
parameters()) {
507 assert(ParamDecl !=
nullptr);
512 LocForRecordReturnVal = &cast<RecordStorageLocation>(
515 if (
const auto *MethodDecl = dyn_cast<CXXMethodDecl>(InitialTargetFunc)) {
516 auto *
Parent = MethodDecl->getParent();
517 assert(
Parent !=
nullptr);
521 if (
Capture.capturesVariable()) {
525 }
else if (
Capture.capturesThis()) {
527 const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor);
529 SurroundingMethodDecl->getFunctionObjectParameterType();
531 cast<RecordStorageLocation>(
createObject(ThisPointeeType)));
532 }
else if (
auto *FieldBeingInitialized =
533 dyn_cast<FieldDecl>(
Parent->getLambdaContextDecl())) {
541 assert(
false &&
"Unexpected this-capturing lambda context.");
545 }
else if (MethodDecl->isImplicitObjectMemberFunction()) {
546 QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
553 if (!isa<CXXConstructorDecl>(MethodDecl))
561 std::make_shared<PrValueToResultObject>(buildResultObjectMap(
563 LocForRecordReturnVal));
569void Environment::initFieldsGlobalsAndFuncs(
const ReferencedDecls &Referenced) {
572 DACtx->addModeledFields(Referenced.
Fields);
602 return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
608 if (
const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(
Call)) {
609 if (
const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
610 if (!isa<CXXThisExpr>(Arg))
618 if (
Call->getType()->isRecordType() &&
Call->isPRValue())
619 Env.LocForRecordReturnVal = &
Env.getResultObjectLocation(*
Call);
621 Env.pushCallInternal(
Call->getDirectCallee(),
630 Env.ThisPointeeLoc = &
Env.getResultObjectLocation(*
Call);
631 Env.LocForRecordReturnVal = &
Env.getResultObjectLocation(*
Call);
633 Env.pushCallInternal(
Call->getConstructor(),
639void Environment::pushCallInternal(
const FunctionDecl *FuncDecl,
647 CallStack.push_back(FuncDecl);
655 for (
unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
656 assert(ParamIt != FuncDecl->
param_end());
657 const VarDecl *Param = *ParamIt;
661 ResultObjectMap = std::make_shared<PrValueToResultObject>(
663 LocForRecordReturnVal));
674 this->LocToVal = std::move(CalleeEnv.LocToVal);
675 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
677 if (
Call->isGLValue()) {
678 if (CalleeEnv.ReturnLoc !=
nullptr)
680 }
else if (!
Call->getType()->isVoidType()) {
681 if (CalleeEnv.ReturnVal !=
nullptr)
689 this->LocToVal = std::move(CalleeEnv.LocToVal);
690 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
695 assert(DACtx ==
Other.DACtx);
697 if (ReturnVal !=
Other.ReturnVal)
700 if (ReturnLoc !=
Other.ReturnLoc)
703 if (LocForRecordReturnVal !=
Other.LocForRecordReturnVal)
706 if (ThisPointeeLoc !=
Other.ThisPointeeLoc)
709 if (DeclToLoc !=
Other.DeclToLoc)
712 if (ExprToLoc !=
Other.ExprToLoc)
726 assert(DACtx == PrevEnv.DACtx);
727 assert(ReturnVal == PrevEnv.ReturnVal);
728 assert(ReturnLoc == PrevEnv.ReturnLoc);
729 assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal);
730 assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
731 assert(CallStack == PrevEnv.CallStack);
732 assert(ResultObjectMap == PrevEnv.ResultObjectMap);
733 assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
734 assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);
744 assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
745 assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());
746 assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
753 if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
754 ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
755 ExprToVal.size() != PrevEnv.ExprToVal.size() ||
756 LocToVal.size() != PrevEnv.LocToVal.size())
765 assert(EnvA.DACtx == EnvB.DACtx);
766 assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal);
767 assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
768 assert(EnvA.CallStack == EnvB.CallStack);
769 assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
770 assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
771 assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);
775 JoinedEnv.CallStack = EnvA.CallStack;
776 JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
777 JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
778 JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
779 JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
780 JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;
784 JoinedEnv.ReturnVal =
nullptr;
786 JoinedEnv.ReturnVal =
787 joinValues(
Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
788 EnvB, JoinedEnv, Model);
791 if (EnvA.ReturnLoc == EnvB.ReturnLoc)
792 JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
794 JoinedEnv.ReturnLoc =
nullptr;
801 EnvA.FlowConditionToken, EnvB.FlowConditionToken);
804 joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);
807 JoinedEnv.ExprToVal =
joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);
808 JoinedEnv.ExprToLoc =
joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
818 if (Val1 ==
nullptr || Val2 ==
nullptr)
851 assert(!DeclToLoc.contains(&
D));
856 assert(
D.getType()->isReferenceType() || isa<BindingDecl>(
D) ||
858 DeclToLoc[&
D] = &
Loc;
862 auto It = DeclToLoc.find(&
D);
863 if (It == DeclToLoc.end())
877 assert(
E.isGLValue() ||
878 E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
880 assert(!ExprToLoc.contains(&CanonE));
881 ExprToLoc[&CanonE] = &
Loc;
886 assert(
E.isGLValue() ||
887 E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
889 return It == ExprToLoc.end() ? nullptr : &*It->second;
897 assert(ResultObjectMap !=
nullptr);
899 assert(
Loc !=
nullptr);
903 return cast<RecordStorageLocation>(
914 llvm::DenseSet<QualType>
Visited;
915 int CreatedValuesCount = 0;
918 llvm::errs() <<
"Attempting to initialize a huge value of type: " <<
Type
925 assert(!isa<RecordStorageLocation>(
Loc));
926 LocToVal[&
Loc] = &Val;
935 ExprToVal[&CanonE] = &Val;
940 assert(!isa<RecordStorageLocation>(
Loc));
941 return LocToVal.lookup(&
Loc);
953 assert(!
E.getType()->isRecordType());
957 return It == ExprToVal.end() ? nullptr : It->second;
961 if (It == ExprToLoc.end())
967 llvm::DenseSet<QualType>
Visited;
968 int CreatedValuesCount = 0;
972 llvm::errs() <<
"Attempting to initialize a huge value of type: " <<
Type
978Value *Environment::createValueUnlessSelfReferential(
980 int &CreatedValuesCount) {
981 assert(!
Type.isNull());
991 CreatedValuesCount++;
999 CreatedValuesCount++;
1003 if (
Type->isPointerType()) {
1004 CreatedValuesCount++;
1005 QualType PointeeType =
Type->getPointeeType();
1006 StorageLocation &PointeeLoc =
1007 createLocAndMaybeValue(PointeeType,
Visited, Depth, CreatedValuesCount);
1016Environment::createLocAndMaybeValue(QualType Ty,
1017 llvm::DenseSet<QualType> &
Visited,
1018 int Depth,
int &CreatedValuesCount) {
1019 if (!
Visited.insert(Ty.getCanonicalType()).second)
1021 auto EraseVisited = llvm::make_scope_exit(
1024 Ty = Ty.getNonReferenceType();
1026 if (Ty->isRecordType()) {
1034 if (
Value *Val = createValueUnlessSelfReferential(Ty,
Visited, Depth,
1035 CreatedValuesCount))
1043 llvm::DenseSet<QualType> &
Visited,
1045 int &CreatedValuesCount) {
1046 auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
1047 if (FieldType->isRecordType()) {
1048 auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc);
1050 Visited, Depth + 1, CreatedValuesCount);
1054 if (!
Visited.insert(FieldType.getCanonicalType()).second)
1056 if (
Value *Val = createValueUnlessSelfReferential(
1057 FieldType,
Visited, Depth + 1, CreatedValuesCount))
1059 Visited.erase(FieldType.getCanonicalType());
1064 assert(Field !=
nullptr);
1065 QualType FieldType =
Field->getType();
1067 if (FieldType->isReferenceType()) {
1068 Loc.setChild(*Field,
1069 &createLocAndMaybeValue(FieldType,
Visited, Depth + 1,
1070 CreatedValuesCount));
1072 StorageLocation *FieldLoc =
Loc.getChild(*Field);
1073 assert(FieldLoc !=
nullptr);
1080 assert(!FieldType->isReferenceType());
1081 initField(FieldType,
Loc.getSyntheticField(FieldName));
1085StorageLocation &Environment::createObjectInternal(
const ValueDecl *
D,
1087 const Expr *InitExpr) {
1088 if (Ty->isReferenceType()) {
1094 return *InitExprLoc;
1101 return createObjectInternal(
D, Ty.getNonReferenceType(),
nullptr);
1104 StorageLocation &
Loc =
1107 if (Ty->isRecordType()) {
1112 Value *Val =
nullptr;
1150 llvm::DenseMap<const StorageLocation *, std::string> LocToName;
1151 if (LocForRecordReturnVal !=
nullptr)
1152 LocToName[LocForRecordReturnVal] =
"(returned record)";
1153 if (ThisPointeeLoc !=
nullptr)
1154 LocToName[ThisPointeeLoc] =
"this";
1156 OS <<
"DeclToLoc:\n";
1157 for (
auto [
D, L] : DeclToLoc) {
1158 auto Iter = LocToName.insert({L,
D->getNameAsString()}).first;
1159 OS <<
" [" <<
Iter->second <<
", " << L <<
"]\n";
1161 OS <<
"ExprToLoc:\n";
1162 for (
auto [
E, L] : ExprToLoc)
1163 OS <<
" [" <<
E <<
", " << L <<
"]\n";
1165 OS <<
"ExprToVal:\n";
1166 for (
auto [
E,
V] : ExprToVal)
1167 OS <<
" [" <<
E <<
", " <<
V <<
": " << *
V <<
"]\n";
1169 OS <<
"LocToVal:\n";
1170 for (
auto [L,
V] : LocToVal) {
1172 if (
auto Iter = LocToName.find(L);
Iter != LocToName.end())
1173 OS <<
" (" <<
Iter->second <<
")";
1174 OS <<
", " <<
V <<
": " << *
V <<
"]\n";
1178 if (
Func->getReturnType()->isReferenceType()) {
1179 OS <<
"ReturnLoc: " << ReturnLoc;
1180 if (
auto Iter = LocToName.find(ReturnLoc);
Iter != LocToName.end())
1181 OS <<
" (" <<
Iter->second <<
")";
1183 }
else if (
Func->getReturnType()->isRecordType() ||
1184 isa<CXXConstructorDecl>(
Func)) {
1185 OS <<
"LocForRecordReturnVal: " << LocForRecordReturnVal <<
"\n";
1186 }
else if (!
Func->getReturnType()->isVoidType()) {
1187 if (ReturnVal ==
nullptr)
1188 OS <<
"ReturnVal: nullptr\n";
1190 OS <<
"ReturnVal: " << *ReturnVal <<
"\n";
1193 if (isa<CXXMethodDecl>(
Func)) {
1194 OS <<
"ThisPointeeLoc: " << ThisPointeeLoc <<
"\n";
1204Environment::PrValueToResultObject Environment::buildResultObjectMap(
1210 PrValueToResultObject Map = buildResultObjectMap(
1211 DACtx, FuncDecl->
getBody(), ThisPointeeLoc, LocForRecordReturnVal);
1213 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1214 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl))
1215 Visitor.traverseConstructorInits(Ctor, ThisPointeeLoc);
1220Environment::PrValueToResultObject Environment::buildResultObjectMap(
1221 DataflowAnalysisContext *DACtx,
Stmt *S,
1222 RecordStorageLocation *ThisPointeeLoc,
1223 RecordStorageLocation *LocForRecordReturnVal) {
1224 PrValueToResultObject Map;
1225 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1226 Visitor.TraverseStmt(S);
1233 if (ImplicitObject ==
nullptr)
1237 return &cast<RecordStorageLocation>(Val->getPointeeLoc());
1240 return cast_or_null<RecordStorageLocation>(
1247 if (
Base ==
nullptr)
1251 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 IsVolatile, 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.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
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.
Decl * getNonClosureAncestor()
Find the nearest non-closure ancestor of this context, i.e.
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()
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.
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 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.
const FunctionProtoType * T
@ 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.