[clang] d9e7173 - [clang][dataflow] Associate `FunctionToPointerDecay` nodes with a value.
Martin Braenne via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 18 00:15:39 PDT 2023
Author: Martin Braenne
Date: 2023-04-18T07:15:29Z
New Revision: d9e717338f8042664177250315364094262c7073
URL: https://github.com/llvm/llvm-project/commit/d9e717338f8042664177250315364094262c7073
DIFF: https://github.com/llvm/llvm-project/commit/d9e717338f8042664177250315364094262c7073.diff
LOG: [clang][dataflow] Associate `FunctionToPointerDecay` nodes with a value.
To ensure that we have a pointee for the `PointerValue`, we also create
storage locations for `FunctionDecl`s referenced in the function under analysis.
Reviewed By: gribozavr2
Differential Revision: https://reviews.llvm.org/D148006
Added:
Modified:
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
Removed:
################################################################################
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 97ea6a573cffd..4e65d974133a6 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -492,9 +492,9 @@ class Environment {
void pushCallInternal(const FunctionDecl *FuncDecl,
ArrayRef<const Expr *> Args);
- /// Assigns storage locations and values to all global variables and fields
- /// referenced in `FuncDecl`. `FuncDecl` must have a body.
- void initFieldsAndGlobals(const FunctionDecl *FuncDecl);
+ /// Assigns storage locations and values to all global variables, fields
+ /// and functions referenced in `FuncDecl`. `FuncDecl` must have a body.
+ void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl);
// `DACtx` is not null and not owned by this object.
DataflowAnalysisContext *DACtx;
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 680036b6a5b39..9f5b3adc8b1b1 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -162,10 +162,19 @@ static void insertIfGlobal(const Decl &D,
Vars.insert(V);
}
-static void getFieldsAndGlobalVars(const Decl &D,
- llvm::DenseSet<const FieldDecl *> &Fields,
- llvm::DenseSet<const VarDecl *> &Vars) {
+static void insertIfFunction(const Decl &D,
+ llvm::DenseSet<const FunctionDecl *> &Funcs) {
+ if (auto *FD = dyn_cast<FunctionDecl>(&D))
+ Funcs.insert(FD);
+}
+
+static void
+getFieldsGlobalsAndFuncs(const Decl &D,
+ llvm::DenseSet<const FieldDecl *> &Fields,
+ llvm::DenseSet<const VarDecl *> &Vars,
+ llvm::DenseSet<const FunctionDecl *> &Funcs) {
insertIfGlobal(D, Vars);
+ insertIfFunction(D, Funcs);
if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
for (const auto *B : Decomp->bindings())
if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
@@ -174,27 +183,32 @@ static void getFieldsAndGlobalVars(const Decl &D,
Fields.insert(FD);
}
-/// Traverses `S` and inserts into `Vars` any global storage values that are
-/// declared in or referenced from sub-statements.
-static void getFieldsAndGlobalVars(const Stmt &S,
- llvm::DenseSet<const FieldDecl *> &Fields,
- llvm::DenseSet<const VarDecl *> &Vars) {
+/// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields,
+/// global variables and functions that are declared in or referenced from
+/// sub-statements.
+static void
+getFieldsGlobalsAndFuncs(const Stmt &S,
+ llvm::DenseSet<const FieldDecl *> &Fields,
+ llvm::DenseSet<const VarDecl *> &Vars,
+ llvm::DenseSet<const FunctionDecl *> &Funcs) {
for (auto *Child : S.children())
if (Child != nullptr)
- getFieldsAndGlobalVars(*Child, Fields, Vars);
+ getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs);
if (auto *DS = dyn_cast<DeclStmt>(&S)) {
if (DS->isSingleDecl())
- getFieldsAndGlobalVars(*DS->getSingleDecl(), Fields, Vars);
+ getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs);
else
for (auto *D : DS->getDeclGroup())
- getFieldsAndGlobalVars(*D, Fields, Vars);
+ getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs);
} else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
insertIfGlobal(*E->getDecl(), Vars);
+ insertIfFunction(*E->getDecl(), Funcs);
} else if (auto *E = dyn_cast<MemberExpr>(&S)) {
// FIXME: should we be using `E->getFoundDecl()`?
const ValueDecl *VD = E->getMemberDecl();
insertIfGlobal(*VD, Vars);
+ insertIfFunction(*VD, Funcs);
if (const auto *FD = dyn_cast<FieldDecl>(VD))
Fields.insert(FD);
}
@@ -202,11 +216,12 @@ static void getFieldsAndGlobalVars(const Stmt &S,
// FIXME: Add support for resetting globals after function calls to enable
// the implementation of sound analyses.
-void Environment::initFieldsAndGlobals(const FunctionDecl *FuncDecl) {
+void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {
assert(FuncDecl->getBody() != nullptr);
llvm::DenseSet<const FieldDecl *> Fields;
llvm::DenseSet<const VarDecl *> Vars;
+ llvm::DenseSet<const FunctionDecl *> Funcs;
// Look for global variable and field references in the
// constructor-initializers.
@@ -216,14 +231,14 @@ void Environment::initFieldsAndGlobals(const FunctionDecl *FuncDecl) {
Fields.insert(M);
const Expr *E = Init->getInit();
assert(E != nullptr);
- getFieldsAndGlobalVars(*E, Fields, Vars);
+ getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);
}
// Add all fields mentioned in default member initializers.
for (const FieldDecl *F : CtorDecl->getParent()->fields())
if (const auto *I = F->getInClassInitializer())
- getFieldsAndGlobalVars(*I, Fields, Vars);
+ getFieldsGlobalsAndFuncs(*I, Fields, Vars, Funcs);
}
- getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars);
+ getFieldsGlobalsAndFuncs(*FuncDecl->getBody(), Fields, Vars, Funcs);
// These have to be added before the lines that follow to ensure that
// `create*` work correctly for structs.
@@ -237,6 +252,13 @@ void Environment::initFieldsAndGlobals(const FunctionDecl *FuncDecl) {
if (auto *Val = createValue(D->getType()))
setValue(Loc, *Val);
}
+
+ for (const FunctionDecl *FD : Funcs) {
+ if (getStorageLocation(*FD, SkipPast::None) != nullptr)
+ continue;
+ auto &Loc = createStorageLocation(FD->getType());
+ setStorageLocation(*FD, Loc);
+ }
}
Environment::Environment(DataflowAnalysisContext &DACtx)
@@ -264,7 +286,7 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
assert(FuncDecl->getBody() != nullptr);
- initFieldsAndGlobals(FuncDecl);
+ initFieldsGlobalsAndFuncs(FuncDecl);
for (const auto *ParamDecl : FuncDecl->parameters()) {
assert(ParamDecl != nullptr);
@@ -338,7 +360,7 @@ void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
ArrayRef<const Expr *> Args) {
CallStack.push_back(FuncDecl);
- initFieldsAndGlobals(FuncDecl);
+ initFieldsGlobalsAndFuncs(FuncDecl);
const auto *ParamIt = FuncDecl->param_begin();
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 1d273e77ef0b5..2d85e7b90f73e 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -403,6 +403,18 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
Env.setValue(Loc, NullPointerVal);
break;
}
+ case CK_FunctionToPointerDecay: {
+ StorageLocation *PointeeLoc =
+ Env.getStorageLocation(*SubExpr, SkipPast::Reference);
+ if (PointeeLoc == nullptr)
+ break;
+
+ auto &PointerLoc = Env.createStorageLocation(*S);
+ auto &PointerVal = Env.create<PointerValue>(*PointeeLoc);
+ Env.setStorageLocation(*S, PointerLoc);
+ Env.setValue(PointerLoc, PointerVal);
+ break;
+ }
default:
break;
}
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 8f02161834dc8..1589067a81c7b 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -5232,4 +5232,43 @@ TEST(TransferTest, NewExpressions_Structs) {
});
}
+TEST(TransferTest, FunctionToPointerDecayHasValue) {
+ std::string Code = R"(
+ struct A { static void static_member_func(); };
+ void target() {
+ // To check that we're treating function-to-pointer decay correctly,
+ // create two pointers, then verify they refer to the same storage
+ // location.
+ // We need to do the test this way because even if an initializer (in this
+ // case, the function-to-pointer decay) does not create a value, we still
+ // create a value for the variable.
+ void (*non_member_p1)() = target;
+ void (*non_member_p2)() = target;
+
+ // Do the same thing but for a static member function.
+ void (*member_p1)() = A::static_member_func;
+ void (*member_p2)() = A::static_member_func;
+ // [[p]]
+ }
+ )";
+ runDataflow(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+ auto &NonMemberP1 =
+ getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p1");
+ auto &NonMemberP2 =
+ getValueForDecl<PointerValue>(ASTCtx, Env, "non_member_p2");
+ EXPECT_EQ(&NonMemberP1.getPointeeLoc(), &NonMemberP2.getPointeeLoc());
+
+ auto &MemberP1 =
+ getValueForDecl<PointerValue>(ASTCtx, Env, "member_p1");
+ auto &MemberP2 =
+ getValueForDecl<PointerValue>(ASTCtx, Env, "member_p2");
+ EXPECT_EQ(&MemberP1.getPointeeLoc(), &MemberP2.getPointeeLoc());
+ });
+}
+
} // namespace
More information about the cfe-commits
mailing list