Auto merge of #63015 - Centril:rollup-ydhpcas, r=Centril
Rollup of 22 pull requests Successful merges: - #62084 (allow clippy::unreadable_literal in unicode tables) - #62120 (Add missing type links in documentation) - #62310 (Add missing doc links in boxed module) - #62421 (Introduce `as_deref` to Option) - #62583 (Implement Unpin for all raw pointers) - #62692 (rustc: precompute the largest Niche and store it in LayoutDetails.) - #62801 (Remove support for -Zlower-128bit-ops) - #62828 (Remove vector fadd/fmul reduction workarounds) - #62862 (code cleanup) - #62904 (Disable d32 on armv6 hf targets) - #62907 (Initialize the MSP430 AsmParser) - #62956 (Implement slow-path for FirstSets::first) - #62963 (Allow lexer to recover from some homoglyphs) - #62964 (clarify and unify some type test names) - #62970 (ci: gate toolstate repo pushes on the TOOLSTATE_PUBLISH envvar) - #62980 (std: Add more accessors for `Metadata` on Windows) - #62983 (Remove needless indirection through Rc) - #62985 (librustc_errors: Support ui-testing flag in annotate-snippet emitter) - #63002 (error_index_generator should output stdout/stderr when it panics.) - #63004 (Add test for issue-54062) - #63007 (ci: debug network failures while downloading awscli from PyPI) - #63009 (Remove redundant `mut` from variable declaration.) Failed merges: r? @ghost
This commit is contained in:
commit
c43753f910
@ -140,9 +140,35 @@ steps:
|
||||
# images, etc.
|
||||
- bash: |
|
||||
set -e
|
||||
# Temporary code to debug #62967.
|
||||
debug_failed_connections() {
|
||||
echo "trying to ping pypi.org"
|
||||
ping pypi.org -c10 || true
|
||||
echo "trying to ping google.com"
|
||||
ping google.com -c10 || true
|
||||
echo "trying to ping 8.8.8.8"
|
||||
ping 8.8.8.8 -c10 || true
|
||||
echo "trying to download pypi.org"
|
||||
curl https://pypi.org || true
|
||||
echo "trying to download from our S3 bucket"
|
||||
curl https://rust-lang-ci2.s3.amazonaws.com || true
|
||||
echo "trying to dig pypi.org"
|
||||
dig pypi.org || true
|
||||
echo "trying to dig files.pythonhosted.org"
|
||||
dig files.pythonhosted.org || true
|
||||
echo "trying to connect to pypi.org with openssl"
|
||||
echo | openssl s_client -connect pypi.org:443 || true
|
||||
echo "trying to connect to files.pythonhosted.org with openssl"
|
||||
echo | openssl s_client -connect files.pythonhosted.org:443 || true
|
||||
}
|
||||
debug_failed_connections_and_fail() {
|
||||
debug_failed_connections
|
||||
return 1
|
||||
}
|
||||
source src/ci/shared.sh
|
||||
sudo apt-get install -y python3-setuptools
|
||||
retry pip3 install -r src/ci/awscli-requirements.txt --upgrade --user
|
||||
debug_failed_connections
|
||||
retry pip3 install -r src/ci/awscli-requirements.txt --upgrade --user || debug_failed_connections_and_fail
|
||||
echo "##vso[task.prependpath]$HOME/.local/bin"
|
||||
displayName: Install awscli (Linux)
|
||||
condition: and(succeeded(), not(variables.SKIP_JOB), eq(variables['Agent.OS'], 'Linux'))
|
||||
|
46
Cargo.lock
46
Cargo.lock
@ -17,7 +17,7 @@ dependencies = [
|
||||
name = "alloc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core 0.0.0",
|
||||
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -44,6 +44,11 @@ dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "annotate-snippets"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
@ -110,7 +115,7 @@ dependencies = [
|
||||
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-std-workspace-core 1.0.0",
|
||||
@ -122,7 +127,7 @@ version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-std-workspace-core 1.0.0",
|
||||
]
|
||||
@ -331,7 +336,7 @@ name = "cfg-if"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-std-workspace-core 1.0.0",
|
||||
]
|
||||
|
||||
@ -460,7 +465,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -791,7 +796,7 @@ name = "dlmalloc"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-std-workspace-core 1.0.0",
|
||||
]
|
||||
@ -956,7 +961,7 @@ name = "fortanix-sgx-abi"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-std-workspace-core 1.0.0",
|
||||
]
|
||||
|
||||
@ -1133,7 +1138,7 @@ name = "hashbrown"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-std-workspace-alloc 1.0.0",
|
||||
"rustc-std-workspace-core 1.0.0",
|
||||
]
|
||||
@ -1951,7 +1956,7 @@ dependencies = [
|
||||
name = "panic_abort"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core 0.0.0",
|
||||
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -1962,7 +1967,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc 0.0.0",
|
||||
"cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core 0.0.0",
|
||||
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unwind 0.0.0",
|
||||
@ -2133,7 +2138,7 @@ name = "profiler_builtins"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
@ -2670,7 +2675,7 @@ name = "rustc-demangle"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-std-workspace-core 1.0.0",
|
||||
]
|
||||
|
||||
@ -2762,7 +2767,7 @@ dependencies = [
|
||||
"alloc 0.0.0",
|
||||
"build_helper 0.1.0",
|
||||
"cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
@ -2891,7 +2896,7 @@ dependencies = [
|
||||
name = "rustc_errors"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"annotate-snippets 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_data_structures 0.0.0",
|
||||
@ -2984,7 +2989,7 @@ dependencies = [
|
||||
"alloc 0.0.0",
|
||||
"build_helper 0.1.0",
|
||||
"cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
@ -3047,7 +3052,7 @@ dependencies = [
|
||||
"alloc 0.0.0",
|
||||
"build_helper 0.1.0",
|
||||
"cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
@ -3165,7 +3170,7 @@ dependencies = [
|
||||
"alloc 0.0.0",
|
||||
"build_helper 0.1.0",
|
||||
"cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core 0.0.0",
|
||||
]
|
||||
|
||||
@ -3472,7 +3477,7 @@ dependencies = [
|
||||
"backtrace 0.3.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core 0.0.0",
|
||||
"dlmalloc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -4099,7 +4104,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core 0.0.0",
|
||||
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -4280,6 +4285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
|
||||
"checksum ammonia 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "384d704f242a0a9faf793fff775a0be6ab9aa27edabffa097331d73779142520"
|
||||
"checksum annotate-snippets 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e8bcdcd5b291ce85a78f2b9d082a8de9676c12b1840d386d67bc5eea6f9d2b4e"
|
||||
"checksum annotate-snippets 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6"
|
||||
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
|
||||
@ -4313,7 +4319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
|
||||
"checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
|
||||
"checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2"
|
||||
"checksum compiler_builtins 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "ad9b4731b9e701aefe9e6bd1e9173f30526661508f9aaadaa5caec25ddf95585"
|
||||
"checksum compiler_builtins 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "ef1c086a06d6f52f9c0d50cacdc021bfb6034ddeec9fb7e62f099f13f65472f4"
|
||||
"checksum compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "f40ecc9332b68270998995c00f8051ee856121764a0d3230e64c9efd059d27b6"
|
||||
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
|
||||
"checksum core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887"
|
||||
|
@ -1493,7 +1493,7 @@ impl Step for ErrorIndex {
|
||||
|
||||
builder.info(&format!("Testing error-index stage{}", compiler.stage));
|
||||
let _time = util::timeit(&builder);
|
||||
builder.run(&mut tool);
|
||||
builder.run_quiet(&mut tool);
|
||||
markdown_test(builder, compiler, &output);
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ $COMMIT\t$(cat "$TOOLSTATE_FILE")
|
||||
}
|
||||
|
||||
if [ "$RUST_RELEASE_CHANNEL" = nightly ]; then
|
||||
if [ -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
|
||||
if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then
|
||||
. "$(dirname $0)/repo.sh"
|
||||
MESSAGE_FILE=$(mktemp -t msg.XXXXXX)
|
||||
echo "($OS CI update)" > "$MESSAGE_FILE"
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! A pointer type for heap allocation.
|
||||
//!
|
||||
//! `Box<T>`, casually referred to as a 'box', provides the simplest form of
|
||||
//! [`Box<T>`], casually referred to as a 'box', provides the simplest form of
|
||||
//! heap allocation in Rust. Boxes provide ownership for this allocation, and
|
||||
//! drop their contents when they go out of scope.
|
||||
//!
|
||||
@ -48,7 +48,7 @@
|
||||
//!
|
||||
//! It wouldn't work. This is because the size of a `List` depends on how many
|
||||
//! elements are in the list, and so we don't know how much memory to allocate
|
||||
//! for a `Cons`. By introducing a `Box`, which has a defined size, we know how
|
||||
//! for a `Cons`. By introducing a [`Box<T>`], which has a defined size, we know how
|
||||
//! big `Cons` needs to be.
|
||||
//!
|
||||
//! # Memory layout
|
||||
@ -59,15 +59,19 @@
|
||||
//! [`Layout`] used with the allocator is correct for the type. More precisely,
|
||||
//! a `value: *mut T` that has been allocated with the [`Global`] allocator
|
||||
//! with `Layout::for_value(&*value)` may be converted into a box using
|
||||
//! `Box::<T>::from_raw(value)`. Conversely, the memory backing a `value: *mut
|
||||
//! T` obtained from `Box::<T>::into_raw` may be deallocated using the
|
||||
//! [`Global`] allocator with `Layout::for_value(&*value)`.
|
||||
//! [`Box::<T>::from_raw(value)`]. Conversely, the memory backing a `value: *mut
|
||||
//! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the
|
||||
//! [`Global`] allocator with [`Layout::for_value(&*value)`].
|
||||
//!
|
||||
//!
|
||||
//! [dereferencing]: ../../std/ops/trait.Deref.html
|
||||
//! [`Box`]: struct.Box.html
|
||||
//! [`Box<T>`]: struct.Box.html
|
||||
//! [`Box::<T>::from_raw(value)`]: struct.Box.html#method.from_raw
|
||||
//! [`Box::<T>::into_raw`]: struct.Box.html#method.into_raw
|
||||
//! [`Global`]: ../alloc/struct.Global.html
|
||||
//! [`Layout`]: ../alloc/struct.Layout.html
|
||||
//! [`Layout::for_value(&*value)`]: ../alloc/struct.Layout.html#method.for_value
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
@ -319,7 +319,7 @@ impl Ordering {
|
||||
/// This method can be used to reverse a comparison:
|
||||
///
|
||||
/// ```
|
||||
/// let mut data: &mut [_] = &mut [2, 10, 5, 8];
|
||||
/// let data: &mut [_] = &mut [2, 10, 5, 8];
|
||||
///
|
||||
/// // sort the array from largest to smallest.
|
||||
/// data.sort_by(|a, b| a.cmp(b).reverse());
|
||||
|
@ -655,6 +655,12 @@ impl<'a, T: ?Sized + 'a> Unpin for &'a T {}
|
||||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
impl<'a, T: ?Sized + 'a> Unpin for &'a mut T {}
|
||||
|
||||
#[stable(feature = "pin_raw", since = "1.38.0")]
|
||||
impl<T: ?Sized> Unpin for *const T {}
|
||||
|
||||
#[stable(feature = "pin_raw", since = "1.38.0")]
|
||||
impl<T: ?Sized> Unpin for *mut T {}
|
||||
|
||||
/// Implementations of `Copy` for primitive types.
|
||||
///
|
||||
/// Implementations that cannot be described in Rust
|
||||
|
@ -136,7 +136,7 @@
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use crate::iter::{FromIterator, FusedIterator, TrustedLen};
|
||||
use crate::{convert, fmt, hint, mem, ops::{self, Deref}};
|
||||
use crate::{convert, fmt, hint, mem, ops::{self, Deref, DerefMut}};
|
||||
use crate::pin::Pin;
|
||||
|
||||
// Note that this is not a lang item per se, but it has a hidden dependency on
|
||||
@ -1104,17 +1104,28 @@ impl<T: Default> Option<T> {
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
impl<T: Deref> Option<T> {
|
||||
/// Converts from `&Option<T>` to `Option<&T::Target>`.
|
||||
/// Converts from `Option<T>` (or `&Option<T>`) to `Option<&T::Target>`.
|
||||
///
|
||||
/// Leaves the original Option in-place, creating a new one with a reference
|
||||
/// to the original one, additionally coercing the contents via [`Deref`].
|
||||
///
|
||||
/// [`Deref`]: ../../std/ops/trait.Deref.html
|
||||
pub fn deref(&self) -> Option<&T::Target> {
|
||||
pub fn as_deref(&self) -> Option<&T::Target> {
|
||||
self.as_ref().map(|t| t.deref())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
impl<T: DerefMut> Option<T> {
|
||||
/// Converts from `Option<T>` (or `&mut Option<T>`) to `Option<&mut T::Target>`.
|
||||
///
|
||||
/// Leaves the original `Option` in-place, creating a new one containing a mutable reference to
|
||||
/// the inner type's `Deref::Target` type.
|
||||
pub fn as_deref_mut(&mut self) -> Option<&mut T::Target> {
|
||||
self.as_mut().map(|t| t.deref_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Option<Result<T, E>> {
|
||||
/// Transposes an `Option` of a [`Result`] into a [`Result`] of an `Option`.
|
||||
///
|
||||
|
@ -11,13 +11,13 @@
|
||||
//! until it gets dropped. We say that the pointee is "pinned".
|
||||
//!
|
||||
//! By default, all types in Rust are movable. Rust allows passing all types by-value,
|
||||
//! and common smart-pointer types such as `Box<T>` and `&mut T` allow replacing and
|
||||
//! moving the values they contain: you can move out of a `Box<T>`, or you can use [`mem::swap`].
|
||||
//! [`Pin<P>`] wraps a pointer type `P`, so `Pin<Box<T>>` functions much like a regular `Box<T>`:
|
||||
//! when a `Pin<Box<T>>` gets dropped, so do its contents, and the memory gets deallocated.
|
||||
//! Similarly, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin<P>`] does not let clients
|
||||
//! actually obtain a `Box<T>` or `&mut T` to pinned data, which implies that you cannot use
|
||||
//! operations such as [`mem::swap`]:
|
||||
//! and common smart-pointer types such as [`Box<T>`] and `&mut T` allow replacing and
|
||||
//! moving the values they contain: you can move out of a [`Box<T>`], or you can use [`mem::swap`].
|
||||
//! [`Pin<P>`] wraps a pointer type `P`, so [`Pin`]`<`[`Box`]`<T>>` functions much like a regular
|
||||
//! [`Box<T>`]: when a [`Pin`]`<`[`Box`]`<T>>` gets dropped, so do its contents, and the memory gets
|
||||
//! deallocated. Similarly, [`Pin`]`<&mut T>` is a lot like `&mut T`. However, [`Pin<P>`] does
|
||||
//! not let clients actually obtain a [`Box<T>`] or `&mut T` to pinned data, which implies that you
|
||||
//! cannot use operations such as [`mem::swap`]:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::pin::Pin;
|
||||
@ -30,15 +30,15 @@
|
||||
//! ```
|
||||
//!
|
||||
//! It is worth reiterating that [`Pin<P>`] does *not* change the fact that a Rust compiler
|
||||
//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin<P>`
|
||||
//! prevents certain *values* (pointed to by pointers wrapped in `Pin<P>`) from being
|
||||
//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, [`Pin<P>`]
|
||||
//! prevents certain *values* (pointed to by pointers wrapped in [`Pin<P>`]) from being
|
||||
//! moved by making it impossible to call methods that require `&mut T` on them
|
||||
//! (like [`mem::swap`]).
|
||||
//!
|
||||
//! [`Pin<P>`] can be used to wrap any pointer type `P`, and as such it interacts with
|
||||
//! [`Deref`] and [`DerefMut`]. A `Pin<P>` where `P: Deref` should be considered
|
||||
//! as a "`P`-style pointer" to a pinned `P::Target` -- so, a `Pin<Box<T>>` is
|
||||
//! an owned pointer to a pinned `T`, and a `Pin<Rc<T>>` is a reference-counted
|
||||
//! [`Deref`] and [`DerefMut`]. A [`Pin<P>`] where `P: Deref` should be considered
|
||||
//! as a "`P`-style pointer" to a pinned `P::Target` -- so, a [`Pin`]`<`[`Box`]`<T>>` is
|
||||
//! an owned pointer to a pinned `T`, and a [`Pin`]`<`[`Rc`]`<T>>` is a reference-counted
|
||||
//! pointer to a pinned `T`.
|
||||
//! For correctness, [`Pin<P>`] relies on the implementations of [`Deref`] and
|
||||
//! [`DerefMut`] not to move out of their `self` parameter, and only ever to
|
||||
@ -48,15 +48,15 @@
|
||||
//!
|
||||
//! Many types are always freely movable, even when pinned, because they do not
|
||||
//! rely on having a stable address. This includes all the basic types (like
|
||||
//! `bool`, `i32`, and references) as well as types consisting solely of these
|
||||
//! [`bool`], [`i32`], and references) as well as types consisting solely of these
|
||||
//! types. Types that do not care about pinning implement the [`Unpin`]
|
||||
//! auto-trait, which cancels the effect of [`Pin<P>`]. For `T: Unpin`,
|
||||
//! `Pin<Box<T>>` and `Box<T>` function identically, as do `Pin<&mut T>` and
|
||||
//! [`Pin`]`<`[`Box`]`<T>>` and [`Box<T>`] function identically, as do [`Pin`]`<&mut T>` and
|
||||
//! `&mut T`.
|
||||
//!
|
||||
//! Note that pinning and `Unpin` only affect the pointed-to type `P::Target`, not the pointer
|
||||
//! type `P` itself that got wrapped in `Pin<P>`. For example, whether or not `Box<T>` is
|
||||
//! `Unpin` has no effect on the behavior of `Pin<Box<T>>` (here, `T` is the
|
||||
//! Note that pinning and [`Unpin`] only affect the pointed-to type `P::Target`, not the pointer
|
||||
//! type `P` itself that got wrapped in [`Pin<P>`]. For example, whether or not [`Box<T>`] is
|
||||
//! [`Unpin`] has no effect on the behavior of [`Pin`]`<`[`Box`]`<T>>` (here, `T` is the
|
||||
//! pointed-to type).
|
||||
//!
|
||||
//! # Example: self-referential struct
|
||||
@ -122,15 +122,15 @@
|
||||
//!
|
||||
//! To make this work, every element has pointers to its predecessor and successor in
|
||||
//! the list. Elements can only be added when they are pinned, because moving the elements
|
||||
//! around would invalidate the pointers. Moreover, the `Drop` implementation of a linked
|
||||
//! around would invalidate the pointers. Moreover, the [`Drop`] implementation of a linked
|
||||
//! list element will patch the pointers of its predecessor and successor to remove itself
|
||||
//! from the list.
|
||||
//!
|
||||
//! Crucially, we have to be able to rely on `drop` being called. If an element
|
||||
//! could be deallocated or otherwise invalidated without calling `drop`, the pointers into it
|
||||
//! Crucially, we have to be able to rely on [`drop`] being called. If an element
|
||||
//! could be deallocated or otherwise invalidated without calling [`drop`], the pointers into it
|
||||
//! from its neighbouring elements would become invalid, which would break the data structure.
|
||||
//!
|
||||
//! Therefore, pinning also comes with a `drop`-related guarantee.
|
||||
//! Therefore, pinning also comes with a [`drop`]-related guarantee.
|
||||
//!
|
||||
//! # `Drop` guarantee
|
||||
//!
|
||||
@ -139,7 +139,7 @@
|
||||
//! 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*. 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.
|
||||
@ -148,26 +148,27 @@
|
||||
//! section needs to function correctly.
|
||||
//!
|
||||
//! Notice that this guarantee does *not* mean that memory does not leak! It is still
|
||||
//! completely okay not ever to call `drop` on a pinned element (e.g., you can still
|
||||
//! call [`mem::forget`] on a `Pin<Box<T>>`). In the example of the doubly-linked
|
||||
//! completely okay not ever to call [`drop`] on a pinned element (e.g., you can still
|
||||
//! call [`mem::forget`] on a [`Pin`]`<`[`Box`]`<T>>`). In the example of the doubly-linked
|
||||
//! list, that element would just stay in the list. However you may not free or reuse the storage
|
||||
//! *without calling `drop`*.
|
||||
//! *without calling [`drop`]*.
|
||||
//!
|
||||
//! # `Drop` implementation
|
||||
//!
|
||||
//! If your type uses pinning (such as the two examples above), you have to be careful
|
||||
//! when implementing `Drop`. The `drop` function takes `&mut self`, but this
|
||||
//! when implementing [`Drop`]. The [`drop`] function takes `&mut self`, but this
|
||||
//! is called *even if your type was previously pinned*! It is as if the
|
||||
//! compiler automatically called `get_unchecked_mut`.
|
||||
//! compiler automatically called [`Pin::get_unchecked_mut`].
|
||||
//!
|
||||
//! This can never cause a problem in safe code because implementing a type that
|
||||
//! relies on pinning requires unsafe code, but be aware that deciding to make
|
||||
//! use of pinning in your type (for example by implementing some operation on
|
||||
//! `Pin<&Self>` or `Pin<&mut Self>`) has consequences for your `Drop`
|
||||
//! [`Pin`]`<&Self>` or [`Pin`]`<&mut Self>`) has consequences for your [`Drop`]
|
||||
//! implementation as well: if an element of your type could have been pinned,
|
||||
//! you must treat Drop as implicitly taking `Pin<&mut Self>`.
|
||||
//! you must treat [`Drop`] as implicitly taking [`Pin`]`<&mut Self>`.
|
||||
//!
|
||||
//! For example, you could implement `Drop` as follows:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # use std::pin::Pin;
|
||||
//! # struct Type { }
|
||||
@ -182,7 +183,8 @@
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//! The function `inner_drop` has the type that `drop` *should* have, so this makes sure that
|
||||
//!
|
||||
//! The function `inner_drop` has the type that [`drop`] *should* have, so this makes sure that
|
||||
//! you do not accidentally use `self`/`this` in a way that is in conflict with pinning.
|
||||
//!
|
||||
//! Moreover, if your type is `#[repr(packed)]`, the compiler will automatically
|
||||
@ -192,10 +194,10 @@
|
||||
//! # Projections and Structural Pinning
|
||||
//!
|
||||
//! When working with pinned structs, the question arises how one can access the
|
||||
//! fields of that struct in a method that takes just `Pin<&mut Struct>`.
|
||||
//! fields of that struct in a method that takes just [`Pin`]`<&mut Struct>`.
|
||||
//! The usual approach is to write helper methods (so called *projections*)
|
||||
//! that turn `Pin<&mut Struct>` into a reference to the field, but what
|
||||
//! type should that reference have? Is it `Pin<&mut Field>` or `&mut Field`?
|
||||
//! that turn [`Pin`]`<&mut Struct>` into a reference to the field, but what
|
||||
//! type should that reference have? Is it [`Pin`]`<&mut Field>` or `&mut Field`?
|
||||
//! The same question arises with the fields of an `enum`, and also when considering
|
||||
//! container/wrapper types such as [`Vec<T>`], [`Box<T>`], or [`RefCell<T>`].
|
||||
//! (This question applies to both mutable and shared references, we just
|
||||
@ -203,7 +205,7 @@
|
||||
//!
|
||||
//! It turns out that it is actually up to the author of the data structure
|
||||
//! to decide whether the pinned projection for a particular field turns
|
||||
//! `Pin<&mut Struct>` into `Pin<&mut Field>` or `&mut Field`. There are some
|
||||
//! [`Pin`]`<&mut Struct>` into [`Pin`]`<&mut Field>` or `&mut Field`. There are some
|
||||
//! constraints though, and the most important constraint is *consistency*:
|
||||
//! every field can be *either* projected to a pinned reference, *or* have
|
||||
//! pinning removed as part of the projection. If both are done for the same field,
|
||||
@ -218,12 +220,13 @@
|
||||
//! ## Pinning *is not* structural for `field`
|
||||
//!
|
||||
//! It may seem counter-intuitive that the field of a pinned struct might not be pinned,
|
||||
//! but that is actually the easiest choice: if a `Pin<&mut Field>` is never created,
|
||||
//! but that is actually the easiest choice: if a [`Pin`]`<&mut Field>` is never created,
|
||||
//! nothing can go wrong! So, if you decide that some field does not have structural pinning,
|
||||
//! all you have to ensure is that you never create a pinned reference to that field.
|
||||
//!
|
||||
//! Fields without structural pinning may have a projection method that turns
|
||||
//! `Pin<&mut Struct>` into `&mut Field`:
|
||||
//! [`Pin`]`<&mut Struct>` into `&mut Field`:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # use std::pin::Pin;
|
||||
//! # type Field = i32;
|
||||
@ -237,16 +240,17 @@
|
||||
//! ```
|
||||
//!
|
||||
//! You may also `impl Unpin for Struct` *even if* the type of `field`
|
||||
//! is not `Unpin`. What that type thinks about pinning is not relevant
|
||||
//! when no `Pin<&mut Field>` is ever created.
|
||||
//! is not [`Unpin`]. What that type thinks about pinning is not relevant
|
||||
//! when no [`Pin`]`<&mut Field>` is ever created.
|
||||
//!
|
||||
//! ## Pinning *is* structural for `field`
|
||||
//!
|
||||
//! The other option is to decide that pinning is "structural" for `field`,
|
||||
//! meaning that if the struct is pinned then so is the field.
|
||||
//!
|
||||
//! This allows writing a projection that creates a `Pin<&mut Field>`, thus
|
||||
//! This allows writing a projection that creates a [`Pin`]`<&mut Field>`, thus
|
||||
//! witnessing that the field is pinned:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # use std::pin::Pin;
|
||||
//! # type Field = i32;
|
||||
@ -262,30 +266,30 @@
|
||||
//! However, structural pinning comes with a few extra requirements:
|
||||
//!
|
||||
//! 1. The struct must only be [`Unpin`] if all the structural fields are
|
||||
//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
|
||||
//! [`Unpin`]. This is the default, but [`Unpin`] is a safe trait, so as the author of
|
||||
//! the struct it is your responsibility *not* to add something like
|
||||
//! `impl<T> Unpin for Struct<T>`. (Notice that adding a projection operation
|
||||
//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break
|
||||
//! requires unsafe code, so the fact that [`Unpin`] is a safe trait does not break
|
||||
//! the principle that you only have to worry about any of this if you use `unsafe`.)
|
||||
//! 2. The destructor of the struct must not move structural fields out of its argument. This
|
||||
//! is the exact point that was raised in the [previous section][drop-impl]: `drop` takes
|
||||
//! `&mut self`, but the struct (and hence its fields) might have been pinned before.
|
||||
//! You have to guarantee that you do not move a field inside your `Drop` implementation.
|
||||
//! You have to guarantee that you do not move a field inside your [`Drop`] implementation.
|
||||
//! In particular, as explained previously, this means that your struct must *not*
|
||||
//! be `#[repr(packed)]`.
|
||||
//! See that section for how to write `drop` in a way that the compiler can help you
|
||||
//! See that section for how to write [`drop`] in a way that the compiler can help you
|
||||
//! not accidentally break pinning.
|
||||
//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]:
|
||||
//! once your struct is pinned, the memory that contains the
|
||||
//! content is not overwritten or deallocated without calling the content's destructors.
|
||||
//! This can be tricky, as witnessed by [`VecDeque<T>`]: the destructor of `VecDeque<T>`
|
||||
//! can fail to call `drop` on all elements if one of the destructors panics. This violates the
|
||||
//! `Drop` guarantee, because it can lead to elements being deallocated without
|
||||
//! their destructor being called. (`VecDeque` has no pinning projections, so this
|
||||
//! This can be tricky, as witnessed by [`VecDeque<T>`]: the destructor of [`VecDeque<T>`]
|
||||
//! can fail to call [`drop`] on all elements if one of the destructors panics. This violates
|
||||
//! the [`Drop`] guarantee, because it can lead to elements being deallocated without
|
||||
//! their destructor being called. ([`VecDeque<T>`] has no pinning projections, so this
|
||||
//! does not cause unsoundness.)
|
||||
//! 4. You must not offer any other operations that could lead to data being moved out of
|
||||
//! the structural fields when your type is pinned. For example, if the struct contains an
|
||||
//! `Option<T>` and there is a `take`-like operation with type
|
||||
//! [`Option<T>`] and there is a `take`-like operation with type
|
||||
//! `fn(Pin<&mut Struct<T>>) -> Option<T>`,
|
||||
//! that operation can be used to move a `T` out of a pinned `Struct<T>` -- which means
|
||||
//! pinning cannot be structural for the field holding this data.
|
||||
@ -301,37 +305,39 @@
|
||||
//! let content = &mut *b; // And here we have `&mut T` to the same data.
|
||||
//! }
|
||||
//! ```
|
||||
//! This is catastrophic, it means we can first pin the content of the `RefCell<T>`
|
||||
//! This is catastrophic, it means we can first pin the content of the [`RefCell<T>`]
|
||||
//! (using `RefCell::get_pin_mut`) and then move that content using the mutable
|
||||
//! reference we got later.
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! For a type like [`Vec<T>`], both possibilites (structural pinning or not) make sense.
|
||||
//! A `Vec<T>` with structural pinning could have `get_pin`/`get_pin_mut` methods to get
|
||||
//! A [`Vec<T>`] with structural pinning could have `get_pin`/`get_pin_mut` methods to get
|
||||
//! pinned references to elements. However, it could *not* allow calling
|
||||
//! `pop` on a pinned `Vec<T>` because that would move the (structurally pinned) contents!
|
||||
//! Nor could it allow `push`, which might reallocate and thus also move the contents.
|
||||
//! A `Vec<T>` without structural pinning could `impl<T> Unpin for Vec<T>`, because the contents
|
||||
//! are never pinned and the `Vec<T>` itself is fine with being moved as well.
|
||||
//! [`pop`][Vec::pop] on a pinned [`Vec<T>`] because that would move the (structurally pinned)
|
||||
//! contents! Nor could it allow [`push`][Vec::push], which might reallocate and thus also move the
|
||||
//! contents.
|
||||
//!
|
||||
//! A [`Vec<T>`] without structural pinning could `impl<T> Unpin for Vec<T>`, because the contents
|
||||
//! are never pinned and the [`Vec<T>`] itself is fine with being moved as well.
|
||||
//! At that point pinning just has no effect on the vector at all.
|
||||
//!
|
||||
//! In the standard library, pointer types generally do not have structural pinning,
|
||||
//! and thus they do not offer pinning projections. This is why `Box<T>: Unpin` holds for all `T`.
|
||||
//! It makes sense to do this for pointer types, because moving the `Box<T>`
|
||||
//! does not actually move the `T`: the `Box<T>` can be freely movable (aka `Unpin`) even if the `T`
|
||||
//! is not. In fact, even `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves,
|
||||
//! for the same reason: their contents (the `T`) are pinned, but the pointers themselves
|
||||
//! can be moved without moving the pinned data. For both `Box<T>` and `Pin<Box<T>>`,
|
||||
//! whether the content is pinned is entirely independent of whether the pointer is
|
||||
//! pinned, meaning pinning is *not* structural.
|
||||
//! does not actually move the `T`: the [`Box<T>`] can be freely movable (aka `Unpin`) even if
|
||||
//! the `T` is not. In fact, even [`Pin`]`<`[`Box`]`<T>>` and [`Pin`]`<&mut T>` are always
|
||||
//! [`Unpin`] themselves, for the same reason: their contents (the `T`) are pinned, but the
|
||||
//! pointers themselves can be moved without moving the pinned data. For both [`Box<T>`] and
|
||||
//! [`Pin`]`<`[`Box`]`<T>>`, whether the content is pinned is entirely independent of whether the
|
||||
//! pointer is pinned, meaning pinning is *not* structural.
|
||||
//!
|
||||
//! When implementing a [`Future`] combinator, you will usually need structural pinning
|
||||
//! for the nested futures, as you need to get pinned references to them to call `poll`.
|
||||
//! for the nested futures, as you need to get pinned references to them to call [`poll`].
|
||||
//! But if your combinator contains any other data that does not need to be pinned,
|
||||
//! you can make those fields not structural and hence freely access them with a
|
||||
//! mutable reference even when you just have `Pin<&mut Self>` (such as in your own
|
||||
//! `poll` implementation).
|
||||
//! mutable reference even when you just have [`Pin`]`<&mut Self>` (such as in your own
|
||||
//! [`poll`] implementation).
|
||||
//!
|
||||
//! [`Pin<P>`]: struct.Pin.html
|
||||
//! [`Unpin`]: ../marker/trait.Unpin.html
|
||||
@ -342,6 +348,16 @@
|
||||
//! [`Box<T>`]: ../../std/boxed/struct.Box.html
|
||||
//! [`Vec<T>`]: ../../std/vec/struct.Vec.html
|
||||
//! [`Vec::set_len`]: ../../std/vec/struct.Vec.html#method.set_len
|
||||
//! [`Pin`]: struct.Pin.html
|
||||
//! [`Box`]: ../../std/boxed/struct.Box.html
|
||||
//! [Vec::pop]: ../../std/vec/struct.Vec.html#method.pop
|
||||
//! [Vec::push]: ../../std/vec/struct.Vec.html#method.push
|
||||
//! [`Rc`]: ../../std/rc/struct.Rc.html
|
||||
//! [`RefCell<T>`]: ../../std/cell/struct.RefCell.html
|
||||
//! [`Drop`]: ../../std/ops/trait.Drop.html
|
||||
//! [`drop`]: ../../std/ops/trait.Drop.html#tymethod.drop
|
||||
//! [`VecDeque<T>`]: ../../std/collections/struct.VecDeque.html
|
||||
//! [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
//! [`VecDeque<T>`]: ../../std/collections/struct.VecDeque.html
|
||||
//! [`RefCell<T>`]: ../cell/struct.RefCell.html
|
||||
//! [`None`]: ../option/enum.Option.html#variant.None
|
||||
@ -350,6 +366,8 @@
|
||||
//! [`Future`]: ../future/trait.Future.html
|
||||
//! [drop-impl]: #drop-implementation
|
||||
//! [drop-guarantee]: #drop-guarantee
|
||||
//! [`poll`]: ../../std/future/trait.Future.html#tymethod.poll
|
||||
//! [`Pin::get_unchecked_mut`]: struct.Pin.html#method.get_unchecked_mut
|
||||
|
||||
#![stable(feature = "pin", since = "1.33.0")]
|
||||
|
||||
|
@ -232,7 +232,7 @@
|
||||
|
||||
use crate::fmt;
|
||||
use crate::iter::{FromIterator, FusedIterator, TrustedLen};
|
||||
use crate::ops::{self, Deref};
|
||||
use crate::ops::{self, Deref, DerefMut};
|
||||
|
||||
/// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
|
||||
///
|
||||
@ -981,24 +981,22 @@ impl<T: Default, E> Result<T, E> {
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
impl<T: Deref, E> Result<T, E> {
|
||||
/// Converts from `&Result<T, E>` to `Result<&T::Target, &E>`.
|
||||
/// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T::Target, &E>`.
|
||||
///
|
||||
/// Leaves the original Result in-place, creating a new one with a reference
|
||||
/// to the original one, additionally coercing the `Ok` arm of the Result via
|
||||
/// `Deref`.
|
||||
pub fn deref_ok(&self) -> Result<&T::Target, &E> {
|
||||
/// Leaves the original `Result` in-place, creating a new one containing a reference to the
|
||||
/// `Ok` type's `Deref::Target` type.
|
||||
pub fn as_deref_ok(&self) -> Result<&T::Target, &E> {
|
||||
self.as_ref().map(|t| t.deref())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
impl<T, E: Deref> Result<T, E> {
|
||||
/// Converts from `&Result<T, E>` to `Result<&T, &E::Target>`.
|
||||
/// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T, &E::Target>`.
|
||||
///
|
||||
/// Leaves the original Result in-place, creating a new one with a reference
|
||||
/// to the original one, additionally coercing the `Err` arm of the Result via
|
||||
/// `Deref`.
|
||||
pub fn deref_err(&self) -> Result<&T, &E::Target>
|
||||
/// Leaves the original `Result` in-place, creating a new one containing a reference to the
|
||||
/// `Err` type's `Deref::Target` type.
|
||||
pub fn as_deref_err(&self) -> Result<&T, &E::Target>
|
||||
{
|
||||
self.as_ref().map_err(|e| e.deref())
|
||||
}
|
||||
@ -1006,17 +1004,52 @@ impl<T, E: Deref> Result<T, E> {
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
impl<T: Deref, E: Deref> Result<T, E> {
|
||||
/// Converts from `&Result<T, E>` to `Result<&T::Target, &E::Target>`.
|
||||
/// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T::Target, &E::Target>`.
|
||||
///
|
||||
/// Leaves the original Result in-place, creating a new one with a reference
|
||||
/// to the original one, additionally coercing both the `Ok` and `Err` arms
|
||||
/// of the Result via `Deref`.
|
||||
pub fn deref(&self) -> Result<&T::Target, &E::Target>
|
||||
/// Leaves the original `Result` in-place, creating a new one containing a reference to both
|
||||
/// the `Ok` and `Err` types' `Deref::Target` types.
|
||||
pub fn as_deref(&self) -> Result<&T::Target, &E::Target>
|
||||
{
|
||||
self.as_ref().map(|t| t.deref()).map_err(|e| e.deref())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
impl<T: DerefMut, E> Result<T, E> {
|
||||
/// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T::Target, &mut E>`.
|
||||
///
|
||||
/// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
|
||||
/// the `Ok` type's `Deref::Target` type.
|
||||
pub fn as_deref_mut_ok(&mut self) -> Result<&mut T::Target, &mut E> {
|
||||
self.as_mut().map(|t| t.deref_mut())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
impl<T, E: DerefMut> Result<T, E> {
|
||||
/// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T, &mut E::Target>`.
|
||||
///
|
||||
/// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
|
||||
/// the `Err` type's `Deref::Target` type.
|
||||
pub fn as_deref_mut_err(&mut self) -> Result<&mut T, &mut E::Target>
|
||||
{
|
||||
self.as_mut().map_err(|e| e.deref_mut())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")]
|
||||
impl<T: DerefMut, E: DerefMut> Result<T, E> {
|
||||
/// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to
|
||||
/// `Result<&mut T::Target, &mut E::Target>`.
|
||||
///
|
||||
/// Leaves the original `Result` in-place, creating a new one containing a mutable reference to
|
||||
/// both the `Ok` and `Err` types' `Deref::Target` types.
|
||||
pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E::Target>
|
||||
{
|
||||
self.as_mut().map(|t| t.deref_mut()).map_err(|e| e.deref_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Result<Option<T>, E> {
|
||||
/// Transposes a `Result` of an `Option` into an `Option` of a `Result`.
|
||||
///
|
||||
|
@ -1,6 +1,8 @@
|
||||
use core::option::*;
|
||||
use core::mem;
|
||||
use core::clone::Clone;
|
||||
use core::array::FixedSizeArray;
|
||||
use core::ops::DerefMut;
|
||||
|
||||
#[test]
|
||||
fn test_get_ptr() {
|
||||
@ -310,20 +312,38 @@ fn test_try() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_option_deref() {
|
||||
fn test_option_as_deref() {
|
||||
// Some: &Option<T: Deref>::Some(T) -> Option<&T::Deref::Target>::Some(&*T)
|
||||
let ref_option = &Some(&42);
|
||||
assert_eq!(ref_option.deref(), Some(&42));
|
||||
assert_eq!(ref_option.as_deref(), Some(&42));
|
||||
|
||||
let ref_option = &Some(String::from("a result"));
|
||||
assert_eq!(ref_option.deref(), Some("a result"));
|
||||
assert_eq!(ref_option.as_deref(), Some("a result"));
|
||||
|
||||
let ref_option = &Some(vec![1, 2, 3, 4, 5]);
|
||||
assert_eq!(ref_option.deref(), Some(&[1, 2, 3, 4, 5][..]));
|
||||
assert_eq!(ref_option.as_deref(), Some([1, 2, 3, 4, 5].as_slice()));
|
||||
|
||||
// None: &Option<T: Deref>>::None -> None
|
||||
let ref_option: &Option<&i32> = &None;
|
||||
assert_eq!(ref_option.deref(), None);
|
||||
assert_eq!(ref_option.as_deref(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_option_as_deref_mut() {
|
||||
// Some: &mut Option<T: Deref>::Some(T) -> Option<&mut T::Deref::Target>::Some(&mut *T)
|
||||
let mut val = 42;
|
||||
let ref_option = &mut Some(&mut val);
|
||||
assert_eq!(ref_option.as_deref_mut(), Some(&mut 42));
|
||||
|
||||
let ref_option = &mut Some(String::from("a result"));
|
||||
assert_eq!(ref_option.as_deref_mut(), Some(String::from("a result").deref_mut()));
|
||||
|
||||
let ref_option = &mut Some(vec![1, 2, 3, 4, 5]);
|
||||
assert_eq!(ref_option.as_deref_mut(), Some([1, 2, 3, 4, 5].as_mut_slice()));
|
||||
|
||||
// None: &mut Option<T: Deref>>::None -> None
|
||||
let ref_option: &mut Option<&mut i32> = &mut None;
|
||||
assert_eq!(ref_option.as_deref_mut(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,4 +1,6 @@
|
||||
use core::option::*;
|
||||
use core::array::FixedSizeArray;
|
||||
use core::ops::DerefMut;
|
||||
|
||||
fn op1() -> Result<isize, &'static str> { Ok(666) }
|
||||
fn op2() -> Result<isize, &'static str> { Err("sadface") }
|
||||
@ -225,94 +227,213 @@ fn test_try() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_result_deref() {
|
||||
// &Result<T: Deref, E>::Ok(T).deref_ok() ->
|
||||
fn test_result_as_deref() {
|
||||
// &Result<T: Deref, E>::Ok(T).as_deref_ok() ->
|
||||
// Result<&T::Deref::Target, &E>::Ok(&*T)
|
||||
let ref_ok = &Result::Ok::<&i32, u8>(&42);
|
||||
let expected_result = Result::Ok::<&i32, &u8>(&42);
|
||||
assert_eq!(ref_ok.deref_ok(), expected_result);
|
||||
assert_eq!(ref_ok.as_deref_ok(), expected_result);
|
||||
|
||||
let ref_ok = &Result::Ok::<String, u32>(String::from("a result"));
|
||||
let expected_result = Result::Ok::<&str, &u32>("a result");
|
||||
assert_eq!(ref_ok.deref_ok(), expected_result);
|
||||
assert_eq!(ref_ok.as_deref_ok(), expected_result);
|
||||
|
||||
let ref_ok = &Result::Ok::<Vec<i32>, u32>(vec![1, 2, 3, 4, 5]);
|
||||
let expected_result = Result::Ok::<&[i32], &u32>(&[1, 2, 3, 4, 5][..]);
|
||||
assert_eq!(ref_ok.deref_ok(), expected_result);
|
||||
let expected_result = Result::Ok::<&[i32], &u32>([1, 2, 3, 4, 5].as_slice());
|
||||
assert_eq!(ref_ok.as_deref_ok(), expected_result);
|
||||
|
||||
// &Result<T: Deref, E: Deref>::Ok(T).deref() ->
|
||||
// &Result<T: Deref, E: Deref>::Ok(T).as_deref() ->
|
||||
// Result<&T::Deref::Target, &E::Deref::Target>::Ok(&*T)
|
||||
let ref_ok = &Result::Ok::<&i32, &u8>(&42);
|
||||
let expected_result = Result::Ok::<&i32, &u8>(&42);
|
||||
assert_eq!(ref_ok.deref(), expected_result);
|
||||
assert_eq!(ref_ok.as_deref(), expected_result);
|
||||
|
||||
let ref_ok = &Result::Ok::<String, &u32>(String::from("a result"));
|
||||
let expected_result = Result::Ok::<&str, &u32>("a result");
|
||||
assert_eq!(ref_ok.deref(), expected_result);
|
||||
assert_eq!(ref_ok.as_deref(), expected_result);
|
||||
|
||||
let ref_ok = &Result::Ok::<Vec<i32>, &u32>(vec![1, 2, 3, 4, 5]);
|
||||
let expected_result = Result::Ok::<&[i32], &u32>(&[1, 2, 3, 4, 5][..]);
|
||||
assert_eq!(ref_ok.deref(), expected_result);
|
||||
let expected_result = Result::Ok::<&[i32], &u32>([1, 2, 3, 4, 5].as_slice());
|
||||
assert_eq!(ref_ok.as_deref(), expected_result);
|
||||
|
||||
// &Result<T, E: Deref>::Err(T).deref_err() ->
|
||||
// &Result<T, E: Deref>::Err(T).as_deref_err() ->
|
||||
// Result<&T, &E::Deref::Target>::Err(&*E)
|
||||
let ref_err = &Result::Err::<u8, &i32>(&41);
|
||||
let expected_result = Result::Err::<&u8, &i32>(&41);
|
||||
assert_eq!(ref_err.deref_err(), expected_result);
|
||||
assert_eq!(ref_err.as_deref_err(), expected_result);
|
||||
|
||||
let ref_err = &Result::Err::<u32, String>(String::from("an error"));
|
||||
let expected_result = Result::Err::<&u32, &str>("an error");
|
||||
assert_eq!(ref_err.deref_err(), expected_result);
|
||||
assert_eq!(ref_err.as_deref_err(), expected_result);
|
||||
|
||||
let ref_err = &Result::Err::<u32, Vec<i32>>(vec![5, 4, 3, 2, 1]);
|
||||
let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]);
|
||||
assert_eq!(ref_err.deref_err(), expected_result);
|
||||
let expected_result = Result::Err::<&u32, &[i32]>([5, 4, 3, 2, 1].as_slice());
|
||||
assert_eq!(ref_err.as_deref_err(), expected_result);
|
||||
|
||||
// &Result<T: Deref, E: Deref>::Err(T).deref_err() ->
|
||||
// &Result<T: Deref, E: Deref>::Err(T).as_deref_err() ->
|
||||
// Result<&T, &E::Deref::Target>::Err(&*E)
|
||||
let ref_err = &Result::Err::<&u8, &i32>(&41);
|
||||
let expected_result = Result::Err::<&u8, &i32>(&41);
|
||||
assert_eq!(ref_err.deref(), expected_result);
|
||||
assert_eq!(ref_err.as_deref(), expected_result);
|
||||
|
||||
let ref_err = &Result::Err::<&u32, String>(String::from("an error"));
|
||||
let expected_result = Result::Err::<&u32, &str>("an error");
|
||||
assert_eq!(ref_err.deref(), expected_result);
|
||||
assert_eq!(ref_err.as_deref(), expected_result);
|
||||
|
||||
let ref_err = &Result::Err::<&u32, Vec<i32>>(vec![5, 4, 3, 2, 1]);
|
||||
let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]);
|
||||
assert_eq!(ref_err.deref(), expected_result);
|
||||
let expected_result = Result::Err::<&u32, &[i32]>([5, 4, 3, 2, 1].as_slice());
|
||||
assert_eq!(ref_err.as_deref(), expected_result);
|
||||
|
||||
// The following cases test calling deref_* with the wrong variant (i.e.
|
||||
// `deref_ok()` with a `Result::Err()`, or `deref_err()` with a `Result::Ok()`.
|
||||
// While unusual, these cases are supported to ensure that an `inner_deref`
|
||||
// The following cases test calling `as_deref_*` with the wrong variant (i.e.
|
||||
// `as_deref_ok()` with a `Result::Err()`, or `as_deref_err()` with a `Result::Ok()`.
|
||||
// While uncommon, these cases are supported to ensure that an `as_deref_*`
|
||||
// call can still be made even when one of the Result types does not implement
|
||||
// `Deref` (for example, std::io::Error).
|
||||
|
||||
// &Result<T, E: Deref>::Ok(T).deref_err() ->
|
||||
// &Result<T, E: Deref>::Ok(T).as_deref_err() ->
|
||||
// Result<&T, &E::Deref::Target>::Ok(&T)
|
||||
let ref_ok = &Result::Ok::<i32, &u8>(42);
|
||||
let expected_result = Result::Ok::<&i32, &u8>(&42);
|
||||
assert_eq!(ref_ok.deref_err(), expected_result);
|
||||
assert_eq!(ref_ok.as_deref_err(), expected_result);
|
||||
|
||||
let ref_ok = &Result::Ok::<&str, &u32>("a result");
|
||||
let expected_result = Result::Ok::<&&str, &u32>(&"a result");
|
||||
assert_eq!(ref_ok.deref_err(), expected_result);
|
||||
assert_eq!(ref_ok.as_deref_err(), expected_result);
|
||||
|
||||
let ref_ok = &Result::Ok::<[i32; 5], &u32>([1, 2, 3, 4, 5]);
|
||||
let expected_result = Result::Ok::<&[i32; 5], &u32>(&[1, 2, 3, 4, 5]);
|
||||
assert_eq!(ref_ok.deref_err(), expected_result);
|
||||
assert_eq!(ref_ok.as_deref_err(), expected_result);
|
||||
|
||||
// &Result<T: Deref, E>::Err(E).deref_ok() ->
|
||||
// &Result<T: Deref, E>::Err(E).as_deref_ok() ->
|
||||
// Result<&T::Deref::Target, &E>::Err(&E)
|
||||
let ref_err = &Result::Err::<&u8, i32>(41);
|
||||
let expected_result = Result::Err::<&u8, &i32>(&41);
|
||||
assert_eq!(ref_err.deref_ok(), expected_result);
|
||||
assert_eq!(ref_err.as_deref_ok(), expected_result);
|
||||
|
||||
let ref_err = &Result::Err::<&u32, &str>("an error");
|
||||
let expected_result = Result::Err::<&u32, &&str>(&"an error");
|
||||
assert_eq!(ref_err.deref_ok(), expected_result);
|
||||
assert_eq!(ref_err.as_deref_ok(), expected_result);
|
||||
|
||||
let ref_err = &Result::Err::<&u32, [i32; 5]>([5, 4, 3, 2, 1]);
|
||||
let expected_result = Result::Err::<&u32, &[i32; 5]>(&[5, 4, 3, 2, 1]);
|
||||
assert_eq!(ref_err.deref_ok(), expected_result);
|
||||
assert_eq!(ref_err.as_deref_ok(), expected_result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_result_as_deref_mut() {
|
||||
// &mut Result<T: Deref, E>::Ok(T).as_deref_mut_ok() ->
|
||||
// Result<&mut T::Deref::Target, &mut E>::Ok(&mut *T)
|
||||
let mut val = 42;
|
||||
let mut expected_val = 42;
|
||||
let mut_ok = &mut Result::Ok::<&mut i32, u8>(&mut val);
|
||||
let expected_result = Result::Ok::<&mut i32, &mut u8>(&mut expected_val);
|
||||
assert_eq!(mut_ok.as_deref_mut_ok(), expected_result);
|
||||
|
||||
let mut expected_string = String::from("a result");
|
||||
let mut_ok = &mut Result::Ok::<String, u32>(expected_string.clone());
|
||||
let expected_result = Result::Ok::<&mut str, &mut u32>(expected_string.deref_mut());
|
||||
assert_eq!(mut_ok.as_deref_mut_ok(), expected_result);
|
||||
|
||||
let mut expected_vec = vec![1, 2, 3, 4, 5];
|
||||
let mut_ok = &mut Result::Ok::<Vec<i32>, u32>(expected_vec.clone());
|
||||
let expected_result = Result::Ok::<&mut [i32], &mut u32>(expected_vec.as_mut_slice());
|
||||
assert_eq!(mut_ok.as_deref_mut_ok(), expected_result);
|
||||
|
||||
// &mut Result<T: Deref, E: Deref>::Ok(T).as_deref_mut() ->
|
||||
// Result<&mut T::Deref::Target, &mut E::Deref::Target>::Ok(&mut *T)
|
||||
let mut val = 42;
|
||||
let mut expected_val = 42;
|
||||
let mut_ok = &mut Result::Ok::<&mut i32, &mut u8>(&mut val);
|
||||
let expected_result = Result::Ok::<&mut i32, &mut u8>(&mut expected_val);
|
||||
assert_eq!(mut_ok.as_deref_mut(), expected_result);
|
||||
|
||||
let mut expected_string = String::from("a result");
|
||||
let mut_ok = &mut Result::Ok::<String, &mut u32>(expected_string.clone());
|
||||
let expected_result = Result::Ok::<&mut str, &mut u32>(expected_string.deref_mut());
|
||||
assert_eq!(mut_ok.as_deref_mut(), expected_result);
|
||||
|
||||
let mut expected_vec = vec![1, 2, 3, 4, 5];
|
||||
let mut_ok = &mut Result::Ok::<Vec<i32>, &mut u32>(expected_vec.clone());
|
||||
let expected_result = Result::Ok::<&mut [i32], &mut u32>(expected_vec.as_mut_slice());
|
||||
assert_eq!(mut_ok.as_deref_mut(), expected_result);
|
||||
|
||||
// &mut Result<T, E: Deref>::Err(T).as_deref_mut_err() ->
|
||||
// Result<&mut T, &mut E::Deref::Target>::Err(&mut *E)
|
||||
let mut val = 41;
|
||||
let mut expected_val = 41;
|
||||
let mut_err = &mut Result::Err::<u8, &mut i32>(&mut val);
|
||||
let expected_result = Result::Err::<&mut u8, &mut i32>(&mut expected_val);
|
||||
assert_eq!(mut_err.as_deref_mut_err(), expected_result);
|
||||
|
||||
let mut expected_string = String::from("an error");
|
||||
let mut_err = &mut Result::Err::<u32, String>(expected_string.clone());
|
||||
let expected_result = Result::Err::<&mut u32, &mut str>(expected_string.deref_mut());
|
||||
assert_eq!(mut_err.as_deref_mut_err(), expected_result);
|
||||
|
||||
let mut expected_vec = vec![5, 4, 3, 2, 1];
|
||||
let mut_err = &mut Result::Err::<u32, Vec<i32>>(expected_vec.clone());
|
||||
let expected_result = Result::Err::<&mut u32, &mut [i32]>(expected_vec.as_mut_slice());
|
||||
assert_eq!(mut_err.as_deref_mut_err(), expected_result);
|
||||
|
||||
// &mut Result<T: Deref, E: Deref>::Err(T).as_deref_mut_err() ->
|
||||
// Result<&mut T, &mut E::Deref::Target>::Err(&mut *E)
|
||||
let mut val = 41;
|
||||
let mut expected_val = 41;
|
||||
let mut_err = &mut Result::Err::<&mut u8, &mut i32>(&mut val);
|
||||
let expected_result = Result::Err::<&mut u8, &mut i32>(&mut expected_val);
|
||||
assert_eq!(mut_err.as_deref_mut(), expected_result);
|
||||
|
||||
let mut expected_string = String::from("an error");
|
||||
let mut_err = &mut Result::Err::<&mut u32, String>(expected_string.clone());
|
||||
let expected_result = Result::Err::<&mut u32, &mut str>(expected_string.as_mut_str());
|
||||
assert_eq!(mut_err.as_deref_mut(), expected_result);
|
||||
|
||||
let mut expected_vec = vec![5, 4, 3, 2, 1];
|
||||
let mut_err = &mut Result::Err::<&mut u32, Vec<i32>>(expected_vec.clone());
|
||||
let expected_result = Result::Err::<&mut u32, &mut [i32]>(expected_vec.as_mut_slice());
|
||||
assert_eq!(mut_err.as_deref_mut(), expected_result);
|
||||
|
||||
// The following cases test calling `as_deref_mut_*` with the wrong variant (i.e.
|
||||
// `as_deref_mut_ok()` with a `Result::Err()`, or `as_deref_mut_err()` with a `Result::Ok()`.
|
||||
// While uncommon, these cases are supported to ensure that an `as_deref_mut_*`
|
||||
// call can still be made even when one of the Result types does not implement
|
||||
// `Deref` (for example, std::io::Error).
|
||||
|
||||
// &mut Result<T, E: Deref>::Ok(T).as_deref_mut_err() ->
|
||||
// Result<&mut T, &mut E::Deref::Target>::Ok(&mut T)
|
||||
let mut expected_val = 42;
|
||||
let mut_ok = &mut Result::Ok::<i32, &mut u8>(expected_val.clone());
|
||||
let expected_result = Result::Ok::<&mut i32, &mut u8>(&mut expected_val);
|
||||
assert_eq!(mut_ok.as_deref_mut_err(), expected_result);
|
||||
|
||||
let string = String::from("a result");
|
||||
let expected_string = string.clone();
|
||||
let mut ref_str = expected_string.as_ref();
|
||||
let mut_ok = &mut Result::Ok::<&str, &mut u32>(string.as_str());
|
||||
let expected_result = Result::Ok::<&mut &str, &mut u32>(&mut ref_str);
|
||||
assert_eq!(mut_ok.as_deref_mut_err(), expected_result);
|
||||
|
||||
let mut expected_arr = [1, 2, 3, 4, 5];
|
||||
let mut_ok = &mut Result::Ok::<[i32; 5], &mut u32>(expected_arr.clone());
|
||||
let expected_result = Result::Ok::<&mut [i32; 5], &mut u32>(&mut expected_arr);
|
||||
assert_eq!(mut_ok.as_deref_mut_err(), expected_result);
|
||||
|
||||
// &mut Result<T: Deref, E>::Err(E).as_deref_mut_ok() ->
|
||||
// Result<&mut T::Deref::Target, &mut E>::Err(&mut E)
|
||||
let mut expected_val = 41;
|
||||
let mut_err = &mut Result::Err::<&mut u8, i32>(expected_val.clone());
|
||||
let expected_result = Result::Err::<&mut u8, &mut i32>(&mut expected_val);
|
||||
assert_eq!(mut_err.as_deref_mut_ok(), expected_result);
|
||||
|
||||
let string = String::from("an error");
|
||||
let expected_string = string.clone();
|
||||
let mut ref_str = expected_string.as_ref();
|
||||
let mut_err = &mut Result::Err::<&mut u32, &str>(string.as_str());
|
||||
let expected_result = Result::Err::<&mut u32, &mut &str>(&mut ref_str);
|
||||
assert_eq!(mut_err.as_deref_mut_ok(), expected_result);
|
||||
|
||||
let mut expected_arr = [5, 4, 3, 2, 1];
|
||||
let mut_err = &mut Result::Err::<&mut u32, [i32; 5]>(expected_arr.clone());
|
||||
let expected_result = Result::Err::<&mut u32, &mut [i32; 5]>(&mut expected_arr);
|
||||
assert_eq!(mut_err.as_deref_mut_ok(), expected_result);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// NOTE: The following code was generated by "./unicode.py", do not edit directly
|
||||
|
||||
#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
|
||||
#![allow(missing_docs, non_upper_case_globals, non_snake_case, clippy::unreadable_literal)]
|
||||
|
||||
use crate::unicode::version::UnicodeVersion;
|
||||
use crate::unicode::bool_trie::{BoolTrie, SmallBoolTrie};
|
||||
|
@ -79,7 +79,7 @@ FETCH_URL_VERSION = "ftp://ftp.unicode.org/Public/{version}/ucd/{filename}"
|
||||
PREAMBLE = """\
|
||||
// NOTE: The following code was generated by "./unicode.py", do not edit directly
|
||||
|
||||
#![allow(missing_docs, non_upper_case_globals, non_snake_case)]
|
||||
#![allow(missing_docs, non_upper_case_globals, non_snake_case, clippy::unreadable_literal)]
|
||||
|
||||
use crate::unicode::version::UnicodeVersion;
|
||||
use crate::unicode::bool_trie::{{BoolTrie, SmallBoolTrie}};
|
||||
|
@ -941,7 +941,7 @@ impl<'a> State<'a> {
|
||||
self.maybe_print_comment(st.span.lo());
|
||||
match st.node {
|
||||
hir::StmtKind::Local(ref loc) => {
|
||||
self.print_local(loc.init.deref(), |this| this.print_local_decl(&loc));
|
||||
self.print_local(loc.init.as_deref(), |this| this.print_local_decl(&loc));
|
||||
}
|
||||
hir::StmtKind::Item(item) => {
|
||||
self.ann.nested(self, Nested::Item(item))
|
||||
|
@ -367,34 +367,6 @@ language_item_table! {
|
||||
|
||||
DebugTraitLangItem, "debug_trait", debug_trait, Target::Trait;
|
||||
|
||||
// A lang item for each of the 128-bit operators we can optionally lower.
|
||||
I128AddFnLangItem, "i128_add", i128_add_fn, Target::Fn;
|
||||
U128AddFnLangItem, "u128_add", u128_add_fn, Target::Fn;
|
||||
I128SubFnLangItem, "i128_sub", i128_sub_fn, Target::Fn;
|
||||
U128SubFnLangItem, "u128_sub", u128_sub_fn, Target::Fn;
|
||||
I128MulFnLangItem, "i128_mul", i128_mul_fn, Target::Fn;
|
||||
U128MulFnLangItem, "u128_mul", u128_mul_fn, Target::Fn;
|
||||
I128DivFnLangItem, "i128_div", i128_div_fn, Target::Fn;
|
||||
U128DivFnLangItem, "u128_div", u128_div_fn, Target::Fn;
|
||||
I128RemFnLangItem, "i128_rem", i128_rem_fn, Target::Fn;
|
||||
U128RemFnLangItem, "u128_rem", u128_rem_fn, Target::Fn;
|
||||
I128ShlFnLangItem, "i128_shl", i128_shl_fn, Target::Fn;
|
||||
U128ShlFnLangItem, "u128_shl", u128_shl_fn, Target::Fn;
|
||||
I128ShrFnLangItem, "i128_shr", i128_shr_fn, Target::Fn;
|
||||
U128ShrFnLangItem, "u128_shr", u128_shr_fn, Target::Fn;
|
||||
// And overflow versions for the operators that are checkable.
|
||||
// While MIR calls these Checked*, they return (T,bool), not Option<T>.
|
||||
I128AddoFnLangItem, "i128_addo", i128_addo_fn, Target::Fn;
|
||||
U128AddoFnLangItem, "u128_addo", u128_addo_fn, Target::Fn;
|
||||
I128SuboFnLangItem, "i128_subo", i128_subo_fn, Target::Fn;
|
||||
U128SuboFnLangItem, "u128_subo", u128_subo_fn, Target::Fn;
|
||||
I128MuloFnLangItem, "i128_mulo", i128_mulo_fn, Target::Fn;
|
||||
U128MuloFnLangItem, "u128_mulo", u128_mulo_fn, Target::Fn;
|
||||
I128ShloFnLangItem, "i128_shlo", i128_shlo_fn, Target::Fn;
|
||||
U128ShloFnLangItem, "u128_shlo", u128_shlo_fn, Target::Fn;
|
||||
I128ShroFnLangItem, "i128_shro", i128_shro_fn, Target::Fn;
|
||||
U128ShroFnLangItem, "u128_shro", u128_shro_fn, Target::Fn;
|
||||
|
||||
// Align offset for stride != 1, must not panic.
|
||||
AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn;
|
||||
|
||||
|
@ -1406,10 +1406,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
saturating_float_casts: bool = (false, parse_bool, [TRACKED],
|
||||
"make float->int casts UB-free: numbers outside the integer type's range are clipped to \
|
||||
the max/min integer respectively, and NaN is mapped to 0"),
|
||||
lower_128bit_ops: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"rewrite operators on i128 and u128 into lang item calls (typically provided \
|
||||
by compiler-builtins) so codegen doesn't need to support them,
|
||||
overriding the default for the current target"),
|
||||
human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
|
||||
"generate human-readable, predictable names for codegen units"),
|
||||
dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
|
||||
|
@ -21,7 +21,7 @@ use crate::middle::cstore::EncodedMetadata;
|
||||
use crate::middle::lang_items;
|
||||
use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
|
||||
use crate::middle::stability;
|
||||
use crate::mir::{self, Body, interpret, ProjectionKind};
|
||||
use crate::mir::{Body, interpret, ProjectionKind};
|
||||
use crate::mir::interpret::{ConstValue, Allocation, Scalar};
|
||||
use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst};
|
||||
use crate::ty::ReprOptions;
|
||||
@ -1297,40 +1297,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self.get_lang_items(LOCAL_CRATE)
|
||||
}
|
||||
|
||||
/// Due to missing llvm support for lowering 128 bit math to software emulation
|
||||
/// (on some targets), the lowering can be done in MIR.
|
||||
///
|
||||
/// This function only exists until said support is implemented.
|
||||
pub fn is_binop_lang_item(&self, def_id: DefId) -> Option<(mir::BinOp, bool)> {
|
||||
let items = self.lang_items();
|
||||
let def_id = Some(def_id);
|
||||
if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
|
||||
else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
|
||||
else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
|
||||
else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
|
||||
else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
|
||||
else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
|
||||
else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
|
||||
else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
|
||||
else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
|
||||
else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
|
||||
else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
|
||||
else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
|
||||
else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
|
||||
else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
|
||||
else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
|
||||
else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
|
||||
else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
|
||||
else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
|
||||
else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
|
||||
else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
|
||||
else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
|
||||
else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
|
||||
else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
|
||||
else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
|
||||
else { None }
|
||||
}
|
||||
|
||||
pub fn stability(self) -> &'tcx stability::Index<'tcx> {
|
||||
self.stability_index(LOCAL_CRATE)
|
||||
}
|
||||
|
@ -246,6 +246,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
let align = a.value.align(dl).max(b_align).max(dl.aggregate_align);
|
||||
let b_offset = a.value.size(dl).align_to(b_align.abi);
|
||||
let size = (b_offset + b.value.size(dl)).align_to(align.abi);
|
||||
|
||||
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
|
||||
// returns the last maximum.
|
||||
let largest_niche = Niche::from_scalar(dl, b_offset, b.clone())
|
||||
.into_iter()
|
||||
.chain(Niche::from_scalar(dl, Size::ZERO, a.clone()))
|
||||
.max_by_key(|niche| niche.available(dl));
|
||||
|
||||
LayoutDetails {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldPlacement::Arbitrary {
|
||||
@ -253,6 +261,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
memory_index: vec![0, 1]
|
||||
},
|
||||
abi: Abi::ScalarPair(a, b),
|
||||
largest_niche,
|
||||
align,
|
||||
size
|
||||
}
|
||||
@ -321,6 +330,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
|
||||
|
||||
let mut offset = Size::ZERO;
|
||||
let mut largest_niche = None;
|
||||
let mut largest_niche_available = 0;
|
||||
|
||||
if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
|
||||
let prefix_align = if packed {
|
||||
@ -355,6 +366,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
debug!("univariant offset: {:?} field: {:#?}", offset, field);
|
||||
offsets[i as usize] = offset;
|
||||
|
||||
if let Some(mut niche) = field.largest_niche.clone() {
|
||||
let available = niche.available(dl);
|
||||
if available > largest_niche_available {
|
||||
largest_niche_available = available;
|
||||
niche.offset += offset;
|
||||
largest_niche = Some(niche);
|
||||
}
|
||||
}
|
||||
|
||||
offset = offset.checked_add(field.size, dl)
|
||||
.ok_or(LayoutError::SizeOverflow(ty))?;
|
||||
}
|
||||
@ -466,6 +486,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
memory_index
|
||||
},
|
||||
abi,
|
||||
largest_niche,
|
||||
align,
|
||||
size
|
||||
})
|
||||
@ -525,6 +546,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldPlacement::Union(0),
|
||||
abi: Abi::Uninhabited,
|
||||
largest_niche: None,
|
||||
align: dl.i8_align,
|
||||
size: Size::ZERO
|
||||
})
|
||||
@ -583,6 +605,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
Abi::Aggregate { sized: true }
|
||||
};
|
||||
|
||||
let largest_niche = if count != 0 {
|
||||
element.largest_niche.clone()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
tcx.intern_layout(LayoutDetails {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldPlacement::Array {
|
||||
@ -590,6 +618,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
count
|
||||
},
|
||||
abi,
|
||||
largest_niche,
|
||||
align: element.align,
|
||||
size
|
||||
})
|
||||
@ -603,6 +632,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
count: 0
|
||||
},
|
||||
abi: Abi::Aggregate { sized: false },
|
||||
largest_niche: None,
|
||||
align: element.align,
|
||||
size: Size::ZERO
|
||||
})
|
||||
@ -615,6 +645,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
count: 0
|
||||
},
|
||||
abi: Abi::Aggregate { sized: false },
|
||||
largest_niche: None,
|
||||
align: dl.i8_align,
|
||||
size: Size::ZERO
|
||||
})
|
||||
@ -683,6 +714,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
element: scalar,
|
||||
count
|
||||
},
|
||||
largest_niche: element.largest_niche.clone(),
|
||||
size,
|
||||
align,
|
||||
})
|
||||
@ -768,6 +800,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
variants: Variants::Single { index },
|
||||
fields: FieldPlacement::Union(variants[index].len()),
|
||||
abi,
|
||||
largest_niche: None,
|
||||
align,
|
||||
size: size.align_to(align.abi)
|
||||
}));
|
||||
@ -829,14 +862,38 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
// `#[rustc_layout_scalar_valid_range(n)]`
|
||||
// attribute to widen the range of anything as that would probably
|
||||
// result in UB somewhere
|
||||
// FIXME(eddyb) the asserts are probably not needed,
|
||||
// as larger validity ranges would result in missed
|
||||
// optimizations, *not* wrongly assuming the inner
|
||||
// value is valid. e.g. unions enlarge validity ranges,
|
||||
// because the values may be uninitialized.
|
||||
if let Bound::Included(start) = start {
|
||||
// FIXME(eddyb) this might be incorrect - it doesn't
|
||||
// account for wrap-around (end < start) ranges.
|
||||
assert!(*scalar.valid_range.start() <= start);
|
||||
scalar.valid_range = start..=*scalar.valid_range.end();
|
||||
}
|
||||
if let Bound::Included(end) = end {
|
||||
// FIXME(eddyb) this might be incorrect - it doesn't
|
||||
// account for wrap-around (end < start) ranges.
|
||||
assert!(*scalar.valid_range.end() >= end);
|
||||
scalar.valid_range = *scalar.valid_range.start()..=end;
|
||||
}
|
||||
|
||||
// Update `largest_niche` if we have introduced a larger niche.
|
||||
let niche = Niche::from_scalar(dl, Size::ZERO, scalar.clone());
|
||||
if let Some(niche) = niche {
|
||||
match &st.largest_niche {
|
||||
Some(largest_niche) => {
|
||||
// Replace the existing niche even if they're equal,
|
||||
// because this one is at a lower offset.
|
||||
if largest_niche.available(dl) <= niche.available(dl) {
|
||||
st.largest_niche = Some(niche);
|
||||
}
|
||||
}
|
||||
None => st.largest_niche = Some(niche),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => assert!(
|
||||
start == Bound::Unbounded && end == Bound::Unbounded,
|
||||
@ -845,6 +902,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
st,
|
||||
),
|
||||
}
|
||||
|
||||
return Ok(tcx.intern_layout(st));
|
||||
}
|
||||
|
||||
@ -886,8 +944,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
let count = (
|
||||
niche_variants.end().as_u32() - niche_variants.start().as_u32() + 1
|
||||
) as u128;
|
||||
// FIXME(#62691) use the largest niche across all fields,
|
||||
// not just the first one.
|
||||
for (field_index, &field) in variants[i].iter().enumerate() {
|
||||
let niche = match self.find_niche(field)? {
|
||||
let niche = match &field.largest_niche {
|
||||
Some(niche) => niche,
|
||||
_ => continue,
|
||||
};
|
||||
@ -937,6 +997,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
abi = Abi::Uninhabited;
|
||||
}
|
||||
|
||||
|
||||
let largest_niche =
|
||||
Niche::from_scalar(dl, offset, niche_scalar.clone());
|
||||
|
||||
return Ok(tcx.intern_layout(LayoutDetails {
|
||||
variants: Variants::Multiple {
|
||||
discr: niche_scalar,
|
||||
@ -953,6 +1017,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
memory_index: vec![0]
|
||||
},
|
||||
abi,
|
||||
largest_niche,
|
||||
size,
|
||||
align,
|
||||
}));
|
||||
@ -1164,6 +1229,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
abi = Abi::Uninhabited;
|
||||
}
|
||||
|
||||
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag.clone());
|
||||
|
||||
tcx.intern_layout(LayoutDetails {
|
||||
variants: Variants::Multiple {
|
||||
discr: tag,
|
||||
@ -1175,6 +1242,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
offsets: vec![Size::ZERO],
|
||||
memory_index: vec![0]
|
||||
},
|
||||
largest_niche,
|
||||
abi,
|
||||
align,
|
||||
size
|
||||
@ -1332,16 +1400,31 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
// locals as part of the prefix. We compute the layout of all of
|
||||
// these fields at once to get optimal packing.
|
||||
let discr_index = substs.prefix_tys(def_id, tcx).count();
|
||||
let promoted_tys =
|
||||
ineligible_locals.iter().map(|local| subst_field(info.field_tys[local]));
|
||||
let prefix_tys = substs.prefix_tys(def_id, tcx)
|
||||
.chain(iter::once(substs.discr_ty(tcx)))
|
||||
.chain(promoted_tys);
|
||||
let prefix = self.univariant_uninterned(
|
||||
// FIXME(eddyb) set the correct vaidity range for the discriminant.
|
||||
let discr_layout = self.layout_of(substs.discr_ty(tcx))?;
|
||||
let discr = match &discr_layout.abi {
|
||||
Abi::Scalar(s) => s.clone(),
|
||||
_ => bug!(),
|
||||
};
|
||||
// FIXME(eddyb) wrap each promoted type in `MaybeUninit` so that they
|
||||
// don't poison the `largest_niche` or `abi` fields of `prefix`.
|
||||
let promoted_layouts = ineligible_locals.iter()
|
||||
.map(|local| subst_field(info.field_tys[local]))
|
||||
.map(|ty| self.layout_of(ty));
|
||||
let prefix_layouts = substs.prefix_tys(def_id, tcx)
|
||||
.map(|ty| self.layout_of(ty))
|
||||
.chain(iter::once(Ok(discr_layout)))
|
||||
.chain(promoted_layouts)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let mut prefix = self.univariant_uninterned(
|
||||
ty,
|
||||
&prefix_tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
|
||||
&prefix_layouts,
|
||||
&ReprOptions::default(),
|
||||
StructKind::AlwaysSized)?;
|
||||
StructKind::AlwaysSized,
|
||||
)?;
|
||||
// FIXME(eddyb) need `MaybeUninit` around promoted types (see above).
|
||||
prefix.largest_niche = None;
|
||||
|
||||
let (prefix_size, prefix_align) = (prefix.size, prefix.align);
|
||||
|
||||
// Split the prefix layout into the "outer" fields (upvars and
|
||||
@ -1463,10 +1546,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
} else {
|
||||
Abi::Aggregate { sized: true }
|
||||
};
|
||||
let discr = match &self.layout_of(substs.discr_ty(tcx))?.abi {
|
||||
Abi::Scalar(s) => s.clone(),
|
||||
_ => bug!(),
|
||||
};
|
||||
|
||||
let layout = tcx.intern_layout(LayoutDetails {
|
||||
variants: Variants::Multiple {
|
||||
@ -1477,6 +1556,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
},
|
||||
fields: outer_fields,
|
||||
abi,
|
||||
largest_niche: prefix.largest_niche,
|
||||
size,
|
||||
align,
|
||||
});
|
||||
@ -1950,6 +2030,7 @@ where
|
||||
variants: Variants::Single { index: variant_index },
|
||||
fields: FieldPlacement::Union(fields),
|
||||
abi: Abi::Uninhabited,
|
||||
largest_niche: None,
|
||||
align: tcx.data_layout.i8_align,
|
||||
size: Size::ZERO
|
||||
})
|
||||
@ -2222,120 +2303,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
struct Niche {
|
||||
offset: Size,
|
||||
scalar: Scalar,
|
||||
available: u128,
|
||||
}
|
||||
|
||||
impl Niche {
|
||||
fn reserve<'tcx>(
|
||||
&self,
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
count: u128,
|
||||
) -> Option<(u128, Scalar)> {
|
||||
if count > self.available {
|
||||
return None;
|
||||
}
|
||||
let Scalar { value, valid_range: ref v } = self.scalar;
|
||||
let bits = value.size(cx).bits();
|
||||
assert!(bits <= 128);
|
||||
let max_value = !0u128 >> (128 - bits);
|
||||
let start = v.end().wrapping_add(1) & max_value;
|
||||
let end = v.end().wrapping_add(count) & max_value;
|
||||
Some((start, Scalar { value, valid_range: *v.start()..=end }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
/// Find the offset of a niche leaf field, starting from
|
||||
/// the given type and recursing through aggregates.
|
||||
// FIXME(eddyb) traverse already optimized enums.
|
||||
fn find_niche(&self, layout: TyLayout<'tcx>) -> Result<Option<Niche>, LayoutError<'tcx>> {
|
||||
let scalar_niche = |scalar: &Scalar, offset| {
|
||||
let Scalar { value, valid_range: ref v } = *scalar;
|
||||
|
||||
let bits = value.size(self).bits();
|
||||
assert!(bits <= 128);
|
||||
let max_value = !0u128 >> (128 - bits);
|
||||
|
||||
// Find out how many values are outside the valid range.
|
||||
let available = if v.start() <= v.end() {
|
||||
v.start() + (max_value - v.end())
|
||||
} else {
|
||||
v.start() - v.end() - 1
|
||||
};
|
||||
|
||||
// Give up if there is no niche value available.
|
||||
if available == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Niche { offset, scalar: scalar.clone(), available })
|
||||
};
|
||||
|
||||
// Locals variables which live across yields are stored
|
||||
// in the generator type as fields. These may be uninitialized
|
||||
// so we don't look for niches there.
|
||||
if let ty::Generator(..) = layout.ty.sty {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
match layout.abi {
|
||||
Abi::Scalar(ref scalar) => {
|
||||
return Ok(scalar_niche(scalar, Size::ZERO));
|
||||
}
|
||||
Abi::ScalarPair(ref a, ref b) => {
|
||||
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
|
||||
// returns the last maximum.
|
||||
let niche = iter::once(
|
||||
(b, a.value.size(self).align_to(b.value.align(self).abi))
|
||||
)
|
||||
.chain(iter::once((a, Size::ZERO)))
|
||||
.filter_map(|(scalar, offset)| scalar_niche(scalar, offset))
|
||||
.max_by_key(|niche| niche.available);
|
||||
return Ok(niche);
|
||||
}
|
||||
Abi::Vector { ref element, .. } => {
|
||||
return Ok(scalar_niche(element, Size::ZERO));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Perhaps one of the fields is non-zero, let's recurse and find out.
|
||||
if let FieldPlacement::Union(_) = layout.fields {
|
||||
// Only Rust enums have safe-to-inspect fields
|
||||
// (a discriminant), other unions are unsafe.
|
||||
if let Variants::Single { .. } = layout.variants {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
if let FieldPlacement::Array { count: original_64_bit_count, .. } = layout.fields {
|
||||
// rust-lang/rust#57038: avoid ICE within FieldPlacement::count when count too big
|
||||
if original_64_bit_count > usize::max_value() as u64 {
|
||||
return Err(LayoutError::SizeOverflow(layout.ty));
|
||||
}
|
||||
if layout.fields.count() > 0 {
|
||||
return self.find_niche(layout.field(self, 0)?);
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
let mut niche = None;
|
||||
let mut available = 0;
|
||||
for i in 0..layout.fields.count() {
|
||||
if let Some(mut c) = self.find_niche(layout.field(self, i)?)? {
|
||||
if c.available > available {
|
||||
available = c.available;
|
||||
c.offset += layout.fields.offset(i);
|
||||
niche = Some(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(niche)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for Variants {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
@ -2456,10 +2423,16 @@ impl<'a> HashStable<StableHashingContext<'a>> for Scalar {
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct crate::ty::layout::Niche {
|
||||
offset,
|
||||
scalar
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct crate::ty::layout::LayoutDetails {
|
||||
variants,
|
||||
fields,
|
||||
abi,
|
||||
largest_niche,
|
||||
size,
|
||||
align
|
||||
});
|
||||
|
@ -1847,7 +1847,7 @@ impl<'tcx> TyS<'tcx> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_mutable_pointer(&self) -> bool {
|
||||
pub fn is_mutable_ptr(&self) -> bool {
|
||||
match self.sty {
|
||||
RawPtr(TypeAndMut { mutbl: hir::Mutability::MutMutable, .. }) |
|
||||
Ref(_, _, hir::Mutability::MutMutable) => true,
|
||||
@ -2002,7 +2002,7 @@ impl<'tcx> TyS<'tcx> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_pointer_sized(&self) -> bool {
|
||||
pub fn is_ptr_sized_integral(&self) -> bool {
|
||||
match self.sty {
|
||||
Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true,
|
||||
_ => false,
|
||||
|
@ -1153,11 +1153,14 @@ impl Builder<'a, 'll, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vector_reduce_fadd(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value {
|
||||
unsafe { llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src) }
|
||||
}
|
||||
pub fn vector_reduce_fmul(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value {
|
||||
unsafe { llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src) }
|
||||
}
|
||||
pub fn vector_reduce_fadd_fast(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value {
|
||||
unsafe {
|
||||
// FIXME: add a non-fast math version once
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=36732
|
||||
// is fixed.
|
||||
let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src);
|
||||
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
||||
instr
|
||||
@ -1165,9 +1168,6 @@ impl Builder<'a, 'll, 'tcx> {
|
||||
}
|
||||
pub fn vector_reduce_fmul_fast(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value {
|
||||
unsafe {
|
||||
// FIXME: add a non-fast math version once
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=36732
|
||||
// is fixed.
|
||||
let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src);
|
||||
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
|
||||
instr
|
||||
|
@ -166,25 +166,6 @@ impl CodegenCx<'ll, 'tcx> {
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_get_real(&self, v: &'ll Value) -> Option<(f64, bool)> {
|
||||
unsafe {
|
||||
if self.is_const_real(v) {
|
||||
let mut loses_info: llvm::Bool = 0;
|
||||
let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info);
|
||||
let loses_info = if loses_info == 1 { true } else { false };
|
||||
Some((r, loses_info))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_const_real(&self, v: &'ll Value) -> bool {
|
||||
unsafe {
|
||||
llvm::LLVMIsAConstantFP(v).is_some()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
|
@ -1640,29 +1640,11 @@ fn generic_simd_intrinsic(
|
||||
}
|
||||
},
|
||||
ty::Float(f) => {
|
||||
// ordered arithmetic reductions take an accumulator
|
||||
let acc = if $ordered {
|
||||
let acc = args[1].immediate();
|
||||
// FIXME: https://bugs.llvm.org/show_bug.cgi?id=36734
|
||||
// * if the accumulator of the fadd isn't 0, incorrect
|
||||
// code is generated
|
||||
// * if the accumulator of the fmul isn't 1, incorrect
|
||||
// code is generated
|
||||
match bx.const_get_real(acc) {
|
||||
None => return_error!("accumulator of {} is not a constant", $name),
|
||||
Some((v, loses_info)) => {
|
||||
if $name.contains("mul") && v != 1.0_f64 {
|
||||
return_error!("accumulator of {} is not 1.0", $name);
|
||||
} else if $name.contains("add") && v != 0.0_f64 {
|
||||
return_error!("accumulator of {} is not 0.0", $name);
|
||||
} else if loses_info {
|
||||
return_error!("accumulator of {} loses information", $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
acc
|
||||
// ordered arithmetic reductions take an accumulator
|
||||
args[1].immediate()
|
||||
} else {
|
||||
// unordered arithmetic reductions do not:
|
||||
// unordered arithmetic reductions use the identity accumulator
|
||||
let identity_acc = if $name.contains("mul") { 1.0 } else { 0.0 };
|
||||
match f.bit_width() {
|
||||
32 => bx.const_real(bx.type_f32(), identity_acc),
|
||||
@ -1688,8 +1670,8 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
|
||||
}
|
||||
}
|
||||
|
||||
arith_red!("simd_reduce_add_ordered": vector_reduce_add, vector_reduce_fadd_fast, true);
|
||||
arith_red!("simd_reduce_mul_ordered": vector_reduce_mul, vector_reduce_fmul_fast, true);
|
||||
arith_red!("simd_reduce_add_ordered": vector_reduce_add, vector_reduce_fadd, true);
|
||||
arith_red!("simd_reduce_mul_ordered": vector_reduce_mul, vector_reduce_fmul, true);
|
||||
arith_red!("simd_reduce_add_unordered": vector_reduce_add, vector_reduce_fadd_fast, false);
|
||||
arith_red!("simd_reduce_mul_unordered": vector_reduce_mul, vector_reduce_fmul_fast, false);
|
||||
|
||||
|
@ -719,7 +719,6 @@ extern "C" {
|
||||
pub fn LLVMConstIntGetZExtValue(ConstantVal: &Value) -> c_ulonglong;
|
||||
pub fn LLVMRustConstInt128Get(ConstantVal: &Value, SExt: bool,
|
||||
high: &mut u64, low: &mut u64) -> bool;
|
||||
pub fn LLVMConstRealGetDouble (ConstantVal: &Value, losesInfo: &mut Bool) -> f64;
|
||||
|
||||
|
||||
// Operations on composite constants
|
||||
@ -1663,7 +1662,6 @@ extern "C" {
|
||||
pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
|
||||
|
||||
pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&Value>;
|
||||
pub fn LLVMIsAConstantFP(value_ref: &Value) -> Option<&Value>;
|
||||
|
||||
pub fn LLVMRustPassKind(Pass: &Pass) -> PassKind;
|
||||
pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> Option<&'static mut Pass>;
|
||||
|
@ -17,4 +17,4 @@ rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
unicode-width = "0.1.4"
|
||||
atty = "0.2"
|
||||
termcolor = "1.0"
|
||||
annotate-snippets = "0.5.0"
|
||||
annotate-snippets = "0.6.1"
|
||||
|
@ -23,7 +23,7 @@ pub struct AnnotateSnippetEmitterWriter {
|
||||
source_map: Option<Lrc<SourceMapperDyn>>,
|
||||
/// If true, hides the longer explanation text
|
||||
short_message: bool,
|
||||
/// If true, will normalize line numbers with LL to prevent noise in UI test diffs.
|
||||
/// If true, will normalize line numbers with `LL` to prevent noise in UI test diffs.
|
||||
ui_testing: bool,
|
||||
}
|
||||
|
||||
@ -173,10 +173,6 @@ impl AnnotateSnippetEmitterWriter {
|
||||
/// Allows to modify `Self` to enable or disable the `ui_testing` flag.
|
||||
///
|
||||
/// If this is set to true, line numbers will be normalized as `LL` in the output.
|
||||
// FIXME(#59346): This method is used via the public interface, but setting the `ui_testing`
|
||||
// flag currently does not anonymize line numbers. We would have to add the `maybe_anonymized`
|
||||
// method from `emitter.rs` and implement rust-lang/annotate-snippets-rs#2 in order to
|
||||
// anonymize line numbers.
|
||||
pub fn ui_testing(mut self, ui_testing: bool) -> Self {
|
||||
self.ui_testing = ui_testing;
|
||||
self
|
||||
@ -202,7 +198,7 @@ impl AnnotateSnippetEmitterWriter {
|
||||
};
|
||||
if let Some(snippet) = converter.to_annotation_snippet() {
|
||||
let dl = DisplayList::from(snippet);
|
||||
let dlf = DisplayListFormatter::new(true);
|
||||
let dlf = DisplayListFormatter::new(true, self.ui_testing);
|
||||
// FIXME(#59346): Figure out if we can _always_ print to stderr or not.
|
||||
// `emitter.rs` has the `Destination` enum that lists various possible output
|
||||
// destinations.
|
||||
|
@ -112,6 +112,10 @@ fn main() {
|
||||
println!("cargo:rustc-cfg=llvm_component=\"{}\"", component);
|
||||
}
|
||||
|
||||
if major >= 9 {
|
||||
println!("cargo:rustc-cfg=llvm_has_msp430_asm_parser");
|
||||
}
|
||||
|
||||
// Link in our own LLVM shims, compiled with the same flags as LLVM
|
||||
let mut cmd = Command::new(&llvm_config);
|
||||
cmd.arg("--cxxflags");
|
||||
|
@ -76,6 +76,8 @@ pub fn initialize_available_targets() {
|
||||
LLVMInitializeMSP430Target,
|
||||
LLVMInitializeMSP430TargetMC,
|
||||
LLVMInitializeMSP430AsmPrinter);
|
||||
init_target!(all(llvm_component = "msp430", llvm_has_msp430_asm_parser),
|
||||
LLVMInitializeMSP430AsmParser);
|
||||
init_target!(llvm_component = "riscv",
|
||||
LLVMInitializeRISCVTargetInfo,
|
||||
LLVMInitializeRISCVTarget,
|
||||
|
@ -536,7 +536,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let base_ty = Place::ty_from(deref_base.base, deref_base.projection, self.body, tcx).ty;
|
||||
if base_ty.is_unsafe_ptr() {
|
||||
BorrowedContentSource::DerefRawPointer
|
||||
} else if base_ty.is_mutable_pointer() {
|
||||
} else if base_ty.is_mutable_ptr() {
|
||||
BorrowedContentSource::DerefMutableRef
|
||||
} else {
|
||||
BorrowedContentSource::DerefSharedRef
|
||||
|
@ -1329,7 +1329,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
base: PlaceBase::Local(local),
|
||||
projection: None,
|
||||
}) if self.body.local_decls[local].is_user_variable.is_none() => {
|
||||
if self.body.local_decls[local].ty.is_mutable_pointer() {
|
||||
if self.body.local_decls[local].ty.is_mutable_ptr() {
|
||||
// The variable will be marked as mutable by the borrow.
|
||||
return;
|
||||
}
|
||||
|
@ -1171,7 +1171,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
|
||||
// For privately empty and non-exhaustive enums, we work as if there were an "extra"
|
||||
// `_` constructor for the type, so we can never match over all constructors.
|
||||
let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive ||
|
||||
(pcx.ty.is_pointer_sized() && !cx.tcx.features().precise_pointer_size_matching);
|
||||
(pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching);
|
||||
|
||||
if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive {
|
||||
split_grouped_constructors(cx.tcx, all_ctors, matrix, pcx.ty).into_iter().map(|c| {
|
||||
@ -1488,7 +1488,7 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>)
|
||||
_ => return false,
|
||||
};
|
||||
if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.sty {
|
||||
!ty.is_pointer_sized() || tcx.features().precise_pointer_size_matching
|
||||
!ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
@ -230,21 +230,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx, M::PointerTag>],
|
||||
dest: Option<PlaceTy<'tcx, M::PointerTag>>,
|
||||
_dest: Option<PlaceTy<'tcx, M::PointerTag>>,
|
||||
) -> InterpResult<'tcx, bool> {
|
||||
let def_id = instance.def_id();
|
||||
// Some fn calls are actually BinOp intrinsics
|
||||
if let Some((op, oflo)) = self.tcx.is_binop_lang_item(def_id) {
|
||||
let dest = dest.expect("128 lowerings can't diverge");
|
||||
let l = self.read_immediate(args[0])?;
|
||||
let r = self.read_immediate(args[1])?;
|
||||
if oflo {
|
||||
self.binop_with_overflow(op, l, r, dest)?;
|
||||
} else {
|
||||
self.binop_ignore_overflow(op, l, r, dest)?;
|
||||
}
|
||||
return Ok(true);
|
||||
} else if Some(def_id) == self.tcx.lang_items().panic_fn() {
|
||||
if Some(def_id) == self.tcx.lang_items().panic_fn() {
|
||||
assert!(args.len() == 1);
|
||||
// &(&'static str, &'static str, u32, u32)
|
||||
let place = self.deref_operand(args[0])?;
|
||||
|
@ -232,13 +232,6 @@ impl Inliner<'tcx> {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not inline {u,i}128 lang items, codegen const eval depends
|
||||
// on detecting calls to these lang items and intercepting them
|
||||
if tcx.is_binop_lang_item(callsite.callee).is_some() {
|
||||
debug!(" not inlining 128bit integer lang item");
|
||||
return false;
|
||||
}
|
||||
|
||||
let codegen_fn_attrs = tcx.codegen_fn_attrs(callsite.callee);
|
||||
|
||||
let hinted = match codegen_fn_attrs.inline {
|
||||
|
@ -1,230 +0,0 @@
|
||||
//! Replaces 128-bit operators with lang item calls
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::lang_items::LangItem;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{self, List, Ty, TyCtxt};
|
||||
use rustc_data_structures::indexed_vec::{Idx};
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
|
||||
pub struct Lower128Bit;
|
||||
|
||||
impl MirPass for Lower128Bit {
|
||||
fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
|
||||
let debugging_override = tcx.sess.opts.debugging_opts.lower_128bit_ops;
|
||||
let target_default = tcx.sess.host.options.i128_lowering;
|
||||
if !debugging_override.unwrap_or(target_default) {
|
||||
return
|
||||
}
|
||||
|
||||
self.lower_128bit_ops(tcx, body);
|
||||
}
|
||||
}
|
||||
|
||||
impl Lower128Bit {
|
||||
fn lower_128bit_ops<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let mut new_blocks = Vec::new();
|
||||
let cur_len = body.basic_blocks().len();
|
||||
|
||||
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
|
||||
for block in basic_blocks.iter_mut() {
|
||||
for i in (0..block.statements.len()).rev() {
|
||||
let (lang_item, rhs_kind) =
|
||||
if let Some((lang_item, rhs_kind)) =
|
||||
lower_to(&block.statements[i], local_decls, tcx)
|
||||
{
|
||||
(lang_item, rhs_kind)
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let rhs_override_ty = rhs_kind.ty(tcx);
|
||||
let cast_local =
|
||||
match rhs_override_ty {
|
||||
None => None,
|
||||
Some(ty) => {
|
||||
let local_decl = LocalDecl::new_internal(
|
||||
ty, block.statements[i].source_info.span);
|
||||
Some(local_decls.push(local_decl))
|
||||
},
|
||||
};
|
||||
|
||||
let storage_dead = cast_local.map(|local| {
|
||||
Statement {
|
||||
source_info: block.statements[i].source_info,
|
||||
kind: StatementKind::StorageDead(local),
|
||||
}
|
||||
});
|
||||
let after_call = BasicBlockData {
|
||||
statements: storage_dead.into_iter()
|
||||
.chain(block.statements.drain((i+1)..)).collect(),
|
||||
is_cleanup: block.is_cleanup,
|
||||
terminator: block.terminator.take(),
|
||||
};
|
||||
|
||||
let bin_statement = block.statements.pop().unwrap();
|
||||
let source_info = bin_statement.source_info;
|
||||
let (place, lhs, mut rhs) = match bin_statement.kind {
|
||||
StatementKind::Assign(place, box rvalue) => {
|
||||
match rvalue {
|
||||
Rvalue::BinaryOp(_, lhs, rhs)
|
||||
| Rvalue::CheckedBinaryOp(_, lhs, rhs) => (place, lhs, rhs),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
_ => bug!()
|
||||
};
|
||||
|
||||
if let Some(local) = cast_local {
|
||||
block.statements.push(Statement {
|
||||
source_info: source_info,
|
||||
kind: StatementKind::StorageLive(local),
|
||||
});
|
||||
block.statements.push(Statement {
|
||||
source_info: source_info,
|
||||
kind: StatementKind::Assign(
|
||||
Place::from(local),
|
||||
box Rvalue::Cast(
|
||||
CastKind::Misc,
|
||||
rhs,
|
||||
rhs_override_ty.unwrap())),
|
||||
});
|
||||
rhs = Operand::Move(Place::from(local));
|
||||
}
|
||||
|
||||
let call_did = check_lang_item_type(
|
||||
lang_item, &place, &lhs, &rhs, local_decls, tcx);
|
||||
|
||||
let bb = BasicBlock::new(cur_len + new_blocks.len());
|
||||
new_blocks.push(after_call);
|
||||
|
||||
block.terminator =
|
||||
Some(Terminator {
|
||||
source_info,
|
||||
kind: TerminatorKind::Call {
|
||||
func: Operand::function_handle(tcx, call_did,
|
||||
List::empty(), source_info.span),
|
||||
args: vec![lhs, rhs],
|
||||
destination: Some((place, bb)),
|
||||
cleanup: None,
|
||||
from_hir_call: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
basic_blocks.extend(new_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_lang_item_type<'tcx, D>(
|
||||
lang_item: LangItem,
|
||||
place: &Place<'tcx>,
|
||||
lhs: &Operand<'tcx>,
|
||||
rhs: &Operand<'tcx>,
|
||||
local_decls: &D,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> DefId
|
||||
where
|
||||
D: HasLocalDecls<'tcx>,
|
||||
{
|
||||
let did = tcx.require_lang_item(lang_item);
|
||||
let poly_sig = tcx.fn_sig(did);
|
||||
let sig = poly_sig.no_bound_vars().unwrap();
|
||||
let lhs_ty = lhs.ty(local_decls, tcx);
|
||||
let rhs_ty = rhs.ty(local_decls, tcx);
|
||||
let place_ty = place.ty(local_decls, tcx).ty;
|
||||
let expected = [lhs_ty, rhs_ty, place_ty];
|
||||
assert_eq!(sig.inputs_and_output[..], expected,
|
||||
"lang item `{}`", tcx.def_path_str(did));
|
||||
did
|
||||
}
|
||||
|
||||
fn lower_to<'tcx, D>(
|
||||
statement: &Statement<'tcx>,
|
||||
local_decls: &D,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<(LangItem, RhsKind)>
|
||||
where
|
||||
D: HasLocalDecls<'tcx>,
|
||||
{
|
||||
match statement.kind {
|
||||
StatementKind::Assign(_, box Rvalue::BinaryOp(bin_op, ref lhs, _)) => {
|
||||
let ty = lhs.ty(local_decls, tcx);
|
||||
if let Some(is_signed) = sign_of_128bit(ty) {
|
||||
return item_for_op(bin_op, is_signed);
|
||||
}
|
||||
},
|
||||
StatementKind::Assign(_, box Rvalue::CheckedBinaryOp(bin_op, ref lhs, _)) => {
|
||||
let ty = lhs.ty(local_decls, tcx);
|
||||
if let Some(is_signed) = sign_of_128bit(ty) {
|
||||
return item_for_checked_op(bin_op, is_signed);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum RhsKind {
|
||||
Unchanged,
|
||||
ForceU128,
|
||||
ForceU32,
|
||||
}
|
||||
|
||||
impl RhsKind {
|
||||
fn ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<Ty<'tcx>> {
|
||||
match *self {
|
||||
RhsKind::Unchanged => None,
|
||||
RhsKind::ForceU128 => Some(tcx.types.u128),
|
||||
RhsKind::ForceU32 => Some(tcx.types.u32),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sign_of_128bit(ty: Ty<'_>) -> Option<bool> {
|
||||
match ty.sty {
|
||||
ty::Int(syntax::ast::IntTy::I128) => Some(true),
|
||||
ty::Uint(syntax::ast::UintTy::U128) => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn item_for_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> {
|
||||
let i = match (bin_op, is_signed) {
|
||||
(BinOp::Add, true) => (LangItem::I128AddFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Add, false) => (LangItem::U128AddFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Sub, true) => (LangItem::I128SubFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Sub, false) => (LangItem::U128SubFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Mul, true) => (LangItem::I128MulFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Mul, false) => (LangItem::U128MulFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Div, true) => (LangItem::I128DivFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Div, false) => (LangItem::U128DivFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Rem, true) => (LangItem::I128RemFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Rem, false) => (LangItem::U128RemFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Shl, true) => (LangItem::I128ShlFnLangItem, RhsKind::ForceU32),
|
||||
(BinOp::Shl, false) => (LangItem::U128ShlFnLangItem, RhsKind::ForceU32),
|
||||
(BinOp::Shr, true) => (LangItem::I128ShrFnLangItem, RhsKind::ForceU32),
|
||||
(BinOp::Shr, false) => (LangItem::U128ShrFnLangItem, RhsKind::ForceU32),
|
||||
_ => return None,
|
||||
};
|
||||
Some(i)
|
||||
}
|
||||
|
||||
fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsKind)> {
|
||||
let i = match (bin_op, is_signed) {
|
||||
(BinOp::Add, true) => (LangItem::I128AddoFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Add, false) => (LangItem::U128AddoFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Sub, true) => (LangItem::I128SuboFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Sub, false) => (LangItem::U128SuboFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Mul, true) => (LangItem::I128MuloFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Mul, false) => (LangItem::U128MuloFnLangItem, RhsKind::Unchanged),
|
||||
(BinOp::Shl, true) => (LangItem::I128ShloFnLangItem, RhsKind::ForceU128),
|
||||
(BinOp::Shl, false) => (LangItem::U128ShloFnLangItem, RhsKind::ForceU128),
|
||||
(BinOp::Shr, true) => (LangItem::I128ShroFnLangItem, RhsKind::ForceU128),
|
||||
(BinOp::Shr, false) => (LangItem::U128ShroFnLangItem, RhsKind::ForceU128),
|
||||
_ => bug!("That should be all the checked ones?"),
|
||||
};
|
||||
Some(i)
|
||||
}
|
@ -34,7 +34,6 @@ pub mod copy_prop;
|
||||
pub mod const_prop;
|
||||
pub mod generator;
|
||||
pub mod inline;
|
||||
pub mod lower_128bit;
|
||||
pub mod uniform_array_move_out;
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers<'_>) {
|
||||
@ -272,8 +271,6 @@ fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> {
|
||||
// From here on out, regions are gone.
|
||||
&erase_regions::EraseRegions,
|
||||
|
||||
&lower_128bit::Lower128Bit,
|
||||
|
||||
|
||||
// Optimizations begin.
|
||||
&uniform_array_move_out::RestoreSubsliceArrayMoveOut,
|
||||
|
@ -878,23 +878,94 @@ pub enum DiscriminantKind {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Niche {
|
||||
pub offset: Size,
|
||||
pub scalar: Scalar,
|
||||
}
|
||||
|
||||
impl Niche {
|
||||
pub fn from_scalar<C: HasDataLayout>(cx: &C, offset: Size, scalar: Scalar) -> Option<Self> {
|
||||
let niche = Niche {
|
||||
offset,
|
||||
scalar,
|
||||
};
|
||||
if niche.available(cx) > 0 {
|
||||
Some(niche)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn available<C: HasDataLayout>(&self, cx: &C) -> u128 {
|
||||
let Scalar { value, valid_range: ref v } = self.scalar;
|
||||
let bits = value.size(cx).bits();
|
||||
assert!(bits <= 128);
|
||||
let max_value = !0u128 >> (128 - bits);
|
||||
|
||||
// Find out how many values are outside the valid range.
|
||||
let niche = v.end().wrapping_add(1)..*v.start();
|
||||
niche.end.wrapping_sub(niche.start) & max_value
|
||||
}
|
||||
|
||||
pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
|
||||
assert!(count > 0);
|
||||
|
||||
let Scalar { value, valid_range: ref v } = self.scalar;
|
||||
let bits = value.size(cx).bits();
|
||||
assert!(bits <= 128);
|
||||
let max_value = !0u128 >> (128 - bits);
|
||||
|
||||
if count > max_value {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Compute the range of invalid values being reserved.
|
||||
let start = v.end().wrapping_add(1) & max_value;
|
||||
let end = v.end().wrapping_add(count) & max_value;
|
||||
|
||||
// If the `end` of our range is inside the valid range,
|
||||
// then we ran out of invalid values.
|
||||
// FIXME(eddyb) abstract this with a wraparound range type.
|
||||
let valid_range_contains = |x| {
|
||||
if v.start() <= v.end() {
|
||||
*v.start() <= x && x <= *v.end()
|
||||
} else {
|
||||
*v.start() <= x || x <= *v.end()
|
||||
}
|
||||
};
|
||||
if valid_range_contains(end) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((start, Scalar { value, valid_range: *v.start()..=end }))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
pub struct LayoutDetails {
|
||||
pub variants: Variants,
|
||||
pub fields: FieldPlacement,
|
||||
pub abi: Abi,
|
||||
|
||||
/// The leaf scalar with the largest number of invalid values
|
||||
/// (i.e. outside of its `valid_range`), if it exists.
|
||||
pub largest_niche: Option<Niche>,
|
||||
|
||||
pub align: AbiAndPrefAlign,
|
||||
pub size: Size
|
||||
}
|
||||
|
||||
impl LayoutDetails {
|
||||
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
|
||||
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar.clone());
|
||||
let size = scalar.value.size(cx);
|
||||
let align = scalar.value.align(cx);
|
||||
LayoutDetails {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldPlacement::Union(0),
|
||||
abi: Abi::Scalar(scalar),
|
||||
largest_niche,
|
||||
size,
|
||||
align,
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ pub fn target() -> TargetResult {
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+strict-align,+v6,+vfp2".to_string(),
|
||||
features: "+strict-align,+v6,+vfp2,-d32".to_string(),
|
||||
abi_blacklist: super::arm_base::abi_blacklist(),
|
||||
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
|
||||
.. base
|
||||
|
@ -5,7 +5,7 @@ pub fn target() -> TargetResult {
|
||||
|
||||
// Most of these settings are copied from the arm_unknown_linux_gnueabihf
|
||||
// target.
|
||||
base.features = "+strict-align,+v6,+vfp2".to_string();
|
||||
base.features = "+strict-align,+v6,+vfp2,-d32".to_string();
|
||||
base.max_atomic_width = Some(64);
|
||||
Ok(Target {
|
||||
// It's important we use "gnueabihf" and not "musleabihf" here. LLVM
|
||||
|
@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+v6,+vfp2".to_string(),
|
||||
features: "+v6,+vfp2,-d32".to_string(),
|
||||
max_atomic_width: Some(64),
|
||||
abi_blacklist: super::arm_base::abi_blacklist(),
|
||||
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
|
||||
|
@ -16,7 +16,7 @@ pub fn target() -> TargetResult {
|
||||
linker_flavor: LinkerFlavor::Gcc,
|
||||
|
||||
options: TargetOptions {
|
||||
features: "+v6,+vfp2".to_string(),
|
||||
features: "+v6,+vfp2,-d32".to_string(),
|
||||
abi_blacklist: super::arm_base::abi_blacklist(),
|
||||
target_mcount: "__mcount".to_string(),
|
||||
.. base
|
||||
|
@ -736,10 +736,6 @@ pub struct TargetOptions {
|
||||
/// for this target unconditionally.
|
||||
pub no_builtins: bool,
|
||||
|
||||
/// Whether to lower 128-bit operations to compiler_builtins calls. Use if
|
||||
/// your backend only supports 64-bit and smaller math.
|
||||
pub i128_lowering: bool,
|
||||
|
||||
/// The codegen backend to use for this target, typically "llvm"
|
||||
pub codegen_backend: String,
|
||||
|
||||
@ -855,7 +851,6 @@ impl Default for TargetOptions {
|
||||
requires_lto: false,
|
||||
singlethread: false,
|
||||
no_builtins: false,
|
||||
i128_lowering: false,
|
||||
codegen_backend: "llvm".to_string(),
|
||||
default_hidden_visibility: false,
|
||||
embed_bitcode: false,
|
||||
|
@ -225,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
tcx.mk_unit()
|
||||
}
|
||||
ExprKind::Break(destination, ref expr_opt) => {
|
||||
self.check_expr_break(destination, expr_opt.deref(), expr)
|
||||
self.check_expr_break(destination, expr_opt.as_deref(), expr)
|
||||
}
|
||||
ExprKind::Continue(destination) => {
|
||||
if destination.target_id.is_ok() {
|
||||
@ -236,7 +236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
ExprKind::Ret(ref expr_opt) => {
|
||||
self.check_expr_return(expr_opt.deref(), expr)
|
||||
self.check_expr_return(expr_opt.as_deref(), expr)
|
||||
}
|
||||
ExprKind::Assign(ref lhs, ref rhs) => {
|
||||
self.check_expr_assign(expr, expected, lhs, rhs)
|
||||
|
@ -86,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
trait_name,
|
||||
item_name,
|
||||
if rcvr_ty.is_region_ptr() && args.is_some() {
|
||||
if rcvr_ty.is_mutable_pointer() {
|
||||
if rcvr_ty.is_mutable_ptr() {
|
||||
"&mut "
|
||||
} else {
|
||||
"&"
|
||||
|
@ -1173,7 +1173,7 @@ themePicker.onblur = handleThemeButtonsBlur;
|
||||
title: "Index of crates",
|
||||
css_class: "mod",
|
||||
root_path: "./",
|
||||
static_root_path: cx.shared.static_root_path.deref(),
|
||||
static_root_path: cx.shared.static_root_path.as_deref(),
|
||||
description: "List of crates",
|
||||
keywords: BASIC_KEYWORDS,
|
||||
resource_suffix: &cx.shared.resource_suffix,
|
||||
@ -1513,7 +1513,7 @@ impl<'a> SourceCollector<'a> {
|
||||
title: &title,
|
||||
css_class: "source",
|
||||
root_path: &root_path,
|
||||
static_root_path: self.scx.static_root_path.deref(),
|
||||
static_root_path: self.scx.static_root_path.as_deref(),
|
||||
description: &desc,
|
||||
keywords: BASIC_KEYWORDS,
|
||||
resource_suffix: &self.scx.resource_suffix,
|
||||
@ -2110,7 +2110,7 @@ impl Context {
|
||||
title: "List of all items in this crate",
|
||||
css_class: "mod",
|
||||
root_path: "../",
|
||||
static_root_path: self.shared.static_root_path.deref(),
|
||||
static_root_path: self.shared.static_root_path.as_deref(),
|
||||
description: "List of all items in this crate",
|
||||
keywords: BASIC_KEYWORDS,
|
||||
resource_suffix: &self.shared.resource_suffix,
|
||||
@ -2137,7 +2137,7 @@ impl Context {
|
||||
self.shared.fs.write(&final_file, &v)?;
|
||||
|
||||
// Generating settings page.
|
||||
let settings = Settings::new(self.shared.static_root_path.deref().unwrap_or("./"),
|
||||
let settings = Settings::new(self.shared.static_root_path.as_deref().unwrap_or("./"),
|
||||
&self.shared.resource_suffix);
|
||||
page.title = "Rustdoc settings";
|
||||
page.description = "Settings of Rustdoc";
|
||||
@ -2195,7 +2195,7 @@ impl Context {
|
||||
let page = layout::Page {
|
||||
css_class: tyname,
|
||||
root_path: &self.root_path(),
|
||||
static_root_path: self.shared.static_root_path.deref(),
|
||||
static_root_path: self.shared.static_root_path.as_deref(),
|
||||
title: &title,
|
||||
description: &desc,
|
||||
keywords: &keywords,
|
||||
|
@ -41,36 +41,6 @@ unsafe impl GlobalAlloc for System {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android",
|
||||
target_os = "hermit",
|
||||
target_os = "redox",
|
||||
target_os = "solaris"))]
|
||||
#[inline]
|
||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
||||
// On android we currently target API level 9 which unfortunately
|
||||
// doesn't have the `posix_memalign` API used below. Instead we use
|
||||
// `memalign`, but this unfortunately has the property on some systems
|
||||
// where the memory returned cannot be deallocated by `free`!
|
||||
//
|
||||
// Upon closer inspection, however, this appears to work just fine with
|
||||
// Android, so for this platform we should be fine to call `memalign`
|
||||
// (which is present in API level 9). Some helpful references could
|
||||
// possibly be chromium using memalign [1], attempts at documenting that
|
||||
// memalign + free is ok [2] [3], or the current source of chromium
|
||||
// which still uses memalign on android [4].
|
||||
//
|
||||
// [1]: https://codereview.chromium.org/10796020/
|
||||
// [2]: https://code.google.com/p/android/issues/detail?id=35391
|
||||
// [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
|
||||
// [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
|
||||
// /memory/aligned_memory.cc
|
||||
libc::memalign(layout.align(), layout.size()) as *mut u8
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android",
|
||||
target_os = "hermit",
|
||||
target_os = "redox",
|
||||
target_os = "solaris")))]
|
||||
#[inline]
|
||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
||||
let mut out = ptr::null_mut();
|
||||
|
@ -1,160 +0,0 @@
|
||||
//! Android ABI-compatibility module
|
||||
//!
|
||||
//! The ABI of Android has changed quite a bit over time, and libstd attempts to
|
||||
//! be both forwards and backwards compatible as much as possible. We want to
|
||||
//! always work with the most recent version of Android, but we also want to
|
||||
//! work with older versions of Android for whenever projects need to.
|
||||
//!
|
||||
//! Our current minimum supported Android version is `android-9`, e.g., Android
|
||||
//! with API level 9. We then in theory want to work on that and all future
|
||||
//! versions of Android!
|
||||
//!
|
||||
//! Some of the detection here is done at runtime via `dlopen` and
|
||||
//! introspection. Other times no detection is performed at all and we just
|
||||
//! provide a fallback implementation as some versions of Android we support
|
||||
//! don't have the function.
|
||||
//!
|
||||
//! You'll find more details below about why each compatibility shim is needed.
|
||||
|
||||
#![cfg(target_os = "android")]
|
||||
|
||||
use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
|
||||
use libc::{ftruncate, pread, pwrite};
|
||||
|
||||
use crate::io;
|
||||
use super::{cvt, cvt_r};
|
||||
|
||||
// The `log2` and `log2f` functions apparently appeared in android-18, or at
|
||||
// least you can see they're not present in the android-17 header [1] and they
|
||||
// are present in android-18 [2].
|
||||
//
|
||||
// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
|
||||
// /android-17/arch-arm/usr/include/math.h
|
||||
// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
|
||||
// /android-18/arch-arm/usr/include/math.h
|
||||
//
|
||||
// Note that these shims are likely less precise than directly calling `log2`,
|
||||
// but hopefully that should be enough for now...
|
||||
//
|
||||
// Note that mathematically, for any arbitrary `y`:
|
||||
//
|
||||
// log_2(x) = log_y(x) / log_y(2)
|
||||
// = log_y(x) / (1 / log_2(y))
|
||||
// = log_y(x) * log_2(y)
|
||||
//
|
||||
// Hence because `ln` (log_e) is available on all Android we just choose `y = e`
|
||||
// and get:
|
||||
//
|
||||
// log_2(x) = ln(x) * log_2(e)
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub fn log2f32(f: f32) -> f32 {
|
||||
f.ln() * crate::f32::consts::LOG2_E
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub fn log2f64(f: f64) -> f64 {
|
||||
f.ln() * crate::f64::consts::LOG2_E
|
||||
}
|
||||
|
||||
// Back in the day [1] the `signal` function was just an inline wrapper
|
||||
// around `bsd_signal`, but starting in API level android-20 the `signal`
|
||||
// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was
|
||||
// removed [3].
|
||||
//
|
||||
// Basically this means that if we want to be binary compatible with multiple
|
||||
// Android releases (oldest being 9 and newest being 21) then we need to check
|
||||
// for both symbols and not actually link against either.
|
||||
//
|
||||
// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
|
||||
// /android-18/arch-arm/usr/include/signal.h
|
||||
// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental
|
||||
// /platforms/android-20/arch-arm
|
||||
// /usr/include/signal.h
|
||||
// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms
|
||||
// /android-21/arch-arm/usr/include/signal.h
|
||||
pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t {
|
||||
weak!(fn signal(c_int, sighandler_t) -> sighandler_t);
|
||||
weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t);
|
||||
|
||||
let f = signal.get().or_else(|| bsd_signal.get());
|
||||
let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
|
||||
f(signum, handler)
|
||||
}
|
||||
|
||||
// The `ftruncate64` symbol apparently appeared in android-12, so we do some
|
||||
// dynamic detection to see if we can figure out whether `ftruncate64` exists.
|
||||
//
|
||||
// If it doesn't we just fall back to `ftruncate`, generating an error for
|
||||
// too-large values.
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
|
||||
weak!(fn ftruncate64(c_int, i64) -> c_int);
|
||||
|
||||
unsafe {
|
||||
match ftruncate64.get() {
|
||||
Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()),
|
||||
None => {
|
||||
if size > i32::max_value() as u64 {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"cannot truncate >2GB"))
|
||||
} else {
|
||||
cvt_r(|| ftruncate(fd, size as i32)).map(|_| ())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
|
||||
unsafe {
|
||||
cvt_r(|| ftruncate(fd, size as i64)).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
|
||||
-> io::Result<ssize_t>
|
||||
{
|
||||
use crate::convert::TryInto;
|
||||
weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
|
||||
pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
|
||||
if let Ok(o) = offset.try_into() {
|
||||
cvt(pread(fd, buf, count, o))
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"cannot pread >2GB"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
|
||||
-> io::Result<ssize_t>
|
||||
{
|
||||
use crate::convert::TryInto;
|
||||
weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
|
||||
pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
|
||||
if let Ok(o) = offset.try_into() {
|
||||
cvt(pwrite(fd, buf, count, o))
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"cannot pwrite >2GB"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
|
||||
-> io::Result<ssize_t>
|
||||
{
|
||||
cvt(pread(fd, buf, count, offset))
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
|
||||
-> io::Result<ssize_t>
|
||||
{
|
||||
cvt(pwrite(fd, buf, count, offset))
|
||||
}
|
@ -62,10 +62,6 @@ impl Condvar {
|
||||
// where we configure condition variable to use monotonic clock (instead of
|
||||
// default system clock). This approach avoids all problems that result
|
||||
// from changes made to the system time.
|
||||
#[cfg(not(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "android",
|
||||
target_os = "hermit")))]
|
||||
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
|
||||
use crate::mem;
|
||||
|
||||
@ -92,78 +88,9 @@ impl Condvar {
|
||||
}
|
||||
|
||||
|
||||
// This implementation is modeled after libcxx's condition_variable
|
||||
// https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
|
||||
// https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
|
||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))]
|
||||
pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
|
||||
use crate::ptr;
|
||||
use crate::time::Instant;
|
||||
|
||||
// 1000 years
|
||||
let max_dur = Duration::from_secs(1000 * 365 * 86400);
|
||||
|
||||
if dur > max_dur {
|
||||
// OSX implementation of `pthread_cond_timedwait` is buggy
|
||||
// with super long durations. When duration is greater than
|
||||
// 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
|
||||
// in macOS Sierra return error 316.
|
||||
//
|
||||
// This program demonstrates the issue:
|
||||
// https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
|
||||
//
|
||||
// To work around this issue, and possible bugs of other OSes, timeout
|
||||
// is clamped to 1000 years, which is allowable per the API of `wait_timeout`
|
||||
// because of spurious wakeups.
|
||||
|
||||
dur = max_dur;
|
||||
}
|
||||
|
||||
// First, figure out what time it currently is, in both system and
|
||||
// stable time. pthread_cond_timedwait uses system time, but we want to
|
||||
// report timeout based on stable time.
|
||||
let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
|
||||
let stable_now = Instant::now();
|
||||
let r = libc::gettimeofday(&mut sys_now, ptr::null_mut());
|
||||
debug_assert_eq!(r, 0);
|
||||
|
||||
let nsec = dur.subsec_nanos() as libc::c_long +
|
||||
(sys_now.tv_usec * 1000) as libc::c_long;
|
||||
let extra = (nsec / 1_000_000_000) as libc::time_t;
|
||||
let nsec = nsec % 1_000_000_000;
|
||||
let seconds = saturating_cast_to_time_t(dur.as_secs());
|
||||
|
||||
let timeout = sys_now.tv_sec.checked_add(extra).and_then(|s| {
|
||||
s.checked_add(seconds)
|
||||
}).map(|s| {
|
||||
libc::timespec { tv_sec: s, tv_nsec: nsec }
|
||||
}).unwrap_or(TIMESPEC_MAX);
|
||||
|
||||
// And wait!
|
||||
let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
|
||||
&timeout);
|
||||
debug_assert!(r == libc::ETIMEDOUT || r == 0);
|
||||
|
||||
// ETIMEDOUT is not a totally reliable method of determining timeout due
|
||||
// to clock shifts, so do the check ourselves
|
||||
stable_now.elapsed() < dur
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(target_os = "dragonfly"))]
|
||||
pub unsafe fn destroy(&self) {
|
||||
let r = libc::pthread_cond_destroy(self.inner.get());
|
||||
debug_assert_eq!(r, 0);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
pub unsafe fn destroy(&self) {
|
||||
let r = libc::pthread_cond_destroy(self.inner.get());
|
||||
// On DragonFly pthread_cond_destroy() returns EINVAL if called on
|
||||
// a condvar that was just initialized with
|
||||
// libc::PTHREAD_COND_INITIALIZER. Once it is used or
|
||||
// pthread_cond_init() is called, this behaviour no longer occurs.
|
||||
debug_assert!(r == 0 || r == libc::EINVAL);
|
||||
}
|
||||
}
|
||||
|
@ -5,16 +5,6 @@
|
||||
#[cfg(unix)]
|
||||
use libc;
|
||||
|
||||
// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
|
||||
#[cfg(not(unix))]
|
||||
mod libc {
|
||||
pub use libc::c_int;
|
||||
pub type socklen_t = u32;
|
||||
pub struct sockaddr;
|
||||
#[derive(Clone)]
|
||||
pub struct sockaddr_un;
|
||||
}
|
||||
|
||||
use crate::ascii;
|
||||
use crate::ffi::OsStr;
|
||||
use crate::fmt;
|
||||
@ -29,15 +19,6 @@ use crate::sys::{self, cvt};
|
||||
use crate::sys::net::Socket;
|
||||
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android",
|
||||
target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "openbsd", target_os = "netbsd",
|
||||
target_os = "haiku"))]
|
||||
use libc::MSG_NOSIGNAL;
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android",
|
||||
target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "openbsd", target_os = "netbsd",
|
||||
target_os = "haiku")))]
|
||||
const MSG_NOSIGNAL: libc::c_int = 0x0;
|
||||
|
||||
fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
|
||||
@ -202,13 +183,7 @@ impl SocketAddr {
|
||||
let len = self.len as usize - sun_path_offset(&self.addr);
|
||||
let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
|
||||
|
||||
// macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
|
||||
if len == 0
|
||||
|| (cfg!(not(any(target_os = "linux", target_os = "android")))
|
||||
&& self.addr.sun_path[0] == 0)
|
||||
{
|
||||
AddressKind::Unnamed
|
||||
} else if self.addr.sun_path[0] == 0 {
|
||||
if self.addr.sun_path[0] == 0 {
|
||||
AddressKind::Abstract(&path[1..len])
|
||||
} else {
|
||||
AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
|
||||
|
@ -1,469 +0,0 @@
|
||||
macro_rules! unimpl {
|
||||
() => (return Err(io::Error::new(io::ErrorKind::Other, "No networking available on L4Re."));)
|
||||
}
|
||||
|
||||
pub mod net {
|
||||
#![allow(warnings)]
|
||||
use crate::fmt;
|
||||
use crate::io::{self, IoVec, IoVecMut};
|
||||
use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::time::Duration;
|
||||
use crate::convert::TryFrom;
|
||||
|
||||
#[allow(unused_extern_crates)]
|
||||
pub extern crate libc as netc;
|
||||
|
||||
pub struct Socket(FileDesc);
|
||||
impl Socket {
|
||||
pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result<Socket> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result<Socket> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn accept(&self, _: *mut libc::sockaddr, _: *mut libc::socklen_t)
|
||||
-> io::Result<Socket> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<Socket> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn timeout(&self, _: libc::c_int) -> io::Result<Option<Duration>> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn nodelay(&self) -> io::Result<bool> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
unimpl!();
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<libc::c_int> for Socket {
|
||||
fn as_inner(&self) -> &libc::c_int { self.0.as_inner() }
|
||||
}
|
||||
|
||||
impl FromInner<libc::c_int> for Socket {
|
||||
fn from_inner(fd: libc::c_int) -> Socket { Socket(FileDesc::new(fd)) }
|
||||
}
|
||||
|
||||
impl IntoInner<libc::c_int> for Socket {
|
||||
fn into_inner(self) -> libc::c_int { self.0.into_raw() }
|
||||
}
|
||||
|
||||
pub struct TcpStream {
|
||||
inner: Socket,
|
||||
}
|
||||
|
||||
impl TcpStream {
|
||||
pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn socket(&self) -> &Socket { &self.inner }
|
||||
|
||||
pub fn into_socket(self) -> Socket { self.inner }
|
||||
|
||||
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<TcpStream> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn nodelay(&self) -> io::Result<bool> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn ttl(&self) -> io::Result<u32> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<Socket> for TcpStream {
|
||||
fn from_inner(socket: Socket) -> TcpStream {
|
||||
TcpStream { inner: socket }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for TcpStream {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "No networking support available on L4Re")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TcpListener {
|
||||
inner: Socket,
|
||||
}
|
||||
|
||||
impl TcpListener {
|
||||
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn socket(&self) -> &Socket { &self.inner }
|
||||
|
||||
pub fn into_socket(self) -> Socket { self.inner }
|
||||
|
||||
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<TcpListener> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn ttl(&self) -> io::Result<u32> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn only_v6(&self) -> io::Result<bool> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<Socket> for TcpListener {
|
||||
fn from_inner(socket: Socket) -> TcpListener {
|
||||
TcpListener { inner: socket }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for TcpListener {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "No networking support available on L4Re.")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UdpSocket {
|
||||
inner: Socket,
|
||||
}
|
||||
|
||||
impl UdpSocket {
|
||||
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn socket(&self) -> &Socket { &self.inner }
|
||||
|
||||
pub fn into_socket(self) -> Socket { self.inner }
|
||||
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<UdpSocket> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn broadcast(&self) -> io::Result<bool> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
|
||||
-> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
|
||||
-> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
|
||||
-> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
|
||||
-> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn ttl(&self) -> io::Result<u32> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn send(&self, _: &[u8]) -> io::Result<usize> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<Socket> for UdpSocket {
|
||||
fn from_inner(socket: Socket) -> UdpSocket {
|
||||
UdpSocket { inner: socket }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for UdpSocket {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "No networking support on L4Re available.")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LookupHost {
|
||||
original: *mut libc::addrinfo,
|
||||
cur: *mut libc::addrinfo,
|
||||
}
|
||||
|
||||
impl Iterator for LookupHost {
|
||||
type Item = SocketAddr;
|
||||
fn next(&mut self) -> Option<SocketAddr> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl LookupHost {
|
||||
pub fn port(&self) -> u16 {
|
||||
unimpl!();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for LookupHost {}
|
||||
unsafe impl Send for LookupHost {}
|
||||
|
||||
|
||||
impl TryFrom<&str> for LookupHost {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(_v: &str) -> io::Result<LookupHost> {
|
||||
unimpl!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
|
||||
unimpl!();
|
||||
}
|
||||
}
|
||||
}
|
@ -16,25 +16,6 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
}
|
||||
|
||||
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
// GNU's memrchr() will - unlike memchr() - error if haystack is empty.
|
||||
if haystack.is_empty() {return None}
|
||||
let p = unsafe {
|
||||
libc::memrchr(
|
||||
haystack.as_ptr() as *const libc::c_void,
|
||||
needle as libc::c_int,
|
||||
haystack.len())
|
||||
};
|
||||
if p.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(p as usize - (haystack.as_ptr() as usize))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
|
||||
core::slice::memchr::memrchr(needle, haystack)
|
||||
}
|
||||
|
@ -7,14 +7,8 @@ pub use crate::os::vxworks as platform;
|
||||
pub use self::rand::hashmap_random_keys;
|
||||
pub use libc::strlen;
|
||||
|
||||
#[macro_use]
|
||||
pub mod weak;
|
||||
|
||||
pub mod alloc;
|
||||
pub mod args;
|
||||
pub mod android;
|
||||
//#[cfg(feature = "backtrace")]
|
||||
//pub mod backtrace;
|
||||
pub mod cmath;
|
||||
pub mod condvar;
|
||||
pub mod env;
|
||||
@ -25,12 +19,7 @@ pub mod fs;
|
||||
pub mod memchr;
|
||||
pub mod io;
|
||||
pub mod mutex;
|
||||
#[cfg(not(target_os = "l4re"))]
|
||||
pub mod net;
|
||||
#[cfg(target_os = "l4re")]
|
||||
mod l4re;
|
||||
#[cfg(target_os = "l4re")]
|
||||
pub use self::l4re::net;
|
||||
pub mod os;
|
||||
pub mod path;
|
||||
pub mod pipe;
|
||||
@ -61,9 +50,6 @@ pub fn init() {
|
||||
unsafe fn reset_sigpipe() { }
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub use crate::sys::android::signal;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
pub use libc::signal;
|
||||
|
||||
pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
||||
|
@ -58,19 +58,6 @@ impl Socket {
|
||||
|
||||
pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
|
||||
unsafe {
|
||||
// On linux we first attempt to pass the SOCK_CLOEXEC flag to
|
||||
// atomically create the socket and set it as CLOEXEC. Support for
|
||||
// this option, however, was added in 2.6.27, and we still support
|
||||
// 2.6.18 as a kernel, so if the returned error is EINVAL we
|
||||
// fallthrough to the fallback.
|
||||
if cfg!(target_os = "linux") {
|
||||
match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
|
||||
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
|
||||
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
let fd = cvt(libc::socket(fam, ty, 0))?;
|
||||
let fd = FileDesc::new(fd);
|
||||
fd.set_cloexec()?;
|
||||
|
@ -422,46 +422,12 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// Android with api less than 21 define sig* functions inline, so it is not
|
||||
// available for dynamic link. Implementing sigemptyset and sigaddset allow us
|
||||
// to support older Android version (independent of libc version).
|
||||
// The following implementations are based on https://git.io/vSkNf
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
extern {
|
||||
#[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")]
|
||||
fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int;
|
||||
|
||||
#[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")]
|
||||
fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
|
||||
libc::memset(set as *mut _, 0, mem::size_of::<libc::sigset_t>());
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
|
||||
use crate::slice;
|
||||
|
||||
let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<libc::sigset_t>());
|
||||
let bit = (signum - 1) as usize;
|
||||
raw[bit / 8] |= 1 << (bit % 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// See #14232 for more information, but it appears that signal delivery to a
|
||||
// newly spawned process may just be raced in the macOS, so to prevent this
|
||||
// test from being flaky we ignore it on macOS.
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "macos", ignore)]
|
||||
// When run under our current QEMU emulation test suite this test fails,
|
||||
// although the reason isn't very clear as to why. For now this test is
|
||||
// ignored there.
|
||||
#[cfg_attr(target_arch = "arm", ignore)]
|
||||
#[cfg_attr(target_arch = "aarch64", ignore)]
|
||||
fn test_process_mask() {
|
||||
unsafe {
|
||||
// Test to make sure that a signal mask does not get inherited.
|
||||
|
@ -23,174 +23,6 @@ impl Drop for Handler {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "bitrig",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "solaris",
|
||||
all(target_os = "netbsd", not(target_vendor = "rumprun")),
|
||||
target_os = "openbsd"))]
|
||||
mod imp {
|
||||
use super::Handler;
|
||||
use crate::mem;
|
||||
use crate::ptr;
|
||||
|
||||
use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
|
||||
use libc::{sigaction, SIGBUS, SIG_DFL,
|
||||
SA_SIGINFO, SA_ONSTACK, sighandler_t};
|
||||
use libc::{mmap, munmap};
|
||||
use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON};
|
||||
use libc::MAP_FAILED;
|
||||
|
||||
use crate::sys_common::thread_info;
|
||||
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
|
||||
#[repr(C)]
|
||||
struct siginfo_t {
|
||||
a: [libc::c_int; 3], // si_signo, si_errno, si_code
|
||||
si_addr: *mut libc::c_void,
|
||||
}
|
||||
|
||||
(*(info as *const siginfo_t)).si_addr as usize
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
|
||||
(*info).si_addr as usize
|
||||
}
|
||||
|
||||
// Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
|
||||
// (unmapped pages) at the end of every thread's stack, so if a thread ends
|
||||
// up running into the guard page it'll trigger this handler. We want to
|
||||
// detect these cases and print out a helpful error saying that the stack
|
||||
// has overflowed. All other signals, however, should go back to what they
|
||||
// were originally supposed to do.
|
||||
//
|
||||
// This handler currently exists purely to print an informative message
|
||||
// whenever a thread overflows its stack. We then abort to exit and
|
||||
// indicate a crash, but to avoid a misleading SIGSEGV that might lead
|
||||
// users to believe that unsafe code has accessed an invalid pointer; the
|
||||
// SIGSEGV encountered when overflowing the stack is expected and
|
||||
// well-defined.
|
||||
//
|
||||
// If this is not a stack overflow, the handler un-registers itself and
|
||||
// then returns (to allow the original signal to be delivered again).
|
||||
// Returning from this kind of signal handler is technically not defined
|
||||
// to work when reading the POSIX spec strictly, but in practice it turns
|
||||
// out many large systems and all implementations allow returning from a
|
||||
// signal handler to work. For a more detailed explanation see the
|
||||
// comments on #26458.
|
||||
unsafe extern fn signal_handler(signum: libc::c_int,
|
||||
info: *mut libc::siginfo_t,
|
||||
_data: *mut libc::c_void) {
|
||||
use crate::sys_common::util::report_overflow;
|
||||
|
||||
let guard = thread_info::stack_guard().unwrap_or(0..0);
|
||||
let addr = siginfo_si_addr(info);
|
||||
|
||||
// If the faulting address is within the guard page, then we print a
|
||||
// message saying so and abort.
|
||||
if guard.start <= addr && addr < guard.end {
|
||||
report_overflow();
|
||||
rtabort!("stack overflow");
|
||||
} else {
|
||||
// Unregister ourselves by reverting back to the default behavior.
|
||||
let mut action: sigaction = mem::zeroed();
|
||||
action.sa_sigaction = SIG_DFL;
|
||||
sigaction(signum, &action, ptr::null_mut());
|
||||
|
||||
// See comment above for why this function returns.
|
||||
}
|
||||
}
|
||||
|
||||
static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
|
||||
|
||||
pub unsafe fn init() {
|
||||
let mut action: sigaction = mem::zeroed();
|
||||
action.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
action.sa_sigaction = signal_handler as sighandler_t;
|
||||
sigaction(SIGSEGV, &action, ptr::null_mut());
|
||||
sigaction(SIGBUS, &action, ptr::null_mut());
|
||||
|
||||
let handler = make_handler();
|
||||
MAIN_ALTSTACK = handler._data;
|
||||
mem::forget(handler);
|
||||
}
|
||||
|
||||
pub unsafe fn cleanup() {
|
||||
Handler { _data: MAIN_ALTSTACK };
|
||||
}
|
||||
|
||||
unsafe fn get_stackp() -> *mut libc::c_void {
|
||||
let stackp = mmap(ptr::null_mut(),
|
||||
SIGSTKSZ,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON,
|
||||
-1,
|
||||
0);
|
||||
if stackp == MAP_FAILED {
|
||||
panic!("failed to allocate an alternative stack");
|
||||
}
|
||||
stackp
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "bitrig",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "solaris"))]
|
||||
unsafe fn get_stack() -> libc::stack_t {
|
||||
libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
|
||||
}
|
||||
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
unsafe fn get_stack() -> libc::stack_t {
|
||||
libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
|
||||
}
|
||||
|
||||
pub unsafe fn make_handler() -> Handler {
|
||||
let mut stack = mem::zeroed();
|
||||
sigaltstack(ptr::null(), &mut stack);
|
||||
// Configure alternate signal stack, if one is not already set.
|
||||
if stack.ss_flags & SS_DISABLE != 0 {
|
||||
stack = get_stack();
|
||||
sigaltstack(&stack, ptr::null_mut());
|
||||
Handler { _data: stack.ss_sp as *mut libc::c_void }
|
||||
} else {
|
||||
Handler { _data: ptr::null_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn drop_handler(handler: &mut Handler) {
|
||||
if !handler._data.is_null() {
|
||||
let stack = libc::stack_t {
|
||||
ss_sp: ptr::null_mut(),
|
||||
ss_flags: SS_DISABLE,
|
||||
// Workaround for bug in macOS implementation of sigaltstack
|
||||
// UNIX2003 which returns ENOMEM when disabling a stack while
|
||||
// passing ss_size smaller than MINSIGSTKSZ. According to POSIX
|
||||
// both ss_sp and ss_size should be ignored in this case.
|
||||
ss_size: SIGSTKSZ,
|
||||
};
|
||||
sigaltstack(&stack, ptr::null_mut());
|
||||
munmap(handler._data, SIGSTKSZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "bitrig",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "solaris",
|
||||
all(target_os = "netbsd", not(target_vendor = "rumprun")),
|
||||
target_os = "openbsd")))]
|
||||
mod imp {
|
||||
use crate::ptr;
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
//use crate::boxed::FnBox;
|
||||
use crate::cmp;
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
@ -9,10 +8,7 @@ use crate::time::Duration;
|
||||
|
||||
use crate::sys_common::thread::*;
|
||||
|
||||
#[cfg(not(target_os = "l4re"))]
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
|
||||
#[cfg(target_os = "l4re")]
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
pub struct Thread {
|
||||
id: libc::pthread_t,
|
||||
@ -25,18 +21,11 @@ unsafe impl Sync for Thread {}
|
||||
|
||||
// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc,
|
||||
// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS.
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
unsafe fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
|
||||
stack_size: libc::size_t) -> libc::c_int {
|
||||
libc::pthread_attr_setstacksize(attr, stack_size)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "emscripten")]
|
||||
unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t,
|
||||
_stack_size: libc::size_t) -> libc::c_int {
|
||||
panic!()
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>)
|
||||
@ -149,31 +138,6 @@ pub mod guard {
|
||||
pub unsafe fn deinit() {}
|
||||
}
|
||||
|
||||
// glibc >= 2.15 has a __pthread_get_minstack() function that returns
|
||||
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
|
||||
// storage. We need that information to avoid blowing up when a small stack
|
||||
// is created in an application with big thread-local storage requirements.
|
||||
// See #6233 for rationale and details.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[allow(deprecated)]
|
||||
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
|
||||
weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
|
||||
|
||||
match __pthread_get_minstack.get() {
|
||||
None => libc::PTHREAD_STACK_MIN,
|
||||
Some(f) => unsafe { f(attr) },
|
||||
}
|
||||
}
|
||||
|
||||
// No point in looking up __pthread_get_minstack() on non-glibc
|
||||
// platforms.
|
||||
#[cfg(all(not(target_os = "linux"),
|
||||
not(target_os = "netbsd")))]
|
||||
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
|
||||
libc::PTHREAD_STACK_MIN
|
||||
}
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
|
||||
2048 // just a guess
|
||||
}
|
||||
|
@ -437,6 +437,33 @@ pub trait MetadataExt {
|
||||
/// ```
|
||||
#[stable(feature = "metadata_ext", since = "1.1.0")]
|
||||
fn file_size(&self) -> u64;
|
||||
|
||||
/// Returns the value of the `dwVolumeSerialNumber` field of this
|
||||
/// metadata.
|
||||
///
|
||||
/// This will return `None` if the `Metadata` instance was created from a
|
||||
/// call to `DirEntry::metadata`. If this `Metadata` was created by using
|
||||
/// `fs::metadata` or `File::metadata`, then this will return `Some`.
|
||||
#[unstable(feature = "windows_by_handle", issue = "63010")]
|
||||
fn volume_serial_number(&self) -> Option<u32>;
|
||||
|
||||
/// Returns the value of the `nNumberOfLinks` field of this
|
||||
/// metadata.
|
||||
///
|
||||
/// This will return `None` if the `Metadata` instance was created from a
|
||||
/// call to `DirEntry::metadata`. If this `Metadata` was created by using
|
||||
/// `fs::metadata` or `File::metadata`, then this will return `Some`.
|
||||
#[unstable(feature = "windows_by_handle", issue = "63010")]
|
||||
fn number_of_links(&self) -> Option<u32>;
|
||||
|
||||
/// Returns the value of the `nFileIndex{Low,High}` fields of this
|
||||
/// metadata.
|
||||
///
|
||||
/// This will return `None` if the `Metadata` instance was created from a
|
||||
/// call to `DirEntry::metadata`. If this `Metadata` was created by using
|
||||
/// `fs::metadata` or `File::metadata`, then this will return `Some`.
|
||||
#[unstable(feature = "windows_by_handle", issue = "63010")]
|
||||
fn file_index(&self) -> Option<u64>;
|
||||
}
|
||||
|
||||
#[stable(feature = "metadata_ext", since = "1.1.0")]
|
||||
@ -446,6 +473,9 @@ impl MetadataExt for Metadata {
|
||||
fn last_access_time(&self) -> u64 { self.as_inner().accessed_u64() }
|
||||
fn last_write_time(&self) -> u64 { self.as_inner().modified_u64() }
|
||||
fn file_size(&self) -> u64 { self.as_inner().size() }
|
||||
fn volume_serial_number(&self) -> Option<u32> { self.as_inner().volume_serial_number() }
|
||||
fn number_of_links(&self) -> Option<u32> { self.as_inner().number_of_links() }
|
||||
fn file_index(&self) -> Option<u64> { self.as_inner().file_index() }
|
||||
}
|
||||
|
||||
/// Windows-specific extensions to [`FileType`].
|
||||
|
@ -25,6 +25,9 @@ pub struct FileAttr {
|
||||
last_write_time: c::FILETIME,
|
||||
file_size: u64,
|
||||
reparse_tag: c::DWORD,
|
||||
volume_serial_number: Option<u32>,
|
||||
number_of_links: Option<u32>,
|
||||
file_index: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
@ -156,6 +159,9 @@ impl DirEntry {
|
||||
} else {
|
||||
0
|
||||
},
|
||||
volume_serial_number: None,
|
||||
number_of_links: None,
|
||||
file_index: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -291,23 +297,26 @@ impl File {
|
||||
pub fn file_attr(&self) -> io::Result<FileAttr> {
|
||||
unsafe {
|
||||
let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed();
|
||||
cvt(c::GetFileInformationByHandle(self.handle.raw(),
|
||||
&mut info))?;
|
||||
let mut attr = FileAttr {
|
||||
cvt(c::GetFileInformationByHandle(self.handle.raw(), &mut info))?;
|
||||
let mut reparse_tag = 0;
|
||||
if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
|
||||
let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
||||
if let Ok((_, buf)) = self.reparse_point(&mut b) {
|
||||
reparse_tag = buf.ReparseTag;
|
||||
}
|
||||
}
|
||||
Ok(FileAttr {
|
||||
attributes: info.dwFileAttributes,
|
||||
creation_time: info.ftCreationTime,
|
||||
last_access_time: info.ftLastAccessTime,
|
||||
last_write_time: info.ftLastWriteTime,
|
||||
file_size: ((info.nFileSizeHigh as u64) << 32) | (info.nFileSizeLow as u64),
|
||||
reparse_tag: 0,
|
||||
};
|
||||
if attr.is_reparse_point() {
|
||||
let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
||||
if let Ok((_, buf)) = self.reparse_point(&mut b) {
|
||||
attr.reparse_tag = buf.ReparseTag;
|
||||
}
|
||||
}
|
||||
Ok(attr)
|
||||
file_size: (info.nFileSizeLow as u64) | ((info.nFileSizeHigh as u64) << 32),
|
||||
reparse_tag,
|
||||
volume_serial_number: Some(info.dwVolumeSerialNumber),
|
||||
number_of_links: Some(info.nNumberOfLinks),
|
||||
file_index: Some((info.nFileIndexLow as u64) |
|
||||
((info.nFileIndexHigh as u64) << 32)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,6 +345,9 @@ impl File {
|
||||
},
|
||||
file_size: 0,
|
||||
reparse_tag: 0,
|
||||
volume_serial_number: None,
|
||||
number_of_links: None,
|
||||
file_index: None,
|
||||
};
|
||||
let mut info: c::FILE_STANDARD_INFO = mem::zeroed();
|
||||
let size = mem::size_of_val(&info);
|
||||
@ -344,6 +356,7 @@ impl File {
|
||||
&mut info as *mut _ as *mut libc::c_void,
|
||||
size as c::DWORD))?;
|
||||
attr.file_size = info.AllocationSize as u64;
|
||||
attr.number_of_links = Some(info.NumberOfLinks);
|
||||
if attr.is_reparse_point() {
|
||||
let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
||||
if let Ok((_, buf)) = self.reparse_point(&mut b) {
|
||||
@ -507,7 +520,9 @@ impl FileAttr {
|
||||
FilePermissions { attrs: self.attributes }
|
||||
}
|
||||
|
||||
pub fn attrs(&self) -> u32 { self.attributes as u32 }
|
||||
pub fn attrs(&self) -> u32 {
|
||||
self.attributes
|
||||
}
|
||||
|
||||
pub fn file_type(&self) -> FileType {
|
||||
FileType::new(self.attributes, self.reparse_tag)
|
||||
@ -537,8 +552,16 @@ impl FileAttr {
|
||||
to_u64(&self.creation_time)
|
||||
}
|
||||
|
||||
fn is_reparse_point(&self) -> bool {
|
||||
self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0
|
||||
pub fn volume_serial_number(&self) -> Option<u32> {
|
||||
self.volume_serial_number
|
||||
}
|
||||
|
||||
pub fn number_of_links(&self) -> Option<u32> {
|
||||
self.number_of_links
|
||||
}
|
||||
|
||||
pub fn file_index(&self) -> Option<u64> {
|
||||
self.file_index
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,6 @@ use rustc_data_structures::sync::Lrc;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
|
||||
// To avoid costly uniqueness checks, we require that `MatchSeq` always has a nonempty body.
|
||||
|
||||
@ -280,7 +279,7 @@ pub enum ParseResult<T> {
|
||||
|
||||
/// A `ParseResult` where the `Success` variant contains a mapping of `Ident`s to `NamedMatch`es.
|
||||
/// This represents the mapping of metavars to the token trees they bind to.
|
||||
pub type NamedParseResult = ParseResult<FxHashMap<Ident, Rc<NamedMatch>>>;
|
||||
pub type NamedParseResult = ParseResult<FxHashMap<Ident, NamedMatch>>;
|
||||
|
||||
/// Count how many metavars are named in the given matcher `ms`.
|
||||
pub fn count_names(ms: &[TokenTree]) -> usize {
|
||||
@ -373,7 +372,7 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
|
||||
sess: &ParseSess,
|
||||
m: &TokenTree,
|
||||
res: &mut I,
|
||||
ret_val: &mut FxHashMap<Ident, Rc<NamedMatch>>,
|
||||
ret_val: &mut FxHashMap<Ident, NamedMatch>,
|
||||
) -> Result<(), (syntax_pos::Span, String)> {
|
||||
match *m {
|
||||
TokenTree::Sequence(_, ref seq) => for next_m in &seq.tts {
|
||||
@ -390,8 +389,7 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
|
||||
TokenTree::MetaVarDecl(sp, bind_name, _) => {
|
||||
match ret_val.entry(bind_name) {
|
||||
Vacant(spot) => {
|
||||
// FIXME(simulacrum): Don't construct Rc here
|
||||
spot.insert(Rc::new(res.next().unwrap()));
|
||||
spot.insert(res.next().unwrap());
|
||||
}
|
||||
Occupied(..) => {
|
||||
return Err((sp, format!("duplicated bind name: {}", bind_name)))
|
||||
|
@ -308,7 +308,7 @@ pub fn compile(
|
||||
let mut valid = true;
|
||||
|
||||
// Extract the arguments:
|
||||
let lhses = match *argument_map[&lhs_nm] {
|
||||
let lhses = match argument_map[&lhs_nm] {
|
||||
MatchedSeq(ref s, _) => s
|
||||
.iter()
|
||||
.map(|m| {
|
||||
@ -335,7 +335,7 @@ pub fn compile(
|
||||
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
|
||||
};
|
||||
|
||||
let rhses = match *argument_map[&rhs_nm] {
|
||||
let rhses = match argument_map[&rhs_nm] {
|
||||
MatchedSeq(ref s, _) => s
|
||||
.iter()
|
||||
.map(|m| {
|
||||
@ -625,38 +625,37 @@ impl FirstSets {
|
||||
return first;
|
||||
}
|
||||
TokenTree::Sequence(sp, ref seq_rep) => {
|
||||
match self.first.get(&sp.entire()) {
|
||||
Some(&Some(ref subfirst)) => {
|
||||
// If the sequence contents can be empty, then the first
|
||||
// token could be the separator token itself.
|
||||
|
||||
if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) {
|
||||
first.add_one_maybe(TokenTree::Token(sep.clone()));
|
||||
}
|
||||
|
||||
assert!(first.maybe_empty);
|
||||
first.add_all(subfirst);
|
||||
if subfirst.maybe_empty
|
||||
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
|
||||
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
|
||||
{
|
||||
// continue scanning for more first
|
||||
// tokens, but also make sure we
|
||||
// restore empty-tracking state
|
||||
first.maybe_empty = true;
|
||||
continue;
|
||||
} else {
|
||||
return first;
|
||||
}
|
||||
}
|
||||
|
||||
let subfirst_owned;
|
||||
let subfirst = match self.first.get(&sp.entire()) {
|
||||
Some(&Some(ref subfirst)) => subfirst,
|
||||
Some(&None) => {
|
||||
panic!("assume all sequences have (unique) spans for now");
|
||||
subfirst_owned = self.first(&seq_rep.tts[..]);
|
||||
&subfirst_owned
|
||||
}
|
||||
|
||||
None => {
|
||||
panic!("We missed a sequence during FirstSets construction");
|
||||
}
|
||||
};
|
||||
|
||||
// If the sequence contents can be empty, then the first
|
||||
// token could be the separator token itself.
|
||||
if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) {
|
||||
first.add_one_maybe(TokenTree::Token(sep.clone()));
|
||||
}
|
||||
|
||||
assert!(first.maybe_empty);
|
||||
first.add_all(subfirst);
|
||||
if subfirst.maybe_empty
|
||||
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrMore
|
||||
|| seq_rep.kleene.op == quoted::KleeneOp::ZeroOrOne
|
||||
{
|
||||
// Continue scanning for more first
|
||||
// tokens, but also make sure we
|
||||
// restore empty-tracking state.
|
||||
first.maybe_empty = true;
|
||||
continue;
|
||||
} else {
|
||||
return first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ use smallvec::{smallvec, SmallVec};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
|
||||
enum Frame {
|
||||
@ -65,9 +64,9 @@ impl Iterator for Frame {
|
||||
/// `transcribe` would return a `TokenStream` containing `println!("{}", stringify!(bar));`.
|
||||
///
|
||||
/// Along the way, we do some additional error checking.
|
||||
pub fn transcribe(
|
||||
pub(super) fn transcribe(
|
||||
cx: &ExtCtxt<'_>,
|
||||
interp: &FxHashMap<Ident, Rc<NamedMatch>>,
|
||||
interp: &FxHashMap<Ident, NamedMatch>,
|
||||
src: Vec<quoted::TokenTree>,
|
||||
) -> TokenStream {
|
||||
// Nothing for us to transcribe...
|
||||
@ -212,7 +211,7 @@ pub fn transcribe(
|
||||
// Find the matched nonterminal from the macro invocation, and use it to replace
|
||||
// the meta-var.
|
||||
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
|
||||
if let MatchedNonterminal(ref nt) = *cur_matched {
|
||||
if let MatchedNonterminal(ref nt) = cur_matched {
|
||||
// FIXME #2887: why do we apply a mark when matching a token tree meta-var
|
||||
// (e.g. `$x:tt`), but not when we are matching any other type of token
|
||||
// tree?
|
||||
@ -273,18 +272,17 @@ pub fn transcribe(
|
||||
/// See the definition of `repeats` in the `transcribe` function. `repeats` is used to descend
|
||||
/// into the right place in nested matchers. If we attempt to descend too far, the macro writer has
|
||||
/// made a mistake, and we return `None`.
|
||||
fn lookup_cur_matched(
|
||||
fn lookup_cur_matched<'a>(
|
||||
ident: Ident,
|
||||
interpolations: &FxHashMap<Ident, Rc<NamedMatch>>,
|
||||
interpolations: &'a FxHashMap<Ident, NamedMatch>,
|
||||
repeats: &[(usize, usize)],
|
||||
) -> Option<Rc<NamedMatch>> {
|
||||
) -> Option<&'a NamedMatch> {
|
||||
interpolations.get(&ident).map(|matched| {
|
||||
let mut matched = matched.clone();
|
||||
let mut matched = matched;
|
||||
for &(idx, _) in repeats {
|
||||
let m = matched.clone();
|
||||
match *m {
|
||||
match matched {
|
||||
MatchedNonterminal(_) => break,
|
||||
MatchedSeq(ref ads, _) => matched = Rc::new(ads[idx].clone()),
|
||||
MatchedSeq(ref ads, _) => matched = ads.get(idx).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,7 +341,7 @@ impl LockstepIterSize {
|
||||
/// multiple nested matcher sequences.
|
||||
fn lockstep_iter_size(
|
||||
tree: "ed::TokenTree,
|
||||
interpolations: &FxHashMap<Ident, Rc<NamedMatch>>,
|
||||
interpolations: &FxHashMap<Ident, NamedMatch>,
|
||||
repeats: &[(usize, usize)],
|
||||
) -> LockstepIterSize {
|
||||
use quoted::TokenTree;
|
||||
@ -360,7 +358,7 @@ fn lockstep_iter_size(
|
||||
}
|
||||
TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => {
|
||||
match lookup_cur_matched(name, interpolations, repeats) {
|
||||
Some(matched) => match *matched {
|
||||
Some(matched) => match matched {
|
||||
MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
|
||||
MatchedSeq(ref ads, _) => LockstepIterSize::Constraint(ads.len(), name),
|
||||
},
|
||||
|
@ -389,8 +389,18 @@ impl<'a> StringReader<'a> {
|
||||
self.pos,
|
||||
"unknown start of token",
|
||||
c);
|
||||
unicode_chars::check_for_substitution(self, start, c, &mut err);
|
||||
return Err(err)
|
||||
// FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs,
|
||||
// instead of keeping a table in `check_for_substitution`into the token. Ideally,
|
||||
// this should be inside `rustc_lexer`. However, we should first remove compound
|
||||
// tokens like `<<` from `rustc_lexer`, and then add fancier error recovery to it,
|
||||
// as there will be less overall work to do this way.
|
||||
return match unicode_chars::check_for_substitution(self, start, c, &mut err) {
|
||||
Some(token) => {
|
||||
err.emit();
|
||||
Ok(token)
|
||||
}
|
||||
None => Err(err),
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(kind)
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
use super::StringReader;
|
||||
use errors::{Applicability, DiagnosticBuilder};
|
||||
use syntax_pos::{BytePos, Pos, Span, NO_EXPANSION};
|
||||
use syntax_pos::{BytePos, Pos, Span, NO_EXPANSION, symbol::kw};
|
||||
use crate::parse::token;
|
||||
|
||||
#[rustfmt::skip] // for line breaks
|
||||
const UNICODE_ARRAY: &[(char, &str, char)] = &[
|
||||
@ -297,32 +298,38 @@ const UNICODE_ARRAY: &[(char, &str, char)] = &[
|
||||
('>', "Fullwidth Greater-Than Sign", '>'),
|
||||
];
|
||||
|
||||
const ASCII_ARRAY: &[(char, &str)] = &[
|
||||
(' ', "Space"),
|
||||
('_', "Underscore"),
|
||||
('-', "Minus/Hyphen"),
|
||||
(',', "Comma"),
|
||||
(';', "Semicolon"),
|
||||
(':', "Colon"),
|
||||
('!', "Exclamation Mark"),
|
||||
('?', "Question Mark"),
|
||||
('.', "Period"),
|
||||
('\'', "Single Quote"),
|
||||
('"', "Quotation Mark"),
|
||||
('(', "Left Parenthesis"),
|
||||
(')', "Right Parenthesis"),
|
||||
('[', "Left Square Bracket"),
|
||||
(']', "Right Square Bracket"),
|
||||
('{', "Left Curly Brace"),
|
||||
('}', "Right Curly Brace"),
|
||||
('*', "Asterisk"),
|
||||
('/', "Slash"),
|
||||
('\\', "Backslash"),
|
||||
('&', "Ampersand"),
|
||||
('+', "Plus Sign"),
|
||||
('<', "Less-Than Sign"),
|
||||
('=', "Equals Sign"),
|
||||
('>', "Greater-Than Sign"),
|
||||
// FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs, instead of
|
||||
// keeping the substitution token in this table. Ideally, this should be inside `rustc_lexer`.
|
||||
// However, we should first remove compound tokens like `<<` from `rustc_lexer`, and then add
|
||||
// fancier error recovery to it, as there will be less overall work to do this way.
|
||||
const ASCII_ARRAY: &[(char, &str, Option<token::TokenKind>)] = &[
|
||||
(' ', "Space", Some(token::Whitespace)),
|
||||
('_', "Underscore", Some(token::Ident(kw::Underscore, false))),
|
||||
('-', "Minus/Hyphen", Some(token::BinOp(token::Minus))),
|
||||
(',', "Comma", Some(token::Comma)),
|
||||
(';', "Semicolon", Some(token::Semi)),
|
||||
(':', "Colon", Some(token::Colon)),
|
||||
('!', "Exclamation Mark", Some(token::Not)),
|
||||
('?', "Question Mark", Some(token::Question)),
|
||||
('.', "Period", Some(token::Dot)),
|
||||
('(', "Left Parenthesis", Some(token::OpenDelim(token::Paren))),
|
||||
(')', "Right Parenthesis", Some(token::CloseDelim(token::Paren))),
|
||||
('[', "Left Square Bracket", Some(token::OpenDelim(token::Bracket))),
|
||||
(']', "Right Square Bracket", Some(token::CloseDelim(token::Bracket))),
|
||||
('{', "Left Curly Brace", Some(token::OpenDelim(token::Brace))),
|
||||
('}', "Right Curly Brace", Some(token::CloseDelim(token::Brace))),
|
||||
('*', "Asterisk", Some(token::BinOp(token::Star))),
|
||||
('/', "Slash", Some(token::BinOp(token::Slash))),
|
||||
('\\', "Backslash", None),
|
||||
('&', "Ampersand", Some(token::BinOp(token::And))),
|
||||
('+', "Plus Sign", Some(token::BinOp(token::Plus))),
|
||||
('<', "Less-Than Sign", Some(token::Lt)),
|
||||
('=', "Equals Sign", Some(token::Eq)),
|
||||
('>', "Greater-Than Sign", Some(token::Gt)),
|
||||
// FIXME: Literals are already lexed by this point, so we can't recover gracefully just by
|
||||
// spitting the correct token out.
|
||||
('\'', "Single Quote", None),
|
||||
('"', "Quotation Mark", None),
|
||||
];
|
||||
|
||||
crate fn check_for_substitution<'a>(
|
||||
@ -330,20 +337,20 @@ crate fn check_for_substitution<'a>(
|
||||
pos: BytePos,
|
||||
ch: char,
|
||||
err: &mut DiagnosticBuilder<'a>,
|
||||
) -> bool {
|
||||
) -> Option<token::TokenKind> {
|
||||
let (u_name, ascii_char) = match UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch) {
|
||||
Some(&(_u_char, u_name, ascii_char)) => (u_name, ascii_char),
|
||||
None => return false,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let span = Span::new(pos, pos + Pos::from_usize(ch.len_utf8()), NO_EXPANSION);
|
||||
|
||||
let ascii_name = match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) {
|
||||
Some((_ascii_char, ascii_name)) => ascii_name,
|
||||
let (ascii_name, token) = match ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) {
|
||||
Some((_ascii_char, ascii_name, token)) => (ascii_name, token),
|
||||
None => {
|
||||
let msg = format!("substitution character not found for '{}'", ch);
|
||||
reader.sess.span_diagnostic.span_bug_no_panic(span, &msg);
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
@ -371,7 +378,7 @@ crate fn check_for_substitution<'a>(
|
||||
);
|
||||
err.span_suggestion(span, &msg, ascii_char.to_string(), Applicability::MaybeIncorrect);
|
||||
}
|
||||
true
|
||||
token.clone()
|
||||
}
|
||||
|
||||
/// Extract string if found at current position with given delimiters
|
||||
|
@ -1,226 +0,0 @@
|
||||
// asmjs can't even pass i128 as arguments or return values, so ignore it.
|
||||
// this will hopefully be fixed by the LLVM 5 upgrade (#43370)
|
||||
// ignore-asmjs
|
||||
// ignore-emscripten
|
||||
|
||||
// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=yes
|
||||
|
||||
static TEST_SIGNED: i128 = const_signed(-222);
|
||||
static TEST_UNSIGNED: u128 = const_unsigned(200);
|
||||
|
||||
const fn const_signed(mut x: i128) -> i128 {
|
||||
((((((x + 1) - 2) * 3) / 4) % 5) << 6) >> 7
|
||||
}
|
||||
|
||||
const fn const_unsigned(mut x: u128) -> u128 {
|
||||
((((((x + 1) - 2) * 3) / 4) % 5) << 6) >> 7
|
||||
}
|
||||
|
||||
fn test_signed(mut x: i128) -> i128 {
|
||||
x += 1;
|
||||
x -= 2;
|
||||
x *= 3;
|
||||
x /= 4;
|
||||
x %= 5;
|
||||
x <<= 6;
|
||||
x >>= 7;
|
||||
x
|
||||
}
|
||||
|
||||
fn test_unsigned(mut x: u128) -> u128 {
|
||||
x += 1;
|
||||
x -= 2;
|
||||
x *= 3;
|
||||
x /= 4;
|
||||
x %= 5;
|
||||
x <<= 6;
|
||||
x >>= 7;
|
||||
x
|
||||
}
|
||||
|
||||
fn check(x: i128, y: u128) {
|
||||
assert_eq!(test_signed(x), -1);
|
||||
assert_eq!(const_signed(x), -1);
|
||||
assert_eq!(TEST_SIGNED, -1);
|
||||
assert_eq!(test_unsigned(y), 2);
|
||||
assert_eq!(const_unsigned(y), 2);
|
||||
assert_eq!(TEST_UNSIGNED, 2);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
check(-222, 200);
|
||||
}
|
||||
|
||||
// END RUST SOURCE
|
||||
|
||||
// START rustc.const_signed.Lower128Bit.after.mir
|
||||
// _8 = _1;
|
||||
// _9 = const compiler_builtins::int::addsub::rust_i128_addo(move _8, const 1i128) -> bb10;
|
||||
// ...
|
||||
// _7 = move (_9.0: i128);
|
||||
// ...
|
||||
// _10 = const compiler_builtins::int::addsub::rust_i128_subo(move _7, const 2i128) -> bb11;
|
||||
// ...
|
||||
// _6 = move (_10.0: i128);
|
||||
// ...
|
||||
// _11 = const compiler_builtins::int::mul::rust_i128_mulo(move _6, const 3i128) -> bb12;
|
||||
// ...
|
||||
// _5 = move (_11.0: i128);
|
||||
// ...
|
||||
// _12 = Eq(const 4i128, const 0i128);
|
||||
// assert(!move _12, "attempt to divide by zero") -> bb4;
|
||||
// ...
|
||||
// _13 = Eq(const 4i128, const -1i128);
|
||||
// _14 = Eq(_5, const -170141183460469231731687303715884105728i128);
|
||||
// _15 = BitAnd(move _13, move _14);
|
||||
// assert(!move _15, "attempt to divide with overflow") -> bb5;
|
||||
// ...
|
||||
// _4 = const compiler_builtins::int::sdiv::rust_i128_div(move _5, const 4i128) -> bb13;
|
||||
// ...
|
||||
// _17 = Eq(const 5i128, const -1i128);
|
||||
// _18 = Eq(_4, const -170141183460469231731687303715884105728i128);
|
||||
// _19 = BitAnd(move _17, move _18);
|
||||
// assert(!move _19, "attempt to calculate the remainder with overflow") -> bb7;
|
||||
// ...
|
||||
// _3 = const compiler_builtins::int::sdiv::rust_i128_rem(move _4, const 5i128) -> bb15;
|
||||
// ...
|
||||
// _2 = move (_20.0: i128);
|
||||
// ...
|
||||
// _23 = const 7i32 as u128 (Misc);
|
||||
// _21 = const compiler_builtins::int::shift::rust_i128_shro(move _2, move _23) -> bb16;
|
||||
// ...
|
||||
// _0 = move (_21.0: i128);
|
||||
// ...
|
||||
// assert(!move (_9.1: bool), "attempt to add with overflow") -> bb1;
|
||||
// ...
|
||||
// assert(!move (_10.1: bool), "attempt to subtract with overflow") -> bb2;
|
||||
// ...
|
||||
// assert(!move (_11.1: bool), "attempt to multiply with overflow") -> bb3;
|
||||
// ...
|
||||
// _16 = Eq(const 5i128, const 0i128);
|
||||
// assert(!move _16, "attempt to calculate the remainder with a divisor of zero") -> bb6;
|
||||
// ...
|
||||
// assert(!move (_20.1: bool), "attempt to shift left with overflow") -> bb8;
|
||||
// ...
|
||||
// _22 = const 6i32 as u128 (Misc);
|
||||
// _20 = const compiler_builtins::int::shift::rust_i128_shlo(move _3, move _22) -> bb14;
|
||||
// ...
|
||||
// assert(!move (_21.1: bool), "attempt to shift right with overflow") -> bb9;
|
||||
// END rustc.const_signed.Lower128Bit.after.mir
|
||||
|
||||
// START rustc.const_unsigned.Lower128Bit.after.mir
|
||||
// _8 = _1;
|
||||
// _9 = const compiler_builtins::int::addsub::rust_u128_addo(move _8, const 1u128) -> bb8;
|
||||
// ...
|
||||
// _7 = move (_9.0: u128);
|
||||
// ...
|
||||
// _10 = const compiler_builtins::int::addsub::rust_u128_subo(move _7, const 2u128) -> bb9;
|
||||
// ...
|
||||
// _6 = move (_10.0: u128);
|
||||
// ...
|
||||
// _11 = const compiler_builtins::int::mul::rust_u128_mulo(move _6, const 3u128) -> bb10;
|
||||
// ...
|
||||
// _5 = move (_11.0: u128);
|
||||
// ...
|
||||
// _12 = Eq(const 4u128, const 0u128);
|
||||
// assert(!move _12, "attempt to divide by zero") -> bb4;
|
||||
// ...
|
||||
// _4 = const compiler_builtins::int::udiv::rust_u128_div(move _5, const 4u128) -> bb11;
|
||||
// ...
|
||||
// _3 = const compiler_builtins::int::udiv::rust_u128_rem(move _4, const 5u128) -> bb13;
|
||||
// ...
|
||||
// _2 = move (_14.0: u128);
|
||||
// ...
|
||||
// _17 = const 7i32 as u128 (Misc);
|
||||
// _15 = const compiler_builtins::int::shift::rust_u128_shro(move _2, move _17) -> bb14;
|
||||
// ...
|
||||
// _0 = move (_15.0: u128);
|
||||
// ...
|
||||
// assert(!move (_9.1: bool), "attempt to add with overflow") -> bb1;
|
||||
// ...
|
||||
// assert(!move (_10.1: bool), "attempt to subtract with overflow") -> bb2;
|
||||
// ...
|
||||
// assert(!move (_11.1: bool), "attempt to multiply with overflow") -> bb3;
|
||||
// ...
|
||||
// _13 = Eq(const 5u128, const 0u128);
|
||||
// assert(!move _13, "attempt to calculate the remainder with a divisor of zero") -> bb5;
|
||||
// ...
|
||||
// assert(!move (_14.1: bool), "attempt to shift left with overflow") -> bb6;
|
||||
// ...
|
||||
// _16 = const 6i32 as u128 (Misc);
|
||||
// _14 = const compiler_builtins::int::shift::rust_u128_shlo(move _3, move _16) -> bb12;
|
||||
// ...
|
||||
// assert(!move (_15.1: bool), "attempt to shift right with overflow") -> bb7;
|
||||
// END rustc.const_unsigned.Lower128Bit.after.mir
|
||||
|
||||
// START rustc.test_signed.Lower128Bit.after.mir
|
||||
// _2 = const compiler_builtins::int::addsub::rust_i128_addo(_1, const 1i128) -> bb10;
|
||||
// ...
|
||||
// _1 = move (_2.0: i128);
|
||||
// _3 = const compiler_builtins::int::addsub::rust_i128_subo(_1, const 2i128) -> bb11;
|
||||
// ...
|
||||
// _1 = move (_3.0: i128);
|
||||
// _4 = const compiler_builtins::int::mul::rust_i128_mulo(_1, const 3i128) -> bb12;
|
||||
// ...
|
||||
// _1 = move (_4.0: i128);
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::sdiv::rust_i128_div(_1, const 4i128) -> bb13;
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::sdiv::rust_i128_rem(_1, const 5i128) -> bb15;
|
||||
// ...
|
||||
// _1 = move (_13.0: i128);
|
||||
// ...
|
||||
// _16 = const 7i32 as u128 (Misc);
|
||||
// _14 = const compiler_builtins::int::shift::rust_i128_shro(_1, move _16) -> bb16;
|
||||
// ...
|
||||
// _1 = move (_14.0: i128);
|
||||
// ...
|
||||
// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
|
||||
// ...
|
||||
// assert(!move (_3.1: bool), "attempt to subtract with overflow") -> bb2;
|
||||
// ...
|
||||
// assert(!move (_4.1: bool), "attempt to multiply with overflow") -> bb3;
|
||||
// ...
|
||||
// assert(!move (_13.1: bool), "attempt to shift left with overflow") -> bb8;
|
||||
// ...
|
||||
// _15 = const 6i32 as u128 (Misc);
|
||||
// _13 = const compiler_builtins::int::shift::rust_i128_shlo(_1, move _15) -> bb14;
|
||||
// ...
|
||||
// assert(!move (_14.1: bool), "attempt to shift right with overflow") -> bb9;
|
||||
// END rustc.test_signed.Lower128Bit.after.mir
|
||||
|
||||
// START rustc.test_unsigned.Lower128Bit.after.mir
|
||||
// _2 = const compiler_builtins::int::addsub::rust_u128_addo(_1, const 1u128) -> bb8;
|
||||
// ...
|
||||
// _1 = move (_2.0: u128);
|
||||
// _3 = const compiler_builtins::int::addsub::rust_u128_subo(_1, const 2u128) -> bb9;
|
||||
// ...
|
||||
// _1 = move (_3.0: u128);
|
||||
// _4 = const compiler_builtins::int::mul::rust_u128_mulo(_1, const 3u128) -> bb10;
|
||||
// ...
|
||||
// _1 = move (_4.0: u128);
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::udiv::rust_u128_div(_1, const 4u128) -> bb11;
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::udiv::rust_u128_rem(_1, const 5u128) -> bb13;
|
||||
// ...
|
||||
// _1 = move (_7.0: u128);
|
||||
// ...
|
||||
// _10 = const 7i32 as u128 (Misc);
|
||||
// _8 = const compiler_builtins::int::shift::rust_u128_shro(_1, move _10) -> bb14;
|
||||
// ...
|
||||
// _1 = move (_8.0: u128);
|
||||
// ...
|
||||
// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
|
||||
// ...
|
||||
// assert(!move (_3.1: bool), "attempt to subtract with overflow") -> bb2;
|
||||
// ...
|
||||
// assert(!move (_4.1: bool), "attempt to multiply with overflow") -> bb3;
|
||||
// ...
|
||||
// assert(!move (_7.1: bool), "attempt to shift left with overflow") -> bb6;
|
||||
// ...
|
||||
// _9 = const 6i32 as u128 (Misc);
|
||||
// _7 = const compiler_builtins::int::shift::rust_u128_shlo(_1, move _9) -> bb12;
|
||||
// ...
|
||||
// assert(!move (_8.1: bool), "attempt to shift right with overflow") -> bb7;
|
||||
// END rustc.test_unsigned.Lower128Bit.after.mir
|
@ -1,149 +0,0 @@
|
||||
// ignore-emscripten
|
||||
|
||||
// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no -O
|
||||
|
||||
static TEST_SIGNED: i128 = const_signed(-222);
|
||||
static TEST_UNSIGNED: u128 = const_unsigned(200);
|
||||
|
||||
const fn const_signed(mut x: i128) -> i128 {
|
||||
((((((x + 1) - 2) * 3) / 4) % 5) << 6) >> 7
|
||||
}
|
||||
|
||||
const fn const_unsigned(mut x: u128) -> u128 {
|
||||
((((((x + 1) - 2) * 3) / 4) % 5) << 6) >> 7
|
||||
}
|
||||
|
||||
fn test_signed(mut x: i128) -> i128 {
|
||||
x += 1;
|
||||
x -= 2;
|
||||
x *= 3;
|
||||
x /= 4;
|
||||
x %= 5;
|
||||
x <<= 6;
|
||||
x >>= 7;
|
||||
x
|
||||
}
|
||||
|
||||
fn test_unsigned(mut x: u128) -> u128 {
|
||||
x += 1;
|
||||
x -= 2;
|
||||
x *= 3;
|
||||
x /= 4;
|
||||
x %= 5;
|
||||
x <<= 6;
|
||||
x >>= 7;
|
||||
x
|
||||
}
|
||||
|
||||
fn check(x: i128, y: u128) {
|
||||
assert_eq!(test_signed(x), -1);
|
||||
assert_eq!(const_signed(x), -1);
|
||||
assert_eq!(TEST_SIGNED, -1);
|
||||
assert_eq!(test_unsigned(y), 2);
|
||||
assert_eq!(const_unsigned(y), 2);
|
||||
assert_eq!(TEST_UNSIGNED, 2);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
check(-222, 200);
|
||||
}
|
||||
|
||||
// END RUST SOURCE
|
||||
|
||||
// START rustc.const_signed.Lower128Bit.after.mir
|
||||
// _7 = const compiler_builtins::int::addsub::rust_i128_add(move _8, const 1i128) -> bb7;
|
||||
// ...
|
||||
// _10 = Eq(const 4i128, const -1i128);
|
||||
// _11 = Eq(_5, const -170141183460469231731687303715884105728i128);
|
||||
// _12 = BitAnd(move _10, move _11);
|
||||
// assert(!move _12, "attempt to divide with overflow") -> bb2;
|
||||
// ...
|
||||
// _4 = const compiler_builtins::int::sdiv::rust_i128_div(move _5, const 4i128) -> bb8;
|
||||
// ...
|
||||
// _14 = Eq(const 5i128, const -1i128);
|
||||
// _15 = Eq(_4, const -170141183460469231731687303715884105728i128);
|
||||
// _16 = BitAnd(move _14, move _15);
|
||||
// assert(!move _16, "attempt to calculate the remainder with overflow") -> bb4;
|
||||
// ...
|
||||
// _3 = const compiler_builtins::int::sdiv::rust_i128_rem(move _4, const 5i128) -> bb11;
|
||||
// ...
|
||||
// _9 = Eq(const 4i128, const 0i128);
|
||||
// assert(!move _9, "attempt to divide by zero") -> bb1;
|
||||
// ...
|
||||
// _5 = const compiler_builtins::int::mul::rust_i128_mul(move _6, const 3i128) -> bb5;
|
||||
// ...
|
||||
// _6 = const compiler_builtins::int::addsub::rust_i128_sub(move _7, const 2i128) -> bb6;
|
||||
// ...
|
||||
// _13 = Eq(const 5i128, const 0i128);
|
||||
// assert(!move _13, "attempt to calculate the remainder with a divisor of zero") -> bb3;
|
||||
// ...
|
||||
// _17 = const 7i32 as u32 (Misc);
|
||||
// _0 = const compiler_builtins::int::shift::rust_i128_shr(move _2, move _17) -> bb9;
|
||||
// ...
|
||||
// _18 = const 6i32 as u32 (Misc);
|
||||
// _2 = const compiler_builtins::int::shift::rust_i128_shl(move _3, move _18) -> bb10;
|
||||
// END rustc.const_signed.Lower128Bit.after.mir
|
||||
|
||||
// START rustc.const_unsigned.Lower128Bit.after.mir
|
||||
// _8 = _1;
|
||||
// _7 = const compiler_builtins::int::addsub::rust_u128_add(move _8, const 1u128) -> bb5;
|
||||
// ...
|
||||
// _4 = const compiler_builtins::int::udiv::rust_u128_div(move _5, const 4u128) -> bb6;
|
||||
// ...
|
||||
// _3 = const compiler_builtins::int::udiv::rust_u128_rem(move _4, const 5u128) -> bb9;
|
||||
// ...
|
||||
// _9 = Eq(const 4u128, const 0u128);
|
||||
// assert(!move _9, "attempt to divide by zero") -> bb1;
|
||||
// ...
|
||||
// _5 = const compiler_builtins::int::mul::rust_u128_mul(move _6, const 3u128) -> bb3;
|
||||
// ...
|
||||
// _6 = const compiler_builtins::int::addsub::rust_u128_sub(move _7, const 2u128) -> bb4;
|
||||
// ...
|
||||
// _10 = Eq(const 5u128, const 0u128);
|
||||
// assert(!move _10, "attempt to calculate the remainder with a divisor of zero") -> bb2;
|
||||
// ...
|
||||
// return;
|
||||
// ...
|
||||
// _11 = const 7i32 as u32 (Misc);
|
||||
// _0 = const compiler_builtins::int::shift::rust_u128_shr(move _2, move _11) -> bb7;
|
||||
// ...
|
||||
// _12 = const 6i32 as u32 (Misc);
|
||||
// _2 = const compiler_builtins::int::shift::rust_u128_shl(move _3, move _12) -> bb8;
|
||||
|
||||
// END rustc.const_unsigned.Lower128Bit.after.mir
|
||||
|
||||
// START rustc.test_signed.Lower128Bit.after.mir
|
||||
// _1 = const compiler_builtins::int::addsub::rust_i128_add(_1, const 1i128) -> bb7;
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::sdiv::rust_i128_div(_1, const 4i128) -> bb8;
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::sdiv::rust_i128_rem(_1, const 5i128) -> bb11;
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::mul::rust_i128_mul(_1, const 3i128) -> bb5;
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::addsub::rust_i128_sub(_1, const 2i128) -> bb6;
|
||||
// ...
|
||||
// _10 = const 7i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_i128_shr(_1, move _10) -> bb9;
|
||||
// ...
|
||||
// _11 = const 6i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_i128_shl(_1, move _11) -> bb10;
|
||||
// END rustc.test_signed.Lower128Bit.after.mir
|
||||
|
||||
// START rustc.test_unsigned.Lower128Bit.after.mir
|
||||
// _1 = const compiler_builtins::int::addsub::rust_u128_add(_1, const 1u128) -> bb5;
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::udiv::rust_u128_div(_1, const 4u128) -> bb6;
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::udiv::rust_u128_rem(_1, const 5u128) -> bb9;
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::mul::rust_u128_mul(_1, const 3u128) -> bb3;
|
||||
// ...
|
||||
// _1 = const compiler_builtins::int::addsub::rust_u128_sub(_1, const 2u128) -> bb4;
|
||||
// ...
|
||||
// _4 = const 7i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_u128_shr(_1, move _4) -> bb7;
|
||||
// ...
|
||||
// _5 = const 6i32 as u32 (Misc);
|
||||
// _1 = const compiler_builtins::int::shift::rust_u128_shl(_1, move _5) -> bb8;
|
||||
// END rustc.test_unsigned.Lower128Bit.after.mir
|
@ -2,7 +2,7 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
// ignore-emscripten
|
||||
// ignore-aarch64 FIXME: https://github.com/rust-lang/rust/issues/54510
|
||||
// min-system-llvm-version: 9.0
|
||||
|
||||
// Test that the simd_reduce_{op} intrinsics produce the correct results.
|
||||
|
||||
@ -124,14 +124,14 @@ fn main() {
|
||||
assert_eq!(r, 6_f32);
|
||||
let r: f32 = simd_reduce_mul_unordered(x);
|
||||
assert_eq!(r, -24_f32);
|
||||
// FIXME: only works correctly for accumulator, 0:
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=36734
|
||||
let r: f32 = simd_reduce_add_ordered(x, 0.);
|
||||
assert_eq!(r, 6_f32);
|
||||
// FIXME: only works correctly for accumulator, 1:
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=36734
|
||||
let r: f32 = simd_reduce_mul_ordered(x, 1.);
|
||||
assert_eq!(r, -24_f32);
|
||||
let r: f32 = simd_reduce_add_ordered(x, 1.);
|
||||
assert_eq!(r, 7_f32);
|
||||
let r: f32 = simd_reduce_mul_ordered(x, 2.);
|
||||
assert_eq!(r, -48_f32);
|
||||
|
||||
let r: f32 = simd_reduce_min(x);
|
||||
assert_eq!(r, -2_f32);
|
||||
|
@ -1,6 +1,6 @@
|
||||
error[E0412]: cannot find type `Iter` in this scope
|
||||
--> $DIR/missing-type.rs:4:11
|
||||
|
|
||||
4 | let x: Iter;
|
||||
| ^^^^ not found in this scope
|
||||
|
|
||||
--> $DIR/missing-type.rs:4:11
|
||||
|
|
||||
LL | let x: Iter;
|
||||
| ^^^^ not found in this scope
|
||||
|
|
||||
|
@ -1,5 +1,6 @@
|
||||
const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹⋅s⁻²
|
||||
//~^ ERROR expected at least one digit in exponent
|
||||
//~| ERROR unknown start of token: \u{2212}
|
||||
//~| ERROR cannot subtract `{integer}` from `{float}`
|
||||
|
||||
fn main() {}
|
||||
|
@ -14,5 +14,14 @@ help: Unicode character '−' (Minus Sign) looks like '-' (Minus/Hyphen), but it
|
||||
LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e-11; // m³⋅kg⁻¹⋅s⁻²
|
||||
| ^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0277]: cannot subtract `{integer}` from `{float}`
|
||||
--> $DIR/issue-49746-unicode-confusable-in-float-literal-expt.rs:1:53
|
||||
|
|
||||
LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹⋅s⁻²
|
||||
| ^ no implementation for `{float} - {integer}`
|
||||
|
|
||||
= help: the trait `std::ops::Sub<{integer}>` is not implemented for `{float}`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
@ -0,0 +1,6 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &Some(42).as_deref();
|
||||
//~^ ERROR no method named `as_deref` found for type `std::option::Option<{integer}>`
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0599]: no method named `as_deref` found for type `std::option::Option<{integer}>` in the current scope
|
||||
--> $DIR/option-as_deref.rs:4:29
|
||||
|
|
||||
LL | let _result = &Some(42).as_deref();
|
||||
| ^^^^^^^^ help: there is a method with a similar name: `as_ref`
|
||||
|
|
||||
= note: the method `as_deref` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::Deref`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -0,0 +1,6 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &mut Some(42).as_deref_mut();
|
||||
//~^ ERROR no method named `as_deref_mut` found for type `std::option::Option<{integer}>`
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0599]: no method named `as_deref_mut` found for type `std::option::Option<{integer}>` in the current scope
|
||||
--> $DIR/option-as_deref_mut.rs:4:33
|
||||
|
|
||||
LL | let _result = &mut Some(42).as_deref_mut();
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: the method `as_deref_mut` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::DerefMut`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -1,6 +0,0 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &Some(42).deref();
|
||||
//~^ ERROR no method named `deref` found for type `std::option::Option<{integer}>`
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
error[E0599]: no method named `deref` found for type `std::option::Option<{integer}>` in the current scope
|
||||
--> $DIR/option-deref.rs:4:29
|
||||
|
|
||||
LL | let _result = &Some(42).deref();
|
||||
| ^^^^^
|
||||
|
|
||||
= note: the method `deref` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::Deref`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -0,0 +1,6 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &Ok(42).as_deref();
|
||||
//~^ ERROR no method named `as_deref` found
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0599]: no method named `as_deref` found for type `std::result::Result<{integer}, _>` in the current scope
|
||||
--> $DIR/result-as_deref.rs:4:27
|
||||
|
|
||||
LL | let _result = &Ok(42).as_deref();
|
||||
| ^^^^^^^^ help: there is a method with a similar name: `as_ref`
|
||||
|
|
||||
= note: the method `as_deref` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::Deref`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -0,0 +1,6 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &Err(41).as_deref_err();
|
||||
//~^ ERROR no method named `as_deref_err` found
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0599]: no method named `as_deref_err` found for type `std::result::Result<_, {integer}>` in the current scope
|
||||
--> $DIR/result-as_deref_err.rs:4:28
|
||||
|
|
||||
LL | let _result = &Err(41).as_deref_err();
|
||||
| ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_ok`
|
||||
|
|
||||
= note: the method `as_deref_err` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::Deref`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -0,0 +1,6 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &mut Ok(42).as_deref_mut();
|
||||
//~^ ERROR no method named `as_deref_mut` found
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0599]: no method named `as_deref_mut` found for type `std::result::Result<{integer}, _>` in the current scope
|
||||
--> $DIR/result-as_deref_mut.rs:4:31
|
||||
|
|
||||
LL | let _result = &mut Ok(42).as_deref_mut();
|
||||
| ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_err`
|
||||
|
|
||||
= note: the method `as_deref_mut` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::DerefMut`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -0,0 +1,6 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &mut Err(41).as_deref_mut_err();
|
||||
//~^ ERROR no method named `as_deref_mut_err` found
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0599]: no method named `as_deref_mut_err` found for type `std::result::Result<_, {integer}>` in the current scope
|
||||
--> $DIR/result-as_deref_mut_err.rs:4:32
|
||||
|
|
||||
LL | let _result = &mut Err(41).as_deref_mut_err();
|
||||
| ^^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut_ok`
|
||||
|
|
||||
= note: the method `as_deref_mut_err` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::DerefMut`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -0,0 +1,6 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &mut Ok(42).as_deref_mut_ok();
|
||||
//~^ ERROR no method named `as_deref_mut_ok` found
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0599]: no method named `as_deref_mut_ok` found for type `std::result::Result<{integer}, _>` in the current scope
|
||||
--> $DIR/result-as_deref_mut_ok.rs:4:31
|
||||
|
|
||||
LL | let _result = &mut Ok(42).as_deref_mut_ok();
|
||||
| ^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut_err`
|
||||
|
|
||||
= note: the method `as_deref_mut_ok` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::DerefMut`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -0,0 +1,6 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &Ok(42).as_deref_ok();
|
||||
//~^ ERROR no method named `as_deref_ok` found
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0599]: no method named `as_deref_ok` found for type `std::result::Result<{integer}, _>` in the current scope
|
||||
--> $DIR/result-as_deref_ok.rs:4:27
|
||||
|
|
||||
LL | let _result = &Ok(42).as_deref_ok();
|
||||
| ^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_err`
|
||||
|
|
||||
= note: the method `as_deref_ok` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::Deref`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -1,6 +0,0 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &Err(41).deref_err();
|
||||
//~^ ERROR no method named `deref_err` found
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
error[E0599]: no method named `deref_err` found for type `std::result::Result<_, {integer}>` in the current scope
|
||||
--> $DIR/result-deref-err.rs:4:28
|
||||
|
|
||||
LL | let _result = &Err(41).deref_err();
|
||||
| ^^^^^^^^^ help: there is a method with a similar name: `deref_ok`
|
||||
|
|
||||
= note: the method `deref_err` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::Deref`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -1,6 +0,0 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &Ok(42).deref_ok();
|
||||
//~^ ERROR no method named `deref_ok` found
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
error[E0599]: no method named `deref_ok` found for type `std::result::Result<{integer}, _>` in the current scope
|
||||
--> $DIR/result-deref-ok.rs:4:27
|
||||
|
|
||||
LL | let _result = &Ok(42).deref_ok();
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: the method `deref_ok` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::Deref`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
@ -1,6 +0,0 @@
|
||||
#![feature(inner_deref)]
|
||||
|
||||
fn main() {
|
||||
let _result = &Ok(42).deref();
|
||||
//~^ ERROR no method named `deref` found
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
error[E0599]: no method named `deref` found for type `std::result::Result<{integer}, _>` in the current scope
|
||||
--> $DIR/result-deref.rs:4:27
|
||||
|
|
||||
LL | let _result = &Ok(42).deref();
|
||||
| ^^^^^
|
||||
|
|
||||
= note: the method `deref` exists but the following trait bounds were not satisfied:
|
||||
`{integer} : std::ops::Deref`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
13
src/test/ui/issues/issue-54062.rs
Normal file
13
src/test/ui/issues/issue-54062.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use std::sync::Mutex;
|
||||
|
||||
struct Test {
|
||||
comps: Mutex<String>,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn testing(test: Test) {
|
||||
let _ = test.comps.inner.lock().unwrap();
|
||||
//~^ ERROR: field `inner` of struct `std::sync::Mutex` is private
|
||||
//~| ERROR: no method named `unwrap` found
|
||||
}
|
16
src/test/ui/issues/issue-54062.stderr
Normal file
16
src/test/ui/issues/issue-54062.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error[E0616]: field `inner` of struct `std::sync::Mutex` is private
|
||||
--> $DIR/issue-54062.rs:10:13
|
||||
|
|
||||
LL | let _ = test.comps.inner.lock().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0599]: no method named `unwrap` found for type `std::sys_common::mutex::MutexGuard<'_>` in the current scope
|
||||
--> $DIR/issue-54062.rs:10:37
|
||||
|
|
||||
LL | let _ = test.comps.inner.lock().unwrap();
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0599, E0616.
|
||||
For more information about an error, try `rustc --explain E0599`.
|
36
src/test/ui/macros/auxiliary/proc_macro_sequence.rs
Normal file
36
src/test/ui/macros/auxiliary/proc_macro_sequence.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
#![feature(proc_macro_span, proc_macro_hygiene, proc_macro_quote)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::{quote, Span, TokenStream};
|
||||
|
||||
fn assert_same_span(a: Span, b: Span) {
|
||||
assert_eq!(a.start(), b.start());
|
||||
assert_eq!(a.end(), b.end());
|
||||
}
|
||||
|
||||
// This macro generates a macro with the same macro definition as `manual_foo` in
|
||||
// `same-sequence-span.rs` but with the same span for all sequences.
|
||||
#[proc_macro]
|
||||
pub fn make_foo(_: TokenStream) -> TokenStream {
|
||||
let result = quote! {
|
||||
macro_rules! generated_foo {
|
||||
(1 $$x:expr $$($$y:tt,)* $$(= $$z:tt)*) => {};
|
||||
}
|
||||
};
|
||||
|
||||
// Check that all spans are equal.
|
||||
let mut span = None;
|
||||
for tt in result.clone() {
|
||||
match span {
|
||||
None => span = Some(tt.span()),
|
||||
Some(span) => assert_same_span(tt.span(), span),
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
23
src/test/ui/macros/same-sequence-span.rs
Normal file
23
src/test/ui/macros/same-sequence-span.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// aux-build:proc_macro_sequence.rs
|
||||
|
||||
// Regression test for issue #62831: Check that multiple sequences with the same span in the
|
||||
// left-hand side of a macro definition behave as if they had unique spans, and in particular that
|
||||
// they don't crash the compiler.
|
||||
|
||||
#![feature(proc_macro_hygiene)]
|
||||
#![allow(unused_macros)]
|
||||
|
||||
extern crate proc_macro_sequence;
|
||||
|
||||
// When ignoring spans, this macro has the same macro definition as `generated_foo` in
|
||||
// `proc_macro_sequence.rs`.
|
||||
macro_rules! manual_foo {
|
||||
(1 $x:expr $($y:tt,)* //~ERROR `$x:expr` may be followed by `$y:tt`
|
||||
$(= $z:tt)* //~ERROR `$x:expr` may be followed by `=`
|
||||
) => {};
|
||||
}
|
||||
|
||||
proc_macro_sequence::make_foo!(); //~ERROR `$x:expr` may be followed by `$y:tt`
|
||||
//~^ERROR `$x:expr` may be followed by `=`
|
||||
|
||||
fn main() {}
|
34
src/test/ui/macros/same-sequence-span.stderr
Normal file
34
src/test/ui/macros/same-sequence-span.stderr
Normal file
@ -0,0 +1,34 @@
|
||||
error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments
|
||||
--> $DIR/same-sequence-span.rs:15:18
|
||||
|
|
||||
LL | (1 $x:expr $($y:tt,)*
|
||||
| ^^^^^ not allowed after `expr` fragments
|
||||
|
|
||||
= note: allowed there are: `=>`, `,` or `;`
|
||||
|
||||
error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragments
|
||||
--> $DIR/same-sequence-span.rs:16:18
|
||||
|
|
||||
LL | $(= $z:tt)*
|
||||
| ^ not allowed after `expr` fragments
|
||||
|
|
||||
= note: allowed there are: `=>`, `,` or `;`
|
||||
|
||||
error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments
|
||||
--> $DIR/same-sequence-span.rs:20:1
|
||||
|
|
||||
LL | proc_macro_sequence::make_foo!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed after `expr` fragments
|
||||
|
|
||||
= note: allowed there are: `=>`, `,` or `;`
|
||||
|
||||
error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragments
|
||||
--> $DIR/same-sequence-span.rs:20:1
|
||||
|
|
||||
LL | proc_macro_sequence::make_foo!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed after `expr` fragments
|
||||
|
|
||||
= note: allowed there are: `=>`, `,` or `;`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
4
src/test/ui/parser/recover-from-homoglyph.rs
Normal file
4
src/test/ui/parser/recover-from-homoglyph.rs
Normal file
@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
println!(""); //~ ERROR unknown start of token: \u{37e}
|
||||
let x: usize = (); //~ ERROR mismatched types
|
||||
}
|
22
src/test/ui/parser/recover-from-homoglyph.stderr
Normal file
22
src/test/ui/parser/recover-from-homoglyph.stderr
Normal file
@ -0,0 +1,22 @@
|
||||
error: unknown start of token: \u{37e}
|
||||
--> $DIR/recover-from-homoglyph.rs:2:17
|
||||
|
|
||||
LL | println!("");
|
||||
| ^
|
||||
help: Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not
|
||||
|
|
||||
LL | println!("");
|
||||
| ^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/recover-from-homoglyph.rs:3:20
|
||||
|
|
||||
LL | let x: usize = ();
|
||||
| ^^ expected usize, found ()
|
||||
|
|
||||
= note: expected type `usize`
|
||||
found type `()`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -30,13 +30,10 @@ fn main() {
|
||||
let z = f32x4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
unsafe {
|
||||
simd_reduce_add_ordered(z, 0_f32);
|
||||
simd_reduce_mul_ordered(z, 1_f32);
|
||||
|
||||
simd_reduce_add_ordered(z, 2_f32);
|
||||
//~^ ERROR accumulator of simd_reduce_add_ordered is not 0.0
|
||||
simd_reduce_mul_ordered(z, 3_f32);
|
||||
//~^ ERROR accumulator of simd_reduce_mul_ordered is not 1.0
|
||||
simd_reduce_add_ordered(z, 0);
|
||||
//~^ ERROR expected return type `f32` (element of input `f32x4`), found `i32`
|
||||
simd_reduce_mul_ordered(z, 1);
|
||||
//~^ ERROR expected return type `f32` (element of input `f32x4`), found `i32`
|
||||
|
||||
let _: f32 = simd_reduce_and(x);
|
||||
//~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32`
|
||||
@ -56,16 +53,5 @@ fn main() {
|
||||
//~^ ERROR unsupported simd_reduce_all from `f32x4` with element `f32` to `bool`
|
||||
let _: bool = simd_reduce_any(z);
|
||||
//~^ ERROR unsupported simd_reduce_any from `f32x4` with element `f32` to `bool`
|
||||
|
||||
foo(0_f32);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
unsafe fn foo(x: f32) {
|
||||
let z = f32x4(0.0, 0.0, 0.0, 0.0);
|
||||
simd_reduce_add_ordered(z, x);
|
||||
//~^ ERROR accumulator of simd_reduce_add_ordered is not a constant
|
||||
simd_reduce_mul_ordered(z, x);
|
||||
//~^ ERROR accumulator of simd_reduce_mul_ordered is not a constant
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user