[llvm] Hybrid attributes kay (PR #214255)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 5 08:17:41 PDT 2026


github-actions[bot] wrote:

<!--LLVM CODE FORMAT COMMENT: {clang-format}-->


:warning: C/C++ code formatter, clang-format found issues in your code. :warning:

<details>
<summary>
You can test this locally with the following command:
</summary>

``````````bash
git-clang-format --diff origin/main HEAD --extensions cpp,h -- hicketts/hicketts_optional_general.h hicketts/hicketts_optional_hybrid.h hicketts/hicketts_vector.h hicketts/test_hicketts_optional_general.cpp hicketts/test_hicketts_optional_hybrid.cpp hicketts/test_hicketts_vector.cpp --diff_from_common_commit
``````````

:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:

</details>

<details>
<summary>
View the diff from clang-format here.
</summary>

``````````diff
diff --git a/hicketts/hicketts_optional_general.h b/hicketts/hicketts_optional_general.h
index be0ff9471..44c7d888e 100644
--- a/hicketts/hicketts_optional_general.h
+++ b/hicketts/hicketts_optional_general.h
@@ -48,10 +48,16 @@ public:
   HickettsOptional(HickettsOptional &&) = default;
 
   // Equivalent to std::optional::value()
-  [[clang::analyze_as_method("value")]] const T &unwrap() const & { return *storage_; }
+  [[clang::analyze_as_method("value")]] const T &unwrap() const & {
+    return *storage_;
+  }
   [[clang::analyze_as_method("value")]] T &unwrap() & { return *storage_; }
-  [[clang::analyze_as_method("value")]] const T &&unwrap() const && { return static_cast<const T &&>(*storage_); }
-  [[clang::analyze_as_method("value")]] T &&unwrap() && { return static_cast<T &&>(*storage_); }
+  [[clang::analyze_as_method("value")]] const T &&unwrap() const && {
+    return static_cast<const T &&>(*storage_);
+  }
+  [[clang::analyze_as_method("value")]] T &&unwrap() && {
+    return static_cast<T &&>(*storage_);
+  }
 
   const T &value() const & { return *storage_; }
   T &value() & { return *storage_; }
@@ -59,30 +65,38 @@ public:
   T &&value() && { return static_cast<T &&>(*storage_); }
 
   // Equivalent to std::optional::operator*()
-  [[clang::analyze_as_method("value")]] const T &deref() const & { return *storage_; }
+  [[clang::analyze_as_method("value")]] const T &deref() const & {
+    return *storage_;
+  }
   [[clang::analyze_as_method("value")]] T &deref() & { return *storage_; }
 
   // Equivalent to std::optional::operator->()
-  const T* operator ->() const { return storage_; }
-  T* operator ->() { return storage_; }
+  const T *operator->() const { return storage_; }
+  T *operator->() { return storage_; }
   const T *arrow() const { return storage_; }
   T *arrow() { return storage_; }
 
   // Equivalent to std::optional::operator bool / hasValue()
   constexpr bool has_value() const noexcept { return storage_ != nullptr; }
-  constexpr explicit operator bool() const noexcept { return storage_ != nullptr; }
-  [[clang::analyze_as_method("has_value")]] constexpr bool isPresent() const noexcept { return storage_ != nullptr; }
+  constexpr explicit operator bool() const noexcept {
+    return storage_ != nullptr;
+  }
+  [[clang::analyze_as_method("has_value")]] constexpr bool
+  isPresent() const noexcept {
+    return storage_ != nullptr;
+  }
 
   // Equivalent to std::optional::value_or()
-  template <typename U>
-  constexpr T unwrapOr(U &&fallback) const & {
+  template <typename U> constexpr T unwrapOr(U &&fallback) const & {
     return storage_ ? *storage_ : static_cast<T>(fallback);
   }
 
   // Equivalent to std::optional::emplace()
   template <typename... Args>
   [[clang::analyze_as_method("emplace(Args&&...)")]]
-  T& construct(Args&&... args) { return *storage_; }
+  T &construct(Args &&...args) {
+    return *storage_;
+  }
 
   // Demo of malformed-signature rejection — disabled. The parameter-balance
   // validation in Sema (isValidAnalyzeAsMethodAttr) that rejected this string
@@ -93,22 +107,28 @@ public:
   // T& load() { return *storage_; }
 
   // Equivalent to std::optional::reset()
-  [[clang::analyze_as_method("reset")]] void clear() noexcept { storage_ = nullptr; }
+  [[clang::analyze_as_method("reset")]] void clear() noexcept {
+    storage_ = nullptr;
+  }
 
   // Equivalent to std::optional::swap()
-  [[clang::analyze_as_method("swap")]] void exchange(HickettsOptional &other) noexcept {
+  [[clang::analyze_as_method("swap")]] void
+  exchange(HickettsOptional &other) noexcept {
     T *tmp = storage_;
     storage_ = other.storage_;
     other.storage_ = tmp;
   }
 
   // Assignment
-  template <typename U>
-  HickettsOptional &operator=(const U &u) { return *this; }
+  template <typename U> HickettsOptional &operator=(const U &u) {
+    return *this;
+  }
 
   [[clang::analyze_as_method("operator=(nullopt_t)")]]
-  HickettsOptional &operator=(mylib::nothing_t){ storage_ = nullptr; return *this;}
-
+  HickettsOptional &operator=(mylib::nothing_t) {
+    storage_ = nullptr;
+    return *this;
+  }
 };
 
 } // namespace mylib
diff --git a/hicketts/hicketts_optional_hybrid.h b/hicketts/hicketts_optional_hybrid.h
index df06e5d91..5a8134257 100644
--- a/hicketts/hicketts_optional_hybrid.h
+++ b/hicketts/hicketts_optional_hybrid.h
@@ -4,32 +4,35 @@
 /// A custom optional-like type wired for the *hybrid* attribute scheme.
 ///
 /// Three cooperating layers sit on the SAME type, each carrying a different
-/// KIND of knowledge (see architecture.md, plan_general.md, why_class_comparison.md):
+/// KIND of knowledge (see architecture.md, plan_general.md,
+/// why_class_comparison.md):
 ///
 ///   L1  IDENTITY   [[clang::analyze_as_class("std::optional")]]
 ///         "I behave like std::optional." A single class-level declaration that
 ///         anchors the type so OTHER clang-tidy checks reuse their built-in,
 ///         per-std-class knowledge by identity (why_class_comparison.md). No
-///         per-method name-maps: on optional nothing else consumes them, and the
-///         dataflow model is driven by the L2 roles below instead.
+///         per-method name-maps: on optional nothing else consumes them, and
+///         the dataflow model is driven by the L2 roles below instead.
 ///
-///   L2  BEHAVIOURAL ROLES   [[clang::engaged/disengaged/test_engaged/assume_engaged]]
+///   L2  BEHAVIOURAL ROLES
+///   [[clang::engaged/disengaged/test_engaged/assume_engaged]]
 ///         The single per-object boolean predicate the flow-sensitive
-///         bugprone-unchecked-optional-access model tracks. The predicate has no
-///         name because it is INERT to the model -- the model tracks one opaque
-///         bit, so "empty" and "disengaged" are the same action (set-false) and
-///         a name would only matter if a type had >1 predicate. What is NOT inert
-///         is polarity; optional's API here is uniformly positive (has_value,
-///         value), so only the positive verbs appear:
-///           engaged        -> establish the bit true   (value ctor, emplace, =value)
-///           disengaged     -> establish the bit false  (nullopt ctor, reset, =nullopt)
-///           test_engaged   -> branch-sensitive read    (has_value, operator bool)
-///           assume_engaged -> precondition: warn if not established (value/*/->)
-///         (A negative-polarity test/assume -- e.g. an isEmpty()-style query, or
-///         vector's empty()/front() -- is where polarity, not the name, would
-///         reappear. Out of scope for this fixture.)
-///         PROPOSED, not yet implemented, so this is the one layer left behind a
-///         macro: -DHO_ROLES turns it on for a roles-off/roles-on baseline.
+///         bugprone-unchecked-optional-access model tracks. The predicate has
+///         no name because it is INERT to the model -- the model tracks one
+///         opaque bit, so "empty" and "disengaged" are the same action
+///         (set-false) and a name would only matter if a type had >1 predicate.
+///         What is NOT inert is polarity; optional's API here is uniformly
+///         positive (has_value, value), so only the positive verbs appear:
+///           engaged        -> establish the bit true   (value ctor, emplace,
+///           =value) disengaged     -> establish the bit false  (nullopt ctor,
+///           reset, =nullopt) test_engaged   -> branch-sensitive read
+///           (has_value, operator bool) assume_engaged -> precondition: warn if
+///           not established (value/*/->)
+///         (A negative-polarity test/assume -- e.g. an isEmpty()-style query,
+///         or vector's empty()/front() -- is where polarity, not the name,
+///         would reappear. Out of scope for this fixture.) PROPOSED, not yet
+///         implemented, so this is the one layer left behind a macro:
+///         -DHO_ROLES turns it on for a roles-off/roles-on baseline.
 ///
 ///   L3  LIFETIME   [[gsl::Owner]] / [[clang::lifetimebound]]
 ///         Real, shipping-today attributes. An optional OWNS its T; unwrap()/
@@ -39,18 +42,18 @@
 ///
 /// L1 and L3 are inline (they exist today, ignored where unsupported). Only L2
 /// is guarded, because those attributes do not exist yet:
-///   (default)    L1 + L3     -> -Wdangling live; dataflow model idle until roles
-///   -DHO_ROLES   + L2        -> needs the proposed role attributes
+///   (default)    L1 + L3     -> -Wdangling live; dataflow model idle until
+///   roles -DHO_ROLES   + L2        -> needs the proposed role attributes
 namespace mylib {
 
 // The only guarded layer: the proposed per-object-state roles, which do not
-// exist yet. Elided by default so the header builds without -Wunknown-attributes;
-// -DHO_ROLES emits them once they are implemented. No predicate argument -- the
-// type has a single, model-opaque predicate.
+// exist yet. Elided by default so the header builds without
+// -Wunknown-attributes; -DHO_ROLES emits them once they are implemented. No
+// predicate argument -- the type has a single, model-opaque predicate.
 #ifdef HO_ROLES
-#define HO_ENGAGED        [[clang::engaged]]
-#define HO_DISENGAGED     [[clang::disengaged]]
-#define HO_TEST_ENGAGED   [[clang::test_engaged]]
+#define HO_ENGAGED [[clang::engaged]]
+#define HO_DISENGAGED [[clang::disengaged]]
+#define HO_TEST_ENGAGED [[clang::test_engaged]]
 #define HO_ASSUME_ENGAGED [[clang::assume_engaged]]
 #else
 #define HO_ENGAGED
@@ -66,7 +69,8 @@ struct nothing_t {
 constexpr nothing_t nothing;
 
 template <typename T>
-class [[gsl::Owner]] [[clang::analyze_as_class("std::optional")]] HickettsOptional {
+class [[gsl::Owner]] [[clang::analyze_as_class("std::optional")]]
+HickettsOptional {
   T *storage_ = nullptr;
 
 public:
@@ -75,8 +79,8 @@ public:
   constexpr HickettsOptional() noexcept {}
 
   // Nullopt-style ctor. SAME 1-arg shape as the value ctor below, DIFFERENT
-  // outcome. The role on THIS decl disambiguates -- overload resolution picks it
-  // for HickettsOptional(nothing); no signature string, no std header.
+  // outcome. The role on THIS decl disambiguates -- overload resolution picks
+  // it for HickettsOptional(nothing); no signature string, no std header.
   HO_DISENGAGED
   constexpr HickettsOptional(nothing_t) noexcept {}
 
@@ -94,29 +98,39 @@ public:
   // INTO *this (L3). One method, two independent hazards:
   //   L2 assume_engaged -> unchecked-optional-access diagnostic
   //   L3 lifetimebound  -> -Wdangling when *this is a temporary
-  HO_ASSUME_ENGAGED const T &unwrap() const & [[clang::lifetimebound]] { return *storage_; }
-  HO_ASSUME_ENGAGED T &unwrap() & [[clang::lifetimebound]] { return *storage_; }
+  HO_ASSUME_ENGAGED const T &unwrap() const &[[clang::lifetimebound]] {
+    return *storage_;
+  }
+  HO_ASSUME_ENGAGED T &unwrap() &[[clang::lifetimebound]] { return *storage_; }
 
-  HO_ASSUME_ENGAGED const T &deref() const & [[clang::lifetimebound]] { return *storage_; }
-  HO_ASSUME_ENGAGED T &deref() & [[clang::lifetimebound]] { return *storage_; }
+  HO_ASSUME_ENGAGED const T &deref() const &[[clang::lifetimebound]] {
+    return *storage_;
+  }
+  HO_ASSUME_ENGAGED T &deref() &[[clang::lifetimebound]] { return *storage_; }
 
   const T *operator->() const [[clang::lifetimebound]] { return storage_; }
   T *operator->() [[clang::lifetimebound]] { return storage_; }
 
   // Queries: branch-sensitive read, positive polarity.
-  HO_TEST_ENGAGED constexpr bool has_value() const noexcept { return storage_ != nullptr; }
-  HO_TEST_ENGAGED constexpr explicit operator bool() const noexcept { return storage_ != nullptr; }
-  HO_TEST_ENGAGED constexpr bool isPresent() const noexcept { return storage_ != nullptr; }
+  HO_TEST_ENGAGED constexpr bool has_value() const noexcept {
+    return storage_ != nullptr;
+  }
+  HO_TEST_ENGAGED constexpr explicit operator bool() const noexcept {
+    return storage_ != nullptr;
+  }
+  HO_TEST_ENGAGED constexpr bool isPresent() const noexcept {
+    return storage_ != nullptr;
+  }
 
   // value_or: always safe, no precondition.
-  template <typename U>
-  constexpr T unwrapOr(U &&fallback) const & {
+  template <typename U> constexpr T unwrapOr(U &&fallback) const & {
     return storage_ ? *storage_ : static_cast<T>(fallback);
   }
 
   // emplace -> engaged.
-  template <typename... Args>
-  HO_ENGAGED T &construct(Args &&...args) { return *storage_; }
+  template <typename... Args> HO_ENGAGED T &construct(Args &&...args) {
+    return *storage_;
+  }
 
   // reset -> disengaged.
   HO_DISENGAGED void clear() noexcept { storage_ = nullptr; }
@@ -130,8 +144,9 @@ public:
   }
 
   // Assignment from a value -> engaged.
-  template <typename U>
-  HO_ENGAGED HickettsOptional &operator=(const U &u) { return *this; }
+  template <typename U> HO_ENGAGED HickettsOptional &operator=(const U &u) {
+    return *this;
+  }
 
   // Nullopt-style assignment -> disengaged. Same disambiguation story as the
   // ctors: the role on this decl routes it.
diff --git a/hicketts/hicketts_vector.h b/hicketts/hicketts_vector.h
index 08cd3b49e..80de82162 100644
--- a/hicketts/hicketts_vector.h
+++ b/hicketts/hicketts_vector.h
@@ -31,8 +31,7 @@ namespace mylib {
 #define HV_REINITIALIZES [[clang::reinitializes]]
 #endif
 
-template <typename T>
-class HV_OWNER HickettsVector {
+template <typename T> class HV_OWNER HickettsVector {
   // Tiny fixed buffer keeps the fixture simple (no allocator); big enough for
   // small tests, and irrelevant to the static lifetime analysis anyway.
   T buf_[16] = {};
diff --git a/hicketts/test_hicketts_optional_general.cpp b/hicketts/test_hicketts_optional_general.cpp
index 1ddea121c..a5eaf7a11 100644
--- a/hicketts/test_hicketts_optional_general.cpp
+++ b/hicketts/test_hicketts_optional_general.cpp
@@ -3,11 +3,13 @@
 //
 // Run from hicketts/ with:
 //   ../build-llvm/bin/clang-tidy -checks='bugprone-unchecked-optional-access' \
-//     test_hicketts_optional_general.cpp -- -I . -std=c++17 -Wno-undefined-inline
+//     test_hicketts_optional_general.cpp -- -I . -std=c++17
+//     -Wno-undefined-inline
 
 #include "hicketts_optional_general.h"
 
-// --- Unchecked access (should warn if the checker recognises HickettsOptional) ---
+// --- Unchecked access (should warn if the checker recognises HickettsOptional)
+// ---
 
 static void uncheckedUnwrap(mylib::HickettsOptional<int> &Val) {
   Val.unwrap(); // unchecked access — may be empty
@@ -49,8 +51,9 @@ static void checkedWithIsPresent(mylib::HickettsOptional<int> &Val) {
 
 // --- State changes ---
 
-// construct() is annotated "emplace(Args&&...)"; the bare "emplace" query matches
-// it via the name-part (accept-either) branch -> engaged, so unwrap is safe.
+// construct() is annotated "emplace(Args&&...)"; the bare "emplace" query
+// matches it via the name-part (accept-either) branch -> engaged, so unwrap is
+// safe.
 static void safeAfterConstruct(mylib::HickettsOptional<int> &Val) {
   Val.construct(42);
   Val.unwrap(); // safe — just constructed a value
@@ -63,7 +66,7 @@ static void unsafeAfterClear(mylib::HickettsOptional<int> &Val) {
 }
 
 static void unsafeAfterExchange(mylib::HickettsOptional<int> &A,
-                         mylib::HickettsOptional<int> &B) {
+                                mylib::HickettsOptional<int> &B) {
   if (A) {
     A.exchange(B);
     A.unwrap(); // unsafe — a's state is now unknown
@@ -71,7 +74,8 @@ static void unsafeAfterExchange(mylib::HickettsOptional<int> &A,
 }
 
 // Works today WITHOUT any annotation: default construction matches no
-// constructor case, so has_value is unconstrained -> access conservatively warns.
+// constructor case, so has_value is unconstrained -> access conservatively
+// warns.
 static void unsafeAfterEmptyConstr() {
   mylib::HickettsOptional<int> A;
   A.unwrap(); // expected: warn (empty)
@@ -79,8 +83,8 @@ static void unsafeAfterEmptyConstr() {
 
 // nothing_t is not std::nullopt_t, so the structural nullopt matcher misses.
 // The "optional(std::nullopt_t)" annotation routes this constructor to the
-// nullopt transfer (empty) via isOptionalNulloptConstructor's annotation branch,
-// so the following unwrap is correctly flagged.
+// nullopt transfer (empty) via isOptionalNulloptConstructor's annotation
+// branch, so the following unwrap is correctly flagged.
 static void unsafeAfterNullConstr() {
   mylib::HickettsOptional<int> A(mylib::nothing);
   A.unwrap(); // warns (empty) — routed to nullopt via the annotation
diff --git a/hicketts/test_hicketts_optional_hybrid.cpp b/hicketts/test_hicketts_optional_hybrid.cpp
index 8abb4d9ce..7fdc70e99 100644
--- a/hicketts/test_hicketts_optional_hybrid.cpp
+++ b/hicketts/test_hicketts_optional_hybrid.cpp
@@ -4,10 +4,12 @@
 // header; only L2 (proposed roles) is behind -DHO_ROLES. Two run modes:
 //
 //   default -- L1 + L3. -Wdangling fires via the compiler's lifetime analysis;
-//   L1 drives unchecked-optional-access if clang-tidy was built with analyze_as_*:
+//   L1 drives unchecked-optional-access if clang-tidy was built with
+//   analyze_as_*:
 //     ../build-llvm/bin/clang-tidy \
 //        -checks='bugprone-unchecked-optional-access' \
-//        test_hicketts_optional_hybrid.cpp -- -I . -std=c++17 -Wno-undefined-inline
+//        test_hicketts_optional_hybrid.cpp -- -I . -std=c++17
+//        -Wno-undefined-inline
 //
 //   + L2 predicate roles (needs the proposed role attributes implemented):
 //     ... -- -I . -std=c++17 -DHO_ROLES -Wno-undefined-inline
@@ -41,11 +43,10 @@ int safe_reference() {
 // === L2: unchecked-optional-access predicate (needs -DHO_ROLES) ==============
 
 // Unchecked access -- may be disengaged. Expected: warn.
-static void uncheckedUnwrap(HickettsOptional<int> &o) {
-  o.unwrap();
-}
+static void uncheckedUnwrap(HickettsOptional<int> &o) { o.unwrap(); }
 
-// Checked via operator bool -> queries_state narrows to engaged. Expected: safe.
+// Checked via operator bool -> queries_state narrows to engaged. Expected:
+// safe.
 static void checkedWithBool(HickettsOptional<int> &o) {
   if (o)
     o.unwrap();
diff --git a/hicketts/test_hicketts_vector.cpp b/hicketts/test_hicketts_vector.cpp
index 9cc29515a..d5ecdf2f3 100644
--- a/hicketts/test_hicketts_vector.cpp
+++ b/hicketts/test_hicketts_vector.cpp
@@ -22,7 +22,8 @@ int dangling_reference_from_temporary() {
 }
 
 int dangling_iterator_from_temporary() {
-  auto it = HickettsVector<int>{}.begin(); // it dangles into destroyed temporary
+  auto it =
+      HickettsVector<int>{}.begin(); // it dangles into destroyed temporary
   return *it;
 }
 
@@ -49,6 +50,6 @@ int safe_iterator() {
 // the gap the role vocabulary is meant to fill.
 
 int precondition_gap() {
-  HickettsVector<int> v;  // empty
-  return v.front();       // UB today: no warning from any attribute
+  HickettsVector<int> v; // empty
+  return v.front();      // UB today: no warning from any attribute
 }

``````````

</details>


https://github.com/llvm/llvm-project/pull/214255


More information about the llvm-commits mailing list