@@ -202,6 +202,16 @@ static auto isStatusOrValueConstructor() {
202202 " std::in_place_t" ))))));
203203}
204204
205+ static auto isStatusOrConstructor () {
206+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
207+ return cxxConstructExpr (hasType (statusOrType ()));
208+ }
209+
210+ static auto isStatusConstructor () {
211+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
212+ return cxxConstructExpr (hasType (statusType ()));
213+ }
214+
205215static auto
206216buildDiagnoseMatchSwitch (const UncheckedStatusOrAccessModelOptions &Options) {
207217 return CFGMatchSwitchBuilder<const Environment,
@@ -574,6 +584,25 @@ static void transferValueConstructor(const CXXConstructExpr *Expr,
574584 State.Env .assume (OkVal.formula ());
575585}
576586
587+ static void transferStatusOrConstructor (const CXXConstructExpr *Expr,
588+ const MatchFinder::MatchResult &,
589+ LatticeTransferState &State) {
590+ RecordStorageLocation &StatusOrLoc = State.Env .getResultObjectLocation (*Expr);
591+ RecordStorageLocation &StatusLoc = locForStatus (StatusOrLoc);
592+
593+ if (State.Env .getValue (locForOk (StatusLoc)) == nullptr )
594+ initializeStatusOr (StatusOrLoc, State.Env );
595+ }
596+
597+ static void transferStatusConstructor (const CXXConstructExpr *Expr,
598+ const MatchFinder::MatchResult &,
599+ LatticeTransferState &State) {
600+ RecordStorageLocation &StatusLoc = State.Env .getResultObjectLocation (*Expr);
601+
602+ if (State.Env .getValue (locForOk (StatusLoc)) == nullptr )
603+ initializeStatus (StatusLoc, State.Env );
604+ }
605+
577606CFGMatchSwitch<LatticeTransferState>
578607buildTransferMatchSwitch (ASTContext &Ctx,
579608 CFGMatchSwitchBuilder<LatticeTransferState> Builder) {
@@ -623,6 +652,16 @@ buildTransferMatchSwitch(ASTContext &Ctx,
623652 transferValueAssignmentCall)
624653 .CaseOfCFGStmt <CXXConstructExpr>(isStatusOrValueConstructor (),
625654 transferValueConstructor)
655+ // N.B. These need to come after all other CXXConstructExpr.
656+ // These are there to make sure that every Status and StatusOr object
657+ // have their ok boolean initialized when constructed. If we were to
658+ // lazily initialize them when we first access them, we can produce
659+ // false positives if that first access is in a control flow statement.
660+ // You can comment out these two constructors and see tests fail.
661+ .CaseOfCFGStmt <CXXConstructExpr>(isStatusOrConstructor (),
662+ transferStatusOrConstructor)
663+ .CaseOfCFGStmt <CXXConstructExpr>(isStatusConstructor (),
664+ transferStatusConstructor)
626665 .Build ();
627666}
628667
0 commit comments