@@ -1785,8 +1785,98 @@ pub struct CopyNonOverlapping<'tcx> {
1785
1785
///////////////////////////////////////////////////////////////////////////
1786
1786
// Places
1787
1787
1788
- /// A path to a value; something that can be evaluated without
1789
- /// changing or disturbing program state.
1788
+ /// Places roughly correspond to a "location in memory." Places in MIR are the same mathematical
1789
+ /// object as places in Rust. This of course means that what exactly they are is undecided and part
1790
+ /// of the Rust memory model. However, they will likely contain at least the following three pieces
1791
+ /// of information in some form:
1792
+ ///
1793
+ /// 1. The part of memory that is referred to (see discussion below for details).
1794
+ /// 2. The type of the place and an optional variant index. See [`PlaceTy`][tcx::PlaceTy]
1795
+ /// 3. The provenance with which the place is being accessed.
1796
+ ///
1797
+ /// We'll give a description below of how the first two of these three properties are computed for a
1798
+ /// place. We cannot give a description of the provenance, because that is part of the undecided
1799
+ /// aliasing model - we only include it here at all to acknowledge its existence.
1800
+ ///
1801
+ /// For a place that has no projections, ie `Place { local, projection: [] }`, the part of memory is
1802
+ /// the local's full allocation and the type is the type of the local. For any other place, we
1803
+ /// define the values as a function of the parent place, that is the place with its last
1804
+ /// [`ProjectionElem`] stripped. The way this is computed of course depends on the kind of that last
1805
+ /// projection element:
1806
+ ///
1807
+ /// - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the
1808
+ /// given one, and makes no other changes. A `Downcast` projection on a place with its variant
1809
+ /// index already set is not well-formed.
1810
+ /// - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a
1811
+ /// place referring to one of the fields of the type. The referred to place in memory is where
1812
+ /// the layout places the field. The type becomes the type of the field.
1813
+ ///
1814
+ /// These projections are only legal for tuples, ADTs, closures, and generators. If the ADT or
1815
+ /// generator has more than one variant, the parent place's variant index must be set, indicating
1816
+ /// which variant is being used. If it has just one variant, the variant index may or may not be
1817
+ /// included - the single possible variant is inferred if it is not included.
1818
+ /// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the
1819
+ /// place as described in the documentation for the `ProjectionElem`. The resulting part of
1820
+ /// memory is the location of that element of the array/slice, and the type is `T`. This is only
1821
+ /// legal if the parent place has type `[T; N]` or `[T]` (*not* `&[T]`).
1822
+ /// - [`Subslice`](ProjectionElem::Subslice): Much like `ConstantIndex`. It is also only legal on
1823
+ /// `[T; N]` and `[T]`. However, this yields a `Place` of type `[T]`, and may refer to more than
1824
+ /// one element in the parent place.
1825
+ /// - [`Index`](ProjectionElem::Index): Like `ConstantIndex`, only legal on `[T; N]` or `[T]`.
1826
+ /// However, `Index` additionally takes a local from which the value of the index is computed at
1827
+ /// runtime. Computing the value of the index involves interpreting the `Local` as a
1828
+ /// `Place { local, projection: [] }`, and then computing its value as if done via
1829
+ /// [`Operand::Copy`]. The array/slice is then indexed with the resulting value. The local must
1830
+ /// have type `usize`.
1831
+ /// - [`Deref`](ProjectionElem::Deref): Derefs are the last type of projection, and the most
1832
+ /// complicated. They are only legal on parent places that are references, pointers, or `Box`. A
1833
+ /// `Deref` projection begins by creating a value from the parent place, as if by
1834
+ /// [`Operand::Copy`]. It then dereferences the resulting pointer, creating a place of the
1835
+ /// pointed to type.
1836
+ ///
1837
+ /// **Needs clarification**: What about metadata resulting from dereferencing wide pointers (and
1838
+ /// possibly from accessing unsized locals - not sure how those work)? That probably deserves to go
1839
+ /// on the list above and be discussed too. It is also probably necessary for making the indexing
1840
+ /// stuff lass hand-wavey.
1841
+ ///
1842
+ /// **Needs clarification**: When it says "part of memory" what does that mean precisely, and how
1843
+ /// does it interact with the metadata?
1844
+ ///
1845
+ /// One possible model that I believe makes sense is that "part of memory" is actually just the
1846
+ /// address of the beginning of the referred to range of bytes. For sized types, the size of the
1847
+ /// range is then stored in the type, and for unsized types it's stored (possibly indirectly,
1848
+ /// through a vtable) in the metadata.
1849
+ ///
1850
+ /// Alternatively, the "part of memory" could be a whole range of bytes. Initially seemed more
1851
+ /// natural to me, but seems like it falls apart after a little bit.
1852
+ ///
1853
+ /// More likely though, we should call this detail a part of the Rust memory model and let that deal
1854
+ /// with the precise definition of this part of a place. If we feel strongly, I don't think we *have
1855
+ /// to* though. MIR places are more flexible than Rust places, and we might be able to make a
1856
+ /// decision on the flexible parts without semi-stabilizing the source language. (end NC)
1857
+ ///
1858
+ /// Computing a place may be UB - this is certainly the case with dereferencing, which requires
1859
+ /// sufficient provenance, but it may additionally be the case for some of the other field
1860
+ /// projections.
1861
+ ///
1862
+ /// It is undecided when this UB kicks in. As best I can tell that is the question being discussed
1863
+ /// in [UCG#319]. Summarizing from that thread, I believe the options are:
1864
+ ///
1865
+ /// [UCG#319]: https://github.com/rust-lang/unsafe-code-guidelines/issues/319
1866
+ ///
1867
+ /// 1. Each intermediate place must have provenance for the whole part of memory it refers to. This
1868
+ /// is the status quo.
1869
+ /// 2. Only for intermediate place where the last projection was *not* a deref. This corresponds to
1870
+ /// "Check inbounds on place projection".
1871
+ /// 3. Only on place to value conversions, assignments, and referencing operation. This corresponds
1872
+ /// to "remove the restrictions from `*` entirely."
1873
+ /// 4. On each intermediate place if the place is used for a place to value conversion as part of
1874
+ /// an assignment assignment or it is used for a referencing operation. For a raw pointer
1875
+ /// computation, never. This corresponds to "magic?".
1876
+ ///
1877
+ /// Hopefully I am not misrepresenting anyone's opinions - please let me know if I am. Currently,
1878
+ /// Rust chooses option 1. This is checked by MIRI and taken advantage of by codegen (via `gep
1879
+ /// inbounds`). That is possibly subject to change.
1790
1880
#[ derive( Copy , Clone , PartialEq , Eq , Hash , TyEncodable , HashStable ) ]
1791
1881
pub struct Place < ' tcx > {
1792
1882
pub local : Local ,
@@ -2155,24 +2245,42 @@ pub struct SourceScopeLocalData {
2155
2245
///////////////////////////////////////////////////////////////////////////
2156
2246
// Operands
2157
2247
2158
- /// These are values that can appear inside an rvalue. They are intentionally
2159
- /// limited to prevent rvalues from being nested in one another.
2248
+ /// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of
2249
+ /// the memory model. One proposal for a definition of values can be found [on UCG][value-def].
2250
+ ///
2251
+ /// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md
2252
+ ///
2253
+ /// The most common way to create values is via a place to value conversion. A place to value
2254
+ /// conversion is an operation which reads the memory of the place and converts it to a value. This
2255
+ /// is a fundamentally *typed* operation. Different types will do different things. These are some
2256
+ /// possible examples of what Rust may - but will not necessarily - decide to do on place to value
2257
+ /// conversions:
2258
+ ///
2259
+ /// 1. Types with validity constraints cause UB if the validity constraint is not met
2260
+ /// 2. References/pointers may have their provenance change or cause other provenance related
2261
+ /// side-effects.
2262
+ ///
2263
+ /// A place to value conversion on a place that has its variant index set is not well-formed.
2264
+ /// However, note that this rule only applies to places appearing in MIR bodies. Many functions,
2265
+ /// such as [`Place::ty`], still accept such a place. If you write a function for which it might be
2266
+ /// ambiguous whether such a thing is accepted, make sure to document your choice clearly.
2160
2267
#[ derive( Clone , PartialEq , TyEncodable , TyDecodable , Hash , HashStable ) ]
2161
2268
pub enum Operand < ' tcx > {
2162
- /// Copy: The value must be available for use afterwards.
2163
- ///
2164
- /// This implies that the type of the place must be `Copy`; this is true
2165
- /// by construction during build, but also checked by the MIR type checker.
2269
+ /// Creates a value by performing a place to value conversion at the given place. The type of
2270
+ /// the place must be `Copy`
2166
2271
Copy ( Place < ' tcx > ) ,
2167
2272
2168
- /// Move: The value (including old borrows of it) will not be used again.
2273
+ /// Creates a value by performing a place to value conversion for the place, just like the
2274
+ /// `Copy` operand.
2275
+ ///
2276
+ /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide
2277
+ /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second place to value
2278
+ /// conversion on this place without first re-initializing it.
2169
2279
///
2170
- /// Safe for values of all types (modulo future developments towards `?Move`).
2171
- /// Correct usage patterns are enforced by the borrow checker for safe code.
2172
- /// `Copy` may be converted to `Move` to enable "last-use" optimizations.
2280
+ /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188
2173
2281
Move ( Place < ' tcx > ) ,
2174
2282
2175
- /// Synthesizes a constant value .
2283
+ /// Constants are already semantically values, and remain unchanged .
2176
2284
Constant ( Box < Constant < ' tcx > > ) ,
2177
2285
}
2178
2286
0 commit comments