From cce258b2b2e5f96367044fb85c04e35dda449dbe Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Wed, 6 Jan 2021 19:04:45 -0800 Subject: [PATCH 01/15] Make NonNull::as_ref (and friends) return refs with unbound lifetimes --- library/core/src/ptr/non_null.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index d849008b88030..ec444ab54ac75 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -103,7 +103,7 @@ impl NonNull { /// [the module documentation]: crate::ptr#safety #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - pub unsafe fn as_uninit_ref(&self) -> &MaybeUninit { + pub unsafe fn as_uninit_ref<'a>(&self) -> &'a MaybeUninit { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a reference. unsafe { &*self.cast().as_ptr() } @@ -135,7 +135,7 @@ impl NonNull { /// [the module documentation]: crate::ptr#safety #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - pub unsafe fn as_uninit_mut(&mut self) -> &mut MaybeUninit { + pub unsafe fn as_uninit_mut<'a>(&mut self) -> &'a mut MaybeUninit { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a reference. unsafe { &mut *self.cast().as_ptr() } @@ -206,7 +206,7 @@ impl NonNull { /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] #[inline] - pub unsafe fn as_ref(&self) -> &T { + pub unsafe fn as_ref<'a>(&self) -> &'a T { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a reference. unsafe { &*self.as_ptr() } @@ -242,7 +242,7 @@ impl NonNull { /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] #[inline] - pub unsafe fn as_mut(&mut self) -> &mut T { + pub unsafe fn as_mut<'a>(&mut self) -> &'a mut T { // SAFETY: the caller must guarantee that `self` meets all the // requirements for a mutable reference. unsafe { &mut *self.as_ptr() } @@ -390,7 +390,7 @@ impl NonNull<[T]> { /// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - pub unsafe fn as_uninit_slice(&self) -> &[MaybeUninit] { + pub unsafe fn as_uninit_slice<'a>(&self) -> &'a [MaybeUninit] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice`. unsafe { slice::from_raw_parts(self.cast().as_ptr(), self.len()) } } @@ -452,7 +452,7 @@ impl NonNull<[T]> { /// ``` #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] - pub unsafe fn as_uninit_slice_mut(&self) -> &mut [MaybeUninit] { + pub unsafe fn as_uninit_slice_mut<'a>(&self) -> &'a mut [MaybeUninit] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice_mut`. unsafe { slice::from_raw_parts_mut(self.cast().as_ptr(), self.len()) } } From c89e64363ba25a4bf487d71a4ad6e9a8cbe40384 Mon Sep 17 00:00:00 2001 From: Giacomo Stevanato Date: Fri, 26 Feb 2021 15:44:35 +0100 Subject: [PATCH 02/15] Fix invalid slice access in String::retain --- library/alloc/src/string.rs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 6fb3fcbb63be2..e8d83d3f18dad 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1233,37 +1233,44 @@ impl String { where F: FnMut(char) -> bool, { - let len = self.len(); - let mut del_bytes = 0; - let mut idx = 0; + struct SetLenOnDrop<'a> { + s: &'a mut String, + idx: usize, + del_bytes: usize, + } - unsafe { - self.vec.set_len(0); + impl<'a> Drop for SetLenOnDrop<'a> { + fn drop(&mut self) { + let new_len = self.idx - self.del_bytes; + debug_assert!(new_len <= self.s.len()); + unsafe { self.s.vec.set_len(new_len) }; + } } - while idx < len { - let ch = unsafe { self.get_unchecked(idx..len).chars().next().unwrap() }; + let len = self.len(); + let mut guard = SetLenOnDrop { s: self, idx: 0, del_bytes: 0 }; + + while guard.idx < len { + let ch = unsafe { guard.s.get_unchecked(guard.idx..len).chars().next().unwrap() }; let ch_len = ch.len_utf8(); if !f(ch) { - del_bytes += ch_len; - } else if del_bytes > 0 { + guard.del_bytes += ch_len; + } else if guard.del_bytes > 0 { unsafe { ptr::copy( - self.vec.as_ptr().add(idx), - self.vec.as_mut_ptr().add(idx - del_bytes), + guard.s.vec.as_ptr().add(guard.idx), + guard.s.vec.as_mut_ptr().add(guard.idx - guard.del_bytes), ch_len, ); } } // Point idx to the next char - idx += ch_len; + guard.idx += ch_len; } - unsafe { - self.vec.set_len(len - del_bytes); - } + drop(guard); } /// Inserts a character into this `String` at a byte position. From 7539626c4aea0ff036a8d200c587f8ae2743d9bc Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Tue, 2 Mar 2021 00:00:04 +0100 Subject: [PATCH 03/15] Move `std::sys::unix::platform` to `std::sys::unix::ext` --- library/std/src/sys/mod.rs | 2 -- library/std/src/sys/unix/ext/fs.rs | 2 +- library/std/src/sys/unix/ext/mod.rs | 36 +++++++++++++++++++++++++++++ library/std/src/sys/unix/ext/raw.rs | 6 ++--- library/std/src/sys/unix/mod.rs | 32 ------------------------- 5 files changed, 40 insertions(+), 38 deletions(-) diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index d3f53801d2d0f..b0b17f2cee993 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -70,8 +70,6 @@ cfg_if::cfg_if! { #[allow(missing_docs)] pub mod unix_ext {} } else { - // On other platforms like Windows document the bare bones of unix - use crate::os::linux as platform; #[path = "unix/ext/mod.rs"] pub mod unix_ext; } diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index ba75b9bac8035..21bdfe29578bf 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -2,11 +2,11 @@ #![stable(feature = "rust1", since = "1.0.0")] +use super::platform::fs::MetadataExt as _; use crate::fs::{self, OpenOptions, Permissions}; use crate::io; use crate::path::Path; use crate::sys; -use crate::sys::platform::fs::MetadataExt as UnixMetadataExt; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; // Used for `File::read` on intra-doc links #[allow(unused_imports)] diff --git a/library/std/src/sys/unix/ext/mod.rs b/library/std/src/sys/unix/ext/mod.rs index f43546880983a..e5048f7e545e0 100644 --- a/library/std/src/sys/unix/ext/mod.rs +++ b/library/std/src/sys/unix/ext/mod.rs @@ -29,6 +29,42 @@ #![doc(cfg(unix))] #![allow(missing_docs)] +cfg_if::cfg_if! { + if #[cfg(doc)] { + // Use linux as the default platform when documenting on other platforms like Windows + use crate::os::linux as platform; + } else { + #[cfg(target_os = "android")] + use crate::os::android as platform; + #[cfg(target_os = "dragonfly")] + use crate::os::dragonfly as platform; + #[cfg(target_os = "emscripten")] + use crate::os::emscripten as platform; + #[cfg(target_os = "freebsd")] + use crate::os::freebsd as platform; + #[cfg(target_os = "fuchsia")] + use crate::os::fuchsia as platform; + #[cfg(target_os = "haiku")] + use crate::os::haiku as platform; + #[cfg(target_os = "illumos")] + use crate::os::illumos as platform; + #[cfg(target_os = "ios")] + use crate::os::ios as platform; + #[cfg(any(target_os = "linux", target_os = "l4re"))] + use crate::os::linux as platform; + #[cfg(target_os = "macos")] + use crate::os::macos as platform; + #[cfg(target_os = "netbsd")] + use crate::os::netbsd as platform; + #[cfg(target_os = "openbsd")] + use crate::os::openbsd as platform; + #[cfg(target_os = "redox")] + use crate::os::redox as platform; + #[cfg(target_os = "solaris")] + use crate::os::solaris as platform; + } +} + pub mod ffi; pub mod fs; pub mod io; diff --git a/library/std/src/sys/unix/ext/raw.rs b/library/std/src/sys/unix/ext/raw.rs index 3199a0bff0bcc..c292955cb4eea 100644 --- a/library/std/src/sys/unix/ext/raw.rs +++ b/library/std/src/sys/unix/ext/raw.rs @@ -24,10 +24,10 @@ pub type pid_t = i32; #[doc(inline)] #[stable(feature = "pthread_t", since = "1.8.0")] -pub use crate::sys::platform::raw::pthread_t; +pub use super::platform::raw::pthread_t; #[doc(inline)] #[stable(feature = "raw_ext", since = "1.1.0")] -pub use crate::sys::platform::raw::{blkcnt_t, time_t}; +pub use super::platform::raw::{blkcnt_t, time_t}; #[doc(inline)] #[stable(feature = "raw_ext", since = "1.1.0")] -pub use crate::sys::platform::raw::{blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t}; +pub use super::platform::raw::{blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t}; diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index f8a5ee8996911..44328ffc22e5b 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -2,38 +2,6 @@ use crate::io::ErrorKind; -#[cfg(any(doc, target_os = "linux"))] -pub use crate::os::linux as platform; - -#[cfg(all(not(doc), target_os = "android"))] -pub use crate::os::android as platform; -#[cfg(all(not(doc), target_os = "dragonfly"))] -pub use crate::os::dragonfly as platform; -#[cfg(all(not(doc), target_os = "emscripten"))] -pub use crate::os::emscripten as platform; -#[cfg(all(not(doc), target_os = "freebsd"))] -pub use crate::os::freebsd as platform; -#[cfg(all(not(doc), target_os = "fuchsia"))] -pub use crate::os::fuchsia as platform; -#[cfg(all(not(doc), target_os = "haiku"))] -pub use crate::os::haiku as platform; -#[cfg(all(not(doc), target_os = "illumos"))] -pub use crate::os::illumos as platform; -#[cfg(all(not(doc), target_os = "ios"))] -pub use crate::os::ios as platform; -#[cfg(all(not(doc), target_os = "l4re"))] -pub use crate::os::linux as platform; -#[cfg(all(not(doc), target_os = "macos"))] -pub use crate::os::macos as platform; -#[cfg(all(not(doc), target_os = "netbsd"))] -pub use crate::os::netbsd as platform; -#[cfg(all(not(doc), target_os = "openbsd"))] -pub use crate::os::openbsd as platform; -#[cfg(all(not(doc), target_os = "redox"))] -pub use crate::os::redox as platform; -#[cfg(all(not(doc), target_os = "solaris"))] -pub use crate::os::solaris as platform; - pub use self::rand::hashmap_random_keys; pub use libc::strlen; From 5176f677f588740549185eb877513282512cde3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 4 Mar 2021 18:57:07 +0100 Subject: [PATCH 04/15] slice: Stabilize IterMut::as_slice. Much like #72584. As per #58957 there's no blocker for this, and I wanted to use this today :-) --- library/core/src/slice/iter.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 796301c76b608..8f404d7153019 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -286,7 +286,6 @@ impl<'a, T> IterMut<'a, T> { /// Basic usage: /// /// ``` - /// # #![feature(slice_iter_mut_as_slice)] /// let mut slice: &mut [usize] = &mut [1, 2, 3]; /// /// // First, we get the iterator: @@ -299,12 +298,19 @@ impl<'a, T> IterMut<'a, T> { /// // Now `as_slice` returns "[2, 3]": /// assert_eq!(iter.as_slice(), &[2, 3]); /// ``` - #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")] + #[stable(feature = "slice_iter_mut_as_slice", since = "1.52.0")] pub fn as_slice(&self) -> &[T] { self.make_slice() } } +#[stable(feature = "slice_iter_mut_as_slice", since = "1.52.0")] +impl AsRef<[T]> for IterMut<'_, T> { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}} /// An internal abstraction over the splitting iterators, so that From 93fda34bdb7007a54e69ecfc2df235ac465da1e4 Mon Sep 17 00:00:00 2001 From: zseri Date: Fri, 5 Mar 2021 20:02:48 +0100 Subject: [PATCH 05/15] stabilize feature(osstring_ascii) --- library/std/src/ffi/os_str.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 272eccda89471..5e0ce0358f782 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -715,7 +715,6 @@ impl OsStr { /// # Examples /// /// ``` - /// #![feature(osstring_ascii)] /// use std::ffi::OsString; /// /// let mut s = OsString::from("GRÜßE, JÜRGEN ❤"); @@ -724,7 +723,7 @@ impl OsStr { /// /// assert_eq!("grÜße, jÜrgen ❤", s); /// ``` - #[unstable(feature = "osstring_ascii", issue = "70516")] + #[stable(feature = "osstring_ascii", since = "1.52.0")] #[inline] pub fn make_ascii_lowercase(&mut self) { self.inner.make_ascii_lowercase() @@ -741,7 +740,6 @@ impl OsStr { /// # Examples /// /// ``` - /// #![feature(osstring_ascii)] /// use std::ffi::OsString; /// /// let mut s = OsString::from("Grüße, Jürgen ❤"); @@ -750,7 +748,7 @@ impl OsStr { /// /// assert_eq!("GRüßE, JüRGEN ❤", s); /// ``` - #[unstable(feature = "osstring_ascii", issue = "70516")] + #[stable(feature = "osstring_ascii", since = "1.52.0")] #[inline] pub fn make_ascii_uppercase(&mut self) { self.inner.make_ascii_uppercase() @@ -767,13 +765,12 @@ impl OsStr { /// # Examples /// /// ``` - /// #![feature(osstring_ascii)] /// use std::ffi::OsString; /// let s = OsString::from("Grüße, Jürgen ❤"); /// /// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase()); /// ``` - #[unstable(feature = "osstring_ascii", issue = "70516")] + #[stable(feature = "osstring_ascii", since = "1.52.0")] pub fn to_ascii_lowercase(&self) -> OsString { OsString::from_inner(self.inner.to_ascii_lowercase()) } @@ -789,13 +786,12 @@ impl OsStr { /// # Examples /// /// ``` - /// #![feature(osstring_ascii)] /// use std::ffi::OsString; /// let s = OsString::from("Grüße, Jürgen ❤"); /// /// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase()); /// ``` - #[unstable(feature = "osstring_ascii", issue = "70516")] + #[stable(feature = "osstring_ascii", since = "1.52.0")] pub fn to_ascii_uppercase(&self) -> OsString { OsString::from_inner(self.inner.to_ascii_uppercase()) } @@ -805,7 +801,6 @@ impl OsStr { /// # Examples /// /// ``` - /// #![feature(osstring_ascii)] /// use std::ffi::OsString; /// /// let ascii = OsString::from("hello!\n"); @@ -814,7 +809,7 @@ impl OsStr { /// assert!(ascii.is_ascii()); /// assert!(!non_ascii.is_ascii()); /// ``` - #[unstable(feature = "osstring_ascii", issue = "70516")] + #[stable(feature = "osstring_ascii", since = "1.52.0")] #[inline] pub fn is_ascii(&self) -> bool { self.inner.is_ascii() @@ -828,14 +823,13 @@ impl OsStr { /// # Examples /// /// ``` - /// #![feature(osstring_ascii)] /// use std::ffi::OsString; /// /// assert!(OsString::from("Ferris").eq_ignore_ascii_case("FERRIS")); /// assert!(OsString::from("Ferrös").eq_ignore_ascii_case("FERRöS")); /// assert!(!OsString::from("Ferrös").eq_ignore_ascii_case("FERRÖS")); /// ``` - #[unstable(feature = "osstring_ascii", issue = "70516")] + #[stable(feature = "osstring_ascii", since = "1.52.0")] pub fn eq_ignore_ascii_case>(&self, other: S) -> bool { self.inner.eq_ignore_ascii_case(&other.as_ref().inner) } From a2e9374048f1c04f025469dde88e13a5037d8db7 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 20 Mar 2021 14:23:38 -0700 Subject: [PATCH 06/15] Move debuginfo docs from `doc.rs` module to `doc.md` file And use `#[doc = include_str!("doc.md")]` in `mod.rs` so the docs are rendered as if they were inline in the root module. --- .../rustc_codegen_llvm/src/debuginfo/doc.md | 179 ++++++++++++++++++ .../rustc_codegen_llvm/src/debuginfo/doc.rs | 179 ------------------ .../rustc_codegen_llvm/src/debuginfo/mod.rs | 3 +- compiler/rustc_codegen_llvm/src/lib.rs | 1 + 4 files changed, 181 insertions(+), 181 deletions(-) create mode 100644 compiler/rustc_codegen_llvm/src/debuginfo/doc.md delete mode 100644 compiler/rustc_codegen_llvm/src/debuginfo/doc.rs diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/doc.md b/compiler/rustc_codegen_llvm/src/debuginfo/doc.md new file mode 100644 index 0000000000000..485b124ab06ba --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/debuginfo/doc.md @@ -0,0 +1,179 @@ +# Debug Info Module + +This module serves the purpose of generating debug symbols. We use LLVM's +[source level debugging](https://llvm.org/docs/SourceLevelDebugging.html) +features for generating the debug information. The general principle is +this: + +Given the right metadata in the LLVM IR, the LLVM code generator is able to +create DWARF debug symbols for the given code. The +[metadata](https://llvm.org/docs/LangRef.html#metadata-type) is structured +much like DWARF *debugging information entries* (DIE), representing type +information such as datatype layout, function signatures, block layout, +variable location and scope information, etc. It is the purpose of this +module to generate correct metadata and insert it into the LLVM IR. + +As the exact format of metadata trees may change between different LLVM +versions, we now use LLVM +[DIBuilder](https://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) +to create metadata where possible. This will hopefully ease the adaption of +this module to future LLVM versions. + +The public API of the module is a set of functions that will insert the +correct metadata into the LLVM IR when called with the right parameters. +The module is thus driven from an outside client with functions like +`debuginfo::create_local_var_metadata(bx: block, local: &ast::local)`. + +Internally the module will try to reuse already created metadata by +utilizing a cache. The way to get a shared metadata node when needed is +thus to just call the corresponding function in this module: + + let file_metadata = file_metadata(cx, file); + +The function will take care of probing the cache for an existing node for +that exact file path. + +All private state used by the module is stored within either the +CrateDebugContext struct (owned by the CodegenCx) or the +FunctionDebugContext (owned by the FunctionCx). + +This file consists of three conceptual sections: +1. The public interface of the module +2. Module-internal metadata creation functions +3. Minor utility functions + + +## Recursive Types + +Some kinds of types, such as structs and enums can be recursive. That means +that the type definition of some type X refers to some other type which in +turn (transitively) refers to X. This introduces cycles into the type +referral graph. A naive algorithm doing an on-demand, depth-first traversal +of this graph when describing types, can get trapped in an endless loop +when it reaches such a cycle. + +For example, the following simple type for a singly-linked list... + +``` +struct List { + value: i32, + tail: Option>, +} +``` + +will generate the following callstack with a naive DFS algorithm: + +``` +describe(t = List) + describe(t = i32) + describe(t = Option>) + describe(t = Box) + describe(t = List) // at the beginning again... + ... +``` + +To break cycles like these, we use "forward declarations". That is, when +the algorithm encounters a possibly recursive type (any struct or enum), it +immediately creates a type description node and inserts it into the cache +*before* describing the members of the type. This type description is just +a stub (as type members are not described and added to it yet) but it +allows the algorithm to already refer to the type. After the stub is +inserted into the cache, the algorithm continues as before. If it now +encounters a recursive reference, it will hit the cache and does not try to +describe the type anew. + +This behavior is encapsulated in the 'RecursiveTypeDescription' enum, +which represents a kind of continuation, storing all state needed to +continue traversal at the type members after the type has been registered +with the cache. (This implementation approach might be a tad over- +engineered and may change in the future) + + +## Source Locations and Line Information + +In addition to data type descriptions the debugging information must also +allow to map machine code locations back to source code locations in order +to be useful. This functionality is also handled in this module. The +following functions allow to control source mappings: + ++ set_source_location() ++ clear_source_location() ++ start_emitting_source_locations() + +`set_source_location()` allows to set the current source location. All IR +instructions created after a call to this function will be linked to the +given source location, until another location is specified with +`set_source_location()` or the source location is cleared with +`clear_source_location()`. In the later case, subsequent IR instruction +will not be linked to any source location. As you can see, this is a +stateful API (mimicking the one in LLVM), so be careful with source +locations set by previous calls. It's probably best to not rely on any +specific state being present at a given point in code. + +One topic that deserves some extra attention is *function prologues*. At +the beginning of a function's machine code there are typically a few +instructions for loading argument values into allocas and checking if +there's enough stack space for the function to execute. This *prologue* is +not visible in the source code and LLVM puts a special PROLOGUE END marker +into the line table at the first non-prologue instruction of the function. +In order to find out where the prologue ends, LLVM looks for the first +instruction in the function body that is linked to a source location. So, +when generating prologue instructions we have to make sure that we don't +emit source location information until the 'real' function body begins. For +this reason, source location emission is disabled by default for any new +function being codegened and is only activated after a call to the third +function from the list above, `start_emitting_source_locations()`. This +function should be called right before regularly starting to codegen the +top-level block of the given function. + +There is one exception to the above rule: `llvm.dbg.declare` instruction +must be linked to the source location of the variable being declared. For +function parameters these `llvm.dbg.declare` instructions typically occur +in the middle of the prologue, however, they are ignored by LLVM's prologue +detection. The `create_argument_metadata()` and related functions take care +of linking the `llvm.dbg.declare` instructions to the correct source +locations even while source location emission is still disabled, so there +is no need to do anything special with source location handling here. + +## Unique Type Identification + +In order for link-time optimization to work properly, LLVM needs a unique +type identifier that tells it across compilation units which types are the +same as others. This type identifier is created by +`TypeMap::get_unique_type_id_of_type()` using the following algorithm: + +(1) Primitive types have their name as ID +(2) Structs, enums and traits have a multipart identifier + + (1) The first part is the SVH (strict version hash) of the crate they + were originally defined in + + (2) The second part is the ast::NodeId of the definition in their + original crate + + (3) The final part is a concatenation of the type IDs of their concrete + type arguments if they are generic types. + +(3) Tuple-, pointer and function types are structurally identified, which + means that they are equivalent if their component types are equivalent + (i.e., (i32, i32) is the same regardless in which crate it is used). + +This algorithm also provides a stable ID for types that are defined in one +crate but instantiated from metadata within another crate. We just have to +take care to always map crate and `NodeId`s back to the original crate +context. + +As a side-effect these unique type IDs also help to solve a problem arising +from lifetime parameters. Since lifetime parameters are completely omitted +in debuginfo, more than one `Ty` instance may map to the same debuginfo +type metadata, that is, some struct `Struct<'a>` may have N instantiations +with different concrete substitutions for `'a`, and thus there will be N +`Ty` instances for the type `Struct<'a>` even though it is not generic +otherwise. Unfortunately this means that we cannot use `ty::type_id()` as +cheap identifier for type metadata -- we have done this in the past, but it +led to unnecessary metadata duplication in the best case and LLVM +assertions in the worst. However, the unique type ID as described above +*can* be used as identifier. Since it is comparatively expensive to +construct, though, `ty::type_id()` is still used additionally as an +optimization for cases where the exact same type has been seen before +(which is most of the time). diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs deleted file mode 100644 index 10dd590652949..0000000000000 --- a/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs +++ /dev/null @@ -1,179 +0,0 @@ -//! # Debug Info Module -//! -//! This module serves the purpose of generating debug symbols. We use LLVM's -//! [source level debugging](https://llvm.org/docs/SourceLevelDebugging.html) -//! features for generating the debug information. The general principle is -//! this: -//! -//! Given the right metadata in the LLVM IR, the LLVM code generator is able to -//! create DWARF debug symbols for the given code. The -//! [metadata](https://llvm.org/docs/LangRef.html#metadata-type) is structured -//! much like DWARF *debugging information entries* (DIE), representing type -//! information such as datatype layout, function signatures, block layout, -//! variable location and scope information, etc. It is the purpose of this -//! module to generate correct metadata and insert it into the LLVM IR. -//! -//! As the exact format of metadata trees may change between different LLVM -//! versions, we now use LLVM -//! [DIBuilder](https://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) -//! to create metadata where possible. This will hopefully ease the adaption of -//! this module to future LLVM versions. -//! -//! The public API of the module is a set of functions that will insert the -//! correct metadata into the LLVM IR when called with the right parameters. -//! The module is thus driven from an outside client with functions like -//! `debuginfo::create_local_var_metadata(bx: block, local: &ast::local)`. -//! -//! Internally the module will try to reuse already created metadata by -//! utilizing a cache. The way to get a shared metadata node when needed is -//! thus to just call the corresponding function in this module: -//! -//! let file_metadata = file_metadata(cx, file); -//! -//! The function will take care of probing the cache for an existing node for -//! that exact file path. -//! -//! All private state used by the module is stored within either the -//! CrateDebugContext struct (owned by the CodegenCx) or the -//! FunctionDebugContext (owned by the FunctionCx). -//! -//! This file consists of three conceptual sections: -//! 1. The public interface of the module -//! 2. Module-internal metadata creation functions -//! 3. Minor utility functions -//! -//! -//! ## Recursive Types -//! -//! Some kinds of types, such as structs and enums can be recursive. That means -//! that the type definition of some type X refers to some other type which in -//! turn (transitively) refers to X. This introduces cycles into the type -//! referral graph. A naive algorithm doing an on-demand, depth-first traversal -//! of this graph when describing types, can get trapped in an endless loop -//! when it reaches such a cycle. -//! -//! For example, the following simple type for a singly-linked list... -//! -//! ``` -//! struct List { -//! value: i32, -//! tail: Option>, -//! } -//! ``` -//! -//! will generate the following callstack with a naive DFS algorithm: -//! -//! ``` -//! describe(t = List) -//! describe(t = i32) -//! describe(t = Option>) -//! describe(t = Box) -//! describe(t = List) // at the beginning again... -//! ... -//! ``` -//! -//! To break cycles like these, we use "forward declarations". That is, when -//! the algorithm encounters a possibly recursive type (any struct or enum), it -//! immediately creates a type description node and inserts it into the cache -//! *before* describing the members of the type. This type description is just -//! a stub (as type members are not described and added to it yet) but it -//! allows the algorithm to already refer to the type. After the stub is -//! inserted into the cache, the algorithm continues as before. If it now -//! encounters a recursive reference, it will hit the cache and does not try to -//! describe the type anew. -//! -//! This behavior is encapsulated in the 'RecursiveTypeDescription' enum, -//! which represents a kind of continuation, storing all state needed to -//! continue traversal at the type members after the type has been registered -//! with the cache. (This implementation approach might be a tad over- -//! engineered and may change in the future) -//! -//! -//! ## Source Locations and Line Information -//! -//! In addition to data type descriptions the debugging information must also -//! allow to map machine code locations back to source code locations in order -//! to be useful. This functionality is also handled in this module. The -//! following functions allow to control source mappings: -//! -//! + set_source_location() -//! + clear_source_location() -//! + start_emitting_source_locations() -//! -//! `set_source_location()` allows to set the current source location. All IR -//! instructions created after a call to this function will be linked to the -//! given source location, until another location is specified with -//! `set_source_location()` or the source location is cleared with -//! `clear_source_location()`. In the later case, subsequent IR instruction -//! will not be linked to any source location. As you can see, this is a -//! stateful API (mimicking the one in LLVM), so be careful with source -//! locations set by previous calls. It's probably best to not rely on any -//! specific state being present at a given point in code. -//! -//! One topic that deserves some extra attention is *function prologues*. At -//! the beginning of a function's machine code there are typically a few -//! instructions for loading argument values into allocas and checking if -//! there's enough stack space for the function to execute. This *prologue* is -//! not visible in the source code and LLVM puts a special PROLOGUE END marker -//! into the line table at the first non-prologue instruction of the function. -//! In order to find out where the prologue ends, LLVM looks for the first -//! instruction in the function body that is linked to a source location. So, -//! when generating prologue instructions we have to make sure that we don't -//! emit source location information until the 'real' function body begins. For -//! this reason, source location emission is disabled by default for any new -//! function being codegened and is only activated after a call to the third -//! function from the list above, `start_emitting_source_locations()`. This -//! function should be called right before regularly starting to codegen the -//! top-level block of the given function. -//! -//! There is one exception to the above rule: `llvm.dbg.declare` instruction -//! must be linked to the source location of the variable being declared. For -//! function parameters these `llvm.dbg.declare` instructions typically occur -//! in the middle of the prologue, however, they are ignored by LLVM's prologue -//! detection. The `create_argument_metadata()` and related functions take care -//! of linking the `llvm.dbg.declare` instructions to the correct source -//! locations even while source location emission is still disabled, so there -//! is no need to do anything special with source location handling here. -//! -//! ## Unique Type Identification -//! -//! In order for link-time optimization to work properly, LLVM needs a unique -//! type identifier that tells it across compilation units which types are the -//! same as others. This type identifier is created by -//! `TypeMap::get_unique_type_id_of_type()` using the following algorithm: -//! -//! (1) Primitive types have their name as ID -//! (2) Structs, enums and traits have a multipart identifier -//! -//! (1) The first part is the SVH (strict version hash) of the crate they -//! were originally defined in -//! -//! (2) The second part is the ast::NodeId of the definition in their -//! original crate -//! -//! (3) The final part is a concatenation of the type IDs of their concrete -//! type arguments if they are generic types. -//! -//! (3) Tuple-, pointer and function types are structurally identified, which -//! means that they are equivalent if their component types are equivalent -//! (i.e., (i32, i32) is the same regardless in which crate it is used). -//! -//! This algorithm also provides a stable ID for types that are defined in one -//! crate but instantiated from metadata within another crate. We just have to -//! take care to always map crate and `NodeId`s back to the original crate -//! context. -//! -//! As a side-effect these unique type IDs also help to solve a problem arising -//! from lifetime parameters. Since lifetime parameters are completely omitted -//! in debuginfo, more than one `Ty` instance may map to the same debuginfo -//! type metadata, that is, some struct `Struct<'a>` may have N instantiations -//! with different concrete substitutions for `'a`, and thus there will be N -//! `Ty` instances for the type `Struct<'a>` even though it is not generic -//! otherwise. Unfortunately this means that we cannot use `ty::type_id()` as -//! cheap identifier for type metadata -- we have done this in the past, but it -//! led to unnecessary metadata duplication in the best case and LLVM -//! assertions in the worst. However, the unique type ID as described above -//! *can* be used as identifier. Since it is comparatively expensive to -//! construct, though, `ty::type_id()` is still used additionally as an -//! optimization for cases where the exact same type has been seen before -//! (which is most of the time). diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 440e4d505fc92..abb87cb36568e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -1,5 +1,4 @@ -// See doc.rs for documentation. -mod doc; +#![doc = include_str!("doc.md")] use rustc_codegen_ssa::mir::debuginfo::VariableKind::*; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index d11c1592f99d1..146c08337fc77 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -8,6 +8,7 @@ #![feature(bool_to_option)] #![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] +#![feature(extended_key_value_attributes)] #![feature(extern_types)] #![feature(in_band_lifetimes)] #![feature(nll)] From dc240faed5ec55968b2468002d2139e1e44d873b Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 20 Mar 2021 14:21:02 -0700 Subject: [PATCH 07/15] Cleanup LLVM debuginfo module docs * Use Markdown list syntax and unindent a bit to prevent Markdown interpreting the nested lists as code blocks * A few more small typographical cleanups --- .../rustc_codegen_llvm/src/debuginfo/doc.md | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/doc.md b/compiler/rustc_codegen_llvm/src/debuginfo/doc.md index 485b124ab06ba..f983d09203904 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/doc.md +++ b/compiler/rustc_codegen_llvm/src/debuginfo/doc.md @@ -96,9 +96,9 @@ allow to map machine code locations back to source code locations in order to be useful. This functionality is also handled in this module. The following functions allow to control source mappings: -+ set_source_location() -+ clear_source_location() -+ start_emitting_source_locations() ++ `set_source_location()` ++ `clear_source_location()` ++ `start_emitting_source_locations()` `set_source_location()` allows to set the current source location. All IR instructions created after a call to this function will be linked to the @@ -142,21 +142,22 @@ type identifier that tells it across compilation units which types are the same as others. This type identifier is created by `TypeMap::get_unique_type_id_of_type()` using the following algorithm: -(1) Primitive types have their name as ID -(2) Structs, enums and traits have a multipart identifier +1. Primitive types have their name as ID - (1) The first part is the SVH (strict version hash) of the crate they - were originally defined in +2. Structs, enums and traits have a multipart identifier - (2) The second part is the ast::NodeId of the definition in their - original crate + 1. The first part is the SVH (strict version hash) of the crate they + were originally defined in - (3) The final part is a concatenation of the type IDs of their concrete - type arguments if they are generic types. + 2. The second part is the ast::NodeId of the definition in their + original crate -(3) Tuple-, pointer and function types are structurally identified, which - means that they are equivalent if their component types are equivalent - (i.e., (i32, i32) is the same regardless in which crate it is used). + 3. The final part is a concatenation of the type IDs of their concrete + type arguments if they are generic types. + +3. Tuple-, pointer-, and function types are structurally identified, which + means that they are equivalent if their component types are equivalent + (i.e., `(i32, i32)` is the same regardless in which crate it is used). This algorithm also provides a stable ID for types that are defined in one crate but instantiated from metadata within another crate. We just have to From 4002171315bb294d9c518dd1f053072ced66e282 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 21 Mar 2021 12:10:34 -0400 Subject: [PATCH 08/15] Download a more recent LLVM version if `src/version` is modified When bumping the bootstrap version, the name of the generated LLVM shared object file is changed, even though it's the same contents as before. If bootstrap tries to use an older version, it will get linking errors: ``` Building rustdoc for stage1 (x86_64-unknown-linux-gnu) Compiling rustdoc-tool v0.0.0 (/home/joshua/rustc/src/tools/rustdoc) error: linking with `cc` failed: exit code: 1 | = note: "cc" "-Wl,--as-needed" ... lots of args ... = note: /usr/bin/ld: cannot find -lLLVM-12-rust-1.53.0-nightly clang: error: linker command failed with exit code 1 (use -v to see invocation) error: could not compile `rustdoc-tool` ``` --- src/bootstrap/bootstrap.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 3e7d1d54f1284..075756b73ba82 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -463,6 +463,8 @@ def download_stage0(self): "--", "{}/src/llvm-project".format(top_level), "{}/src/bootstrap/download-ci-llvm-stamp".format(top_level), + # the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` + "{}/src/version".format(top_level) ]).decode(sys.getdefaultencoding()).strip() llvm_assertions = self.get_toml('assertions', 'llvm') == 'true' llvm_root = self.llvm_root() From 0acdada18b38f0f0e45836cbc20663e32216f211 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 21 Mar 2021 17:49:14 +0100 Subject: [PATCH 09/15] Bump osstring_ascii stabilization version to 1.53.0. --- library/std/src/ffi/os_str.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 5e0ce0358f782..b407714c380a9 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -723,7 +723,7 @@ impl OsStr { /// /// assert_eq!("grÜße, jÜrgen ❤", s); /// ``` - #[stable(feature = "osstring_ascii", since = "1.52.0")] + #[stable(feature = "osstring_ascii", since = "1.53.0")] #[inline] pub fn make_ascii_lowercase(&mut self) { self.inner.make_ascii_lowercase() @@ -748,7 +748,7 @@ impl OsStr { /// /// assert_eq!("GRüßE, JüRGEN ❤", s); /// ``` - #[stable(feature = "osstring_ascii", since = "1.52.0")] + #[stable(feature = "osstring_ascii", since = "1.53.0")] #[inline] pub fn make_ascii_uppercase(&mut self) { self.inner.make_ascii_uppercase() @@ -770,7 +770,7 @@ impl OsStr { /// /// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase()); /// ``` - #[stable(feature = "osstring_ascii", since = "1.52.0")] + #[stable(feature = "osstring_ascii", since = "1.53.0")] pub fn to_ascii_lowercase(&self) -> OsString { OsString::from_inner(self.inner.to_ascii_lowercase()) } @@ -791,7 +791,7 @@ impl OsStr { /// /// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase()); /// ``` - #[stable(feature = "osstring_ascii", since = "1.52.0")] + #[stable(feature = "osstring_ascii", since = "1.53.0")] pub fn to_ascii_uppercase(&self) -> OsString { OsString::from_inner(self.inner.to_ascii_uppercase()) } @@ -809,7 +809,7 @@ impl OsStr { /// assert!(ascii.is_ascii()); /// assert!(!non_ascii.is_ascii()); /// ``` - #[stable(feature = "osstring_ascii", since = "1.52.0")] + #[stable(feature = "osstring_ascii", since = "1.53.0")] #[inline] pub fn is_ascii(&self) -> bool { self.inner.is_ascii() @@ -829,7 +829,7 @@ impl OsStr { /// assert!(OsString::from("Ferrös").eq_ignore_ascii_case("FERRöS")); /// assert!(!OsString::from("Ferrös").eq_ignore_ascii_case("FERRÖS")); /// ``` - #[stable(feature = "osstring_ascii", since = "1.52.0")] + #[stable(feature = "osstring_ascii", since = "1.53.0")] pub fn eq_ignore_ascii_case>(&self, other: S) -> bool { self.inner.eq_ignore_ascii_case(&other.as_ref().inner) } From 236c0cf103aa485db1748587ad87213943bcfb33 Mon Sep 17 00:00:00 2001 From: The8472 Date: Sun, 31 Jan 2021 21:12:43 +0100 Subject: [PATCH 10/15] implement TrustedLen and TrustedRandomAccess for VecDeque iterators --- .../src/collections/vec_deque/into_iter.rs | 32 ++++++++++++++++++- .../alloc/src/collections/vec_deque/iter.rs | 24 +++++++++++++- .../src/collections/vec_deque/iter_mut.rs | 24 +++++++++++++- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index 465b058cd98e9..1c635dd4f27fa 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -1,5 +1,5 @@ use core::fmt; -use core::iter::FusedIterator; +use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; use super::VecDeque; @@ -36,6 +36,22 @@ impl Iterator for IntoIter { let len = self.inner.len(); (len, Some(len)) } + + #[inline] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + // Safety: The TrustedRandomAccess contract requires that callers only pass an index + // that is in bounds. + // Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even + // multiple repeated reads of the same index would be safe and the + // values are !Drop, thus won't suffer from double drops. + unsafe { + let idx = self.inner.wrap_add(self.inner.tail, idx); + self.inner.buffer_read(idx) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -55,3 +71,17 @@ impl ExactSizeIterator for IntoIter { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IntoIter {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +// T: Copy as approximation for !Drop since get_unchecked does not update the pointers +// and thus we can't implement drop-handling +unsafe impl TrustedRandomAccess for IntoIter +where + T: Copy, +{ + const MAY_HAVE_SIDE_EFFECT: bool = false; +} diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index ad31b991cb6c3..e4cfb3acdfd5c 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -1,5 +1,5 @@ use core::fmt; -use core::iter::FusedIterator; +use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; use core::ops::Try; use super::{count, wrap_index, RingSlices}; @@ -101,6 +101,19 @@ impl<'a, T> Iterator for Iter<'a, T> { fn last(mut self) -> Option<&'a T> { self.next_back() } + + #[inline] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + // Safety: The TrustedRandomAccess contract requires that callers only pass an index + // that is in bounds. + unsafe { + let idx = wrap_index(self.tail.wrapping_add(idx), self.ring.len()); + self.ring.get_unchecked(idx) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -157,3 +170,12 @@ impl ExactSizeIterator for Iter<'_, T> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Iter<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Iter<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Iter<'_, T> { + const MAY_HAVE_SIDE_EFFECT: bool = false; +} diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 3d0c3094e26cd..9493676e66bc8 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -1,5 +1,5 @@ use core::fmt; -use core::iter::FusedIterator; +use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; use core::marker::PhantomData; use super::{count, wrap_index, RingSlices}; @@ -87,6 +87,19 @@ impl<'a, T> Iterator for IterMut<'a, T> { fn last(mut self) -> Option<&'a mut T> { self.next_back() } + + #[inline] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + // Safety: The TrustedRandomAccess contract requires that callers only pass an index + // that is in bounds. + unsafe { + let idx = wrap_index(self.tail.wrapping_add(idx), self.ring.len()); + &mut *self.ring.get_unchecked_mut(idx) + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -126,3 +139,12 @@ impl ExactSizeIterator for IterMut<'_, T> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IterMut<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IterMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for IterMut<'_, T> { + const MAY_HAVE_SIDE_EFFECT: bool = false; +} From 1438207c3d150ce42804e857537b12082c68c79b Mon Sep 17 00:00:00 2001 From: The8472 Date: Sun, 31 Jan 2021 21:13:04 +0100 Subject: [PATCH 11/15] use BITS constant --- library/alloc/src/collections/vec_deque/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 7a0de74eb239d..d3e70991ad518 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -58,7 +58,7 @@ mod tests; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 -const MAXIMUM_ZST_CAPACITY: usize = 1 << (core::mem::size_of::() * 8 - 1); // Largest possible power of two +const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible power of two /// A double-ended queue implemented with a growable ring buffer. /// From 895d7a9a096aab4690a032cee28f57f4b8a0e9ac Mon Sep 17 00:00:00 2001 From: The8472 Date: Sun, 31 Jan 2021 21:15:18 +0100 Subject: [PATCH 12/15] implement TrustedRandomAccess for Ranges over int types --- library/core/src/iter/range.rs | 43 +++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index cc80e06decd48..4b293c596e7af 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -3,7 +3,7 @@ use crate::convert::TryFrom; use crate::mem; use crate::ops::{self, Try}; -use super::{FusedIterator, TrustedLen}; +use super::{FusedIterator, TrustedLen, TrustedRandomAccess}; /// Objects that have a notion of *successor* and *predecessor* operations. /// @@ -493,6 +493,18 @@ macro_rules! range_exact_iter_impl { )*) } +/// Safety: This macro must only be used on types that are `Copy` and result in ranges +/// which have an exact `size_hint()` where the upper bound must not be `None`. +macro_rules! unsafe_range_trusted_random_access_impl { + ($($t:ty)*) => ($( + #[doc(hidden)] + #[unstable(feature = "trusted_random_access", issue = "none")] + unsafe impl TrustedRandomAccess for ops::Range<$t> { + const MAY_HAVE_SIDE_EFFECT: bool = false; + } + )*) +} + macro_rules! range_incl_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "inclusive_range", since = "1.26.0")] @@ -553,6 +565,18 @@ impl Iterator for ops::Range { fn max(mut self) -> Option { self.next_back() } + + #[inline] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: The TrustedRandomAccess contract requires that callers only pass an index + // that is in bounds. + // Additionally Self: TrustedRandomAccess is only implemented for Copy types + // which means even repeated reads of the same index would be safe. + unsafe { Step::forward_unchecked(self.start.clone(), idx) } + } } // These macros generate `ExactSizeIterator` impls for various range types. @@ -574,6 +598,23 @@ range_exact_iter_impl! { u32 i32 } + +unsafe_range_trusted_random_access_impl! { + usize u8 u16 + isize i8 i16 +} + +#[cfg(target_pointer_width = "32")] +unsafe_range_trusted_random_access_impl! { + u32 i32 +} + +#[cfg(target_pointer_width = "64")] +unsafe_range_trusted_random_access_impl! { + u32 i32 + u64 i64 +} + range_incl_exact_iter_impl! { u8 i8 From 08a1dd287d371b8df7fbef610e66bc925b3eea0b Mon Sep 17 00:00:00 2001 From: The8472 Date: Sun, 31 Jan 2021 21:16:08 +0100 Subject: [PATCH 13/15] implement TrustedRandomAccess for array::IntoIter --- library/core/src/array/iter.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 4472fba26b99b..f82454addd09a 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -2,7 +2,7 @@ use crate::{ fmt, - iter::{ExactSizeIterator, FusedIterator, TrustedLen}, + iter::{ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess}, mem::{self, MaybeUninit}, ops::Range, ptr, @@ -130,6 +130,18 @@ impl Iterator for IntoIter { fn last(mut self) -> Option { self.next_back() } + + #[inline] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: Callers are only allowed to pass an index that is in bounds + // Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even + // multiple repeated reads of the same index would be safe and the + // values aree !Drop, thus won't suffer from double drops. + unsafe { self.data.get_unchecked(self.alive.start + idx).assume_init_read() } + } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] @@ -184,6 +196,17 @@ impl FusedIterator for IntoIter {} #[stable(feature = "array_value_iter_impls", since = "1.40.0")] unsafe impl TrustedLen for IntoIter {} +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +// T: Copy as approximation for !Drop since get_unchecked does not update the pointers +// and thus we can't implement drop-handling +unsafe impl TrustedRandomAccess for IntoIter +where + T: Copy, +{ + const MAY_HAVE_SIDE_EFFECT: bool = false; +} + #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl Clone for IntoIter { fn clone(&self) -> Self { From bfae41d7b01f016fab65ed4be9ecdb5c31a97f09 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 20 Mar 2021 20:00:25 -0700 Subject: [PATCH 14/15] Fix ICE with `use clippy::a::b;` --- compiler/rustc_resolve/src/imports.rs | 4 ++-- src/test/ui/imports/tool-mod-child.rs | 7 ++++++ src/test/ui/imports/tool-mod-child.stderr | 28 +++++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/imports/tool-mod-child.rs create mode 100644 src/test/ui/imports/tool-mod-child.stderr diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 61f4c00a4ca42..26858915f45a0 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -955,14 +955,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } return None; } - PathResult::NonModule(path_res) if path_res.base_res() == Res::Err => { + PathResult::NonModule(_) => { if no_ambiguity { assert!(import.imported_module.get().is_none()); } // The error was already reported earlier. return None; } - PathResult::Indeterminate | PathResult::NonModule(..) => unreachable!(), + PathResult::Indeterminate => unreachable!(), }; let (ident, target, source_bindings, target_bindings, type_ns_only) = match import.kind { diff --git a/src/test/ui/imports/tool-mod-child.rs b/src/test/ui/imports/tool-mod-child.rs new file mode 100644 index 0000000000000..4581dc2e2ad88 --- /dev/null +++ b/src/test/ui/imports/tool-mod-child.rs @@ -0,0 +1,7 @@ +use clippy::a; //~ ERROR unresolved import `clippy` +use clippy::a::b; //~ ERROR failed to resolve: maybe a missing crate `clippy`? + +use rustdoc::a; //~ ERROR unresolved import `rustdoc` +use rustdoc::a::b; //~ ERROR failed to resolve: maybe a missing crate `rustdoc`? + +fn main() {} diff --git a/src/test/ui/imports/tool-mod-child.stderr b/src/test/ui/imports/tool-mod-child.stderr new file mode 100644 index 0000000000000..efab4f6a74f83 --- /dev/null +++ b/src/test/ui/imports/tool-mod-child.stderr @@ -0,0 +1,28 @@ +error[E0433]: failed to resolve: maybe a missing crate `clippy`? + --> $DIR/tool-mod-child.rs:2:5 + | +LL | use clippy::a::b; + | ^^^^^^ maybe a missing crate `clippy`? + +error[E0432]: unresolved import `clippy` + --> $DIR/tool-mod-child.rs:1:5 + | +LL | use clippy::a; + | ^^^^^^ maybe a missing crate `clippy`? + +error[E0433]: failed to resolve: maybe a missing crate `rustdoc`? + --> $DIR/tool-mod-child.rs:5:5 + | +LL | use rustdoc::a::b; + | ^^^^^^^ maybe a missing crate `rustdoc`? + +error[E0432]: unresolved import `rustdoc` + --> $DIR/tool-mod-child.rs:4:5 + | +LL | use rustdoc::a; + | ^^^^^^^ maybe a missing crate `rustdoc`? + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`. From 2bd7c1b5de8bdbc7cafa2ee496ef9d80381fb0dd Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 21 Mar 2021 23:01:28 +0100 Subject: [PATCH 15/15] Bump slice_iter_mut_as_slice stable version. --- library/core/src/slice/iter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 8f404d7153019..25cd8e6e29d3c 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -298,13 +298,13 @@ impl<'a, T> IterMut<'a, T> { /// // Now `as_slice` returns "[2, 3]": /// assert_eq!(iter.as_slice(), &[2, 3]); /// ``` - #[stable(feature = "slice_iter_mut_as_slice", since = "1.52.0")] + #[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")] pub fn as_slice(&self) -> &[T] { self.make_slice() } } -#[stable(feature = "slice_iter_mut_as_slice", since = "1.52.0")] +#[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")] impl AsRef<[T]> for IterMut<'_, T> { fn as_ref(&self) -> &[T] { self.as_slice()