mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 22:16:53 +00:00
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:🅰️:b;`) - #83350 (Download a more recent LLVM version if `src/version` is modified) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
142c831861
180
compiler/rustc_codegen_llvm/src/debuginfo/doc.md
Normal file
180
compiler/rustc_codegen_llvm/src/debuginfo/doc.md
Normal file
@ -0,0 +1,180 @@
|
||||
# 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).
|
@ -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<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).
|
@ -1,5 +1,4 @@
|
||||
// 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 @@ 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 {
|
||||
|
@ -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<T> Iterator for IntoIter<T> {
|
||||
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<T> ExactSizeIterator for IntoIter<T> {
|
||||
|
||||
#[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;
|
||||
}
|
||||
|
@ -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<T> ExactSizeIterator for Iter<'_, T> {
|
||||
|
||||
#[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;
|
||||
}
|
||||
|
@ -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<T> ExactSizeIterator for IterMut<'_, T> {
|
||||
|
||||
#[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 @@ 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::<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 @@ impl String {
|
||||
where
|
||||
F: FnMut(char) -> bool,
|
||||
{
|
||||
let len = self.len();
|
||||
let mut del_bytes = 0;
|
||||
let mut idx = 0;
|
||||
|
||||
unsafe {
|
||||
self.vec.set_len(0);
|
||||
struct SetLenOnDrop<'a> {
|
||||
s: &'a mut String,
|
||||
idx: usize,
|
||||
del_bytes: usize,
|
||||
}
|
||||
|
||||
while idx < len {
|
||||
let ch = unsafe { self.get_unchecked(idx..len).chars().next().unwrap() };
|
||||
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) };
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
|
||||
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::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<A: Step> Iterator for ops::Range<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 @@ 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
|
||||
|
@ -110,7 +110,7 @@ impl<T: Sized> NonNull<T> {
|
||||
/// [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 @@ impl<T: Sized> NonNull<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 @@ impl<T: ?Sized> NonNull<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 @@ impl<T: ?Sized> NonNull<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 @@ impl<T> NonNull<[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 @@ impl<T> NonNull<[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 @@ 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.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 @@ impl OsStr {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(osstring_ascii)]
|
||||
/// use std::ffi::OsString;
|
||||
///
|
||||
/// let mut s = OsString::from("GRÜßE, JÜRGEN ❤");
|
||||
@ -725,7 +724,7 @@ impl OsStr {
|
||||
///
|
||||
/// 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 @@ impl OsStr {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(osstring_ascii)]
|
||||
/// use std::ffi::OsString;
|
||||
///
|
||||
/// let mut s = OsString::from("Grüße, Jürgen ❤");
|
||||
@ -751,7 +749,7 @@ impl OsStr {
|
||||
///
|
||||
/// 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 @@ 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.53.0")]
|
||||
pub fn to_ascii_lowercase(&self) -> OsString {
|
||||
OsString::from_inner(self.inner.to_ascii_lowercase())
|
||||
}
|
||||
@ -790,13 +787,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.53.0")]
|
||||
pub fn to_ascii_uppercase(&self) -> OsString {
|
||||
OsString::from_inner(self.inner.to_ascii_uppercase())
|
||||
}
|
||||
@ -806,7 +802,6 @@ impl OsStr {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(osstring_ascii)]
|
||||
/// use std::ffi::OsString;
|
||||
///
|
||||
/// let ascii = OsString::from("hello!\n");
|
||||
@ -815,7 +810,7 @@ impl OsStr {
|
||||
/// 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 @@ 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.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 @@ 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;
|
||||
}
|
||||
|
@ -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 @@ 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};
|
||||
|
@ -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()
|
||||
|
7
src/test/ui/imports/tool-mod-child.rs
Normal file
7
src/test/ui/imports/tool-mod-child.rs
Normal file
@ -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() {}
|
28
src/test/ui/imports/tool-mod-child.stderr
Normal file
28
src/test/ui/imports/tool-mod-child.stderr
Normal file
@ -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`.
|
Loading…
Reference in New Issue
Block a user