about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Scherer <github35764891676564198441@oli-obk.de>2019-08-21 19:56:46 +0200
committerOliver Scherer <github35764891676564198441@oli-obk.de>2019-11-06 11:04:42 +0100
commit02f9167f94a06900ee555a5797081a44ebba009e (patch)
tree78b13570e6846bdbe329d53347101c43d9825f07
parente8b190ac4ad79e58d21ee1d573529ff74d8eedaa (diff)
downloadrust-02f9167f94a06900ee555a5797081a44ebba009e.tar.gz
rust-02f9167f94a06900ee555a5797081a44ebba009e.zip
Have tidy ensure that we document all `unsafe` blocks in libcore
-rw-r--r--src/libcore/alloc.rs2
-rw-r--r--src/libcore/any.rs6
-rw-r--r--src/libcore/array/mod.rs2
-rw-r--r--src/libcore/ascii.rs1
-rw-r--r--src/libcore/benches/ascii.rs2
-rw-r--r--src/libcore/cell.rs2
-rw-r--r--src/libcore/char/convert.rs1
-rw-r--r--src/libcore/char/decode.rs3
-rw-r--r--src/libcore/char/methods.rs2
-rw-r--r--src/libcore/ffi.rs1
-rw-r--r--src/libcore/fmt/float.rs2
-rw-r--r--src/libcore/fmt/mod.rs2
-rw-r--r--src/libcore/fmt/num.rs2
-rw-r--r--src/libcore/hash/mod.rs2
-rw-r--r--src/libcore/hash/sip.rs2
-rw-r--r--src/libcore/hint.rs2
-rw-r--r--src/libcore/iter/adapters/mod.rs6
-rw-r--r--src/libcore/iter/adapters/zip.rs2
-rw-r--r--src/libcore/mem/maybe_uninit.rs2
-rw-r--r--src/libcore/mem/mod.rs18
-rw-r--r--src/libcore/num/dec2flt/algorithm.rs4
-rw-r--r--src/libcore/num/f32.rs2
-rw-r--r--src/libcore/num/f64.rs2
-rw-r--r--src/libcore/num/mod.rs25
-rw-r--r--src/libcore/option.rs2
-rw-r--r--src/libcore/panicking.rs2
-rw-r--r--src/libcore/pin.rs2
-rw-r--r--src/libcore/ptr/mod.rs2
-rw-r--r--src/libcore/ptr/non_null.rs2
-rw-r--r--src/libcore/ptr/unique.rs2
-rw-r--r--src/libcore/slice/memchr.rs2
-rw-r--r--src/libcore/slice/mod.rs1
-rw-r--r--src/libcore/slice/sort.rs2
-rw-r--r--src/libcore/str/lossy.rs2
-rw-r--r--src/libcore/str/mod.rs1
-rw-r--r--src/libcore/str/pattern.rs2
-rw-r--r--src/libcore/sync/atomic.rs2
-rw-r--r--src/libcore/tests/num/flt2dec/mod.rs2
-rw-r--r--src/libcore/time.rs2
-rw-r--r--src/librustc_typeck/check/intrinsic.rs2
-rw-r--r--src/tools/tidy/src/style.rs17
41 files changed, 137 insertions, 5 deletions
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index 5d0333d5226..1b06baeb711 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -1,5 +1,7 @@
 //! Memory allocation APIs
 
