diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -178,17 +178,10 @@ return; } - if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) { + if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) Env.setValue(Loc, *InitExprVal); - } else if (!D.getType()->isStructureOrClassType()) { - // FIXME: The initializer expression must always be assigned a value. - // Replace this with an assert when we have sufficient coverage of - // language features. - if (Value *Val = Env.createValue(D.getType())) - Env.setValue(Loc, *Val); - } else { - llvm_unreachable("structs and classes must always be assigned values"); - } + else if (Value *Val = Env.createValue(D.getType())) + Env.setValue(Loc, *Val); } void VisitImplicitCastExpr(const ImplicitCastExpr *S) { diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -187,6 +187,54 @@ }); } +TEST_F(TransferTest, StructVarDeclWithInit) { + std::string Code = R"( + struct A { + int Bar; + }; + + A Gen(); + + void target() { + A Foo = Gen(); + // [[p]] + } + )"; + runDataflow( + Code, [](llvm::ArrayRef< + std::pair>> + Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results, ElementsAre(Pair("p", _))); + const Environment &Env = Results[0].second.Env; + + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + ASSERT_TRUE(FooDecl->getType()->isStructureType()); + auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields(); + + FieldDecl *BarDecl = nullptr; + for (FieldDecl *Field : FooFields) { + if (Field->getNameAsString() == "Bar") { + BarDecl = Field; + } else { + FAIL() << "Unexpected field: " << Field->getNameAsString(); + } + } + ASSERT_THAT(BarDecl, NotNull()); + + const auto *FooLoc = cast( + Env.getStorageLocation(*FooDecl, SkipPast::None)); + const auto *BarLoc = + cast(&FooLoc->getChild(*BarDecl)); + + const auto *FooVal = cast(Env.getValue(*FooLoc)); + const auto *BarVal = cast(FooVal->getChild(*BarDecl)); + EXPECT_EQ(Env.getValue(*BarLoc), BarVal); + }); +} + TEST_F(TransferTest, ClassVarDecl) { std::string Code = R"( class A {