@@ -12,6 +12,7 @@ use crate::panic_detail;
12
12
use crate :: pointer_id:: PointerTable ;
13
13
use crate :: type_desc:: { self , Ownership , Quantity , TypeDesc } ;
14
14
use crate :: util:: { ty_callee, Callee } ;
15
+ use log:: * ;
15
16
use rustc_ast:: Mutability ;
16
17
use rustc_middle:: mir:: {
17
18
BasicBlock , Body , Location , Operand , Place , Rvalue , Statement , StatementKind , Terminator ,
@@ -51,13 +52,24 @@ pub enum RewriteKind {
51
52
RemoveAsPtr ,
52
53
/// Replace &raw with & or &raw mut with &mut
53
54
RawToRef { mutbl : bool } ,
55
+
56
+ /// Cast `&T` to `*const T` or `&mut T` to `*mut T`.
57
+ CastRefToRaw { mutbl : bool } ,
58
+ /// Cast `*const T` to `*mut T` or vice versa. If `to_mutbl` is true, we are casting to
59
+ /// `*mut T`; otherwise, we're casting to `*const T`.
60
+ CastRawToRaw { to_mutbl : bool } ,
61
+ /// Cast `*const T` to `& T` or `*mut T` to `&mut T`.
62
+ UnsafeCastRawToRef { mutbl : bool } ,
63
+
54
64
/// Replace `y` in `let x = y` with `Cell::new(y)`, i.e. `let x = Cell::new(y)`
55
65
/// TODO: ensure `y` implements `Copy`
56
66
CellNew ,
57
67
/// Replace `*y` with `Cell::get(y)` where `y` is a pointer
58
68
CellGet ,
59
69
/// Replace `*y = x` with `Cell::set(x)` where `y` is a pointer
60
70
CellSet ,
71
+ /// Wrap `&mut T` in `Cell::from_mut` to get `&Cell<T>`.
72
+ CellFromMut ,
61
73
}
62
74
63
75
#[ derive( Clone , PartialEq , Eq , Debug ) ]
@@ -257,11 +269,9 @@ impl<'a, 'tcx> ExprRewriteVisitor<'a, 'tcx> {
257
269
match ty_callee ( tcx, func_ty) {
258
270
Callee :: PtrOffset { .. } => {
259
271
self . visit_ptr_offset ( & args[ 0 ] , pl_ty) ;
260
- return ;
261
272
}
262
273
Callee :: SliceAsPtr { elem_ty, .. } => {
263
274
self . visit_slice_as_ptr ( elem_ty, & args[ 0 ] , pl_ty) ;
264
- return ;
265
275
}
266
276
_ => { }
267
277
}
@@ -424,10 +434,9 @@ impl<'a, 'tcx> ExprRewriteVisitor<'a, 'tcx> {
424
434
425
435
self . emit ( RewriteKind :: OffsetSlice { mutbl } ) ;
426
436
427
- // If the result is `Single`, also insert an upcast.
428
- if result_desc. qty == Quantity :: Single {
429
- self . emit ( RewriteKind :: SliceFirst { mutbl } ) ;
430
- }
437
+ // The `OffsetSlice` operation returns something of the same type as its input. Afterward,
438
+ // we must cast the result to the `result_ty`/`result_desc`.
439
+ self . emit_cast_desc_desc ( arg_expect_desc, result_desc) ;
431
440
}
432
441
433
442
fn visit_slice_as_ptr ( & mut self , elem_ty : Ty < ' tcx > , op : & Operand < ' tcx > , result_lty : LTy < ' tcx > ) {
@@ -468,38 +477,172 @@ impl<'a, 'tcx> ExprRewriteVisitor<'a, 'tcx> {
468
477
}
469
478
470
479
fn emit_cast_desc_desc ( & mut self , from : TypeDesc < ' tcx > , to : TypeDesc < ' tcx > ) {
480
+ let orig_from = from;
481
+ let mut from = orig_from;
482
+
483
+ // The `from` and `to` pointee types should only differ in their lifetimes.
471
484
assert_eq ! (
472
485
self . acx. tcx( ) . erase_regions( from. pointee_ty) ,
473
486
self . acx. tcx( ) . erase_regions( to. pointee_ty) ,
474
487
) ;
488
+ // There might still be differences in lifetimes, which we don't care about here.
489
+ // Overwriting `from.pointee_ty` allows the final `from == to` check to succeed below.
490
+ from. pointee_ty = to. pointee_ty ;
475
491
476
492
if from == to {
477
493
return ;
478
494
}
479
495
480
- let orig_from = from;
481
- let mut from = orig_from;
496
+ // Early `Ownership` casts. We do certain casts here in hopes of reaching an `Ownership`
497
+ // on which we can safely adjust `Quantity`.
498
+ from. own = self . cast_ownership ( from, to, true ) ;
499
+
500
+ // Safe casts that change `Quantity`.
501
+ while from. qty != to. qty {
502
+ // Mutability of `from`. `None` here means that safe `Quantity` conversions aren't
503
+ // possible given `from`'s `Ownership`. For example, we can't convert `Box<[T]>` to
504
+ // `Box<T>`.
505
+ let opt_mutbl = match from. own {
506
+ // Note that `Cell` + `Slice` is `&[Cell<T>]`, not `&Cell<[T]>`, so it can be
507
+ // handled like any other `&[_]`.
508
+ Ownership :: Imm | Ownership :: Cell => Some ( false ) ,
509
+ Ownership :: Mut => Some ( true ) ,
510
+ _ => None ,
511
+ } ;
512
+ match ( from. qty , to. qty ) {
513
+ ( Quantity :: Array , _) => {
514
+ // `Array` goes only to `Slice` directly. All other `Array` conversions go
515
+ // through `Slice` first.
516
+ error ! ( "TODO: cast Array to {:?}" , to. qty) ;
517
+ from. qty = Quantity :: Slice ;
518
+ }
519
+ // Bidirectional conversions between `Slice` and `OffsetPtr`.
520
+ ( Quantity :: Slice , Quantity :: OffsetPtr ) | ( Quantity :: OffsetPtr , Quantity :: Slice ) => {
521
+ // Currently a no-op, since `Slice` and `OffsetPtr` are identical.
522
+ from. qty = to. qty ;
523
+ }
524
+ // `Slice` and `OffsetPtr` convert to `Single` the same way.
525
+ // TODO: when converting to `Ownership::Raw`/`RawMut`, use `slice.as_ptr()` to
526
+ // avoid panic on 0-length inputs
527
+ ( _, Quantity :: Single ) => {
528
+ let rw = match opt_mutbl {
529
+ Some ( mutbl) => RewriteKind :: SliceFirst { mutbl } ,
530
+ None => break ,
531
+ } ;
532
+ self . emit ( rw) ;
533
+ from. qty = Quantity :: Single ;
534
+ }
482
535
483
- if ( from. qty , to. qty ) == ( Quantity :: OffsetPtr , Quantity :: Slice ) {
484
- // TODO: emit rewrite
485
- from. qty = to. qty ;
486
- }
536
+ // Unsupported cases
537
+ ( Quantity :: Single , _) => break ,
538
+ ( _, Quantity :: Array ) => break ,
487
539
488
- if from. qty == to. qty && ( from. own , to. own ) == ( Ownership :: Mut , Ownership :: Imm ) {
489
- self . emit ( RewriteKind :: MutToImm ) ;
490
- from. own = to. own ;
540
+ // Remaining cases are impossible, since `from.qty != to.qty`.
541
+ ( Quantity :: Slice , Quantity :: Slice ) | ( Quantity :: OffsetPtr , Quantity :: OffsetPtr ) => {
542
+ unreachable ! ( )
543
+ }
544
+ }
491
545
}
492
546
493
- // TODO: handle Slice -> Single here instead of special-casing in `offset`
547
+ // Late `Ownership` casts.
548
+ from. own = self . cast_ownership ( from, to, false ) ;
494
549
495
550
if from != to {
496
- eprintln ! (
551
+ panic ! (
497
552
"unsupported cast kind: {:?} -> {:?} (original input: {:?})" ,
498
553
from, to, orig_from
499
554
) ;
500
555
}
501
556
}
502
557
558
+ fn cast_ownership ( & mut self , from : TypeDesc , to : TypeDesc , early : bool ) -> Ownership {
559
+ let mut from = from;
560
+ while from. own != to. own {
561
+ match self . cast_ownership_one_step ( from, to, early) {
562
+ Some ( new_own) => {
563
+ from. own = new_own;
564
+ }
565
+ None => break ,
566
+ }
567
+ }
568
+ from. own
569
+ }
570
+
571
+ fn cast_ownership_one_step (
572
+ & mut self ,
573
+ from : TypeDesc ,
574
+ to : TypeDesc ,
575
+ early : bool ,
576
+ ) -> Option < Ownership > {
577
+ match from. own {
578
+ Ownership :: Box => match to. own {
579
+ Ownership :: Raw | Ownership :: Imm => {
580
+ error ! ( "TODO: cast Box to Imm" ) ;
581
+ Some ( Ownership :: Imm )
582
+ }
583
+ Ownership :: RawMut | Ownership :: Mut => {
584
+ error ! ( "TODO: cast Box to Mut" ) ;
585
+ Some ( Ownership :: Mut )
586
+ }
587
+ _ => None ,
588
+ } ,
589
+ Ownership :: Rc => match to. own {
590
+ Ownership :: Imm | Ownership :: Raw | Ownership :: RawMut => {
591
+ error ! ( "TODO: cast Rc to Imm" ) ;
592
+ Some ( Ownership :: Imm )
593
+ }
594
+ _ => None ,
595
+ } ,
596
+ Ownership :: Mut => match to. own {
597
+ Ownership :: Imm | Ownership :: Raw => {
598
+ self . emit ( RewriteKind :: MutToImm ) ;
599
+ Some ( Ownership :: Imm )
600
+ }
601
+ Ownership :: Cell => {
602
+ self . emit ( RewriteKind :: CellFromMut ) ;
603
+ Some ( Ownership :: Cell )
604
+ }
605
+ Ownership :: RawMut if !early => {
606
+ self . emit ( RewriteKind :: CastRefToRaw { mutbl : true } ) ;
607
+ Some ( Ownership :: RawMut )
608
+ }
609
+ _ => None ,
610
+ } ,
611
+ Ownership :: Cell => None ,
612
+ Ownership :: Imm => match to. own {
613
+ Ownership :: Raw | Ownership :: RawMut if !early => {
614
+ self . emit ( RewriteKind :: CastRefToRaw { mutbl : false } ) ;
615
+ Some ( Ownership :: Raw )
616
+ }
617
+ _ => None ,
618
+ } ,
619
+ Ownership :: RawMut => match to. own {
620
+ // For `RawMut` to `Imm`, we go through `Raw` instead of through `Mut` because
621
+ // `&mut` adds more implicit constraints under the Rust memory model.
622
+ Ownership :: Raw | Ownership :: Imm if !early => {
623
+ self . emit ( RewriteKind :: CastRawToRaw { to_mutbl : false } ) ;
624
+ Some ( Ownership :: Raw )
625
+ }
626
+ Ownership :: Mut if !early => {
627
+ self . emit ( RewriteKind :: UnsafeCastRawToRef { mutbl : true } ) ;
628
+ Some ( Ownership :: Mut )
629
+ }
630
+ _ => None ,
631
+ } ,
632
+ Ownership :: Raw => match to. own {
633
+ Ownership :: RawMut | Ownership :: Mut if !early => {
634
+ self . emit ( RewriteKind :: CastRawToRaw { to_mutbl : true } ) ;
635
+ Some ( Ownership :: RawMut )
636
+ }
637
+ Ownership :: Imm if !early => {
638
+ self . emit ( RewriteKind :: UnsafeCastRawToRef { mutbl : false } ) ;
639
+ Some ( Ownership :: Imm )
640
+ }
641
+ _ => None ,
642
+ } ,
643
+ }
644
+ }
645
+
503
646
fn emit_cast_lty_desc ( & mut self , from_lty : LTy < ' tcx > , to : TypeDesc < ' tcx > ) {
504
647
let from = type_desc:: perms_to_desc_with_pointee (
505
648
self . acx . tcx ( ) ,
0 commit comments