diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp index 21913d5809a6e..4a9d8c268f614 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp @@ -525,6 +525,18 @@ static void transferNotOkStatusCall(const CallExpr *Expr, State.Env.assume(A.makeNot(OkVal.formula())); } +static void transferEmplaceCall(const CXXMemberCallExpr *Expr, + const MatchFinder::MatchResult &, + LatticeTransferState &State) { + RecordStorageLocation *StatusOrLoc = + getImplicitObjectLocation(*Expr, State.Env); + if (StatusOrLoc == nullptr) + return; + + auto &OkVal = valForOk(locForStatus(*StatusOrLoc), State.Env); + State.Env.assume(OkVal.formula()); +} + CFGMatchSwitch buildTransferMatchSwitch(ASTContext &Ctx, CFGMatchSwitchBuilder Builder) { @@ -568,6 +580,8 @@ buildTransferMatchSwitch(ASTContext &Ctx, }) .CaseOfCFGStmt(isOkStatusCall(), transferOkStatusCall) .CaseOfCFGStmt(isNotOkStatusCall(), transferNotOkStatusCall) + .CaseOfCFGStmt(isStatusOrMemberCallWithName("emplace"), + transferEmplaceCall) .Build(); } diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp index 62e456ad07bdb..f354441299156 100644 --- a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp @@ -2915,6 +2915,54 @@ TEST_P(UncheckedStatusOrAccessModelTest, PointerEqualityCheck) { )cc"); } +TEST_P(UncheckedStatusOrAccessModelTest, Emplace) { + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + struct Foo { + Foo(int); + }; + + void target(absl::StatusOr sor, int value) { + sor.emplace(value); + sor.value(); + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + struct Foo { + Foo(std::initializer_list, int); + }; + + void target(absl::StatusOr sor, int value) { + sor.emplace({1, 2, 3}, value); + sor.value(); + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(bool b) { + STATUSOR_INT sor; + bool sor_ok = sor.ok(); + if (b) + sor.emplace(42); + else if (sor_ok) + sor.value(); + } + )cc"); + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + void target(bool b) { + STATUSOR_INT sor; + if (b) sor.emplace(42); + if (b) sor.value(); + } + )cc"); +} + } // namespace std::string