56
56
use rustc_const_eval:: interpret:: { ImmTy , InterpCx , MemPlaceMeta , OpTy , Projectable , Scalar } ;
57
57
use rustc_data_structures:: fx:: { FxHashMap , FxIndexSet } ;
58
58
use rustc_data_structures:: graph:: dominators:: Dominators ;
59
+ use rustc_hir:: def:: DefKind ;
59
60
use rustc_index:: bit_set:: BitSet ;
60
61
use rustc_index:: IndexVec ;
61
62
use rustc_macros:: newtype_index;
@@ -64,6 +65,7 @@ use rustc_middle::mir::visit::*;
64
65
use rustc_middle:: mir:: * ;
65
66
use rustc_middle:: ty:: layout:: LayoutOf ;
66
67
use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeAndMut } ;
68
+ use rustc_span:: def_id:: DefId ;
67
69
use rustc_span:: DUMMY_SP ;
68
70
use rustc_target:: abi:: { self , Abi , Size , VariantIdx , FIRST_VARIANT } ;
69
71
use std:: borrow:: Cow ;
@@ -136,6 +138,16 @@ newtype_index! {
136
138
struct VnIndex { }
137
139
}
138
140
141
+ /// Computing the aggregate's type can be quite slow, so we only keep the minimal amount of
142
+ /// information to reconstruct it when needed.
143
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
144
+ enum AggregateTy < ' tcx > {
145
+ /// Invariant: this must not be used for an empty array.
146
+ Array ,
147
+ Tuple ,
148
+ Def ( DefId , ty:: GenericArgsRef < ' tcx > ) ,
149
+ }
150
+
139
151
#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
140
152
enum AddressKind {
141
153
Ref ( BorrowKind ) ,
@@ -152,7 +164,7 @@ enum Value<'tcx> {
152
164
Constant ( Const < ' tcx > ) ,
153
165
/// An aggregate value, either tuple/closure/struct/enum.
154
166
/// This does not contain unions, as we cannot reason with the value.
155
- Aggregate ( Ty < ' tcx > , VariantIdx , Vec < VnIndex > ) ,
167
+ Aggregate ( AggregateTy < ' tcx > , VariantIdx , Vec < VnIndex > ) ,
156
168
/// This corresponds to a `[value; count]` expression.
157
169
Repeat ( VnIndex , ty:: Const < ' tcx > ) ,
158
170
/// The address of a place.
@@ -289,11 +301,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
289
301
Repeat ( ..) => return None ,
290
302
291
303
Constant ( ref constant) => self . ecx . eval_mir_constant ( constant, None , None ) . ok ( ) ?,
292
- Aggregate ( ty , variant, ref fields) => {
304
+ Aggregate ( kind , variant, ref fields) => {
293
305
let fields = fields
294
306
. iter ( )
295
307
. map ( |& f| self . evaluated [ f] . as_ref ( ) )
296
308
. collect :: < Option < Vec < _ > > > ( ) ?;
309
+ let ty = match kind {
310
+ AggregateTy :: Array => {
311
+ assert ! ( fields. len( ) > 0 ) ;
312
+ Ty :: new_array ( self . tcx , fields[ 0 ] . layout . ty , fields. len ( ) as u64 )
313
+ }
314
+ AggregateTy :: Tuple => {
315
+ Ty :: new_tup_from_iter ( self . tcx , fields. iter ( ) . map ( |f| f. layout . ty ) )
316
+ }
317
+ AggregateTy :: Def ( def_id, args) => {
318
+ self . tcx . type_of ( def_id) . instantiate ( self . tcx , args)
319
+ }
320
+ } ;
297
321
let variant = if ty. is_enum ( ) { Some ( variant) } else { None } ;
298
322
let ty = self . ecx . layout_of ( ty) . ok ( ) ?;
299
323
if ty. is_zst ( ) {
@@ -510,7 +534,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
510
534
Value :: Repeat ( inner, _) => {
511
535
return Some ( * inner) ;
512
536
}
513
- Value :: Aggregate ( ty , _, operands) if ty . is_array ( ) => {
537
+ Value :: Aggregate ( AggregateTy :: Array , _, operands) => {
514
538
let offset = if from_end {
515
539
operands. len ( ) - offset as usize
516
540
} else {
@@ -659,20 +683,30 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
659
683
}
660
684
Rvalue :: NullaryOp ( op, ty) => Value :: NullaryOp ( op, ty) ,
661
685
Rvalue :: Aggregate ( box ref kind, ref mut fields) => {
662
- let variant_index = match * kind {
663
- AggregateKind :: Array ( ..)
664
- | AggregateKind :: Tuple
665
- | AggregateKind :: Closure ( ..)
666
- | AggregateKind :: Generator ( ..) => FIRST_VARIANT ,
667
- AggregateKind :: Adt ( _, variant_index, _, _, None ) => variant_index,
686
+ let ( ty, variant_index) = match * kind {
687
+ // For empty arrays, we have not mean to recover the type. They are ZSTs
688
+ // anyway, so return them as such.
689
+ AggregateKind :: Array ( ..) | AggregateKind :: Tuple if fields. is_empty ( ) => {
690
+ return Some ( self . insert ( Value :: Constant ( Const :: zero_sized (
691
+ rvalue. ty ( self . local_decls , self . tcx ) ,
692
+ ) ) ) ) ;
693
+ }
694
+ AggregateKind :: Array ( ..) => ( AggregateTy :: Array , FIRST_VARIANT ) ,
695
+ AggregateKind :: Tuple => ( AggregateTy :: Tuple , FIRST_VARIANT ) ,
696
+ AggregateKind :: Closure ( did, substs)
697
+ | AggregateKind :: Generator ( did, substs, _) => {
698
+ ( AggregateTy :: Def ( did, substs) , FIRST_VARIANT )
699
+ }
700
+ AggregateKind :: Adt ( did, variant_index, substs, _, None ) => {
701
+ ( AggregateTy :: Def ( did, substs) , variant_index)
702
+ }
668
703
// Do not track unions.
669
704
AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
670
705
} ;
671
706
let fields: Option < Vec < _ > > = fields
672
707
. iter_mut ( )
673
708
. map ( |op| self . simplify_operand ( op, location) . or_else ( || self . new_opaque ( ) ) )
674
709
. collect ( ) ;
675
- let ty = rvalue. ty ( self . local_decls , self . tcx ) ;
676
710
Value :: Aggregate ( ty, variant_index, fields?)
677
711
}
678
712
Rvalue :: Ref ( _, borrow_kind, ref mut place) => {
@@ -725,8 +759,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
725
759
726
760
fn simplify_discriminant ( & mut self , place : VnIndex ) -> Option < VnIndex > {
727
761
if let Value :: Aggregate ( enum_ty, variant, _) = * self . get ( place)
728
- && enum_ty. is_enum ( )
762
+ && let AggregateTy :: Def ( enum_did, enum_substs) = enum_ty
763
+ && let DefKind :: Enum = self . tcx . def_kind ( enum_did)
729
764
{
765
+ let enum_ty = self . tcx . type_of ( enum_did) . instantiate ( self . tcx , enum_substs) ;
730
766
let discr = self . ecx . discriminant_for_variant ( enum_ty, variant) . ok ( ) ?;
731
767
return Some ( self . insert_scalar ( discr. to_scalar ( ) , discr. layout . ty ) ) ;
732
768
}
0 commit comments