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

Reply via email to