Merge pull request #2 from rust-lang/master
update from origin 2020-06-10
This commit is contained in:
commit
d139a720a2
1279 changed files with 25442 additions and 15148 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -442,7 +442,7 @@ jobs:
|
|||
- name: x86_64-msvc-cargo
|
||||
env:
|
||||
SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-lld"
|
||||
VCVARS_BAT: vcvars64.bat
|
||||
NO_DEBUG_ASSERTIONS: 1
|
||||
NO_LLVM_ASSERTIONS: 1
|
||||
|
|
|
|||
8
.mailmap
8
.mailmap
|
|
@ -44,6 +44,7 @@ Brian Anderson <banderson@mozilla.com> <andersrb@gmail.com>
|
|||
Brian Anderson <banderson@mozilla.com> <banderson@mozilla.org>
|
||||
Brian Dawn <brian.t.dawn@gmail.com>
|
||||
Brian Leibig <brian@brianleibig.com> Brian Leibig <brian.leibig@gmail.com>
|
||||
Camelid <camelidcamel@gmail.com> <37223377+camelid@users.noreply.github.com>
|
||||
Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com>
|
||||
Carol (Nichols || Goulding) <carol.nichols@gmail.com> <193874+carols10cents@users.noreply.github.com>
|
||||
Carol (Nichols || Goulding) <carol.nichols@gmail.com> <carol.nichols@gmail.com>
|
||||
|
|
@ -70,6 +71,8 @@ David Manescu <david.manescu@gmail.com> <dman2626@uni.sydney.edu.au>
|
|||
David Ross <daboross@daboross.net>
|
||||
Derek Chiang <derekchiang93@gmail.com> Derek Chiang (Enchi Jiang) <derekchiang93@gmail.com>
|
||||
Diggory Hardy <diggory.hardy@gmail.com> Diggory Hardy <github@dhardy.name>
|
||||
Donough Liu <ldm2993593805@163.com> <donoughliu@gmail.com>
|
||||
Donough Liu <ldm2993593805@163.com> DingMing Liu <liudingming@bupt.edu.cn>
|
||||
Dustin Bensing <dustin.bensing@googlemail.com>
|
||||
Dylan Braithwaite <dylanbraithwaite1@gmail.com> <mail@dylanb.me>
|
||||
Dzmitry Malyshau <kvarkus@gmail.com>
|
||||
|
|
@ -150,6 +153,10 @@ Kang Seonghoon <kang.seonghoon@mearie.org> <public+git@mearie.org>
|
|||
Keegan McAllister <mcallister.keegan@gmail.com> <kmcallister@mozilla.com>
|
||||
Kevin Butler <haqkrs@gmail.com>
|
||||
Kyeongwoon Lee <kyeongwoon.lee@samsung.com>
|
||||
Kyle J Strand <batmanaod@gmail.com> <BatmanAoD@users.noreply.github.com>
|
||||
Kyle J Strand <batmanaod@gmail.com> <kyle.j.strand@gmail.com>
|
||||
Kyle J Strand <batmanaod@gmail.com> <kyle.strand@pieinsurance.com>
|
||||
Kyle J Strand <batmanaod@gmail.com> <kyle.strand@rms.com>
|
||||
Laurențiu Nicola <lnicola@dend.ro>
|
||||
Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
|
||||
Lee Wondong <wdlee91@gmail.com>
|
||||
|
|
@ -259,6 +266,7 @@ Tim Chevalier <chevalier@alum.wellesley.edu> <catamorphism@gmail.com>
|
|||
Tim JIANG <p90eri@gmail.com>
|
||||
Tim Joseph Dumol <tim@timdumol.com>
|
||||
Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com>
|
||||
Trevor Spiteri <tspiteri@ieee.org> <trevor.spiteri@um.edu.mt>
|
||||
Ty Overby <ty@pre-alpha.com>
|
||||
Ulrik Sverdrup <bluss@users.noreply.github.com> bluss <bluss@users.noreply.github.com>
|
||||
Ulrik Sverdrup <bluss@users.noreply.github.com> bluss <bluss>
|
||||
|
|
|
|||
501
Cargo.lock
501
Cargo.lock
File diff suppressed because it is too large
Load diff
|
|
@ -22,6 +22,7 @@ members = [
|
|||
"src/tools/rls",
|
||||
"src/tools/rustfmt",
|
||||
"src/tools/miri",
|
||||
"src/tools/miri/cargo-miri",
|
||||
"src/tools/rustdoc-themes",
|
||||
"src/tools/unicode-table-generator",
|
||||
"src/tools/expand-yaml-anchors",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ or reading the [rustc dev guide][rustcguidebuild].
|
|||
|
||||
[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html
|
||||
|
||||
### Building on *nix
|
||||
### Building on a Unix-like system
|
||||
1. Make sure you have installed the dependencies:
|
||||
|
||||
* `g++` 5.1 or later or `clang++` 3.5 or later
|
||||
|
|
|
|||
162
RELEASES.md
162
RELEASES.md
|
|
@ -1,3 +1,165 @@
|
|||
Version 1.44.0 (2020-06-04)
|
||||
==========================
|
||||
|
||||
Language
|
||||
--------
|
||||
- [You can now use `async/.await` with `#[no_std]` enabled.][69033]
|
||||
- [Added the `unused_braces` lint.][70081]
|
||||
|
||||
**Syntax-only changes**
|
||||
|
||||
- [Expansion-driven outline module parsing][69838]
|
||||
```rust
|
||||
#[cfg(FALSE)]
|
||||
mod foo {
|
||||
mod bar {
|
||||
mod baz; // `foo/bar/baz.rs` doesn't exist, but no error!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These are still rejected semantically, so you will likely receive an error but
|
||||
these changes can be seen and parsed by macros and conditional compilation.
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Rustc now respects the `-C codegen-units` flag in incremental mode.][70156]
|
||||
Additionally when in incremental mode rustc defaults to 256 codegen units.
|
||||
- [Refactored `catch_unwind` to have zero-cost, unless unwinding is enabled and
|
||||
a panic is thrown.][67502]
|
||||
- [Added tier 3\* support for the `aarch64-unknown-none` and
|
||||
`aarch64-unknown-none-softfloat` targets.][68334]
|
||||
- [Added tier 3 support for `arm64-apple-tvos` and
|
||||
`x86_64-apple-tvos` targets.][68191]
|
||||
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Special cased `vec![]` to map directly to `Vec::new()`.][70632] This allows
|
||||
`vec![]` to be able to be used in `const` contexts.
|
||||
- [`convert::Infallible` now implements `Hash`.][70281]
|
||||
- [`OsString` now implements `DerefMut` and `IndexMut` returning
|
||||
a `&mut OsStr`.][70048]
|
||||
- [Unicode 13 is now supported.][69929]
|
||||
- [`String` now implements `From<&mut str>`.][69661]
|
||||
- [`IoSlice` now implements `Copy`.][69403]
|
||||
- [`Vec<T>` now implements `From<[T; N]>`.][68692] Where `N` is at most 32.
|
||||
- [`proc_macro::LexError` now implements `fmt::Display` and `Error`.][68899]
|
||||
- [`from_le_bytes`, `to_le_bytes`, `from_be_bytes`, `to_be_bytes`,
|
||||
`from_ne_bytes`, and `to_ne_bytes` methods are now `const` for all
|
||||
integer types.][69373]
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
- [`PathBuf::with_capacity`]
|
||||
- [`PathBuf::capacity`]
|
||||
- [`PathBuf::clear`]
|
||||
- [`PathBuf::reserve`]
|
||||
- [`PathBuf::reserve_exact`]
|
||||
- [`PathBuf::shrink_to_fit`]
|
||||
- [`f32::to_int_unchecked`]
|
||||
- [`f64::to_int_unchecked`]
|
||||
- [`Layout::align_to`]
|
||||
- [`Layout::pad_to_align`]
|
||||
- [`Layout::array`]
|
||||
- [`Layout::extend`]
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [Added the `cargo tree` command which will print a tree graph of
|
||||
your dependencies.][cargo/8062] E.g.
|
||||
```
|
||||
mdbook v0.3.2 (/Users/src/rust/mdbook)
|
||||
├── ammonia v3.0.0
|
||||
│ ├── html5ever v0.24.0
|
||||
│ │ ├── log v0.4.8
|
||||
│ │ │ └── cfg-if v0.1.9
|
||||
│ │ ├── mac v0.1.1
|
||||
│ │ └── markup5ever v0.9.0
|
||||
│ │ ├── log v0.4.8 (*)
|
||||
│ │ ├── phf v0.7.24
|
||||
│ │ │ └── phf_shared v0.7.24
|
||||
│ │ │ ├── siphasher v0.2.3
|
||||
│ │ │ └── unicase v1.4.2
|
||||
│ │ │ [build-dependencies]
|
||||
│ │ │ └── version_check v0.1.5
|
||||
...
|
||||
```
|
||||
You can also display dependencies on multiple versions of the same crate with
|
||||
`cargo tree -d` (short for `cargo tree --duplicates`).
|
||||
|
||||
Misc
|
||||
----
|
||||
- [Rustdoc now allows you to specify `--crate-version` to have rustdoc include
|
||||
the version in the sidebar.][69494]
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Rustc now correctly generates static libraries on Windows GNU targets with
|
||||
the `.a` extension, rather than the previous `.lib`.][70937]
|
||||
- [Removed the `-C no_integrated_as` flag from rustc.][70345]
|
||||
- [The `file_name` property in JSON output of macro errors now points the actual
|
||||
source file rather than the previous format of `<NAME macros>`.][70969]
|
||||
**Note:** this may not point to a file that actually exists on the user's system.
|
||||
- [The minimum required external LLVM version has been bumped to LLVM 8.][71147]
|
||||
- [`mem::{zeroed, uninitialised}` will now panic when used with types that do
|
||||
not allow zero initialization such as `NonZeroU8`.][66059] This was
|
||||
previously a warning.
|
||||
- [In 1.45.0 (the next release) converting a `f64` to `u32` using the `as`
|
||||
operator has been defined as a saturating operation.][71269] This was previously
|
||||
undefined behaviour, but you can use the `{f64, f32}::to_int_unchecked` methods to
|
||||
continue using the current behaviour, which may be desirable in rare performance
|
||||
sensitive situations.
|
||||
|
||||
Internal Only
|
||||
-------------
|
||||
These changes provide no direct user facing benefits, but represent significant
|
||||
improvements to the internals and overall performance of rustc and
|
||||
related tools.
|
||||
|
||||
- [dep_graph Avoid allocating a set on when the number reads are small.][69778]
|
||||
- [Replace big JS dict with JSON parsing.][71250]
|
||||
|
||||
[69373]: https://github.com/rust-lang/rust/pull/69373/
|
||||
[66059]: https://github.com/rust-lang/rust/pull/66059/
|
||||
[68191]: https://github.com/rust-lang/rust/pull/68191/
|
||||
[68899]: https://github.com/rust-lang/rust/pull/68899/
|
||||
[71147]: https://github.com/rust-lang/rust/pull/71147/
|
||||
[71250]: https://github.com/rust-lang/rust/pull/71250/
|
||||
[70937]: https://github.com/rust-lang/rust/pull/70937/
|
||||
[70969]: https://github.com/rust-lang/rust/pull/70969/
|
||||
[70632]: https://github.com/rust-lang/rust/pull/70632/
|
||||
[70281]: https://github.com/rust-lang/rust/pull/70281/
|
||||
[70345]: https://github.com/rust-lang/rust/pull/70345/
|
||||
[70048]: https://github.com/rust-lang/rust/pull/70048/
|
||||
[70081]: https://github.com/rust-lang/rust/pull/70081/
|
||||
[70156]: https://github.com/rust-lang/rust/pull/70156/
|
||||
[71269]: https://github.com/rust-lang/rust/pull/71269/
|
||||
[69838]: https://github.com/rust-lang/rust/pull/69838/
|
||||
[69929]: https://github.com/rust-lang/rust/pull/69929/
|
||||
[69661]: https://github.com/rust-lang/rust/pull/69661/
|
||||
[69778]: https://github.com/rust-lang/rust/pull/69778/
|
||||
[69494]: https://github.com/rust-lang/rust/pull/69494/
|
||||
[69403]: https://github.com/rust-lang/rust/pull/69403/
|
||||
[69033]: https://github.com/rust-lang/rust/pull/69033/
|
||||
[68692]: https://github.com/rust-lang/rust/pull/68692/
|
||||
[68334]: https://github.com/rust-lang/rust/pull/68334/
|
||||
[67502]: https://github.com/rust-lang/rust/pull/67502/
|
||||
[cargo/8062]: https://github.com/rust-lang/cargo/pull/8062/
|
||||
[`PathBuf::with_capacity`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.with_capacity
|
||||
[`PathBuf::capacity`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.capacity
|
||||
[`PathBuf::clear`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.clear
|
||||
[`PathBuf::reserve`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.reserve
|
||||
[`PathBuf::reserve_exact`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.reserve_exact
|
||||
[`PathBuf::shrink_to_fit`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.shrink_to_fit
|
||||
[`f32::to_int_unchecked`]: https://doc.rust-lang.org/std/primitive.f32.html#method.to_int_unchecked
|
||||
[`f64::to_int_unchecked`]: https://doc.rust-lang.org/std/primitive.f64.html#method.to_int_unchecked
|
||||
[`Layout::align_to`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.align_to
|
||||
[`Layout::pad_to_align`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.pad_to_align
|
||||
[`Layout::array`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.array
|
||||
[`Layout::extend`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.extend
|
||||
|
||||
|
||||
Version 1.43.1 (2020-05-07)
|
||||
===========================
|
||||
|
||||
|
|
|
|||
|
|
@ -312,11 +312,11 @@
|
|||
|
||||
# Whether or not debug assertions are enabled for the compiler and standard
|
||||
# library.
|
||||
#debug-assertions = false
|
||||
#debug-assertions = debug
|
||||
|
||||
# Whether or not debug assertions are enabled for the standard library.
|
||||
# Overrides the `debug-assertions` option, if defined.
|
||||
#debug-assertions-std = false
|
||||
#debug-assertions-std = debug-assertions
|
||||
|
||||
# Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`.
|
||||
# `0` - no debug info
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ toml = "0.5"
|
|||
lazy_static = "1.3.0"
|
||||
time = "0.1"
|
||||
ignore = "0.4.10"
|
||||
opener = "0.4"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.winapi]
|
||||
version = "0.3"
|
||||
|
|
|
|||
|
|
@ -344,10 +344,12 @@ impl<'a> Builder<'a> {
|
|||
tool::Rls,
|
||||
tool::Rustdoc,
|
||||
tool::Clippy,
|
||||
tool::CargoClippy,
|
||||
native::Llvm,
|
||||
native::Sanitizers,
|
||||
tool::Rustfmt,
|
||||
tool::Miri,
|
||||
tool::CargoMiri,
|
||||
native::Lld
|
||||
),
|
||||
Kind::Check | Kind::Clippy | Kind::Fix | Kind::Format => {
|
||||
|
|
@ -503,7 +505,7 @@ impl<'a> Builder<'a> {
|
|||
Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
|
||||
Subcommand::Clippy { ref paths } => (Kind::Clippy, &paths[..]),
|
||||
Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]),
|
||||
Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
|
||||
Subcommand::Doc { ref paths, .. } => (Kind::Doc, &paths[..]),
|
||||
Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
|
||||
Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
|
||||
Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
|
||||
|
|
@ -648,6 +650,7 @@ impl<'a> Builder<'a> {
|
|||
pub fn sysroot_libdir_relative(&self, compiler: Compiler) -> &Path {
|
||||
match self.config.libdir_relative() {
|
||||
Some(relative_libdir) if compiler.stage >= 1 => relative_libdir,
|
||||
_ if compiler.stage == 0 => &self.build.initial_libdir,
|
||||
_ => Path::new("lib"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,9 @@ use crate::{Build, GitRepo};
|
|||
// try to infer the archiver path from the C compiler path.
|
||||
// In the future this logic should be replaced by calling into the `cc` crate.
|
||||
fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
|
||||
if let Some(ar) = env::var_os("AR") {
|
||||
if let Some(ar) = env::var_os(format!("AR_{}", target.replace("-", "_"))) {
|
||||
Some(PathBuf::from(ar))
|
||||
} else if let Some(ar) = env::var_os("AR") {
|
||||
Some(PathBuf::from(ar))
|
||||
} else if target.contains("msvc") {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use build_helper::output;
|
|||
use crate::Build;
|
||||
|
||||
// The version number
|
||||
pub const CFG_RELEASE_NUM: &str = "1.45.0";
|
||||
pub const CFG_RELEASE_NUM: &str = "1.46.0";
|
||||
|
||||
pub struct GitInfo {
|
||||
inner: Option<Info>,
|
||||
|
|
|
|||
|
|
@ -773,7 +773,8 @@ impl Step for Assemble {
|
|||
|
||||
// Ensure that `libLLVM.so` ends up in the newly build compiler directory,
|
||||
// so that it can be found when the newly built `rustc` is run.
|
||||
dist::maybe_install_llvm_dylib(builder, target_compiler.host, &sysroot);
|
||||
dist::maybe_install_llvm_runtime(builder, target_compiler.host, &sysroot);
|
||||
dist::maybe_install_llvm_target(builder, target_compiler.host, &sysroot);
|
||||
|
||||
// Link the compiler binary itself into place
|
||||
let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host);
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ impl Step for Rustc {
|
|||
// components like the llvm tools and LLD. LLD is included below and
|
||||
// tools/LLDB come later, so let's just throw it in the rustc
|
||||
// component for now.
|
||||
maybe_install_llvm_dylib(builder, host, image);
|
||||
maybe_install_llvm_runtime(builder, host, image);
|
||||
|
||||
// Copy over lld if it's there
|
||||
if builder.config.lld_enabled {
|
||||
|
|
@ -2228,27 +2228,18 @@ impl Step for HashSign {
|
|||
}
|
||||
}
|
||||
|
||||
// Maybe add libLLVM.so to the lib-dir. It will only have been built if
|
||||
// LLVM tools are linked dynamically.
|
||||
//
|
||||
// We add this to both the libdir of the rustc binary itself (for it to load at
|
||||
// runtime) and also to the target directory so it can find it at link-time.
|
||||
//
|
||||
// Note: This function does no yet support Windows but we also don't support
|
||||
// linking LLVM tools dynamically on Windows yet.
|
||||
pub fn maybe_install_llvm_dylib(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
|
||||
/// Maybe add libLLVM.so to the given destination lib-dir. It will only have
|
||||
/// been built if LLVM tools are linked dynamically.
|
||||
///
|
||||
/// Note: This function does not yet support Windows, but we also don't support
|
||||
/// linking LLVM tools dynamically on Windows yet.
|
||||
fn maybe_install_llvm(builder: &Builder<'_>, target: Interned<String>, dst_libdir: &Path) {
|
||||
let src_libdir = builder.llvm_out(target).join("lib");
|
||||
let dst_libdir1 = sysroot.join("lib/rustlib").join(&*target).join("lib");
|
||||
let dst_libdir2 =
|
||||
sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
|
||||
t!(fs::create_dir_all(&dst_libdir1));
|
||||
t!(fs::create_dir_all(&dst_libdir2));
|
||||
|
||||
if target.contains("apple-darwin") {
|
||||
let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
|
||||
if llvm_dylib_path.exists() {
|
||||
builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
|
||||
builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
|
||||
builder.install(&llvm_dylib_path, dst_libdir, 0o644);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -2262,11 +2253,23 @@ pub fn maybe_install_llvm_dylib(builder: &Builder<'_>, target: Interned<String>,
|
|||
panic!("dist: Error calling canonicalize path `{}`: {}", llvm_dylib_path.display(), e);
|
||||
});
|
||||
|
||||
builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
|
||||
builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
|
||||
builder.install(&llvm_dylib_path, dst_libdir, 0o644);
|
||||
}
|
||||
}
|
||||
|
||||
/// Maybe add libLLVM.so to the target lib-dir for linking.
|
||||
pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
|
||||
let dst_libdir = sysroot.join("lib/rustlib").join(&*target).join("lib");
|
||||
maybe_install_llvm(builder, target, &dst_libdir);
|
||||
}
|
||||
|
||||
/// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
|
||||
pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
|
||||
let dst_libdir =
|
||||
sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
|
||||
maybe_install_llvm(builder, target, &dst_libdir);
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct LlvmTools {
|
||||
pub target: Interned<String>,
|
||||
|
|
@ -2314,6 +2317,12 @@ impl Step for LlvmTools {
|
|||
builder.install(&exe, &dst_bindir, 0o755);
|
||||
}
|
||||
|
||||
// Copy libLLVM.so to the target lib dir as well, so the RPATH like
|
||||
// `$ORIGIN/../lib` can find it. It may also be used as a dependency
|
||||
// of `rustc-dev` to support the inherited `-lLLVM` when using the
|
||||
// compiler libraries.
|
||||
maybe_install_llvm_target(builder, target, &image);
|
||||
|
||||
// Prepare the overlay
|
||||
let overlay = tmp.join("llvm-tools-overlay");
|
||||
drop(fs::remove_dir_all(&overlay));
|
||||
|
|
|
|||
|
|
@ -70,6 +70,35 @@ book!(
|
|||
RustdocBook, "src/doc/rustdoc", "rustdoc";
|
||||
);
|
||||
|
||||
fn open(builder: &Builder<'_>, path: impl AsRef<Path>) {
|
||||
if builder.config.dry_run || !builder.config.cmd.open() {
|
||||
return;
|
||||
}
|
||||
|
||||
let path = path.as_ref();
|
||||
builder.info(&format!("Opening doc {}", path.display()));
|
||||
if let Err(err) = opener::open(path) {
|
||||
builder.info(&format!("{}\n", err));
|
||||
}
|
||||
}
|
||||
|
||||
// "src/libstd" -> ["src", "libstd"]
|
||||
//
|
||||
// Used for deciding whether a particular step is one requested by the user on
|
||||
// the `x.py doc` command line, which determines whether `--open` will open that
|
||||
// page.
|
||||
fn components_simplified(path: &PathBuf) -> Vec<&str> {
|
||||
path.iter().map(|component| component.to_str().unwrap_or("???")).collect()
|
||||
}
|
||||
|
||||
fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool {
|
||||
builder
|
||||
.paths
|
||||
.iter()
|
||||
.map(components_simplified)
|
||||
.any(|requested| requested.iter().copied().eq(path.split("/")))
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct UnstableBook {
|
||||
target: Interned<String>,
|
||||
|
|
@ -200,6 +229,12 @@ impl Step for TheBook {
|
|||
|
||||
invoke_rustdoc(builder, compiler, target, path);
|
||||
}
|
||||
|
||||
if is_explicit_request(builder, "src/doc/book") {
|
||||
let out = builder.doc_out(target);
|
||||
let index = out.join("book").join("index.html");
|
||||
open(builder, &index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -338,6 +373,13 @@ impl Step for Standalone {
|
|||
}
|
||||
builder.run(&mut cmd);
|
||||
}
|
||||
|
||||
// We open doc/index.html as the default if invoked as `x.py doc --open`
|
||||
// with no particular explicit doc requested (e.g. src/libcore).
|
||||
if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") {
|
||||
let index = out.join("index.html");
|
||||
open(builder, &index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -418,10 +460,25 @@ impl Step for Std {
|
|||
|
||||
builder.run(&mut cargo.into());
|
||||
};
|
||||
for krate in &["alloc", "core", "std", "proc_macro", "test"] {
|
||||
let krates = ["alloc", "core", "std", "proc_macro", "test"];
|
||||
for krate in &krates {
|
||||
run_cargo_rustdoc_for(krate);
|
||||
}
|
||||
builder.cp_r(&my_out, &out);
|
||||
|
||||
// Look for src/libstd, src/libcore etc in the `x.py doc` arguments and
|
||||
// open the corresponding rendered docs.
|
||||
for path in builder.paths.iter().map(components_simplified) {
|
||||
if path.get(0) == Some(&"src")
|
||||
&& path.get(1).map_or(false, |dir| dir.starts_with("lib"))
|
||||
{
|
||||
let requested_crate = &path[1][3..];
|
||||
if krates.contains(&requested_crate) {
|
||||
let index = out.join(requested_crate).join("index.html");
|
||||
open(builder, &index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ pub enum Subcommand {
|
|||
},
|
||||
Doc {
|
||||
paths: Vec<PathBuf>,
|
||||
open: bool,
|
||||
},
|
||||
Test {
|
||||
paths: Vec<PathBuf>,
|
||||
|
|
@ -248,6 +249,9 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
|
|||
"bench" => {
|
||||
opts.optmulti("", "test-args", "extra arguments", "ARGS");
|
||||
}
|
||||
"doc" => {
|
||||
opts.optflag("", "open", "open the docs in a browser");
|
||||
}
|
||||
"clean" => {
|
||||
opts.optflag("", "all", "clean all build artifacts");
|
||||
}
|
||||
|
|
@ -404,6 +408,7 @@ Arguments:
|
|||
./x.py doc src/doc/book
|
||||
./x.py doc src/doc/nomicon
|
||||
./x.py doc src/doc/book src/libstd
|
||||
./x.py doc src/libstd --open
|
||||
|
||||
If no arguments are passed then everything is documented:
|
||||
|
||||
|
|
@ -479,7 +484,7 @@ Arguments:
|
|||
},
|
||||
},
|
||||
"bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
|
||||
"doc" => Subcommand::Doc { paths },
|
||||
"doc" => Subcommand::Doc { paths, open: matches.opt_present("open") },
|
||||
"clean" => {
|
||||
if !paths.is_empty() {
|
||||
println!("\nclean does not take a path argument\n");
|
||||
|
|
@ -613,6 +618,13 @@ impl Subcommand {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open(&self) -> bool {
|
||||
match *self {
|
||||
Subcommand::Doc { open, .. } => open,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn split(s: &[String]) -> Vec<String> {
|
||||
|
|
|
|||
|
|
@ -243,6 +243,7 @@ pub struct Build {
|
|||
initial_rustc: PathBuf,
|
||||
initial_cargo: PathBuf,
|
||||
initial_lld: PathBuf,
|
||||
initial_libdir: PathBuf,
|
||||
|
||||
// Runtime state filled in later on
|
||||
// C/C++ compilers and archiver for all targets
|
||||
|
|
@ -344,18 +345,39 @@ impl Build {
|
|||
// we always try to use git for LLVM builds
|
||||
let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project"));
|
||||
|
||||
let initial_sysroot = config.initial_rustc.parent().unwrap().parent().unwrap();
|
||||
let initial_lld = initial_sysroot
|
||||
.join("lib")
|
||||
.join("rustlib")
|
||||
.join(config.build)
|
||||
.join("bin")
|
||||
.join("rust-lld");
|
||||
let initial_target_libdir_str = if config.dry_run {
|
||||
"/dummy/lib/path/to/lib/".to_string()
|
||||
} else {
|
||||
output(
|
||||
Command::new(&config.initial_rustc)
|
||||
.arg("--target")
|
||||
.arg(config.build)
|
||||
.arg("--print")
|
||||
.arg("target-libdir"),
|
||||
)
|
||||
};
|
||||
let initial_target_dir = Path::new(&initial_target_libdir_str).parent().unwrap();
|
||||
let initial_lld = initial_target_dir.join("bin").join("rust-lld");
|
||||
|
||||
let initial_sysroot = if config.dry_run {
|
||||
"/dummy".to_string()
|
||||
} else {
|
||||
output(Command::new(&config.initial_rustc).arg("--print").arg("sysroot"))
|
||||
};
|
||||
let initial_libdir = initial_target_dir
|
||||
.parent()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.strip_prefix(initial_sysroot.trim())
|
||||
.unwrap()
|
||||
.to_path_buf();
|
||||
|
||||
let mut build = Build {
|
||||
initial_rustc: config.initial_rustc.clone(),
|
||||
initial_cargo: config.initial_cargo.clone(),
|
||||
initial_lld,
|
||||
initial_libdir,
|
||||
local_rebuild: config.local_rebuild,
|
||||
fail_fast: config.cmd.fail_fast(),
|
||||
doc_tests: config.cmd.doc_tests(),
|
||||
|
|
@ -941,29 +963,15 @@ impl Build {
|
|||
return s;
|
||||
}
|
||||
|
||||
let beta = output(
|
||||
Command::new("git").arg("ls-remote").arg("origin").arg("beta").current_dir(&self.src),
|
||||
);
|
||||
let beta = beta.trim().split_whitespace().next().unwrap();
|
||||
let master = output(
|
||||
Command::new("git").arg("ls-remote").arg("origin").arg("master").current_dir(&self.src),
|
||||
);
|
||||
let master = master.trim().split_whitespace().next().unwrap();
|
||||
|
||||
// Figure out where the current beta branch started.
|
||||
let base = output(
|
||||
Command::new("git").arg("merge-base").arg(beta).arg(master).current_dir(&self.src),
|
||||
);
|
||||
let base = base.trim();
|
||||
|
||||
// Next figure out how many merge commits happened since we branched off
|
||||
// beta. That's our beta number!
|
||||
// Figure out how many merge commits happened since we branched off master.
|
||||
// That's our beta number!
|
||||
// (Note that we use a `..` range, not the `...` symmetric difference.)
|
||||
let count = output(
|
||||
Command::new("git")
|
||||
.arg("rev-list")
|
||||
.arg("--count")
|
||||
.arg("--merges")
|
||||
.arg(format!("{}...HEAD", base))
|
||||
.arg("refs/remotes/origin/master..HEAD")
|
||||
.current_dir(&self.src),
|
||||
);
|
||||
let n = count.trim().parse().unwrap();
|
||||
|
|
|
|||
|
|
@ -360,7 +360,12 @@ impl Step for Miri {
|
|||
|
||||
let miri =
|
||||
builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
|
||||
if let Some(miri) = miri {
|
||||
let cargo_miri = builder.ensure(tool::CargoMiri {
|
||||
compiler,
|
||||
target: self.host,
|
||||
extra_features: Vec::new(),
|
||||
});
|
||||
if let (Some(miri), Some(_cargo_miri)) = (miri, cargo_miri) {
|
||||
let mut cargo = builder.cargo(compiler, Mode::ToolRustc, host, "install");
|
||||
cargo.arg("xargo");
|
||||
// Configure `cargo install` path. cargo adds a `bin/`.
|
||||
|
|
@ -378,14 +383,16 @@ impl Step for Miri {
|
|||
Mode::ToolRustc,
|
||||
host,
|
||||
"run",
|
||||
"src/tools/miri",
|
||||
"src/tools/miri/cargo-miri",
|
||||
SourceType::Submodule,
|
||||
&[],
|
||||
);
|
||||
cargo.arg("--bin").arg("cargo-miri").arg("--").arg("miri").arg("setup");
|
||||
cargo.arg("--").arg("miri").arg("setup");
|
||||
|
||||
// Tell `cargo miri setup` where to find the sources.
|
||||
cargo.env("XARGO_RUST_SRC", builder.src.join("src"));
|
||||
// Tell it where to find Miri.
|
||||
cargo.env("MIRI", &miri);
|
||||
// Debug things.
|
||||
cargo.env("RUST_BACKTRACE", "1");
|
||||
// Overwrite bootstrap's `rustc` wrapper overwriting our flags.
|
||||
|
|
@ -437,7 +444,9 @@ impl Step for Miri {
|
|||
// miri tests need to know about the stage sysroot
|
||||
cargo.env("MIRI_SYSROOT", miri_sysroot);
|
||||
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
|
||||
cargo.env("MIRI_PATH", miri);
|
||||
cargo.env("MIRI", miri);
|
||||
|
||||
cargo.arg("--").args(builder.config.cmd.test_args());
|
||||
|
||||
builder.add_rustc_lib_path(compiler, &mut cargo);
|
||||
|
||||
|
|
@ -514,43 +523,37 @@ impl Step for Clippy {
|
|||
let host = self.host;
|
||||
let compiler = builder.compiler(stage, host);
|
||||
|
||||
let clippy = builder.ensure(tool::Clippy {
|
||||
let clippy = builder
|
||||
.ensure(tool::Clippy { compiler, target: self.host, extra_features: Vec::new() })
|
||||
.expect("in-tree tool");
|
||||
let mut cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
target: self.host,
|
||||
extra_features: Vec::new(),
|
||||
});
|
||||
if let Some(clippy) = clippy {
|
||||
let mut cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
Mode::ToolRustc,
|
||||
host,
|
||||
"test",
|
||||
"src/tools/clippy",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
Mode::ToolRustc,
|
||||
host,
|
||||
"test",
|
||||
"src/tools/clippy",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
|
||||
// clippy tests need to know about the stage sysroot
|
||||
cargo.env("SYSROOT", builder.sysroot(compiler));
|
||||
cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
|
||||
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
|
||||
let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
|
||||
let target_libs = builder
|
||||
.stage_out(compiler, Mode::ToolRustc)
|
||||
.join(&self.host)
|
||||
.join(builder.cargo_dir());
|
||||
cargo.env("HOST_LIBS", host_libs);
|
||||
cargo.env("TARGET_LIBS", target_libs);
|
||||
// clippy tests need to find the driver
|
||||
cargo.env("CLIPPY_DRIVER_PATH", clippy);
|
||||
// clippy tests need to know about the stage sysroot
|
||||
cargo.env("SYSROOT", builder.sysroot(compiler));
|
||||
cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
|
||||
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
|
||||
let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
|
||||
let target_libs =
|
||||
builder.stage_out(compiler, Mode::ToolRustc).join(&self.host).join(builder.cargo_dir());
|
||||
cargo.env("HOST_LIBS", host_libs);
|
||||
cargo.env("TARGET_LIBS", target_libs);
|
||||
// clippy tests need to find the driver
|
||||
cargo.env("CLIPPY_DRIVER_PATH", clippy);
|
||||
|
||||
builder.add_rustc_lib_path(compiler, &mut cargo);
|
||||
cargo.arg("--").args(builder.config.cmd.test_args());
|
||||
|
||||
try_run(builder, &mut cargo.into());
|
||||
} else {
|
||||
eprintln!("failed to test clippy: could not build");
|
||||
}
|
||||
builder.add_rustc_lib_path(compiler, &mut cargo);
|
||||
|
||||
try_run(builder, &mut cargo.into());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1766,7 +1769,7 @@ impl Step for Crate {
|
|||
} else if builder.remote_tested(target) {
|
||||
cargo.env(
|
||||
format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
|
||||
format!("{} run", builder.tool_exe(Tool::RemoteTestClient).display()),
|
||||
format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -252,6 +252,10 @@ pub fn prepare_tool_cargo(
|
|||
// own copy
|
||||
cargo.env("LZMA_API_STATIC", "1");
|
||||
|
||||
// CFG_RELEASE is needed by rustfmt (and possibly other tools) which
|
||||
// import rustc-ap-rustc_attr which requires this to be set for the
|
||||
// `#[cfg(version(...))]` attribute.
|
||||
cargo.env("CFG_RELEASE", builder.rust_release());
|
||||
cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel);
|
||||
cargo.env("CFG_VERSION", builder.rust_version());
|
||||
cargo.env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM);
|
||||
|
|
@ -645,12 +649,14 @@ macro_rules! tool_extended {
|
|||
}
|
||||
}
|
||||
|
||||
// Note: tools need to be also added to `Builder::get_step_descriptions` in `build.rs`
|
||||
// to make `./x.py build <tool>` work.
|
||||
tool_extended!((self, builder),
|
||||
Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", {};
|
||||
CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", {};
|
||||
Clippy, clippy, "src/tools/clippy", "clippy-driver", {};
|
||||
Miri, miri, "src/tools/miri", "miri", {};
|
||||
CargoMiri, miri, "src/tools/miri", "cargo-miri", {};
|
||||
CargoMiri, miri, "src/tools/miri/cargo-miri", "cargo-miri", {};
|
||||
Rls, rls, "src/tools/rls", "rls", {
|
||||
builder.ensure(Clippy {
|
||||
compiler: self.compiler,
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ jobs:
|
|||
INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
|
||||
x86_64-msvc-cargo:
|
||||
SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
|
||||
INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
|
||||
INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld
|
||||
VCVARS_BAT: vcvars64.bat
|
||||
# FIXME(#59637)
|
||||
NO_DEBUG_ASSERTIONS: 1
|
||||
|
|
|
|||
|
|
@ -28,6 +28,29 @@ RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y --no
|
|||
RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7924C5513486
|
||||
RUN add-apt-repository -y 'deb http://apt.dilos.org/dilos dilos2 main'
|
||||
|
||||
ENV \
|
||||
AR_x86_64_fuchsia=x86_64-fuchsia-ar \
|
||||
CC_x86_64_fuchsia=x86_64-fuchsia-clang \
|
||||
CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \
|
||||
AR_aarch64_fuchsia=aarch64-fuchsia-ar \
|
||||
CC_aarch64_fuchsia=aarch64-fuchsia-clang \
|
||||
CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \
|
||||
AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \
|
||||
CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \
|
||||
CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \
|
||||
AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \
|
||||
CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \
|
||||
CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \
|
||||
CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-7 \
|
||||
CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-7 \
|
||||
AR_x86_64_fortanix_unknown_sgx=ar \
|
||||
CC_x86_64_fortanix_unknown_sgx=x86_64-fortanix-unknown-sgx-clang-11 \
|
||||
CFLAGS_x86_64_fortanix_unknown_sgx="-mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
|
||||
CXX_x86_64_fortanix_unknown_sgx=x86_64-fortanix-unknown-sgx-clang++-11 \
|
||||
CXXFLAGS_x86_64_fortanix_unknown_sgx="-mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
|
||||
CC=gcc-7 \
|
||||
CXX=g++-7
|
||||
|
||||
WORKDIR /build
|
||||
COPY scripts/musl.sh /build
|
||||
RUN env \
|
||||
|
|
@ -46,9 +69,11 @@ COPY dist-various-2/build-solaris-toolchain.sh /tmp/
|
|||
RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386
|
||||
RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
|
||||
COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
|
||||
COPY dist-various-2/x86_64-fortanix-unknown-sgx-clang-wrap.sh /usr/bin/x86_64-fortanix-unknown-sgx-clang-11
|
||||
RUN ln -s /usr/bin/x86_64-fortanix-unknown-sgx-clang-11 /usr/bin/x86_64-fortanix-unknown-sgx-clang++-11
|
||||
# We pass the commit id of the port of LLVM's libunwind to the build script.
|
||||
# Any update to the commit id here, should cause the container image to be re-built from this point on.
|
||||
RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "5125c169b30837208a842f85f7ae44a83533bd0e"
|
||||
RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "800f95131fe6acd20b96b6f4723ca3c820f3d379"
|
||||
|
||||
COPY dist-various-2/build-wasi-toolchain.sh /tmp/
|
||||
RUN /tmp/build-wasi-toolchain.sh
|
||||
|
|
@ -56,24 +81,6 @@ RUN /tmp/build-wasi-toolchain.sh
|
|||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV \
|
||||
AR_x86_64_fuchsia=x86_64-fuchsia-ar \
|
||||
CC_x86_64_fuchsia=x86_64-fuchsia-clang \
|
||||
CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \
|
||||
AR_aarch64_fuchsia=aarch64-fuchsia-ar \
|
||||
CC_aarch64_fuchsia=aarch64-fuchsia-clang \
|
||||
CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \
|
||||
AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \
|
||||
CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \
|
||||
CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \
|
||||
AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \
|
||||
CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \
|
||||
CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \
|
||||
CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-7 \
|
||||
CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-7 \
|
||||
CC=gcc-7 \
|
||||
CXX=g++-7
|
||||
|
||||
ENV CARGO_TARGET_X86_64_FUCHSIA_AR /usr/local/bin/llvm-ar
|
||||
ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \
|
||||
-C link-arg=--sysroot=/usr/local/x86_64-fuchsia \
|
||||
|
|
|
|||
|
|
@ -13,12 +13,15 @@ url="https://github.com/fortanix/llvm-project/archive/${1}.tar.gz"
|
|||
repo_name="llvm-project"
|
||||
|
||||
install_prereq() {
|
||||
curl https://apt.llvm.org/llvm-snapshot.gpg.key|apt-key add -
|
||||
add-apt-repository -y 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main'
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
cmake \
|
||||
git
|
||||
git \
|
||||
clang-11
|
||||
}
|
||||
|
||||
build_unwind() {
|
||||
|
|
@ -35,7 +38,14 @@ build_unwind() {
|
|||
# Build libunwind
|
||||
mkdir -p build
|
||||
cd build
|
||||
target_CC="CC_${target//-/_}"
|
||||
target_CXX="CXX_${target//-/_}"
|
||||
target_CFLAGS="CFLAGS_${target//-/_}"
|
||||
target_CXXFLAGS="CXXFLAGS_${target//-/_}"
|
||||
cmake -DCMAKE_BUILD_TYPE="RELEASE" -DRUST_SGX=1 -G "Unix Makefiles" \
|
||||
-DCMAKE_C_COMPILER="${!target_CC}" -DCMAKE_CXX_COMPILER="${!target_CXX}" \
|
||||
-DCMAKE_C_FLAGS="${!target_CFLAGS}" -DCMAKE_CXX_FLAGS="${!target_CXXFLAGS}" \
|
||||
-DCMAKE_C_COMPILER_TARGET=$target -DCMAKE_CXX_COMPILER_TARGET=$target \
|
||||
-DLLVM_ENABLE_WARNINGS=1 -DLIBUNWIND_ENABLE_WERROR=1 -DLIBUNWIND_ENABLE_PEDANTIC=0 \
|
||||
-DLLVM_PATH=../../llvm/ ../
|
||||
make unwind_static
|
||||
|
|
|
|||
14
src/ci/docker/dist-various-2/x86_64-fortanix-unknown-sgx-clang-wrap.sh
Executable file
14
src/ci/docker/dist-various-2/x86_64-fortanix-unknown-sgx-clang-wrap.sh
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
args=("$@")
|
||||
|
||||
for i in "${!args[@]}"; do
|
||||
# x86_64-fortanix-unknown-sgx doesn't have a C sysroot for things like
|
||||
# stdint.h and the C++ STL. Unlike GCC, clang will not use the host's
|
||||
# sysroot instead. Force it.
|
||||
if [ "${args[$i]}" = "--target=x86_64-fortanix-unknown-sgx" ]; then
|
||||
args[$i]="--target=x86_64-unknown-linux-gnu"
|
||||
fi
|
||||
done
|
||||
|
||||
exec "${0/x86_64-fortanix-unknown-sgx-clang/clang}" "${args[@]}"
|
||||
|
|
@ -505,7 +505,7 @@ jobs:
|
|||
- name: x86_64-msvc-cargo
|
||||
env:
|
||||
SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld
|
||||
VCVARS_BAT: vcvars64.bat
|
||||
# FIXME(#59637)
|
||||
NO_DEBUG_ASSERTIONS: 1
|
||||
|
|
|
|||
|
|
@ -6,17 +6,6 @@ IFS=$'\n\t'
|
|||
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
|
||||
|
||||
if isWindows; then
|
||||
# FIXME(mati865): temporary workaround until chocolatey updates their MSYS2
|
||||
base_url='https://ci-mirrors.rust-lang.org/rustc/msys2-repo/msys/x86_64'
|
||||
curl ${base_url}/libzstd-1.4.4-2-x86_64.pkg.tar.xz -o libzstd-1.4.4-2-x86_64.pkg.tar.xz
|
||||
curl ${base_url}/pacman-5.2.1-6-x86_64.pkg.tar.xz -o pacman-5.2.1-6-x86_64.pkg.tar.xz
|
||||
curl ${base_url}/zstd-1.4.4-2-x86_64.pkg.tar.xz -o zstd-1.4.4-2-x86_64.pkg.tar.xz
|
||||
pacman -U --noconfirm libzstd-1.4.4-2-x86_64.pkg.tar.xz pacman-5.2.1-6-x86_64.pkg.tar.xz \
|
||||
zstd-1.4.4-2-x86_64.pkg.tar.xz
|
||||
rm libzstd-1.4.4-2-x86_64.pkg.tar.xz pacman-5.2.1-6-x86_64.pkg.tar.xz \
|
||||
zstd-1.4.4-2-x86_64.pkg.tar.xz
|
||||
pacman -Sy
|
||||
|
||||
pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar \
|
||||
binutils
|
||||
|
||||
|
|
|
|||
|
|
@ -17,9 +17,8 @@ if isWindows; then
|
|||
msys2.nupkg
|
||||
curl -sSL https://packages.chocolatey.org/chocolatey-core.extension.1.3.5.1.nupkg > \
|
||||
chocolatey-core.extension.nupkg
|
||||
# FIXME(mati865): remove `/NoUpdate` once chocolatey updates MSYS2
|
||||
choco install -s . msys2 \
|
||||
--params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath /NoUpdate" -y --no-progress
|
||||
--params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath" -y --no-progress
|
||||
rm msys2.nupkg chocolatey-core.extension.nupkg
|
||||
mkdir -p "$(ciCheckoutPath)/msys2/home/${USERNAME}"
|
||||
ciCommandAddPath "$(ciCheckoutPath)/msys2/usr/bin"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 6247be15a7f7509559f7981ee2209b9e0cc121df
|
||||
Subproject commit 30cd9dfe71c446de63826bb4472627af45acc9db
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 49270740c7a4bff2763e6bc730b191d45b7d5167
|
||||
Subproject commit 82bec5877c77cfad530ca11095db4456d757f668
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 366c50a03bed928589771eba8a6f18e0c0c01d23
|
||||
Subproject commit 5555a97f04ad7974ac6fb8fb47c267c4274adf4a
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit d1517d4e3f29264c5c67bce2658516bb5202c800
|
||||
Subproject commit bfe1ab96d717d1dda50e499b360f2e2f57e1750a
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 892b928b565e35d25b6f9c47faee03b94bc41489
|
||||
Subproject commit 5d40ba5c2515caffa7790cda621239dc21ef5a72
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit ab072b14393cbd9e8a1d1d75879bf51e27217bbb
|
||||
Subproject commit 7aa82129aa23e7e181efbeb8da03a2a897ef6afc
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
% Rustc UX guidelines
|
||||
|
||||
Don't forget the user. Whether human or another program, such as an IDE, a
|
||||
good user experience with the compiler goes a long way toward making developers'
|
||||
lives better. We do not want users to be baffled by compiler output or
|
||||
learn arcane patterns to compile their program.
|
||||
|
||||
## Error, Warning, Help, Note Messages
|
||||
|
||||
When the compiler detects a problem, it can emit one of the following: an error, a warning,
|
||||
a note, or a help message.
|
||||
|
||||
An `error` is emitted when the compiler detects a problem that makes it unable
|
||||
to compile the program, either because the program is invalid or the
|
||||
programmer has decided to make a specific `warning` into an error.
|
||||
|
||||
A `warning` is emitted when the compiler detects something odd about a
|
||||
program. For instance, dead code and unused `Result` values.
|
||||
|
||||
A `help` message is emitted following an `error` or `warning` to give additional
|
||||
information to the user about how to solve their problem.
|
||||
|
||||
A `note` is emitted to identify additional circumstances and parts of the code
|
||||
that caused the warning or error. For example, the borrow checker will note any
|
||||
previous conflicting borrows.
|
||||
|
||||
* Write in plain simple English. If your message, when shown on a – possibly
|
||||
small – screen (which hasn't been cleaned for a while), cannot be understood
|
||||
by a normal programmer, who just came out of bed after a night partying, it's
|
||||
too complex.
|
||||
* `Errors` and `Warnings` should not suggest how to fix the problem. A `Help`
|
||||
message should be emitted instead.
|
||||
* `Error`, `Warning`, `Note`, and `Help` messages start with a lowercase
|
||||
letter and do not end with punctuation.
|
||||
* Error messages should be succinct. Users will see these error messages many
|
||||
times, and more verbose descriptions can be viewed with the `--explain` flag.
|
||||
That said, don't make it so terse that it's hard to understand.
|
||||
* The word "illegal" is illegal. Prefer "invalid" or a more specific word
|
||||
instead.
|
||||
* Errors should document the span of code where they occur – the `span_..`
|
||||
methods allow to easily do this. Also `note` other spans that have contributed
|
||||
to the error if the span isn't too large.
|
||||
* When emitting a message with span, try to reduce the span to the smallest
|
||||
amount possible that still signifies the issue
|
||||
* Try not to emit multiple error messages for the same error. This may require
|
||||
detecting duplicates.
|
||||
* When the compiler has too little information for a specific error message,
|
||||
lobby for annotations for library code that allow adding more. For example see
|
||||
`#[on_unimplemented]`. Use these annotations when available!
|
||||
* Keep in mind that Rust's learning curve is rather steep, and that the
|
||||
compiler messages are an important learning tool.
|
||||
|
||||
## Error Explanations
|
||||
|
||||
Error explanations are long form descriptions of error messages provided with
|
||||
the compiler. They are accessible via the `--explain` flag. Each explanation
|
||||
comes with an example of how to trigger it and advice on how to fix it.
|
||||
|
||||
Please read [RFC 1567](https://github.com/rust-lang/rfcs/blob/master/text/1567-long-error-codes-explanation-normalization.md)
|
||||
for details on how to format and write long error codes.
|
||||
|
||||
* All of them are accessible [online](http://doc.rust-lang.org/error-index.html),
|
||||
which are auto-generated from rustc source code in different places:
|
||||
[librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/error_codes.rs),
|
||||
[librustc_ast](https://github.com/rust-lang/rust/blob/master/src/librustc_ast/error_codes.rs),
|
||||
[librustc_borrowck](https://github.com/rust-lang/rust/blob/master/src/librustc_borrowck/error_codes.rs),
|
||||
[librustc_metadata](https://github.com/rust-lang/rust/blob/master/src/librustc_metadata/error_codes.rs),
|
||||
[librustc_mir](https://github.com/rust-lang/rust/blob/master/src/librustc_mir/error_codes.rs),
|
||||
[librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/error_codes.rs),
|
||||
[librustc_privacy](https://github.com/rust-lang/rust/blob/master/src/librustc_privacy/error_codes.rs),
|
||||
[librustc_resolve](https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/error_codes.rs),
|
||||
[librustc_codegen_llvm](https://github.com/rust-lang/rust/blob/master/src/librustc_codegen_llvm/error_codes.rs),
|
||||
[librustc_plugin_impl](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/error_codes.rs),
|
||||
[librustc_typeck](https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/error_codes.rs).
|
||||
* Explanations have full markdown support. Use it, especially to highlight
|
||||
code with backticks.
|
||||
* When talking about the compiler, call it `the compiler`, not `Rust` or
|
||||
`rustc`.
|
||||
|
||||
## Compiler Flags
|
||||
|
||||
* Flags should be orthogonal to each other. For example, if we'd have a
|
||||
json-emitting variant of multiple actions `foo` and `bar`, an additional
|
||||
--json flag is better than adding `--foo-json` and `--bar-json`.
|
||||
* Always give options a long descriptive name, if only for more
|
||||
understandable compiler scripts.
|
||||
* The `--verbose` flag is for adding verbose information to `rustc` output
|
||||
when not compiling a program. For example, using it with the `--version` flag
|
||||
gives information about the hashes of the code.
|
||||
* Experimental flags and options must be guarded behind the `-Z unstable-options` flag.
|
||||
|
|
@ -4,15 +4,39 @@ The tracking issue for this feature is: [#68793](https://github.com/rust-lang/ru
|
|||
|
||||
------------------------
|
||||
|
||||
The `-Zcontrol_flow_guard=checks` compiler flag enables the Windows [Control Flow Guard][cfguard-docs] platform security feature. When enabled, the compiler outputs a list of valid indirect call targets, and inserts runtime checks on all indirect jump instructions to ensure that the destination is in the list of valid call targets.
|
||||
The rustc flag `-Z control_flow_guard=checks` enables the Windows [Control Flow Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) (CFG) platform security feature.
|
||||
|
||||
[cfguard-docs]: https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard
|
||||
CFG is an exploit mitigation designed to enforce control-flow integrity for software running on supported Windows platforms (Windows 8.1 onwards). Specifically, CFG uses runtime checks to validate the target address of every indirect call/jump before allowing the call to complete.
|
||||
|
||||
For testing purposes, the `-Zcontrol_flow_guard=nochecks` compiler flag can be used to emit only the list of valid call targets, but not the runtime checks.
|
||||
During compilation, the compiler identifies all indirect calls/jumps and adds CFG checks. It also emits metadata containing the relative addresses of all address-taken functions. At runtime, if the binary is run on a CFG-aware operating system, the loader uses the CFG metadata to generate a bitmap of the address space and marks those addresses that contain valid targets. On each indirect call, the inserted check determines whether the target address is marked in this bitmap. If the target is not valid, the process is terminated.
|
||||
|
||||
It is strongly recommended to also enable Control Flow Guard checks in all linked libraries, including the standard library.
|
||||
In terms of interoperability:
|
||||
- Code compiled with CFG enabled can be linked with libraries and object files that are not compiled with CFG. In this case, a CFG-aware linker can identify address-taken functions in the non-CFG libraries.
|
||||
- Libraries compiled with CFG can linked into non-CFG programs. In this case, the CFG runtime checks in the libraries are not used (i.e. the mitigation is completely disabled).
|
||||
|
||||
To enable Control Flow Guard in the standard library, you can use the [cargo `-Zbuild-std` functionality][build-std] to recompile the standard library with the same configuration options as the main program.
|
||||
CFG functionality is completely implemented in the LLVM backend and is supported for X86 (32-bit and 64-bit), ARM, and Aarch64 targets. The rustc flag adds the relevant LLVM module flags to enable the feature. This flag will be ignored for all non-Windows targets.
|
||||
|
||||
|
||||
## When to use Control Flow Guard
|
||||
|
||||
The primary motivation for enabling CFG in Rust is to enhance security when linking against non-Rust code, especially C/C++ code. To achieve full CFG protection, all indirect calls (including any from Rust code) must have the appropriate CFG checks, as added by this flag. CFG can also improve security for Rust code that uses the `unsafe` keyword
|
||||
|
||||
|
||||
## Overhead of Control Flow Guard
|
||||
|
||||
The CFG checks and metadata can potentially increase binary size and runtime overhead. The magnitude of any increase depends on the number and frequency of indirect calls. For example, enabling CFG for the Rust standard library increases binary size by approximately 0.14%. Enabling CFG in the SPEC CPU 2017 Integer Speed benchmark suite (compiled with Clang/LLVM) incurs approximate runtime overheads of between 0% and 8%, with a geometric mean of 2.9%.
|
||||
|
||||
|
||||
## Testing Control Flow Guard
|
||||
|
||||
The rustc flag `-Z control_flow_guard=nochecks` instructs LLVM to emit the list of valid call targets without inserting runtime checks. This flag should only be used for testing purposes as it does not provide security enforcement.
|
||||
|
||||
|
||||
## Control Flow Guard in libraries
|
||||
|
||||
It is strongly recommended to also enable CFG checks for all linked libraries, including the standard library.
|
||||
|
||||
To enable CFG in the standard library, use the [cargo `-Z build-std` functionality][build-std] to recompile the standard library with the same configuration options as the main program.
|
||||
|
||||
[build-std]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
|
||||
|
||||
|
|
@ -20,14 +44,14 @@ For example:
|
|||
```cmd
|
||||
rustup toolchain install --force nightly
|
||||
rustup component add rust-src
|
||||
SET RUSTFLAGS=-Zcontrol_flow_guard=checks
|
||||
SET RUSTFLAGS=-Z control_flow_guard=checks
|
||||
cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc
|
||||
```
|
||||
|
||||
```PowerShell
|
||||
rustup toolchain install --force nightly
|
||||
rustup component add rust-src
|
||||
$Env:RUSTFLAGS = "-Zcontrol_flow_guard=checks"
|
||||
$Env:RUSTFLAGS = "-Z control_flow_guard=checks"
|
||||
cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,16 @@ For example:
|
|||
```Bash
|
||||
cargo new testgcov --bin
|
||||
cd testgcov
|
||||
export RUSTFLAGS="-Zprofile"
|
||||
export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
|
||||
export CARGO_INCREMENTAL=0
|
||||
cargo build
|
||||
cargo run
|
||||
```
|
||||
|
||||
Once you've built and run your program, files with the `gcno` (after build) and `gcda` (after execution) extensions will be created.
|
||||
You can parse them with [llvm-cov gcov](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/mozilla/grcov).
|
||||
|
||||
Please note that `RUSTFLAGS` by default applies to everything that cargo builds and runs during a build!
|
||||
When the `--target` flag is explicitly passed to cargo, the `RUSTFLAGS` no longer apply to build scripts and procedural macros.
|
||||
For more fine-grained control consider passing a `RUSTC_WRAPPER` program to cargo that only adds the profiling flags to
|
||||
rustc for the specific crates you want to profile.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ Available options:
|
|||
|
||||
```sh
|
||||
--report-time [plain|colored]
|
||||
Show execution time of each test. Awailable values:
|
||||
Show execution time of each test. Available values:
|
||||
plain = do not colorize the execution time (default);
|
||||
colored = colorize output according to the `color`
|
||||
parameter value;
|
||||
|
|
|
|||
|
|
@ -468,12 +468,17 @@ Here is the list of currently supported register classes:
|
|||
| ARM | `qreg` | `q[0-15]` | `w` |
|
||||
| ARM | `qreg_low8` | `q[0-7]` | `t` |
|
||||
| ARM | `qreg_low4` | `q[0-3]` | `x` |
|
||||
| NVPTX | `reg16` | None\* | `h` |
|
||||
| NVPTX | `reg32` | None\* | `r` |
|
||||
| NVPTX | `reg64` | None\* | `l` |
|
||||
| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
|
||||
| RISC-V | `freg` | `f[0-31]` | `f` |
|
||||
|
||||
> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
|
||||
>
|
||||
> Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register.
|
||||
>
|
||||
> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
|
||||
|
||||
Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
|
||||
|
||||
|
|
@ -495,6 +500,9 @@ Each register class has constraints on which value types they can be used with.
|
|||
| ARM | `sreg` | `vfp2` | `i32`, `f32` |
|
||||
| ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |
|
||||
| ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |
|
||||
| NVPTX | `reg16` | None | `i8`, `i16` |
|
||||
| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
|
||||
| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
|
||||
| RISC-V32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
|
||||
| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
|
||||
| RISC-V | `freg` | `f` | `f32` |
|
||||
|
|
@ -610,6 +618,9 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
|
|||
| ARM | `dreg` | None | `d0` | `P` |
|
||||
| ARM | `qreg` | None | `q0` | `q` |
|
||||
| ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |
|
||||
| NVPTX | `reg16` | None | `rs0` | None |
|
||||
| NVPTX | `reg32` | None | `r0` | None |
|
||||
| NVPTX | `reg64` | None | `rd0` | None |
|
||||
| RISC-V | `reg` | None | `x1` | None |
|
||||
| RISC-V | `freg` | None | `f0` | None |
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
# `default_free_fn`
|
||||
|
||||
The tracking issue for this feature is: [#73014]
|
||||
|
||||
[#73014]: https://github.com/rust-lang/rust/issues/73014
|
||||
|
||||
------------------------
|
||||
|
||||
Adds a free `default()` function to the `std::default` module. This function
|
||||
just forwards to [`Default::default()`], but may remove repetition of the word
|
||||
"default" from the call site.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```rust
|
||||
#![feature(default_free_fn)]
|
||||
use std::default::default;
|
||||
|
||||
#[derive(Default)]
|
||||
struct AppConfig {
|
||||
foo: FooConfig,
|
||||
bar: BarConfig,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FooConfig {
|
||||
foo: i32,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct BarConfig {
|
||||
bar: f32,
|
||||
baz: u8,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let options = AppConfig {
|
||||
foo: default(),
|
||||
bar: BarConfig {
|
||||
bar: 10.1,
|
||||
..default()
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
|
@ -865,6 +865,25 @@ impl From<Box<str>> for Box<[u8]> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "box_from_array", since = "1.45.0")]
|
||||
impl<T, const N: usize> From<[T; N]> for Box<[T]>
|
||||
where
|
||||
[T; N]: LengthAtMost32,
|
||||
{
|
||||
/// Converts a `[T; N]` into a `Box<[T]>`
|
||||
///
|
||||
/// This conversion moves the array to newly heap-allocated memory.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```rust
|
||||
/// let boxed: Box<[u8]> = Box::from([4, 2]);
|
||||
/// println!("{:?}", boxed);
|
||||
/// ```
|
||||
fn from(array: [T; N]) -> Box<[T]> {
|
||||
box array
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
|
||||
impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]>
|
||||
where
|
||||
|
|
@ -1090,6 +1109,14 @@ impl<T: Clone> Clone for Box<[T]> {
|
|||
fn clone(&self) -> Self {
|
||||
self.to_vec().into_boxed_slice()
|
||||
}
|
||||
|
||||
fn clone_from(&mut self, other: &Self) {
|
||||
if self.len() == other.len() {
|
||||
self.clone_from_slice(&other);
|
||||
} else {
|
||||
*self = other.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "box_borrow", since = "1.1.0")]
|
||||
|
|
|
|||
|
|
@ -1376,6 +1376,16 @@ impl<T: Ord> Extend<T> for BinaryHeap<T> {
|
|||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
<Self as SpecExtend<I>>::spec_extend(self, iter);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, item: T) {
|
||||
self.push(item);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
self.reserve(additional);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord, I: IntoIterator<Item = T>> SpecExtend<I> for BinaryHeap<T> {
|
||||
|
|
@ -1406,4 +1416,14 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap<T> {
|
|||
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().cloned());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, &item: &'a T) {
|
||||
self.push(item);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
self.reserve(additional);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1901,6 +1901,11 @@ impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
|
|||
self.insert(k, v);
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, (k, v): (K, V)) {
|
||||
self.insert(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "extend_ref", since = "1.2.0")]
|
||||
|
|
@ -1908,6 +1913,11 @@ impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap<K, V> {
|
|||
fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) {
|
||||
self.insert(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -1152,6 +1152,11 @@ impl<T: Ord> Extend<T> for BTreeSet<T> {
|
|||
self.insert(elem);
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, elem: T) {
|
||||
self.insert(elem);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "extend_ref", since = "1.2.0")]
|
||||
|
|
@ -1159,6 +1164,11 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet<T> {
|
|||
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().cloned());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, &elem: &'a T) {
|
||||
self.insert(elem);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -1748,6 +1748,11 @@ impl<T> Extend<T> for LinkedList<T> {
|
|||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
<Self as SpecExtend<I>>::spec_extend(self, iter);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, elem: T) {
|
||||
self.push_back(elem);
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: IntoIterator> SpecExtend<I> for LinkedList<I::Item> {
|
||||
|
|
@ -1767,6 +1772,11 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList<T> {
|
|||
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().cloned());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, &elem: &'a T) {
|
||||
self.push_back(elem);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -2881,6 +2881,16 @@ impl<A> Extend<A> for VecDeque<A> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, elem: A) {
|
||||
self.push_back(elem);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
self.reserve(additional);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "extend_ref", since = "1.2.0")]
|
||||
|
|
@ -2888,6 +2898,16 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque<T> {
|
|||
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().cloned());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, &elem: &T) {
|
||||
self.push_back(elem);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
self.reserve(additional);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@
|
|||
#![feature(container_error_extra)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(fmt_internals)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(fundamental)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use core::ptr::{NonNull, Unique};
|
|||
use core::slice;
|
||||
|
||||
use crate::alloc::{
|
||||
handle_alloc_error, AllocErr,
|
||||
handle_alloc_error,
|
||||
AllocInit::{self, *},
|
||||
AllocRef, Global, Layout,
|
||||
ReallocPlacement::{self, *},
|
||||
|
|
@ -118,6 +118,30 @@ impl<T> RawVec<T, Global> {
|
|||
RawVec::from_raw_parts(slice.as_mut_ptr(), slice.len())
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
|
||||
///
|
||||
/// Note that this will correctly reconstitute any `cap` changes
|
||||
/// that may have been performed. (See description of type for details.)
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `len` must be greater than or equal to the most recently requested capacity, and
|
||||
/// * `len` must be less than or equal to `self.capacity()`.
|
||||
///
|
||||
/// Note, that the requested capacity and `self.capacity()` could differ, as
|
||||
/// an allocator could overallocate and return a greater memory block than requested.
|
||||
pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>]> {
|
||||
// Sanity-check one half of the safety requirement (we cannot check the other half).
|
||||
debug_assert!(
|
||||
len <= self.capacity(),
|
||||
"`len` must be smaller than or equal to `self.capacity()`"
|
||||
);
|
||||
|
||||
let me = ManuallyDrop::new(self);
|
||||
let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len);
|
||||
Box::from_raw(slice)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: AllocRef> RawVec<T, A> {
|
||||
|
|
@ -211,13 +235,13 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Ensures that the buffer contains at least enough space to hold
|
||||
/// `used_capacity + needed_extra_capacity` elements. If it doesn't already have
|
||||
/// enough capacity, will reallocate enough space plus comfortable slack
|
||||
/// space to get amortized `O(1)` behavior. Will limit this behavior
|
||||
/// if it would needlessly cause itself to panic.
|
||||
/// Ensures that the buffer contains at least enough space to hold `len +
|
||||
/// additional` elements. If it doesn't already have enough capacity, will
|
||||
/// reallocate enough space plus comfortable slack space to get amortized
|
||||
/// `O(1)` behavior. Will limit this behavior if it would needlessly cause
|
||||
/// itself to panic.
|
||||
///
|
||||
/// If `used_capacity` exceeds `self.capacity()`, this may fail to actually allocate
|
||||
/// If `len` exceeds `self.capacity()`, this may fail to actually allocate
|
||||
/// the requested space. This is not really unsafe, but the unsafe
|
||||
/// code *you* write that relies on the behavior of this function may break.
|
||||
///
|
||||
|
|
@ -263,8 +287,8 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
/// # vector.push_all(&[1, 3, 5, 7, 9]);
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn reserve(&mut self, used_capacity: usize, needed_extra_capacity: usize) {
|
||||
match self.try_reserve(used_capacity, needed_extra_capacity) {
|
||||
pub fn reserve(&mut self, len: usize, additional: usize) {
|
||||
match self.try_reserve(len, additional) {
|
||||
Err(CapacityOverflow) => capacity_overflow(),
|
||||
Err(AllocError { layout, .. }) => handle_alloc_error(layout),
|
||||
Ok(()) => { /* yay */ }
|
||||
|
|
@ -272,55 +296,23 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
}
|
||||
|
||||
/// The same as `reserve`, but returns on errors instead of panicking or aborting.
|
||||
pub fn try_reserve(
|
||||
&mut self,
|
||||
used_capacity: usize,
|
||||
needed_extra_capacity: usize,
|
||||
) -> Result<(), TryReserveError> {
|
||||
if self.needs_to_grow(used_capacity, needed_extra_capacity) {
|
||||
self.grow_amortized(used_capacity, needed_extra_capacity, MayMove)
|
||||
pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
|
||||
if self.needs_to_grow(len, additional) {
|
||||
self.grow_amortized(len, additional)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to ensure that the buffer contains at least enough space to hold
|
||||
/// `used_capacity + needed_extra_capacity` elements. If it doesn't already have
|
||||
/// enough capacity, will reallocate in place enough space plus comfortable slack
|
||||
/// space to get amortized `O(1)` behavior. Will limit this behaviour
|
||||
/// if it would needlessly cause itself to panic.
|
||||
/// Ensures that the buffer contains at least enough space to hold `len +
|
||||
/// additional` elements. If it doesn't already, will reallocate the
|
||||
/// minimum possible amount of memory necessary. Generally this will be
|
||||
/// exactly the amount of memory necessary, but in principle the allocator
|
||||
/// is free to give back more than we asked for.
|
||||
///
|
||||
/// If `used_capacity` exceeds `self.capacity()`, this may fail to actually allocate
|
||||
/// the requested space. This is not really unsafe, but the unsafe
|
||||
/// code *you* write that relies on the behavior of this function may break.
|
||||
///
|
||||
/// Returns `true` if the reallocation attempt has succeeded.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// * Panics if the requested capacity exceeds `usize::MAX` bytes.
|
||||
/// * Panics on 32-bit platforms if the requested capacity exceeds
|
||||
/// `isize::MAX` bytes.
|
||||
pub fn reserve_in_place(&mut self, used_capacity: usize, needed_extra_capacity: usize) -> bool {
|
||||
// This is more readable than putting this in one line:
|
||||
// `!self.needs_to_grow(...) || self.grow(...).is_ok()`
|
||||
if self.needs_to_grow(used_capacity, needed_extra_capacity) {
|
||||
self.grow_amortized(used_capacity, needed_extra_capacity, InPlace).is_ok()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures that the buffer contains at least enough space to hold
|
||||
/// `used_capacity + needed_extra_capacity` elements. If it doesn't already,
|
||||
/// will reallocate the minimum possible amount of memory necessary.
|
||||
/// Generally this will be exactly the amount of memory necessary,
|
||||
/// but in principle the allocator is free to give back more than
|
||||
/// we asked for.
|
||||
///
|
||||
/// If `used_capacity` exceeds `self.capacity()`, this may fail to actually allocate
|
||||
/// the requested space. This is not really unsafe, but the unsafe
|
||||
/// code *you* write that relies on the behavior of this function may break.
|
||||
/// If `len` exceeds `self.capacity()`, this may fail to actually allocate
|
||||
/// the requested space. This is not really unsafe, but the unsafe code
|
||||
/// *you* write that relies on the behavior of this function may break.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
|
@ -331,8 +323,8 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
/// # Aborts
|
||||
///
|
||||
/// Aborts on OOM.
|
||||
pub fn reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize) {
|
||||
match self.try_reserve_exact(used_capacity, needed_extra_capacity) {
|
||||
pub fn reserve_exact(&mut self, len: usize, additional: usize) {
|
||||
match self.try_reserve_exact(len, additional) {
|
||||
Err(CapacityOverflow) => capacity_overflow(),
|
||||
Err(AllocError { layout, .. }) => handle_alloc_error(layout),
|
||||
Ok(()) => { /* yay */ }
|
||||
|
|
@ -342,14 +334,10 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
/// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
|
||||
pub fn try_reserve_exact(
|
||||
&mut self,
|
||||
used_capacity: usize,
|
||||
needed_extra_capacity: usize,
|
||||
len: usize,
|
||||
additional: usize,
|
||||
) -> Result<(), TryReserveError> {
|
||||
if self.needs_to_grow(used_capacity, needed_extra_capacity) {
|
||||
self.grow_exact(used_capacity, needed_extra_capacity)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
if self.needs_to_grow(len, additional) { self.grow_exact(len, additional) } else { Ok(()) }
|
||||
}
|
||||
|
||||
/// Shrinks the allocation down to the specified amount. If the given amount
|
||||
|
|
@ -374,8 +362,8 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
impl<T, A: AllocRef> RawVec<T, A> {
|
||||
/// Returns if the buffer needs to grow to fulfill the needed extra capacity.
|
||||
/// Mainly used to make inlining reserve-calls possible without inlining `grow`.
|
||||
fn needs_to_grow(&self, used_capacity: usize, needed_extra_capacity: usize) -> bool {
|
||||
needed_extra_capacity > self.capacity().wrapping_sub(used_capacity)
|
||||
fn needs_to_grow(&self, len: usize, additional: usize) -> bool {
|
||||
additional > self.capacity().wrapping_sub(len)
|
||||
}
|
||||
|
||||
fn capacity_from_bytes(excess: usize) -> usize {
|
||||
|
|
@ -395,14 +383,9 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
// so that all of the code that depends on `T` is within it, while as much
|
||||
// of the code that doesn't depend on `T` as possible is in functions that
|
||||
// are non-generic over `T`.
|
||||
fn grow_amortized(
|
||||
&mut self,
|
||||
used_capacity: usize,
|
||||
needed_extra_capacity: usize,
|
||||
placement: ReallocPlacement,
|
||||
) -> Result<(), TryReserveError> {
|
||||
fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
|
||||
// This is ensured by the calling contexts.
|
||||
debug_assert!(needed_extra_capacity > 0);
|
||||
debug_assert!(additional > 0);
|
||||
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// Since we return a capacity of `usize::MAX` when `elem_size` is
|
||||
|
|
@ -411,8 +394,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
}
|
||||
|
||||
// Nothing we can really do about these checks, sadly.
|
||||
let required_cap =
|
||||
used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
|
||||
let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
|
||||
|
||||
// This guarantees exponential growth. The doubling cannot overflow
|
||||
// because `cap <= isize::MAX` and the type of `cap` is `usize`.
|
||||
|
|
@ -437,7 +419,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
let new_layout = Layout::array::<T>(cap);
|
||||
|
||||
// `finish_grow` is non-generic over `T`.
|
||||
let memory = finish_grow(new_layout, placement, self.current_memory(), &mut self.alloc)?;
|
||||
let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
|
||||
self.set_memory(memory);
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -445,22 +427,18 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
// The constraints on this method are much the same as those on
|
||||
// `grow_amortized`, but this method is usually instantiated less often so
|
||||
// it's less critical.
|
||||
fn grow_exact(
|
||||
&mut self,
|
||||
used_capacity: usize,
|
||||
needed_extra_capacity: usize,
|
||||
) -> Result<(), TryReserveError> {
|
||||
fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// Since we return a capacity of `usize::MAX` when the type size is
|
||||
// 0, getting to here necessarily means the `RawVec` is overfull.
|
||||
return Err(CapacityOverflow);
|
||||
}
|
||||
|
||||
let cap = used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
|
||||
let cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
|
||||
let new_layout = Layout::array::<T>(cap);
|
||||
|
||||
// `finish_grow` is non-generic over `T`.
|
||||
let memory = finish_grow(new_layout, MayMove, self.current_memory(), &mut self.alloc)?;
|
||||
let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?;
|
||||
self.set_memory(memory);
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -494,7 +472,6 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
|||
// much smaller than the number of `T` types.)
|
||||
fn finish_grow<A>(
|
||||
new_layout: Result<Layout, LayoutErr>,
|
||||
placement: ReallocPlacement,
|
||||
current_memory: Option<(NonNull<u8>, Layout)>,
|
||||
alloc: &mut A,
|
||||
) -> Result<MemoryBlock, TryReserveError>
|
||||
|
|
@ -508,44 +485,15 @@ where
|
|||
|
||||
let memory = if let Some((ptr, old_layout)) = current_memory {
|
||||
debug_assert_eq!(old_layout.align(), new_layout.align());
|
||||
unsafe { alloc.grow(ptr, old_layout, new_layout.size(), placement, Uninitialized) }
|
||||
unsafe { alloc.grow(ptr, old_layout, new_layout.size(), MayMove, Uninitialized) }
|
||||
} else {
|
||||
match placement {
|
||||
MayMove => alloc.alloc(new_layout, Uninitialized),
|
||||
InPlace => Err(AllocErr),
|
||||
}
|
||||
alloc.alloc(new_layout, Uninitialized)
|
||||
}
|
||||
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?;
|
||||
|
||||
Ok(memory)
|
||||
}
|
||||
|
||||
impl<T> RawVec<T, Global> {
|
||||
/// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
|
||||
///
|
||||
/// Note that this will correctly reconstitute any `cap` changes
|
||||
/// that may have been performed. (See description of type for details.)
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `len` must be greater than or equal to the most recently requested capacity, and
|
||||
/// * `len` must be less than or equal to `self.capacity()`.
|
||||
///
|
||||
/// Note, that the requested capacity and `self.capacity()` could differ, as
|
||||
/// an allocator could overallocate and return a greater memory block than requested.
|
||||
pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>]> {
|
||||
// Sanity-check one half of the safety requirement (we cannot check the other half).
|
||||
debug_assert!(
|
||||
len <= self.capacity(),
|
||||
"`len` must be smaller than or equal to `self.capacity()`"
|
||||
);
|
||||
|
||||
let me = ManuallyDrop::new(self);
|
||||
let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len);
|
||||
Box::from_raw(slice)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec<T, A> {
|
||||
/// Frees the memory owned by the `RawVec` *without* trying to drop its contents.
|
||||
fn drop(&mut self) {
|
||||
|
|
|
|||
|
|
@ -580,8 +580,6 @@ impl<T: ?Sized> Rc<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(weak_into_raw)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let x = Rc::new("hello".to_owned());
|
||||
|
|
@ -590,7 +588,7 @@ impl<T: ?Sized> Rc<T> {
|
|||
/// assert_eq!(x_ptr, Rc::as_ptr(&y));
|
||||
/// assert_eq!(unsafe { &*x_ptr }, "hello");
|
||||
/// ```
|
||||
#[unstable(feature = "weak_into_raw", issue = "60728")]
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn as_ptr(this: &Self) -> *const T {
|
||||
let ptr: *mut RcBox<T> = NonNull::as_ptr(this.ptr);
|
||||
let fake_ptr = ptr as *mut T;
|
||||
|
|
@ -1681,8 +1679,6 @@ impl<T> Weak<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(weak_into_raw)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
/// use std::ptr;
|
||||
///
|
||||
|
|
@ -1700,7 +1696,7 @@ impl<T> Weak<T> {
|
|||
/// ```
|
||||
///
|
||||
/// [`null`]: ../../std/ptr/fn.null.html
|
||||
#[unstable(feature = "weak_into_raw", issue = "60728")]
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
let offset = data_offset_sized::<T>();
|
||||
let ptr = self.ptr.cast::<u8>().as_ptr().wrapping_offset(offset);
|
||||
|
|
@ -1718,8 +1714,6 @@ impl<T> Weak<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(weak_into_raw)]
|
||||
///
|
||||
/// use std::rc::{Rc, Weak};
|
||||
///
|
||||
/// let strong = Rc::new("hello".to_owned());
|
||||
|
|
@ -1735,7 +1729,7 @@ impl<T> Weak<T> {
|
|||
///
|
||||
/// [`from_raw`]: struct.Weak.html#method.from_raw
|
||||
/// [`as_ptr`]: struct.Weak.html#method.as_ptr
|
||||
#[unstable(feature = "weak_into_raw", issue = "60728")]
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn into_raw(self) -> *const T {
|
||||
let result = self.as_ptr();
|
||||
mem::forget(self);
|
||||
|
|
@ -1762,8 +1756,6 @@ impl<T> Weak<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(weak_into_raw)]
|
||||
///
|
||||
/// use std::rc::{Rc, Weak};
|
||||
///
|
||||
/// let strong = Rc::new("hello".to_owned());
|
||||
|
|
@ -1788,7 +1780,7 @@ impl<T> Weak<T> {
|
|||
/// [`Weak`]: struct.Weak.html
|
||||
/// [`new`]: struct.Weak.html#method.new
|
||||
/// [`forget`]: ../../std/mem/fn.forget.html
|
||||
#[unstable(feature = "weak_into_raw", issue = "60728")]
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
||||
if ptr.is_null() {
|
||||
Self::new()
|
||||
|
|
@ -2043,11 +2035,7 @@ trait RcBoxPtr<T: ?Sized> {
|
|||
// nevertheless, we insert an abort here to hint LLVM at
|
||||
// an otherwise missed optimization.
|
||||
if strong == 0 || strong == usize::max_value() {
|
||||
// remove `unsafe` on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
abort();
|
||||
}
|
||||
self.inner().strong.set(strong + 1);
|
||||
}
|
||||
|
|
@ -2071,11 +2059,7 @@ trait RcBoxPtr<T: ?Sized> {
|
|||
// nevertheless, we insert an abort here to hint LLVM at
|
||||
// an otherwise missed optimization.
|
||||
if weak == 0 || weak == usize::max_value() {
|
||||
// remove `unsafe` on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
abort();
|
||||
}
|
||||
self.inner().weak.set(weak + 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1799,6 +1799,16 @@ impl Extend<char> for String {
|
|||
self.reserve(lower_bound);
|
||||
iterator.for_each(move |c| self.push(c));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, c: char) {
|
||||
self.push(c);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
self.reserve(additional);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "extend_ref", since = "1.2.0")]
|
||||
|
|
@ -1806,6 +1816,16 @@ impl<'a> Extend<&'a char> for String {
|
|||
fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().cloned());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, &c: &'a char) {
|
||||
self.push(c);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
self.reserve(additional);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1813,6 +1833,11 @@ impl<'a> Extend<&'a str> for String {
|
|||
fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
|
||||
iter.into_iter().for_each(move |s| self.push_str(s));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, s: &'a str) {
|
||||
self.push_str(s);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "extend_string", since = "1.4.0")]
|
||||
|
|
@ -1820,6 +1845,11 @@ impl Extend<String> for String {
|
|||
fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
|
||||
iter.into_iter().for_each(move |s| self.push_str(&s));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, s: String) {
|
||||
self.push_str(&s);
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "herd_cows", since = "1.19.0")]
|
||||
|
|
@ -1827,6 +1857,11 @@ impl<'a> Extend<Cow<'a, str>> for String {
|
|||
fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
|
||||
iter.into_iter().for_each(move |s| self.push_str(&s));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, s: Cow<'a, str>) {
|
||||
self.push_str(&s);
|
||||
}
|
||||
}
|
||||
|
||||
/// A convenience impl that delegates to the impl for `&str`.
|
||||
|
|
|
|||
|
|
@ -579,8 +579,6 @@ impl<T: ?Sized> Arc<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(weak_into_raw)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let x = Arc::new("hello".to_owned());
|
||||
|
|
@ -589,7 +587,7 @@ impl<T: ?Sized> Arc<T> {
|
|||
/// assert_eq!(x_ptr, Arc::as_ptr(&y));
|
||||
/// assert_eq!(unsafe { &*x_ptr }, "hello");
|
||||
/// ```
|
||||
#[unstable(feature = "weak_into_raw", issue = "60728")]
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn as_ptr(this: &Self) -> *const T {
|
||||
let ptr: *mut ArcInner<T> = NonNull::as_ptr(this.ptr);
|
||||
let fake_ptr = ptr as *mut T;
|
||||
|
|
@ -867,12 +865,10 @@ impl<T: ?Sized> Arc<T> {
|
|||
unsafe fn drop_slow(&mut self) {
|
||||
// Destroy the data at this time, even though we may not free the box
|
||||
// allocation itself (there may still be weak pointers lying around).
|
||||
ptr::drop_in_place(&mut self.ptr.as_mut().data);
|
||||
ptr::drop_in_place(Self::get_mut_unchecked(self));
|
||||
|
||||
if self.inner().weak.fetch_sub(1, Release) == 1 {
|
||||
acquire!(self.inner().weak);
|
||||
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()))
|
||||
}
|
||||
// Drop the weak ref collectively held by all strong references
|
||||
drop(Weak { ptr: self.ptr });
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1097,11 +1093,7 @@ impl<T: ?Sized> Clone for Arc<T> {
|
|||
// We abort because such a program is incredibly degenerate, and we
|
||||
// don't care to support it.
|
||||
if old_size > MAX_REFCOUNT {
|
||||
// remove `unsafe` on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
Self::from_inner(self.ptr)
|
||||
|
|
@ -1204,7 +1196,7 @@ impl<T: Clone> Arc<T> {
|
|||
|
||||
// As with `get_mut()`, the unsafety is ok because our reference was
|
||||
// either unique to begin with, or became one upon cloning the contents.
|
||||
unsafe { &mut this.ptr.as_mut().data }
|
||||
unsafe { Self::get_mut_unchecked(this) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1280,7 +1272,9 @@ impl<T: ?Sized> Arc<T> {
|
|||
#[inline]
|
||||
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
|
||||
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
|
||||
&mut this.ptr.as_mut().data
|
||||
// We are careful to *not* create a reference covering the "count" fields, as
|
||||
// this would alias with concurrent access to the reference counts (e.g. by `Weak`).
|
||||
&mut (*this.ptr.as_ptr()).data
|
||||
}
|
||||
|
||||
/// Determine whether this is the unique reference (including weak refs) to
|
||||
|
|
@ -1449,8 +1443,6 @@ impl<T> Weak<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(weak_into_raw)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
/// use std::ptr;
|
||||
///
|
||||
|
|
@ -1468,7 +1460,7 @@ impl<T> Weak<T> {
|
|||
/// ```
|
||||
///
|
||||
/// [`null`]: ../../std/ptr/fn.null.html
|
||||
#[unstable(feature = "weak_into_raw", issue = "60728")]
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
let offset = data_offset_sized::<T>();
|
||||
let ptr = self.ptr.cast::<u8>().as_ptr().wrapping_offset(offset);
|
||||
|
|
@ -1486,8 +1478,6 @@ impl<T> Weak<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(weak_into_raw)]
|
||||
///
|
||||
/// use std::sync::{Arc, Weak};
|
||||
///
|
||||
/// let strong = Arc::new("hello".to_owned());
|
||||
|
|
@ -1503,7 +1493,7 @@ impl<T> Weak<T> {
|
|||
///
|
||||
/// [`from_raw`]: struct.Weak.html#method.from_raw
|
||||
/// [`as_ptr`]: struct.Weak.html#method.as_ptr
|
||||
#[unstable(feature = "weak_into_raw", issue = "60728")]
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub fn into_raw(self) -> *const T {
|
||||
let result = self.as_ptr();
|
||||
mem::forget(self);
|
||||
|
|
@ -1531,8 +1521,6 @@ impl<T> Weak<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(weak_into_raw)]
|
||||
///
|
||||
/// use std::sync::{Arc, Weak};
|
||||
///
|
||||
/// let strong = Arc::new("hello".to_owned());
|
||||
|
|
@ -1557,7 +1545,7 @@ impl<T> Weak<T> {
|
|||
/// [`Weak`]: struct.Weak.html
|
||||
/// [`Arc`]: struct.Arc.html
|
||||
/// [`forget`]: ../../std/mem/fn.forget.html
|
||||
#[unstable(feature = "weak_into_raw", issue = "60728")]
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
||||
if ptr.is_null() {
|
||||
Self::new()
|
||||
|
|
@ -1571,6 +1559,13 @@ impl<T> Weak<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Helper type to allow accessing the reference counts without
|
||||
/// making any assertions about the data field.
|
||||
struct WeakInner<'a> {
|
||||
weak: &'a atomic::AtomicUsize,
|
||||
strong: &'a atomic::AtomicUsize,
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Weak<T> {
|
||||
/// Attempts to upgrade the `Weak` pointer to an [`Arc`], delaying
|
||||
/// dropping of the inner value if successful.
|
||||
|
|
@ -1617,11 +1612,7 @@ impl<T: ?Sized> Weak<T> {
|
|||
|
||||
// See comments in `Arc::clone` for why we do this (for `mem::forget`).
|
||||
if n > MAX_REFCOUNT {
|
||||
// remove `unsafe` on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
// Relaxed is valid for the same reason it is on Arc's Clone impl
|
||||
|
|
@ -1678,8 +1669,18 @@ impl<T: ?Sized> Weak<T> {
|
|||
/// Returns `None` when the pointer is dangling and there is no allocated `ArcInner`,
|
||||
/// (i.e., when this `Weak` was created by `Weak::new`).
|
||||
#[inline]
|
||||
fn inner(&self) -> Option<&ArcInner<T>> {
|
||||
if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) }
|
||||
fn inner(&self) -> Option<WeakInner<'_>> {
|
||||
if is_dangling(self.ptr) {
|
||||
None
|
||||
} else {
|
||||
// We are careful to *not* create a reference covering the "data" field, as
|
||||
// the field may be mutated concurrently (for example, if the last `Arc`
|
||||
// is dropped, the data field will be dropped in-place).
|
||||
Some(unsafe {
|
||||
let ptr = self.ptr.as_ptr();
|
||||
WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the two `Weak`s point to the same allocation (similar to
|
||||
|
|
@ -1758,10 +1759,7 @@ impl<T: ?Sized> Clone for Weak<T> {
|
|||
|
||||
// See comments in Arc::clone() for why we do this (for mem::forget).
|
||||
if old_size > MAX_REFCOUNT {
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // remove `unsafe` on bootstrap bump
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
Weak { ptr: self.ptr }
|
||||
|
|
|
|||
|
|
@ -16,3 +16,36 @@ fn unitialized_zero_size_box() {
|
|||
NonNull::<MaybeUninit<String>>::dangling().as_ptr(),
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
struct Dummy {
|
||||
_data: u8,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn box_clone_and_clone_from_equivalence() {
|
||||
for size in (0..8).map(|i| 2usize.pow(i)) {
|
||||
let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
|
||||
let clone = control.clone();
|
||||
let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
|
||||
copy.clone_from(&control);
|
||||
assert_eq!(control, clone);
|
||||
assert_eq!(control, copy);
|
||||
}
|
||||
}
|
||||
|
||||
/// This test might give a false positive in case the box realocates, but the alocator keeps the
|
||||
/// original pointer.
|
||||
///
|
||||
/// On the other hand it won't give a false negative, if it fails than the memory was definitly not
|
||||
/// reused
|
||||
#[test]
|
||||
fn box_clone_from_ptr_stability() {
|
||||
for size in (0..8).map(|i| 2usize.pow(i)) {
|
||||
let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
|
||||
let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
|
||||
let copy_raw = copy.as_ptr() as usize;
|
||||
copy.clone_from(&control);
|
||||
assert_eq!(copy.as_ptr() as usize, copy_raw);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ impl Drop for DropCounter<'_> {
|
|||
|
||||
#[test]
|
||||
fn test_small_vec_struct() {
|
||||
assert!(size_of::<Vec<u8>>() == size_of::<usize>() * 3);
|
||||
assert_eq!(size_of::<Vec<u8>>(), size_of::<usize>() * 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -343,14 +343,19 @@ impl<T> Vec<T> {
|
|||
///
|
||||
/// // The vector contains no items, even though it has capacity for more
|
||||
/// assert_eq!(vec.len(), 0);
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
///
|
||||
/// // These are all done without reallocating...
|
||||
/// for i in 0..10 {
|
||||
/// vec.push(i);
|
||||
/// }
|
||||
/// assert_eq!(vec.len(), 10);
|
||||
/// assert_eq!(vec.capacity(), 10);
|
||||
///
|
||||
/// // ...but this may make the vector reallocate
|
||||
/// vec.push(11);
|
||||
/// assert_eq!(vec.len(), 11);
|
||||
/// assert!(vec.capacity() >= 11);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -979,7 +984,7 @@ impl<T> Vec<T> {
|
|||
// bounds check above succeeds there must be a last element (which
|
||||
// can be self[index] itself).
|
||||
let last = ptr::read(self.as_ptr().add(len - 1));
|
||||
let hole: *mut T = self.as_mut_ptr().add(index);
|
||||
let hole = self.as_mut_ptr().add(index);
|
||||
self.set_len(len - 1);
|
||||
ptr::replace(hole, last)
|
||||
}
|
||||
|
|
@ -1900,6 +1905,22 @@ unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
|
|||
// Common trait implementations for Vec
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Deref for Vec<T> {
|
||||
type Target = [T];
|
||||
|
||||
fn deref(&self) -> &[T] {
|
||||
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::DerefMut for Vec<T> {
|
||||
fn deref_mut(&mut self) -> &mut [T] {
|
||||
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Clone> Clone for Vec<T> {
|
||||
#[cfg(not(test))]
|
||||
|
|
@ -1955,22 +1976,6 @@ impl<T, I: SliceIndex<[T]>> IndexMut<I> for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::Deref for Vec<T> {
|
||||
type Target = [T];
|
||||
|
||||
fn deref(&self) -> &[T] {
|
||||
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ops::DerefMut for Vec<T> {
|
||||
fn deref_mut(&mut self) -> &mut [T] {
|
||||
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> FromIterator<T> for Vec<T> {
|
||||
#[inline]
|
||||
|
|
@ -2045,6 +2050,16 @@ impl<T> Extend<T> for Vec<T> {
|
|||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
<Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, item: T) {
|
||||
self.push(item);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
self.reserve(additional);
|
||||
}
|
||||
}
|
||||
|
||||
// Specialization trait used for Vec::from_iter and Vec::extend
|
||||
|
|
@ -2316,6 +2331,16 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for Vec<T> {
|
|||
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||
self.spec_extend(iter.into_iter())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_one(&mut self, &item: &'a T) {
|
||||
self.push(item);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
self.reserve(additional);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! __impl_slice_eq1 {
|
||||
|
|
@ -2603,6 +2628,13 @@ impl<T> IntoIter<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]
|
||||
impl<T> AsRef<[T]> for IntoIter<T> {
|
||||
fn as_ref(&self) -> &[T] {
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe impl<T: Send> Send for IntoIter<T> {}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -2945,12 +2977,12 @@ impl<T> Drain<'_, T> {
|
|||
}
|
||||
|
||||
/// Makes room for inserting more elements before the tail.
|
||||
unsafe fn move_tail(&mut self, extra_capacity: usize) {
|
||||
unsafe fn move_tail(&mut self, additional: usize) {
|
||||
let vec = self.vec.as_mut();
|
||||
let used_capacity = self.tail_start + self.tail_len;
|
||||
vec.buf.reserve(used_capacity, extra_capacity);
|
||||
let len = self.tail_start + self.tail_len;
|
||||
vec.buf.reserve(len, additional);
|
||||
|
||||
let new_tail_start = self.tail_start + extra_capacity;
|
||||
let new_tail_start = self.tail_start + additional;
|
||||
let src = vec.as_ptr().add(self.tail_start);
|
||||
let dst = vec.as_mut_ptr().add(new_tail_start);
|
||||
ptr::copy(src, dst, self.tail_len);
|
||||
|
|
|
|||
|
|
@ -849,11 +849,11 @@ impl<T: ?Sized> RefCell<T> {
|
|||
/// ```
|
||||
/// use std::cell::RefCell;
|
||||
///
|
||||
/// let c = RefCell::new(5);
|
||||
/// let c = RefCell::new("hello".to_owned());
|
||||
///
|
||||
/// *c.borrow_mut() = 7;
|
||||
/// *c.borrow_mut() = "bonjour".to_owned();
|
||||
///
|
||||
/// assert_eq!(*c.borrow(), 7);
|
||||
/// assert_eq!(&*c.borrow(), "bonjour");
|
||||
/// ```
|
||||
///
|
||||
/// An example of panic:
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ pub fn from_u32(i: u32) -> Option<char> {
|
|||
#[inline]
|
||||
#[stable(feature = "char_from_unchecked", since = "1.5.0")]
|
||||
pub unsafe fn from_u32_unchecked(i: u32) -> char {
|
||||
transmute(i)
|
||||
if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { transmute(i) }
|
||||
}
|
||||
|
||||
#[stable(feature = "char_convert", since = "1.13.0")]
|
||||
|
|
@ -218,7 +218,7 @@ impl TryFrom<u32> for char {
|
|||
Err(CharTryFromError(()))
|
||||
} else {
|
||||
// SAFETY: checked that it's a legal unicode value
|
||||
Ok(unsafe { from_u32_unchecked(i) })
|
||||
Ok(unsafe { transmute(i) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -593,16 +593,7 @@ impl char {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn len_utf8(self) -> usize {
|
||||
let code = self as u32;
|
||||
if code < MAX_ONE_B {
|
||||
1
|
||||
} else if code < MAX_TWO_B {
|
||||
2
|
||||
} else if code < MAX_THREE_B {
|
||||
3
|
||||
} else {
|
||||
4
|
||||
}
|
||||
len_utf8(self as u32)
|
||||
}
|
||||
|
||||
/// Returns the number of 16-bit code units this `char` would need if
|
||||
|
|
@ -670,36 +661,8 @@ impl char {
|
|||
#[stable(feature = "unicode_encode_char", since = "1.15.0")]
|
||||
#[inline]
|
||||
pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
|
||||
let code = self as u32;
|
||||
let len = self.len_utf8();
|
||||
match (len, &mut dst[..]) {
|
||||
(1, [a, ..]) => {
|
||||
*a = code as u8;
|
||||
}
|
||||
(2, [a, b, ..]) => {
|
||||
*a = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
||||
*b = (code & 0x3F) as u8 | TAG_CONT;
|
||||
}
|
||||
(3, [a, b, c, ..]) => {
|
||||
*a = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
||||
*b = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
*c = (code & 0x3F) as u8 | TAG_CONT;
|
||||
}
|
||||
(4, [a, b, c, d, ..]) => {
|
||||
*a = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
||||
*b = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
*c = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
*d = (code & 0x3F) as u8 | TAG_CONT;
|
||||
}
|
||||
_ => panic!(
|
||||
"encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
|
||||
len,
|
||||
code,
|
||||
dst.len(),
|
||||
),
|
||||
};
|
||||
// SAFETY: We just wrote UTF-8 content in, so converting to str is fine.
|
||||
unsafe { from_utf8_unchecked_mut(&mut dst[..len]) }
|
||||
// SAFETY: `char` is not a surrogate, so this is valid UTF-8.
|
||||
unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) }
|
||||
}
|
||||
|
||||
/// Encodes this character as UTF-16 into the provided `u16` buffer,
|
||||
|
|
@ -739,28 +702,7 @@ impl char {
|
|||
#[stable(feature = "unicode_encode_char", since = "1.15.0")]
|
||||
#[inline]
|
||||
pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
|
||||
let mut code = self as u32;
|
||||
// SAFETY: each arm checks whether there are enough bits to write into
|
||||
unsafe {
|
||||
if (code & 0xFFFF) == code && !dst.is_empty() {
|
||||
// The BMP falls through (assuming non-surrogate, as it should)
|
||||
*dst.get_unchecked_mut(0) = code as u16;
|
||||
slice::from_raw_parts_mut(dst.as_mut_ptr(), 1)
|
||||
} else if dst.len() >= 2 {
|
||||
// Supplementary planes break into surrogates.
|
||||
code -= 0x1_0000;
|
||||
*dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16);
|
||||
*dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF);
|
||||
slice::from_raw_parts_mut(dst.as_mut_ptr(), 2)
|
||||
} else {
|
||||
panic!(
|
||||
"encode_utf16: need {} units to encode U+{:X}, but the buffer has {}",
|
||||
from_u32_unchecked(code).len_utf16(),
|
||||
code,
|
||||
dst.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
encode_utf16_raw(self as u32, dst)
|
||||
}
|
||||
|
||||
/// Returns `true` if this `char` has the `Alphabetic` property.
|
||||
|
|
@ -1673,3 +1615,100 @@ impl char {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn len_utf8(code: u32) -> usize {
|
||||
if code < MAX_ONE_B {
|
||||
1
|
||||
} else if code < MAX_TWO_B {
|
||||
2
|
||||
} else if code < MAX_THREE_B {
|
||||
3
|
||||
} else {
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes a raw u32 value as UTF-8 into the provided byte buffer,
|
||||
/// and then returns the subslice of the buffer that contains the encoded character.
|
||||
///
|
||||
/// Unlike `char::encode_utf8`, this method also handles codepoints in the surrogate range.
|
||||
/// (Creating a `char` in the surrogate range is UB.)
|
||||
/// The result is valid [generalized UTF-8] but not valid UTF-8.
|
||||
///
|
||||
/// [generalized UTF-8]: https://simonsapin.github.io/wtf-8/#generalized-utf8
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the buffer is not large enough.
|
||||
/// A buffer of length four is large enough to encode any `char`.
|
||||
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] {
|
||||
let len = len_utf8(code);
|
||||
match (len, &mut dst[..]) {
|
||||
(1, [a, ..]) => {
|
||||
*a = code as u8;
|
||||
}
|
||||
(2, [a, b, ..]) => {
|
||||
*a = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
||||
*b = (code & 0x3F) as u8 | TAG_CONT;
|
||||
}
|
||||
(3, [a, b, c, ..]) => {
|
||||
*a = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
||||
*b = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
*c = (code & 0x3F) as u8 | TAG_CONT;
|
||||
}
|
||||
(4, [a, b, c, d, ..]) => {
|
||||
*a = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
||||
*b = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
*c = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
*d = (code & 0x3F) as u8 | TAG_CONT;
|
||||
}
|
||||
_ => panic!(
|
||||
"encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
|
||||
len,
|
||||
code,
|
||||
dst.len(),
|
||||
),
|
||||
};
|
||||
&mut dst[..len]
|
||||
}
|
||||
|
||||
/// Encodes a raw u32 value as UTF-16 into the provided `u16` buffer,
|
||||
/// and then returns the subslice of the buffer that contains the encoded character.
|
||||
///
|
||||
/// Unlike `char::encode_utf16`, this method also handles codepoints in the surrogate range.
|
||||
/// (Creating a `char` in the surrogate range is UB.)
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the buffer is not large enough.
|
||||
/// A buffer of length 2 is large enough to encode any `char`.
|
||||
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] {
|
||||
// SAFETY: each arm checks whether there are enough bits to write into
|
||||
unsafe {
|
||||
if (code & 0xFFFF) == code && !dst.is_empty() {
|
||||
// The BMP falls through
|
||||
*dst.get_unchecked_mut(0) = code as u16;
|
||||
slice::from_raw_parts_mut(dst.as_mut_ptr(), 1)
|
||||
} else if dst.len() >= 2 {
|
||||
// Supplementary planes break into surrogates.
|
||||
code -= 0x1_0000;
|
||||
*dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16);
|
||||
*dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF);
|
||||
slice::from_raw_parts_mut(dst.as_mut_ptr(), 2)
|
||||
} else {
|
||||
panic!(
|
||||
"encode_utf16: need {} units to encode U+{:X}, but the buffer has {}",
|
||||
from_u32_unchecked(code).len_utf16(),
|
||||
code,
|
||||
dst.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@ pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error};
|
|||
#[stable(feature = "unicode_version", since = "1.45.0")]
|
||||
pub use crate::unicode::UNICODE_VERSION;
|
||||
|
||||
// perma-unstable re-exports
|
||||
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
|
||||
pub use self::methods::encode_utf16_raw;
|
||||
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
|
||||
pub use self::methods::encode_utf8_raw;
|
||||
|
||||
use crate::fmt::{self, Write};
|
||||
use crate::iter::FusedIterator;
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,50 @@ pub trait Default: Sized {
|
|||
fn default() -> Self;
|
||||
}
|
||||
|
||||
/// Return the default value of a type according to the `Default` trait.
|
||||
///
|
||||
/// The type to return is inferred from context; this is equivalent to
|
||||
/// `Default::default()` but shorter to type.
|
||||
///
|
||||
/// For example:
|
||||
/// ```
|
||||
/// #![feature(default_free_fn)]
|
||||
///
|
||||
/// use std::default::default;
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// struct AppConfig {
|
||||
/// foo: FooConfig,
|
||||
/// bar: BarConfig,
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// struct FooConfig {
|
||||
/// foo: i32,
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// struct BarConfig {
|
||||
/// bar: f32,
|
||||
/// baz: u8,
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let options = AppConfig {
|
||||
/// foo: default(),
|
||||
/// bar: BarConfig {
|
||||
/// bar: 10.1,
|
||||
/// ..default()
|
||||
/// },
|
||||
/// };
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "default_free_fn", issue = "73014")]
|
||||
#[inline]
|
||||
pub fn default<T: Default>() -> T {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Derive macro generating an impl of the trait `Default`.
|
||||
#[rustc_builtin_macro]
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
|
|
|
|||
|
|
@ -441,6 +441,13 @@ impl Display for Arguments<'_> {
|
|||
/// `enum`s, it will use the name of the variant and, if applicable, `(`, then the
|
||||
/// `Debug` values of the fields, then `)`.
|
||||
///
|
||||
/// # Stability
|
||||
///
|
||||
/// Derived `Debug` formats are not stable, and so may change with future Rust
|
||||
/// versions. Additionally, `Debug` implementations of types provided by the
|
||||
/// standard library (`libstd`, `libcore`, `liballoc`, etc.) are not stable, and
|
||||
/// may also change with future Rust versions.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Deriving an implementation:
|
||||
|
|
@ -1611,7 +1618,8 @@ impl<'a> Formatter<'a> {
|
|||
self.width
|
||||
}
|
||||
|
||||
/// Optionally specified precision for numeric types.
|
||||
/// Optionally specified precision for numeric types. Alternatively, the
|
||||
/// maximum width for string types.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
27
src/libcore/future/into_future.rs
Normal file
27
src/libcore/future/into_future.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use crate::future::Future;
|
||||
|
||||
/// Conversion into a `Future`.
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
pub trait IntoFuture {
|
||||
/// The output that the future will produce on completion.
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
type Output;
|
||||
|
||||
/// Which kind of future are we turning this into?
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
type Future: Future<Output = Self::Output>;
|
||||
|
||||
/// Creates a future from a value.
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
fn into_future(self) -> Self::Future;
|
||||
}
|
||||
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
impl<F: Future> IntoFuture for F {
|
||||
type Output = F::Output;
|
||||
type Future = F;
|
||||
|
||||
fn into_future(self) -> Self::Future {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
@ -10,12 +10,16 @@ use crate::{
|
|||
};
|
||||
|
||||
mod future;
|
||||
mod into_future;
|
||||
mod pending;
|
||||
mod ready;
|
||||
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
pub use self::future::Future;
|
||||
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
pub use into_future::IntoFuture;
|
||||
|
||||
#[unstable(feature = "future_readiness_fns", issue = "70921")]
|
||||
pub use pending::{pending, Pending};
|
||||
#[unstable(feature = "future_readiness_fns", issue = "70921")]
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@
|
|||
)]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
use crate::marker::DiscriminantKind;
|
||||
use crate::mem;
|
||||
|
||||
|
|
@ -1314,6 +1313,7 @@ extern "rust-intrinsic" {
|
|||
/// The stabilized version of this intrinsic is
|
||||
/// [`std::pointer::offset`](../../std/primitive.pointer.html#method.offset).
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
|
||||
|
||||
/// Calculates the offset from a pointer, potentially wrapping.
|
||||
|
|
@ -1331,6 +1331,7 @@ extern "rust-intrinsic" {
|
|||
/// The stabilized version of this intrinsic is
|
||||
/// [`std::pointer::wrapping_offset`](../../std/primitive.pointer.html#method.wrapping_offset).
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
|
||||
|
||||
/// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
|
||||
|
|
@ -1914,11 +1915,7 @@ extern "rust-intrinsic" {
|
|||
/// The stabilized version of this intrinsic is
|
||||
/// [`std::mem::discriminant`](../../std/mem/fn.discriminant.html)
|
||||
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
|
||||
#[cfg(not(bootstrap))]
|
||||
pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
|
||||
#[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
|
||||
#[cfg(bootstrap)]
|
||||
pub fn discriminant_value<T>(v: &T) -> u64;
|
||||
|
||||
/// Rust's "try catch" construct which invokes the function pointer `try_fn`
|
||||
/// with the data pointer `data`.
|
||||
|
|
|
|||
|
|
@ -1619,6 +1619,69 @@ impl<I: Iterator> Peekable<I> {
|
|||
let iter = &mut self.iter;
|
||||
self.peeked.get_or_insert_with(|| iter.next()).as_ref()
|
||||
}
|
||||
|
||||
/// Consume the next value of this iterator if a condition is true.
|
||||
///
|
||||
/// If `func` returns `true` for the next value of this iterator, consume and return it.
|
||||
/// Otherwise, return `None`.
|
||||
///
|
||||
/// # Examples
|
||||
/// Consume a number if it's equal to 0.
|
||||
/// ```
|
||||
/// #![feature(peekable_next_if)]
|
||||
/// let mut iter = (0..5).peekable();
|
||||
/// // The first item of the iterator is 0; consume it.
|
||||
/// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
|
||||
/// // The next item returned is now 1, so `consume` will return `false`.
|
||||
/// assert_eq!(iter.next_if(|&x| x == 0), None);
|
||||
/// // `next_if` saves the value of the next item if it was not equal to `expected`.
|
||||
/// assert_eq!(iter.next(), Some(1));
|
||||
/// ```
|
||||
///
|
||||
/// Consume any number less than 10.
|
||||
/// ```
|
||||
/// #![feature(peekable_next_if)]
|
||||
/// let mut iter = (1..20).peekable();
|
||||
/// // Consume all numbers less than 10
|
||||
/// while iter.next_if(|&x| x < 10).is_some() {}
|
||||
/// // The next value returned will be 10
|
||||
/// assert_eq!(iter.next(), Some(10));
|
||||
/// ```
|
||||
#[unstable(feature = "peekable_next_if", issue = "72480")]
|
||||
pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
|
||||
match self.next() {
|
||||
Some(matched) if func(&matched) => Some(matched),
|
||||
other => {
|
||||
// Since we called `self.next()`, we consumed `self.peeked`.
|
||||
assert!(self.peeked.is_none());
|
||||
self.peeked = Some(other);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume the next item if it is equal to `expected`.
|
||||
///
|
||||
/// # Example
|
||||
/// Consume a number if it's equal to 0.
|
||||
/// ```
|
||||
/// #![feature(peekable_next_if)]
|
||||
/// let mut iter = (0..5).peekable();
|
||||
/// // The first item of the iterator is 0; consume it.
|
||||
/// assert_eq!(iter.next_if_eq(&0), Some(0));
|
||||
/// // The next item returned is now 1, so `consume` will return `false`.
|
||||
/// assert_eq!(iter.next_if_eq(&0), None);
|
||||
/// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
|
||||
/// assert_eq!(iter.next(), Some(1));
|
||||
/// ```
|
||||
#[unstable(feature = "peekable_next_if", issue = "72480")]
|
||||
pub fn next_if_eq<R>(&mut self, expected: &R) -> Option<I::Item>
|
||||
where
|
||||
R: ?Sized,
|
||||
I::Item: PartialEq<R>,
|
||||
{
|
||||
self.next_if(|next| next == expected)
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that rejects elements while `predicate` returns `true`.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::char;
|
||||
use crate::convert::TryFrom;
|
||||
use crate::mem;
|
||||
use crate::ops::{self, Add, Sub, Try};
|
||||
|
|
@ -400,6 +401,73 @@ step_integer_impls! {
|
|||
wider than usize: [u32 i32], [u64 i64], [u128 i128];
|
||||
}
|
||||
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for char {
|
||||
#[inline]
|
||||
fn steps_between(&start: &char, &end: &char) -> Option<usize> {
|
||||
let start = start as u32;
|
||||
let end = end as u32;
|
||||
if start <= end {
|
||||
let count = end - start;
|
||||
if start < 0xD800 && 0xE000 <= end {
|
||||
usize::try_from(count - 0x800).ok()
|
||||
} else {
|
||||
usize::try_from(count).ok()
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn forward_checked(start: char, count: usize) -> Option<char> {
|
||||
let start = start as u32;
|
||||
let mut res = Step::forward_checked(start, count)?;
|
||||
if start < 0xD800 && 0xD800 <= res {
|
||||
res = Step::forward_checked(res, 0x800)?;
|
||||
}
|
||||
if res <= char::MAX as u32 {
|
||||
// SAFETY: res is a valid unicode scalar
|
||||
// (below 0x110000 and not in 0xD800..0xE000)
|
||||
Some(unsafe { char::from_u32_unchecked(res) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn backward_checked(start: char, count: usize) -> Option<char> {
|
||||
let start = start as u32;
|
||||
let mut res = Step::backward_checked(start, count)?;
|
||||
if start >= 0xE000 && 0xE000 > res {
|
||||
res = Step::backward_checked(res, 0x800)?;
|
||||
}
|
||||
// SAFETY: res is a valid unicode scalar
|
||||
// (below 0x110000 and not in 0xD800..0xE000)
|
||||
Some(unsafe { char::from_u32_unchecked(res) })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn forward_unchecked(start: char, count: usize) -> char {
|
||||
let start = start as u32;
|
||||
let mut res = Step::forward_unchecked(start, count);
|
||||
if start < 0xD800 && 0xD800 <= res {
|
||||
res = Step::forward_unchecked(res, 0x800);
|
||||
}
|
||||
char::from_u32_unchecked(res)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn backward_unchecked(start: char, count: usize) -> char {
|
||||
let start = start as u32;
|
||||
let mut res = Step::backward_unchecked(start, count);
|
||||
if start >= 0xE000 && 0xE000 > res {
|
||||
res = Step::backward_unchecked(res, 0x800);
|
||||
}
|
||||
char::from_u32_unchecked(res)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! range_exact_iter_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -551,15 +619,7 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {
|
|||
|
||||
#[inline]
|
||||
fn nth(&mut self, n: usize) -> Option<A> {
|
||||
// If we would jump over the maximum value, panic immediately.
|
||||
// This is consistent with behavior before the Step redesign,
|
||||
// even though it's inconsistent with n `next` calls.
|
||||
// To get consistent behavior, change it to use `forward` instead.
|
||||
// This change should go through FCP separately to the redesign, so is for now left as a
|
||||
// FIXME: make this consistent
|
||||
let plus_n =
|
||||
Step::forward_checked(self.start.clone(), n).expect("overflow in RangeFrom::nth");
|
||||
// The final step should always be debug-checked.
|
||||
let plus_n = Step::forward(self.start.clone(), n);
|
||||
self.start = Step::forward(plus_n.clone(), 1);
|
||||
Some(plus_n)
|
||||
}
|
||||
|
|
@ -582,7 +642,11 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
|||
}
|
||||
let is_iterating = self.start < self.end;
|
||||
Some(if is_iterating {
|
||||
let n = Step::forward(self.start.clone(), 1);
|
||||
// SAFETY: just checked precondition
|
||||
// We use the unchecked version here, because
|
||||
// otherwise `for _ in '\0'..=char::MAX`
|
||||
// does not successfully remove panicking code.
|
||||
let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
|
||||
mem::replace(&mut self.start, n)
|
||||
} else {
|
||||
self.exhausted = true;
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ impl<I: Iterator> IntoIterator for I {
|
|||
pub trait Extend<A> {
|
||||
/// Extends a collection with the contents of an iterator.
|
||||
///
|
||||
/// As this is the only method for this trait, the [trait-level] docs
|
||||
/// As this is the only required method for this trait, the [trait-level] docs
|
||||
/// contain more details.
|
||||
///
|
||||
/// [trait-level]: trait.Extend.html
|
||||
|
|
@ -341,6 +341,20 @@ pub trait Extend<A> {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T);
|
||||
|
||||
/// Extends a collection with exactly one element.
|
||||
#[unstable(feature = "extend_one", issue = "72631")]
|
||||
fn extend_one(&mut self, item: A) {
|
||||
self.extend(Some(item));
|
||||
}
|
||||
|
||||
/// Reserves capacity in a collection for the given number of additional elements.
|
||||
///
|
||||
/// The default implementation does nothing.
|
||||
#[unstable(feature = "extend_one", issue = "72631")]
|
||||
fn extend_reserve(&mut self, additional: usize) {
|
||||
let _ = additional;
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "extend_for_unit", since = "1.28.0")]
|
||||
|
|
@ -348,4 +362,5 @@ impl Extend<()> for () {
|
|||
fn extend<T: IntoIterator<Item = ()>>(&mut self, iter: T) {
|
||||
iter.into_iter().for_each(drop)
|
||||
}
|
||||
fn extend_one(&mut self, _item: ()) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,32 @@ pub trait DoubleEndedIterator: Iterator {
|
|||
/// assert_eq!(None, iter.next());
|
||||
/// assert_eq!(None, iter.next_back());
|
||||
/// ```
|
||||
///
|
||||
/// # Remarks
|
||||
///
|
||||
/// The elements yielded by `DoubleEndedIterator`'s methods may differ from
|
||||
/// the ones yielded by `Iterator`'s methods:
|
||||
///
|
||||
/// ```
|
||||
/// let vec = vec![(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b')];
|
||||
/// let uniq_by_fst_comp = || {
|
||||
/// let mut seen = std::collections::HashSet::new();
|
||||
/// vec.iter().copied().filter(move |x| seen.insert(x.0))
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(uniq_by_fst_comp().last(), Some((2, 'a')));
|
||||
/// assert_eq!(uniq_by_fst_comp().next_back(), Some((2, 'b')));
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// uniq_by_fst_comp().fold(vec![], |mut v, x| {v.push(x); v}),
|
||||
/// vec![(1, 'a'), (2, 'a')]
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// uniq_by_fst_comp().rfold(vec![], |mut v, x| {v.push(x); v}),
|
||||
/// vec![(2, 'b'), (1, 'c')]
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn next_back(&mut self) -> Option<Self::Item>;
|
||||
|
||||
|
|
|
|||
|
|
@ -1180,6 +1180,17 @@ pub trait Iterator {
|
|||
/// assert_eq!(iter.next(), Some(2));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
///
|
||||
/// If less than `n` elements are available,
|
||||
/// `take` will limit itself to the size of the underlying iterator:
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec![1, 2];
|
||||
/// let mut iter = v.into_iter().take(5);
|
||||
/// assert_eq!(iter.next(), Some(1));
|
||||
/// assert_eq!(iter.next(), Some(2));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn take(self, n: usize) -> Take<Self>
|
||||
|
|
@ -1700,9 +1711,9 @@ pub trait Iterator {
|
|||
) -> impl FnMut((), T) + 'a {
|
||||
move |(), x| {
|
||||
if f(&x) {
|
||||
left.extend(Some(x));
|
||||
left.extend_one(x);
|
||||
} else {
|
||||
right.extend(Some(x));
|
||||
right.extend_one(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2675,14 +2686,20 @@ pub trait Iterator {
|
|||
us: &'a mut impl Extend<B>,
|
||||
) -> impl FnMut((), (A, B)) + 'a {
|
||||
move |(), (t, u)| {
|
||||
ts.extend(Some(t));
|
||||
us.extend(Some(u));
|
||||
ts.extend_one(t);
|
||||
us.extend_one(u);
|
||||
}
|
||||
}
|
||||
|
||||
let mut ts: FromA = Default::default();
|
||||
let mut us: FromB = Default::default();
|
||||
|
||||
let (lower_bound, _) = self.size_hint();
|
||||
if lower_bound > 0 {
|
||||
ts.extend_reserve(lower_bound);
|
||||
us.extend_reserve(lower_bound);
|
||||
}
|
||||
|
||||
self.fold((), extend(&mut ts, &mut us));
|
||||
|
||||
(ts, us)
|
||||
|
|
|
|||
|
|
@ -85,8 +85,11 @@
|
|||
#![feature(const_panic)]
|
||||
#![feature(const_fn_union)]
|
||||
#![feature(const_generics)]
|
||||
#![feature(const_ptr_offset)]
|
||||
#![feature(const_ptr_offset_from)]
|
||||
#![feature(const_result)]
|
||||
#![feature(const_slice_from_raw_parts)]
|
||||
#![feature(const_slice_ptr_len)]
|
||||
#![feature(const_type_name)]
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![feature(decl_macro)]
|
||||
|
|
|
|||
|
|
@ -1315,7 +1315,7 @@ pub(crate) mod builtin {
|
|||
#[unstable(
|
||||
feature = "llvm_asm",
|
||||
issue = "70173",
|
||||
reason = "LLVM-style inline assembly will never be stabilized, prefer using asm! instead"
|
||||
reason = "prefer using the new asm! syntax instead"
|
||||
)]
|
||||
#[rustc_builtin_macro]
|
||||
#[macro_export]
|
||||
|
|
|
|||
|
|
@ -692,25 +692,13 @@ mod impls {
|
|||
issue = "none",
|
||||
reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead"
|
||||
)]
|
||||
#[cfg_attr(not(bootstrap), lang = "discriminant_kind")]
|
||||
#[lang = "discriminant_kind"]
|
||||
pub trait DiscriminantKind {
|
||||
/// The type of the dicriminant, which must satisfy the trait
|
||||
/// bounds required by `mem::Discriminant`.
|
||||
type Discriminant: Clone + Copy + Debug + Eq + PartialEq + Hash + Send + Sync + Unpin;
|
||||
}
|
||||
|
||||
// Manually implement `DiscriminantKind` for all types during bootstrap
|
||||
// to reduce the required amount of conditional compilation.
|
||||
#[unstable(
|
||||
feature = "discriminant_kind",
|
||||
issue = "none",
|
||||
reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead"
|
||||
)]
|
||||
#[cfg(bootstrap)]
|
||||
impl<T: ?Sized> DiscriminantKind for T {
|
||||
type Discriminant = u64;
|
||||
}
|
||||
|
||||
/// Compiler-internal trait used to determine whether a type contains
|
||||
/// any `UnsafeCell` internally, but not through an indirection.
|
||||
/// This affects, for example, whether a `static` of that type is
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ use crate::mem::ManuallyDrop;
|
|||
/// # #![allow(invalid_value)]
|
||||
/// use std::mem::{self, MaybeUninit};
|
||||
///
|
||||
/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior!
|
||||
/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! ⚠️
|
||||
/// // The equivalent code with `MaybeUninit<&i32>`:
|
||||
/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior!
|
||||
/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior! ⚠️
|
||||
/// ```
|
||||
///
|
||||
/// This is exploited by the compiler for various optimizations, such as eliding
|
||||
|
|
@ -35,9 +35,9 @@ use crate::mem::ManuallyDrop;
|
|||
/// # #![allow(invalid_value)]
|
||||
/// use std::mem::{self, MaybeUninit};
|
||||
///
|
||||
/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior!
|
||||
/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! ⚠️
|
||||
/// // The equivalent code with `MaybeUninit<bool>`:
|
||||
/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior!
|
||||
/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️
|
||||
/// ```
|
||||
///
|
||||
/// Moreover, uninitialized memory is special in that the compiler knows that
|
||||
|
|
@ -49,9 +49,9 @@ use crate::mem::ManuallyDrop;
|
|||
/// # #![allow(invalid_value)]
|
||||
/// use std::mem::{self, MaybeUninit};
|
||||
///
|
||||
/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior!
|
||||
/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! ⚠️
|
||||
/// // The equivalent code with `MaybeUninit<i32>`:
|
||||
/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior!
|
||||
/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️
|
||||
/// ```
|
||||
/// (Notice that the rules around uninitialized integers are not finalized yet, but
|
||||
/// until they are, it is advisable to avoid them.)
|
||||
|
|
@ -214,7 +214,6 @@ use crate::mem::ManuallyDrop;
|
|||
/// remain `#[repr(transparent)]`. That said, `MaybeUninit<T>` will *always* guarantee that it has
|
||||
/// the same size, alignment, and ABI as `T`; it's just that the way `MaybeUninit` implements that
|
||||
/// guarantee may evolve.
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[stable(feature = "maybe_uninit", since = "1.36.0")]
|
||||
// Lang item so we can wrap other types in it. This is useful for generators.
|
||||
#[lang = "maybe_uninit"]
|
||||
|
|
@ -348,7 +347,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// let x = MaybeUninit::<(u8, NotZero)>::zeroed();
|
||||
/// let x = unsafe { x.assume_init() };
|
||||
/// // Inside a pair, we create a `NotZero` that does not have a valid discriminant.
|
||||
/// // This is undefined behavior.
|
||||
/// // This is undefined behavior. ⚠️
|
||||
/// ```
|
||||
#[stable(feature = "maybe_uninit", since = "1.36.0")]
|
||||
#[inline]
|
||||
|
|
@ -400,7 +399,7 @@ impl<T> MaybeUninit<T> {
|
|||
///
|
||||
/// let x = MaybeUninit::<Vec<u32>>::uninit();
|
||||
/// let x_vec = unsafe { &*x.as_ptr() };
|
||||
/// // We have created a reference to an uninitialized vector! This is undefined behavior.
|
||||
/// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️
|
||||
/// ```
|
||||
///
|
||||
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
|
||||
|
|
@ -437,7 +436,7 @@ impl<T> MaybeUninit<T> {
|
|||
///
|
||||
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
|
||||
/// let x_vec = unsafe { &mut *x.as_mut_ptr() };
|
||||
/// // We have created a reference to an uninitialized vector! This is undefined behavior.
|
||||
/// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️
|
||||
/// ```
|
||||
///
|
||||
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
|
||||
|
|
@ -489,7 +488,7 @@ impl<T> MaybeUninit<T> {
|
|||
///
|
||||
/// let x = MaybeUninit::<Vec<u32>>::uninit();
|
||||
/// let x_init = unsafe { x.assume_init() };
|
||||
/// // `x` had not been initialized yet, so this last line caused undefined behavior.
|
||||
/// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️
|
||||
/// ```
|
||||
#[stable(feature = "maybe_uninit", since = "1.36.0")]
|
||||
#[inline(always)]
|
||||
|
|
@ -553,7 +552,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// x.write(Some(vec![0,1,2]));
|
||||
/// let x1 = unsafe { x.read() };
|
||||
/// let x2 = unsafe { x.read() };
|
||||
/// // We now created two copies of the same vector, leading to a double-free when
|
||||
/// // We now created two copies of the same vector, leading to a double-free ⚠️ when
|
||||
/// // they both get dropped!
|
||||
/// ```
|
||||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
|
|
@ -603,7 +602,7 @@ impl<T> MaybeUninit<T> {
|
|||
///
|
||||
/// let x = MaybeUninit::<Vec<u32>>::uninit();
|
||||
/// let x_vec: &Vec<u32> = unsafe { x.get_ref() };
|
||||
/// // We have created a reference to an uninitialized vector! This is undefined behavior.
|
||||
/// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️
|
||||
/// ```
|
||||
///
|
||||
/// ```rust,no_run
|
||||
|
|
@ -686,7 +685,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// unsafe {
|
||||
/// *b.get_mut() = true;
|
||||
/// // We have created a (mutable) reference to an uninitialized `bool`!
|
||||
/// // This is undefined behavior.
|
||||
/// // This is undefined behavior. ⚠️
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
|
|
|
|||
|
|
@ -808,7 +808,7 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
|||
|
||||
/// Disposes of a value.
|
||||
///
|
||||
/// This does call the argument's implementation of [`Drop`][drop].
|
||||
/// This does so by calling the argument's implementation of [`Drop`][drop].
|
||||
///
|
||||
/// This effectively does nothing for types which implement `Copy`, e.g.
|
||||
/// integers. Such values are copied and _then_ moved into the function, so the
|
||||
|
|
|
|||
|
|
@ -810,4 +810,78 @@ impl f32 {
|
|||
pub fn from_ne_bytes(bytes: [u8; 4]) -> Self {
|
||||
Self::from_bits(u32::from_ne_bytes(bytes))
|
||||
}
|
||||
|
||||
/// Returns an ordering between self and other values.
|
||||
/// Unlike the standard partial comparison between floating point numbers,
|
||||
/// this comparison always produces an ordering in accordance to
|
||||
/// the totalOrder predicate as defined in IEEE 754 (2008 revision)
|
||||
/// floating point standard. The values are ordered in following order:
|
||||
/// - Negative quiet NaN
|
||||
/// - Negative signaling NaN
|
||||
/// - Negative infinity
|
||||
/// - Negative numbers
|
||||
/// - Negative subnormal numbers
|
||||
/// - Negative zero
|
||||
/// - Positive zero
|
||||
/// - Positive subnormal numbers
|
||||
/// - Positive numbers
|
||||
/// - Positive infinity
|
||||
/// - Positive signaling NaN
|
||||
/// - Positive quiet NaN
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// #![feature(total_cmp)]
|
||||
/// struct GoodBoy {
|
||||
/// name: String,
|
||||
/// weight: f32,
|
||||
/// }
|
||||
///
|
||||
/// let mut bois = vec![
|
||||
/// GoodBoy { name: "Pucci".to_owned(), weight: 0.1 },
|
||||
/// GoodBoy { name: "Woofer".to_owned(), weight: 99.0 },
|
||||
/// GoodBoy { name: "Yapper".to_owned(), weight: 10.0 },
|
||||
/// GoodBoy { name: "Chonk".to_owned(), weight: f32::INFINITY },
|
||||
/// GoodBoy { name: "Abs. Unit".to_owned(), weight: f32::NAN },
|
||||
/// GoodBoy { name: "Floaty".to_owned(), weight: -5.0 },
|
||||
/// ];
|
||||
///
|
||||
/// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
|
||||
/// # assert!(bois.into_iter().map(|b| b.weight)
|
||||
/// # .zip([-5.0, 0.1, 10.0, 99.0, f32::INFINITY, f32::NAN].iter())
|
||||
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
|
||||
/// ```
|
||||
#[unstable(feature = "total_cmp", issue = "72599")]
|
||||
#[inline]
|
||||
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
|
||||
let mut left = self.to_bits() as i32;
|
||||
let mut right = other.to_bits() as i32;
|
||||
|
||||
// In case of negatives, flip all the bits except the sign
|
||||
// to achieve a similar layout as two's complement integers
|
||||
//
|
||||
// Why does this work? IEEE 754 floats consist of three fields:
|
||||
// Sign bit, exponent and mantissa. The set of exponent and mantissa
|
||||
// fields as a whole have the property that their bitwise order is
|
||||
// equal to the numeric magnitude where the magnitude is defined.
|
||||
// The magnitude is not normally defined on NaN values, but
|
||||
// IEEE 754 totalOrder defines the NaN values also to follow the
|
||||
// bitwise order. This leads to order explained in the doc comment.
|
||||
// However, the representation of magnitude is the same for negative
|
||||
// and positive numbers – only the sign bit is different.
|
||||
// To easily compare the floats as signed integers, we need to
|
||||
// flip the exponent and mantissa bits in case of negative numbers.
|
||||
// We effectively convert the numbers to "two's complement" form.
|
||||
//
|
||||
// To do the flipping, we construct a mask and XOR against it.
|
||||
// We branchlessly calculate an "all-ones except for the sign bit"
|
||||
// mask from negative-signed values: right shifting sign-extends
|
||||
// the integer, so we "fill" the mask with sign bits, and then
|
||||
// convert to unsigned to push one more zero bit.
|
||||
// On positive values, the mask is all zeros, so it's a no-op.
|
||||
left ^= (((left >> 31) as u32) >> 1) as i32;
|
||||
right ^= (((right >> 31) as u32) >> 1) as i32;
|
||||
|
||||
left.cmp(&right)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -824,4 +824,78 @@ impl f64 {
|
|||
pub fn from_ne_bytes(bytes: [u8; 8]) -> Self {
|
||||
Self::from_bits(u64::from_ne_bytes(bytes))
|
||||
}
|
||||
|
||||
/// Returns an ordering between self and other values.
|
||||
/// Unlike the standard partial comparison between floating point numbers,
|
||||
/// this comparison always produces an ordering in accordance to
|
||||
/// the totalOrder predicate as defined in IEEE 754 (2008 revision)
|
||||
/// floating point standard. The values are ordered in following order:
|
||||
/// - Negative quiet NaN
|
||||
/// - Negative signaling NaN
|
||||
/// - Negative infinity
|
||||
/// - Negative numbers
|
||||
/// - Negative subnormal numbers
|
||||
/// - Negative zero
|
||||
/// - Positive zero
|
||||
/// - Positive subnormal numbers
|
||||
/// - Positive numbers
|
||||
/// - Positive infinity
|
||||
/// - Positive signaling NaN
|
||||
/// - Positive quiet NaN
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// #![feature(total_cmp)]
|
||||
/// struct GoodBoy {
|
||||
/// name: String,
|
||||
/// weight: f64,
|
||||
/// }
|
||||
///
|
||||
/// let mut bois = vec![
|
||||
/// GoodBoy { name: "Pucci".to_owned(), weight: 0.1 },
|
||||
/// GoodBoy { name: "Woofer".to_owned(), weight: 99.0 },
|
||||
/// GoodBoy { name: "Yapper".to_owned(), weight: 10.0 },
|
||||
/// GoodBoy { name: "Chonk".to_owned(), weight: f64::INFINITY },
|
||||
/// GoodBoy { name: "Abs. Unit".to_owned(), weight: f64::NAN },
|
||||
/// GoodBoy { name: "Floaty".to_owned(), weight: -5.0 },
|
||||
/// ];
|
||||
///
|
||||
/// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight));
|
||||
/// # assert!(bois.into_iter().map(|b| b.weight)
|
||||
/// # .zip([-5.0, 0.1, 10.0, 99.0, f64::INFINITY, f64::NAN].iter())
|
||||
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
|
||||
/// ```
|
||||
#[unstable(feature = "total_cmp", issue = "72599")]
|
||||
#[inline]
|
||||
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
|
||||
let mut left = self.to_bits() as i64;
|
||||
let mut right = other.to_bits() as i64;
|
||||
|
||||
// In case of negatives, flip all the bits except the sign
|
||||
// to achieve a similar layout as two's complement integers
|
||||
//
|
||||
// Why does this work? IEEE 754 floats consist of three fields:
|
||||
// Sign bit, exponent and mantissa. The set of exponent and mantissa
|
||||
// fields as a whole have the property that their bitwise order is
|
||||
// equal to the numeric magnitude where the magnitude is defined.
|
||||
// The magnitude is not normally defined on NaN values, but
|
||||
// IEEE 754 totalOrder defines the NaN values also to follow the
|
||||
// bitwise order. This leads to order explained in the doc comment.
|
||||
// However, the representation of magnitude is the same for negative
|
||||
// and positive numbers – only the sign bit is different.
|
||||
// To easily compare the floats as signed integers, we need to
|
||||
// flip the exponent and mantissa bits in case of negative numbers.
|
||||
// We effectively convert the numbers to "two's complement" form.
|
||||
//
|
||||
// To do the flipping, we construct a mask and XOR against it.
|
||||
// We branchlessly calculate an "all-ones except for the sign bit"
|
||||
// mask from negative-signed values: right shifting sign-extends
|
||||
// the integer, so we "fill" the mask with sign bits, and then
|
||||
// convert to unsigned to push one more zero bit.
|
||||
// On positive values, the mask is all zeros, so it's a no-op.
|
||||
left ^= (((left >> 63) as u64) >> 1) as i64;
|
||||
right ^= (((right >> 63) as u64) >> 1) as i64;
|
||||
|
||||
left.cmp(&right)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -337,14 +337,10 @@ Basic usage:
|
|||
#![feature(wrapping_int_impl)]
|
||||
use std::num::Wrapping;
|
||||
|
||||
assert_eq!(<Wrapping<", stringify!($t), ">>::min_value(), ",
|
||||
"Wrapping(", stringify!($t), "::min_value()));
|
||||
assert_eq!(<Wrapping<", stringify!($t), ">>::MIN, Wrapping(", stringify!($t), "::MIN));
|
||||
```"),
|
||||
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
|
||||
#[inline]
|
||||
pub const fn min_value() -> Self {
|
||||
Wrapping(<$t>::min_value())
|
||||
}
|
||||
pub const MIN: Self = Self(<$t>::MIN);
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
|
|
@ -358,14 +354,10 @@ Basic usage:
|
|||
#![feature(wrapping_int_impl)]
|
||||
use std::num::Wrapping;
|
||||
|
||||
assert_eq!(<Wrapping<", stringify!($t), ">>::max_value(), ",
|
||||
"Wrapping(", stringify!($t), "::max_value()));
|
||||
assert_eq!(<Wrapping<", stringify!($t), ">>::MAX, Wrapping(", stringify!($t), "::MAX));
|
||||
```"),
|
||||
#[unstable(feature = "wrapping_int_impl", issue = "32463")]
|
||||
#[inline]
|
||||
pub const fn max_value() -> Self {
|
||||
Wrapping(<$t>::max_value())
|
||||
}
|
||||
pub const MAX: Self = Self(<$t>::MAX);
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
///
|
||||
/// If `T` implements `Deref<Target = U>`, and `x` is a value of type `T`, then:
|
||||
///
|
||||
/// * In immutable contexts, `*x` on non-pointer types is equivalent to
|
||||
/// `*Deref::deref(&x)`.
|
||||
/// * In immutable contexts, `*x` (where `T` is neither a reference nor a raw pointer)
|
||||
/// is equivalent to `*Deref::deref(&x)`.
|
||||
/// * Values of type `&T` are coerced to values of type `&U`
|
||||
/// * `T` implicitly implements all the (immutable) methods of the type `U`.
|
||||
///
|
||||
|
|
@ -115,8 +115,8 @@ impl<T: ?Sized> Deref for &mut T {
|
|||
/// If `T` implements `DerefMut<Target = U>`, and `x` is a value of type `T`,
|
||||
/// then:
|
||||
///
|
||||
/// * In mutable contexts, `*x` on non-pointer types is equivalent to
|
||||
/// `*DerefMut::deref_mut(&mut x)`.
|
||||
/// * In mutable contexts, `*x` (where `T` is neither a reference nor a raw pointer)
|
||||
/// is equivalent to `*DerefMut::deref_mut(&mut x)`.
|
||||
/// * Values of type `&mut T` are coerced to values of type `&mut U`
|
||||
/// * `T` implicitly implements all the (mutable) methods of the type `U`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -151,10 +151,16 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
|
|||
///
|
||||
/// The `RangeFrom` `start..` contains all values with `x >= start`.
|
||||
///
|
||||
/// *Note*: Currently, no overflow checking is done for the [`Iterator`]
|
||||
/// implementation; if you use an integer range and the integer overflows, it
|
||||
/// might panic in debug mode or create an endless loop in release mode. **This
|
||||
/// overflow behavior might change in the future.**
|
||||
/// *Note*: Overflow in the [`Iterator`] implementation (when the contained
|
||||
/// data type reaches its numerical limit) is allowed to panic, wrap, or
|
||||
/// saturate. This behavior is defined by the implementation of the [`Step`]
|
||||
/// trait. For primitive integers, this follows the normal rules, and respects
|
||||
/// the overflow checks profile (panic in debug, wrap in release). Note also
|
||||
/// that overflow happens earlier than you might assume: the overflow happens
|
||||
/// in the call to `next` that yields the maximum value, as the range must be
|
||||
/// set to a state to yield the next value.
|
||||
///
|
||||
/// [`Step`]: crate::iter::Step
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
)
|
||||
)]
|
||||
#[doc(alias = "?")]
|
||||
#[lang = "try"]
|
||||
pub trait Try {
|
||||
/// The type of this value when viewed as successful.
|
||||
#[unstable(feature = "try_trait", issue = "42327")]
|
||||
|
|
|
|||
|
|
@ -39,12 +39,7 @@ use crate::panic::{Location, PanicInfo};
|
|||
#[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
|
||||
pub fn panic(expr: &str) -> ! {
|
||||
if cfg!(feature = "panic_immediate_abort") {
|
||||
// remove `unsafe` (and safety comment) on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
// SAFETY: the `abort` intrinsic has no requirements to be called.
|
||||
unsafe {
|
||||
super::intrinsics::abort()
|
||||
}
|
||||
super::intrinsics::abort()
|
||||
}
|
||||
|
||||
// Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
|
||||
|
|
@ -62,12 +57,7 @@ pub fn panic(expr: &str) -> ! {
|
|||
#[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
|
||||
fn panic_bounds_check(index: usize, len: usize) -> ! {
|
||||
if cfg!(feature = "panic_immediate_abort") {
|
||||
// remove `unsafe` (and safety comment) on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
// SAFETY: the `abort` intrinsic has no requirements to be called.
|
||||
unsafe {
|
||||
super::intrinsics::abort()
|
||||
}
|
||||
super::intrinsics::abort()
|
||||
}
|
||||
|
||||
panic!("index out of bounds: the len is {} but the index is {}", len, index)
|
||||
|
|
@ -80,12 +70,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
|
|||
#[track_caller]
|
||||
pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
|
||||
if cfg!(feature = "panic_immediate_abort") {
|
||||
// remove `unsafe` (and safety comment) on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
// SAFETY: the `abort` intrinsic has no requirements to be called.
|
||||
unsafe {
|
||||
super::intrinsics::abort()
|
||||
}
|
||||
super::intrinsics::abort()
|
||||
}
|
||||
|
||||
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
||||
|
|
|
|||
|
|
@ -139,10 +139,12 @@
|
|||
//! otherwise invalidating the memory used to store the data is restricted, too.
|
||||
//! Concretely, for pinned data you have to maintain the invariant
|
||||
//! that *its memory will not get invalidated or repurposed from the moment it gets pinned until
|
||||
//! when [`drop`] is called*. Memory can be invalidated by deallocation, but also by
|
||||
//! when [`drop`] is called*. Only once [`drop`] returns or panics, the memory may be reused.
|
||||
//!
|
||||
//! Memory can be "invalidated" by deallocation, but also by
|
||||
//! replacing a [`Some(v)`] by [`None`], or calling [`Vec::set_len`] to "kill" some elements
|
||||
//! off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without
|
||||
//! calling the destructor first.
|
||||
//! calling the destructor first. None of this is allowed for pinned data without calling [`drop`].
|
||||
//!
|
||||
//! This is exactly the kind of guarantee that the intrusive linked list from the previous
|
||||
//! section needs to function correctly.
|
||||
|
|
|
|||
|
|
@ -151,8 +151,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn offset(self, count: isize) -> *const T
|
||||
pub const unsafe fn offset(self, count: isize) -> *const T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
@ -210,8 +211,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_offset(self, count: isize) -> *const T
|
||||
pub const fn wrapping_offset(self, count: isize) -> *const T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
@ -393,8 +395,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn add(self, count: usize) -> Self
|
||||
pub const unsafe fn add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
@ -455,8 +458,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn sub(self, count: usize) -> Self
|
||||
pub const unsafe fn sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
@ -511,8 +515,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_add(self, count: usize) -> Self
|
||||
pub const fn wrapping_add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
@ -567,8 +572,9 @@ impl<T: ?Sized> *const T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_sub(self, count: usize) -> Self
|
||||
pub const fn wrapping_sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -145,8 +145,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn offset(self, count: isize) -> *mut T
|
||||
pub const unsafe fn offset(self, count: isize) -> *mut T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
@ -203,8 +204,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_offset(self, count: isize) -> *mut T
|
||||
pub const fn wrapping_offset(self, count: isize) -> *mut T
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
@ -439,8 +441,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn add(self, count: usize) -> Self
|
||||
pub const unsafe fn add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
@ -501,8 +504,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub unsafe fn sub(self, count: usize) -> Self
|
||||
pub const unsafe fn sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
@ -557,8 +561,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_add(self, count: usize) -> Self
|
||||
pub const fn wrapping_add(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
@ -613,8 +618,9 @@ impl<T: ?Sized> *mut T {
|
|||
/// ```
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
|
||||
#[inline]
|
||||
pub fn wrapping_sub(self, count: usize) -> Self
|
||||
pub const fn wrapping_sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -142,6 +142,65 @@ impl<T: ?Sized> NonNull<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> NonNull<[T]> {
|
||||
/// Creates a non-null raw slice from a thin pointer and a length.
|
||||
///
|
||||
/// The `len` argument is the number of **elements**, not the number of bytes.
|
||||
///
|
||||
/// This function is safe, but dereferencing the return value is unsafe.
|
||||
/// See the documentation of [`slice::from_raw_parts`] for slice safety requirements.
|
||||
///
|
||||
/// [`slice::from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(nonnull_slice_from_raw_parts)]
|
||||
///
|
||||
/// use std::ptr::NonNull;
|
||||
///
|
||||
/// // create a slice pointer when starting out with a pointer to the first element
|
||||
/// let mut x = [5, 6, 7];
|
||||
/// let nonnull_pointer = NonNull::new(x.as_mut_ptr()).unwrap();
|
||||
/// let slice = NonNull::slice_from_raw_parts(nonnull_pointer, 3);
|
||||
/// assert_eq!(unsafe { slice.as_ref()[2] }, 7);
|
||||
/// ```
|
||||
///
|
||||
/// (Note that this example artifically demonstrates a use of this method,
|
||||
/// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.)
|
||||
#[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")]
|
||||
#[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")]
|
||||
#[inline]
|
||||
pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
|
||||
// SAFETY: `data` is a `NonNull` pointer which is necessarily non-null
|
||||
unsafe { Self::new_unchecked(super::slice_from_raw_parts_mut(data.as_ptr(), len)) }
|
||||
}
|
||||
|
||||
/// Returns the length of a non-null raw slice.
|
||||
///
|
||||
/// The returned value is the number of **elements**, not the number of bytes.
|
||||
///
|
||||
/// This function is safe, even when the non-null raw slice cannot be dereferenced to a slice
|
||||
/// because the pointer does not have a valid address.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(slice_ptr_len, nonnull_slice_from_raw_parts)]
|
||||
///
|
||||
/// use std::ptr::NonNull;
|
||||
///
|
||||
/// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
|
||||
/// assert_eq!(slice.len(), 3);
|
||||
/// ```
|
||||
#[unstable(feature = "slice_ptr_len", issue = "71146")]
|
||||
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
|
||||
#[inline]
|
||||
pub const fn len(self) -> usize {
|
||||
self.as_ptr().len()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "nonnull", since = "1.25.0")]
|
||||
impl<T: ?Sized> Clone for NonNull<T> {
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -9,15 +9,15 @@
|
|||
//! Their definition should always match the ABI defined in
|
||||
//! `rustc_middle::ty::layout`.
|
||||
|
||||
/// The representation of a trait object like `&SomeTrait`.
|
||||
/// The representation of a trait object like `&dyn SomeTrait`.
|
||||
///
|
||||
/// This struct has the same layout as types like `&SomeTrait` and
|
||||
/// This struct has the same layout as types like `&dyn SomeTrait` and
|
||||
/// `Box<dyn AnotherTrait>`.
|
||||
///
|
||||
/// `TraitObject` is guaranteed to match layouts, but it is not the
|
||||
/// type of trait objects (e.g., the fields are not directly accessible
|
||||
/// on a `&SomeTrait`) nor does it control that layout (changing the
|
||||
/// definition will not change the layout of a `&SomeTrait`). It is
|
||||
/// on a `&dyn SomeTrait`) nor does it control that layout (changing the
|
||||
/// definition will not change the layout of a `&dyn SomeTrait`). It is
|
||||
/// only designed to be used by unsafe code that needs to manipulate
|
||||
/// the low-level details.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@ impl<T> [T] {
|
|||
/// The returned range is half-open, which means that the end pointer
|
||||
/// points *one past* the last element of the slice. This way, an empty
|
||||
/// slice is represented by two equal pointers, and the difference between
|
||||
/// the two pointers represents the size of the size.
|
||||
/// the two pointers represents the size of the slice.
|
||||
///
|
||||
/// See [`as_ptr`] for warnings on using these pointers. The end pointer
|
||||
/// requires extra caution, as it does not point to a valid element in the
|
||||
|
|
@ -464,7 +464,7 @@ impl<T> [T] {
|
|||
/// The returned range is half-open, which means that the end pointer
|
||||
/// points *one past* the last element of the slice. This way, an empty
|
||||
/// slice is represented by two equal pointers, and the difference between
|
||||
/// the two pointers represents the size of the size.
|
||||
/// the two pointers represents the size of the slice.
|
||||
///
|
||||
/// See [`as_mut_ptr`] for warnings on using these pointers. The end
|
||||
/// pointer requires extra caution, as it does not point to a valid element
|
||||
|
|
@ -1654,7 +1654,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// ```
|
||||
/// let mut floats = [5f64, 4.0, 1.0, 3.0, 2.0];
|
||||
/// floats.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
/// floats.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
/// assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 5.0]);
|
||||
/// ```
|
||||
///
|
||||
|
|
@ -2173,7 +2173,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// The length of `src` must be the same as `self`.
|
||||
///
|
||||
/// If `src` implements `Copy`, it can be more performant to use
|
||||
/// If `T` implements `Copy`, it can be more performant to use
|
||||
/// [`copy_from_slice`].
|
||||
///
|
||||
/// # Panics
|
||||
|
|
@ -2244,7 +2244,7 @@ impl<T> [T] {
|
|||
///
|
||||
/// The length of `src` must be the same as `self`.
|
||||
///
|
||||
/// If `src` does not implement `Copy`, use [`clone_from_slice`].
|
||||
/// If `T` does not implement `Copy`, use [`clone_from_slice`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
|
@ -5740,7 +5740,8 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
|
|||
/// and it must be properly aligned. This means in particular:
|
||||
///
|
||||
/// * The entire memory range of this slice must be contained within a single allocated object!
|
||||
/// Slices can never span across multiple allocated objects.
|
||||
/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
|
||||
/// for an example incorrectly not taking this into account.
|
||||
/// * `data` must be non-null and aligned even for zero-length slices. One
|
||||
/// reason for this is that enum layout optimizations may rely on references
|
||||
/// (including slices of any length) being aligned and non-null to distinguish
|
||||
|
|
@ -5773,6 +5774,34 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
|
|||
/// assert_eq!(slice[0], 42);
|
||||
/// ```
|
||||
///
|
||||
/// ### Incorrect usage
|
||||
///
|
||||
/// The following `join_slices` function is **unsound** ⚠️
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use std::slice;
|
||||
///
|
||||
/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
|
||||
/// let fst_end = fst.as_ptr().wrapping_add(fst.len());
|
||||
/// let snd_start = snd.as_ptr();
|
||||
/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
|
||||
/// unsafe {
|
||||
/// // The assertion above ensures `fst` and `snd` are contiguous, but they might
|
||||
/// // still be contained within _different allocated objects_, in which case
|
||||
/// // creating this slice is undefined behavior.
|
||||
/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// // `a` and `b` are different allocated objects...
|
||||
/// let a = 42;
|
||||
/// let b = 27;
|
||||
/// // ... which may nevertheless be laid out contiguously in memory: | a | b |
|
||||
/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [valid]: ../../std/ptr/index.html#safety
|
||||
/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling
|
||||
/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
|
||||
|
|
|
|||
|
|
@ -2270,12 +2270,11 @@ impl str {
|
|||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Checks that `index`-th byte lies at the start and/or end of a
|
||||
/// UTF-8 code point sequence.
|
||||
/// Checks that `index`-th byte is the first byte in a UTF-8 code point
|
||||
/// sequence or the end of the string.
|
||||
///
|
||||
/// The start and end of the string (when `index == self.len()`) are
|
||||
/// considered to be
|
||||
/// boundaries.
|
||||
/// considered to be boundaries.
|
||||
///
|
||||
/// Returns `false` if `index` is greater than `self.len()`.
|
||||
///
|
||||
|
|
@ -4052,15 +4051,13 @@ impl str {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(str_strip)]
|
||||
///
|
||||
/// assert_eq!("foo:bar".strip_prefix("foo:"), Some("bar"));
|
||||
/// assert_eq!("foo:bar".strip_prefix("bar"), None);
|
||||
/// assert_eq!("foofoo".strip_prefix("foo"), Some("foo"));
|
||||
/// ```
|
||||
#[must_use = "this returns the remaining substring as a new slice, \
|
||||
without modifying the original"]
|
||||
#[unstable(feature = "str_strip", reason = "newly added", issue = "67302")]
|
||||
#[stable(feature = "str_strip", since = "1.45.0")]
|
||||
pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str> {
|
||||
prefix.strip_prefix_of(self)
|
||||
}
|
||||
|
|
@ -4082,14 +4079,13 @@ impl str {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(str_strip)]
|
||||
/// assert_eq!("bar:foo".strip_suffix(":foo"), Some("bar"));
|
||||
/// assert_eq!("bar:foo".strip_suffix("bar"), None);
|
||||
/// assert_eq!("foofoo".strip_suffix("foo"), Some("foo"));
|
||||
/// ```
|
||||
#[must_use = "this returns the remaining substring as a new slice, \
|
||||
without modifying the original"]
|
||||
#[unstable(feature = "str_strip", reason = "newly added", issue = "67302")]
|
||||
#[stable(feature = "str_strip", since = "1.45.0")]
|
||||
pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str>
|
||||
where
|
||||
P: Pattern<'a>,
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@ pub fn spin_loop_hint() {
|
|||
///
|
||||
/// This type has the same in-memory representation as a [`bool`].
|
||||
///
|
||||
/// **Note**: This type is only available on platforms that support atomic
|
||||
/// loads and stores of `u8`.
|
||||
///
|
||||
/// [`bool`]: ../../../std/primitive.bool.html
|
||||
#[cfg(target_has_atomic_load_store = "8")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -178,6 +181,9 @@ unsafe impl Sync for AtomicBool {}
|
|||
/// A raw pointer type which can be safely shared between threads.
|
||||
///
|
||||
/// This type has the same in-memory representation as a `*mut T`.
|
||||
///
|
||||
/// **Note**: This type is only available on platforms that support atomic
|
||||
/// loads and stores of pointers. Its size depends on the target pointer's size.
|
||||
#[cfg(target_has_atomic_load_store = "ptr")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(target_pointer_width = "16", repr(C, align(2)))]
|
||||
|
|
@ -447,6 +453,9 @@ impl AtomicBool {
|
|||
/// [`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
/// using [`Release`] makes the load part [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
/// [`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -481,6 +490,9 @@ impl AtomicBool {
|
|||
/// Using [`Acquire`] makes the store part of this operation [`Relaxed`] if it
|
||||
/// happens, and using [`Release`] makes the load part [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
/// [`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -524,6 +536,8 @@ impl AtomicBool {
|
|||
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
|
||||
/// and must be equivalent to or weaker than the success ordering.
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// [`bool`]: ../../../std/primitive.bool.html
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
|
|
@ -586,6 +600,9 @@ impl AtomicBool {
|
|||
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
|
||||
/// and must be equivalent to or weaker than the success ordering.
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// [`bool`]: ../../../std/primitive.bool.html
|
||||
/// [`compare_exchange`]: #method.compare_exchange
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
|
|
@ -646,6 +663,9 @@ impl AtomicBool {
|
|||
/// [`Release`]: enum.Ordering.html#variant.Release
|
||||
/// [`Acquire`]: enum.Ordering.html#variant.Acquire
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -683,6 +703,9 @@ impl AtomicBool {
|
|||
/// [`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
/// using [`Release`] makes the load part [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
/// [`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -737,6 +760,9 @@ impl AtomicBool {
|
|||
/// [`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
/// using [`Release`] makes the load part [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
/// [`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -779,6 +805,9 @@ impl AtomicBool {
|
|||
/// [`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
/// using [`Release`] makes the load part [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
/// [`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -981,6 +1010,9 @@ impl<T> AtomicPtr<T> {
|
|||
/// [`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
/// using [`Release`] makes the load part [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on pointers.
|
||||
///
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
/// [`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1017,6 +1049,9 @@ impl<T> AtomicPtr<T> {
|
|||
/// Using [`Acquire`] makes the store part of this operation [`Relaxed`] if it
|
||||
/// happens, and using [`Release`] makes the load part [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on pointers.
|
||||
///
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
/// [`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1058,6 +1093,9 @@ impl<T> AtomicPtr<T> {
|
|||
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
|
||||
/// and must be equivalent to or weaker than the success ordering.
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on pointers.
|
||||
///
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
/// [`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1118,6 +1156,9 @@ impl<T> AtomicPtr<T> {
|
|||
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
|
||||
/// and must be equivalent to or weaker than the success ordering.
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on pointers.
|
||||
///
|
||||
/// [`compare_exchange`]: #method.compare_exchange
|
||||
/// [`Ordering`]: enum.Ordering.html
|
||||
/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
|
|
@ -1223,6 +1264,13 @@ macro_rules! atomic_int {
|
|||
/// non-atomic types as well as information about the portability of
|
||||
/// this type, please see the [module-level documentation].
|
||||
///
|
||||
/// **Note:** This type is only available on platforms that support
|
||||
/// atomic loads and stores of [`
|
||||
#[doc = $s_int_type]
|
||||
/// `](
|
||||
#[doc = $int_ref]
|
||||
/// ).
|
||||
///
|
||||
/// [module-level documentation]: index.html
|
||||
#[$stable]
|
||||
#[repr(C, align($align))]
|
||||
|
|
@ -1408,6 +1456,9 @@ of this operation. All ordering modes are possible. Note that using
|
|||
[`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
using [`Release`] makes the load part [`Relaxed`].
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1444,6 +1495,9 @@ might fail and hence just perform an `Acquire` load, but not have `Release` sema
|
|||
Using [`Acquire`] makes the store part of this operation [`Relaxed`] if it
|
||||
happens, and using [`Release`] makes the load part [`Relaxed`].
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1496,6 +1550,9 @@ of this operation [`Relaxed`], and using [`Release`] makes the successful load
|
|||
[`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
|
||||
and must be equivalent to or weaker than the success ordering.
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1558,6 +1615,9 @@ and must be equivalent to or weaker than the success ordering.
|
|||
[`Acquire`]: enum.Ordering.html#variant.Acquire
|
||||
[`SeqCst`]: enum.Ordering.html#variant.SeqCst
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
# Examples
|
||||
|
||||
```
|
||||
|
|
@ -1599,6 +1659,9 @@ of this operation. All ordering modes are possible. Note that using
|
|||
[`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
using [`Release`] makes the load part [`Relaxed`].
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1632,6 +1695,9 @@ of this operation. All ordering modes are possible. Note that using
|
|||
[`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
using [`Release`] makes the load part [`Relaxed`].
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1668,6 +1734,9 @@ of this operation. All ordering modes are possible. Note that using
|
|||
[`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
using [`Release`] makes the load part [`Relaxed`].
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1704,6 +1773,9 @@ of this operation. All ordering modes are possible. Note that using
|
|||
[`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
using [`Release`] makes the load part [`Relaxed`].
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1741,6 +1813,9 @@ of this operation. All ordering modes are possible. Note that using
|
|||
[`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
using [`Release`] makes the load part [`Relaxed`].
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1777,6 +1852,9 @@ of this operation. All ordering modes are possible. Note that using
|
|||
[`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
using [`Release`] makes the load part [`Relaxed`].
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1807,19 +1885,21 @@ new value. Returns a `Result` of `Ok(previous_value)` if the function returned `
|
|||
|
||||
Note: This may call the function multiple times if the value has been changed from other threads in
|
||||
the meantime, as long as the function returns `Some(_)`, but the function will have been applied
|
||||
but once to the stored value.
|
||||
only once to the stored value.
|
||||
|
||||
`fetch_update` takes two [`Ordering`] arguments to describe the memory
|
||||
ordering of this operation. The first describes the required ordering for loads
|
||||
and failed updates while the second describes the required ordering when the
|
||||
operation finally succeeds. Beware that this is different from the two
|
||||
modes in [`compare_exchange`]!
|
||||
`fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
|
||||
The first describes the required ordering for when the operation finally succeeds while the second
|
||||
describes the required ordering for loads. These correspond to the success and failure orderings of
|
||||
[`compare_exchange`] respectively.
|
||||
|
||||
Using [`Acquire`] as success ordering makes the store part
|
||||
of this operation [`Relaxed`], and using [`Release`] makes the final successful load
|
||||
[`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
|
||||
and must be equivalent to or weaker than the success ordering.
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`bool`]: ../../../std/primitive.bool.html
|
||||
[`compare_exchange`]: #method.compare_exchange
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
|
|
@ -1831,24 +1911,21 @@ and must be equivalent to or weaker than the success ordering.
|
|||
# Examples
|
||||
|
||||
```rust
|
||||
#![feature(no_more_cas)]
|
||||
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
|
||||
|
||||
let x = ", stringify!($atomic_type), "::new(7);
|
||||
assert_eq!(x.fetch_update(|_| None, Ordering::SeqCst, Ordering::SeqCst), Err(7));
|
||||
assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(7));
|
||||
assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(8));
|
||||
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7));
|
||||
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7));
|
||||
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8));
|
||||
assert_eq!(x.load(Ordering::SeqCst), 9);
|
||||
```"),
|
||||
#[inline]
|
||||
#[unstable(feature = "no_more_cas",
|
||||
reason = "no more CAS loops in user code",
|
||||
issue = "48655")]
|
||||
#[stable(feature = "no_more_cas", since = "1.45.0")]
|
||||
#[$cfg_cas]
|
||||
pub fn fetch_update<F>(&self,
|
||||
mut f: F,
|
||||
set_order: Ordering,
|
||||
fetch_order: Ordering,
|
||||
set_order: Ordering) -> Result<$int_type, $int_type>
|
||||
mut f: F) -> Result<$int_type, $int_type>
|
||||
where F: FnMut($int_type) -> Option<$int_type> {
|
||||
let mut prev = self.load(fetch_order);
|
||||
while let Some(next) = f(prev) {
|
||||
|
|
@ -1874,6 +1951,9 @@ of this operation. All ordering modes are possible. Note that using
|
|||
[`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
using [`Release`] makes the load part [`Relaxed`].
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1882,7 +1962,6 @@ using [`Release`] makes the load part [`Relaxed`].
|
|||
# Examples
|
||||
|
||||
```
|
||||
#![feature(atomic_min_max)]
|
||||
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
|
||||
|
||||
let foo = ", stringify!($atomic_type), "::new(23);
|
||||
|
|
@ -1893,7 +1972,6 @@ assert_eq!(foo.load(Ordering::SeqCst), 42);
|
|||
If you want to obtain the maximum value in one step, you can use the following:
|
||||
|
||||
```
|
||||
#![feature(atomic_min_max)]
|
||||
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
|
||||
|
||||
let foo = ", stringify!($atomic_type), "::new(23);
|
||||
|
|
@ -1902,9 +1980,7 @@ let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar);
|
|||
assert!(max_foo == 42);
|
||||
```"),
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_min_max",
|
||||
reason = "easier and faster min/max than writing manual CAS loop",
|
||||
issue = "48655")]
|
||||
#[stable(feature = "atomic_min_max", since = "1.45.0")]
|
||||
#[$cfg_cas]
|
||||
pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
|
||||
// SAFETY: data races are prevented by atomic intrinsics.
|
||||
|
|
@ -1925,6 +2001,9 @@ of this operation. All ordering modes are possible. Note that using
|
|||
[`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
using [`Release`] makes the load part [`Relaxed`].
|
||||
|
||||
**Note**: This method is only available on platforms that support atomic
|
||||
operations on [`", $s_int_type, "`](", $int_ref, ").
|
||||
|
||||
[`Ordering`]: enum.Ordering.html
|
||||
[`Relaxed`]: enum.Ordering.html#variant.Relaxed
|
||||
[`Release`]: enum.Ordering.html#variant.Release
|
||||
|
|
@ -1933,7 +2012,6 @@ using [`Release`] makes the load part [`Relaxed`].
|
|||
# Examples
|
||||
|
||||
```
|
||||
#![feature(atomic_min_max)]
|
||||
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
|
||||
|
||||
let foo = ", stringify!($atomic_type), "::new(23);
|
||||
|
|
@ -1946,7 +2024,6 @@ assert_eq!(foo.load(Ordering::Relaxed), 22);
|
|||
If you want to obtain the minimum value in one step, you can use the following:
|
||||
|
||||
```
|
||||
#![feature(atomic_min_max)]
|
||||
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
|
||||
|
||||
let foo = ", stringify!($atomic_type), "::new(23);
|
||||
|
|
@ -1955,9 +2032,7 @@ let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar);
|
|||
assert_eq!(min_foo, 12);
|
||||
```"),
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_min_max",
|
||||
reason = "easier and faster min/max than writing manual CAS loop",
|
||||
issue = "48655")]
|
||||
#[stable(feature = "atomic_min_max", since = "1.45.0")]
|
||||
#[$cfg_cas]
|
||||
pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
|
||||
// SAFETY: data races are prevented by atomic intrinsics.
|
||||
|
|
|
|||
|
|
@ -813,6 +813,30 @@ fn test_iterator_peekable_rfold() {
|
|||
assert_eq!(i, xs.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_peekable_next_if_eq() {
|
||||
// first, try on references
|
||||
let xs = vec!["Heart", "of", "Gold"];
|
||||
let mut it = xs.into_iter().peekable();
|
||||
// try before `peek()`
|
||||
assert_eq!(it.next_if_eq(&"trillian"), None);
|
||||
assert_eq!(it.next_if_eq(&"Heart"), Some("Heart"));
|
||||
// try after peek()
|
||||
assert_eq!(it.peek(), Some(&"of"));
|
||||
assert_eq!(it.next_if_eq(&"of"), Some("of"));
|
||||
assert_eq!(it.next_if_eq(&"zaphod"), None);
|
||||
// make sure `next()` still behaves
|
||||
assert_eq!(it.next(), Some("Gold"));
|
||||
|
||||
// make sure comparison works for owned values
|
||||
let xs = vec![String::from("Ludicrous"), "speed".into()];
|
||||
let mut it = xs.into_iter().peekable();
|
||||
// make sure basic functionality works
|
||||
assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into()));
|
||||
assert_eq!(it.next_if_eq("speed"), Some("speed".into()));
|
||||
assert_eq!(it.next_if_eq(""), None);
|
||||
}
|
||||
|
||||
/// This is an iterator that follows the Iterator contract,
|
||||
/// but it is not fused. After having returned None once, it will start
|
||||
/// producing elements if .next() is called again.
|
||||
|
|
@ -1932,6 +1956,21 @@ fn test_range() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char_range() {
|
||||
use std::char;
|
||||
// Miri is too slow
|
||||
let from = if cfg!(miri) { char::from_u32(0xD800 - 10).unwrap() } else { '\0' };
|
||||
let to = if cfg!(miri) { char::from_u32(0xDFFF + 10).unwrap() } else { char::MAX };
|
||||
assert!((from..=to).eq((from as u32..=to as u32).filter_map(char::from_u32)));
|
||||
assert!((from..=to).rev().eq((from as u32..=to as u32).filter_map(char::from_u32).rev()));
|
||||
|
||||
assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2);
|
||||
assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2)));
|
||||
assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1);
|
||||
assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_exhaustion() {
|
||||
let mut r = 10..10;
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#![feature(leading_trailing_ones)]
|
||||
#![feature(const_forget)]
|
||||
#![feature(option_unwrap_none)]
|
||||
#![feature(peekable_next_if)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,6 @@ impl Duration {
|
|||
/// ```
|
||||
#[stable(feature = "duration", since = "1.3.0")]
|
||||
#[inline]
|
||||
#[rustc_promotable]
|
||||
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
|
||||
pub const fn from_secs(secs: u64) -> Duration {
|
||||
Duration { secs, nanos: 0 }
|
||||
|
|
|
|||
|
|
@ -327,8 +327,5 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
|
|||
#[lang = "eh_personality"]
|
||||
#[cfg(not(test))]
|
||||
fn rust_eh_personality() {
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // remove `unsafe` on bootstrap bump
|
||||
unsafe {
|
||||
core::intrinsics::abort()
|
||||
}
|
||||
core::intrinsics::abort()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ mod diagnostic;
|
|||
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
|
||||
pub use diagnostic::{Diagnostic, Level, MultiSpan};
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
|
@ -420,6 +421,20 @@ impl !Send for LineColumn {}
|
|||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
impl !Sync for LineColumn {}
|
||||
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
impl Ord for LineColumn {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.line.cmp(&other.line).then(self.column.cmp(&other.column))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
impl PartialOrd for LineColumn {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
/// The source file of a given `Span`.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
#[derive(Clone)]
|
||||
|
|
|
|||
12
src/libproc_macro/tests/test.rs
Normal file
12
src/libproc_macro/tests/test.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#![feature(proc_macro_span)]
|
||||
|
||||
use proc_macro::LineColumn;
|
||||
|
||||
#[test]
|
||||
fn test_line_column_ord() {
|
||||
let line0_column0 = LineColumn { line: 0, column: 0 };
|
||||
let line0_column1 = LineColumn { line: 0, column: 1 };
|
||||
let line1_column0 = LineColumn { line: 1, column: 0 };
|
||||
assert!(line0_column0 < line0_column1);
|
||||
assert!(line0_column1 < line1_column0);
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "arena"
|
||||
name = "rustc_arena"
|
||||
version = "0.0.0"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "arena"
|
||||
name = "rustc_arena"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
|
|
@ -146,18 +146,18 @@ impl<T> TypedArena<T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn can_allocate(&self, len: usize) -> bool {
|
||||
let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize;
|
||||
let at_least_bytes = len.checked_mul(mem::size_of::<T>()).unwrap();
|
||||
available_capacity_bytes >= at_least_bytes
|
||||
fn can_allocate(&self, additional: usize) -> bool {
|
||||
let available_bytes = self.end.get() as usize - self.ptr.get() as usize;
|
||||
let additional_bytes = additional.checked_mul(mem::size_of::<T>()).unwrap();
|
||||
available_bytes >= additional_bytes
|
||||
}
|
||||
|
||||
/// Ensures there's enough space in the current chunk to fit `len` objects.
|
||||
#[inline]
|
||||
fn ensure_capacity(&self, len: usize) {
|
||||
if !self.can_allocate(len) {
|
||||
self.grow(len);
|
||||
debug_assert!(self.can_allocate(len));
|
||||
fn ensure_capacity(&self, additional: usize) {
|
||||
if !self.can_allocate(additional) {
|
||||
self.grow(additional);
|
||||
debug_assert!(self.can_allocate(additional));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -214,36 +214,31 @@ impl<T> TypedArena<T> {
|
|||
/// Grows the arena.
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn grow(&self, n: usize) {
|
||||
fn grow(&self, additional: usize) {
|
||||
unsafe {
|
||||
// We need the element size in to convert chunk sizes (ranging from
|
||||
// We need the element size to convert chunk sizes (ranging from
|
||||
// PAGE to HUGE_PAGE bytes) to element counts.
|
||||
let elem_size = cmp::max(1, mem::size_of::<T>());
|
||||
let mut chunks = self.chunks.borrow_mut();
|
||||
let (chunk, mut new_capacity);
|
||||
let mut new_cap;
|
||||
if let Some(last_chunk) = chunks.last_mut() {
|
||||
let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
|
||||
let currently_used_cap = used_bytes / mem::size_of::<T>();
|
||||
last_chunk.entries = currently_used_cap;
|
||||
if last_chunk.storage.reserve_in_place(currently_used_cap, n) {
|
||||
self.end.set(last_chunk.end());
|
||||
return;
|
||||
} else {
|
||||
// If the previous chunk's capacity is less than HUGE_PAGE
|
||||
// bytes, then this chunk will be least double the previous
|
||||
// chunk's size.
|
||||
new_capacity = last_chunk.storage.capacity();
|
||||
if new_capacity < HUGE_PAGE / elem_size {
|
||||
new_capacity = new_capacity.checked_mul(2).unwrap();
|
||||
}
|
||||
last_chunk.entries = used_bytes / mem::size_of::<T>();
|
||||
|
||||
// If the previous chunk's capacity is less than HUGE_PAGE
|
||||
// bytes, then this chunk will be least double the previous
|
||||
// chunk's size.
|
||||
new_cap = last_chunk.storage.capacity();
|
||||
if new_cap < HUGE_PAGE / elem_size {
|
||||
new_cap = new_cap.checked_mul(2).unwrap();
|
||||
}
|
||||
} else {
|
||||
new_capacity = PAGE / elem_size;
|
||||
new_cap = PAGE / elem_size;
|
||||
}
|
||||
// Also ensure that this chunk can fit `n`.
|
||||
new_capacity = cmp::max(n, new_capacity);
|
||||
// Also ensure that this chunk can fit `additional`.
|
||||
new_cap = cmp::max(additional, new_cap);
|
||||
|
||||
chunk = TypedArenaChunk::<T>::new(new_capacity);
|
||||
let chunk = TypedArenaChunk::<T>::new(new_cap);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
chunks.push(chunk);
|
||||
|
|
@ -347,31 +342,28 @@ impl DroplessArena {
|
|||
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn grow(&self, needed_bytes: usize) {
|
||||
fn grow(&self, additional: usize) {
|
||||
unsafe {
|
||||
let mut chunks = self.chunks.borrow_mut();
|
||||
let (chunk, mut new_capacity);
|
||||
let mut new_cap;
|
||||
if let Some(last_chunk) = chunks.last_mut() {
|
||||
let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
|
||||
if last_chunk.storage.reserve_in_place(used_bytes, needed_bytes) {
|
||||
self.end.set(last_chunk.end());
|
||||
return;
|
||||
} else {
|
||||
// If the previous chunk's capacity is less than HUGE_PAGE
|
||||
// bytes, then this chunk will be least double the previous
|
||||
// chunk's size.
|
||||
new_capacity = last_chunk.storage.capacity();
|
||||
if new_capacity < HUGE_PAGE {
|
||||
new_capacity = new_capacity.checked_mul(2).unwrap();
|
||||
}
|
||||
// There is no need to update `last_chunk.entries` because that
|
||||
// field isn't used by `DroplessArena`.
|
||||
|
||||
// If the previous chunk's capacity is less than HUGE_PAGE
|
||||
// bytes, then this chunk will be least double the previous
|
||||
// chunk's size.
|
||||
new_cap = last_chunk.storage.capacity();
|
||||
if new_cap < HUGE_PAGE {
|
||||
new_cap = new_cap.checked_mul(2).unwrap();
|
||||
}
|
||||
} else {
|
||||
new_capacity = PAGE;
|
||||
new_cap = PAGE;
|
||||
}
|
||||
// Also ensure that this chunk can fit `needed_bytes`.
|
||||
new_capacity = cmp::max(needed_bytes, new_capacity);
|
||||
// Also ensure that this chunk can fit `additional`.
|
||||
new_cap = cmp::max(additional, new_cap);
|
||||
|
||||
chunk = TypedArenaChunk::<u8>::new(new_capacity);
|
||||
let chunk = TypedArenaChunk::<u8>::new(new_cap);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
chunks.push(chunk);
|
||||
|
|
@ -386,7 +378,7 @@ impl DroplessArena {
|
|||
self.align(align);
|
||||
|
||||
let future_end = intrinsics::arith_offset(self.ptr.get(), bytes as isize);
|
||||
if (future_end as *mut u8) >= self.end.get() {
|
||||
if (future_end as *mut u8) > self.end.get() {
|
||||
self.grow(bytes);
|
||||
}
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ path = "lib.rs"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
rustc_serialize = { path = "../libserialize", package = "serialize" }
|
||||
rustc_serialize = { path = "../librustc_serialize" }
|
||||
log = "0.4"
|
||||
scoped-tls = "1.0"
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
|
|
|
|||
|
|
@ -1006,11 +1006,12 @@ pub struct Expr {
|
|||
pub kind: ExprKind,
|
||||
pub span: Span,
|
||||
pub attrs: AttrVec,
|
||||
pub tokens: Option<TokenStream>,
|
||||
}
|
||||
|
||||
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
rustc_data_structures::static_assert_size!(Expr, 96);
|
||||
rustc_data_structures::static_assert_size!(Expr, 104);
|
||||
|
||||
impl Expr {
|
||||
/// Returns `true` if this expression would be valid somewhere that expects a value;
|
||||
|
|
@ -1251,7 +1252,7 @@ pub enum ExprKind {
|
|||
Ret(Option<P<Expr>>),
|
||||
|
||||
/// Output of the `asm!()` macro.
|
||||
InlineAsm(InlineAsm),
|
||||
InlineAsm(P<InlineAsm>),
|
||||
/// Output of the `llvm_asm!()` macro.
|
||||
LlvmInlineAsm(P<LlvmInlineAsm>),
|
||||
|
||||
|
|
@ -1970,6 +1971,7 @@ pub struct InlineAsm {
|
|||
pub template: Vec<InlineAsmTemplatePiece>,
|
||||
pub operands: Vec<(InlineAsmOperand, Span)>,
|
||||
pub options: InlineAsmOptions,
|
||||
pub line_spans: Vec<Span>,
|
||||
}
|
||||
|
||||
/// Inline assembly dialect.
|
||||
|
|
|
|||
|
|
@ -1095,7 +1095,10 @@ pub fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonCo
|
|||
vis.visit_expr(value);
|
||||
}
|
||||
|
||||
pub fn noop_visit_expr<T: MutVisitor>(Expr { kind, id, span, attrs }: &mut Expr, vis: &mut T) {
|
||||
pub fn noop_visit_expr<T: MutVisitor>(
|
||||
Expr { kind, id, span, attrs, tokens: _ }: &mut Expr,
|
||||
vis: &mut T,
|
||||
) {
|
||||
match kind {
|
||||
ExprKind::Box(expr) => vis.visit_expr(expr),
|
||||
ExprKind::Array(exprs) => visit_exprs(exprs, vis),
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ use rustc_macros::HashStable_Generic;
|
|||
use rustc_span::{Span, DUMMY_SP};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use log::debug;
|
||||
|
||||
use std::{iter, mem};
|
||||
|
||||
/// When the main rust parser encounters a syntax-extension invocation, it
|
||||
|
|
@ -338,8 +340,71 @@ impl TokenStream {
|
|||
true
|
||||
}
|
||||
|
||||
let mut t1 = self.trees().filter(semantic_tree);
|
||||
let mut t2 = other.trees().filter(semantic_tree);
|
||||
// When comparing two `TokenStream`s, we ignore the `IsJoint` information.
|
||||
//
|
||||
// However, `rustc_parse::lexer::tokentrees::TokenStreamBuilder` will
|
||||
// use `Token.glue` on adjacent tokens with the proper `IsJoint`.
|
||||
// Since we are ignoreing `IsJoint`, a 'glued' token (e.g. `BinOp(Shr)`)
|
||||
// and its 'split'/'unglued' compoenents (e.g. `Gt, Gt`) are equivalent
|
||||
// when determining if two `TokenStream`s are 'probably equal'.
|
||||
//
|
||||
// Therefore, we use `break_two_token_op` to convert all tokens
|
||||
// to the 'unglued' form (if it exists). This ensures that two
|
||||
// `TokenStream`s which differ only in how their tokens are glued
|
||||
// will be considered 'probably equal', which allows us to keep spans.
|
||||
//
|
||||
// This is important when the original `TokenStream` contained
|
||||
// extra spaces (e.g. `f :: < Vec < _ > > ( ) ;'). These extra spaces
|
||||
// will be omitted when we pretty-print, which can cause the original
|
||||
// and reparsed `TokenStream`s to differ in the assignment of `IsJoint`,
|
||||
// leading to some tokens being 'glued' together in one stream but not
|
||||
// the other. See #68489 for more details.
|
||||
fn break_tokens(tree: TokenTree) -> impl Iterator<Item = TokenTree> {
|
||||
// In almost all cases, we should have either zero or one levels
|
||||
// of 'unglueing'. However, in some unusual cases, we may need
|
||||
// to iterate breaking tokens mutliple times. For example:
|
||||
// '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]'
|
||||
let mut token_trees: SmallVec<[_; 2]>;
|
||||
if let TokenTree::Token(token) = &tree {
|
||||
let mut out = SmallVec::<[_; 2]>::new();
|
||||
out.push(token.clone());
|
||||
// Iterate to fixpoint:
|
||||
// * We start off with 'out' containing our initial token, and `temp` empty
|
||||
// * If we are able to break any tokens in `out`, then `out` will have
|
||||
// at least one more element than 'temp', so we will try to break tokens
|
||||
// again.
|
||||
// * If we cannot break any tokens in 'out', we are done
|
||||
loop {
|
||||
let mut temp = SmallVec::<[_; 2]>::new();
|
||||
let mut changed = false;
|
||||
|
||||
for token in out.into_iter() {
|
||||
if let Some((first, second)) = token.kind.break_two_token_op() {
|
||||
temp.push(Token::new(first, DUMMY_SP));
|
||||
temp.push(Token::new(second, DUMMY_SP));
|
||||
changed = true;
|
||||
} else {
|
||||
temp.push(token);
|
||||
}
|
||||
}
|
||||
out = temp;
|
||||
if !changed {
|
||||
break;
|
||||
}
|
||||
}
|
||||
token_trees = out.into_iter().map(|t| TokenTree::Token(t)).collect();
|
||||
if token_trees.len() != 1 {
|
||||
debug!("break_tokens: broke {:?} to {:?}", tree, token_trees);
|
||||
}
|
||||
} else {
|
||||
token_trees = SmallVec::new();
|
||||
token_trees.push(tree);
|
||||
}
|
||||
token_trees.into_iter()
|
||||
}
|
||||
|
||||
let mut t1 = self.trees().filter(semantic_tree).flat_map(break_tokens);
|
||||
let mut t2 = other.trees().filter(semantic_tree).flat_map(break_tokens);
|
||||
for (t1, t2) in t1.by_ref().zip(t2.by_ref()) {
|
||||
if !t1.probably_equal_for_proc_macro(&t2) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ path = "lib.rs"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
arena = { path = "../libarena" }
|
||||
rustc_arena = { path = "../librustc_arena" }
|
||||
log = { version = "0.4", features = ["release_max_level_info", "std"] }
|
||||
rustc_ast_pretty = { path = "../librustc_ast_pretty" }
|
||||
rustc_hir = { path = "../librustc_hir" }
|
||||
|
|
|
|||
|
|
@ -974,20 +974,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> {
|
||||
let asm_arch = if let Some(asm_arch) = self.sess.asm_arch {
|
||||
asm_arch
|
||||
} else {
|
||||
if self.sess.asm_arch.is_none() {
|
||||
struct_span_err!(self.sess, sp, E0472, "asm! is unsupported on this target").emit();
|
||||
return hir::ExprKind::Err;
|
||||
};
|
||||
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
|
||||
match asm_arch {
|
||||
asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64 => {}
|
||||
_ => self
|
||||
.sess
|
||||
.struct_span_err(sp, "the `att_syntax` option is only supported on x86")
|
||||
.emit(),
|
||||
}
|
||||
}
|
||||
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
|
||||
&& !matches!(
|
||||
self.sess.asm_arch,
|
||||
Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64)
|
||||
)
|
||||
{
|
||||
self.sess
|
||||
.struct_span_err(sp, "the `att_syntax` option is only supported on x86")
|
||||
.emit();
|
||||
}
|
||||
|
||||
// Lower operands to HIR, filter_map skips any operands with invalid
|
||||
|
|
@ -1001,10 +999,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
Some(match reg {
|
||||
InlineAsmRegOrRegClass::Reg(s) => asm::InlineAsmRegOrRegClass::Reg(
|
||||
asm::InlineAsmReg::parse(
|
||||
asm_arch,
|
||||
|feature| {
|
||||
self.sess.target_features.contains(&Symbol::intern(feature))
|
||||
},
|
||||
sess.asm_arch?,
|
||||
|feature| sess.target_features.contains(&Symbol::intern(feature)),
|
||||
s,
|
||||
)
|
||||
.map_err(|e| {
|
||||
|
|
@ -1015,7 +1011,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
),
|
||||
InlineAsmRegOrRegClass::RegClass(s) => {
|
||||
asm::InlineAsmRegOrRegClass::RegClass(
|
||||
asm::InlineAsmRegClass::parse(asm_arch, s)
|
||||
asm::InlineAsmRegClass::parse(sess.asm_arch?, s)
|
||||
.map_err(|e| {
|
||||
let msg = format!(
|
||||
"invalid register class `{}`: {}",
|
||||
|
|
@ -1029,33 +1025,38 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
})
|
||||
};
|
||||
let op = match op {
|
||||
InlineAsmOperand::In { reg, expr } => hir::InlineAsmOperand::In {
|
||||
reg: lower_reg(*reg)?,
|
||||
|
||||
// lower_reg is executed last because we need to lower all
|
||||
// sub-expressions even if we throw them away later.
|
||||
let op = match *op {
|
||||
InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
|
||||
expr: self.lower_expr_mut(expr),
|
||||
reg: lower_reg(reg)?,
|
||||
},
|
||||
InlineAsmOperand::Out { reg, late, expr } => hir::InlineAsmOperand::Out {
|
||||
reg: lower_reg(*reg)?,
|
||||
late: *late,
|
||||
InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
|
||||
late,
|
||||
expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
reg: lower_reg(reg)?,
|
||||
},
|
||||
InlineAsmOperand::InOut { reg, late, expr } => hir::InlineAsmOperand::InOut {
|
||||
reg: lower_reg(*reg)?,
|
||||
late: *late,
|
||||
expr: self.lower_expr_mut(expr),
|
||||
},
|
||||
InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
|
||||
hir::InlineAsmOperand::SplitInOut {
|
||||
reg: lower_reg(*reg)?,
|
||||
late: *late,
|
||||
in_expr: self.lower_expr_mut(in_expr),
|
||||
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
InlineAsmOperand::InOut { reg, late, ref expr } => {
|
||||
hir::InlineAsmOperand::InOut {
|
||||
late,
|
||||
expr: self.lower_expr_mut(expr),
|
||||
reg: lower_reg(reg)?,
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Const { expr } => {
|
||||
InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
|
||||
hir::InlineAsmOperand::SplitInOut {
|
||||
late,
|
||||
in_expr: self.lower_expr_mut(in_expr),
|
||||
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
|
||||
reg: lower_reg(reg)?,
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Const { ref expr } => {
|
||||
hir::InlineAsmOperand::Const { expr: self.lower_expr_mut(expr) }
|
||||
}
|
||||
InlineAsmOperand::Sym { expr } => {
|
||||
InlineAsmOperand::Sym { ref expr } => {
|
||||
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
|
||||
}
|
||||
};
|
||||
|
|
@ -1069,6 +1070,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
// Validate template modifiers against the register classes for the operands
|
||||
let asm_arch = sess.asm_arch.unwrap();
|
||||
for p in &asm.template {
|
||||
if let InlineAsmTemplatePiece::Placeholder {
|
||||
operand_idx,
|
||||
|
|
@ -1265,7 +1267,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let operands = self.arena.alloc_from_iter(operands);
|
||||
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
|
||||
let hir_asm = hir::InlineAsm { template, operands, options: asm.options };
|
||||
let line_spans = self.arena.alloc_slice(&asm.line_spans[..]);
|
||||
let hir_asm = hir::InlineAsm { template, operands, options: asm.options, line_spans };
|
||||
hir::ExprKind::InlineAsm(self.arena.alloc(hir_asm))
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue