================
@@ -4318,6 +4319,324 @@ void foo() {
                             // expected-note {{result of call to 'get' aliases 
the storage of local variable 'o' because the implicit object parameter is 
inferred as lifetimebound}}
         up = std::move(o);  // expected-note {{potentially moved here}}
     }                       // expected-note {{local variable 'o' is destroyed 
here}}
-    (void)*p;               // expected-note {{later used here}}
+    use(*p);                // expected-note {{later used here}}
 }
 } // namespace TakeOwnershipTests
+
+//===----------------------------------------------------------------------===//
+// What counts as a use
+//
+// A use is an access through an lvalue: reading it (an lvalue-to-rvalue
+// conversion) or writing through it. The loans of the accessed lvalue say 
which
+// objects it may name, so a dereference needs no special handling. Taking an
+// address, naming a variable, or copying a pointer out of one is not an 
access.
+//===----------------------------------------------------------------------===//
+
+namespace std { class type_info; }
+
+namespace what_is_a_use {
+struct Node {
+  int id;
+  Node *next;
+};
+
+void copying_a_pointer_is_not_a_use() {
+  Node *p;
+  {
+    Node local;
+    p = &local;  // expected-warning {{local variable 'local' does not live 
long enough}}
+  }              // expected-note {{local variable 'local' is destroyed here}}
+  Node *q = p;   // Reads p, not *p.
+                 // expected-note@-1 {{local variable 'p' aliases the storage 
of local variable 'local'}}
+  use(q);        // expected-note {{later used here}}
+}
+
+void taking_an_address_is_not_a_use() {
+  Node *p;
+  {
+    Node local;
+    p = &local;
+  }
+  Node **pp = &p;          // no-warning: borrows p's storage, never reads it.
+  Node *reborrow = &*p;    // no-warning: reborrows, no access.
+  Node **pnext = &p->next; // no-warning: address of a field.
+  (void)pp; (void)reborrow; (void)pnext;
+}
+
+void reading_through_a_pointer_is_a_use() {
+  Node *p;
+  int sink;
+  {
+    Node local;
+    p = &local;   // expected-warning {{local variable 'local' does not live 
long enough}}
+  }               // expected-note {{local variable 'local' is destroyed here}}
+  sink = p->id;   // expected-note {{later used here}}
+  (void)sink;
+}
+
+// Loading a scalar is not a use of the scalar; it is a use of the pointer that
+// was dereferenced to reach it.
+void reading_a_pointer_field_is_a_use() {
+  Node *p;
+  Node *sink;
+  {
+    Node local;
+    p = &local;   // expected-warning {{local variable 'local' does not live 
long enough}}
+  }               // expected-note {{local variable 'local' is destroyed here}}
+  sink = p->next; // expected-note {{later used here}}
+  (void)sink;
+}
+
+void writing_through_a_pointer_is_a_use() {
+  Node *p;
+  {
+    Node local;
+    p = &local;      // expected-warning {{local variable 'local' does not 
live long enough}}
+  }                  // expected-note {{local variable 'local' is destroyed 
here}}
+  p->id = 1;         // expected-note {{later used here}}
+  p->next = nullptr;
+}
+
+void incrementing_through_a_pointer_is_a_use() {
+  Node *p;
+  {
+    Node local;
+    p = &local;   // expected-warning {{local variable 'local' does not live 
long enough}}
+  }               // expected-note {{local variable 'local' is destroyed here}}
+  p->id++;        // expected-note {{later used here}}
+}
+
+// Incrementing the pointer itself only touches p's own storage.
+void incrementing_the_pointer_is_not_a_use() {
+  Node *p;
+  {
+    Node local;
+    p = &local;
+  }
+  p++;             // no-warning
+  p += 1;          // no-warning
+}
+
+void discarding_the_value_is_not_a_use() {
+  Node *p;
+  {
+    Node local;
+    p = &local;
+  }
+  (void)p;         // no-warning
+}
+
+void element_access(int i) {
+  Node *arr[4];
+  Node *p, *sink;
+  {
+    Node local;
+    p = &local;
+  }
+  Node **elem = &arr[i];  // no-warning: address of an element.
+  arr[i] = p;             // Reads p, writes the element; neither reads *p.
+  sink = arr[i];          // Reads the element, which names part of arr.
+  (void)elem; (void)sink;
+}
+
+// A dereference only accesses the level actually loaded.
+void one_level_per_load() {
+  Node **pp;
+  {
+    Node *inner;
+    Node outer;
+    inner = &outer;
+    pp = &inner;    // expected-warning {{local variable 'inner' does not live 
long enough}}
+  }                 // expected-note {{local variable 'inner' is destroyed 
here}}
+  Node *q = *pp;    // expected-note {{later used here}}
+  (void)q;          // Reads pp, so it names 'inner'; 'outer' is never read.
----------------
usx95 wrote:

Can you also add `(void)*q`, `use(q)` and `use(pp)` all of which should read 
`outer` (current: https://godbolt.org/z/j9ffMjzx9)

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

Reply via email to