[clang] 73c9883 - [clang][dataflow] Fix missed fields in field set construction.

Yitzhak Mandelbaum via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 28 10:57:46 PST 2023


Author: Yitzhak Mandelbaum
Date: 2023-02-28T18:56:54Z
New Revision: 73c98831f6482371f9b773592478ea9e51a6b16a

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

LOG: [clang][dataflow] Fix missed fields in field set construction.

When building the set of referenced fields for the `DataflowAnalysisContext`,
include fields referenced only in default member initializers. These
initializers are visited in the CFGs of constructors and so the fields must be
included when analysing constructor bodies.

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

Added: 
    

Modified: 
    clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
    clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index cc3992805cc78..5d502fee30daf 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -242,7 +242,8 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
     llvm::DenseSet<const FieldDecl *> Fields;
     llvm::DenseSet<const VarDecl *> Vars;
 
-    // Look for global variable references in the constructor-initializers.
+    // Look for global variable and field references in the
+    // constructor-initializers.
     if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&DeclCtx)) {
       for (const auto *Init : CtorDecl->inits()) {
         if (const auto *M = Init->getAnyMember())
@@ -251,6 +252,10 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
         assert(E != nullptr);
         getFieldsAndGlobalVars(*E, Fields, Vars);
       }
+      // 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);
     }
     getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars);
 

diff  --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
index dfbd4ff274154..fa7322bc586be 100644
--- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
@@ -7,13 +7,14 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
-#include "TestingSupport.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
-#include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
+#include "clang/Analysis/FlowSensitive/StorageLocation.h"
 #include "clang/Analysis/FlowSensitive/Value.h"
 #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
+#include "clang/Tooling/Tooling.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include <memory>
@@ -126,6 +127,58 @@ TEST_F(EnvironmentTest, InitGlobalVarsFun) {
   EXPECT_THAT(Env.getValue(*Var, SkipPast::None), NotNull());
 }
 
+// Tests that fields mentioned only in default member initializers are included
+// in the set of tracked fields.
+TEST_F(EnvironmentTest, IncludeFieldsFromDefaultInitializers) {
+  using namespace ast_matchers;
+
+  std::string Code = R"cc(
+     struct S {
+     S() {}
+     int X = 3;
+     int Y = X;
+     };
+     S foo();
+  )cc";
+
+  auto Unit =
+      tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"});
+  auto &Context = Unit->getASTContext();
+
+  ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U);
+
+  auto Results = match(
+      qualType(hasDeclaration(
+                   cxxRecordDecl(hasName("S"),
+                                 hasMethod(cxxConstructorDecl().bind("target")))
+                       .bind("struct")))
+          .bind("ty"),
+      Context);
+  const auto *Constructor = selectFirst<FunctionDecl>("target", Results);
+  const auto *Rec = selectFirst<RecordDecl>("struct", Results);
+  const auto QTy = *selectFirst<QualType>("ty", Results);
+  ASSERT_THAT(Constructor, NotNull());
+  ASSERT_THAT(Rec, NotNull());
+  ASSERT_FALSE(QTy.isNull());
+
+  auto Fields = Rec->fields();
+  FieldDecl *XDecl = nullptr;
+  for (FieldDecl *Field : Fields) {
+    if (Field->getNameAsString() == "X") {
+      XDecl = Field;
+      break;
+    }
+  }
+  ASSERT_THAT(XDecl, NotNull());
+
+  // Verify that the `X` field of `S` is populated when analyzing the
+  // constructor, even though it is not referenced directly in the constructor.
+  Environment Env(DAContext, *Constructor);
+  auto *Val = cast<StructValue>(Env.createValue(QTy));
+  ASSERT_THAT(Val, NotNull());
+  EXPECT_THAT(Val->getChild(*XDecl), NotNull());
+}
+
 TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) {
   using namespace ast_matchers;
 


        


More information about the cfe-commits mailing list