@@ -509,32 +509,183 @@ impl<T> MaybeUninit<T> {
509
509
self . as_ptr ( ) . read ( )
510
510
}
511
511
512
- /// Gets a reference to the contained value.
512
+ /// Gets a shared reference to the contained value.
513
+ ///
514
+ /// This can be useful when we want to access a `MaybeUninit` that has been
515
+ /// initialized but don't have ownership of the `MaybeUninit` (preventing the use
516
+ /// of `.assume_init()`).
513
517
///
514
518
/// # Safety
515
519
///
516
- /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
517
- /// state. Calling this when the content is not yet fully initialized causes undefined
518
- /// behavior.
520
+ /// Calling this when the content is not yet fully initialized causes undefined
521
+ /// behavior: it is up to the caller to guarantee that the `MaybeUninit<T>` really
522
+ /// is in an initialized state.
523
+ ///
524
+ /// # Examples
525
+ ///
526
+ /// ### Correct usage of this method:
527
+ ///
528
+ /// ```rust
529
+ /// #![feature(maybe_uninit_ref)]
530
+ /// use std::mem::MaybeUninit;
531
+ ///
532
+ /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
533
+ /// // Initialize `x`:
534
+ /// unsafe { x.as_mut_ptr().write(vec![1, 2, 3]); }
535
+ /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to
536
+ /// // create a shared reference to it:
537
+ /// let x: &Vec<u32> = unsafe {
538
+ /// // Safety: `x` has been initialized.
539
+ /// x.get_ref()
540
+ /// };
541
+ /// assert_eq!(x, &vec![1, 2, 3]);
542
+ /// ```
543
+ ///
544
+ /// ### *Incorrect* usages of this method:
545
+ ///
546
+ /// ```rust,no_run
547
+ /// #![feature(maybe_uninit_ref)]
548
+ /// use std::mem::MaybeUninit;
549
+ ///
550
+ /// let x = MaybeUninit::<Vec<u32>>::uninit();
551
+ /// let x_vec: &Vec<u32> = unsafe { x.get_ref() };
552
+ /// // We have created a reference to an uninitialized vector! This is undefined behavior.
553
+ /// ```
554
+ ///
555
+ /// ```rust,no_run
556
+ /// #![feature(maybe_uninit_ref)]
557
+ /// use std::{cell::Cell, mem::MaybeUninit};
558
+ ///
559
+ /// let b = MaybeUninit::<Cell<bool>>::uninit();
560
+ /// // Initialize the `MaybeUninit` using `Cell::set`:
561
+ /// unsafe {
562
+ /// b.get_ref().set(true);
563
+ /// // ^^^^^^^^^^^
564
+ /// // Reference to an uninitialized `Cell<bool>`: UB!
565
+ /// }
566
+ /// ```
519
567
#[ unstable( feature = "maybe_uninit_ref" , issue = "63568" ) ]
520
568
#[ inline( always) ]
521
569
pub unsafe fn get_ref ( & self ) -> & T {
570
+ intrinsics:: panic_if_uninhabited :: < T > ( ) ;
522
571
& * self . value
523
572
}
524
573
525
- /// Gets a mutable reference to the contained value.
574
+ /// Gets a mutable (unique) reference to the contained value.
575
+ ///
576
+ /// This can be useful when we want to access a `MaybeUninit` that has been
577
+ /// initialized but don't have ownership of the `MaybeUninit` (preventing the use
578
+ /// of `.assume_init()`).
526
579
///
527
580
/// # Safety
528
581
///
529
- /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
530
- /// state. Calling this when the content is not yet fully initialized causes undefined
531
- /// behavior.
582
+ /// Calling this when the content is not yet fully initialized causes undefined
583
+ /// behavior: it is up to the caller to guarantee that the `MaybeUninit<T>` really
584
+ /// is in an initialized state. For instance, `.get_mut()` cannot be used to
585
+ /// initialize a `MaybeUninit`.
586
+ ///
587
+ /// # Examples
588
+ ///
589
+ /// ### Correct usage of this method:
590
+ ///
591
+ /// ```rust
592
+ /// #![feature(maybe_uninit_ref)]
593
+ /// use std::mem::MaybeUninit;
594
+ ///
595
+ /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 2048]) { *buf = [0; 2048] }
596
+ /// # #[cfg(FALSE)]
597
+ /// extern "C" {
598
+ /// /// Initializes *all* the bytes of the input buffer.
599
+ /// fn initialize_buffer(buf: *mut [u8; 2048]);
600
+ /// }
601
+ ///
602
+ /// let mut buf = MaybeUninit::<[u8; 2048]>::uninit();
603
+ ///
604
+ /// // Initialize `buf`:
605
+ /// unsafe { initialize_buffer(buf.as_mut_ptr()); }
606
+ /// // Now we know that `buf` has been initialized, so we could `.assume_init()` it.
607
+ /// // However, using `.assume_init()` may trigger a `memcpy` of the 2048 bytes.
608
+ /// // To assert our buffer has been initialized without copying it, we upgrade
609
+ /// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`:
610
+ /// let buf: &mut [u8; 2048] = unsafe {
611
+ /// // Safety: `buf` has been initialized.
612
+ /// buf.get_mut()
613
+ /// };
614
+ ///
615
+ /// // Now we can use `buf` as a normal slice:
616
+ /// buf.sort_unstable();
617
+ /// assert!(
618
+ /// buf.chunks(2).all(|chunk| chunk[0] <= chunk[1]),
619
+ /// "buffer is sorted",
620
+ /// );
621
+ /// ```
622
+ ///
623
+ /// ### *Incorrect* usages of this method:
624
+ ///
625
+ /// You cannot use `.get_mut()` to initialize a value:
626
+ ///
627
+ /// ```rust,no_run
628
+ /// #![feature(maybe_uninit_ref)]
629
+ /// use std::mem::MaybeUninit;
630
+ ///
631
+ /// let mut b = MaybeUninit::<bool>::uninit();
632
+ /// unsafe {
633
+ /// *b.get_mut() = true;
634
+ /// // We have created a (mutable) reference to an uninitialized `bool`!
635
+ /// // This is undefined behavior.
636
+ /// }
637
+ /// ```
638
+ ///
639
+ /// For instance, you cannot [`Read`] into an uninitialized buffer:
640
+ ///
641
+ /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
642
+ ///
643
+ /// ```rust,no_run
644
+ /// #![feature(maybe_uninit_ref)]
645
+ /// use std::{io, mem::MaybeUninit};
646
+ ///
647
+ /// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]>
648
+ /// {
649
+ /// let mut buffer = MaybeUninit::<[u8; 64]>::uninit();
650
+ /// reader.read_exact(unsafe { buffer.get_mut() })?;
651
+ /// // ^^^^^^^^^^^^^^^^
652
+ /// // (mutable) reference to uninitialized memory!
653
+ /// // This is undefined behavior.
654
+ /// Ok(unsafe { buffer.assume_init() })
655
+ /// }
656
+ /// ```
657
+ ///
658
+ /// Nor can you use direct field access to do field-by-field gradual initialization:
659
+ ///
660
+ /// ```rust,no_run
661
+ /// #![feature(maybe_uninit_ref)]
662
+ /// use std::{mem::MaybeUninit, ptr};
663
+ ///
664
+ /// struct Foo {
665
+ /// a: u32,
666
+ /// b: u8,
667
+ /// }
668
+ ///
669
+ /// let foo: Foo = unsafe {
670
+ /// let mut foo = MaybeUninit::<Foo>::uninit();
671
+ /// ptr::write(&mut foo.get_mut().a as *mut u32, 1337);
672
+ /// // ^^^^^^^^^^^^^
673
+ /// // (mutable) reference to uninitialized memory!
674
+ /// // This is undefined behavior.
675
+ /// ptr::write(&mut foo.get_mut().b as *mut u8, 42);
676
+ /// // ^^^^^^^^^^^^^
677
+ /// // (mutable) reference to uninitialized memory!
678
+ /// // This is undefined behavior.
679
+ /// foo.assume_init()
680
+ /// };
681
+ /// ```
532
682
// FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references
533
683
// to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make
534
684
// a final decision about the rules before stabilization.
535
685
#[ unstable( feature = "maybe_uninit_ref" , issue = "63568" ) ]
536
686
#[ inline( always) ]
537
687
pub unsafe fn get_mut ( & mut self ) -> & mut T {
688
+ intrinsics:: panic_if_uninhabited :: < T > ( ) ;
538
689
& mut * self . value
539
690
}
540
691
0 commit comments