samestep updated this revision to Diff 448044.
samestep added a comment.
Set a storage location for the outermost context too
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D130600/new/
https://reviews.llvm.org/D130600
Files:
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Index: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
===================================================================
--- clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -3903,7 +3903,10 @@
TEST(TransferTest, ContextSensitiveSetTrue) {
std::string Code = R"(
bool GiveBool();
- void SetBool(bool &Var) { Var = true; }
+ void SetBool(bool &Var) {
+ Var = true;
+ return;
+ }
void target() {
bool Foo = GiveBool();
@@ -3933,7 +3936,10 @@
TEST(TransferTest, ContextSensitiveSetFalse) {
std::string Code = R"(
bool GiveBool();
- void SetBool(bool &Var) { Var = false; }
+ void SetBool(bool &Var) {
+ Var = false;
+ return;
+ }
void target() {
bool Foo = GiveBool();
@@ -4001,4 +4007,60 @@
/*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
}
+TEST(TransferTest, ContextSensitiveReturnTrue) {
+ std::string Code = R"(
+ bool GiveBool() { return true; }
+
+ void target() {
+ bool Foo = GiveBool();
+ // [[p]]
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const Environment &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ auto &FooVal =
+ *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
+ EXPECT_TRUE(Env.flowConditionImplies(FooVal));
+ },
+ {/*.ApplyBuiltinTransfer=*/true,
+ /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
+}
+
+TEST(TransferTest, ContextSensitiveReturnFalse) {
+ std::string Code = R"(
+ bool GiveBool() { return false; }
+
+ void target() {
+ bool Foo = GiveBool();
+ // [[p]]
+ }
+ )";
+ runDataflow(Code,
+ [](llvm::ArrayRef<
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+ Results,
+ ASTContext &ASTCtx) {
+ ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+ const Environment &Env = Results[0].second.Env;
+
+ const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+ ASSERT_THAT(FooDecl, NotNull());
+
+ auto &FooVal =
+ *cast<BoolValue>(Env.getValue(*FooDecl, SkipPast::None));
+ EXPECT_TRUE(Env.flowConditionImplies(Env.makeNot(FooVal)));
+ },
+ {/*.ApplyBuiltinTransfer=*/true,
+ /*.BuiltinTransferOptions=*/{/*.ContextSensitive=*/true}});
+}
+
} // namespace
Index: clang/lib/Analysis/FlowSensitive/Transfer.cpp
===================================================================
--- clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -332,6 +332,21 @@
std::make_unique<PointerValue>(*ThisPointeeLoc)));
}
+ void VisitReturnStmt(const ReturnStmt *S) {
+ auto *Ret = S->getRetValue();
+ if (Ret == nullptr)
+ return;
+
+ auto *Val = Env.getValue(*Ret, SkipPast::Reference);
+ if (Val == nullptr)
+ return;
+
+ auto *Loc = Env.getReturnStorageLocation();
+ assert(Loc != nullptr);
+ // FIXME: Model NRVO.
+ Env.setValue(*Loc, *Val);
+ }
+
void VisitMemberExpr(const MemberExpr *S) {
ValueDecl *Member = S->getMemberDecl();
assert(Member != nullptr);
@@ -534,7 +549,11 @@
auto ExitState = (*BlockToOutputState)[ExitBlock];
assert(ExitState);
- Env.popCall(ExitState->Env);
+ auto &ExitEnv = ExitState->Env;
+ auto *ReturnLoc = ExitEnv.getReturnStorageLocation();
+ assert(ReturnLoc != nullptr);
+ Env.setStorageLocation(*S, *ReturnLoc);
+ Env.popCall(ExitEnv);
}
}
Index: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
===================================================================
--- clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -179,6 +179,10 @@
if (Value *ParamVal = createValue(ParamDecl->getType()))
setValue(ParamLoc, *ParamVal);
}
+
+ QualType ReturnType = FuncDecl->getReturnType();
+ auto &ReturnLoc = createStorageLocation(ReturnType);
+ DACtx.getFrame(CallStr).setReturnStorageLocation(ReturnLoc);
}
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
@@ -204,6 +208,16 @@
Environment Env(*this);
Env.CallStr.push_back(Call);
+ const auto *FuncDecl = Call->getDirectCallee();
+ assert(FuncDecl != nullptr);
+
+ auto *ReturnLoc = DACtx->getFrame(Env.CallStr).getReturnStorageLocation();
+ if (ReturnLoc == nullptr) {
+ QualType ReturnType = FuncDecl->getReturnType();
+ DACtx->getFrame(Env.CallStr)
+ .setReturnStorageLocation(Env.createStorageLocation(ReturnType));
+ }
+
// FIXME: Currently this only works if the callee is never a method and the
// same callee is never analyzed from multiple separate callsites. To
// generalize this, we'll need to store a "context" field (probably a stack of
@@ -212,8 +226,6 @@
// where each frame stores its own version of what are currently the
// `DeclToLoc`, `ExprToLoc`, and `ThisPointeeLoc` fields.
- const auto *FuncDecl = Call->getDirectCallee();
- assert(FuncDecl != nullptr);
const auto *Body = FuncDecl->getBody();
assert(Body != nullptr);
// FIXME: In order to allow the callee to reference globals, we probably need
@@ -380,6 +392,10 @@
return DACtx->getFrame(CallStr).getThisPointeeStorageLocation();
}
+StorageLocation *Environment::getReturnStorageLocation() const {
+ return DACtx->getFrame(CallStr).getReturnStorageLocation();
+}
+
PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
return DACtx->getOrCreateNullPointerValue(PointeeType);
}
Index: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
===================================================================
--- clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -221,6 +221,10 @@
/// in the environment.
StorageLocation *getThisPointeeStorageLocation() const;
+ /// Returns the storage location of the return value or null if it was not set
+ /// yet.
+ StorageLocation *getReturnStorageLocation() const;
+
/// Returns a pointer value that represents a null pointer. Calls with
/// `PointeeType` that are canonically equivalent will return the same result.
PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
Index: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
===================================================================
--- clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -107,6 +107,20 @@
return ThisPointeeLoc;
}
+ /// Assigns `Loc` as the storage location of the return value.
+ ///
+ /// Requirements:
+ ///
+ /// `return` must not be assigned a storage location.
+ void setReturnStorageLocation(StorageLocation &Loc) {
+ assert(ReturnLoc == nullptr);
+ ReturnLoc = &Loc;
+ }
+
+ /// Returns the storage location of the returned value or null if it was not
+ /// set yet.
+ StorageLocation *getReturnStorageLocation() const { return ReturnLoc; }
+
private:
// Maps from program declarations and statements to storage locations that are
// assigned to them. These assignments are global (aggregated across all basic
@@ -117,6 +131,7 @@
llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc;
StorageLocation *ThisPointeeLoc = nullptr;
+ StorageLocation *ReturnLoc = nullptr;
};
/// Owns objects that encompass the state of a program and stores context that
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits