diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2cee23a5c752..9a23b54dfa0a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1423,13 +1423,14 @@ pub(crate) fn is_aligned_and_not_null(ptr: *const T) -> bool { } /// Checks whether the regions of memory starting at `src` and `dst` of size -/// `count * size_of::()` overlap. -fn overlaps(src: *const T, dst: *const T, count: usize) -> bool { +/// `count * size_of::()` do *not* overlap. +pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) -> bool { let src_usize = src as usize; let dst_usize = dst as usize; let size = mem::size_of::().checked_mul(count).unwrap(); let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize }; - size > diff + let overlaps = size > diff; + !overlaps } /// Copies `count * size_of::()` bytes from `src` to `dst`. The source @@ -1524,7 +1525,7 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer"); debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer"); - debug_assert!(!overlaps(src, dst, count), "attempt to copy to overlapping memory"); + debug_assert!(is_nonoverlapping(src, dst, count), "attempt to copy to overlapping memory"); copy_nonoverlapping(src, dst, count) } diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 0ee50966f968..3d41a158b6d8 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -72,7 +72,7 @@ use crate::cmp::Ordering; use crate::fmt; use crate::hash; -use crate::intrinsics; +use crate::intrinsics::{self, is_aligned_and_not_null, is_nonoverlapping}; use crate::mem::{self, MaybeUninit}; #[stable(feature = "rust1", since = "1.0.0")] @@ -119,10 +119,13 @@ mod mut_ptr; /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `to_drop` must be [valid] for reads. +/// * `to_drop` must be [valid] for both reads and writes. /// /// * `to_drop` must be properly aligned. /// +/// * The value `to_drop` points to must be valid for dropping, which may mean it must uphold +/// additional invariants - this is type-dependent. +/// /// Additionally, if `T` is not [`Copy`], using the pointed-to value after /// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = /// foo` counts as a use because it will cause the value to be dropped @@ -289,7 +292,7 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * Both `x` and `y` must be [valid] for reads and writes. +/// * Both `x` and `y` must be [valid] for both reads and writes. /// /// * Both `x` and `y` must be properly aligned. /// @@ -355,7 +358,7 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * Both `x` and `y` must be [valid] for reads and writes of `count * +/// * Both `x` and `y` must be [valid] for both reads and writes of `count * /// size_of::()` bytes. /// /// * Both `x` and `y` must be properly aligned. @@ -389,6 +392,10 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { #[inline] #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { + debug_assert!(is_aligned_and_not_null(x), "attempt to swap unaligned or null pointer"); + debug_assert!(is_aligned_and_not_null(y), "attempt to swap unaligned or null pointer"); + debug_assert!(is_nonoverlapping(x, y, count), "attempt to swap overlapping memory"); + let x = x as *mut u8; let y = y as *mut u8; let len = mem::size_of::() * count; @@ -471,10 +478,12 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dst` must be [valid] for writes. +/// * `dst` must be [valid] for both reads and writes. /// /// * `dst` must be properly aligned. /// +/// * `dst` must point to a properly initialized value of type `T`. +/// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety @@ -514,6 +523,8 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the /// case. /// +/// * `src` must point to a properly initialized value of type `T`. +/// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// /// # Examples @@ -612,6 +623,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { + // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); tmp.assume_init() @@ -628,6 +640,8 @@ pub unsafe fn read(src: *const T) -> T { /// /// * `src` must be [valid] for reads. /// +/// * `src` must point to a properly initialized value of type `T`. +/// /// Like [`read`], `read_unaligned` creates a bitwise copy of `T`, regardless of /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned /// value and the value at `*src` can [violate memory safety][read-ownership]. @@ -703,6 +717,7 @@ pub unsafe fn read(src: *const T) -> T { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn read_unaligned(src: *const T) -> T { + // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::()); tmp.assume_init() @@ -795,6 +810,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { + debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); intrinsics::move_val_init(&mut *dst, src) } @@ -887,6 +903,7 @@ pub unsafe fn write(dst: *mut T, src: T) { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn write_unaligned(dst: *mut T, src: T) { + // `copy_nonoverlapping` takes care of debug_assert. copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::()); mem::forget(src); } @@ -922,6 +939,8 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// * `src` must be properly aligned. /// +/// * `src` must point to a properly initialized value of type `T`. +/// /// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned /// value and the value at `*src` can [violate memory safety][read-ownership]. @@ -956,6 +975,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { #[inline] #[stable(feature = "volatile", since = "1.9.0")] pub unsafe fn read_volatile(src: *const T) -> T { + debug_assert!(is_aligned_and_not_null(src), "attempt to read from unaligned or null pointer"); intrinsics::volatile_load(src) } @@ -1024,6 +1044,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { #[inline] #[stable(feature = "volatile", since = "1.9.0")] pub unsafe fn write_volatile(dst: *mut T, src: T) { + debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); intrinsics::volatile_store(dst, src); } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 734b3ba7c6bb..e5b8412e117e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2658,7 +2658,8 @@ impl str { /// /// It's important to remember that [`char`] represents a Unicode Scalar /// Value, and may not match your idea of what a 'character' is. Iteration - /// over grapheme clusters may be what you actually want. + /// over grapheme clusters may be what you actually want. This functionality + /// is not provided by Rust's standard library, check crates.io instead. /// /// # Examples /// diff --git a/src/librustc_error_codes/error_codes/E0309.md b/src/librustc_error_codes/error_codes/E0309.md index 73ce7407476f..e719ee590aba 100644 --- a/src/librustc_error_codes/error_codes/E0309.md +++ b/src/librustc_error_codes/error_codes/E0309.md @@ -1,9 +1,7 @@ -The type definition contains some field whose type -requires an outlives annotation. Outlives annotations -(e.g., `T: 'a`) are used to guarantee that all the data in T is valid -for at least the lifetime `'a`. This scenario most commonly -arises when the type contains an associated type reference -like `>::Output`, as shown in this example: +A parameter type is missing an explicit lifetime bound and may not live long +enough. + +Erroneous code example: ```compile_fail,E0309 // This won't compile because the applicable impl of @@ -25,9 +23,15 @@ where } ``` -Here, the where clause `T: 'a` that appears on the impl is not known to be -satisfied on the struct. To make this example compile, you have to add -a where-clause like `T: 'a` to the struct definition: +The type definition contains some field whose type requires an outlives +annotation. Outlives annotations (e.g., `T: 'a`) are used to guarantee that all +the data in T is valid for at least the lifetime `'a`. This scenario most +commonly arises when the type contains an associated type reference like +`>::Output`, as shown in the previous code. + +There, the where clause `T: 'a` that appears on the impl is not known to be +satisfied on the struct. To make this example compile, you have to add a +where-clause like `T: 'a` to the struct definition: ``` struct Foo<'a, T> diff --git a/src/librustc_expand/mbe/macro_check.rs b/src/librustc_expand/mbe/macro_check.rs index 47865b2fb9fc..10cdceefdf57 100644 --- a/src/librustc_expand/mbe/macro_check.rs +++ b/src/librustc_expand/mbe/macro_check.rs @@ -109,7 +109,7 @@ use crate::mbe::{KleeneToken, TokenTree}; use rustc_data_structures::fx::FxHashMap; use rustc_session::lint::builtin::META_VARIABLE_MISUSE; use rustc_session::parse::ParseSess; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::kw; use rustc_span::{symbol::Ident, MultiSpan, Span}; use syntax::ast::NodeId; use syntax::token::{DelimToken, Token, TokenKind}; @@ -392,7 +392,7 @@ fn check_nested_occurrences( NestedMacroState::Empty, &TokenTree::Token(Token { kind: TokenKind::Ident(name, false), .. }), ) => { - if name == sym::macro_rules { + if name == kw::MacroRules { state = NestedMacroState::MacroRules; } else if name == kw::Macro { state = NestedMacroState::Macro; diff --git a/src/librustc_expand/parse/tests.rs b/src/librustc_expand/parse/tests.rs index 3641f03cb30c..4713c8dcd9a3 100644 --- a/src/librustc_expand/parse/tests.rs +++ b/src/librustc_expand/parse/tests.rs @@ -65,7 +65,7 @@ fn string_to_tts_macro() { match tts { [TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }), TokenTree::Token(Token { kind: token::Not, .. }), TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), TokenTree::Delimited(_, macro_delim, macro_tts)] - if name_macro_rules == &sym::macro_rules && name_zip.as_str() == "zip" => + if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); match &tts[..] { diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 500aaaf43b92..d7b8d9778f0d 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1343,14 +1343,14 @@ impl<'a> Parser<'a> { /// Is this unambiguously the start of a `macro_rules! foo` item defnition? fn is_macro_rules_item(&mut self) -> bool { - self.check_keyword(sym::macro_rules) + self.check_keyword(kw::MacroRules) && self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) } /// Parses a legacy `macro_rules! foo { ... }` declarative macro. fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> { - self.expect_keyword(sym::macro_rules)?; // `macro_rules` + self.expect_keyword(kw::MacroRules)?; // `macro_rules` self.expect(&token::Not)?; // `!` let ident = self.parse_ident()?; diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 1cc4a2778809..3c419334d421 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -97,6 +97,7 @@ symbols! { Auto: "auto", Catch: "catch", Default: "default", + MacroRules: "macro_rules", Raw: "raw", Union: "union", } @@ -429,7 +430,6 @@ symbols! { macro_lifetime_matcher, macro_literal_matcher, macro_reexport, - macro_rules, macros_in_extern, macro_use, macro_vis_matcher, @@ -1071,6 +1071,9 @@ pub mod sym { symbols!(); + // Used from a macro in `librustc_feature/accepted.rs` + pub use super::kw::MacroRules as macro_rules; + // Get the symbol for an integer. The first few non-negative integers each // have a static symbol and therefore are fast. pub fn integer + Copy + ToString>(n: N) -> Symbol { diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 3ca778354e41..674d4c711380 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -255,8 +255,9 @@ pub mod guard { #[cfg(target_os = "macos")] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { - let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - - libc::pthread_get_stacksize_np(libc::pthread_self()); + let th = libc::pthread_self(); + let stackaddr = + libc::pthread_get_stackaddr_np(th) as usize - libc::pthread_get_stacksize_np(th); Some(stackaddr as *mut libc::c_void) }