提交 142c8318 编写于 作者: B bors

Auto merge of #83360 - Dylan-DPC:rollup-17xulpv, r=Dylan-DPC

Rollup of 9 pull requests

Successful merges:

 - #80193 (stabilize `feature(osstring_ascii)`)
 - #80771 (Make NonNull::as_ref (and friends) return refs with unbound lifetimes)
 - #81607 (Implement TrustedLen and TrustedRandomAccess for Range<integer>, array::IntoIter, VecDequeue's iterators)
 - #82554 (Fix invalid slice access in String::retain)
 - #82686 (Move `std::sys::unix::platform` to `std::sys::unix::ext`)
 - #82771 (slice: Stabilize IterMut::as_slice.)
 - #83329 (Cleanup LLVM debuginfo module docs)
 - #83336 (Fix ICE with `use clippy::a::b;`)
 - #83350 (Download a more recent LLVM version if `src/version` is modified)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
# 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<Box<List>>,
}
```
will generate the following callstack with a naive DFS algorithm:
```
describe(t = List)
describe(t = i32)
describe(t = Option<Box<List>>)
describe(t = Box<List>)
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).
//! # 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<Box<List>>,
//! }
//! ```
//!
//! will generate the following callstack with a naive DFS algorithm:
//!
//! ```
//! describe(t = List)
//! describe(t = i32)
//! describe(t = Option<Box<List>>)
//! describe(t = Box<List>)
//! 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).
// See doc.rs for documentation.
mod doc;
#![doc = include_str!("doc.md")]
use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
......
......@@ -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)]
......
......@@ -955,14 +955,14 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
}
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 {
......
use core::fmt;
use core::iter::FusedIterator;
use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess};
use super::VecDeque;
......@@ -36,6 +36,22 @@ fn size_hint(&self) -> (usize, Option<usize>) {
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 @@ fn is_empty(&self) -> bool {
#[stable(feature = "fused", since = "1.26.0")]
impl<T> FusedIterator for IntoIter<T> {}
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<T> TrustedLen for IntoIter<T> {}
#[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<T> TrustedRandomAccess for IntoIter<T>
where
T: Copy,
{
const MAY_HAVE_SIDE_EFFECT: bool = false;
}
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 @@ fn nth(&mut self, n: usize) -> Option<Self::Item> {
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 @@ fn is_empty(&self) -> bool {
#[stable(feature = "fused", since = "1.26.0")]
impl<T> FusedIterator for Iter<'_, T> {}
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<T> TrustedLen for Iter<'_, T> {}
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<T> TrustedRandomAccess for Iter<'_, T> {
const MAY_HAVE_SIDE_EFFECT: bool = false;
}
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 @@ fn nth(&mut self, n: usize) -> Option<Self::Item> {
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 @@ fn is_empty(&self) -> bool {
#[stable(feature = "fused", since = "1.26.0")]
impl<T> FusedIterator for IterMut<'_, T> {}
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<T> TrustedLen for IterMut<'_, T> {}
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<T> TrustedRandomAccess for IterMut<'_, T> {
const MAY_HAVE_SIDE_EFFECT: bool = false;
}
......@@ -58,7 +58,7 @@
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::<usize>() * 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.
///
......
......@@ -1289,37 +1289,44 @@ pub fn retain<F>(&mut self, mut f: F)
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.
......
......@@ -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 @@ fn count(self) -> usize {
fn last(mut self) -> Option<Self::Item> {
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<T, const N: usize> FusedIterator for IntoIter<T, N> {}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}
#[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<T, const N: usize> TrustedRandomAccess for IntoIter<T, N>
where
T: Copy,
{
const MAY_HAVE_SIDE_EFFECT: bool = false;
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
fn clone(&self) -> Self {
......
......@@ -3,7 +3,7 @@
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 @@ impl ExactSizeIterator for ops::Range<$t> { }
)*)
}
/// 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 @@ fn min(mut self) -> Option<A> {
fn max(mut self) -> Option<A> {
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 @@ fn max(mut self) -> Option<A> {
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
......
......@@ -110,7 +110,7 @@ pub const fn dangling() -> Self {
/// [the module documentation]: crate::ptr#safety
#[inline]
#[unstable(feature = "ptr_as_uninit", issue = "75402")]
pub unsafe fn as_uninit_ref(&self) -> &MaybeUninit<T> {
pub unsafe fn as_uninit_ref<'a>(&self) -> &'a MaybeUninit<T> {
// SAFETY: the caller must guarantee that `self` meets all the
// requirements for a reference.
unsafe { &*self.cast().as_ptr() }
......@@ -142,7 +142,7 @@ pub unsafe fn as_uninit_ref(&self) -> &MaybeUninit<T> {
/// [the module documentation]: crate::ptr#safety
#[inline]
#[unstable(feature = "ptr_as_uninit", issue = "75402")]
pub unsafe fn as_uninit_mut(&mut self) -> &mut MaybeUninit<T> {
pub unsafe fn as_uninit_mut<'a>(&mut self) -> &'a mut MaybeUninit<T> {
// SAFETY: the caller must guarantee that `self` meets all the
// requirements for a reference.
unsafe { &mut *self.cast().as_ptr() }
......@@ -244,7 +244,7 @@ pub const fn as_ptr(self) -> *mut T {
/// [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() }
......@@ -280,7 +280,7 @@ pub unsafe fn as_ref(&self) -> &T {
/// [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() }
......@@ -427,7 +427,7 @@ pub const fn as_mut_ptr(self) -> *mut T {
/// [valid]: crate::ptr#safety
#[inline]
#[unstable(feature = "ptr_as_uninit", issue = "75402")]
pub unsafe fn as_uninit_slice(&self) -> &[MaybeUninit<T>] {
pub unsafe fn as_uninit_slice<'a>(&self) -> &'a [MaybeUninit<T>] {
// SAFETY: the caller must uphold the safety contract for `as_uninit_slice`.
unsafe { slice::from_raw_parts(self.cast().as_ptr(), self.len()) }
}
......@@ -488,7 +488,7 @@ pub unsafe fn as_uninit_slice(&self) -> &[MaybeUninit<T>] {
/// ```
#[inline]
#[unstable(feature = "ptr_as_uninit", issue = "75402")]
pub unsafe fn as_uninit_slice_mut(&self) -> &mut [MaybeUninit<T>] {
pub unsafe fn as_uninit_slice_mut<'a>(&self) -> &'a mut [MaybeUninit<T>] {
// 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()) }
}
......
......@@ -286,7 +286,6 @@ pub fn into_slice(self) -> &'a mut [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 @@ pub fn into_slice(self) -> &'a mut [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.53.0")]
pub fn as_slice(&self) -> &[T] {
self.make_slice()
}
}
#[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")]
impl<T> 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
......
......@@ -716,7 +716,6 @@ pub(crate) fn bytes(&self) -> &[u8] {
/// # Examples
///
/// ```
/// #![feature(osstring_ascii)]
/// use std::ffi::OsString;
///
/// let mut s = OsString::from("GRÜßE, JÜRGEN ❤");
......@@ -725,7 +724,7 @@ pub(crate) fn bytes(&self) -> &[u8] {
///
/// assert_eq!("grÜße, jÜrgen ❤", s);
/// ```
#[unstable(feature = "osstring_ascii", issue = "70516")]
#[stable(feature = "osstring_ascii", since = "1.53.0")]
#[inline]
pub fn make_ascii_lowercase(&mut self) {
self.inner.make_ascii_lowercase()
......@@ -742,7 +741,6 @@ pub fn make_ascii_lowercase(&mut self) {
/// # Examples
///
/// ```
/// #![feature(osstring_ascii)]
/// use std::ffi::OsString;
///
/// let mut s = OsString::from("Grüße, Jürgen ❤");
......@@ -751,7 +749,7 @@ pub fn make_ascii_lowercase(&mut self) {
///
/// assert_eq!("GRüßE, JüRGEN ❤", s);
/// ```
#[unstable(feature = "osstring_ascii", issue = "70516")]
#[stable(feature = "osstring_ascii", since = "1.53.0")]
#[inline]
pub fn make_ascii_uppercase(&mut self) {
self.inner.make_ascii_uppercase()
......@@ -768,13 +766,12 @@ pub fn make_ascii_uppercase(&mut self) {
/// # 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.53.0")]
pub fn to_ascii_lowercase(&self) -> OsString {
OsString::from_inner(self.inner.to_ascii_lowercase())
}
......@@ -790,13 +787,12 @@ pub fn to_ascii_lowercase(&self) -> OsString {
/// # 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.53.0")]
pub fn to_ascii_uppercase(&self) -> OsString {
OsString::from_inner(self.inner.to_ascii_uppercase())
}
......@@ -806,7 +802,6 @@ pub fn to_ascii_uppercase(&self) -> OsString {
/// # Examples
///
/// ```
/// #![feature(osstring_ascii)]
/// use std::ffi::OsString;
///
/// let ascii = OsString::from("hello!\n");
......@@ -815,7 +810,7 @@ pub fn to_ascii_uppercase(&self) -> OsString {
/// assert!(ascii.is_ascii());
/// assert!(!non_ascii.is_ascii());
/// ```
#[unstable(feature = "osstring_ascii", issue = "70516")]
#[stable(feature = "osstring_ascii", since = "1.53.0")]
#[inline]
pub fn is_ascii(&self) -> bool {
self.inner.is_ascii()
......@@ -829,14 +824,13 @@ pub fn is_ascii(&self) -> bool {
/// # 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.53.0")]
pub fn eq_ignore_ascii_case<S: AsRef<OsStr>>(&self, other: S) -> bool {
self.inner.eq_ignore_ascii_case(&other.as_ref().inner)
}
......
......@@ -70,8 +70,6 @@
#[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;
}
......
......@@ -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)]
......
......@@ -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;
......
......@@ -24,10 +24,10 @@
#[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};
......@@ -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;
......
......@@ -463,6 +463,8 @@ class RustBuild(object):
"--",
"{}/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()
......
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() {}
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`.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册