This revision was automatically updated to reflect the committed changes. Closed by commit rG3ce03c42dbb4: [clang][dataflow] Fix 2 bugs in `MemberExpr` interpretation. (authored by ymandel).
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D141384/new/ https://reviews.llvm.org/D141384 Files: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/Transfer.cpp clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Index: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp =================================================================== --- clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -1066,6 +1066,28 @@ }); } +TEST(TransferTest, StructMemberEnum) { + std::string Code = R"( + struct A { + int Bar; + enum E { ONE, TWO }; + }; + + void target(A Foo) { + A::E Baz = Foo.ONE; + // [[p]] + } + )"; + // Minimal expectations -- we're just testing that it doesn't crash, since + // enums aren't interpreted. + runDataflow( + Code, + [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results, + ASTContext &ASTCtx) { + EXPECT_THAT(Results.keys(), UnorderedElementsAre("p")); + }); +} + TEST(TransferTest, DerivedBaseMemberClass) { std::string Code = R"( class A { Index: clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp =================================================================== --- clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -118,7 +118,7 @@ Context); const auto *Fun = selectFirst<FunctionDecl>("target", Results); const auto *Var = selectFirst<VarDecl>("global", Results); - ASSERT_TRUE(Fun != nullptr); + ASSERT_THAT(Fun, NotNull()); ASSERT_THAT(Var, NotNull()); // Verify the global variable is populated when we analyze `Target`. @@ -126,6 +126,53 @@ EXPECT_THAT(Env.getValue(*Var, SkipPast::None), NotNull()); } +TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) { + using namespace ast_matchers; + + std::string Code = R"cc( + struct S { int Bar; }; + S Global = {0}; + int Target () { return Global.Bar; } + )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(decl(anyOf(varDecl(hasName("Global")).bind("global"), + functionDecl(hasName("Target")).bind("target"))), + Context); + const auto *Fun = selectFirst<FunctionDecl>("target", Results); + const auto *GlobalDecl = selectFirst<VarDecl>("global", Results); + ASSERT_THAT(Fun, NotNull()); + ASSERT_THAT(GlobalDecl, NotNull()); + + ASSERT_TRUE(GlobalDecl->getType()->isStructureType()); + auto GlobalFields = GlobalDecl->getType()->getAsRecordDecl()->fields(); + + FieldDecl *BarDecl = nullptr; + for (FieldDecl *Field : GlobalFields) { + if (Field->getNameAsString() == "Bar") { + BarDecl = Field; + break; + } + FAIL() << "Unexpected field: " << Field->getNameAsString(); + } + ASSERT_THAT(BarDecl, NotNull()); + + // Verify the global variable is populated when we analyze `Target`. + Environment Env(DAContext, *Fun); + const auto *GlobalLoc = cast<AggregateStorageLocation>( + Env.getStorageLocation(*GlobalDecl, SkipPast::None)); + const auto *GlobalVal = cast<StructValue>(Env.getValue(*GlobalLoc)); + const auto *BarVal = GlobalVal->getChild(*BarDecl); + ASSERT_THAT(BarVal, NotNull()); + EXPECT_TRUE(isa<IntegerValue>(BarVal)); +} + TEST_F(EnvironmentTest, InitGlobalVarsConstructor) { using namespace ast_matchers; Index: clang/lib/Analysis/FlowSensitive/Transfer.cpp =================================================================== --- clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -461,6 +461,10 @@ if (Member->isFunctionOrFunctionTemplate()) return; + // FIXME: if/when we add support for modeling enums, use that support here. + if (isa<EnumConstantDecl>(Member)) + return; + if (auto *D = dyn_cast<VarDecl>(Member)) { if (D->hasGlobalStorage()) { auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None); Index: clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp =================================================================== --- clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -250,11 +250,12 @@ } getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars); - initVars(Vars); - // These have to be set before the lines that follow to ensure that create* - // work correctly for structs. + // These have to be added before the lines that follow to ensure that + // `create*` work correctly for structs. DACtx.addModeledFields(Fields); + initVars(Vars); + for (const auto *ParamDecl : FuncDecl->parameters()) { assert(ParamDecl != nullptr); auto &ParamLoc = createStorageLocation(*ParamDecl); @@ -341,9 +342,13 @@ } } getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars); - initVars(Vars); + + // These have to be added before the lines that follow to ensure that + // `create*` work correctly for structs. DACtx->addModeledFields(Fields); + initVars(Vars); + const auto *ParamIt = FuncDecl->param_begin(); // FIXME: Parameters don't always map to arguments 1:1; examples include
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits