[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