move perennial paper to consistent location
[web.git] / personal / _posts / 2024-08-14-places.md
index 813bfc91fea7769306ae45e25237dc231dbb1379..4b93ee5e1dd1ac1083fa935d5952de785ade3d1a 100644 (file)
@@ -151,6 +151,17 @@ match *ptr { _val => "not happy" } // This is UB.
 The scrutinee of a `match` expression is a place expression, and if the pattern is `_` then a value is never constructed.
 However, when an actual binder is present, this introduces a local variable and a place-to-value coercion is inserted to compute the value that will be stored in that local variable.
 
 The scrutinee of a `match` expression is a place expression, and if the pattern is `_` then a value is never constructed.
 However, when an actual binder is present, this introduces a local variable and a place-to-value coercion is inserted to compute the value that will be stored in that local variable.
 
+**Note on `unsafe` blocks.**
+Note that wrapping an expression in a block forces it to be a value expression.
+This means that `unsafe { *ptr }` always loads from the pointer!
+In other words:
+```rust
+let ptr = std::ptr::null::<i32>();
+let _ = *ptr; // This is fine!
+let _ = unsafe { *ptr }; // This is UB.
+```
+The fact that braces force a value expression can occasionally be useful, but the fact that `unsafe` blocks do that is definitely quite unfortunate.
+
 ### Are there also value-to-place coercions?
 
 So far, we have discussed what happens when a place expression is encountered in a spot where a value expression was expected.
 ### Are there also value-to-place coercions?
 
 So far, we have discussed what happens when a place expression is encountered in a spot where a value expression was expected.