clarify how 'let _' relates to the grammar above
authorRalf Jung <post@ralfj.de>
Thu, 22 Aug 2024 07:54:09 +0000 (09:54 +0200)
committerRalf Jung <post@ralfj.de>
Thu, 22 Aug 2024 07:54:09 +0000 (09:54 +0200)
personal/_posts/2024-08-14-places.md

index 8f3532c3574f08881704ca4d7c2ecb395c1cc7aa..813bfc91fea7769306ae45e25237dc231dbb1379 100644 (file)
@@ -126,10 +126,16 @@ let _ = *ptr; // This is fine!
 let _val = *ptr; // This is UB.
 ```
 
 let _val = *ptr; // This is UB.
 ```
 
-The reason for this is that the `_` pattern does *not* incur a place-to-value coercion.
+Note that the grammar above cannot represent this program: in the full grammar of Rust, the `let` syntax is something like "`let` _Pattern_ `=` _PlaceExpr_ `;`",
+and then pattern desugaring decides what to do with that place expression.
+If the pattern is a binder (the common case), a `load` gets inserted to compute the initial value for the local variable that this binder refers to.
+However, if the pattern is `_`, then the place expression still gets evaluated---but the result of that evaluation is simply discarded.
+MIR uses a `PlaceMention` statement to indicate these semantics.
+
+In particular, this means that the `_` pattern does *not* incur a place-to-value coercion!
 The desugared form of the relevant part of this code is:
 ```rust
 The desugared form of the relevant part of this code is:
 ```rust
-let _ = *(load ptr); // This is fine!
+PlaceMention(*(load ptr)); // This is fine!
 let _val = load *(load ptr); // This is UB.
 ```
 As you can see, the first line does not actually load from the pointer (the only `load` is there to load the pointer itself from the local variable that stores it).
 let _val = load *(load ptr); // This is UB.
 ```
 As you can see, the first line does not actually load from the pointer (the only `load` is there to load the pointer itself from the local variable that stores it).