[clang] e8a1560 - [clang][dataflow] Various changes to handling of modeled fields.

Martin Braenne via cfe-commits cfe-commits at lists.llvm.org
Sun Jul 9 23:46:04 PDT 2023


Author: Martin Braenne
Date: 2023-07-10T06:45:53Z
New Revision: e8a1560d1de9514d3f1631388fe966476778e540

URL: https://github.com/llvm/llvm-project/commit/e8a1560d1de9514d3f1631388fe966476778e540
DIFF: https://github.com/llvm/llvm-project/commit/e8a1560d1de9514d3f1631388fe966476778e540.diff

LOG: [clang][dataflow] Various changes to handling of modeled fields.

- Rename `getReferencedFields()` to `getModeledFields()`. Move the logic that
  returns all object fields when doing a context-sensitive analysis to here from
  `DataflowAnalysisContext::createStorageLocation()`. I think all callers of
  the previous `getReferencedFields()` should use this logic; the fact that they
  were not doing so looks like a bug.

- Make `getModeledFields()` public. I have an upcoming patch that will need to
  use this function from Transfer.cpp, and there doesn't seem to be any reason
  why this function should not be public.

- Use a `SmallSetVector` to get deterministic iteration order. I have a pending
  patch where I'm getting flaky tests because
  `Environment::createValueUnlessSelfReferential()` is non-deterministically
  populating different fields depending on the iteration order. This change
  fixes those flaky tests.

Reviewed By: gribozavr2

Differential Revision: https://reviews.llvm.org/D154586

Added: 
    

Modified: 
    clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
    clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
    clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
index 2a31a3477e8ceb..e5c325b876bd7a 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -51,8 +51,12 @@ class Logger;
 const Expr &ignoreCFGOmittedNodes(const Expr &E);
 const Stmt &ignoreCFGOmittedNodes(const Stmt &S);
 
+/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic
+/// iteration order.
+using FieldSet = llvm::SmallSetVector<const FieldDecl *, 4>;
+
 /// Returns the set of all fields in the type.
