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