@@ -12,7 +12,7 @@ use rustc_middle::mir::interpret::Scalar;
12
12
use rustc_middle:: ty:: SubstsRef ;
13
13
use rustc_middle:: ty:: { self , EarlyBinder , FloatTy , ScalarInt , Ty , TyCtxt } ;
14
14
use rustc_middle:: { bug, span_bug} ;
15
- use rustc_span:: symbol:: Symbol ;
15
+ use rustc_span:: symbol:: { Ident , Symbol } ;
16
16
use std:: cmp:: Ordering :: { self , Equal } ;
17
17
use std:: hash:: { Hash , Hasher } ;
18
18
use std:: iter;
@@ -239,7 +239,7 @@ pub fn constant<'tcx>(
239
239
needed_resolution : false ,
240
240
substs : ty:: List :: empty ( ) ,
241
241
} ;
242
- cx. expr ( e) . map ( |cst| ( cst, cx. needed_resolution ) )
242
+ cx. expr ( e, None ) . map ( |cst| ( cst, cx. needed_resolution ) )
243
243
}
244
244
245
245
pub fn constant_simple < ' tcx > (
@@ -320,9 +320,9 @@ pub struct ConstEvalLateContext<'a, 'tcx> {
320
320
321
321
impl < ' a , ' tcx > ConstEvalLateContext < ' a , ' tcx > {
322
322
/// Simple constant folding: Insert an expression, get a constant or none.
323
- pub fn expr ( & mut self , e : & Expr < ' _ > ) -> Option < Constant > {
323
+ pub fn expr ( & mut self , e : & Expr < ' _ > , field : Option < Ident > ) -> Option < Constant > {
324
324
match e. kind {
325
- ExprKind :: Path ( ref qpath) => self . fetch_path ( qpath, e. hir_id , self . typeck_results . expr_ty ( e) ) ,
325
+ ExprKind :: Path ( ref qpath) => self . fetch_path ( qpath, e. hir_id , self . typeck_results . expr_ty ( e) , field ) ,
326
326
ExprKind :: Block ( block, _) => self . block ( block) ,
327
327
ExprKind :: Lit ( lit) => {
328
328
if is_direct_expn_of ( e. span , "cfg" ) . is_some ( ) {
@@ -338,9 +338,9 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
338
338
ty:: Array ( _, n) => n. try_eval_target_usize ( self . lcx . tcx , self . lcx . param_env ) ?,
339
339
_ => span_bug ! ( e. span, "typeck error" ) ,
340
340
} ;
341
- self . expr ( value) . map ( |v| Constant :: Repeat ( Box :: new ( v) , n) )
341
+ self . expr ( value, None ) . map ( |v| Constant :: Repeat ( Box :: new ( v) , n) )
342
342
} ,
343
- ExprKind :: Unary ( op, operand) => self . expr ( operand) . and_then ( |o| match op {
343
+ ExprKind :: Unary ( op, operand) => self . expr ( operand, None ) . and_then ( |o| match op {
344
344
UnOp :: Not => self . constant_not ( & o, self . typeck_results . expr_ty ( e) ) ,
345
345
UnOp :: Neg => self . constant_negate ( & o, self . typeck_results . expr_ty ( e) ) ,
346
346
UnOp :: Deref => Some ( if let Constant :: Ref ( r) = o { * r } else { o } ) ,
@@ -373,8 +373,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
373
373
}
374
374
} ,
375
375
ExprKind :: Index ( arr, index) => self . index ( arr, index) ,
376
- ExprKind :: AddrOf ( _, _, inner) => self . expr ( inner) . map ( |r| Constant :: Ref ( Box :: new ( r) ) ) ,
377
- // TODO: add other expressions.
376
+ ExprKind :: AddrOf ( _, _, inner) => self . expr ( inner, None ) . map ( |r| Constant :: Ref ( Box :: new ( r) ) ) ,
377
+ ExprKind :: Field ( local_expr , field ) => self . expr ( local_expr , Some ( field ) ) ,
378
378
_ => None ,
379
379
}
380
380
}
@@ -416,27 +416,24 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
416
416
/// Create `Some(Vec![..])` of all constants, unless there is any
417
417
/// non-constant part.
418
418
fn multi ( & mut self , vec : & [ Expr < ' _ > ] ) -> Option < Vec < Constant > > {
419
- vec. iter ( ) . map ( |elem| self . expr ( elem) ) . collect :: < Option < _ > > ( )
419
+ vec. iter ( ) . map ( |elem| self . expr ( elem, None ) ) . collect :: < Option < _ > > ( )
420
420
}
421
421
422
422
/// Lookup a possibly constant expression from an `ExprKind::Path`.
423
- fn fetch_path ( & mut self , qpath : & QPath < ' _ > , id : HirId , ty : Ty < ' tcx > ) -> Option < Constant > {
423
+ fn fetch_path ( & mut self , qpath : & QPath < ' _ > , id : HirId , ty : Ty < ' tcx > , field : Option < Ident > ) -> Option < Constant > {
424
424
let res = self . typeck_results . qpath_res ( qpath, id) ;
425
425
match res {
426
426
Res :: Def ( DefKind :: Const | DefKind :: AssocConst , def_id) => {
427
427
// Check if this constant is based on `cfg!(..)`,
428
428
// which is NOT constant for our purposes.
429
- if let Some ( node) = self . lcx . tcx . hir ( ) . get_if_local ( def_id) &&
430
- let Node :: Item ( & Item {
431
- kind : ItemKind :: Const ( _, body_id) ,
432
- ..
433
- } ) = node &&
434
- let Node :: Expr ( & Expr {
435
- kind : ExprKind :: Lit ( _) ,
436
- span,
437
- ..
438
- } ) = self . lcx . tcx . hir ( ) . get ( body_id. hir_id ) &&
439
- is_direct_expn_of ( span, "cfg" ) . is_some ( ) {
429
+ if let Some ( node) = self . lcx . tcx . hir ( ) . get_if_local ( def_id)
430
+ && let Node :: Item ( Item { kind : ItemKind :: Const ( _, body_id) , .. } ) = node
431
+ && let Node :: Expr ( Expr { kind : ExprKind :: Lit ( _) , span, .. } ) = self . lcx
432
+ . tcx
433
+ . hir ( )
434
+ . get ( body_id. hir_id )
435
+ && is_direct_expn_of ( * span, "cfg" ) . is_some ( )
436
+ {
440
437
return None ;
441
438
}
442
439
@@ -446,27 +443,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
446
443
} else {
447
444
EarlyBinder ( substs) . subst ( self . lcx . tcx , self . substs )
448
445
} ;
449
-
450
446
let result = self
451
447
. lcx
452
448
. tcx
453
449
. const_eval_resolve ( self . param_env , mir:: UnevaluatedConst :: new ( def_id, substs) , None )
454
450
. ok ( )
455
451
. map ( |val| rustc_middle:: mir:: ConstantKind :: from_value ( val, ty) ) ?;
456
- let result = miri_to_const ( self . lcx . tcx , result) ;
452
+ let result = miri_to_const ( self . lcx , result, field ) ;
457
453
if result. is_some ( ) {
458
454
self . needed_resolution = true ;
459
455
}
460
456
result
461
457
} ,
462
- // FIXME: cover all usable cases.
463
458
_ => None ,
464
459
}
465
460
}
466
461
467
462
fn index ( & mut self , lhs : & ' _ Expr < ' _ > , index : & ' _ Expr < ' _ > ) -> Option < Constant > {
468
- let lhs = self . expr ( lhs) ;
469
- let index = self . expr ( index) ;
463
+ let lhs = self . expr ( lhs, None ) ;
464
+ let index = self . expr ( index, None ) ;
470
465
471
466
match ( lhs, index) {
472
467
( Some ( Constant :: Vec ( vec) ) , Some ( Constant :: Int ( index) ) ) => match vec. get ( index as usize ) {
@@ -492,27 +487,27 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
492
487
/// A block can only yield a constant if it only has one constant expression.
493
488
fn block ( & mut self , block : & Block < ' _ > ) -> Option < Constant > {
494
489
if block. stmts . is_empty ( ) {
495
- block. expr . as_ref ( ) . and_then ( |b| self . expr ( b) )
490
+ block. expr . as_ref ( ) . and_then ( |b| self . expr ( b, None ) )
496
491
} else {
497
492
None
498
493
}
499
494
}
500
495
501
496
fn ifthenelse ( & mut self , cond : & Expr < ' _ > , then : & Expr < ' _ > , otherwise : Option < & Expr < ' _ > > ) -> Option < Constant > {
502
- if let Some ( Constant :: Bool ( b) ) = self . expr ( cond) {
497
+ if let Some ( Constant :: Bool ( b) ) = self . expr ( cond, None ) {
503
498
if b {
504
- self . expr ( then)
499
+ self . expr ( then, None )
505
500
} else {
506
- otherwise. as_ref ( ) . and_then ( |expr| self . expr ( expr) )
501
+ otherwise. as_ref ( ) . and_then ( |expr| self . expr ( expr, None ) )
507
502
}
508
503
} else {
509
504
None
510
505
}
511
506
}
512
507
513
508
fn binop ( & mut self , op : BinOp , left : & Expr < ' _ > , right : & Expr < ' _ > ) -> Option < Constant > {
514
- let l = self . expr ( left) ?;
515
- let r = self . expr ( right) ;
509
+ let l = self . expr ( left, None ) ?;
510
+ let r = self . expr ( right, None ) ;
516
511
match ( l, r) {
517
512
( Constant :: Int ( l) , Some ( Constant :: Int ( r) ) ) => match * self . typeck_results . expr_ty_opt ( left) ?. kind ( ) {
518
513
ty:: Int ( ity) => {
@@ -603,23 +598,29 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
603
598
}
604
599
}
605
600
606
- pub fn miri_to_const < ' tcx > ( tcx : TyCtxt < ' tcx > , result : mir:: ConstantKind < ' tcx > ) -> Option < Constant > {
601
+ pub fn miri_to_const < ' tcx > (
602
+ lcx : & LateContext < ' tcx > ,
603
+ result : mir:: ConstantKind < ' tcx > ,
604
+ field : Option < Ident > ,
605
+ ) -> Option < Constant > {
607
606
use rustc_middle:: mir:: interpret:: ConstValue ;
608
607
match result {
609
- mir:: ConstantKind :: Val ( ConstValue :: Scalar ( Scalar :: Int ( int) ) , _) => {
610
- match result. ty ( ) . kind ( ) {
611
- ty:: Bool => Some ( Constant :: Bool ( int == ScalarInt :: TRUE ) ) ,
612
- ty:: Uint ( _) | ty:: Int ( _) => Some ( Constant :: Int ( int. assert_bits ( int. size ( ) ) ) ) ,
613
- ty:: Float ( FloatTy :: F32 ) => Some ( Constant :: F32 ( f32:: from_bits (
614
- int. try_into ( ) . expect ( "invalid f32 bit representation" ) ,
615
- ) ) ) ,
616
- ty:: Float ( FloatTy :: F64 ) => Some ( Constant :: F64 ( f64:: from_bits (
617
- int. try_into ( ) . expect ( "invalid f64 bit representation" ) ,
618
- ) ) ) ,
619
- ty:: RawPtr ( _) => Some ( Constant :: RawPtr ( int. assert_bits ( int. size ( ) ) ) ) ,
620
- // FIXME: implement other conversions.
621
- _ => None ,
622
- }
608
+ mir:: ConstantKind :: Val ( ConstValue :: Scalar ( Scalar :: Int ( int) ) , _) => match result. ty ( ) . kind ( ) {
609
+ ty:: Adt ( adt_def, _) if adt_def. is_struct ( ) => {
610
+ let dc = lcx. tcx . destructure_mir_constant ( lcx. param_env , result) ;
611
+ let & [ field] = dc. fields else { return None ; } ;
612
+ miri_to_const ( lcx, field, None )
613
+ } ,
614
+ ty:: Bool => Some ( Constant :: Bool ( int == ScalarInt :: TRUE ) ) ,
615
+ ty:: Uint ( _) | ty:: Int ( _) => Some ( Constant :: Int ( int. assert_bits ( int. size ( ) ) ) ) ,
616
+ ty:: Float ( FloatTy :: F32 ) => Some ( Constant :: F32 ( f32:: from_bits (
617
+ int. try_into ( ) . expect ( "invalid f32 bit representation" ) ,
618
+ ) ) ) ,
619
+ ty:: Float ( FloatTy :: F64 ) => Some ( Constant :: F64 ( f64:: from_bits (
620
+ int. try_into ( ) . expect ( "invalid f64 bit representation" ) ,
621
+ ) ) ) ,
622
+ ty:: RawPtr ( _) => Some ( Constant :: RawPtr ( int. assert_bits ( int. size ( ) ) ) ) ,
623
+ _ => None ,
623
624
} ,
624
625
mir:: ConstantKind :: Val ( ConstValue :: Slice { data, start, end } , _) => match result. ty ( ) . kind ( ) {
625
626
ty:: Ref ( _, tam, _) => match tam. kind ( ) {
@@ -635,8 +636,22 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
635
636
_ => None ,
636
637
} ,
637
638
mir:: ConstantKind :: Val ( ConstValue :: ByRef { alloc, offset : _ } , _) => match result. ty ( ) . kind ( ) {
639
+ ty:: Adt ( adt_def, _) if adt_def. is_struct ( ) => {
640
+ let dc = lcx. tcx . destructure_mir_constant ( lcx. param_env , result) ;
641
+ if let Some ( dc_variant) = dc. variant
642
+ && let Some ( local_field) = field
643
+ && let Some ( variant) = & adt_def. variants ( ) . get ( dc_variant)
644
+ && let Some ( field_idx) = variant. fields . iter ( ) . position ( |el| el. name == local_field. name )
645
+ && let Some ( dc_field) = dc. fields . get ( field_idx)
646
+ {
647
+ miri_to_const ( lcx, * dc_field, None )
648
+ }
649
+ else {
650
+ None
651
+ }
652
+ } ,
638
653
ty:: Array ( sub_type, len) => match sub_type. kind ( ) {
639
- ty:: Float ( FloatTy :: F32 ) => match len. kind ( ) . try_to_target_usize ( tcx) {
654
+ ty:: Float ( FloatTy :: F32 ) => match len. kind ( ) . try_to_target_usize ( lcx . tcx ) {
640
655
Some ( len) => alloc
641
656
. inner ( )
642
657
. inspect_with_uninit_and_ptr_outside_interpreter ( 0 ..( 4 * usize:: try_from ( len) . unwrap ( ) ) )
@@ -647,7 +662,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
647
662
. map ( Constant :: Vec ) ,
648
663
_ => None ,
649
664
} ,
650
- ty:: Float ( FloatTy :: F64 ) => match len. kind ( ) . try_to_target_usize ( tcx) {
665
+ ty:: Float ( FloatTy :: F64 ) => match len. kind ( ) . try_to_target_usize ( lcx . tcx ) {
651
666
Some ( len) => alloc
652
667
. inner ( )
653
668
. inspect_with_uninit_and_ptr_outside_interpreter ( 0 ..( 8 * usize:: try_from ( len) . unwrap ( ) ) )
@@ -658,12 +673,10 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
658
673
. map ( Constant :: Vec ) ,
659
674
_ => None ,
660
675
} ,
661
- // FIXME: implement other array type conversions.
662
676
_ => None ,
663
677
} ,
664
678
_ => None ,
665
679
} ,
666
- // FIXME: implement other conversions.
667
680
_ => None ,
668
681
}
669
682
}
0 commit comments