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; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits