From ac19dffd1eaea34c3861324c2588f9cb1f1489f5 Mon Sep 17 00:00:00 2001 From: Steven Degutis Date: Thu, 23 Jan 2020 15:25:10 -0600 Subject: [PATCH 1/9] Updating str.chars docs to mention crates.io. This might spare someone else a little time searching the stdlib for unicode/grapheme support. --- src/libcore/str/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5a7cddd4041d5..89d5ba577c621 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 /// From dcad07af8aa831344fd3be353c71379854637c21 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 15 Feb 2020 15:46:25 +0300 Subject: [PATCH 2/9] parser: `macro_rules` is a weak keyword --- src/librustc_expand/mbe/macro_check.rs | 4 ++-- src/librustc_expand/parse/tests.rs | 2 +- src/librustc_parse/parser/item.rs | 4 ++-- src/librustc_span/symbol.rs | 5 ++++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/librustc_expand/mbe/macro_check.rs b/src/librustc_expand/mbe/macro_check.rs index 47865b2fb9fc3..10cdceefdf579 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 3641f03cb30c5..4713c8dcd9a3b 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 500aaaf43b92a..d7b8d9778f0d2 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 1cc4a27788098..3c419334d421e 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 { From 302b9e4b540cc352e75d3de6f803a99147107a50 Mon Sep 17 00:00:00 2001 From: Amos Onn Date: Sat, 15 Feb 2020 13:58:54 +0100 Subject: [PATCH 3/9] Improve #Safety in various methods in core::ptr s/for reads and writes/for both ... --- src/libcore/ptr/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 0ee50966f968c..d465ab11c55da 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -289,7 +289,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 +355,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. From 351782d30aaa6e15204e17ecdd51ac1e712685cf Mon Sep 17 00:00:00 2001 From: Amos Onn Date: Fri, 31 Jan 2020 15:18:27 +0100 Subject: [PATCH 4/9] Improve #Safety of core::ptr::replace Added missing condition: `dst` must be readable --- src/libcore/ptr/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index d465ab11c55da..7faede4402031 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -471,7 +471,7 @@ 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. /// From 40ca16794456e9b1520bba6d887a176395f127f0 Mon Sep 17 00:00:00 2001 From: Amos Onn Date: Fri, 31 Jan 2020 15:22:51 +0100 Subject: [PATCH 5/9] Improve #Safety in various methods in core::ptr For all methods which read a value of type T, `read`, `read_unaligned`, `read_volatile` and `replace`, added missing constraint: The value they point to must be properly initialized --- src/libcore/ptr/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 7faede4402031..7fb2d4f039929 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -475,6 +475,8 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// * `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 +516,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 @@ -628,6 +632,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]. @@ -922,6 +928,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]. From cadf9efad123a62472cad45f22569747cc599256 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 15 Feb 2020 16:41:21 +0100 Subject: [PATCH 6/9] Clean up E0309 explanation --- src/librustc_error_codes/error_codes/E0309.md | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0309.md b/src/librustc_error_codes/error_codes/E0309.md index 73ce7407476f9..e719ee590aba6 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> From 67068f35dd41409c8e79710f1335cc9dc64f1860 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sun, 2 Feb 2020 21:25:38 +0900 Subject: [PATCH 7/9] macOS: avoid calling pthread_self() twice --- src/libstd/sys/unix/thread.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 3ca778354e413..674d4c7113801 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) } From 943e65396d7bc7b91bcc30407d323d06f4b20a22 Mon Sep 17 00:00:00 2001 From: Amos Onn Date: Sat, 15 Feb 2020 00:34:15 +0100 Subject: [PATCH 8/9] Improve #Safety of core::ptr::drop_in_place Added missing conditions: - Valid for writes - Valid for destructing --- src/libcore/ptr/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 7fb2d4f039929..88b490a25d5dd 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -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 From bec5d37ee19c33bec96ed235f0197317d3728e0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 14:44:16 +0100 Subject: [PATCH 9/9] debug_assert a few more raw pointer methods --- src/libcore/intrinsics.rs | 9 +++++---- src/libcore/ptr/mod.rs | 12 +++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2cee23a5c752c..9a23b54dfa0a5 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 0ee50966f968c..ce21773165a6a 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")] @@ -389,6 +389,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; @@ -612,6 +616,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() @@ -703,6 +708,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 +801,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 +894,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); } @@ -956,6 +964,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 +1033,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); }