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:
bors 2019-07-26 16:57:54 +00:00
commit c43753f910
101 changed files with 1106 additions and 2323 deletions

View File

@ -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'))

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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"

View 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")]

View File

@ -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());

View File

@ -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

View File

@ -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`.
///

View File

@ -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")]

View File

@ -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`.
///

View File

@ -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]

View File

@ -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);
}

View File

@ -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};

View File

@ -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}};

View File

@ -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))

View File

@ -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;

View File

@ -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],

View File

@ -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)
}

View File

@ -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
});

View File

@ -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,

View File

@ -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

View File

@ -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> {

View File

@ -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);

View File

@ -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>;

View File

@ -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"

View File

@ -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.

View File

@ -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");

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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
}

View File

@ -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])?;

View File

@ -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 {

View File

@ -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)
}

View File

@ -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,

View File

@ -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,
}

View File

@ -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

View File

@ -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

View File

@ -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(),

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -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 {
"&"

View File

@ -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,

View File

@ -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();

View File

@ -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))
}

View File

@ -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);
}
}

View File

@ -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())

View File

@ -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!();
}
}
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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()?;

View File

@ -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.

View File

@ -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;

View File

@ -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
}

View File

@ -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`].

View File

@ -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
}
}

View File

@ -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)))

View File

@ -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;
}
}
}

View File

@ -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: &quoted::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),
},

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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
|

View File

@ -1,5 +1,6 @@
const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e11; // 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() {}

View File

@ -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.674e11; // 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`.

View File

@ -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}>`
}

View File

@ -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`.

View File

@ -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}>`
}

View File

@ -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`.

View File

@ -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}>`
}

View File

@ -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`.

View File

@ -0,0 +1,6 @@
#![feature(inner_deref)]
fn main() {
let _result = &Ok(42).as_deref();
//~^ ERROR no method named `as_deref` found
}

View File

@ -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`.

View File

@ -0,0 +1,6 @@
#![feature(inner_deref)]
fn main() {
let _result = &Err(41).as_deref_err();
//~^ ERROR no method named `as_deref_err` found
}

View File

@ -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`.

View File

@ -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
}

View File

@ -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`.

View File

@ -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
}

View File

@ -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`.

View File

@ -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
}

View File

@ -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`.

View File

@ -0,0 +1,6 @@
#![feature(inner_deref)]
fn main() {
let _result = &Ok(42).as_deref_ok();
//~^ ERROR no method named `as_deref_ok` found
}

View File

@ -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`.

View File

@ -1,6 +0,0 @@
#![feature(inner_deref)]
fn main() {
let _result = &Err(41).deref_err();
//~^ ERROR no method named `deref_err` found
}

View File

@ -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`.

View File

@ -1,6 +0,0 @@
#![feature(inner_deref)]
fn main() {
let _result = &Ok(42).deref_ok();
//~^ ERROR no method named `deref_ok` found
}

View File

@ -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`.

View File

@ -1,6 +0,0 @@
#![feature(inner_deref)]
fn main() {
let _result = &Ok(42).deref();
//~^ ERROR no method named `deref` found
}

View File

@ -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`.

View 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
}

View 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`.

View 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
}

View 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() {}

View 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

View File

@ -0,0 +1,4 @@
fn main() {
println!(""); //~ ERROR unknown start of token: \u{37e}
let x: usize = (); //~ ERROR mismatched types
}

View 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`.

View File

@ -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