[clang] [LifetimeSafety] Add support for destructive function calls (PR #195064)

Utkarsh Saxena via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 30 12:50:42 PDT 2026


================
@@ -540,6 +540,71 @@ void function_captured_ref_invalidated() {
 
 } // namespace callable_wrappers
 
+// FIXME: does not report a double free
+namespace explicit_destructor {
+
+void explicit_destructor_invalidates_pointer() {
+  std::string s = "42";
+  const char *p = s.data(); // expected-warning {{object whose reference is captured is later invalidated}}
+  s.~basic_string();        // expected-note {{invalidated here}}
+  (void)*p;                 // expected-note {{later used here}}
+}
+
+void pointer_destructor_invalidates_pointer() {
+  char storage[sizeof(std::string)];
+  std::string *obj = new (storage) std::string("42"); // expected-warning {{object whose reference is captured is later invalidated}}
+  const char *p = obj->data();
+  obj->~basic_string();                               // expected-note {{invalidated here}}
+  (void)*p;                                           // expected-note {{later used here}}
+}
+
+void destroy_at_invalidates_pointer() {
+  char storage[sizeof(std::string)];
+  std::string *obj = new (storage) std::string("42"); // expected-warning {{object whose reference is captured is later invalidated}}
+  const char *p = obj->data();
+  std::destroy_at(obj);                               // expected-note {{invalidated here}}
+  (void)*p;                                           // expected-note {{later used here}}
+}
+
+void destroy_at_then_placement_new_rescues_pointer() {
+  char storage[sizeof(std::string)];
+  std::string *obj = new (storage) std::string("42");
+  const char *p = obj->data();
+  std::destroy_at(obj);
+  obj = new (storage) std::string("23");
+  p = obj->data();
+  (void)*p;
+}
+
+void destroy_at_invalidates_array_pointer() {
+  std::string arr[1] = {"42"};
+  std::string (&arr_ref)[1] = arr;
+  const char *p = arr[0].data(); // expected-warning {{object whose reference is captured is later invalidated}}
+  std::destroy_at(&arr_ref);     // expected-note {{invalidated here}}
+  (void)*p;                      // expected-note {{later used here}}
+}
+
+void reference_destructor_invalidates_pointer() {
+  std::string s = "42";
+  std::string &ref = s;       // expected-warning {{object whose reference is captured is later invalidated}}
+  const char *p = ref.data();
+  std::destroy_at(&ref);      // expected-note {{invalidated here}}
+  (void)*p;                   // expected-note {{later used here}}
+}
+
+struct StringOwner {
+  std::string s;
+};
+
+void member_destructor_invalidates_pointer() {
+  StringOwner owner = {"42"};
+  const char *p = owner.s.data(); // expected-warning {{object whose reference is captured is later invalidated}}
+  owner.s.~basic_string();        // expected-note {{invalidated here}}
+  (void)*p;                       // expected-note {{later used here}}
+}
+
----------------
usx95 wrote:

No. It should be fine to have this false-positive for now. This PR is not the reason for this FP. Should be fixed more systematically later.

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


More information about the cfe-commits mailing list