diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -227,8 +227,12 @@ // constructor-initializers. if (const auto *CtorDecl = dyn_cast(FuncDecl)) { for (const auto *Init : CtorDecl->inits()) { - if (const auto *M = Init->getAnyMember()) - Fields.insert(M); + if (Init->isMemberInitializer()) { + Fields.insert(Init->getMember()); + } else if (Init->isIndirectMemberInitializer()) { + for (const auto *I : Init->getIndirectMember()->chain()) + Fields.insert(cast(I)); + } const Expr *E = Init->getInit(); assert(E != nullptr); getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs); 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 @@ -153,7 +153,7 @@ Env.setStorageLocationStrict(To, *Loc); } -// Forwards the value or storage location of `From` to `To` in cases where +// Propagates the value or storage location of `From` to `To` in cases where // `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff // `From` is a glvalue. static void propagateValueOrStorageLocation(const Expr &From, const Expr &To, @@ -572,18 +572,7 @@ void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { const Expr *InitExpr = S->getExpr(); assert(InitExpr != nullptr); - - Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None); - if (InitExprVal == nullptr) - return; - - const FieldDecl *Field = S->getField(); - assert(Field != nullptr); - - auto &ThisLoc = - *cast(Env.getThisPointeeStorageLocation()); - auto &FieldLoc = ThisLoc.getChild(*Field); - Env.setValue(FieldLoc, *InitExprVal); + propagateValueOrStorageLocation(*InitExpr, *S, Env); } void VisitCXXConstructExpr(const CXXConstructExpr *S) { diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -366,27 +366,41 @@ assert(Init != nullptr); auto &Env = InputState.Env; - const auto &ThisLoc = + auto &ThisLoc = *cast(Env.getThisPointeeStorageLocation()); - const FieldDecl *Member = Init->getMember(); - if (Member == nullptr) - // Not a field initializer. + if (!Init->isAnyMemberInitializer()) + // FIXME: Handle base initialization return; auto *InitStmt = Init->getInit(); assert(InitStmt != nullptr); + const FieldDecl *Member = nullptr; + StorageLocation *MemberLoc = nullptr; + if (Init->isMemberInitializer()) { + Member = Init->getMember(); + MemberLoc = &ThisLoc.getChild(*Member); + } else { + IndirectFieldDecl *IndirectField = Init->getIndirectMember(); + assert(IndirectField != nullptr); + MemberLoc = &ThisLoc; + for (const auto *I : IndirectField->chain()) { + Member = cast(I); + MemberLoc = &cast(MemberLoc)->getChild(*Member); + } + } + assert(Member != nullptr); + assert(MemberLoc != nullptr); + if (Member->getType()->isReferenceType()) { auto *InitStmtLoc = Env.getStorageLocationStrict(*InitStmt); if (InitStmtLoc == nullptr) return; - auto &MemberLoc = ThisLoc.getChild(*Member); - Env.setValue(MemberLoc, Env.create(*InitStmtLoc)); + Env.setValue(*MemberLoc, Env.create(*InitStmtLoc)); } else if (auto *InitStmtVal = Env.getValueStrict(*InitStmt)) { - auto &MemberLoc = ThisLoc.getChild(*Member); - Env.setValue(MemberLoc, *InitStmtVal); + Env.setValue(*MemberLoc, *InitStmtVal); } } 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 @@ -5483,4 +5483,35 @@ }); } +TEST(TransferTest, AnonymousStructWithInitializer) { + std::string Code = R"( + struct target { + target() { + (void)0; + // [[p]] + } + struct { + bool b = true; + }; + }; + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + const ValueDecl *BDecl = findValueDecl(ASTCtx, "b"); + const IndirectFieldDecl *IndirectField = + findIndirectFieldDecl(ASTCtx, "b"); + + auto *ThisLoc = + cast(Env.getThisPointeeStorageLocation()); + auto &AnonStruct = cast(ThisLoc->getChild( + *cast(IndirectField->chain().front()))); + + auto *B = cast(Env.getValue(AnonStruct.getChild(*BDecl))); + ASSERT_TRUE(Env.flowConditionImplies(*B)); + }); +} + } // namespace