-llvm::DenseSet<const FieldDecl *> getObjectFields(QualType Type);
+FieldSet getObjectFields(QualType Type);
 
 struct ContextSensitiveOptions {
   /// The maximum depth to analyze. A value of zero is equivalent to disabling
@@ -181,6 +185,10 @@ class DataflowAnalysisContext {
   /// been stored in flow conditions.
   Solver::Result querySolver(llvm::SetVector<const Formula *> Constraints);
 
+  /// Returns the fields of `Type`, limited to the set of fields modeled by this
+  /// context.
+  FieldSet getModeledFields(QualType Type);
+
 private:
   friend class Environment;
 
@@ -196,11 +204,7 @@ class DataflowAnalysisContext {
   };
 
   // Extends the set of modeled field declarations.
-  void addModeledFields(const llvm::DenseSet<const FieldDecl *> &Fields);
-
-  /// Returns the fields of `Type`, limited to the set of fields modeled by this
-  /// context.
-  llvm::DenseSet<const FieldDecl *> getReferencedFields(QualType Type);
+  void addModeledFields(const FieldSet &Fields);
 
   /// Adds all constraints of the flow condition identified by `Token` and all
   /// of its transitive dependencies to `Constraints`. `VisitedTokens` is used
@@ -257,7 +261,7 @@ class DataflowAnalysisContext {
   llvm::DenseMap<const FunctionDecl *, ControlFlowContext> FunctionContexts;
 
   // Fields modeled by environments covered by this context.
-  llvm::DenseSet<const FieldDecl *> ModeledFields;
+  FieldSet ModeledFields;
 
   std::unique_ptr<Logger> LogOwner; // If created via flags.
 };

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index a807ef8209be85..b0c1014e3c975e 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -40,31 +40,28 @@ static llvm::cl::opt<std::string> DataflowLog(
 namespace clang {
 namespace dataflow {
 
-void DataflowAnalysisContext::addModeledFields(
-    const llvm::DenseSet<const FieldDecl *> &Fields) {
-  llvm::set_union(ModeledFields, Fields);
+FieldSet DataflowAnalysisContext::getModeledFields(QualType Type) {
+  // During context-sensitive analysis, a struct may be allocated in one
+  // function, but its field accessed in a function lower in the stack than
+  // the allocation. Since we only collect fields used in the function where
+  // the allocation occurs, we can't apply that filter when performing
+  // context-sensitive analysis. But, this only applies to storage locations,
+  // since field access it not allowed to fail. In contrast, field *values*
+  // don't need this allowance, since the API allows for uninitialized fields.
+  if (Opts.ContextSensitiveOpts)
+    return getObjectFields(Type);
+
+  return llvm::set_intersection(getObjectFields(Type), ModeledFields);
 }
 
-llvm::DenseSet<const FieldDecl *>
-DataflowAnalysisContext::getReferencedFields(QualType Type) {
-  llvm::DenseSet<const FieldDecl *> Fields = getObjectFields(Type);
-  llvm::set_intersect(Fields, ModeledFields);
-  return Fields;
+void DataflowAnalysisContext::addModeledFields(const FieldSet &Fields) {
+  ModeledFields.set_union(Fields);
 }
 
 StorageLocation &DataflowAnalysisContext::createStorageLocation(QualType Type) {
   if (!Type.isNull() && Type->isRecordType()) {
     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
-    // During context-sensitive analysis, a struct may be allocated in one
-    // function, but its field accessed in a function lower in the stack than
-    // the allocation. Since we only collect fields used in the function where
-    // the allocation occurs, we can't apply that filter when performing
-    // context-sensitive analysis. But, this only applies to storage locations,
-    // since field access it not allowed to fail. In contrast, field *values*
-    // don't need this allowance, since the API allows for uninitialized fields.
-    auto Fields = Opts.ContextSensitiveOpts ? getObjectFields(Type)
-                                            : getReferencedFields(Type);
-    for (const FieldDecl *Field : Fields)
+    for (const FieldDecl *Field : getModeledFields(Type))
       FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
     return arena().create<AggregateStorageLocation>(Type, std::move(FieldLocs));
   }
@@ -305,9 +302,8 @@ const Stmt &clang::dataflow::ignoreCFGOmittedNodes(const Stmt &S) {
 
 // FIXME: Does not precisely handle non-virtual diamond inheritance. A single
 // field decl will be modeled for all instances of the inherited field.
-static void
-getFieldsFromClassHierarchy(QualType Type,
-                            llvm::DenseSet<const FieldDecl *> &Fields) {
+static void getFieldsFromClassHierarchy(QualType Type,
+                                        clang::dataflow::FieldSet &Fields) {
   if (Type->isIncompleteType() || Type->isDependentType() ||
       !Type->isRecordType())
     return;
@@ -320,9 +316,8 @@ getFieldsFromClassHierarchy(QualType Type,
 }
 
 /// Gets the set of all fields in the type.
-llvm::DenseSet<const FieldDecl *>
-clang::dataflow::getObjectFields(QualType Type) {
-  llvm::DenseSet<const FieldDecl *> Fields;
+clang::dataflow::FieldSet clang::dataflow::getObjectFields(QualType Type) {
+  FieldSet Fields;
   getFieldsFromClassHierarchy(Type, Fields);
   return Fields;
 }

diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 11bb7da97d52f4..c3de50894c9ede 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -170,8 +170,7 @@ static void insertIfFunction(const Decl &D,
 }
 
 static void
-getFieldsGlobalsAndFuncs(const Decl &D,
-                         llvm::DenseSet<const FieldDecl *> &Fields,
+getFieldsGlobalsAndFuncs(const Decl &D, FieldSet &Fields,
                          llvm::DenseSet<const VarDecl *> &Vars,
                          llvm::DenseSet<const FunctionDecl *> &Funcs) {
   insertIfGlobal(D, Vars);
@@ -188,8 +187,7 @@ getFieldsGlobalsAndFuncs(const Decl &D,
 /// global variables and functions that are declared in or referenced from
 /// sub-statements.
 static void
-getFieldsGlobalsAndFuncs(const Stmt &S,
-                         llvm::DenseSet<const FieldDecl *> &Fields,
+getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields,
                          llvm::DenseSet<const VarDecl *> &Vars,
                          llvm::DenseSet<const FunctionDecl *> &Funcs) {
   for (auto *Child : S.children())
@@ -222,7 +220,7 @@ getFieldsGlobalsAndFuncs(const Stmt &S,
 void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {
   assert(FuncDecl->getBody() != nullptr);
 
-  llvm::DenseSet<const FieldDecl *> Fields;
+  FieldSet Fields;
   llvm::DenseSet<const VarDecl *> Vars;
   llvm::DenseSet<const FunctionDecl *> Funcs;
 
@@ -708,7 +706,7 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) {
     const QualType Type = AggregateLoc.getType();
     assert(Type->isRecordType());
 
-    for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) {
+    for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
       assert(Field != nullptr);
       StorageLocation &FieldLoc = AggregateLoc.getChild(*Field);
       MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field);
@@ -846,7 +844,7 @@ Value *Environment::createValueUnlessSelfReferential(
   if (Type->isRecordType()) {
     CreatedValuesCount++;
     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
-    for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) {
+    for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
       assert(Field != nullptr);
 
       QualType FieldType = Field->getType();


        


More information about the cfe-commits mailing list