ymandel created this revision.
ymandel added reviewers: xazax.hun, sgatev, gribozavr2.
Herald added subscribers: martong, rnkovacs.
Herald added a reviewer: NoQ.
Herald added a project: All.
ymandel requested review of this revision.
Herald added a project: clang.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D144987

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

Index: clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
===================================================================
--- clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
+++ 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 @@
   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;
 
Index: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
===================================================================
--- clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -242,7 +242,8 @@
     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 @@
         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);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D144987: [clang... Yitzhak Mandelbaum via Phabricator via cfe-commits

Reply via email to