[clang] [LifetimeSafety] Fix crash on explicit object member functions (PR #212154)

via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 27 03:02:31 PDT 2026


================
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 %s -std=c++23 -verify -fsyntax-only -Wlifetime-safety -Wlifetime-safety-lifetimebound-violation
+
+// expected-no-diagnostics
+
+// Explicit object member functions must not be treated as having an implicit
+// object argument.
+struct Foo {
+  template <typename T>
+  int get(this Foo &&self, T) {
+    return self.field;
+  }
+
+  int field;
+};
+
+struct Base {};
+struct Derived : Base {
+  int base(this Base &&, int);
+};
+
+template <typename T>
+struct Crtp {
+  template <typename Self>
+  int deduced(this Self &&self, T) {
+    return self.field;
+  }
+};
+
+struct Widget : Crtp<int> {
+  int field;
+};
+
+struct NoMove {
+  NoMove() = default;
+  NoMove(NoMove &&) = delete;
+  NoMove(const NoMove &) = delete;
+
+  int get(this NoMove &&self, int) {
+    return self.field;
+  }
+
+  int field;
+};
+
+template <typename T>
+struct SharedPtr {
+  SharedPtr() = default;
+  SharedPtr(SharedPtr &&o) : p(o.p) { o.p = nullptr; }
+  SharedPtr(const SharedPtr &) = default;
+
+  int get(this SharedPtr &&self, int) {
+    return self.p->field;
+  }
+
+  T *p = nullptr;
+};
+
+void call() {
+  Foo().get(0);
+  Derived().base(0);
+  Widget().deduced(0);
+  NoMove().get(0);
+  SharedPtr<NoMove>().get(0);
+}
+
+struct Holder {
+  int field;
+  const int *borrow() [[clang::lifetimebound]] { return &field; }
+  void consume(this Holder &&self) {}
+};
+
+const int *object_arg_is_not_moved(Holder &&h [[clang::lifetimebound]]) {
+  static_cast<Holder &&>(h).consume();
+  return h.borrow();
+}
----------------
arhwx wrote:

Added both tests, they warn as you expected and fail without the guard.

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


More information about the cfe-commits mailing list