Previously, the newly added test would crash.
Depends On D153851
Reviewed By: gribozavr2
Differential Revision: https://reviews.llvm.org/D153852
// constructor-initializers.
if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(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<FieldDecl>(I));
+ }
const Expr *E = Init->getInit();
assert(E != nullptr);
getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);
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,
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<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
- auto &FieldLoc = ThisLoc.getChild(*Field);
- Env.setValue(FieldLoc, *InitExprVal);
+ propagateValueOrStorageLocation(*InitExpr, *S, Env);
}
void VisitCXXConstructExpr(const CXXConstructExpr *S) {
assert(Init != nullptr);
auto &Env = InputState.Env;
- const auto &ThisLoc =
+ auto &ThisLoc =
*cast<AggregateStorageLocation>(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<FieldDecl>(I);
+ MemberLoc = &cast<AggregateStorageLocation>(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<ReferenceValue>(*InitStmtLoc));
+ Env.setValue(*MemberLoc, Env.create<ReferenceValue>(*InitStmtLoc));
} else if (auto *InitStmtVal = Env.getValueStrict(*InitStmt)) {
- auto &MemberLoc = ThisLoc.getChild(*Member);
- Env.setValue(MemberLoc, *InitStmtVal);
+ Env.setValue(*MemberLoc, *InitStmtVal);
}
}
});
}
+TEST(TransferTest, AnonymousStructWithInitializer) {
+ std::string Code = R"(
+ struct target {
+ target() {
+ (void)0;
+ // [[p]]
+ }
+ struct {
+ bool b = true;
+ };
+ };
+ )";
+ runDataflow(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+ const ValueDecl *BDecl = findValueDecl(ASTCtx, "b");
+ const IndirectFieldDecl *IndirectField =
+ findIndirectFieldDecl(ASTCtx, "b");
+
+ auto *ThisLoc =
+ cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
+ auto &AnonStruct = cast<AggregateStorageLocation>(ThisLoc->getChild(
+ *cast<ValueDecl>(IndirectField->chain().front())));
+
+ auto *B = cast<BoolValue>(Env.getValue(AnonStruct.getChild(*BDecl)));
+ ASSERT_TRUE(Env.flowConditionImplies(*B));
+ });
+}
+
} // namespace