Author: Florian Mayer Date: 2026-05-29T01:59:33Z New Revision: 4910eda2a04e8532e434acb140c692e1c4da319c
URL: https://github.com/llvm/llvm-project/commit/4910eda2a04e8532e434acb140c692e1c4da319c DIFF: https://github.com/llvm/llvm-project/commit/4910eda2a04e8532e434acb140c692e1c4da319c.diff LOG: [FlowSensitive] [StatusOr] Support ABSL_RETURN_IF_ERROR (#200287) This was recently introduced in absl Added: Modified: clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp Removed: ################################################################################ diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp index 7b54d64fb5fcb..6e1bdca22f1c5 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp @@ -363,6 +363,39 @@ static auto isStatusPtrReturningCall() { recordType(hasDeclaration(statusClass())))))))))); } +static auto ofClassReturnIfErrorAdaptor() { + using namespace ::clang::ast_matchers; + return ofClass( + hasName("::absl::status_macro_internal::ReturnIfErrorAdaptor")); +} + +static auto returnIfErrorAdaptorClass() { + using namespace ::clang::ast_matchers; + return cxxRecordDecl( + hasName("::absl::status_macro_internal::ReturnIfErrorAdaptor")); +} + +static auto returnIfErrorAdaptorType() { + using namespace ::clang::ast_matchers; + return hasUnqualifiedDesugaredType( + recordType(hasDeclaration(returnIfErrorAdaptorClass()))); +} + +static auto isReturnIfErrorAdaptorOperatorBoolCall() { + using namespace ::clang::ast_matchers; + return cxxMemberCallExpr( + on(expr(unless(cxxThisExpr()))), + callee(cxxMethodDecl(hasName("operator bool"), + ofClassReturnIfErrorAdaptor()))); +} + +static auto isMacroAdaptorCall() { + using namespace ::clang::ast_matchers; + return callExpr(callee( + functionDecl(hasName("::absl::status_macro_internal::MacroAdaptor"), + returns(returnIfErrorAdaptorType())))); +} + static auto buildDiagnoseMatchSwitch(const UncheckedStatusOrAccessModelOptions &Options) { return CFGMatchSwitchBuilder<const Environment, @@ -472,6 +505,11 @@ static bool isStatusIsMatcherType(QualType Type) { "CanonicalStatusIsMatcher"); } +static bool IsMacroAdaptorType(clang::QualType type) { + return isTypeNamed(type, {"absl", "status_macro_internal"}, + "ReturnIfErrorAdaptor"); +} + llvm::StringMap<QualType> getSyntheticFields(QualType Ty, QualType StatusType, const CXXRecordDecl &RD) { if (auto *TRD = getStatusOrBaseClass(Ty)) @@ -485,6 +523,8 @@ llvm::StringMap<QualType> getSyntheticFields(QualType Ty, QualType StatusType, return {{"ok_predicate", RD.getASTContext().BoolTy}}; if (isStatusIsMatcherType(Ty)) return {{"ok_matcher", RD.getASTContext().BoolTy}}; + if (IsMacroAdaptorType(Ty)) + return {{"status", StatusType}}; return {}; } @@ -1143,6 +1183,31 @@ getSmartPtrLikeStorageLocation(const Expr &E, const Environment &Env) { &PointerVal->getPointeeLoc()); return nullptr; } +static void transferMacroAdaptorCall(const clang::CallExpr *Expr, + const MatchFinder::MatchResult &, + LatticeTransferState &State) { + assert(Expr->getNumArgs() > 0); + + auto *StatusAdaptorLoc = + State.Env.get<RecordStorageLocation>(*Expr->getArg(0)); + if (StatusAdaptorLoc == nullptr) + return; + + copyRecord(*StatusAdaptorLoc, + locForStatus(State.Env.getResultObjectLocation(*Expr)), State.Env); +} + +static void transferReturnIfErrorAdaptorOperatorBoolCall( + const clang::CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, + LatticeTransferState &State) { + RecordStorageLocation *StatusAdaptorLoc = + getImplicitObjectLocation(*Expr, State.Env); + if (StatusAdaptorLoc == nullptr) + return; + + auto &OkVal = valForOk(locForStatus(*StatusAdaptorLoc), State.Env); + State.Env.setValue(*Expr, OkVal); +} CFGMatchSwitch<LatticeTransferState> buildTransferMatchSwitch(ASTContext &Ctx, @@ -1312,6 +1377,11 @@ buildTransferMatchSwitch(ASTContext &Ctx, .CaseOfCFGStmt<ImplicitCastExpr>( implicitCastExpr(hasCastKind(CK_PointerToBoolean)), transferPointerToBoolean) + .CaseOfCFGStmt<clang::CXXMemberCallExpr>( + isReturnIfErrorAdaptorOperatorBoolCall(), + transferReturnIfErrorAdaptorOperatorBoolCall) + .CaseOfCFGStmt<clang::CallExpr>(isMacroAdaptorCall(), + transferMacroAdaptorCall) .Build(); } diff --git a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp index 2a85a08e819d5..c5ad8ea4dcb1f 100644 --- a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp +++ b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp @@ -1717,8 +1717,49 @@ bool operator==(const StatusOr<T> &lhs, const StatusOr<T> &rhs); template <typename T> bool operator!=(const StatusOr<T> &lhs, const StatusOr<T> &rhs); +using StatusBuilder = Status; +namespace status_macro_internal { +class ReturnIfErrorAdaptor { + public: + explicit ReturnIfErrorAdaptor( + const absl::Status& status, + absl::SourceLocation loc = absl::SourceLocation::current()); + + explicit ReturnIfErrorAdaptor( + absl::Status&& status, + absl::SourceLocation loc = absl::SourceLocation::current()); + + ~ReturnIfErrorAdaptor(); + + explicit operator bool() const; + StatusBuilder Consume(); +}; + +ReturnIfErrorAdaptor MacroAdaptor(const absl::Status& s, + absl::SourceLocation loc); +ReturnIfErrorAdaptor MacroAdaptor(absl::Status&& s, + absl::SourceLocation loc); +} + } // namespace absl +#define ABSL_INTERNAL_STATUS_MACROS_IMPL_ELSE_BLOCKER_ \ + switch (0) \ + case 0: \ + default: // NOLINT + +#define ABSL_INTERNAL_STATUS_MACROS_RETURN_IF_ERROR_IMPL_(return_keyword, \ + expr) \ + ABSL_INTERNAL_STATUS_MACROS_IMPL_ELSE_BLOCKER_ \ + if (auto status_macro_internal_adaptor = \ + absl::status_macro_internal::MacroAdaptor( \ + (expr), absl::SourceLocation::current())) { \ + } else /* NOLINT */ \ + return_keyword status_macro_internal_adaptor.Consume() + +#define ABSL_RETURN_IF_ERROR(expr) \ + ABSL_INTERNAL_STATUS_MACROS_RETURN_IF_ERROR_IMPL_(return, expr) + #endif // STATUSOR_H_ )cc"; diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp index 08c89818a645d..3b5c2be87c3d0 100644 --- a/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedStatusOrAccessModelTestFixture.cpp @@ -4572,6 +4572,18 @@ TEST_P(UncheckedStatusOrAccessModelTest, CoroutineCoReturnEnds) { )cc"); } +TEST_P(UncheckedStatusOrAccessModelTest, ReturnIfError) { + ExpectDiagnosticsFor(R"cc( +#include "unchecked_statusor_access_test_defs.h" + + absl::Status target(STATUSOR_INT sor) { + ABSL_RETURN_IF_ERROR(sor.status()); + *sor; + return {}; + } + )cc"); +} + } // namespace std::string _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