+// ignore-tidy-undocumented-unsafe
+
 #![stable(feature = "alloc_module", since = "1.28.0")]
 
 use crate::cmp;
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index e2704e807d1..681f341b544 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -182,6 +182,7 @@ impl dyn Any {
     #[inline]
     pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
         if self.is::<T>() {
+            // SAFETY: just checked whether we are pointing to the correct type
             unsafe {
                 Some(&*(self as *const dyn Any as *const T))
             }
@@ -217,6 +218,7 @@ impl dyn Any {
     #[inline]
     pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
         if self.is::<T>() {
+            // SAFETY: just checked whether we are pointing to the correct type
             unsafe {
                 Some(&mut *(self as *mut dyn Any as *mut T))
             }
@@ -424,7 +426,11 @@ impl TypeId {
     #[rustc_const_unstable(feature="const_type_id")]
     pub const fn of<T: ?Sized + 'static>() -> TypeId {
         TypeId {
+            #[cfg(boostrap_stdarch_ignore_this)]
+            // SAFETY: going away soon
             t: unsafe { intrinsics::type_id::<T>() },
+            #[cfg(not(boostrap_stdarch_ignore_this))]
+            t: intrinsics::type_id::<T>(),
         }
     }
 }
diff --git a/src/libcore/array/mod.rs b/src/libcore/array/mod.rs
index e1ec8b795d0..74a7d062d3f 100644
--- a/src/libcore/array/mod.rs
+++ b/src/libcore/array/mod.rs
@@ -156,6 +156,7 @@ where
     fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> {
         if slice.len() == N {
             let ptr = slice.as_ptr() as *const [T; N];
+            // SAFETY: ok because we just checked that the length fits
             unsafe { Ok(&*ptr) }
         } else {
             Err(TryFromSliceError(()))
@@ -173,6 +174,7 @@ where
     fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> {
         if slice.len() == N {
             let ptr = slice.as_mut_ptr() as *mut [T; N];
+            // SAFETY: ok because we just checked that the length fits
             unsafe { Ok(&mut *ptr) }
         } else {
             Err(TryFromSliceError(()))
diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs
index 4087333e2cf..9b588525bd6 100644
--- a/src/libcore/ascii.rs
+++ b/src/libcore/ascii.rs
@@ -135,6 +135,7 @@ impl FusedIterator for EscapeDefault {}
 #[stable(feature = "ascii_escape_display", since = "1.39.0")]
 impl fmt::Display for EscapeDefault {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // SAFETY: ok because `escape_default` created only valid utf-8 data
         f.write_str(unsafe { from_utf8_unchecked(&self.data[self.range.clone()]) })
     }
 }
diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs
index a337c467131..e921dd1ba06 100644
--- a/src/libcore/benches/ascii.rs
+++ b/src/libcore/benches/ascii.rs
@@ -118,6 +118,7 @@ benches! {
     }
 
     fn case07_fake_simd_u32(bytes: &mut [u8]) {
+        // SAFETY: transmuting a sequence of `u8` to `u32` is always fine
         let (before, aligned, after) = unsafe {
             bytes.align_to_mut::<u32>()
         };
@@ -142,6 +143,7 @@ benches! {
     }
 
     fn case08_fake_simd_u64(bytes: &mut [u8]) {
+        // SAFETY: transmuting a sequence of `u8` to `u64` is always fine
         let (before, aligned, after) = unsafe {
             bytes.align_to_mut::<u64>()
         };
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index fda103a52d8..31d7514133e 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -182,6 +182,8 @@
 //! ```
 //!
 
+// ignore-tidy-undocumented-unsafe
+
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::cmp::Ordering;
diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs
index c456e14db12..28f52074495 100644
--- a/src/libcore/char/convert.rs
+++ b/src/libcore/char/convert.rs
@@ -224,6 +224,7 @@ impl TryFrom<u32> for char {
         if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
             Err(CharTryFromError(()))
         } else {
+            // SAFETY: checked that it's a legal unicode value
             Ok(unsafe { from_u32_unchecked(i) })
         }
     }
diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs
index b71c9c2c40b..ae09251c776 100644
--- a/src/libcore/char/decode.rs
+++ b/src/libcore/char/decode.rs
@@ -87,7 +87,7 @@ impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> {
         };
 
         if u < 0xD800 || 0xDFFF < u {
-            // not a surrogate
+            // SAFETY: not a surrogate
             Some(Ok(unsafe { from_u32_unchecked(u as u32) }))
         } else if u >= 0xDC00 {
             // a trailing surrogate
@@ -107,6 +107,7 @@ impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> {
 
             // all ok, so lets decode it.
             let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000;
+            // SAFETY: we checked that it's a legal unicode value
             Some(Ok(unsafe { from_u32_unchecked(c) }))
         }
     }
diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs
index 971d89e0044..c048bab287d 100644
--- a/src/libcore/char/methods.rs
+++ b/src/libcore/char/methods.rs
@@ -438,6 +438,7 @@ impl char {
     #[inline]
     pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
         let code = self as u32;
+        // SAFETY: each arm checks the size of the slice and only uses `get_unchecked` unsafe ops
         unsafe {
             let len = if code < MAX_ONE_B && !dst.is_empty() {
                 *dst.get_unchecked_mut(0) = code as u8;
@@ -507,6 +508,7 @@ impl char {
     #[inline]
     pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
         let mut code = self as u32;
+        // SAFETY: each arm checks whether there are enough bits to write into
         unsafe {
             if (code & 0xFFFF) == code && !dst.is_empty() {
                 // The BMP falls through (assuming non-surrogate, as it should)
diff --git a/src/libcore/ffi.rs b/src/libcore/ffi.rs
index 569c667ac0a..499dd0facd3 100644
--- a/src/libcore/ffi.rs
+++ b/src/libcore/ffi.rs
@@ -315,6 +315,7 @@ impl<'f> Clone for VaListImpl<'f> {
     #[inline]
     fn clone(&self) -> Self {
         let mut dest = crate::mem::MaybeUninit::uninit();
+        // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal
         unsafe {
             va_copy(dest.as_mut_ptr(), self);
             dest.assume_init()
diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs
index a2fff913ac7..b52b56b1bdb 100644
--- a/src/libcore/fmt/float.rs
+++ b/src/libcore/fmt/float.rs
@@ -2,6 +2,8 @@ use crate::fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
 use crate::mem::MaybeUninit;
 use crate::num::flt2dec;
 
+// ignore-tidy-undocumented-unsafe
+
 // Don't inline this so callers don't use the stack space this function
 // requires unless they have to.
 #[inline(never)]
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 0e83a282b18..5a039144f66 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -1,5 +1,7 @@
 //! Utilities for formatting and printing strings.
 
+// ignore-tidy-undocumented-unsafe
+
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::cell::{UnsafeCell, Cell, RefCell, Ref, RefMut};
diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs
index 3b5c9fbff25..3c7aefc090f 100644
--- a/src/libcore/fmt/num.rs
+++ b/src/libcore/fmt/num.rs
@@ -1,5 +1,7 @@
 //! Integer and floating-point number formatting
 
+// ignore-tidy-undocumented-unsafe
+
 
 use crate::fmt;
 use crate::ops::{Div, Rem, Sub};
diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs
index 020e085abf8..0082363692d 100644
--- a/src/libcore/hash/mod.rs
+++ b/src/libcore/hash/mod.rs
@@ -79,6 +79,8 @@
 //! }
 //! ```
 
+// ignore-tidy-undocumented-unsafe
+
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::fmt;
diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs
index 19aeafd882e..194d9e6e2f8 100644
--- a/src/libcore/hash/sip.rs
+++ b/src/libcore/hash/sip.rs
@@ -1,5 +1,7 @@
 //! An implementation of SipHash.
 
+// ignore-tidy-undocumented-unsafe
+
 #![allow(deprecated)] // the types in this module are deprecated
 
 use crate::marker::PhantomData;
diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs
index 368a2f16b28..f68a3e5a76f 100644
--- a/src/libcore/hint.rs
+++ b/src/libcore/hint.rs
@@ -2,6 +2,8 @@
 
 //! Hints to compiler that affects how code should be emitted or optimized.
 
+// ignore-tidy-undocumented-unsafe
+
 use crate::intrinsics;
 
 /// Informs the compiler that this point in the code is not reachable, enabling
diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs
index 3b8edc2ad61..b016127a07a 100644
--- a/src/libcore/iter/adapters/mod.rs
+++ b/src/libcore/iter/adapters/mod.rs
@@ -517,9 +517,15 @@ impl<I> Iterator for StepBy<I> where I: Iterator {
         // overflow handling
         loop {
             let mul = n.checked_mul(step);
+            #[cfg(boostrap_stdarch_ignore_this)]
+            // SAFETY: going away soon
             if unsafe { intrinsics::likely(mul.is_some()) } {
                 return self.iter.nth(mul.unwrap() - 1);
             }
+            #[cfg(not(boostrap_stdarch_ignore_this))]
+            if intrinsics::likely(mul.is_some()) {
+                return self.iter.nth(mul.unwrap() - 1);
+            }
             let div_n = usize::MAX / n;
             let div_step = usize::MAX / step;
             let nth_n = div_n * n;
diff --git a/src/libcore/iter/adapters/zip.rs b/src/libcore/iter/adapters/zip.rs
index 430ceacdd9f..14d9d5499b8 100644
--- a/src/libcore/iter/adapters/zip.rs
+++ b/src/libcore/iter/adapters/zip.rs
@@ -1,3 +1,5 @@
+// ignore-tidy-undocumented-unsafe
+
 use crate::cmp;
 
 use super::super::{Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen};
diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs
index 51ba260589f..9f2948dcb03 100644
--- a/src/libcore/mem/maybe_uninit.rs
+++ b/src/libcore/mem/maybe_uninit.rs
@@ -1,6 +1,8 @@
 use crate::intrinsics;
 use crate::mem::ManuallyDrop;
 
+// ignore-tidy-undocumented-unsafe
+
 /// A wrapper type to construct uninitialized instances of `T`.
 ///
 /// # Initialization invariant
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index c7da56aad30..7c504016c75 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -93,6 +93,8 @@ pub fn forget<T>(t: T) {
 #[inline]
 #[unstable(feature = "forget_unsized", issue = "0")]
 pub fn forget_unsized<T: ?Sized>(t: T) {
+    // SAFETY: the forget intrinsic could be safe, but there's no point in making it safe since
+    // we'll be implementing this function soon via `ManuallyDrop`
     unsafe { intrinsics::forget(t) }
 }
 
@@ -266,7 +268,11 @@ pub const fn size_of<T>() -> usize {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
+    #[cfg(boostrap_stdarch_ignore_this)]
+    // SAFETY: going away soon
     unsafe { intrinsics::size_of_val(val) }
+    #[cfg(not(boostrap_stdarch_ignore_this))]
+    intrinsics::size_of_val(val)
 }
 
 /// Returns the [ABI]-required minimum alignment of a type.
@@ -310,7 +316,11 @@ pub fn min_align_of<T>() -> usize {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")]
 pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
+    #[cfg(boostrap_stdarch_ignore_this)]
+    // SAFETY: going away soon
     unsafe { intrinsics::min_align_of_val(val) }
+    #[cfg(not(boostrap_stdarch_ignore_this))]
+    intrinsics::min_align_of_val(val)
 }
 
 /// Returns the [ABI]-required minimum alignment of a type.
@@ -351,7 +361,7 @@ pub const fn align_of<T>() -> usize {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
-    unsafe { intrinsics::min_align_of_val(val) }
+    min_align_of_val(val)
 }
 
 /// Returns `true` if dropping values of type `T` matters.
@@ -508,6 +518,8 @@ pub unsafe fn uninitialized<T>() -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn swap<T>(x: &mut T, y: &mut T) {
+    // SAFETY: the raw pointers have been created from safe mutable references satisfying all the
+    // constraints on `ptr::swap_nonoverlapping_one`
     unsafe {
         ptr::swap_nonoverlapping_one(x, y);
     }
@@ -822,7 +834,11 @@ impl<T> fmt::Debug for Discriminant<T> {
 /// ```
 #[stable(feature = "discriminant_value", since = "1.21.0")]
 pub fn discriminant<T>(v: &T) -> Discriminant<T> {
+    #[cfg(boostrap_stdarch_ignore_this)]
+    // SAFETY: going away soon
     unsafe {
         Discriminant(intrinsics::discriminant_value(v), PhantomData)
     }
+    #[cfg(not(boostrap_stdarch_ignore_this))]
+    Discriminant(intrinsics::discriminant_value(v), PhantomData)
 }
diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs
index ed89852dc48..64146302626 100644
--- a/src/libcore/num/dec2flt/algorithm.rs
+++ b/src/libcore/num/dec2flt/algorithm.rs
@@ -58,6 +58,8 @@ mod fpu_precision {
     pub struct FPUControlWord(u16);
 
     fn set_cw(cw: u16) {
+        // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with
+        // any `u16`
         unsafe { asm!("fldcw $0" :: "m" (cw) :: "volatile") }
     }
 
@@ -74,6 +76,8 @@ mod fpu_precision {
 
         // Get the original value of the control word to restore it later, when the
         // `FPUControlWord` structure is dropped
+        // SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with
+        // any `u16`
         unsafe { asm!("fnstcw $0" : "=*m" (&cw) ::: "volatile") }
 
         // Set the control word to the desired precision. This is achieved by masking away the old
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 5730088c4d9..7662bba6b5e 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -414,6 +414,7 @@ impl f32 {
     #[stable(feature = "float_bits_conv", since = "1.20.0")]
     #[inline]
     pub fn to_bits(self) -> u32 {
+        // SAFETY: `u32` is a plain old datatype so we can always transmute to it
         unsafe { mem::transmute(self) }
     }
 
@@ -456,6 +457,7 @@ impl f32 {
     #[stable(feature = "float_bits_conv", since = "1.20.0")]
     #[inline]
     pub fn from_bits(v: u32) -> Self {
+        // SAFETY: `u32` is a plain old datatype so we can always transmute from it
         // It turns out the safety issues with sNaN were overblown! Hooray!
         unsafe { mem::transmute(v) }
     }
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 2bdeda340dc..4a2a35dfb09 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -427,6 +427,7 @@ impl f64 {
     #[stable(feature = "float_bits_conv", since = "1.20.0")]
     #[inline]
     pub fn to_bits(self) -> u64 {
+        // SAFETY: `u64` is a plain old datatype so we can always transmute to it
         unsafe { mem::transmute(self) }
     }
 
@@ -469,6 +470,7 @@ impl f64 {
     #[stable(feature = "float_bits_conv", since = "1.20.0")]
     #[inline]
     pub fn from_bits(v: u64) -> Self {
+        // SAFETY: `u64` is a plain old datatype so we can always transmute from it
         // It turns out the safety issues with sNaN were overblown! Hooray!
         unsafe { mem::transmute(v) }
     }
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index b4ade704144..4b9e82c7cfe 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -71,6 +71,7 @@ assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", s
                 #[inline]
                 pub fn new(n: $Int) -> Option<Self> {
                     if n != 0 {
+                        // SAFETY: we just checked that there's no `0`
                         Some(unsafe { $Ty(n) })
                     } else {
                         None
@@ -703,6 +704,7 @@ $EndFeature, "
                 if rhs == 0 || (self == Self::min_value() && rhs == -1) {
                     None
                 } else {
+                    // SAFETY: div by zero and by INT_MIN have been checked above
                     Some(unsafe { intrinsics::unchecked_div(self, rhs) })
                 }
             }
@@ -759,6 +761,7 @@ $EndFeature, "
                 if rhs == 0 || (self == Self::min_value() && rhs == -1) {
                     None
                 } else {
+                    // SAFETY: div by zero and by INT_MIN have been checked above
                     Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
                 }
             }
@@ -1329,6 +1332,8 @@ $EndFeature, "
                           without modifying the original"]
             #[inline]
             pub const fn wrapping_shl(self, rhs: u32) -> Self {
+                // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+                // out of bounds
                 unsafe {
                     intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
                 }
@@ -1358,6 +1363,8 @@ $EndFeature, "
                           without modifying the original"]
             #[inline]
             pub const fn wrapping_shr(self, rhs: u32) -> Self {
+                // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+                // out of bounds
                 unsafe {
                     intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
                 }
@@ -2113,6 +2120,8 @@ assert_eq!(
             #[rustc_const_unstable(feature = "const_int_conversion")]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+                // SAFETY: integers are plain old datatypes so we can always transmute them to
+                // arrays of bytes
                 unsafe { mem::transmute(self) }
             }
         }
@@ -2221,6 +2230,7 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
             #[rustc_const_unstable(feature = "const_int_conversion")]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+                // SAFETY: integers are plain old datatypes so we can always transmute to them
                 unsafe { mem::transmute(bytes) }
             }
         }
@@ -2748,6 +2758,8 @@ assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, "
             pub fn checked_div(self, rhs: Self) -> Option<Self> {
                 match rhs {
                     0 => None,
+                    // SAFETY: div by zero has been checked above and unsigned types have no other
+                    // failure modes for division
                     rhs => Some(unsafe { intrinsics::unchecked_div(self, rhs) }),
                 }
             }
@@ -2799,6 +2811,8 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, "
                 if rhs == 0 {
                     None
                 } else {
+                    // SAFETY: div by zero has been checked above and unsigned types have no other
+                    // failure modes for division
                     Some(unsafe { intrinsics::unchecked_rem(self, rhs) })
                 }
             }
@@ -3248,6 +3262,8 @@ assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, "
                           without modifying the original"]
             #[inline]
             pub const fn wrapping_shl(self, rhs: u32) -> Self {
+                // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+                // out of bounds
                 unsafe {
                     intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
                 }
@@ -3279,6 +3295,8 @@ assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, "
                           without modifying the original"]
             #[inline]
             pub const fn wrapping_shr(self, rhs: u32) -> Self {
+                // SAFETY: the masking by the bitsize of the type ensures that we do not shift
+                // out of bounds
                 unsafe {
                     intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
                 }
@@ -3775,11 +3793,11 @@ assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
         fn one_less_than_next_power_of_two(self) -> Self {
             if self <= 1 { return 0; }
 
-            // Because `p > 0`, it cannot consist entirely of leading zeros.
+            let p = self - 1;
+            // SAFETY: Because `p > 0`, it cannot consist entirely of leading zeros.
             // That means the shift is always in-bounds, and some processors
             // (such as intel pre-haswell) have more efficient ctlz
             // intrinsics when the argument is non-zero.
-            let p = self - 1;
             let z = unsafe { intrinsics::ctlz_nonzero(p) };
             <$SelfT>::max_value() >> z
         }
@@ -3925,6 +3943,8 @@ assert_eq!(
             #[rustc_const_unstable(feature = "const_int_conversion")]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+                // SAFETY: integers are plain old datatypes so we can always transmute them to
+                // arrays of bytes
                 unsafe { mem::transmute(self) }
             }
         }
@@ -4033,6 +4053,7 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
             #[rustc_const_unstable(feature = "const_int_conversion")]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+                // SAFETY: integers are plain old datatypes so we can always transmute to them
                 unsafe { mem::transmute(bytes) }
             }
         }
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index f0ac5e749f6..958f31c0fd2 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -133,6 +133,8 @@
 //! [`Box<T>`]: ../../std/boxed/struct.Box.html
 //! [`i32`]: ../../std/primitive.i32.html
 
+// ignore-tidy-undocumented-unsafe
+
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::iter::{FromIterator, FusedIterator, TrustedLen};
diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs
index 685b749776b..b88dc336097 100644
--- a/src/libcore/panicking.rs
+++ b/src/libcore/panicking.rs
@@ -20,6 +20,8 @@
 //! one function. Currently, the actual symbol is declared in the standard
 //! library, but the location of this may change over time.
 
+// ignore-tidy-undocumented-unsafe
+
 #![allow(dead_code, missing_docs)]
 #![unstable(feature = "core_panic",
             reason = "internal details of the implementation of the `panic!` \
diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs
index be057ed6d59..1219fd09a9d 100644
--- a/src/libcore/pin.rs
+++ b/src/libcore/pin.rs
@@ -552,6 +552,7 @@ impl<P: Deref> Pin<P> {
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub fn as_ref(&self) -> Pin<&P::Target> {
+        // SAFETY: see documentation on this function
         unsafe { Pin::new_unchecked(&*self.pointer) }
     }
 
@@ -610,6 +611,7 @@ impl<P: DerefMut> Pin<P> {
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub fn as_mut(&mut self) -> Pin<&mut P::Target> {
+        // SAFETY: see documentation on this function
         unsafe { Pin::new_unchecked(&mut *self.pointer) }
     }
 
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index 1355ce1aa43..cb2fe7bc8bd 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -61,6 +61,8 @@
 //! [`write_volatile`]: ./fn.write_volatile.html
 //! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling
 
+// ignore-tidy-undocumented-unsafe
+
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::intrinsics;
diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs
index 7dcd57f1f98..7599991f0f1 100644
--- a/src/libcore/ptr/non_null.rs
+++ b/src/libcore/ptr/non_null.rs
@@ -7,6 +7,8 @@ use crate::mem;
 use crate::ptr::Unique;
 use crate::cmp::Ordering;
 
+// ignore-tidy-undocumented-unsafe
+
 /// `*mut T` but non-zero and covariant.
 ///
 /// This is often the correct thing to use when building data structures using
diff --git a/src/libcore/ptr/unique.rs b/src/libcore/ptr/unique.rs
index 3521dd79979..11a3aed1ab4 100644
--- a/src/libcore/ptr/unique.rs
+++ b/src/libcore/ptr/unique.rs
@@ -5,6 +5,8 @@ use crate::marker::{PhantomData, Unsize};
 use crate::mem;
 use crate::ptr::NonNull;
 
+// ignore-tidy-undocumented-unsafe
+
 /// A wrapper around a raw non-null `*mut T` that indicates that the possessor
 /// of this wrapper owns the referent. Useful for building abstractions like
 /// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`.
diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs
index 45ab016c496..2a2169dd348 100644
--- a/src/libcore/slice/memchr.rs
+++ b/src/libcore/slice/memchr.rs
@@ -1,6 +1,8 @@
 // Original implementation taken from rust-memchr.
 // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
 
+// ignore-tidy-undocumented-unsafe
+
 use crate::cmp;
 use crate::mem;
 
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index cdada1252d2..88e367fe40c 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -1,4 +1,5 @@
 // ignore-tidy-filelength
+// ignore-tidy-undocumented-unsafe
 
 //! Slice management and manipulation.
 //!
diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs
index 2f2170f7ff1..a719a51b616 100644
--- a/src/libcore/slice/sort.rs
+++ b/src/libcore/slice/sort.rs
@@ -6,6 +6,8 @@
 //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our
 //! stable sorting implementation.
 
+// ignore-tidy-undocumented-unsafe
+
 use crate::cmp;
 use crate::mem::{self, MaybeUninit};
 use crate::ptr;
diff --git a/src/libcore/str/lossy.rs b/src/libcore/str/lossy.rs
index e8f747f1a67..762de0489a9 100644
--- a/src/libcore/str/lossy.rs
+++ b/src/libcore/str/lossy.rs
@@ -3,6 +3,8 @@ use crate::str as core_str;
 use crate::fmt::{self, Write};
 use crate::mem;
 
+// ignore-tidy-undocumented-unsafe
+
 /// Lossy UTF-8 string.
 #[unstable(feature = "str_internals", issue = "0")]
 pub struct Utf8Lossy {
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 1968919f554..25b7eec5b33 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -1,4 +1,5 @@
 // ignore-tidy-filelength
+// ignore-tidy-undocumented-unsafe
 
 //! String manipulation.
 //!
diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs
index ad9d956fda1..a494274118a 100644
--- a/src/libcore/str/pattern.rs
+++ b/src/libcore/str/pattern.rs
@@ -3,6 +3,8 @@
 //! For more details, see the traits [`Pattern`], [`Searcher`],
 //! [`ReverseSearcher`], and [`DoubleEndedSearcher`].
 
+// ignore-tidy-undocumented-unsafe
+
 #![unstable(feature = "pattern",
             reason = "API not fully fleshed out and ready to be stabilized",
             issue = "27721")]
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 73d5abf1aed..d311cb16b64 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -112,6 +112,8 @@
 //! println!("live threads: {}", old_thread_count + 1);
 //! ```
 
+// ignore-tidy-undocumented-unsafe
+
 #![stable(feature = "rust1", since = "1.0.0")]
 #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))]
 #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(unused_imports))]
diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs
index c41d35efced..a35897e9bc1 100644
--- a/src/libcore/tests/num/flt2dec/mod.rs
+++ b/src/libcore/tests/num/flt2dec/mod.rs
@@ -85,6 +85,8 @@ fn ldexp_f64(a: f64, b: i32) -> f64 {
     extern {
         fn ldexp(x: f64, n: i32) -> f64;
     }
+    // SAFETY: assuming a correct `ldexp` has been supplied, the given arguments cannot possibly
+    // cause undefined behavior
     unsafe { ldexp(a, b) }
 }
 
diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index 5a0e4388e03..57fc1a7b760 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -920,7 +920,7 @@ impl fmt::Debug for Duration {
             if end == 0 {
                 write!(f, "{}", integer_part)
             } else {
-                // We are only writing ASCII digits into the buffer and it was
+                // SAFETY: We are only writing ASCII digits into the buffer and it was
                 // initialized with '0's, so it contains valid UTF8.
                 let s = unsafe {
                     crate::str::from_utf8_unchecked(&buf[..end])
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 33dc85fc68a..693f6f05fab 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -67,11 +67,13 @@ fn equate_intrinsic_type<'tcx>(
 pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
     match intrinsic {
         "size_of" | "min_align_of" | "needs_drop" | "caller_location" |
+        "size_of_val" | "min_align_of_val" |
         "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
         "wrapping_add" | "wrapping_sub" | "wrapping_mul" |
         "saturating_add" | "saturating_sub" |
         "rotate_left" | "rotate_right" |
         "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" |
+        "discriminant_value" | "type_id" | "likely" | "unlikely" |
         "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64" | "type_name"
         => hir::Unsafety::Normal,
         _ => hir::Unsafety::Unsafe,
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 93029099686..5abe481368d 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -160,6 +160,8 @@ pub fn check(path: &Path, bad: &mut bool) {
         let can_contain = contents.contains("// ignore-tidy-") ||
             contents.contains("# ignore-tidy-");
         let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr");
+        let mut skip_undocumented_unsafe =
+            contains_ignore_directive(can_contain, &contents, "undocumented-unsafe");
         let mut skip_tab = contains_ignore_directive(can_contain, &contents, "tab");
         let mut skip_line_length = contains_ignore_directive(can_contain, &contents, "linelength");
         let mut skip_file_length = contains_ignore_directive(can_contain, &contents, "filelength");
@@ -171,6 +173,7 @@ pub fn check(path: &Path, bad: &mut bool) {
         let mut leading_new_lines = false;
         let mut trailing_new_lines = 0;
         let mut lines = 0;
+        let mut last_safety_comment = false;
         for (i, line) in contents.split('\n').enumerate() {
             let mut err = |msg: &str| {
                 tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
@@ -200,6 +203,20 @@ pub fn check(path: &Path, bad: &mut bool) {
                     err("XXX is deprecated; use FIXME")
                 }
             }
+            let is_test = || file.components().any(|c| c.as_os_str() == "tests");
+            // for now we just check libcore
+            if line.contains("unsafe {") && !line.trim().starts_with("//") && !last_safety_comment {
+                if file.components().any(|c| c.as_os_str() == "libcore") && !is_test() {
+                    suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe");
+                }
+            }
+            if line.contains("// SAFETY: ") || line.contains("// Safety: ") {
+                last_safety_comment = true;
+            } else if line.trim().starts_with("//") || line.trim().is_empty() {
+                // keep previous value
+            } else {
+                last_safety_comment = false;
+            }
             if (line.starts_with("// Copyright") ||
                 line.starts_with("# Copyright") ||
                 line.starts_with("Copyright"))