https://github.com/jvoung updated 
https://github.com/llvm/llvm-project/pull/191681

>From 4312d9f4d766578067d0cd3495eb31d9ff2df863 Mon Sep 17 00:00:00 2001
From: Jan Voung <[email protected]>
Date: Sun, 12 Apr 2026 03:16:45 +0000
Subject: [PATCH 1/2] Fix registered matcher for
 bugprone-unchecked-optional-access (recent changes to libcxx)

Further fix for #187788. Previous attempt in PR 188044 only updated the
model and model tests, but forgot to update the registered matcher.
---
 .../bugprone/UncheckedOptionalAccessCheck.cpp |  5 ++-
 .../std/types/optional.h                      | 39 +++++++++++++------
 .../bugprone/unchecked-optional-access.cpp    | 35 ++++++++++++++---
 .../Models/UncheckedOptionalAccessModel.h     |  5 ++-
 .../Models/UncheckedOptionalAccessModel.cpp   | 11 ++++--
 5 files changed, 71 insertions(+), 24 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
index 79d6e4974c316..cf7829984fab9 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp
@@ -27,8 +27,9 @@ static constexpr StringRef FuncID = "fun";
 void UncheckedOptionalAccessCheck::registerMatchers(MatchFinder *Finder) {
   using namespace ast_matchers;
 
-  auto HasOptionalCallDescendant = hasDescendant(callExpr(callee(cxxMethodDecl(
-      ofClass(UncheckedOptionalAccessModel::optionalClassDecl())))));
+  auto HasOptionalCallDescendant = hasDescendant(callExpr(
+      anyOf(UncheckedOptionalAccessModel::memberCallToOptionalClass(),
+            UncheckedOptionalAccessModel::operatorCallToOptionalClass())));
   Finder->addMatcher(
       decl(anyOf(functionDecl(
                      // FIXME: Remove the filter below when lambdas are
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/std/types/optional.h
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/std/types/optional.h
index d331585a4c21c..c508b2abe6e47 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/std/types/optional.h
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unchecked-optional-access/std/types/optional.h
@@ -1,6 +1,7 @@
 #ifndef 
LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_STD_TYPES_OPTIONAL_H_
 #define 
LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_STD_TYPES_OPTIONAL_H_
 
+/// Mock of `std::optional`.
 namespace std {
 
 struct nullopt_t {
@@ -9,16 +10,13 @@ struct nullopt_t {
 
 constexpr nullopt_t nullopt;
 
-template <typename T>
-class optional {
-public:
-  constexpr optional() noexcept;
-
-  constexpr optional(nullopt_t) noexcept;
-
-  optional(const optional &) = default;
+template <class T> struct __optional_destruct_base {
+  constexpr void reset() noexcept;
+};
 
-  optional(optional &&) = default;
+template <class T>
+struct __optional_storage_base : __optional_destruct_base<T> {
+  constexpr bool has_value() const noexcept;
 
   const T &operator*() const &;
   T &operator*() &;
@@ -32,9 +30,28 @@ class optional {
   T &value() &;
   const T &&value() const &&;
   T &&value() &&;
+};
+
+// Note: the inheritance may or may not be private:
+// https://github.com/llvm/llvm-project/issues/187788
+template <typename T> class optional : public __optional_storage_base<T> {
+  using base = __optional_storage_base<T>;
+
+public:
+  constexpr optional() noexcept;
+
+  constexpr optional(nullopt_t) noexcept;
+
+  optional(const optional &) = default;
+
+  optional(optional &&) = default;
+
+  using base::operator*;
+  using base::operator->;
+  using base::value;
 
   constexpr explicit operator bool() const noexcept;
-  constexpr bool has_value() const noexcept;
+  using base::has_value;
 
   template <typename U>
   constexpr T value_or(U &&v) const &;
@@ -44,7 +61,7 @@ class optional {
   template <typename... Args>
   T &emplace(Args &&...args);
 
-  void reset() noexcept;
+  using base::reset;
 
   void swap(optional &rhs) noexcept;
 
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
index 214072de772e2..e4d59528134c0 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
@@ -1,16 +1,28 @@
 // RUN: %check_clang_tidy %s bugprone-unchecked-optional-access %t -- -- -I 
%S/Inputs/unchecked-optional-access
 
 #include "absl/types/optional.h"
-#include "folly/types/Optional.h"
-#include "bde/types/bsl_optional.h"
 #include "bde/types/bdlb_nullablevalue.h"
+#include "bde/types/bsl_optional.h"
+#include "folly/types/Optional.h"
+#include "std/types/optional.h"
 
-void unchecked_value_access(const absl::optional<int> &opt) {
+void unchecked_value_access(std::optional<int> opt) {
   opt.value();
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional 
value [bugprone-unchecked-optional-access]
 }
 
-void unchecked_deref_operator_access(const absl::optional<int> &opt) {
+void absl_unchecked_value_access(const absl::optional<int> &opt) {
+  opt.value();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional 
value
+  // [bugprone-unchecked-optional-access]
+}
+
+void unchecked_deref_operator_access(std::optional<int> opt) {
+  *opt;
+  // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: unchecked access to optional 
value
+}
+
+void absl_unchecked_deref_operator_access(const absl::optional<int> &opt) {
   *opt;
   // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: unchecked access to optional 
value
 }
@@ -19,7 +31,12 @@ struct Foo {
   void foo() const {}
 };
 
-void unchecked_arrow_operator_access(const absl::optional<Foo> &opt) {
+void unchecked_arrow_operator_access(std::optional<Foo> opt) {
+  opt->foo();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional 
value
+}
+
+void absl_unchecked_arrow_operator_access(const absl::optional<Foo> &opt) {
   opt->foo();
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional 
value
 }
@@ -40,7 +57,13 @@ void folly_value_after_swap(folly::Optional<int> opt1, 
folly::Optional<int> opt2
   }
 }
 
-void checked_access(const absl::optional<int> &opt) {
+void checked_access(std::optional<int> opt) {
+  if (opt.has_value()) {
+    opt.value();
+  }
+}
+
+void absl_checked_access(const absl::optional<int> &opt) {
   if (opt.has_value()) {
     opt.value();
   }
diff --git 
a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
 
b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
index c547d6ce2e387..e7f1f407d9912 100644
--- 
a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
+++ 
b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
@@ -62,8 +62,9 @@ class UncheckedOptionalAccessModel
 public:
   UncheckedOptionalAccessModel(ASTContext &Ctx, dataflow::Environment &Env);
 
-  /// Returns a matcher for the optional classes covered by this model.
-  static ast_matchers::DeclarationMatcher optionalClassDecl();
+  /// Returns a matcher for calls to optional classes diagnosed by this model.
+  static ast_matchers::StatementMatcher memberCallToOptionalClass();
+  static ast_matchers::StatementMatcher operatorCallToOptionalClass();
 
   static UncheckedOptionalAccessLattice initialElement() { return {}; }
 
diff --git 
a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp 
b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 182db36be3513..568564fb361f4 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -1278,9 +1278,14 @@ auto buildDiagnoseMatchSwitch(
 
 } // namespace
 
-ast_matchers::DeclarationMatcher
-UncheckedOptionalAccessModel::optionalClassDecl() {
-  return cxxRecordDecl(optionalClass());
+ast_matchers::StatementMatcher
+UncheckedOptionalAccessModel::memberCallToOptionalClass() {
+  return cxxMemberCallExpr(hasOptionalReceiverType());
+}
+
+ast_matchers::StatementMatcher
+UncheckedOptionalAccessModel::operatorCallToOptionalClass() {
+  return cxxOperatorCallExpr(hasOptionalOperatorObjectType());
 }
 
 UncheckedOptionalAccessModel::UncheckedOptionalAccessModel(ASTContext &Ctx,

>From 092b8ac39a034f2ec7539f69177940afdc36038b Mon Sep 17 00:00:00 2001
From: Jan Voung <[email protected]>
Date: Mon, 13 Apr 2026 14:38:43 +0000
Subject: [PATCH 2/2] Fix test CHECK

---
 .../clang-tidy/checkers/bugprone/unchecked-optional-access.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
index e4d59528134c0..337474bdf7535 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unchecked-optional-access.cpp
@@ -13,8 +13,7 @@ void unchecked_value_access(std::optional<int> opt) {
 
 void absl_unchecked_value_access(const absl::optional<int> &opt) {
   opt.value();
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional 
value
-  // [bugprone-unchecked-optional-access]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: unchecked access to optional 
value [bugprone-unchecked-optional-access]
 }
 
 void unchecked_deref_operator_access(std::optional<int> opt) {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to