@@ -88,6 +88,7 @@ use std::borrow::Cow;
88
88
89
89
use either:: Either ;
90
90
use rustc_abi:: { self as abi, BackendRepr , FIRST_VARIANT , FieldIdx , Primitive , Size , VariantIdx } ;
91
+ use rustc_arena:: DroplessArena ;
91
92
use rustc_const_eval:: const_eval:: DummyMachine ;
92
93
use rustc_const_eval:: interpret:: {
93
94
ImmTy , Immediate , InterpCx , MemPlaceMeta , MemoryKind , OpTy , Projectable , Scalar ,
@@ -126,7 +127,9 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
126
127
// Clone dominators because we need them while mutating the body.
127
128
let dominators = body. basic_blocks . dominators ( ) . clone ( ) ;
128
129
129
- let mut state = VnState :: new ( tcx, body, typing_env, & ssa, dominators, & body. local_decls ) ;
130
+ let arena = DroplessArena :: default ( ) ;
131
+ let mut state =
132
+ VnState :: new ( tcx, body, typing_env, & ssa, dominators, & body. local_decls , & arena) ;
130
133
131
134
for local in body. args_iter ( ) . filter ( |& local| ssa. is_ssa ( local) ) {
132
135
let opaque = state. new_opaque ( body. local_decls [ local] . ty ) ;
@@ -160,8 +163,8 @@ enum AddressKind {
160
163
Address ( RawPtrKind ) ,
161
164
}
162
165
163
- #[ derive( Debug , PartialEq , Eq , Hash ) ]
164
- enum Value < ' tcx > {
166
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
167
+ enum Value < ' a , ' tcx > {
165
168
// Root values.
166
169
/// Used to represent values we know nothing about.
167
170
/// The `usize` is a counter incremented by `new_opaque`.
@@ -176,7 +179,7 @@ enum Value<'tcx> {
176
179
} ,
177
180
/// An aggregate value, either tuple/closure/struct/enum.
178
181
/// This does not contain unions, as we cannot reason with the value.
179
- Aggregate ( VariantIdx , Vec < VnIndex > ) ,
182
+ Aggregate ( VariantIdx , & ' a [ VnIndex ] ) ,
180
183
/// A raw pointer aggregate built from a thin pointer and metadata.
181
184
RawPtr {
182
185
/// Thin pointer component. This is field 0 in MIR.
@@ -212,7 +215,7 @@ enum Value<'tcx> {
212
215
} ,
213
216
}
214
217
215
- struct VnState < ' body , ' tcx > {
218
+ struct VnState < ' body , ' a , ' tcx > {
216
219
tcx : TyCtxt < ' tcx > ,
217
220
ecx : InterpCx < ' tcx , DummyMachine > ,
218
221
local_decls : & ' body LocalDecls < ' tcx > ,
@@ -222,7 +225,7 @@ struct VnState<'body, 'tcx> {
222
225
/// Locals that are assigned that value.
223
226
// This vector does not hold all the values of `VnIndex` that we create.
224
227
rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
225
- values : FxIndexSet < ( Value < ' tcx > , Ty < ' tcx > ) > ,
228
+ values : FxIndexSet < ( Value < ' a , ' tcx > , Ty < ' tcx > ) > ,
226
229
/// Values evaluated as constants if possible.
227
230
evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
228
231
/// Counter to generate different values.
@@ -232,16 +235,18 @@ struct VnState<'body, 'tcx> {
232
235
ssa : & ' body SsaLocals ,
233
236
dominators : Dominators < BasicBlock > ,
234
237
reused_locals : DenseBitSet < Local > ,
238
+ arena : & ' a DroplessArena ,
235
239
}
236
240
237
- impl < ' body , ' tcx > VnState < ' body , ' tcx > {
241
+ impl < ' body , ' a , ' tcx > VnState < ' body , ' a , ' tcx > {
238
242
fn new (
239
243
tcx : TyCtxt < ' tcx > ,
240
244
body : & Body < ' tcx > ,
241
245
typing_env : ty:: TypingEnv < ' tcx > ,
242
246
ssa : & ' body SsaLocals ,
243
247
dominators : Dominators < BasicBlock > ,
244
248
local_decls : & ' body LocalDecls < ' tcx > ,
249
+ arena : & ' a DroplessArena ,
245
250
) -> Self {
246
251
// Compute a rough estimate of the number of values in the body from the number of
247
252
// statements. This is meant to reduce the number of allocations, but it's all right if
@@ -264,6 +269,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
264
269
ssa,
265
270
dominators,
266
271
reused_locals : DenseBitSet :: new_empty ( local_decls. len ( ) ) ,
272
+ arena,
267
273
}
268
274
}
269
275
@@ -272,7 +278,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
272
278
}
273
279
274
280
#[ instrument( level = "trace" , skip( self ) , ret) ]
275
- fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' tcx > ) -> VnIndex {
281
+ fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' a , ' tcx > ) -> VnIndex {
276
282
let ( index, new) = self . values . insert_full ( ( value, ty) ) ;
277
283
let index = VnIndex :: from_usize ( index) ;
278
284
if new {
@@ -315,8 +321,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
315
321
}
316
322
317
323
#[ inline]
318
- fn get ( & self , index : VnIndex ) -> & Value < ' tcx > {
319
- & self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
324
+ fn get ( & self , index : VnIndex ) -> Value < ' a , ' tcx > {
325
+ self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 0
320
326
}
321
327
322
328
#[ inline]
@@ -361,8 +367,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
361
367
self . insert ( ty, Value :: Constant { value, disambiguator : 0 } )
362
368
}
363
369
364
- fn insert_tuple ( & mut self , ty : Ty < ' tcx > , values : Vec < VnIndex > ) -> VnIndex {
365
- self . insert ( ty, Value :: Aggregate ( VariantIdx :: ZERO , values) )
370
+ fn insert_tuple ( & mut self , ty : Ty < ' tcx > , values : & [ VnIndex ] ) -> VnIndex {
371
+ self . insert ( ty, Value :: Aggregate ( VariantIdx :: ZERO , self . arena . alloc_slice ( values) ) )
366
372
}
367
373
368
374
fn insert_deref ( & mut self , ty : Ty < ' tcx > , value : VnIndex ) -> VnIndex {
@@ -388,7 +394,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
388
394
} else {
389
395
return None ;
390
396
} ;
391
- let op = match * self . get ( value) {
397
+ let op = match self . get ( value) {
392
398
_ if ty. is_zst ( ) => ImmTy :: uninit ( ty) . into ( ) ,
393
399
394
400
Opaque ( _) => return None ,
@@ -608,7 +614,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
608
614
if let Value :: Aggregate ( _, fields) = self . get ( value) {
609
615
return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ;
610
616
} else if let Value :: Projection ( outer_value, ProjectionElem :: Downcast ( _, read_variant) ) = self . get ( value)
611
- && let Value :: Aggregate ( written_variant, fields) = self . get ( * outer_value)
617
+ && let Value :: Aggregate ( written_variant, fields) = self . get ( outer_value)
612
618
// This pass is not aware of control-flow, so we do not know whether the
613
619
// replacement we are doing is actually reachable. We could be in any arm of
614
620
// ```
@@ -633,15 +639,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
633
639
ProjectionElem :: Index ( idx) => {
634
640
if let Value :: Repeat ( inner, _) = self . get ( value) {
635
641
* from_non_ssa_index |= self . locals [ idx] . is_none ( ) ;
636
- return Some ( ( projection_ty, * inner) ) ;
642
+ return Some ( ( projection_ty, inner) ) ;
637
643
}
638
644
let idx = self . locals [ idx] ?;
639
645
ProjectionElem :: Index ( idx)
640
646
}
641
647
ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
642
648
match self . get ( value) {
643
649
Value :: Repeat ( inner, _) => {
644
- return Some ( ( projection_ty, * inner) ) ;
650
+ return Some ( ( projection_ty, inner) ) ;
645
651
}
646
652
Value :: Aggregate ( _, operands) => {
647
653
let offset = if from_end {
@@ -731,8 +737,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
731
737
let mut place_ty = PlaceTy :: from_ty ( self . local_decls [ place. local ] . ty ) ;
732
738
let mut from_non_ssa_index = false ;
733
739
for ( index, proj) in place. projection . iter ( ) . enumerate ( ) {
734
- if let Value :: Projection ( pointer, ProjectionElem :: Deref ) = * self . get ( value)
735
- && let Value :: Address { place : mut pointee, kind, .. } = * self . get ( pointer)
740
+ if let Value :: Projection ( pointer, ProjectionElem :: Deref ) = self . get ( value)
741
+ && let Value :: Address { place : mut pointee, kind, .. } = self . get ( pointer)
736
742
&& let AddressKind :: Ref ( BorrowKind :: Shared ) = kind
737
743
&& let Some ( v) = self . simplify_place_value ( & mut pointee, location)
738
744
{
@@ -755,8 +761,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
755
761
( place_ty, value) = self . project ( place_ty, value, proj, & mut from_non_ssa_index) ?;
756
762
}
757
763
758
- if let Value :: Projection ( pointer, ProjectionElem :: Deref ) = * self . get ( value)
759
- && let Value :: Address { place : mut pointee, kind, .. } = * self . get ( pointer)
764
+ if let Value :: Projection ( pointer, ProjectionElem :: Deref ) = self . get ( value)
765
+ && let Value :: Address { place : mut pointee, kind, .. } = self . get ( pointer)
760
766
&& let AddressKind :: Ref ( BorrowKind :: Shared ) = kind
761
767
&& let Some ( v) = self . simplify_place_value ( & mut pointee, location)
762
768
{
@@ -868,7 +874,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
868
874
fn simplify_discriminant ( & mut self , place : VnIndex ) -> Option < VnIndex > {
869
875
let enum_ty = self . ty ( place) ;
870
876
if enum_ty. is_enum ( )
871
- && let Value :: Aggregate ( variant, _) = * self . get ( place)
877
+ && let Value :: Aggregate ( variant, _) = self . get ( place)
872
878
{
873
879
let discr = self . ecx . discriminant_for_variant ( enum_ty, variant) . discard_err ( ) ?;
874
880
return Some ( self . insert_scalar ( discr. layout . ty , discr. to_scalar ( ) ) ) ;
@@ -904,12 +910,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
904
910
let Some ( & first_field) = fields. first ( ) else {
905
911
return None ;
906
912
} ;
907
- let Value :: Projection ( copy_from_value, _) = * self . get ( first_field) else {
913
+ let Value :: Projection ( copy_from_value, _) = self . get ( first_field) else {
908
914
return None ;
909
915
} ;
910
916
// All fields must correspond one-to-one and come from the same aggregate value.
911
917
if fields. iter ( ) . enumerate ( ) . any ( |( index, & v) | {
912
- if let Value :: Projection ( pointer, ProjectionElem :: Field ( from_index, _) ) = * self . get ( v)
918
+ if let Value :: Projection ( pointer, ProjectionElem :: Field ( from_index, _) ) = self . get ( v)
913
919
&& copy_from_value == pointer
914
920
&& from_index. index ( ) == index
915
921
{
@@ -921,7 +927,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
921
927
}
922
928
923
929
let mut copy_from_local_value = copy_from_value;
924
- if let Value :: Projection ( pointer, proj) = * self . get ( copy_from_value)
930
+ if let Value :: Projection ( pointer, proj) = self . get ( copy_from_value)
925
931
&& let ProjectionElem :: Downcast ( _, read_variant) = proj
926
932
{
927
933
if variant_index == read_variant {
@@ -979,13 +985,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
979
985
}
980
986
}
981
987
982
- let fields: Vec < _ > = field_ops
983
- . iter_mut ( )
984
- . map ( |op| {
985
- self . simplify_operand ( op, location)
986
- . unwrap_or_else ( || self . new_opaque ( op. ty ( self . local_decls , self . tcx ) ) )
987
- } )
988
- . collect ( ) ;
988
+ let fields = self . arena . alloc_from_iter ( field_ops. iter_mut ( ) . map ( |op| {
989
+ self . simplify_operand ( op, location)
990
+ . unwrap_or_else ( || self . new_opaque ( op. ty ( self . local_decls , self . tcx ) ) )
991
+ } ) ) ;
989
992
990
993
let variant_index = match * kind {
991
994
AggregateKind :: Array ( ..) | AggregateKind :: Tuple => {
@@ -1006,12 +1009,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1006
1009
let mut was_updated = false ;
1007
1010
while let Value :: Cast { kind : CastKind :: PtrToPtr , value : cast_value } =
1008
1011
self . get ( pointer)
1009
- && let ty:: RawPtr ( from_pointee_ty, from_mtbl) = self . ty ( * cast_value) . kind ( )
1012
+ && let ty:: RawPtr ( from_pointee_ty, from_mtbl) = self . ty ( cast_value) . kind ( )
1010
1013
&& let ty:: RawPtr ( _, output_mtbl) = ty. kind ( )
1011
1014
&& from_mtbl == output_mtbl
1012
1015
&& from_pointee_ty. is_sized ( self . tcx , self . typing_env ( ) )
1013
1016
{
1014
- pointer = * cast_value;
1017
+ pointer = cast_value;
1015
1018
was_updated = true ;
1016
1019
}
1017
1020
@@ -1069,9 +1072,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1069
1072
// To allow things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`,
1070
1073
// it's fine to get a projection as the type.
1071
1074
Value :: Cast { kind : CastKind :: PtrToPtr , value : inner }
1072
- if self . pointers_have_same_metadata ( self . ty ( * inner) , arg_ty) =>
1075
+ if self . pointers_have_same_metadata ( self . ty ( inner) , arg_ty) =>
1073
1076
{
1074
- arg_index = * inner;
1077
+ arg_index = inner;
1075
1078
was_updated = true ;
1076
1079
continue ;
1077
1080
}
@@ -1098,15 +1101,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1098
1101
}
1099
1102
1100
1103
let value = match ( op, self . get ( arg_index) ) {
1101
- ( UnOp :: Not , Value :: UnaryOp ( UnOp :: Not , inner) ) => return Some ( * inner) ,
1102
- ( UnOp :: Neg , Value :: UnaryOp ( UnOp :: Neg , inner) ) => return Some ( * inner) ,
1104
+ ( UnOp :: Not , Value :: UnaryOp ( UnOp :: Not , inner) ) => return Some ( inner) ,
1105
+ ( UnOp :: Neg , Value :: UnaryOp ( UnOp :: Neg , inner) ) => return Some ( inner) ,
1103
1106
( UnOp :: Not , Value :: BinaryOp ( BinOp :: Eq , lhs, rhs) ) => {
1104
- Value :: BinaryOp ( BinOp :: Ne , * lhs, * rhs)
1107
+ Value :: BinaryOp ( BinOp :: Ne , lhs, rhs)
1105
1108
}
1106
1109
( UnOp :: Not , Value :: BinaryOp ( BinOp :: Ne , lhs, rhs) ) => {
1107
- Value :: BinaryOp ( BinOp :: Eq , * lhs, * rhs)
1110
+ Value :: BinaryOp ( BinOp :: Eq , lhs, rhs)
1108
1111
}
1109
- ( UnOp :: PtrMetadata , Value :: RawPtr { metadata, .. } ) => return Some ( * metadata) ,
1112
+ ( UnOp :: PtrMetadata , Value :: RawPtr { metadata, .. } ) => return Some ( metadata) ,
1110
1113
// We have an unsizing cast, which assigns the length to wide pointer metadata.
1111
1114
(
1112
1115
UnOp :: PtrMetadata ,
@@ -1115,7 +1118,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1115
1118
value : inner,
1116
1119
} ,
1117
1120
) if let ty:: Slice ( ..) = arg_ty. builtin_deref ( true ) . unwrap ( ) . kind ( )
1118
- && let ty:: Array ( _, len) = self . ty ( * inner) . builtin_deref ( true ) . unwrap ( ) . kind ( ) =>
1121
+ && let ty:: Array ( _, len) = self . ty ( inner) . builtin_deref ( true ) . unwrap ( ) . kind ( ) =>
1119
1122
{
1120
1123
return Some ( self . insert_constant ( Const :: Ty ( self . tcx . types . usize , * len) ) ) ;
1121
1124
}
@@ -1148,12 +1151,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1148
1151
&& lhs_ty. is_any_ptr ( )
1149
1152
&& let Value :: Cast { kind : CastKind :: PtrToPtr , value : lhs_value } = self . get ( lhs)
1150
1153
&& let Value :: Cast { kind : CastKind :: PtrToPtr , value : rhs_value } = self . get ( rhs)
1151
- && let lhs_from = self . ty ( * lhs_value)
1152
- && lhs_from == self . ty ( * rhs_value)
1154
+ && let lhs_from = self . ty ( lhs_value)
1155
+ && lhs_from == self . ty ( rhs_value)
1153
1156
&& self . pointers_have_same_metadata ( lhs_from, lhs_ty)
1154
1157
{
1155
- lhs = * lhs_value;
1156
- rhs = * rhs_value;
1158
+ lhs = lhs_value;
1159
+ rhs = rhs_value;
1157
1160
if let Some ( lhs_op) = self . try_as_operand ( lhs, location)
1158
1161
&& let Some ( rhs_op) = self . try_as_operand ( rhs, location)
1159
1162
{
@@ -1287,7 +1290,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1287
1290
if op. is_overflowing ( ) {
1288
1291
let ty = Ty :: new_tup ( self . tcx , & [ self . ty ( result) , self . tcx . types . bool ] ) ;
1289
1292
let false_val = self . insert_bool ( false ) ;
1290
- Some ( self . insert_tuple ( ty, vec ! [ result, false_val] ) )
1293
+ Some ( self . insert_tuple ( ty, & [ result, false_val] ) )
1291
1294
} else {
1292
1295
Some ( result)
1293
1296
}
@@ -1340,11 +1343,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1340
1343
&& let ty:: RawPtr ( to_pointee, _) = to. kind ( )
1341
1344
&& to_pointee. is_sized ( self . tcx , self . typing_env ( ) )
1342
1345
{
1343
- from = self . ty ( * pointer) ;
1344
- value = * pointer;
1346
+ from = self . ty ( pointer) ;
1347
+ value = pointer;
1345
1348
was_updated_this_iteration = true ;
1346
1349
if from == to {
1347
- return Some ( * pointer) ;
1350
+ return Some ( pointer) ;
1348
1351
}
1349
1352
}
1350
1353
@@ -1353,7 +1356,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1353
1356
if let Transmute = kind
1354
1357
&& let Value :: Aggregate ( variant_idx, field_values) = self . get ( value)
1355
1358
&& let Some ( ( field_idx, field_ty) ) =
1356
- self . value_is_all_in_one_field ( from, * variant_idx)
1359
+ self . value_is_all_in_one_field ( from, variant_idx)
1357
1360
{
1358
1361
from = field_ty;
1359
1362
value = field_values[ field_idx. as_usize ( ) ] ;
@@ -1364,7 +1367,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1364
1367
}
1365
1368
1366
1369
// Various cast-then-cast cases can be simplified.
1367
- if let Value :: Cast { kind : inner_kind, value : inner_value } = * self . get ( value) {
1370
+ if let Value :: Cast { kind : inner_kind, value : inner_value } = self . get ( value) {
1368
1371
let inner_from = self . ty ( inner_value) ;
1369
1372
let new_kind = match ( inner_kind, kind) {
1370
1373
// Even if there's a narrowing cast in here that's fine, because
@@ -1438,7 +1441,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
1438
1441
// We have an unsizing cast, which assigns the length to wide pointer metadata.
1439
1442
if let Value :: Cast { kind, value : from } = self . get ( inner)
1440
1443
&& let CastKind :: PointerCoercion ( ty:: adjustment:: PointerCoercion :: Unsize , _) = kind
1441
- && let Some ( from) = self . ty ( * from) . builtin_deref ( true )
1444
+ && let Some ( from) = self . ty ( from) . builtin_deref ( true )
1442
1445
&& let ty:: Array ( _, len) = from. kind ( )
1443
1446
&& let Some ( to) = self . ty ( inner) . builtin_deref ( true )
1444
1447
&& let ty:: Slice ( ..) = to. kind ( )
@@ -1596,7 +1599,7 @@ fn op_to_prop_const<'tcx>(
1596
1599
None
1597
1600
}
1598
1601
1599
- impl < ' tcx > VnState < ' _ , ' tcx > {
1602
+ impl < ' tcx > VnState < ' _ , ' _ , ' tcx > {
1600
1603
/// If either [`Self::try_as_constant`] as [`Self::try_as_place`] succeeds,
1601
1604
/// returns that result as an [`Operand`].
1602
1605
fn try_as_operand ( & mut self , index : VnIndex , location : Location ) -> Option < Operand < ' tcx > > {
@@ -1615,7 +1618,7 @@ impl<'tcx> VnState<'_, 'tcx> {
1615
1618
// This was already constant in MIR, do not change it. If the constant is not
1616
1619
// deterministic, adding an additional mention of it in MIR will not give the same value as
1617
1620
// the former mention.
1618
- if let Value :: Constant { value, disambiguator : 0 } = * self . get ( index) {
1621
+ if let Value :: Constant { value, disambiguator : 0 } = self . get ( index) {
1619
1622
debug_assert ! ( value. is_deterministic( ) ) ;
1620
1623
return Some ( ConstOperand { span : DUMMY_SP , user_ty : None , const_ : value } ) ;
1621
1624
}
@@ -1654,7 +1657,7 @@ impl<'tcx> VnState<'_, 'tcx> {
1654
1657
let place =
1655
1658
Place { local, projection : self . tcx . mk_place_elems ( projection. as_slice ( ) ) } ;
1656
1659
return Some ( place) ;
1657
- } else if let Value :: Projection ( pointer, proj) = * self . get ( index)
1660
+ } else if let Value :: Projection ( pointer, proj) = self . get ( index)
1658
1661
&& ( allow_complex_projection || proj. is_stable_offset ( ) )
1659
1662
&& let Some ( proj) = self . try_as_place_elem ( self . ty ( index) , proj, loc)
1660
1663
{
@@ -1677,7 +1680,7 @@ impl<'tcx> VnState<'_, 'tcx> {
1677
1680
}
1678
1681
}
1679
1682
1680
- impl < ' tcx > MutVisitor < ' tcx > for VnState < ' _ , ' tcx > {
1683
+ impl < ' tcx > MutVisitor < ' tcx > for VnState < ' _ , ' _ , ' tcx > {
1681
1684
fn tcx ( & self ) -> TyCtxt < ' tcx > {
1682
1685
self . tcx
1683
1686
}
0 commit comments