1
+ use super :: flags:: FlagComputation ;
2
+ use super :: { DebruijnIndex , DebugWithInfcx , InferCtxtLike , TyCtxt , TypeFlags , WithInfcx } ;
1
3
use crate :: arena:: Arena ;
2
4
use rustc_data_structures:: aligned:: { align_of, Aligned } ;
3
5
use rustc_serialize:: { Encodable , Encoder } ;
4
- use rustc_type_ir:: { InferCtxtLike , WithInfcx } ;
5
6
use std:: alloc:: Layout ;
6
7
use std:: cmp:: Ordering ;
7
8
use std:: fmt;
@@ -12,6 +13,9 @@ use std::ops::Deref;
12
13
use std:: ptr;
13
14
use std:: slice;
14
15
16
+ #[ cfg( parallel_compiler) ]
17
+ use rustc_data_structures:: sync:: DynSync ;
18
+
15
19
/// `List<T>` is a bit like `&[T]`, but with some critical differences.
16
20
/// - IMPORTANT: Every `List<T>` is *required* to have unique contents. The
17
21
/// type's correctness relies on this, *but it does not enforce it*.
@@ -28,15 +32,27 @@ use std::slice;
28
32
/// - `T` must be `Copy`. This lets `List<T>` be stored in a dropless arena and
29
33
/// iterators return a `T` rather than a `&T`.
30
34
/// - `T` must not be zero-sized.
35
+ pub type List < T > = RawList < ( ) , T > ;
36
+
37
+ /// A generic type that can be used to prepend a [`List`] with some header.
38
+ ///
39
+ /// The header will be ignored for value-based operations like [`PartialEq`],
40
+ /// [`Hash`] and [`Encodable`].
31
41
#[ repr( C ) ]
32
- pub struct List < T > {
33
- len : usize ,
42
+ pub struct RawList < H , T > {
43
+ skel : ListSkeleton < H , T > ,
44
+ opaque : OpaqueListContents ,
45
+ }
34
46
47
+ /// A [`RawList`] without the unsized tail. This type is used for layout computation
48
+ /// and constructing empty lists.
49
+ #[ repr( C ) ]
50
+ struct ListSkeleton < H , T > {
51
+ header : H ,
52
+ len : usize ,
35
53
/// Although this claims to be a zero-length array, in practice `len`
36
54
/// elements are actually present.
37
55
data : [ T ; 0 ] ,
38
-
39
- opaque : OpaqueListContents ,
40
56
}
41
57
42
58
extern "C" {
@@ -45,35 +61,17 @@ extern "C" {
45
61
type OpaqueListContents ;
46
62
}
47
63
48
- impl < T > List < T > {
49
- /// Returns a reference to the (unique, static) empty list.
64
+ impl < H , T > RawList < H , T > {
50
65
#[ inline( always) ]
51
- pub fn empty < ' a > ( ) -> & ' a List < T > {
52
- #[ repr( align( 64 ) ) ]
53
- struct MaxAlign ;
54
-
55
- assert ! ( mem:: align_of:: <T >( ) <= mem:: align_of:: <MaxAlign >( ) ) ;
56
-
57
- #[ repr( C ) ]
58
- struct InOrder < T , U > ( T , U ) ;
59
-
60
- // The empty slice is static and contains a single `0` usize (for the
61
- // length) that is 64-byte aligned, thus featuring the necessary
62
- // trailing padding for elements with up to 64-byte alignment.
63
- static EMPTY_SLICE : InOrder < usize , MaxAlign > = InOrder ( 0 , MaxAlign ) ;
64
- unsafe { & * ( std:: ptr:: addr_of!( EMPTY_SLICE ) as * const List < T > ) }
65
- }
66
-
67
66
pub fn len ( & self ) -> usize {
68
- self . len
67
+ self . skel . len
69
68
}
70
69
70
+ #[ inline( always) ]
71
71
pub fn as_slice ( & self ) -> & [ T ] {
72
72
self
73
73
}
74
- }
75
74
76
- impl < T : Copy > List < T > {
77
75
/// Allocates a list from `arena` and copies the contents of `slice` into it.
78
76
///
79
77
/// WARNING: the contents *must be unique*, such that no list with these
@@ -84,20 +82,31 @@ impl<T: Copy> List<T> {
84
82
/// (because the empty list exists statically, and is available via
85
83
/// `empty()`).
86
84
#[ inline]
87
- pub ( super ) fn from_arena < ' tcx > ( arena : & ' tcx Arena < ' tcx > , slice : & [ T ] ) -> & ' tcx List < T > {
85
+ pub ( super ) fn from_arena < ' tcx > (
86
+ arena : & ' tcx Arena < ' tcx > ,
87
+ header : H ,
88
+ slice : & [ T ] ,
89
+ ) -> & ' tcx RawList < H , T >
90
+ where
91
+ T : Copy ,
92
+ {
88
93
assert ! ( !mem:: needs_drop:: <T >( ) ) ;
89
94
assert ! ( mem:: size_of:: <T >( ) != 0 ) ;
90
95
assert ! ( !slice. is_empty( ) ) ;
91
96
92
97
let ( layout, _offset) =
93
- Layout :: new :: < usize > ( ) . extend ( Layout :: for_value :: < [ T ] > ( slice) ) . unwrap ( ) ;
94
- let mem = arena. dropless . alloc_raw ( layout) as * mut List < T > ;
98
+ Layout :: new :: < ListSkeleton < H , T > > ( ) . extend ( Layout :: for_value :: < [ T ] > ( slice) ) . unwrap ( ) ;
99
+
100
+ let mem = arena. dropless . alloc_raw ( layout) as * mut RawList < H , T > ;
95
101
unsafe {
102
+ // Write the header
103
+ ptr:: addr_of_mut!( ( * mem) . skel. header) . write ( header) ;
104
+
96
105
// Write the length
97
- ptr:: addr_of_mut!( ( * mem) . len) . write ( slice. len ( ) ) ;
106
+ ptr:: addr_of_mut!( ( * mem) . skel . len) . write ( slice. len ( ) ) ;
98
107
99
108
// Write the elements
100
- ptr:: addr_of_mut!( ( * mem) . data)
109
+ ptr:: addr_of_mut!( ( * mem) . skel . data)
101
110
. cast :: < T > ( )
102
111
. copy_from_nonoverlapping ( slice. as_ptr ( ) , slice. len ( ) ) ;
103
112
@@ -110,17 +119,44 @@ impl<T: Copy> List<T> {
110
119
//
111
120
// This would be weird, as `self.into_iter` iterates over `T` directly.
112
121
#[ inline( always) ]
113
- pub fn iter ( & self ) -> <& ' _ List < T > as IntoIterator >:: IntoIter {
122
+ pub fn iter ( & self ) -> <& ' _ RawList < H , T > as IntoIterator >:: IntoIter
123
+ where
124
+ T : Copy ,
125
+ {
114
126
self . into_iter ( )
115
127
}
116
128
}
117
129
118
- impl < T : fmt:: Debug > fmt:: Debug for List < T > {
130
+ macro_rules! impl_list_empty {
131
+ ( $header_ty: ty, $header_init: expr) => {
132
+ impl <T > RawList <$header_ty, T > {
133
+ /// Returns a reference to the (per header unique, static) empty list.
134
+ #[ inline( always) ]
135
+ pub fn empty<' a>( ) -> & ' a RawList <$header_ty, T > {
136
+ #[ repr( align( 64 ) ) ]
137
+ struct MaxAlign ;
138
+
139
+ static EMPTY : ListSkeleton <$header_ty, MaxAlign > =
140
+ ListSkeleton { header: $header_init, len: 0 , data: [ ] } ;
141
+
142
+ assert!( mem:: align_of:: <T >( ) <= mem:: align_of:: <MaxAlign >( ) ) ;
143
+
144
+ // SAFETY: `EMPTY` is sufficiently aligned to be an empty list for all
145
+ // types with `align_of(T) <= align_of(MaxAlign)`, which we checked above.
146
+ unsafe { & * ( std:: ptr:: addr_of!( EMPTY ) as * const RawList <$header_ty, T >) }
147
+ }
148
+ }
149
+ } ;
150
+ }
151
+
152
+ impl_list_empty ! ( ( ) , ( ) ) ;
153
+
154
+ impl < H , T : fmt:: Debug > fmt:: Debug for RawList < H , T > {
119
155
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
120
156
( * * self ) . fmt ( f)
121
157
}
122
158
}
123
- impl < ' tcx , T : super :: DebugWithInfcx < TyCtxt < ' tcx > > > super :: DebugWithInfcx < TyCtxt < ' tcx > > for List < T > {
159
+ impl < ' tcx , H , T : DebugWithInfcx < TyCtxt < ' tcx > > > DebugWithInfcx < TyCtxt < ' tcx > > for RawList < H , T > {
124
160
fn fmt < Infcx : InferCtxtLike < Interner = TyCtxt < ' tcx > > > (
125
161
this : WithInfcx < ' _ , Infcx , & Self > ,
126
162
f : & mut core:: fmt:: Formatter < ' _ > ,
@@ -129,40 +165,40 @@ impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<
129
165
}
130
166
}
131
167
132
- impl < S : Encoder , T : Encodable < S > > Encodable < S > for List < T > {
168
+ impl < H , S : Encoder , T : Encodable < S > > Encodable < S > for RawList < H , T > {
133
169
#[ inline]
134
170
fn encode ( & self , s : & mut S ) {
135
171
( * * self ) . encode ( s) ;
136
172
}
137
173
}
138
174
139
- impl < T : PartialEq > PartialEq for List < T > {
175
+ impl < H , T : PartialEq > PartialEq for RawList < H , T > {
140
176
#[ inline]
141
- fn eq ( & self , other : & List < T > ) -> bool {
177
+ fn eq ( & self , other : & RawList < H , T > ) -> bool {
142
178
// Pointer equality implies list equality (due to the unique contents
143
179
// assumption).
144
180
ptr:: eq ( self , other)
145
181
}
146
182
}
147
183
148
- impl < T : Eq > Eq for List < T > { }
184
+ impl < H , T : Eq > Eq for RawList < H , T > { }
149
185
150
- impl < T > Ord for List < T >
186
+ impl < H , T > Ord for RawList < H , T >
151
187
where
152
188
T : Ord ,
153
189
{
154
- fn cmp ( & self , other : & List < T > ) -> Ordering {
190
+ fn cmp ( & self , other : & RawList < H , T > ) -> Ordering {
155
191
// Pointer equality implies list equality (due to the unique contents
156
192
// assumption), but the contents must be compared otherwise.
157
193
if self == other { Ordering :: Equal } else { <[ T ] as Ord >:: cmp ( & * * self , & * * other) }
158
194
}
159
195
}
160
196
161
- impl < T > PartialOrd for List < T >
197
+ impl < H , T > PartialOrd for RawList < H , T >
162
198
where
163
199
T : PartialOrd ,
164
200
{
165
- fn partial_cmp ( & self , other : & List < T > ) -> Option < Ordering > {
201
+ fn partial_cmp ( & self , other : & RawList < H , T > ) -> Option < Ordering > {
166
202
// Pointer equality implies list equality (due to the unique contents
167
203
// assumption), but the contents must be compared otherwise.
168
204
if self == other {
@@ -173,31 +209,36 @@ where
173
209
}
174
210
}
175
211
176
- impl < T > Hash for List < T > {
212
+ impl < Hdr , T > Hash for RawList < Hdr , T > {
177
213
#[ inline]
178
214
fn hash < H : Hasher > ( & self , s : & mut H ) {
179
215
// Pointer hashing is sufficient (due to the unique contents
180
216
// assumption).
181
- ( self as * const List < T > ) . hash ( s)
217
+ ptr :: from_ref ( self ) . hash ( s)
182
218
}
183
219
}
184
220
185
- impl < T > Deref for List < T > {
221
+ impl < H , T > Deref for RawList < H , T > {
186
222
type Target = [ T ] ;
187
223
#[ inline( always) ]
188
224
fn deref ( & self ) -> & [ T ] {
189
225
self . as_ref ( )
190
226
}
191
227
}
192
228
193
- impl < T > AsRef < [ T ] > for List < T > {
229
+ impl < H , T > AsRef < [ T ] > for RawList < H , T > {
194
230
#[ inline( always) ]
195
231
fn as_ref ( & self ) -> & [ T ] {
196
- unsafe { slice:: from_raw_parts ( self . data . as_ptr ( ) , self . len ) }
232
+ let data_ptr = ptr:: addr_of!( self . skel. data) . cast :: < T > ( ) ;
233
+ // SAFETY: `data_ptr` has the same provenance as `self` and can therefore
234
+ // access the `self.skel.len` elements stored at `self.skel.data`.
235
+ // Note that we specifically don't reborrow `&self.skel.data`, because that
236
+ // would give us a pointer with provenance over 0 bytes.
237
+ unsafe { slice:: from_raw_parts ( data_ptr, self . skel . len ) }
197
238
}
198
239
}
199
240
200
- impl < ' a , T : Copy > IntoIterator for & ' a List < T > {
241
+ impl < ' a , H , T : Copy > IntoIterator for & ' a RawList < H , T > {
201
242
type Item = T ;
202
243
type IntoIter = iter:: Copied < <& ' a [ T ] as IntoIterator >:: IntoIter > ;
203
244
#[ inline( always) ]
@@ -206,27 +247,56 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> {
206
247
}
207
248
}
208
249
209
- unsafe impl < T : Sync > Sync for List < T > { }
250
+ unsafe impl < H : Sync , T : Sync > Sync for RawList < H , T > { }
210
251
211
252
// We need this since `List` uses extern type `OpaqueListContents`.
212
253
#[ cfg( parallel_compiler) ]
213
- use rustc_data_structures:: sync:: DynSync ;
214
-
215
- use super :: TyCtxt ;
216
- #[ cfg( parallel_compiler) ]
217
- unsafe impl < T : DynSync > DynSync for List < T > { }
254
+ unsafe impl < H : DynSync , T : DynSync > DynSync for RawList < H , T > { }
218
255
219
256
// Safety:
220
- // Layouts of `Equivalent<T>` and `List<T>` are the same, modulo opaque tail,
221
- // thus aligns of `Equivalent<T>` and `List<T>` must be the same.
222
- unsafe impl < T > Aligned for List < T > {
223
- const ALIGN : ptr:: Alignment = {
224
- #[ repr( C ) ]
225
- struct Equivalent < T > {
226
- _len : usize ,
227
- _data : [ T ; 0 ] ,
228
- }
257
+ // Layouts of `ListSkeleton<H, T>` and `RawList<H, T>` are the same, modulo opaque tail,
258
+ // thus aligns of `ListSkeleton<H, T>` and `RawList<H, T>` must be the same.
259
+ unsafe impl < H , T > Aligned for RawList < H , T > {
260
+ const ALIGN : ptr:: Alignment = align_of :: < ListSkeleton < H , T > > ( ) ;
261
+ }
229
262
230
- align_of :: < Equivalent < T > > ( )
231
- } ;
263
+ /// A [`List`] that additionally stores type information inline to speed up
264
+ /// [`TypeVisitableExt`](super::TypeVisitableExt) operations.
265
+ pub type ListWithCachedTypeInfo < T > = RawList < TypeInfo , T > ;
266
+
267
+ impl < T > ListWithCachedTypeInfo < T > {
268
+ #[ inline( always) ]
269
+ pub fn flags ( & self ) -> TypeFlags {
270
+ self . skel . header . flags
271
+ }
272
+
273
+ #[ inline( always) ]
274
+ pub fn outer_exclusive_binder ( & self ) -> DebruijnIndex {
275
+ self . skel . header . outer_exclusive_binder
276
+ }
277
+ }
278
+
279
+ impl_list_empty ! ( TypeInfo , TypeInfo :: empty( ) ) ;
280
+
281
+ /// The additional info that is stored in [`ListWithCachedTypeInfo`].
282
+ #[ repr( C ) ]
283
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
284
+ pub struct TypeInfo {
285
+ flags : TypeFlags ,
286
+ outer_exclusive_binder : DebruijnIndex ,
287
+ }
288
+
289
+ impl TypeInfo {
290
+ const fn empty ( ) -> Self {
291
+ Self { flags : TypeFlags :: empty ( ) , outer_exclusive_binder : super :: INNERMOST }
292
+ }
293
+ }
294
+
295
+ impl From < FlagComputation > for TypeInfo {
296
+ fn from ( computation : FlagComputation ) -> TypeInfo {
297
+ TypeInfo {
298
+ flags : computation. flags ,
299
+ outer_exclusive_binder : computation. outer_exclusive_binder ,
300
+ }
301
+ }
232
302
}
0 commit comments