Merge remote-tracking branch 'upstream/master' into asm-compile-tests
This commit is contained in:
commit
60f1644fd2
478 changed files with 5339 additions and 4185 deletions
|
@ -251,7 +251,7 @@ dependencies = [
|
|||
"fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"git2-curl 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1009,7 +1009,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.2.11"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -4083,7 +4083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05"
|
||||
"checksum git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7339329bfa14a00223244311560d11f8f489b453fb90092af97f267a6090ab0"
|
||||
"checksum git2-curl 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d58551e903ed7e2d6fe3a2f3c7efa3a784ec29b19d0fbb035aaf0497c183fbdd"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
"checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865"
|
||||
"checksum handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d89ec99d1594f285d4590fc32bac5f75cdab383f1123d504d27862c644a807dd"
|
||||
"checksum handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166"
|
||||
|
|
|
@ -110,8 +110,11 @@ Compatibility Notes
|
|||
methods instead.
|
||||
- The `Error::cause` method has been deprecated in favor of `Error::source` which supports
|
||||
downcasting.
|
||||
- [Libtest no longer creates a new thread for each test when
|
||||
`--test-threads=1`. It also runs the tests in deterministic order][56243]
|
||||
|
||||
[55982]: https://github.com/rust-lang/rust/pull/55982/
|
||||
[56243]: https://github.com/rust-lang/rust/pull/56243
|
||||
[56303]: https://github.com/rust-lang/rust/pull/56303/
|
||||
[56351]: https://github.com/rust-lang/rust/pull/56351/
|
||||
[56362]: https://github.com/rust-lang/rust/pull/56362
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
environment:
|
||||
# This is required for at least an AArch64 compiler in one image, and is also
|
||||
# going to soon be required for compiling LLVM.
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 Preview
|
||||
|
||||
# By default schannel checks revocation of certificates unlike some other SSL
|
||||
# backends, but we've historically had problems on CI where a revocation
|
||||
|
@ -81,7 +84,6 @@ environment:
|
|||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
DEPLOY: 1
|
||||
CI_JOB_NAME: dist-x86_64-msvc
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 Preview
|
||||
- RUST_CONFIGURE_ARGS: >
|
||||
--build=i686-pc-windows-msvc
|
||||
--target=i586-pc-windows-msvc
|
||||
|
|
|
@ -35,7 +35,7 @@ fn main() {
|
|||
.arg("--cfg")
|
||||
.arg("dox")
|
||||
.arg("--sysroot")
|
||||
.arg(sysroot)
|
||||
.arg(&sysroot)
|
||||
.env(bootstrap::util::dylib_path_var(),
|
||||
env::join_paths(&dylib_path).unwrap());
|
||||
|
||||
|
@ -72,7 +72,13 @@ fn main() {
|
|||
}
|
||||
|
||||
if verbose > 1 {
|
||||
eprintln!("rustdoc command: {:?}", cmd);
|
||||
eprintln!(
|
||||
"rustdoc command: {:?}={:?} {:?}",
|
||||
bootstrap::util::dylib_path_var(),
|
||||
env::join_paths(&dylib_path).unwrap(),
|
||||
cmd,
|
||||
);
|
||||
eprintln!("sysroot: {:?}", sysroot);
|
||||
eprintln!("libdir: {:?}", libdir);
|
||||
}
|
||||
|
||||
|
|
|
@ -374,6 +374,7 @@ impl<'a> Builder<'a> {
|
|||
test::MirOpt,
|
||||
test::Codegen,
|
||||
test::CodegenUnits,
|
||||
test::Assembly,
|
||||
test::Incremental,
|
||||
test::Debuginfo,
|
||||
test::UiFullDeps,
|
||||
|
@ -408,12 +409,11 @@ impl<'a> Builder<'a> {
|
|||
test::RustdocJSStd,
|
||||
test::RustdocJSNotStd,
|
||||
test::RustdocTheme,
|
||||
test::RustdocUi,
|
||||
// Run bootstrap close to the end as it's unlikely to fail
|
||||
test::Bootstrap,
|
||||
// Run run-make last, since these won't pass without make on Windows
|
||||
test::RunMake,
|
||||
test::RustdocUi,
|
||||
test::Assembly,
|
||||
),
|
||||
Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
|
||||
Kind::Doc => describe!(
|
||||
|
|
|
@ -241,6 +241,8 @@ pub struct Build {
|
|||
clippy_info: channel::GitInfo,
|
||||
miri_info: channel::GitInfo,
|
||||
rustfmt_info: channel::GitInfo,
|
||||
in_tree_llvm_info: channel::GitInfo,
|
||||
emscripten_llvm_info: channel::GitInfo,
|
||||
local_rebuild: bool,
|
||||
fail_fast: bool,
|
||||
doc_tests: DocTests,
|
||||
|
@ -363,6 +365,8 @@ impl Build {
|
|||
let clippy_info = channel::GitInfo::new(&config, &src.join("src/tools/clippy"));
|
||||
let miri_info = channel::GitInfo::new(&config, &src.join("src/tools/miri"));
|
||||
let rustfmt_info = channel::GitInfo::new(&config, &src.join("src/tools/rustfmt"));
|
||||
let in_tree_llvm_info = channel::GitInfo::new(&config, &src.join("src/llvm-project"));
|
||||
let emscripten_llvm_info = channel::GitInfo::new(&config, &src.join("src/llvm-emscripten"));
|
||||
|
||||
let mut build = Build {
|
||||
initial_rustc: config.initial_rustc.clone(),
|
||||
|
@ -386,6 +390,8 @@ impl Build {
|
|||
clippy_info,
|
||||
miri_info,
|
||||
rustfmt_info,
|
||||
in_tree_llvm_info,
|
||||
emscripten_llvm_info,
|
||||
cc: HashMap::new(),
|
||||
cxx: HashMap::new(),
|
||||
ar: HashMap::new(),
|
||||
|
|
|
@ -48,7 +48,6 @@ check:
|
|||
$(Q)$(BOOTSTRAP) test $(BOOTSTRAP_ARGS)
|
||||
check-aux:
|
||||
$(Q)$(BOOTSTRAP) test \
|
||||
src/test/pretty \
|
||||
src/test/run-pass/pretty \
|
||||
src/test/run-fail/pretty \
|
||||
src/test/run-pass-valgrind/pretty \
|
||||
|
|
|
@ -18,6 +18,7 @@ use build_helper::output;
|
|||
use cmake;
|
||||
use cc;
|
||||
|
||||
use crate::channel;
|
||||
use crate::util::{self, exe};
|
||||
use build_helper::up_to_date;
|
||||
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
|
||||
|
@ -231,7 +232,26 @@ impl Step for Llvm {
|
|||
}
|
||||
|
||||
if let Some(ref suffix) = builder.config.llvm_version_suffix {
|
||||
cfg.define("LLVM_VERSION_SUFFIX", suffix);
|
||||
// Allow version-suffix="" to not define a version suffix at all.
|
||||
if !suffix.is_empty() {
|
||||
cfg.define("LLVM_VERSION_SUFFIX", suffix);
|
||||
}
|
||||
} else {
|
||||
let mut default_suffix = format!(
|
||||
"-rust-{}-{}",
|
||||
channel::CFG_RELEASE_NUM,
|
||||
builder.config.channel,
|
||||
);
|
||||
let llvm_info = if self.emscripten {
|
||||
&builder.emscripten_llvm_info
|
||||
} else {
|
||||
&builder.in_tree_llvm_info
|
||||
};
|
||||
if let Some(sha) = llvm_info.sha_short() {
|
||||
default_suffix.push_str("-");
|
||||
default_suffix.push_str(sha);
|
||||
}
|
||||
cfg.define("LLVM_VERSION_SUFFIX", default_suffix);
|
||||
}
|
||||
|
||||
if let Some(ref linker) = builder.config.llvm_use_linker {
|
||||
|
|
|
@ -897,12 +897,10 @@ host_test!(Rustdoc {
|
|||
suite: "rustdoc"
|
||||
});
|
||||
|
||||
test!(Pretty {
|
||||
host_test!(Pretty {
|
||||
path: "src/test/pretty",
|
||||
mode: "pretty",
|
||||
suite: "pretty",
|
||||
default: false,
|
||||
host: true
|
||||
suite: "pretty"
|
||||
});
|
||||
test!(RunPassPretty {
|
||||
path: "src/test/run-pass/pretty",
|
||||
|
@ -999,11 +997,7 @@ impl Step for Compiletest {
|
|||
});
|
||||
}
|
||||
|
||||
if suite.ends_with("fulldeps") ||
|
||||
// FIXME: Does pretty need librustc compiled? Note that there are
|
||||
// fulldeps test suites with mode = pretty as well.
|
||||
mode == "pretty"
|
||||
{
|
||||
if suite.ends_with("fulldeps") {
|
||||
builder.ensure(compile::Rustc { compiler, target });
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
g++ \
|
||||
make \
|
||||
file \
|
||||
wget \
|
||||
curl \
|
||||
ca-certificates \
|
||||
python2.7 \
|
||||
|
@ -18,19 +19,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
|
||||
WORKDIR /build/
|
||||
|
||||
COPY scripts/musl.sh /build/
|
||||
COPY scripts/musl-toolchain.sh /build/
|
||||
# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
|
||||
RUN CC=gcc \
|
||||
CFLAGS="-Wa,-mrelax-relocations=no" \
|
||||
CXX=g++ \
|
||||
RUN CFLAGS="-Wa,-mrelax-relocations=no" \
|
||||
CXXFLAGS="-Wa,-mrelax-relocations=no" \
|
||||
bash musl.sh x86_64 && rm -rf /build
|
||||
bash musl-toolchain.sh x86_64 && rm -rf build
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--musl-root-x86_64=/musl-x86_64 \
|
||||
--musl-root-x86_64=/usr/local/x86_64-linux-musl \
|
||||
--enable-extended \
|
||||
--disable-docs
|
||||
|
||||
|
@ -41,6 +40,12 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
# See: https://github.com/rust-lang/rust/issues/34978
|
||||
ENV CFLAGS_x86_64_unknown_linux_musl=-Wa,-mrelax-relocations=no
|
||||
|
||||
ENV SCRIPT \
|
||||
python2.7 ../x.py test --target x86_64-unknown-linux-musl && \
|
||||
python2.7 ../x.py dist --target x86_64-unknown-linux-musl
|
||||
ENV HOSTS=x86_64-unknown-linux-musl \
|
||||
CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc \
|
||||
CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++
|
||||
|
||||
# Musl defaults to static libs but we need them to be dynamic for host toolchain.
|
||||
# The toolchain will produce static libs by default.
|
||||
ENV RUSTFLAGS="-C target-feature=-crt-static"
|
||||
|
||||
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
70
src/ci/docker/scripts/musl-toolchain.sh
Normal file
70
src/ci/docker/scripts/musl-toolchain.sh
Normal file
|
@ -0,0 +1,70 @@
|
|||
# This script runs `musl-cross-make` to prepare C toolchain (Binutils, GCC, musl itself)
|
||||
# and builds static libunwind that we distribute for static target.
|
||||
#
|
||||
# Versions of the toolchain components are configurable in `musl-cross-make/Makefile` and
|
||||
# musl unlike GLIBC is forward compatible so upgrading it shouldn't break old distributions.
|
||||
# Right now we have: Binutils 2.27, GCC 6.3.0, musl 1.1.18
|
||||
set -ex
|
||||
|
||||
hide_output() {
|
||||
set +x
|
||||
on_err="
|
||||
echo ERROR: An error was encountered with the build.
|
||||
cat /tmp/build.log
|
||||
exit 1
|
||||
"
|
||||
trap "$on_err" ERR
|
||||
bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
|
||||
PING_LOOP_PID=$!
|
||||
$@ &> /tmp/build.log
|
||||
trap - ERR
|
||||
kill $PING_LOOP_PID
|
||||
rm /tmp/build.log
|
||||
set -x
|
||||
}
|
||||
|
||||
ARCH=$1
|
||||
TARGET=$ARCH-linux-musl
|
||||
|
||||
OUTPUT=/usr/local
|
||||
shift
|
||||
|
||||
git clone https://github.com/richfelker/musl-cross-make -b v0.9.7
|
||||
cd musl-cross-make
|
||||
|
||||
hide_output make -j$(nproc) TARGET=$TARGET
|
||||
hide_output make install TARGET=$TARGET OUTPUT=$OUTPUT
|
||||
|
||||
cd -
|
||||
|
||||
# Install musl library to make binaries executable
|
||||
ln -s $OUTPUT/$TARGET/lib/libc.so /lib/ld-musl-$ARCH.so.1
|
||||
echo $OUTPUT/$TARGET/lib >> /etc/ld-musl-$ARCH.path
|
||||
|
||||
|
||||
export CC=$TARGET-gcc
|
||||
export CXX=$TARGET-g++
|
||||
|
||||
LLVM=70
|
||||
|
||||
# may have been downloaded in a previous run
|
||||
if [ ! -d libunwind-release_$LLVM ]; then
|
||||
curl -L https://github.com/llvm-mirror/llvm/archive/release_$LLVM.tar.gz | tar xzf -
|
||||
curl -L https://github.com/llvm-mirror/libunwind/archive/release_$LLVM.tar.gz | tar xzf -
|
||||
fi
|
||||
|
||||
# fixme(mati865): Replace it with https://github.com/rust-lang/rust/pull/59089
|
||||
mkdir libunwind-build
|
||||
cd libunwind-build
|
||||
cmake ../libunwind-release_$LLVM \
|
||||
-DLLVM_PATH=/build/llvm-release_$LLVM \
|
||||
-DLIBUNWIND_ENABLE_SHARED=0 \
|
||||
-DCMAKE_C_COMPILER=$CC \
|
||||
-DCMAKE_CXX_COMPILER=$CXX \
|
||||
-DCMAKE_C_FLAGS="$CFLAGS" \
|
||||
-DCMAKE_CXX_FLAGS="$CXXFLAGS"
|
||||
|
||||
hide_output make -j$(nproc)
|
||||
cp lib/libunwind.a $OUTPUT/$TARGET/lib
|
||||
cd - && rm -rf libunwind-build
|
||||
|
|
@ -11,7 +11,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
cmake \
|
||||
sudo \
|
||||
gdb \
|
||||
xz-utils
|
||||
xz-utils \
|
||||
wget \
|
||||
patch
|
||||
|
||||
# FIXME: build the `ptx-linker` instead.
|
||||
RUN curl -sL https://github.com/denzp/rust-ptx-linker/releases/download/v0.9.0-alpha.2/rust-ptx-linker.linux64.tar.gz | \
|
||||
|
@ -20,10 +22,16 @@ RUN curl -sL https://github.com/denzp/rust-ptx-linker/releases/download/v0.9.0-a
|
|||
RUN curl -sL https://nodejs.org/dist/v9.2.0/node-v9.2.0-linux-x64.tar.xz | \
|
||||
tar -xJ
|
||||
|
||||
WORKDIR /build/
|
||||
COPY scripts/musl-toolchain.sh /build/
|
||||
RUN bash musl-toolchain.sh x86_64 && rm -rf build
|
||||
WORKDIR /
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--musl-root-x86_64=/usr/local/x86_64-linux-musl \
|
||||
--set build.nodejs=/node-v9.2.0-linux-x64/bin/node \
|
||||
--set rust.lld
|
||||
|
||||
|
@ -48,4 +56,9 @@ ENV NVPTX_SCRIPT python2.7 /checkout/x.py test --target $NVPTX_TARGETS \
|
|||
src/test/run-make \
|
||||
src/test/assembly
|
||||
|
||||
ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT
|
||||
ENV MUSL_TARGETS=x86_64-unknown-linux-musl \
|
||||
CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc \
|
||||
CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++
|
||||
ENV MUSL_SCRIPT python2.7 /checkout/x.py test --target $MUSL_TARGETS
|
||||
|
||||
ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
//! The alloc Prelude
|
||||
//!
|
||||
//! The purpose of this module is to alleviate imports of commonly-used
|
||||
//! items of the `alloc` crate by adding a glob import to the top of modules:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_imports)]
|
||||
//! # #![feature(alloc)]
|
||||
//! extern crate alloc;
|
||||
//! use alloc::prelude::*;
|
||||
//! ```
|
||||
|
||||
#![unstable(feature = "alloc", issue = "27783")]
|
||||
|
||||
#[unstable(feature = "alloc", issue = "27783")] pub use crate::borrow::ToOwned;
|
||||
#[unstable(feature = "alloc", issue = "27783")] pub use crate::boxed::Box;
|
||||
#[unstable(feature = "alloc", issue = "27783")] pub use crate::slice::SliceConcatExt;
|
||||
#[unstable(feature = "alloc", issue = "27783")] pub use crate::string::{String, ToString};
|
||||
#[unstable(feature = "alloc", issue = "27783")] pub use crate::vec::Vec;
|
16
src/liballoc/prelude/mod.rs
Normal file
16
src/liballoc/prelude/mod.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
//! The alloc Prelude
|
||||
//!
|
||||
//! The purpose of this module is to alleviate imports of commonly-used
|
||||
//! items of the `alloc` crate by adding a glob import to the top of modules:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(unused_imports)]
|
||||
//! # #![feature(alloc)]
|
||||
//! #![feature(alloc_prelude)]
|
||||
//! extern crate alloc;
|
||||
//! use alloc::prelude::v1::*;
|
||||
//! ```
|
||||
|
||||
#![unstable(feature = "alloc_prelude", issue = "58935")]
|
||||
|
||||
pub mod v1;
|
11
src/liballoc/prelude/v1.rs
Normal file
11
src/liballoc/prelude/v1.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
//! The first version of the prelude of `alloc` crate.
|
||||
//!
|
||||
//! See the [module-level documentation](../index.html) for more.
|
||||
|
||||
#![unstable(feature = "alloc_prelude", issue = "58935")]
|
||||
|
||||
#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::borrow::ToOwned;
|
||||
#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::boxed::Box;
|
||||
#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::slice::SliceConcatExt;
|
||||
#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::string::{String, ToString};
|
||||
#[unstable(feature = "alloc_prelude", issue = "58935")] pub use crate::vec::Vec;
|
|
@ -282,7 +282,7 @@ fn assert_covariance() {
|
|||
//
|
||||
// Destructors must be called exactly once per element.
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
#[cfg(not(miri))] // Miri does not support panics nor entropy
|
||||
fn panic_safe() {
|
||||
static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
|
|
|
@ -226,7 +226,6 @@ fn test_range_equal_empty_cases() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_range_equal_excluded() {
|
||||
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
|
||||
map.range((Excluded(2), Excluded(2)));
|
||||
|
@ -234,7 +233,6 @@ fn test_range_equal_excluded() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_range_backwards_1() {
|
||||
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
|
||||
map.range((Included(3), Included(2)));
|
||||
|
@ -242,7 +240,6 @@ fn test_range_backwards_1() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_range_backwards_2() {
|
||||
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
|
||||
map.range((Included(3), Excluded(2)));
|
||||
|
@ -250,7 +247,6 @@ fn test_range_backwards_2() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_range_backwards_3() {
|
||||
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
|
||||
map.range((Excluded(3), Included(2)));
|
||||
|
@ -258,7 +254,6 @@ fn test_range_backwards_3() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_range_backwards_4() {
|
||||
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
|
||||
map.range((Excluded(3), Excluded(2)));
|
||||
|
|
|
@ -258,7 +258,6 @@ fn test_swap_remove() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_swap_remove_fail() {
|
||||
let mut v = vec![1];
|
||||
let _ = v.swap_remove(0);
|
||||
|
@ -632,7 +631,6 @@ fn test_insert() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_insert_oob() {
|
||||
let mut a = vec![1, 2, 3];
|
||||
a.insert(4, 5);
|
||||
|
@ -657,7 +655,6 @@ fn test_remove() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_remove_fail() {
|
||||
let mut a = vec![1];
|
||||
let _ = a.remove(0);
|
||||
|
@ -939,7 +936,6 @@ fn test_windowsator() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_windowsator_0() {
|
||||
let v = &[1, 2, 3, 4];
|
||||
let _it = v.windows(0);
|
||||
|
@ -964,7 +960,6 @@ fn test_chunksator() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_chunksator_0() {
|
||||
let v = &[1, 2, 3, 4];
|
||||
let _it = v.chunks(0);
|
||||
|
@ -989,7 +984,6 @@ fn test_chunks_exactator() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_chunks_exactator_0() {
|
||||
let v = &[1, 2, 3, 4];
|
||||
let _it = v.chunks_exact(0);
|
||||
|
@ -1014,7 +1008,6 @@ fn test_rchunksator() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_rchunksator_0() {
|
||||
let v = &[1, 2, 3, 4];
|
||||
let _it = v.rchunks(0);
|
||||
|
@ -1039,7 +1032,6 @@ fn test_rchunks_exactator() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_rchunks_exactator_0() {
|
||||
let v = &[1, 2, 3, 4];
|
||||
let _it = v.rchunks_exact(0);
|
||||
|
@ -1092,7 +1084,6 @@ fn test_vec_default() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_overflow_does_not_cause_segfault() {
|
||||
let mut v = vec![];
|
||||
v.reserve_exact(!0);
|
||||
|
@ -1102,7 +1093,6 @@ fn test_overflow_does_not_cause_segfault() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_overflow_does_not_cause_segfault_managed() {
|
||||
let mut v = vec![Rc::new(1)];
|
||||
v.reserve_exact(!0);
|
||||
|
@ -1278,7 +1268,6 @@ fn test_mut_chunks_rev() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mut_chunks_0() {
|
||||
let mut v = [1, 2, 3, 4];
|
||||
let _it = v.chunks_mut(0);
|
||||
|
@ -1311,7 +1300,6 @@ fn test_mut_chunks_exact_rev() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mut_chunks_exact_0() {
|
||||
let mut v = [1, 2, 3, 4];
|
||||
let _it = v.chunks_exact_mut(0);
|
||||
|
@ -1344,7 +1332,6 @@ fn test_mut_rchunks_rev() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mut_rchunks_0() {
|
||||
let mut v = [1, 2, 3, 4];
|
||||
let _it = v.rchunks_mut(0);
|
||||
|
@ -1377,7 +1364,6 @@ fn test_mut_rchunks_exact_rev() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mut_rchunks_exact_0() {
|
||||
let mut v = [1, 2, 3, 4];
|
||||
let _it = v.rchunks_exact_mut(0);
|
||||
|
@ -1411,7 +1397,7 @@ fn test_box_slice_clone() {
|
|||
#[test]
|
||||
#[allow(unused_must_use)] // here, we care about the side effects of `.clone()`
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
#[cfg(not(miri))] // Miri does not support threads nor entropy
|
||||
fn test_box_slice_clone_panics() {
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
@ -1476,7 +1462,6 @@ fn test_copy_from_slice() {
|
|||
|
||||
#[test]
|
||||
#[should_panic(expected = "destination and source slices have different lengths")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_copy_from_slice_dst_longer() {
|
||||
let src = [0, 1, 2, 3];
|
||||
let mut dst = [0; 5];
|
||||
|
@ -1485,7 +1470,6 @@ fn test_copy_from_slice_dst_longer() {
|
|||
|
||||
#[test]
|
||||
#[should_panic(expected = "destination and source slices have different lengths")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_copy_from_slice_dst_shorter() {
|
||||
let src = [0, 1, 2, 3];
|
||||
let mut dst = [0; 3];
|
||||
|
@ -1605,7 +1589,7 @@ thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
|
|||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)] // no threads
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
#[cfg(not(miri))] // Miri does not support threads nor entropy
|
||||
fn panic_safe() {
|
||||
let prev = panic::take_hook();
|
||||
panic::set_hook(Box::new(move |info| {
|
||||
|
|
|
@ -7,7 +7,7 @@ fn test_le() {
|
|||
assert!("" <= "");
|
||||
assert!("" <= "foo");
|
||||
assert!("foo" <= "foo");
|
||||
assert!("foo" != "bar");
|
||||
assert_ne!("foo", "bar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -351,7 +351,6 @@ mod slice_index {
|
|||
// to be used in `should_panic`)
|
||||
#[test]
|
||||
#[should_panic(expected = "out of bounds")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn assert_range_eq_can_fail_by_panic() {
|
||||
assert_range_eq!("abc", 0..5, "abc");
|
||||
}
|
||||
|
@ -361,7 +360,6 @@ mod slice_index {
|
|||
// to be used in `should_panic`)
|
||||
#[test]
|
||||
#[should_panic(expected = "==")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn assert_range_eq_can_fail_by_inequality() {
|
||||
assert_range_eq!("abc", 0..2, "abc");
|
||||
}
|
||||
|
@ -409,7 +407,6 @@ mod slice_index {
|
|||
|
||||
#[test]
|
||||
#[should_panic(expected = $expect_msg)]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn index_fail() {
|
||||
let v: String = $data.into();
|
||||
let v: &str = &v;
|
||||
|
@ -418,7 +415,6 @@ mod slice_index {
|
|||
|
||||
#[test]
|
||||
#[should_panic(expected = $expect_msg)]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn index_mut_fail() {
|
||||
let mut v: String = $data.into();
|
||||
let v: &mut str = &mut v;
|
||||
|
@ -514,7 +510,6 @@ mod slice_index {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_slice_fail() {
|
||||
&"中华Việt Nam"[0..2];
|
||||
}
|
||||
|
@ -666,14 +661,12 @@ mod slice_index {
|
|||
// check the panic includes the prefix of the sliced string
|
||||
#[test]
|
||||
#[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_slice_fail_truncated_1() {
|
||||
&LOREM_PARAGRAPH[..1024];
|
||||
}
|
||||
// check the truncation in the panic message
|
||||
#[test]
|
||||
#[should_panic(expected="luctus, im`[...]")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_slice_fail_truncated_2() {
|
||||
&LOREM_PARAGRAPH[..1024];
|
||||
}
|
||||
|
@ -688,7 +681,6 @@ fn test_str_slice_rangetoinclusive_ok() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_str_slice_rangetoinclusive_notok() {
|
||||
let s = "abcαβγ";
|
||||
&s[..=3];
|
||||
|
@ -704,7 +696,6 @@ fn test_str_slicemut_rangetoinclusive_ok() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_str_slicemut_rangetoinclusive_notok() {
|
||||
let mut s = "abcαβγ".to_owned();
|
||||
let s: &mut str = &mut s;
|
||||
|
@ -894,7 +885,6 @@ fn test_as_bytes() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_as_bytes_fail() {
|
||||
// Don't double free. (I'm not sure if this exercises the
|
||||
// original problem code path anymore.)
|
||||
|
@ -984,7 +974,6 @@ fn test_split_at_mut() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_split_at_boundscheck() {
|
||||
let s = "ศไทย中华Việt Nam";
|
||||
s.split_at(1);
|
||||
|
|
|
@ -231,7 +231,6 @@ fn test_split_off_empty() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_split_off_past_end() {
|
||||
let orig = "Hello, world!";
|
||||
let mut split = String::from(orig);
|
||||
|
@ -240,7 +239,6 @@ fn test_split_off_past_end() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_split_off_mid_char() {
|
||||
let mut orig = String::from("山");
|
||||
orig.split_off(1);
|
||||
|
@ -289,7 +287,6 @@ fn test_str_truncate_invalid_len() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_str_truncate_split_codepoint() {
|
||||
let mut s = String::from("\u{FC}"); // ü
|
||||
s.truncate(1);
|
||||
|
@ -324,7 +321,6 @@ fn remove() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn remove_bad() {
|
||||
"ศ".to_string().remove(1);
|
||||
}
|
||||
|
@ -360,13 +356,11 @@ fn insert() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn insert_bad1() {
|
||||
"".to_string().insert(1, 't');
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn insert_bad2() {
|
||||
"ệ".to_string().insert(1, 't');
|
||||
}
|
||||
|
@ -447,7 +441,6 @@ fn test_replace_range() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_replace_range_char_boundary() {
|
||||
let mut s = "Hello, 世界!".to_owned();
|
||||
s.replace_range(..8, "");
|
||||
|
@ -464,7 +457,6 @@ fn test_replace_range_inclusive_range() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_replace_range_out_of_bounds() {
|
||||
let mut s = String::from("12345");
|
||||
s.replace_range(5..6, "789");
|
||||
|
@ -472,7 +464,6 @@ fn test_replace_range_out_of_bounds() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_replace_range_inclusive_out_of_bounds() {
|
||||
let mut s = String::from("12345");
|
||||
s.replace_range(5..=5, "789");
|
||||
|
|
|
@ -368,7 +368,6 @@ fn test_vec_truncate_drop() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_vec_truncate_fail() {
|
||||
struct BadElem(i32);
|
||||
impl Drop for BadElem {
|
||||
|
@ -392,7 +391,6 @@ fn test_index() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_index_out_of_bounds() {
|
||||
let vec = vec![1, 2, 3];
|
||||
let _ = vec[3];
|
||||
|
@ -400,7 +398,6 @@ fn test_index_out_of_bounds() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_slice_out_of_bounds_1() {
|
||||
let x = vec![1, 2, 3, 4, 5];
|
||||
&x[!0..];
|
||||
|
@ -408,7 +405,6 @@ fn test_slice_out_of_bounds_1() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_slice_out_of_bounds_2() {
|
||||
let x = vec![1, 2, 3, 4, 5];
|
||||
&x[..6];
|
||||
|
@ -416,7 +412,6 @@ fn test_slice_out_of_bounds_2() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_slice_out_of_bounds_3() {
|
||||
let x = vec![1, 2, 3, 4, 5];
|
||||
&x[!0..4];
|
||||
|
@ -424,7 +419,6 @@ fn test_slice_out_of_bounds_3() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_slice_out_of_bounds_4() {
|
||||
let x = vec![1, 2, 3, 4, 5];
|
||||
&x[1..6];
|
||||
|
@ -432,7 +426,6 @@ fn test_slice_out_of_bounds_4() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_slice_out_of_bounds_5() {
|
||||
let x = vec![1, 2, 3, 4, 5];
|
||||
&x[3..2];
|
||||
|
@ -440,7 +433,6 @@ fn test_slice_out_of_bounds_5() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_swap_remove_empty() {
|
||||
let mut vec = Vec::<i32>::new();
|
||||
vec.swap_remove(0);
|
||||
|
@ -511,7 +503,6 @@ fn test_drain_items_zero_sized() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_drain_out_of_bounds() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
v.drain(5..6);
|
||||
|
@ -585,7 +576,6 @@ fn test_drain_max_vec_size() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_drain_inclusive_out_of_bounds() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
v.drain(5..=5);
|
||||
|
@ -615,7 +605,6 @@ fn test_splice_inclusive_range() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_splice_out_of_bounds() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
let a = [10, 11, 12];
|
||||
|
@ -624,7 +613,6 @@ fn test_splice_out_of_bounds() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_splice_inclusive_out_of_bounds() {
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
let a = [10, 11, 12];
|
||||
|
|
|
@ -108,7 +108,6 @@ fn test_index() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_index_out_of_bounds() {
|
||||
let mut deq = VecDeque::new();
|
||||
for i in 1..4 {
|
||||
|
|
|
@ -567,6 +567,32 @@ pub trait Ord: Eq + PartialOrd<Self> {
|
|||
where Self: Sized {
|
||||
if self <= other { self } else { other }
|
||||
}
|
||||
|
||||
/// Returns max if self is greater than max, and min if self is less than min.
|
||||
/// Otherwise this will return self. Panics if min > max.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(clamp)]
|
||||
///
|
||||
/// assert!((-3).clamp(-2, 1) == -2);
|
||||
/// assert!(0.clamp(-2, 1) == 0);
|
||||
/// assert!(2.clamp(-2, 1) == 1);
|
||||
/// ```
|
||||
#[unstable(feature = "clamp", issue = "44095")]
|
||||
fn clamp(self, min: Self, max: Self) -> Self
|
||||
where Self: Sized {
|
||||
assert!(min <= max);
|
||||
if self < min {
|
||||
min
|
||||
}
|
||||
else if self > max {
|
||||
max
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
@ -79,9 +79,9 @@ impl fmt::Debug for VaListImpl {
|
|||
all supported platforms",
|
||||
issue = "44930")]
|
||||
struct VaListImpl {
|
||||
stack: *mut (),
|
||||
gr_top: *mut (),
|
||||
vr_top: *mut (),
|
||||
stack: *mut c_void,
|
||||
gr_top: *mut c_void,
|
||||
vr_top: *mut c_void,
|
||||
gr_offs: i32,
|
||||
vr_offs: i32,
|
||||
}
|
||||
|
@ -98,8 +98,8 @@ struct VaListImpl {
|
|||
gpr: u8,
|
||||
fpr: u8,
|
||||
reserved: u16,
|
||||
overflow_arg_area: *mut (),
|
||||
reg_save_area: *mut (),
|
||||
overflow_arg_area: *mut c_void,
|
||||
reg_save_area: *mut c_void,
|
||||
}
|
||||
|
||||
/// x86_64 ABI implementation of a `va_list`.
|
||||
|
@ -113,8 +113,8 @@ struct VaListImpl {
|
|||
struct VaListImpl {
|
||||
gp_offset: i32,
|
||||
fp_offset: i32,
|
||||
overflow_arg_area: *mut (),
|
||||
reg_save_area: *mut (),
|
||||
overflow_arg_area: *mut c_void,
|
||||
reg_save_area: *mut c_void,
|
||||
}
|
||||
|
||||
/// A wrapper for a `va_list`
|
||||
|
|
|
@ -1198,7 +1198,7 @@ impl<I: Iterator> Peekable<I> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator that rejects elements while `predicate` is true.
|
||||
/// An iterator that rejects elements while `predicate` returns `true`.
|
||||
///
|
||||
/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its
|
||||
/// documentation for more.
|
||||
|
@ -1286,7 +1286,7 @@ impl<I: Iterator, P> Iterator for SkipWhile<I, P>
|
|||
impl<I, P> FusedIterator for SkipWhile<I, P>
|
||||
where I: FusedIterator, P: FnMut(&I::Item) -> bool {}
|
||||
|
||||
/// An iterator that only accepts elements while `predicate` is true.
|
||||
/// An iterator that only accepts elements while `predicate` returns `true`.
|
||||
///
|
||||
/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its
|
||||
/// documentation for more.
|
||||
|
|
|
@ -39,8 +39,7 @@ unsafe impl<A: Clone> TrustedLen for Repeat<A> {}
|
|||
|
||||
/// Creates a new iterator that endlessly repeats a single element.
|
||||
///
|
||||
/// The `repeat()` function repeats a single value over and over and over and
|
||||
/// over and over and 🔁.
|
||||
/// The `repeat()` function repeats a single value over and over again.
|
||||
///
|
||||
/// Infinite iterators like `repeat()` are often used with adapters like
|
||||
/// [`take`], in order to make them finite.
|
||||
|
@ -128,8 +127,7 @@ unsafe impl<A, F: FnMut() -> A> TrustedLen for RepeatWith<F> {}
|
|||
/// Creates a new iterator that repeats elements of type `A` endlessly by
|
||||
/// applying the provided closure, the repeater, `F: FnMut() -> A`.
|
||||
///
|
||||
/// The `repeat_with()` function calls the repeater over and over and over and
|
||||
/// over and over and 🔁.
|
||||
/// The `repeat_with()` function calls the repeater over and over again.
|
||||
///
|
||||
/// Infinite iterators like `repeat_with()` are often used with adapters like
|
||||
/// [`take`], in order to make them finite.
|
||||
|
|
|
@ -1111,11 +1111,12 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
|
|||
/// ```
|
||||
///
|
||||
/// The compiler then knows to not make any incorrect assumptions or optimizations on this code.
|
||||
//
|
||||
// FIXME before stabilizing, explain how to initialize a struct field-by-field.
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
||||
#[derive(Copy)]
|
||||
// NOTE after stabilizing `MaybeUninit` proceed to deprecate `mem::uninitialized`.
|
||||
// NOTE: after stabilizing `MaybeUninit`, proceed to deprecate `mem::uninitialized`.
|
||||
pub union MaybeUninit<T> {
|
||||
uninit: (),
|
||||
value: ManuallyDrop<T>,
|
||||
|
@ -1125,13 +1126,13 @@ pub union MaybeUninit<T> {
|
|||
impl<T: Copy> Clone for MaybeUninit<T> {
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> Self {
|
||||
// Not calling T::clone(), we cannot know if we are initialized enough for that.
|
||||
// Not calling `T::clone()`, we cannot know if we are initialized enough for that.
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MaybeUninit<T> {
|
||||
/// Create a new `MaybeUninit<T>` initialized with the given value.
|
||||
/// Creates a new `MaybeUninit<T>` initialized with the given value.
|
||||
///
|
||||
/// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
|
||||
/// It is your responsibility to make sure `T` gets dropped if it got initialized.
|
||||
|
@ -1239,6 +1240,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// let x_vec = unsafe { &*x.as_ptr() };
|
||||
/// // We have created a reference to an uninitialized vector! This is undefined behavior.
|
||||
/// ```
|
||||
///
|
||||
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
|
||||
/// until they are, it is advisable to avoid them.)
|
||||
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
||||
|
@ -1277,6 +1279,7 @@ impl<T> MaybeUninit<T> {
|
|||
/// let x_vec = unsafe { &mut *x.as_mut_ptr() };
|
||||
/// // We have created a reference to an uninitialized vector! This is undefined behavior.
|
||||
/// ```
|
||||
///
|
||||
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
|
||||
/// until they are, it is advisable to avoid them.)
|
||||
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
||||
|
|
|
@ -326,7 +326,7 @@ pub fn algorithm_m<T: RawFloat>(f: &Big, e: i16) -> T {
|
|||
round_by_remainder(v, rem, q, z)
|
||||
}
|
||||
|
||||
/// Skip over most Algorithm M iterations by checking the bit length.
|
||||
/// Skips over most Algorithm M iterations by checking the bit length.
|
||||
fn quick_start<T: RawFloat>(u: &mut Big, v: &mut Big, k: &mut i16) {
|
||||
// The bit length is an estimate of the base two logarithm, and log(u / v) = log(u) - log(v).
|
||||
// The estimate is off by at most 1, but always an under-estimate, so the error on log(u)
|
||||
|
|
|
@ -304,8 +304,8 @@ fn simplify(decimal: &mut Decimal) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Quick and dirty upper bound on the size (log10) of the largest value that Algorithm R and
|
||||
/// Algorithm M will compute while working on the given decimal.
|
||||
/// Returns a quick-an-dirty upper bound on the size (log10) of the largest value that Algorithm R
|
||||
/// and Algorithm M will compute while working on the given decimal.
|
||||
fn bound_intermediate_digits(decimal: &Decimal, e: i64) -> u64 {
|
||||
// We don't need to worry too much about overflow here thanks to trivial_cases() and the
|
||||
// parser, which filter out the most extreme inputs for us.
|
||||
|
@ -324,7 +324,7 @@ fn bound_intermediate_digits(decimal: &Decimal, e: i64) -> u64 {
|
|||
}
|
||||
}
|
||||
|
||||
/// Detect obvious overflows and underflows without even looking at the decimal digits.
|
||||
/// Detects obvious overflows and underflows without even looking at the decimal digits.
|
||||
fn trivial_cases<T: RawFloat>(decimal: &Decimal) -> Option<T> {
|
||||
// There were zeros but they were stripped by simplify()
|
||||
if decimal.integral.is_empty() && decimal.fractional.is_empty() {
|
||||
|
|
|
@ -78,7 +78,7 @@ pub fn parse_decimal(s: &str) -> ParseResult {
|
|||
}
|
||||
}
|
||||
|
||||
/// Carve off decimal digits up to the first non-digit character.
|
||||
/// Carves off decimal digits up to the first non-digit character.
|
||||
fn eat_digits(s: &[u8]) -> (&[u8], &[u8]) {
|
||||
let mut i = 0;
|
||||
while i < s.len() && b'0' <= s[i] && s[i] <= b'9' {
|
||||
|
|
|
@ -10,7 +10,7 @@ use num::dec2flt::rawfp::RawFloat;
|
|||
///
|
||||
/// - Any number from `(mant - minus) * 2^exp` to `(mant + plus) * 2^exp` will
|
||||
/// round to the original value. The range is inclusive only when
|
||||
/// `inclusive` is true.
|
||||
/// `inclusive` is `true`.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Decoded {
|
||||
/// The scaled mantissa.
|
||||
|
|
|
@ -315,15 +315,15 @@ fn digits_to_dec_str<'a>(buf: &'a [u8], exp: i16, frac_digits: usize,
|
|||
}
|
||||
}
|
||||
|
||||
/// Formats given decimal digits `0.<...buf...> * 10^exp` into the exponential form
|
||||
/// with at least given number of significant digits. When `upper` is true,
|
||||
/// Formats the given decimal digits `0.<...buf...> * 10^exp` into the exponential
|
||||
/// form with at least the given number of significant digits. When `upper` is `true`,
|
||||
/// the exponent will be prefixed by `E`; otherwise that's `e`. The result is
|
||||
/// stored to the supplied parts array and a slice of written parts is returned.
|
||||
///
|
||||
/// `min_digits` can be less than the number of actual significant digits in `buf`;
|
||||
/// it will be ignored and full digits will be printed. It is only used to print
|
||||
/// additional zeroes after rendered digits. Thus `min_digits` of 0 means that
|
||||
/// it will only print given digits and nothing else.
|
||||
/// additional zeroes after rendered digits. Thus, `min_digits == 0` means that
|
||||
/// it will only print the given digits and nothing else.
|
||||
fn digits_to_exp_str<'a>(buf: &'a [u8], exp: i16, min_ndigits: usize, upper: bool,
|
||||
parts: &'a mut [Part<'a>]) -> &'a [Part<'a>] {
|
||||
assert!(!buf.is_empty());
|
||||
|
@ -384,7 +384,7 @@ fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static
|
|||
}
|
||||
}
|
||||
|
||||
/// Formats given floating point number into the decimal form with at least
|
||||
/// Formats the given floating point number into the decimal form with at least
|
||||
/// given number of fractional digits. The result is stored to the supplied parts
|
||||
/// array while utilizing given byte buffer as a scratch. `upper` is currently
|
||||
/// unused but left for the future decision to change the case of non-finite values,
|
||||
|
@ -438,7 +438,7 @@ pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T,
|
|||
}
|
||||
}
|
||||
|
||||
/// Formats given floating point number into the decimal form or
|
||||
/// Formats the given floating point number into the decimal form or
|
||||
/// the exponential form, depending on the resulting exponent. The result is
|
||||
/// stored to the supplied parts array while utilizing given byte buffer
|
||||
/// as a scratch. `upper` is used to determine the case of non-finite values
|
||||
|
@ -497,7 +497,7 @@ pub fn to_shortest_exp_str<'a, T, F>(mut format_shortest: F, v: T,
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns rather crude approximation (upper bound) for the maximum buffer size
|
||||
/// Returns a rather crude approximation (upper bound) for the maximum buffer size
|
||||
/// calculated from the given decoded exponent.
|
||||
///
|
||||
/// The exact limit is:
|
||||
|
|
|
@ -71,7 +71,7 @@ impl fmt::Debug for RangeFull {
|
|||
/// assert_eq!(arr[1..=3], [ 1,2,3 ]);
|
||||
/// ```
|
||||
#[doc(alias = "..")]
|
||||
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
||||
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Range<Idx> {
|
||||
/// The lower bound of the range (inclusive).
|
||||
|
@ -95,8 +95,6 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_contains)]
|
||||
///
|
||||
/// use std::f32;
|
||||
///
|
||||
/// assert!(!(3..5).contains(&2));
|
||||
|
@ -112,7 +110,7 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
|
|||
/// assert!(!(0.0..f32::NAN).contains(&0.5));
|
||||
/// assert!(!(f32::NAN..1.0).contains(&0.5));
|
||||
/// ```
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
#[stable(feature = "range_contains", since = "1.35.0")]
|
||||
pub fn contains<U>(&self, item: &U) -> bool
|
||||
where
|
||||
Idx: PartialOrd<U>,
|
||||
|
@ -175,7 +173,7 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
|
|||
///
|
||||
/// [`Iterator`]: ../iter/trait.IntoIterator.html
|
||||
#[doc(alias = "..")]
|
||||
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
||||
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct RangeFrom<Idx> {
|
||||
/// The lower bound of the range (inclusive).
|
||||
|
@ -196,8 +194,6 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_contains)]
|
||||
///
|
||||
/// use std::f32;
|
||||
///
|
||||
/// assert!(!(3..).contains(&2));
|
||||
|
@ -208,7 +204,7 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
|
|||
/// assert!(!(0.0..).contains(&f32::NAN));
|
||||
/// assert!(!(f32::NAN..).contains(&0.5));
|
||||
/// ```
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
#[stable(feature = "range_contains", since = "1.35.0")]
|
||||
pub fn contains<U>(&self, item: &U) -> bool
|
||||
where
|
||||
Idx: PartialOrd<U>,
|
||||
|
@ -280,8 +276,6 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_contains)]
|
||||
///
|
||||
/// use std::f32;
|
||||
///
|
||||
/// assert!( (..5).contains(&-1_000_000_000));
|
||||
|
@ -292,7 +286,7 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
|
|||
/// assert!(!(..1.0).contains(&f32::NAN));
|
||||
/// assert!(!(..f32::NAN).contains(&0.5));
|
||||
/// ```
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
#[stable(feature = "range_contains", since = "1.35.0")]
|
||||
pub fn contains<U>(&self, item: &U) -> bool
|
||||
where
|
||||
Idx: PartialOrd<U>,
|
||||
|
@ -329,7 +323,7 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
|
|||
/// assert_eq!(arr[1..=3], [ 1,2,3 ]); // RangeInclusive
|
||||
/// ```
|
||||
#[doc(alias = "..=")]
|
||||
#[derive(Clone)] // not Copy -- see #27186
|
||||
#[derive(Clone)] // not Copy -- see #27186
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
pub struct RangeInclusive<Idx> {
|
||||
pub(crate) start: Idx,
|
||||
|
@ -365,7 +359,8 @@ impl<T: PartialOrd> RangeInclusiveEquality for T {
|
|||
impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.start == other.start && self.end == other.end
|
||||
self.start == other.start
|
||||
&& self.end == other.end
|
||||
&& RangeInclusiveEquality::canonicalized_is_empty(self)
|
||||
== RangeInclusiveEquality::canonicalized_is_empty(other)
|
||||
}
|
||||
|
@ -397,7 +392,11 @@ impl<Idx> RangeInclusive<Idx> {
|
|||
#[inline]
|
||||
#[rustc_promotable]
|
||||
pub const fn new(start: Idx, end: Idx) -> Self {
|
||||
Self { start, end, is_empty: None }
|
||||
Self {
|
||||
start,
|
||||
end,
|
||||
is_empty: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the lower bound of the range (inclusive).
|
||||
|
@ -478,8 +477,6 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_contains)]
|
||||
///
|
||||
/// use std::f32;
|
||||
///
|
||||
/// assert!(!(3..=5).contains(&2));
|
||||
|
@ -496,7 +493,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
|||
/// assert!(!(0.0..=f32::NAN).contains(&0.0));
|
||||
/// assert!(!(f32::NAN..=1.0).contains(&1.0));
|
||||
/// ```
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
#[stable(feature = "range_contains", since = "1.35.0")]
|
||||
pub fn contains<U>(&self, item: &U) -> bool
|
||||
where
|
||||
Idx: PartialOrd<U>,
|
||||
|
@ -609,15 +606,12 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
|
||||
/// Returns `true` if `item` is contained in the range.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_contains)]
|
||||
///
|
||||
/// use std::f32;
|
||||
///
|
||||
/// assert!( (..=5).contains(&-1_000_000_000));
|
||||
|
@ -628,7 +622,7 @@ impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
|
|||
/// assert!(!(..=1.0).contains(&f32::NAN));
|
||||
/// assert!(!(..=f32::NAN).contains(&0.5));
|
||||
/// ```
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
#[stable(feature = "range_contains", since = "1.35.0")]
|
||||
pub fn contains<U>(&self, item: &U) -> bool
|
||||
where
|
||||
Idx: PartialOrd<U>,
|
||||
|
@ -730,14 +724,11 @@ pub trait RangeBounds<T: ?Sized> {
|
|||
#[stable(feature = "collections_range", since = "1.28.0")]
|
||||
fn end_bound(&self) -> Bound<&T>;
|
||||
|
||||
|
||||
/// Returns `true` if `item` is contained in the range.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(range_contains)]
|
||||
///
|
||||
/// use std::f32;
|
||||
///
|
||||
/// assert!( (3..5).contains(&4));
|
||||
|
@ -747,7 +738,7 @@ pub trait RangeBounds<T: ?Sized> {
|
|||
/// assert!(!(0.0..1.0).contains(&f32::NAN));
|
||||
/// assert!(!(0.0..f32::NAN).contains(&0.5));
|
||||
/// assert!(!(f32::NAN..1.0).contains(&0.5));
|
||||
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
|
||||
#[stable(feature = "range_contains", since = "1.35.0")]
|
||||
fn contains<U>(&self, item: &U) -> bool
|
||||
where
|
||||
T: PartialOrd<U>,
|
||||
|
@ -757,9 +748,7 @@ pub trait RangeBounds<T: ?Sized> {
|
|||
Included(ref start) => *start <= item,
|
||||
Excluded(ref start) => *start < item,
|
||||
Unbounded => true,
|
||||
})
|
||||
&&
|
||||
(match self.end_bound() {
|
||||
}) && (match self.end_bound() {
|
||||
Included(ref end) => item <= *end,
|
||||
Excluded(ref end) => item < *end,
|
||||
Unbounded => true,
|
||||
|
@ -835,7 +824,7 @@ impl<T> RangeBounds<T> for (Bound<T>, Bound<T>) {
|
|||
match *self {
|
||||
(Included(ref start), _) => Included(start),
|
||||
(Excluded(ref start), _) => Excluded(start),
|
||||
(Unbounded, _) => Unbounded,
|
||||
(Unbounded, _) => Unbounded,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -843,7 +832,7 @@ impl<T> RangeBounds<T> for (Bound<T>, Bound<T>) {
|
|||
match *self {
|
||||
(_, Included(ref end)) => Included(end),
|
||||
(_, Excluded(ref end)) => Excluded(end),
|
||||
(_, Unbounded) => Unbounded,
|
||||
(_, Unbounded) => Unbounded,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,7 +210,7 @@ impl<T> Option<T> {
|
|||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Option<T>` to `Option<&T>`.
|
||||
/// Converts from `&Option<T>` to `Option<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -239,7 +239,7 @@ impl<T> Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts from `Option<T>` to `Option<&mut T>`.
|
||||
/// Converts from `&mut Option<T>` to `Option<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -881,15 +881,13 @@ impl<T: Copy> Option<&T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(copied)]
|
||||
///
|
||||
/// let x = 12;
|
||||
/// let opt_x = Some(&x);
|
||||
/// assert_eq!(opt_x, Some(&12));
|
||||
/// let copied = opt_x.copied();
|
||||
/// assert_eq!(copied, Some(12));
|
||||
/// ```
|
||||
#[unstable(feature = "copied", issue = "57126")]
|
||||
#[stable(feature = "copied", since = "1.35.0")]
|
||||
pub fn copied(self) -> Option<T> {
|
||||
self.map(|&t| t)
|
||||
}
|
||||
|
@ -902,15 +900,13 @@ impl<T: Copy> Option<&mut T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(copied)]
|
||||
///
|
||||
/// let mut x = 12;
|
||||
/// let opt_x = Some(&mut x);
|
||||
/// assert_eq!(opt_x, Some(&mut 12));
|
||||
/// let copied = opt_x.copied();
|
||||
/// assert_eq!(copied, Some(12));
|
||||
/// ```
|
||||
#[unstable(feature = "copied", issue = "57126")]
|
||||
#[stable(feature = "copied", since = "1.35.0")]
|
||||
pub fn copied(self) -> Option<T> {
|
||||
self.map(|&mut t| t)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Types which pin data to its location in memory
|
||||
//! Types that pin data to its location in memory.
|
||||
//!
|
||||
//! It is sometimes useful to have objects that are guaranteed to not move,
|
||||
//! in the sense that their placement in memory does not change, and can thus be relied upon.
|
||||
|
|
|
@ -369,7 +369,7 @@ impl<T, E> Result<T, E> {
|
|||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Result<T, E>` to `Result<&T, &E>`.
|
||||
/// Converts from `&Result<T, E>` to `Result<&T, &E>`.
|
||||
///
|
||||
/// Produces a new `Result`, containing a reference
|
||||
/// into the original, leaving the original in place.
|
||||
|
@ -394,7 +394,7 @@ impl<T, E> Result<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts from `Result<T, E>` to `Result<&mut T, &mut E>`.
|
||||
/// Converts from `&mut Result<T, E>` to `Result<&mut T, &mut E>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
@ -2968,7 +2968,7 @@ impl str {
|
|||
///
|
||||
/// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
|
||||
/// allows a reverse search and forward/reverse search yields the same
|
||||
/// elements. This is true for, eg, [`char`] but not for `&str`.
|
||||
/// elements. This is true for, e.g., [`char`], but not for `&str`.
|
||||
///
|
||||
/// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
|
||||
///
|
||||
|
@ -3143,7 +3143,7 @@ impl str {
|
|||
///
|
||||
/// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
|
||||
/// allows a reverse search and forward/reverse search yields the same
|
||||
/// elements. This is true for, eg, [`char`] but not for `&str`.
|
||||
/// elements. This is true for, e.g., [`char`], but not for `&str`.
|
||||
///
|
||||
/// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
|
||||
///
|
||||
|
@ -3326,7 +3326,7 @@ impl str {
|
|||
///
|
||||
/// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
|
||||
/// allows a reverse search and forward/reverse search yields the same
|
||||
/// elements. This is true for, eg, [`char`] but not for `&str`.
|
||||
/// elements. This is true for, e.g., [`char`], but not for `&str`.
|
||||
///
|
||||
/// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
|
||||
///
|
||||
|
@ -3402,7 +3402,7 @@ impl str {
|
|||
///
|
||||
/// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
|
||||
/// allows a reverse search and forward/reverse search yields the same
|
||||
/// elements. This is true for, eg, [`char`] but not for `&str`.
|
||||
/// elements. This is true for, e.g., [`char`], but not for `&str`.
|
||||
///
|
||||
/// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
|
||||
///
|
||||
|
|
|
@ -108,7 +108,7 @@ impl Waker {
|
|||
unsafe { (self.waker.vtable.wake)(self.waker.data) }
|
||||
}
|
||||
|
||||
/// Returns whether or not this `Waker` and other `Waker` have awaken the same task.
|
||||
/// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
|
||||
///
|
||||
/// This function works on a best-effort basis, and may return false even
|
||||
/// when the `Waker`s would awaken the same task. However, if this function
|
||||
|
|
|
@ -5,15 +5,15 @@ use std::mem::drop;
|
|||
#[test]
|
||||
fn smoketest_cell() {
|
||||
let x = Cell::new(10);
|
||||
assert!(x == Cell::new(10));
|
||||
assert!(x.get() == 10);
|
||||
assert_eq!(x, Cell::new(10));
|
||||
assert_eq!(x.get(), 10);
|
||||
x.set(20);
|
||||
assert!(x == Cell::new(20));
|
||||
assert!(x.get() == 20);
|
||||
assert_eq!(x, Cell::new(20));
|
||||
assert_eq!(x.get(), 20);
|
||||
|
||||
let y = Cell::new((30, 40));
|
||||
assert!(y == Cell::new((30, 40)));
|
||||
assert!(y.get() == (30, 40));
|
||||
assert_eq!(y, Cell::new((30, 40)));
|
||||
assert_eq!(y.get(), (30, 40));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -109,7 +109,6 @@ fn double_borrow_single_release_no_borrow_mut() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn discard_doesnt_unborrow() {
|
||||
let x = RefCell::new(0);
|
||||
let _b = x.borrow();
|
||||
|
@ -350,7 +349,6 @@ fn refcell_ref_coercion() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn refcell_swap_borrows() {
|
||||
let x = RefCell::new(0);
|
||||
let _b = x.borrow();
|
||||
|
@ -360,7 +358,6 @@ fn refcell_swap_borrows() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn refcell_replace_borrows() {
|
||||
let x = RefCell::new(0);
|
||||
let _b = x.borrow();
|
||||
|
|
|
@ -253,7 +253,6 @@ fn test_iterator_step_by_nth_overflow() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_iterator_step_by_zero() {
|
||||
let mut it = (0..).step_by(0);
|
||||
it.next();
|
||||
|
@ -1442,7 +1441,6 @@ fn test_rposition() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_rposition_panic() {
|
||||
let v: [(Box<_>, Box<_>); 4] =
|
||||
[(box 0, box 0), (box 0, box 0),
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#![feature(box_syntax)]
|
||||
#![feature(cell_update)]
|
||||
#![feature(copied)]
|
||||
#![feature(core_private_bignum)]
|
||||
#![feature(core_private_diy_float)]
|
||||
#![feature(dec2flt)]
|
||||
|
|
|
@ -3,7 +3,6 @@ use core::num::bignum::tests::Big8x3 as Big;
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_from_u64_overflow() {
|
||||
Big::from_u64(0x1000000);
|
||||
}
|
||||
|
@ -20,14 +19,12 @@ fn test_add() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_add_overflow_1() {
|
||||
Big::from_small(1).add(&Big::from_u64(0xffffff));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_add_overflow_2() {
|
||||
Big::from_u64(0xffffff).add(&Big::from_small(1));
|
||||
}
|
||||
|
@ -45,7 +42,6 @@ fn test_add_small() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_add_small_overflow() {
|
||||
Big::from_u64(0xffffff).add_small(1);
|
||||
}
|
||||
|
@ -61,14 +57,12 @@ fn test_sub() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_sub_underflow_1() {
|
||||
Big::from_u64(0x10665).sub(&Big::from_u64(0x10666));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_sub_underflow_2() {
|
||||
Big::from_small(0).sub(&Big::from_u64(0x123456));
|
||||
}
|
||||
|
@ -82,7 +76,6 @@ fn test_mul_small() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mul_small_overflow() {
|
||||
Big::from_u64(0x800000).mul_small(2);
|
||||
}
|
||||
|
@ -101,14 +94,12 @@ fn test_mul_pow2() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mul_pow2_overflow_1() {
|
||||
Big::from_u64(0x1).mul_pow2(24);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mul_pow2_overflow_2() {
|
||||
Big::from_u64(0x123).mul_pow2(16);
|
||||
}
|
||||
|
@ -127,14 +118,12 @@ fn test_mul_pow5() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mul_pow5_overflow_1() {
|
||||
Big::from_small(1).mul_pow5(12);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mul_pow5_overflow_2() {
|
||||
Big::from_small(230).mul_pow5(8);
|
||||
}
|
||||
|
@ -152,14 +141,12 @@ fn test_mul_digits() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mul_digits_overflow_1() {
|
||||
Big::from_u64(0x800000).mul_digits(&[2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_mul_digits_overflow_2() {
|
||||
Big::from_u64(0x1000).mul_digits(&[0, 0x10]);
|
||||
}
|
||||
|
@ -219,7 +206,6 @@ fn test_get_bit() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_get_bit_out_of_range() {
|
||||
Big::from_small(42).get_bit(24);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ mod tests {
|
|||
fn test_overflows() {
|
||||
assert!(MAX > 0);
|
||||
assert!(MIN <= 0);
|
||||
assert!(MIN + MAX + 1 == 0);
|
||||
assert_eq!(MIN + MAX + 1, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -22,22 +22,22 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_rem_euclid() {
|
||||
assert!((-1 as $T).rem_euclid(MIN) == MAX);
|
||||
assert_eq!((-1 as $T).rem_euclid(MIN), MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_abs() {
|
||||
assert!((1 as $T).abs() == 1 as $T);
|
||||
assert!((0 as $T).abs() == 0 as $T);
|
||||
assert!((-1 as $T).abs() == 1 as $T);
|
||||
assert_eq!((1 as $T).abs(), 1 as $T);
|
||||
assert_eq!((0 as $T).abs(), 0 as $T);
|
||||
assert_eq!((-1 as $T).abs(), 1 as $T);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signum() {
|
||||
assert!((1 as $T).signum() == 1 as $T);
|
||||
assert!((0 as $T).signum() == 0 as $T);
|
||||
assert!((-0 as $T).signum() == 0 as $T);
|
||||
assert!((-1 as $T).signum() == -1 as $T);
|
||||
assert_eq!((1 as $T).signum(), 1 as $T);
|
||||
assert_eq!((0 as $T).signum(), 0 as $T);
|
||||
assert_eq!((-0 as $T).signum(), 0 as $T);
|
||||
assert_eq!((-1 as $T).signum(), -1 as $T);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -58,12 +58,12 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_bitwise_operators() {
|
||||
assert!(0b1110 as $T == (0b1100 as $T).bitor(0b1010 as $T));
|
||||
assert!(0b1000 as $T == (0b1100 as $T).bitand(0b1010 as $T));
|
||||
assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T));
|
||||
assert!(0b1110 as $T == (0b0111 as $T).shl(1));
|
||||
assert!(0b0111 as $T == (0b1110 as $T).shr(1));
|
||||
assert!(-(0b11 as $T) - (1 as $T) == (0b11 as $T).not());
|
||||
assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(0b1010 as $T));
|
||||
assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(0b1010 as $T));
|
||||
assert_eq!(0b0110 as $T, (0b1100 as $T).bitxor(0b1010 as $T));
|
||||
assert_eq!(0b1110 as $T, (0b0111 as $T).shl(1));
|
||||
assert_eq!(0b0111 as $T, (0b1110 as $T).shr(1));
|
||||
assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not());
|
||||
}
|
||||
|
||||
const A: $T = 0b0101100;
|
||||
|
@ -75,17 +75,17 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_count_ones() {
|
||||
assert!(A.count_ones() == 3);
|
||||
assert!(B.count_ones() == 2);
|
||||
assert!(C.count_ones() == 5);
|
||||
assert_eq!(A.count_ones(), 3);
|
||||
assert_eq!(B.count_ones(), 2);
|
||||
assert_eq!(C.count_ones(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_zeros() {
|
||||
let bits = mem::size_of::<$T>() * 8;
|
||||
assert!(A.count_zeros() == bits as u32 - 3);
|
||||
assert!(B.count_zeros() == bits as u32 - 2);
|
||||
assert!(C.count_zeros() == bits as u32 - 5);
|
||||
assert_eq!(A.count_zeros(), bits as u32 - 3);
|
||||
assert_eq!(B.count_zeros(), bits as u32 - 2);
|
||||
assert_eq!(C.count_zeros(), bits as u32 - 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -148,9 +148,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_signed_checked_div() {
|
||||
assert!((10 as $T).checked_div(2) == Some(5));
|
||||
assert!((5 as $T).checked_div(0) == None);
|
||||
assert!(isize::MIN.checked_div(-1) == None);
|
||||
assert_eq!((10 as $T).checked_div(2), Some(5));
|
||||
assert_eq!((5 as $T).checked_div(0), None);
|
||||
assert_eq!(isize::MIN.checked_div(-1), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -7,11 +7,11 @@ fn test_range() {
|
|||
let r = Range { start: 2, end: 10 };
|
||||
let mut count = 0;
|
||||
for (i, ri) in r.enumerate() {
|
||||
assert!(ri == i + 2);
|
||||
assert_eq!(ri, i + 2);
|
||||
assert!(ri >= 2 && ri < 10);
|
||||
count += 1;
|
||||
}
|
||||
assert!(count == 8);
|
||||
assert_eq!(count, 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -19,11 +19,11 @@ fn test_range_from() {
|
|||
let r = RangeFrom { start: 2 };
|
||||
let mut count = 0;
|
||||
for (i, ri) in r.take(10).enumerate() {
|
||||
assert!(ri == i + 2);
|
||||
assert_eq!(ri, i + 2);
|
||||
assert!(ri >= 2 && ri < 12);
|
||||
count += 1;
|
||||
}
|
||||
assert!(count == 10);
|
||||
assert_eq!(count, 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -69,7 +69,6 @@ fn test_option_dance() {
|
|||
}
|
||||
|
||||
#[test] #[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_option_too_much_dance() {
|
||||
struct A;
|
||||
let mut y = Some(A);
|
||||
|
@ -130,7 +129,6 @@ fn test_unwrap() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_unwrap_panic1() {
|
||||
let x: Option<isize> = None;
|
||||
x.unwrap();
|
||||
|
@ -138,7 +136,6 @@ fn test_unwrap_panic1() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_unwrap_panic2() {
|
||||
let x: Option<String> = None;
|
||||
x.unwrap();
|
||||
|
|
|
@ -117,7 +117,6 @@ fn test_unwrap_or_else() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
pub fn test_unwrap_or_else_panic() {
|
||||
fn handler(msg: &'static str) -> isize {
|
||||
if msg == "I got this." {
|
||||
|
@ -139,7 +138,6 @@ pub fn test_expect_ok() {
|
|||
}
|
||||
#[test]
|
||||
#[should_panic(expected="Got expected error: \"All good\"")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
pub fn test_expect_err() {
|
||||
let err: Result<isize, &'static str> = Err("All good");
|
||||
err.expect("Got expected error");
|
||||
|
@ -153,7 +151,6 @@ pub fn test_expect_err_err() {
|
|||
}
|
||||
#[test]
|
||||
#[should_panic(expected="Got expected ok: \"All good\"")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
pub fn test_expect_err_ok() {
|
||||
let err: Result<&'static str, isize> = Ok("All good");
|
||||
err.expect_err("Got expected ok");
|
||||
|
|
|
@ -782,7 +782,6 @@ mod slice_index {
|
|||
// to be used in `should_panic`)
|
||||
#[test]
|
||||
#[should_panic(expected = "out of range")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn assert_range_eq_can_fail_by_panic() {
|
||||
assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]);
|
||||
}
|
||||
|
@ -792,7 +791,6 @@ mod slice_index {
|
|||
// to be used in `should_panic`)
|
||||
#[test]
|
||||
#[should_panic(expected = "==")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn assert_range_eq_can_fail_by_inequality() {
|
||||
assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]);
|
||||
}
|
||||
|
@ -842,7 +840,6 @@ mod slice_index {
|
|||
|
||||
#[test]
|
||||
#[should_panic(expected = $expect_msg)]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn index_fail() {
|
||||
let v = $data;
|
||||
let v: &[_] = &v;
|
||||
|
@ -851,7 +848,6 @@ mod slice_index {
|
|||
|
||||
#[test]
|
||||
#[should_panic(expected = $expect_msg)]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn index_mut_fail() {
|
||||
let mut v = $data;
|
||||
let v: &mut [_] = &mut v;
|
||||
|
@ -1304,7 +1300,6 @@ fn test_copy_within() {
|
|||
|
||||
#[test]
|
||||
#[should_panic(expected = "src is out of bounds")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_copy_within_panics_src_too_long() {
|
||||
let mut bytes = *b"Hello, World!";
|
||||
// The length is only 13, so 14 is out of bounds.
|
||||
|
@ -1313,7 +1308,6 @@ fn test_copy_within_panics_src_too_long() {
|
|||
|
||||
#[test]
|
||||
#[should_panic(expected = "dest is out of bounds")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_copy_within_panics_dest_too_long() {
|
||||
let mut bytes = *b"Hello, World!";
|
||||
// The length is only 13, so a slice of length 4 starting at index 10 is out of bounds.
|
||||
|
@ -1321,7 +1315,6 @@ fn test_copy_within_panics_dest_too_long() {
|
|||
}
|
||||
#[test]
|
||||
#[should_panic(expected = "src end is before src start")]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn test_copy_within_panics_src_inverted() {
|
||||
let mut bytes = *b"Hello, World!";
|
||||
// 2 is greater than 1, so this range is invalid.
|
||||
|
|
|
@ -107,14 +107,12 @@ fn checked_sub() {
|
|||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn sub_bad1() {
|
||||
let _ = Duration::new(0, 0) - Duration::new(0, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[cfg(not(miri))] // Miri does not support panics
|
||||
fn sub_bad2() {
|
||||
let _ = Duration::new(0, 0) - Duration::new(1, 0);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ const NANOS_PER_MILLI: u32 = 1_000_000;
|
|||
const NANOS_PER_MICRO: u32 = 1_000;
|
||||
const MILLIS_PER_SEC: u64 = 1_000;
|
||||
const MICROS_PER_SEC: u64 = 1_000_000;
|
||||
const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64;
|
||||
|
||||
/// A `Duration` type to represent a span of time, typically used for system
|
||||
/// timeouts.
|
||||
|
@ -510,15 +509,34 @@ impl Duration {
|
|||
/// use std::time::Duration;
|
||||
///
|
||||
/// let dur = Duration::new(2, 700_000_000);
|
||||
/// assert_eq!(dur.as_float_secs(), 2.7);
|
||||
/// assert_eq!(dur.as_secs_f64(), 2.7);
|
||||
/// ```
|
||||
#[unstable(feature = "duration_float", issue = "54361")]
|
||||
#[inline]
|
||||
pub const fn as_float_secs(&self) -> f64 {
|
||||
pub const fn as_secs_f64(&self) -> f64 {
|
||||
(self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
|
||||
}
|
||||
|
||||
/// Creates a new `Duration` from the specified number of seconds.
|
||||
/// Returns the number of seconds contained by this `Duration` as `f32`.
|
||||
///
|
||||
/// The returned value does include the fractional (nanosecond) part of the duration.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// #![feature(duration_float)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let dur = Duration::new(2, 700_000_000);
|
||||
/// assert_eq!(dur.as_secs_f32(), 2.7);
|
||||
/// ```
|
||||
#[unstable(feature = "duration_float", issue = "54361")]
|
||||
#[inline]
|
||||
pub const fn as_secs_f32(&self) -> f32 {
|
||||
(self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32)
|
||||
}
|
||||
|
||||
/// Creates a new `Duration` from the specified number of seconds represented
|
||||
/// as `f64`.
|
||||
///
|
||||
/// # Panics
|
||||
/// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
|
||||
|
@ -528,12 +546,14 @@ impl Duration {
|
|||
/// #![feature(duration_float)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let dur = Duration::from_float_secs(2.7);
|
||||
/// let dur = Duration::from_secs_f64(2.7);
|
||||
/// assert_eq!(dur, Duration::new(2, 700_000_000));
|
||||
/// ```
|
||||
#[unstable(feature = "duration_float", issue = "54361")]
|
||||
#[inline]
|
||||
pub fn from_float_secs(secs: f64) -> Duration {
|
||||
pub fn from_secs_f64(secs: f64) -> Duration {
|
||||
const MAX_NANOS_F64: f64 =
|
||||
((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64;
|
||||
let nanos = secs * (NANOS_PER_SEC as f64);
|
||||
if !nanos.is_finite() {
|
||||
panic!("got non-finite value when converting float to duration");
|
||||
|
@ -551,6 +571,42 @@ impl Duration {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new `Duration` from the specified number of seconds represented
|
||||
/// as `f32`.
|
||||
///
|
||||
/// # Panics
|
||||
/// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// #![feature(duration_float)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let dur = Duration::from_secs_f32(2.7);
|
||||
/// assert_eq!(dur, Duration::new(2, 700_000_000));
|
||||
/// ```
|
||||
#[unstable(feature = "duration_float", issue = "54361")]
|
||||
#[inline]
|
||||
pub fn from_secs_f32(secs: f32) -> Duration {
|
||||
const MAX_NANOS_F32: f32 =
|
||||
((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f32;
|
||||
let nanos = secs * (NANOS_PER_SEC as f32);
|
||||
if !nanos.is_finite() {
|
||||
panic!("got non-finite value when converting float to duration");
|
||||
}
|
||||
if nanos >= MAX_NANOS_F32 {
|
||||
panic!("overflow when converting float to duration");
|
||||
}
|
||||
if nanos < 0.0 {
|
||||
panic!("underflow when converting float to duration");
|
||||
}
|
||||
let nanos = nanos as u128;
|
||||
Duration {
|
||||
secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
|
||||
nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
|
||||
}
|
||||
}
|
||||
|
||||
/// Multiplies `Duration` by `f64`.
|
||||
///
|
||||
/// # Panics
|
||||
|
@ -568,7 +624,29 @@ impl Duration {
|
|||
#[unstable(feature = "duration_float", issue = "54361")]
|
||||
#[inline]
|
||||
pub fn mul_f64(self, rhs: f64) -> Duration {
|
||||
Duration::from_float_secs(rhs * self.as_float_secs())
|
||||
Duration::from_secs_f64(rhs * self.as_secs_f64())
|
||||
}
|
||||
|
||||
/// Multiplies `Duration` by `f32`.
|
||||
///
|
||||
/// # Panics
|
||||
/// This method will panic if result is not finite, negative or overflows `Duration`.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// #![feature(duration_float)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let dur = Duration::new(2, 700_000_000);
|
||||
/// // note that due to rounding errors result is slightly different
|
||||
/// // from 8.478 and 847800.0
|
||||
/// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640));
|
||||
/// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256));
|
||||
/// ```
|
||||
#[unstable(feature = "duration_float", issue = "54361")]
|
||||
#[inline]
|
||||
pub fn mul_f32(self, rhs: f32) -> Duration {
|
||||
Duration::from_secs_f32(rhs * self.as_secs_f32())
|
||||
}
|
||||
|
||||
/// Divide `Duration` by `f64`.
|
||||
|
@ -589,7 +667,30 @@ impl Duration {
|
|||
#[unstable(feature = "duration_float", issue = "54361")]
|
||||
#[inline]
|
||||
pub fn div_f64(self, rhs: f64) -> Duration {
|
||||
Duration::from_float_secs(self.as_float_secs() / rhs)
|
||||
Duration::from_secs_f64(self.as_secs_f64() / rhs)
|
||||
}
|
||||
|
||||
/// Divide `Duration` by `f32`.
|
||||
///
|
||||
/// # Panics
|
||||
/// This method will panic if result is not finite, negative or overflows `Duration`.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// #![feature(duration_float)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let dur = Duration::new(2, 700_000_000);
|
||||
/// // note that due to rounding errors result is slightly
|
||||
/// // different from 0.859_872_611
|
||||
/// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_576));
|
||||
/// // note that truncation is used, not rounding
|
||||
/// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598));
|
||||
/// ```
|
||||
#[unstable(feature = "duration_float", issue = "54361")]
|
||||
#[inline]
|
||||
pub fn div_f32(self, rhs: f32) -> Duration {
|
||||
Duration::from_secs_f32(self.as_secs_f32() / rhs)
|
||||
}
|
||||
|
||||
/// Divide `Duration` by `Duration` and return `f64`.
|
||||
|
@ -601,12 +702,29 @@ impl Duration {
|
|||
///
|
||||
/// let dur1 = Duration::new(2, 700_000_000);
|
||||
/// let dur2 = Duration::new(5, 400_000_000);
|
||||
/// assert_eq!(dur1.div_duration(dur2), 0.5);
|
||||
/// assert_eq!(dur1.div_duration_f64(dur2), 0.5);
|
||||
/// ```
|
||||
#[unstable(feature = "duration_float", issue = "54361")]
|
||||
#[inline]
|
||||
pub fn div_duration(self, rhs: Duration) -> f64 {
|
||||
self.as_float_secs() / rhs.as_float_secs()
|
||||
pub fn div_duration_f64(self, rhs: Duration) -> f64 {
|
||||
self.as_secs_f64() / rhs.as_secs_f64()
|
||||
}
|
||||
|
||||
/// Divide `Duration` by `Duration` and return `f32`.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// #![feature(duration_float)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let dur1 = Duration::new(2, 700_000_000);
|
||||
/// let dur2 = Duration::new(5, 400_000_000);
|
||||
/// assert_eq!(dur1.div_duration_f32(dur2), 0.5);
|
||||
/// ```
|
||||
#[unstable(feature = "duration_float", issue = "54361")]
|
||||
#[inline]
|
||||
pub fn div_duration_f32(self, rhs: Duration) -> f32 {
|
||||
self.as_secs_f32() / rhs.as_secs_f32()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -724,7 +724,7 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for DefId {
|
|||
}
|
||||
|
||||
fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String {
|
||||
tcx.item_path_str(*self)
|
||||
tcx.def_path_str(*self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -736,7 +736,7 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for DefIndex {
|
|||
}
|
||||
|
||||
fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String {
|
||||
tcx.item_path_str(DefId::local(*self))
|
||||
tcx.def_path_str(DefId::local(*self))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -249,7 +249,7 @@ impl DefId {
|
|||
if self.is_local() && self.index == CRATE_DEF_INDEX {
|
||||
format!("top-level module")
|
||||
} else {
|
||||
format!("module `{}`", tcx.item_path_str(*self))
|
||||
format!("module `{}`", tcx.def_path_str(*self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -679,13 +679,13 @@ impl DefPathData {
|
|||
return name
|
||||
}
|
||||
// note that this does not show up in user printouts
|
||||
CrateRoot => "{{root}}",
|
||||
CrateRoot => "{{crate}}",
|
||||
Impl => "{{impl}}",
|
||||
Misc => "{{?}}",
|
||||
Misc => "{{misc}}",
|
||||
ClosureExpr => "{{closure}}",
|
||||
StructCtor => "{{constructor}}",
|
||||
AnonConst => "{{constant}}",
|
||||
ImplTrait => "{{impl-Trait}}",
|
||||
ImplTrait => "{{opaque}}",
|
||||
};
|
||||
|
||||
Symbol::intern(s).as_interned_str()
|
||||
|
|
|
@ -541,7 +541,8 @@ impl<'hir> Map<'hir> {
|
|||
|
||||
pub fn ty_param_owner(&self, id: HirId) -> HirId {
|
||||
match self.get_by_hir_id(id) {
|
||||
Node::Item(&Item { node: ItemKind::Trait(..), .. }) => id,
|
||||
Node::Item(&Item { node: ItemKind::Trait(..), .. }) |
|
||||
Node::Item(&Item { node: ItemKind::TraitAlias(..), .. }) => id,
|
||||
Node::GenericParam(_) => self.get_parent_node_by_hir_id(id),
|
||||
_ => bug!("ty_param_owner: {} not a type parameter", self.hir_to_string(id))
|
||||
}
|
||||
|
@ -549,7 +550,8 @@ impl<'hir> Map<'hir> {
|
|||
|
||||
pub fn ty_param_name(&self, id: HirId) -> Name {
|
||||
match self.get_by_hir_id(id) {
|
||||
Node::Item(&Item { node: ItemKind::Trait(..), .. }) => keywords::SelfUpper.name(),
|
||||
Node::Item(&Item { node: ItemKind::Trait(..), .. }) |
|
||||
Node::Item(&Item { node: ItemKind::TraitAlias(..), .. }) => keywords::SelfUpper.name(),
|
||||
Node::GenericParam(param) => param.name.ident().name,
|
||||
_ => bug!("ty_param_name: {} not a type parameter", self.hir_to_string(id)),
|
||||
}
|
||||
|
@ -1019,6 +1021,7 @@ impl<'hir> Map<'hir> {
|
|||
pub fn attrs(&self, id: NodeId) -> &'hir [ast::Attribute] {
|
||||
self.read(id); // reveals attributes on the node
|
||||
let attrs = match self.find(id) {
|
||||
Some(Node::Local(l)) => Some(&l.attrs[..]),
|
||||
Some(Node::Item(i)) => Some(&i.attrs[..]),
|
||||
Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]),
|
||||
Some(Node::TraitItem(ref ti)) => Some(&ti.attrs[..]),
|
||||
|
@ -1350,7 +1353,8 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String {
|
|||
// the user-friendly path, otherwise fall back to stringifying DefPath.
|
||||
crate::ty::tls::with_opt(|tcx| {
|
||||
if let Some(tcx) = tcx {
|
||||
tcx.node_path_str(id)
|
||||
let def_id = map.local_def_id(id);
|
||||
tcx.def_path_str(def_id)
|
||||
} else if let Some(path) = map.def_path_from_id(id) {
|
||||
path.data.into_iter().map(|elem| {
|
||||
elem.data.to_string()
|
||||
|
|
|
@ -223,7 +223,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
self.hir().span_by_hir_id(node),
|
||||
),
|
||||
_ => (
|
||||
format!("the lifetime {} as defined on", fr.bound_region),
|
||||
format!("the lifetime {} as defined on", region),
|
||||
cm.def_span(self.hir().span_by_hir_id(node)),
|
||||
),
|
||||
},
|
||||
|
@ -444,17 +444,109 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
terr: &TypeError<'tcx>,
|
||||
sp: Span,
|
||||
) {
|
||||
use hir::def_id::CrateNum;
|
||||
use hir::map::DisambiguatedDefPathData;
|
||||
use ty::print::Printer;
|
||||
use ty::subst::Kind;
|
||||
|
||||
struct AbsolutePathPrinter<'a, 'gcx, 'tcx> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
struct NonTrivialPath;
|
||||
|
||||
impl<'gcx, 'tcx> Printer<'gcx, 'tcx> for AbsolutePathPrinter<'_, 'gcx, 'tcx> {
|
||||
type Error = NonTrivialPath;
|
||||
|
||||
type Path = Vec<String>;
|
||||
type Region = !;
|
||||
type Type = !;
|
||||
type DynExistential = !;
|
||||
|
||||
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn print_region(
|
||||
self,
|
||||
_region: ty::Region<'_>,
|
||||
) -> Result<Self::Region, Self::Error> {
|
||||
Err(NonTrivialPath)
|
||||
}
|
||||
|
||||
fn print_type(
|
||||
self,
|
||||
_ty: Ty<'tcx>,
|
||||
) -> Result<Self::Type, Self::Error> {
|
||||
Err(NonTrivialPath)
|
||||
}
|
||||
|
||||
fn print_dyn_existential(
|
||||
self,
|
||||
_predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
|
||||
) -> Result<Self::DynExistential, Self::Error> {
|
||||
Err(NonTrivialPath)
|
||||
}
|
||||
|
||||
fn path_crate(
|
||||
self,
|
||||
cnum: CrateNum,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
Ok(vec![self.tcx.original_crate_name(cnum).to_string()])
|
||||
}
|
||||
fn path_qualified(
|
||||
self,
|
||||
_self_ty: Ty<'tcx>,
|
||||
_trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
Err(NonTrivialPath)
|
||||
}
|
||||
|
||||
fn path_append_impl(
|
||||
self,
|
||||
_print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
_disambiguated_data: &DisambiguatedDefPathData,
|
||||
_self_ty: Ty<'tcx>,
|
||||
_trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
Err(NonTrivialPath)
|
||||
}
|
||||
fn path_append(
|
||||
self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
disambiguated_data: &DisambiguatedDefPathData,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
let mut path = print_prefix(self)?;
|
||||
path.push(disambiguated_data.data.as_interned_str().to_string());
|
||||
Ok(path)
|
||||
}
|
||||
fn path_generic_args(
|
||||
self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
_args: &[Kind<'tcx>],
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
print_prefix(self)
|
||||
}
|
||||
}
|
||||
|
||||
let report_path_match = |err: &mut DiagnosticBuilder<'_>, did1: DefId, did2: DefId| {
|
||||
// Only external crates, if either is from a local
|
||||
// module we could have false positives
|
||||
if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
|
||||
let exp_path = self.tcx.item_path_str(did1);
|
||||
let found_path = self.tcx.item_path_str(did2);
|
||||
let exp_abs_path = self.tcx.absolute_item_path_str(did1);
|
||||
let found_abs_path = self.tcx.absolute_item_path_str(did2);
|
||||
let abs_path = |def_id| {
|
||||
AbsolutePathPrinter { tcx: self.tcx }
|
||||
.print_def_path(def_id, &[])
|
||||
};
|
||||
|
||||
// We compare strings because DefPath can be different
|
||||
// for imported and non-imported crates
|
||||
if exp_path == found_path || exp_abs_path == found_abs_path {
|
||||
let same_path = || -> Result<_, NonTrivialPath> {
|
||||
Ok(
|
||||
self.tcx.def_path_str(did1) == self.tcx.def_path_str(did2) ||
|
||||
abs_path(did1)? == abs_path(did2)?
|
||||
)
|
||||
};
|
||||
if same_path().unwrap_or(false) {
|
||||
let crate_name = self.tcx.crate_name(did1.krate);
|
||||
err.span_note(
|
||||
sp,
|
||||
|
@ -658,7 +750,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
return Some(());
|
||||
}
|
||||
if let &ty::Adt(def, _) = &ta.sty {
|
||||
let path_ = self.tcx.item_path_str(def.did.clone());
|
||||
let path_ = self.tcx.def_path_str(def.did.clone());
|
||||
if path_ == other_path {
|
||||
self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
|
||||
return Some(());
|
||||
|
@ -683,7 +775,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
/// For generic types with parameters with defaults, remove the parameters corresponding to
|
||||
/// the defaults. This repeats a lot of the logic found in `PrintContext::parameterized`.
|
||||
/// the defaults. This repeats a lot of the logic found in `ty::print::pretty`.
|
||||
fn strip_generic_default_params(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
|
@ -742,11 +834,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
mutbl: hir::Mutability,
|
||||
s: &mut DiagnosticStyledString,
|
||||
) {
|
||||
let r = &r.to_string();
|
||||
let mut r = r.to_string();
|
||||
if r == "'_" {
|
||||
r.clear();
|
||||
} else {
|
||||
r.push(' ');
|
||||
}
|
||||
s.push_highlighted(format!(
|
||||
"&{}{}{}",
|
||||
"&{}{}",
|
||||
r,
|
||||
if r == "" { "" } else { " " },
|
||||
if mutbl == hir::MutMutable { "mut " } else { "" }
|
||||
));
|
||||
s.push_normal(ty.to_string());
|
||||
|
@ -757,8 +853,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1);
|
||||
let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2);
|
||||
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
|
||||
let path1 = self.tcx.item_path_str(def1.did.clone());
|
||||
let path2 = self.tcx.item_path_str(def2.did.clone());
|
||||
let path1 = self.tcx.def_path_str(def1.did.clone());
|
||||
let path2 = self.tcx.def_path_str(def2.did.clone());
|
||||
if def1.did == def2.did {
|
||||
// Easy case. Replace same types with `_` to shorten the output and highlight
|
||||
// the differing ones.
|
||||
|
@ -1013,7 +1109,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
if exp_is_struct && &exp_found.expected == ret_ty.skip_binder() {
|
||||
let message = format!(
|
||||
"did you mean `{}(/* fields */)`?",
|
||||
self.tcx.item_path_str(def_id)
|
||||
self.tcx.def_path_str(def_id)
|
||||
);
|
||||
diag.span_label(span, message);
|
||||
}
|
||||
|
@ -1425,7 +1521,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
var_origin: RegionVariableOrigin,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let br_string = |br: ty::BoundRegion| {
|
||||
let mut s = br.to_string();
|
||||
let mut s = match br {
|
||||
ty::BrNamed(_, name) => name.to_string(),
|
||||
_ => String::new(),
|
||||
};
|
||||
if !s.is_empty() {
|
||||
s.push_str(" ");
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use crate::hir::def::Namespace;
|
||||
use crate::hir::{self, Local, Pat, Body, HirId};
|
||||
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::type_variable::TypeVariableOrigin;
|
||||
use crate::ty::{self, Ty, Infer, TyVar};
|
||||
use crate::ty::print::Print;
|
||||
use syntax::source_map::CompilerDesugaringKind;
|
||||
use syntax_pos::Span;
|
||||
use errors::DiagnosticBuilder;
|
||||
|
@ -64,18 +66,26 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
|
|||
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
|
||||
pub fn extract_type_name(
|
||||
&self,
|
||||
ty: &'a Ty<'tcx>,
|
||||
highlight: Option<ty::print::RegionHighlightMode>,
|
||||
) -> String {
|
||||
if let ty::Infer(ty::TyVar(ty_vid)) = (*ty).sty {
|
||||
let ty_vars = self.type_variables.borrow();
|
||||
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
|
||||
*ty_vars.var_origin(ty_vid) {
|
||||
name.to_string()
|
||||
} else {
|
||||
ty.to_string()
|
||||
return name.to_string();
|
||||
}
|
||||
} else {
|
||||
ty.to_string()
|
||||
}
|
||||
|
||||
let mut s = String::new();
|
||||
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
||||
if let Some(highlight) = highlight {
|
||||
printer.region_highlight_mode = highlight;
|
||||
}
|
||||
let _ = ty.print(printer);
|
||||
s
|
||||
}
|
||||
|
||||
pub fn need_type_info_err(&self,
|
||||
|
@ -84,7 +94,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
ty: Ty<'tcx>)
|
||||
-> DiagnosticBuilder<'gcx> {
|
||||
let ty = self.resolve_type_vars_if_possible(&ty);
|
||||
let name = self.extract_type_name(&ty);
|
||||
let name = self.extract_type_name(&ty, None);
|
||||
|
||||
let mut err_span = span;
|
||||
let mut labels = vec![(
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
use errors::DiagnosticBuilder;
|
||||
use crate::hir::def::Namespace;
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
||||
use crate::infer::ValuePairs;
|
||||
use crate::infer::{SubregionOrigin, TypeTrace};
|
||||
use crate::traits::{ObligationCause, ObligationCauseCode};
|
||||
use crate::ty;
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use crate::ty::error::ExpectedFound;
|
||||
use crate::ty::subst::SubstsRef;
|
||||
use crate::util::ppaux::RegionHighlightMode;
|
||||
use crate::ty::print::{Print, RegionHighlightMode, FmtPrinter};
|
||||
|
||||
use std::fmt::{self, Write};
|
||||
|
||||
impl NiceRegionError<'me, 'gcx, 'tcx> {
|
||||
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
|
||||
|
@ -193,7 +196,7 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
|
|||
cause.span(&self.tcx()),
|
||||
&format!(
|
||||
"implementation of `{}` is not general enough",
|
||||
self.tcx().item_path_str(trait_def_id),
|
||||
self.tcx().def_path_str(trait_def_id),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -201,7 +204,7 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
|
|||
ObligationCauseCode::ItemObligation(def_id) => {
|
||||
err.note(&format!(
|
||||
"Due to a where-clause on `{}`,",
|
||||
self.tcx().item_path_str(def_id),
|
||||
self.tcx().def_path_str(def_id),
|
||||
));
|
||||
}
|
||||
_ => (),
|
||||
|
@ -309,13 +312,46 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
|
|||
sup_placeholder: Option<ty::Region<'tcx>>,
|
||||
has_sub: Option<usize>,
|
||||
has_sup: Option<usize>,
|
||||
expected_trait_ref: ty::TraitRef<'_>,
|
||||
actual_trait_ref: ty::TraitRef<'_>,
|
||||
expected_trait_ref: ty::TraitRef<'tcx>,
|
||||
actual_trait_ref: ty::TraitRef<'tcx>,
|
||||
vid: Option<ty::Region<'tcx>>,
|
||||
expected_has_vid: Option<usize>,
|
||||
actual_has_vid: Option<usize>,
|
||||
any_self_ty_has_vid: bool,
|
||||
) {
|
||||
// HACK(eddyb) maybe move this in a more central location.
|
||||
#[derive(Copy, Clone)]
|
||||
struct Highlighted<'a, 'gcx, 'tcx, T> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
highlight: RegionHighlightMode,
|
||||
value: T,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx, T> Highlighted<'a, 'gcx, 'tcx, T> {
|
||||
fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'a, 'gcx, 'tcx, U> {
|
||||
Highlighted {
|
||||
tcx: self.tcx,
|
||||
highlight: self.highlight,
|
||||
value: f(self.value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx, T> fmt::Display for Highlighted<'a, 'gcx, 'tcx, T>
|
||||
where T: for<'b, 'c> Print<'gcx, 'tcx,
|
||||
FmtPrinter<'a, 'gcx, 'tcx, &'b mut fmt::Formatter<'c>>,
|
||||
Error = fmt::Error,
|
||||
>,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut printer = ty::print::FmtPrinter::new(self.tcx, f, Namespace::TypeNS);
|
||||
printer.region_highlight_mode = self.highlight;
|
||||
|
||||
self.value.print(printer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// The weird thing here with the `maybe_highlighting_region` calls and the
|
||||
// the match inside is meant to be like this:
|
||||
//
|
||||
|
@ -331,112 +367,93 @@ impl NiceRegionError<'me, 'gcx, 'tcx> {
|
|||
// None, an then we check again inside the closure, but this
|
||||
// setup sort of minimized the number of calls and so form.
|
||||
|
||||
RegionHighlightMode::maybe_highlighting_region(sub_placeholder, has_sub, || {
|
||||
RegionHighlightMode::maybe_highlighting_region(sup_placeholder, has_sup, || {
|
||||
match (has_sub, has_sup) {
|
||||
(Some(n1), Some(n2)) => {
|
||||
if any_self_ty_has_vid {
|
||||
err.note(&format!(
|
||||
"`{}` would have to be implemented for the type `{}`, \
|
||||
for any two lifetimes `'{}` and `'{}`",
|
||||
expected_trait_ref,
|
||||
expected_trait_ref.self_ty(),
|
||||
std::cmp::min(n1, n2),
|
||||
std::cmp::max(n1, n2),
|
||||
));
|
||||
} else {
|
||||
err.note(&format!(
|
||||
"`{}` must implement `{}`, \
|
||||
for any two lifetimes `'{}` and `'{}`",
|
||||
expected_trait_ref.self_ty(),
|
||||
expected_trait_ref,
|
||||
std::cmp::min(n1, n2),
|
||||
std::cmp::max(n1, n2),
|
||||
));
|
||||
}
|
||||
let highlight_trait_ref = |trait_ref| Highlighted {
|
||||
tcx: self.tcx(),
|
||||
highlight: RegionHighlightMode::default(),
|
||||
value: trait_ref,
|
||||
};
|
||||
|
||||
let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
|
||||
expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
|
||||
expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
|
||||
err.note(&{
|
||||
let passive_voice = match (has_sub, has_sup) {
|
||||
(Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
|
||||
(None, None) => {
|
||||
expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
|
||||
match expected_has_vid {
|
||||
Some(_) => true,
|
||||
None => any_self_ty_has_vid,
|
||||
}
|
||||
(Some(n), _) | (_, Some(n)) => {
|
||||
if any_self_ty_has_vid {
|
||||
err.note(&format!(
|
||||
"`{}` would have to be implemented for the type `{}`, \
|
||||
for any lifetime `'{}`",
|
||||
expected_trait_ref,
|
||||
expected_trait_ref.self_ty(),
|
||||
n,
|
||||
));
|
||||
} else {
|
||||
err.note(&format!(
|
||||
"`{}` must implement `{}`, for any lifetime `'{}`",
|
||||
expected_trait_ref.self_ty(),
|
||||
expected_trait_ref,
|
||||
n,
|
||||
));
|
||||
}
|
||||
}
|
||||
(None, None) => RegionHighlightMode::maybe_highlighting_region(
|
||||
vid,
|
||||
expected_has_vid,
|
||||
|| {
|
||||
if let Some(n) = expected_has_vid {
|
||||
err.note(&format!(
|
||||
"`{}` would have to be implemented for the type `{}`, \
|
||||
for some specific lifetime `'{}`",
|
||||
expected_trait_ref,
|
||||
expected_trait_ref.self_ty(),
|
||||
n,
|
||||
));
|
||||
} else {
|
||||
if any_self_ty_has_vid {
|
||||
err.note(&format!(
|
||||
"`{}` would have to be implemented for the type `{}`",
|
||||
expected_trait_ref,
|
||||
expected_trait_ref.self_ty(),
|
||||
));
|
||||
} else {
|
||||
err.note(&format!(
|
||||
"`{}` must implement `{}`",
|
||||
expected_trait_ref.self_ty(),
|
||||
expected_trait_ref,
|
||||
));
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let mut note = if passive_voice {
|
||||
format!(
|
||||
"`{}` would have to be implemented for the type `{}`",
|
||||
expected_trait_ref,
|
||||
expected_trait_ref.map(|tr| tr.self_ty()),
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"`{}` must implement `{}`",
|
||||
expected_trait_ref.map(|tr| tr.self_ty()),
|
||||
expected_trait_ref,
|
||||
)
|
||||
};
|
||||
|
||||
match (has_sub, has_sup) {
|
||||
(Some(n1), Some(n2)) => {
|
||||
let _ = write!(note,
|
||||
", for any two lifetimes `'{}` and `'{}`",
|
||||
std::cmp::min(n1, n2),
|
||||
std::cmp::max(n1, n2),
|
||||
);
|
||||
}
|
||||
(Some(n), _) | (_, Some(n)) => {
|
||||
let _ = write!(note,
|
||||
", for any lifetime `'{}`",
|
||||
n,
|
||||
);
|
||||
}
|
||||
(None, None) => if let Some(n) = expected_has_vid {
|
||||
let _ = write!(note,
|
||||
", for some specific lifetime `'{}`",
|
||||
n,
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
note
|
||||
});
|
||||
|
||||
RegionHighlightMode::maybe_highlighting_region(
|
||||
vid,
|
||||
actual_has_vid,
|
||||
|| match actual_has_vid {
|
||||
Some(n) => {
|
||||
if any_self_ty_has_vid {
|
||||
err.note(&format!(
|
||||
"but `{}` is actually implemented for the type `{}`, \
|
||||
for some specific lifetime `'{}`",
|
||||
actual_trait_ref,
|
||||
actual_trait_ref.self_ty(),
|
||||
n
|
||||
));
|
||||
} else {
|
||||
err.note(&format!(
|
||||
"but `{}` actually implements `{}`, for some specific lifetime `'{}`",
|
||||
actual_trait_ref.self_ty(),
|
||||
actual_trait_ref,
|
||||
n
|
||||
));
|
||||
}
|
||||
}
|
||||
let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
|
||||
actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
|
||||
err.note(&{
|
||||
let passive_voice = match actual_has_vid {
|
||||
Some(_) => any_self_ty_has_vid,
|
||||
None => true,
|
||||
};
|
||||
|
||||
_ => {
|
||||
err.note(&format!(
|
||||
"but `{}` is actually implemented for the type `{}`",
|
||||
actual_trait_ref,
|
||||
actual_trait_ref.self_ty(),
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
let mut note = if passive_voice {
|
||||
format!(
|
||||
"but `{}` is actually implemented for the type `{}`",
|
||||
actual_trait_ref,
|
||||
actual_trait_ref.map(|tr| tr.self_ty()),
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"but `{}` actually implements `{}`",
|
||||
actual_trait_ref.map(|tr| tr.self_ty()),
|
||||
actual_trait_ref,
|
||||
)
|
||||
};
|
||||
|
||||
if let Some(n) = actual_has_vid {
|
||||
let _ = write!(note, ", for some specific lifetime `'{}`", n);
|
||||
}
|
||||
|
||||
note
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use crate::hir;
|
||||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use crate::ty::{self, Region, Ty};
|
||||
use crate::ty::{self, DefIdTree, Region, Ty};
|
||||
use crate::hir::def_id::DefId;
|
||||
use syntax_pos::Span;
|
||||
|
||||
|
@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
|
|||
let (id, bound_region) = match *anon_region {
|
||||
ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
|
||||
ty::ReEarlyBound(ref ebr) => (
|
||||
self.tcx().parent_def_id(ebr.def_id).unwrap(),
|
||||
self.tcx().parent(ebr.def_id).unwrap(),
|
||||
ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
|
||||
),
|
||||
_ => return None, // not a free region
|
||||
|
|
|
@ -91,7 +91,7 @@ impl_stable_hash_for!(struct FreeRegionMap<'tcx> {
|
|||
impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
|
||||
type Lifted = FreeRegionMap<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<FreeRegionMap<'tcx>> {
|
||||
self.relation.maybe_map(|&fr| fr.lift_to_tcx(tcx))
|
||||
self.relation.maybe_map(|&fr| tcx.lift(&fr))
|
||||
.map(|relation| FreeRegionMap { relation })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#![deny(rust_2018_idioms)]
|
||||
#![allow(explicit_outlives_requirements)]
|
||||
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(core_intrinsics)]
|
||||
|
@ -134,9 +135,7 @@ pub mod ty;
|
|||
pub mod util {
|
||||
pub mod captures;
|
||||
pub mod common;
|
||||
pub mod ppaux;
|
||||
pub mod nodemap;
|
||||
pub mod time_graph;
|
||||
pub mod profiling;
|
||||
pub mod bug;
|
||||
}
|
||||
|
|
|
@ -157,6 +157,7 @@ pub struct LintLevelsBuilder<'a> {
|
|||
|
||||
pub struct BuilderPush {
|
||||
prev: u32,
|
||||
pub(super) changed: bool,
|
||||
}
|
||||
|
||||
impl<'a> LintLevelsBuilder<'a> {
|
||||
|
@ -454,6 +455,7 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
|
||||
BuilderPush {
|
||||
prev: prev,
|
||||
changed: prev != self.cur,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -512,11 +514,6 @@ impl LintLevelMap {
|
|||
self.sets.get_lint_level(lint, *idx, None, session)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns if this `id` has lint level information.
|
||||
pub fn lint_level_set(&self, id: HirId) -> Option<u32> {
|
||||
self.id_to_set.get(&id).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
|
||||
|
|
|
@ -721,6 +721,16 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
|
|||
return err
|
||||
}
|
||||
|
||||
pub fn maybe_lint_level_root(tcx: TyCtxt<'_, '_, '_>, id: hir::HirId) -> bool {
|
||||
let attrs = tcx.hir().attrs_by_hir_id(id);
|
||||
for attr in attrs {
|
||||
if Level::from_str(&attr.name().as_str()).is_some() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum)
|
||||
-> Lrc<LintLevelMap>
|
||||
{
|
||||
|
@ -731,9 +741,10 @@ fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum)
|
|||
};
|
||||
let krate = tcx.hir().krate();
|
||||
|
||||
builder.with_lint_attrs(hir::CRATE_HIR_ID, &krate.attrs, |builder| {
|
||||
intravisit::walk_crate(builder, krate);
|
||||
});
|
||||
let push = builder.levels.push(&krate.attrs);
|
||||
builder.levels.register_id(hir::CRATE_HIR_ID);
|
||||
intravisit::walk_crate(&mut builder, krate);
|
||||
builder.levels.pop(push);
|
||||
|
||||
Lrc::new(builder.levels.build_map())
|
||||
}
|
||||
|
@ -751,7 +762,9 @@ impl<'a, 'tcx> LintLevelMapBuilder<'a, 'tcx> {
|
|||
where F: FnOnce(&mut Self)
|
||||
{
|
||||
let push = self.levels.push(attrs);
|
||||
self.levels.register_id(id);
|
||||
if push.changed {
|
||||
self.levels.register_id(id);
|
||||
}
|
||||
f(self);
|
||||
self.levels.pop(push);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::hir::CodegenFnAttrFlags;
|
|||
use crate::hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use crate::lint;
|
||||
use crate::middle::privacy;
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use crate::ty::{self, DefIdTree, TyCtxt};
|
||||
use crate::util::nodemap::FxHashSet;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
@ -78,7 +78,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
|||
Def::PrimTy(..) | Def::SelfTy(..) | Def::SelfCtor(..) |
|
||||
Def::Local(..) | Def::Upvar(..) => {}
|
||||
Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
|
||||
if let Some(enum_id) = self.tcx.parent_def_id(variant_id) {
|
||||
if let Some(enum_id) = self.tcx.parent(variant_id) {
|
||||
self.check_def_id(enum_id);
|
||||
}
|
||||
if !self.ignore_variant_stack.contains(&variant_id) {
|
||||
|
|
|
@ -64,7 +64,7 @@ use crate::hir::Node;
|
|||
use crate::infer::InferCtxt;
|
||||
use crate::hir::def::{Def, CtorKind};
|
||||
use crate::ty::adjustment;
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::ty::{self, DefIdTree, Ty, TyCtxt};
|
||||
use crate::ty::fold::TypeFoldable;
|
||||
use crate::ty::layout::VariantIdx;
|
||||
|
||||
|
@ -786,7 +786,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
// FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
|
||||
// FnOnce | copied | upvar -> &'up bk
|
||||
|
||||
let kind = match self.node_ty(fn_hir_id)?.sty {
|
||||
let ty = self.node_ty(fn_hir_id)?;
|
||||
let kind = match ty.sty {
|
||||
ty::Generator(..) => ty::ClosureKind::FnOnce,
|
||||
ty::Closure(closure_def_id, closure_substs) => {
|
||||
match self.infcx {
|
||||
|
@ -803,7 +804,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
.closure_kind(closure_def_id, self.tcx.global_tcx()),
|
||||
}
|
||||
}
|
||||
ref t => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", t),
|
||||
_ => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", ty),
|
||||
};
|
||||
|
||||
let closure_expr_def_id = self.tcx.hir().local_def_id(fn_node_id);
|
||||
|
@ -1064,7 +1065,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
let bk = ty::BorrowKind::from_mutbl(mutbl);
|
||||
BorrowedPtr(bk, r)
|
||||
}
|
||||
ref ty => bug!("unexpected type in cat_deref: {:?}", ty)
|
||||
_ => bug!("unexpected type in cat_deref: {:?}", base_cmt.ty)
|
||||
};
|
||||
let ret = cmt_ {
|
||||
hir_id: node.hir_id(),
|
||||
|
@ -1132,7 +1133,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
variant_did: DefId)
|
||||
-> cmt<'tcx> {
|
||||
// univariant enums do not need downcasts
|
||||
let base_did = self.tcx.parent_def_id(variant_did).unwrap();
|
||||
let base_did = self.tcx.parent(variant_did).unwrap();
|
||||
if self.tcx.adt_def(base_did).variants.len() != 1 {
|
||||
let base_ty = base_cmt.ty;
|
||||
let ret = Rc::new(cmt_ {
|
||||
|
@ -1274,16 +1275,17 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
return Err(())
|
||||
}
|
||||
Def::VariantCtor(def_id, CtorKind::Fn) => {
|
||||
let enum_def = self.tcx.parent_def_id(def_id).unwrap();
|
||||
let enum_def = self.tcx.parent(def_id).unwrap();
|
||||
(self.cat_downcast_if_needed(pat, cmt, def_id),
|
||||
self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len())
|
||||
}
|
||||
Def::StructCtor(_, CtorKind::Fn) | Def::SelfCtor(..) => {
|
||||
match self.pat_ty_unadjusted(&pat)?.sty {
|
||||
let ty = self.pat_ty_unadjusted(&pat)?;
|
||||
match ty.sty {
|
||||
ty::Adt(adt_def, _) => {
|
||||
(cmt, adt_def.non_enum_variant().fields.len())
|
||||
}
|
||||
ref ty => {
|
||||
_ => {
|
||||
span_bug!(pat.span,
|
||||
"tuple struct pattern unexpected type {:?}", ty);
|
||||
}
|
||||
|
@ -1334,9 +1336,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
|||
|
||||
PatKind::Tuple(ref subpats, ddpos) => {
|
||||
// (p1, ..., pN)
|
||||
let expected_len = match self.pat_ty_unadjusted(&pat)?.sty {
|
||||
let ty = self.pat_ty_unadjusted(&pat)?;
|
||||
let expected_len = match ty.sty {
|
||||
ty::Tuple(ref tys) => tys.len(),
|
||||
ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
|
||||
_ => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
|
||||
};
|
||||
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
|
||||
let subpat_ty = self.pat_ty_adjusted(&subpat)?; // see (*2)
|
||||
|
|
|
@ -17,7 +17,7 @@ use rustc_macros::HashStable;
|
|||
use syntax::source_map;
|
||||
use syntax::ast;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use crate::ty::TyCtxt;
|
||||
use crate::ty::{DefIdTree, TyCtxt};
|
||||
use crate::ty::query::Providers;
|
||||
|
||||
use crate::hir;
|
||||
|
@ -650,7 +650,7 @@ impl<'tcx> ScopeTree {
|
|||
pub fn early_free_scope<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
br: &ty::EarlyBoundRegion)
|
||||
-> Scope {
|
||||
let param_owner = tcx.parent_def_id(br.def_id).unwrap();
|
||||
let param_owner = tcx.parent(br.def_id).unwrap();
|
||||
|
||||
let param_owner_id = tcx.hir().as_local_hir_id(param_owner).unwrap();
|
||||
let scope = tcx.hir().maybe_body_owned_by_by_hir_id(param_owner_id).map(|body_id| {
|
||||
|
@ -679,7 +679,7 @@ impl<'tcx> ScopeTree {
|
|||
-> Scope {
|
||||
let param_owner = match fr.bound_region {
|
||||
ty::BoundRegion::BrNamed(def_id, _) => {
|
||||
tcx.parent_def_id(def_id).unwrap()
|
||||
tcx.parent(def_id).unwrap()
|
||||
}
|
||||
_ => fr.scope
|
||||
};
|
||||
|
|
|
@ -2299,6 +2299,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
let span = lifetime_refs[0].span;
|
||||
let mut late_depth = 0;
|
||||
let mut scope = self.scope;
|
||||
let mut lifetime_names = FxHashSet::default();
|
||||
let error = loop {
|
||||
match *scope {
|
||||
// Do not assign any resolution, it will be inferred.
|
||||
|
@ -2306,12 +2307,18 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
|
||||
Scope::Root => break None,
|
||||
|
||||
Scope::Binder { s, .. } => {
|
||||
Scope::Binder { s, ref lifetimes, .. } => {
|
||||
// collect named lifetimes for suggestions
|
||||
for name in lifetimes.keys() {
|
||||
if let hir::ParamName::Plain(name) = name {
|
||||
lifetime_names.insert(*name);
|
||||
}
|
||||
}
|
||||
late_depth += 1;
|
||||
scope = s;
|
||||
}
|
||||
|
||||
Scope::Elision { ref elide, .. } => {
|
||||
Scope::Elision { ref elide, ref s, .. } => {
|
||||
let lifetime = match *elide {
|
||||
Elide::FreshLateAnon(ref counter) => {
|
||||
for lifetime_ref in lifetime_refs {
|
||||
|
@ -2321,7 +2328,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
Elide::Exact(l) => l.shifted(late_depth),
|
||||
Elide::Error(ref e) => break Some(e),
|
||||
Elide::Error(ref e) => {
|
||||
if let Scope::Binder { ref lifetimes, .. } = s {
|
||||
// collect named lifetimes for suggestions
|
||||
for name in lifetimes.keys() {
|
||||
if let hir::ParamName::Plain(name) = name {
|
||||
lifetime_names.insert(*name);
|
||||
}
|
||||
}
|
||||
}
|
||||
break Some(e);
|
||||
}
|
||||
};
|
||||
for lifetime_ref in lifetime_refs {
|
||||
self.insert_lifetime(lifetime_ref, lifetime);
|
||||
|
@ -2344,7 +2361,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
if add_label {
|
||||
add_missing_lifetime_specifiers_label(&mut err, span, lifetime_refs.len());
|
||||
add_missing_lifetime_specifiers_label(
|
||||
&mut err,
|
||||
span,
|
||||
lifetime_refs.len(),
|
||||
&lifetime_names,
|
||||
self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()),
|
||||
);
|
||||
}
|
||||
|
||||
err.emit();
|
||||
|
@ -2885,10 +2908,23 @@ fn add_missing_lifetime_specifiers_label(
|
|||
err: &mut DiagnosticBuilder<'_>,
|
||||
span: Span,
|
||||
count: usize,
|
||||
lifetime_names: &FxHashSet<ast::Ident>,
|
||||
snippet: Option<&str>,
|
||||
) {
|
||||
if count > 1 {
|
||||
err.span_label(span, format!("expected {} lifetime parameters", count));
|
||||
} else if let (1, Some(name), Some("&")) = (
|
||||
lifetime_names.len(),
|
||||
lifetime_names.iter().next(),
|
||||
snippet,
|
||||
) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider using the named lifetime",
|
||||
format!("&{} ", name),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_label(span, "expected lifetime parameter");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -593,7 +593,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
.map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
|
||||
|
||||
if !skip {
|
||||
let path = self.item_path_str(def_id);
|
||||
let path = self.def_path_str(def_id);
|
||||
let message = format!("use of deprecated item '{}'", path);
|
||||
lint_deprecated(def_id,
|
||||
id,
|
||||
|
@ -620,7 +620,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
if let Some(id) = id {
|
||||
if let Some(stability) = stability {
|
||||
if let Some(depr) = &stability.rustc_depr {
|
||||
let path = self.item_path_str(def_id);
|
||||
let path = self.def_path_str(def_id);
|
||||
if deprecation_in_effect(&depr.since.as_str()) {
|
||||
let message = format!("use of deprecated item '{}'", path);
|
||||
lint_deprecated(def_id,
|
||||
|
|
|
@ -101,8 +101,7 @@ impl AllocationExtra<(), ()> for () {
|
|||
impl<Tag, Extra> Allocation<Tag, Extra> {
|
||||
/// Creates a read-only allocation initialized by the given bytes
|
||||
pub fn from_bytes(slice: &[u8], align: Align, extra: Extra) -> Self {
|
||||
let mut undef_mask = UndefMask::new(Size::ZERO);
|
||||
undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
|
||||
let undef_mask = UndefMask::new(Size::from_bytes(slice.len() as u64), true);
|
||||
Self {
|
||||
bytes: slice.to_owned(),
|
||||
relocations: Relocations::new(),
|
||||
|
@ -122,7 +121,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
|
|||
Allocation {
|
||||
bytes: vec![0; size.bytes() as usize],
|
||||
relocations: Relocations::new(),
|
||||
undef_mask: UndefMask::new(size),
|
||||
undef_mask: UndefMask::new(size, false),
|
||||
align,
|
||||
mutability: Mutability::Mutable,
|
||||
extra,
|
||||
|
@ -614,8 +613,9 @@ impl<Tag> DerefMut for Relocations<Tag> {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type Block = u64;
|
||||
const BLOCK_SIZE: u64 = 64;
|
||||
|
||||
/// A bitmask where each bit refers to the byte with the same index. If the bit is `true`, the byte
|
||||
/// is defined. If it is `false` the byte is undefined.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct UndefMask {
|
||||
blocks: Vec<Block>,
|
||||
|
@ -625,12 +625,14 @@ pub struct UndefMask {
|
|||
impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len});
|
||||
|
||||
impl UndefMask {
|
||||
pub fn new(size: Size) -> Self {
|
||||
pub const BLOCK_SIZE: u64 = 64;
|
||||
|
||||
pub fn new(size: Size, state: bool) -> Self {
|
||||
let mut m = UndefMask {
|
||||
blocks: vec![],
|
||||
len: Size::ZERO,
|
||||
};
|
||||
m.grow(size, false);
|
||||
m.grow(size, state);
|
||||
m
|
||||
}
|
||||
|
||||
|
@ -644,6 +646,7 @@ impl UndefMask {
|
|||
return Err(self.len);
|
||||
}
|
||||
|
||||
// FIXME(oli-obk): optimize this for allocations larger than a block.
|
||||
let idx = (start.bytes()..end.bytes())
|
||||
.map(|i| Size::from_bytes(i))
|
||||
.find(|&i| !self.get(i));
|
||||
|
@ -663,20 +666,63 @@ impl UndefMask {
|
|||
}
|
||||
|
||||
pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) {
|
||||
for i in start.bytes()..end.bytes() {
|
||||
self.set(Size::from_bytes(i), new_state);
|
||||
let (blocka, bita) = bit_index(start);
|
||||
let (blockb, bitb) = bit_index(end);
|
||||
if blocka == blockb {
|
||||
// first set all bits but the first `bita`
|
||||
// then unset the last `64 - bitb` bits
|
||||
let range = if bitb == 0 {
|
||||
u64::max_value() << bita
|
||||
} else {
|
||||
(u64::max_value() << bita) & (u64::max_value() >> (64 - bitb))
|
||||
};
|
||||
if new_state {
|
||||
self.blocks[blocka] |= range;
|
||||
} else {
|
||||
self.blocks[blocka] &= !range;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// across block boundaries
|
||||
if new_state {
|
||||
// set bita..64 to 1
|
||||
self.blocks[blocka] |= u64::max_value() << bita;
|
||||
// set 0..bitb to 1
|
||||
if bitb != 0 {
|
||||
self.blocks[blockb] |= u64::max_value() >> (64 - bitb);
|
||||
}
|
||||
// fill in all the other blocks (much faster than one bit at a time)
|
||||
for block in (blocka + 1) .. blockb {
|
||||
self.blocks[block] = u64::max_value();
|
||||
}
|
||||
} else {
|
||||
// set bita..64 to 0
|
||||
self.blocks[blocka] &= !(u64::max_value() << bita);
|
||||
// set 0..bitb to 0
|
||||
if bitb != 0 {
|
||||
self.blocks[blockb] &= !(u64::max_value() >> (64 - bitb));
|
||||
}
|
||||
// fill in all the other blocks (much faster than one bit at a time)
|
||||
for block in (blocka + 1) .. blockb {
|
||||
self.blocks[block] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self, i: Size) -> bool {
|
||||
let (block, bit) = bit_index(i);
|
||||
(self.blocks[block] & 1 << bit) != 0
|
||||
(self.blocks[block] & (1 << bit)) != 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set(&mut self, i: Size, new_state: bool) {
|
||||
let (block, bit) = bit_index(i);
|
||||
self.set_bit(block, bit, new_state);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_bit(&mut self, block: usize, bit: usize, new_state: bool) {
|
||||
if new_state {
|
||||
self.blocks[block] |= 1 << bit;
|
||||
} else {
|
||||
|
@ -685,11 +731,15 @@ impl UndefMask {
|
|||
}
|
||||
|
||||
pub fn grow(&mut self, amount: Size, new_state: bool) {
|
||||
let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len.bytes();
|
||||
if amount.bytes() == 0 {
|
||||
return;
|
||||
}
|
||||
let unused_trailing_bits = self.blocks.len() as u64 * Self::BLOCK_SIZE - self.len.bytes();
|
||||
if amount.bytes() > unused_trailing_bits {
|
||||
let additional_blocks = amount.bytes() / BLOCK_SIZE + 1;
|
||||
let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1;
|
||||
assert_eq!(additional_blocks as usize as u64, additional_blocks);
|
||||
self.blocks.extend(
|
||||
// FIXME(oli-obk): optimize this by repeating `new_state as Block`
|
||||
iter::repeat(0).take(additional_blocks as usize),
|
||||
);
|
||||
}
|
||||
|
@ -702,8 +752,8 @@ impl UndefMask {
|
|||
#[inline]
|
||||
fn bit_index(bits: Size) -> (usize, usize) {
|
||||
let bits = bits.bytes();
|
||||
let a = bits / BLOCK_SIZE;
|
||||
let b = bits % BLOCK_SIZE;
|
||||
let a = bits / UndefMask::BLOCK_SIZE;
|
||||
let b = bits % UndefMask::BLOCK_SIZE;
|
||||
assert_eq!(a as usize as u64, a);
|
||||
assert_eq!(b as usize as u64, b);
|
||||
(a as usize, b as usize)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//!
|
||||
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/mir/index.html
|
||||
|
||||
use crate::hir::def::CtorKind;
|
||||
use crate::hir::def::{CtorKind, Namespace};
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::hir::{self, HirId, InlineAsm};
|
||||
use crate::mir::interpret::{ConstValue, EvalErrorKind, Scalar};
|
||||
|
@ -34,7 +34,7 @@ use crate::ty::{
|
|||
self, AdtDef, CanonicalUserTypeAnnotations, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt,
|
||||
UserTypeAnnotationIndex,
|
||||
};
|
||||
use crate::util::ppaux;
|
||||
use crate::ty::print::{FmtPrinter, Printer};
|
||||
|
||||
pub use crate::mir::interpret::AssertMessage;
|
||||
|
||||
|
@ -2062,7 +2062,7 @@ impl<'tcx> Debug for Place<'tcx> {
|
|||
Base(PlaceBase::Static(box self::Static { def_id, ty })) => write!(
|
||||
fmt,
|
||||
"({}: {:?})",
|
||||
ty::tls::with(|tcx| tcx.item_path_str(def_id)),
|
||||
ty::tls::with(|tcx| tcx.def_path_str(def_id)),
|
||||
ty
|
||||
),
|
||||
Base(PlaceBase::Promoted(ref promoted)) => write!(
|
||||
|
@ -2369,7 +2369,10 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
};
|
||||
|
||||
// When printing regions, add trailing space if necessary.
|
||||
let region = if ppaux::verbose() || ppaux::identify_regions() {
|
||||
let print_region = ty::tls::with(|tcx| {
|
||||
tcx.sess.verbose() || tcx.sess.opts.debugging_opts.identify_regions
|
||||
});
|
||||
let region = if print_region {
|
||||
let mut region = region.to_string();
|
||||
if region.len() > 0 {
|
||||
region.push(' ');
|
||||
|
@ -2403,7 +2406,13 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => {
|
||||
let variant_def = &adt_def.variants[variant];
|
||||
|
||||
ppaux::parameterized(fmt, substs, variant_def.did, &[])?;
|
||||
let f = &mut *fmt;
|
||||
ty::tls::with(|tcx| {
|
||||
let substs = tcx.lift(&substs).expect("could not lift for printing");
|
||||
FmtPrinter::new(tcx, f, Namespace::ValueNS)
|
||||
.print_def_path(variant_def.did, substs)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
match variant_def.ctor_kind {
|
||||
CtorKind::Const => Ok(()),
|
||||
|
@ -2729,7 +2738,7 @@ pub fn fmt_const_val(f: &mut impl Write, const_val: ty::Const<'_>) -> fmt::Resul
|
|||
}
|
||||
// print function definitions
|
||||
if let FnDef(did, _) = ty.sty {
|
||||
return write!(f, "{}", item_path_str(did));
|
||||
return write!(f, "{}", def_path_str(did));
|
||||
}
|
||||
// print string literals
|
||||
if let ConstValue::Slice(ptr, len) = value {
|
||||
|
@ -2754,8 +2763,8 @@ pub fn fmt_const_val(f: &mut impl Write, const_val: ty::Const<'_>) -> fmt::Resul
|
|||
write!(f, "{:?}:{}", value, ty)
|
||||
}
|
||||
|
||||
fn item_path_str(def_id: DefId) -> String {
|
||||
ty::tls::with(|tcx| tcx.item_path_str(def_id))
|
||||
fn def_path_str(def_id: DefId) -> String {
|
||||
ty::tls::with(|tcx| tcx.def_path_str(def_id))
|
||||
}
|
||||
|
||||
impl<'tcx> graph::DirectedGraph for Mir<'tcx> {
|
||||
|
|
|
@ -800,6 +800,7 @@ macro_rules! options {
|
|||
pub const parse_opt_pathbuf: Option<&str> = Some("a path");
|
||||
pub const parse_list: Option<&str> = Some("a space-separated list of strings");
|
||||
pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
|
||||
pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
|
||||
pub const parse_uint: Option<&str> = Some("a number");
|
||||
pub const parse_passes: Option<&str> =
|
||||
Some("a space-separated list of passes, or `all`");
|
||||
|
@ -926,6 +927,18 @@ macro_rules! options {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
|
||||
-> bool {
|
||||
match v {
|
||||
Some(s) => {
|
||||
let v = s.split(',').map(|s| s.to_string()).collect();
|
||||
*slot = Some(v);
|
||||
true
|
||||
},
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
|
||||
match v.and_then(|s| s.parse().ok()) {
|
||||
Some(i) => { *slot = i; true },
|
||||
|
@ -1427,6 +1440,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
|
||||
"control the operation of the MergeFunctions LLVM pass, taking
|
||||
the same values as the target option of the same name"),
|
||||
allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
|
||||
"only allow the listed language features to be enabled in code (space separated)"),
|
||||
}
|
||||
|
||||
pub fn default_lib_output() -> CrateType {
|
||||
|
@ -3273,6 +3288,10 @@ mod tests {
|
|||
opts = reference.clone();
|
||||
opts.debugging_opts.merge_functions = Some(MergeFunctions::Disabled);
|
||||
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
|
||||
|
||||
opts = reference.clone();
|
||||
opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]);
|
||||
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -854,10 +854,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
_ => vec![ArgKind::empty()],
|
||||
};
|
||||
|
||||
let expected = match expected_trait_ref.skip_binder().substs.type_at(1).sty {
|
||||
let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
|
||||
let expected = match expected_ty.sty {
|
||||
ty::Tuple(ref tys) => tys.iter()
|
||||
.map(|t| ArgKind::from_expected_ty(t, Some(span))).collect(),
|
||||
ref sty => vec![ArgKind::Arg("_".to_owned(), sty.to_string())],
|
||||
_ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
|
||||
};
|
||||
|
||||
if found.len() == expected.len() {
|
||||
|
@ -1284,11 +1285,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
let span = self.sess.source_map().def_span(span);
|
||||
let mut err = struct_span_err!(self.sess, span, E0072,
|
||||
"recursive type `{}` has infinite size",
|
||||
self.item_path_str(type_def_id));
|
||||
self.def_path_str(type_def_id));
|
||||
err.span_label(span, "recursive type has infinite size");
|
||||
err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
|
||||
at some point to make `{}` representable",
|
||||
self.item_path_str(type_def_id)));
|
||||
self.def_path_str(type_def_id)));
|
||||
err
|
||||
}
|
||||
|
||||
|
@ -1298,7 +1299,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
violations: Vec<ObjectSafetyViolation>)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
{
|
||||
let trait_str = self.item_path_str(trait_def_id);
|
||||
let trait_str = self.def_path_str(trait_def_id);
|
||||
let span = self.sess.source_map().def_span(span);
|
||||
let mut err = struct_span_err!(
|
||||
self.sess, span, E0038,
|
||||
|
@ -1523,7 +1524,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
region, object_ty));
|
||||
}
|
||||
ObligationCauseCode::ItemObligation(item_def_id) => {
|
||||
let item_name = tcx.item_path_str(item_def_id);
|
||||
let item_name = tcx.def_path_str(item_def_id);
|
||||
let msg = format!("required by `{}`", item_name);
|
||||
|
||||
if let Some(sp) = tcx.hir().span_if_local(item_def_id) {
|
||||
|
@ -1686,10 +1687,10 @@ impl ArgKind {
|
|||
ty::Tuple(ref tys) => ArgKind::Tuple(
|
||||
span,
|
||||
tys.iter()
|
||||
.map(|ty| ("_".to_owned(), ty.sty.to_string()))
|
||||
.map(|ty| ("_".to_owned(), ty.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
),
|
||||
_ => ArgKind::Arg("_".to_owned(), t.sty.to_string()),
|
||||
_ => ArgKind::Arg("_".to_owned(), t.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -650,7 +650,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'gcx, 'tcx>(
|
|||
) -> bool {
|
||||
debug!("type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})",
|
||||
ty,
|
||||
infcx.tcx.item_path_str(def_id));
|
||||
infcx.tcx.def_path_str(def_id));
|
||||
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id,
|
||||
|
@ -665,7 +665,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'gcx, 'tcx>(
|
|||
|
||||
let result = infcx.predicate_must_hold_modulo_regions(&obligation);
|
||||
debug!("type_known_to_meet_ty={:?} bound={} => {:?}",
|
||||
ty, infcx.tcx.item_path_str(def_id), result);
|
||||
ty, infcx.tcx.def_path_str(def_id), result);
|
||||
|
||||
if result && (ty.has_infer_types() || ty.has_closure_types()) {
|
||||
// Because of inference "guessing", selection can sometimes claim
|
||||
|
@ -692,13 +692,13 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'gcx, 'tcx>(
|
|||
Ok(()) => {
|
||||
debug!("type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
|
||||
ty,
|
||||
infcx.tcx.item_path_str(def_id));
|
||||
infcx.tcx.def_path_str(def_id));
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
|
||||
ty,
|
||||
infcx.tcx.item_path_str(def_id),
|
||||
infcx.tcx.def_path_str(def_id),
|
||||
e);
|
||||
false
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
|||
hir::CRATE_HIR_ID,
|
||||
*span,
|
||||
&format!("the trait `{}` cannot be made into an object",
|
||||
self.item_path_str(trait_def_id)),
|
||||
self.def_path_str(trait_def_id)),
|
||||
&violation.error_msg());
|
||||
false
|
||||
} else {
|
||||
|
|
|
@ -276,7 +276,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
|||
-> String
|
||||
{
|
||||
let name = tcx.item_name(trait_ref.def_id);
|
||||
let trait_str = tcx.item_path_str(trait_ref.def_id);
|
||||
let trait_str = tcx.def_path_str(trait_ref.def_id);
|
||||
let generics = tcx.generics_of(trait_ref.def_id);
|
||||
let generic_map = generics.params.iter().filter_map(|param| {
|
||||
let value = match param.kind {
|
||||
|
|
|
@ -1549,7 +1549,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
|
|||
// should have failed in astconv.
|
||||
bug!("No associated type `{}` for {}",
|
||||
assoc_ty_name,
|
||||
tcx.item_path_str(impl_def_id))
|
||||
tcx.def_path_str(impl_def_id))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -411,7 +411,7 @@ fn to_pretty_impl_header(tcx: TyCtxt<'_, '_, '_>, impl_def_id: DefId) -> Option<
|
|||
w.push('<');
|
||||
w.push_str(&substs.iter()
|
||||
.map(|k| k.to_string())
|
||||
.filter(|k| &k[..] != "'_")
|
||||
.filter(|k| k != "'_")
|
||||
.collect::<Vec<_>>().join(", "));
|
||||
w.push('>');
|
||||
}
|
||||
|
|
|
@ -165,7 +165,8 @@ impl<'tcx> fmt::Display for traits::WhereClause<'tcx> {
|
|||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use crate::traits::WhereClause::*;
|
||||
|
||||
// Bypass ppaux because it does not print out anonymous regions.
|
||||
// Bypass `ty::print` because it does not print out anonymous regions.
|
||||
// FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`.
|
||||
fn write_region_name<'tcx>(
|
||||
r: ty::Region<'tcx>,
|
||||
fmt: &mut fmt::Formatter<'_>
|
||||
|
@ -256,7 +257,7 @@ impl fmt::Display for traits::QuantifierKind {
|
|||
}
|
||||
|
||||
/// Collect names for regions / types bound by a quantified goal / clause.
|
||||
/// This collector does not try to do anything clever like in ppaux, it's just used
|
||||
/// This collector does not try to do anything clever like in `ty::print`, it's just used
|
||||
/// for debug output in tests anyway.
|
||||
struct BoundNamesCollector {
|
||||
// Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway.
|
||||
|
|
|
@ -26,7 +26,7 @@ use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst};
|
|||
use crate::ty::ReprOptions;
|
||||
use crate::traits;
|
||||
use crate::traits::{Clause, Clauses, GoalKind, Goal, Goals};
|
||||
use crate::ty::{self, Ty, TypeAndMut};
|
||||
use crate::ty::{self, DefIdTree, Ty, TypeAndMut};
|
||||
use crate::ty::{TyS, TyKind, List};
|
||||
use crate::ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const, LazyConst};
|
||||
use crate::ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate};
|
||||
|
@ -1594,7 +1594,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
let (suitable_region_binding_scope, bound_region) = match *region {
|
||||
ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
|
||||
ty::ReEarlyBound(ref ebr) => (
|
||||
self.parent_def_id(ebr.def_id).unwrap(),
|
||||
self.parent(ebr.def_id).unwrap(),
|
||||
ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
|
||||
),
|
||||
_ => return None, // not a free region
|
||||
|
@ -2886,30 +2886,44 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
err.emit()
|
||||
}
|
||||
|
||||
pub fn lint_level_at_node(self, lint: &'static Lint, mut id: hir::HirId)
|
||||
-> (lint::Level, lint::LintSource)
|
||||
{
|
||||
// Right now we insert a `with_ignore` node in the dep graph here to
|
||||
// ignore the fact that `lint_levels` below depends on the entire crate.
|
||||
// For now this'll prevent false positives of recompiling too much when
|
||||
// anything changes.
|
||||
//
|
||||
// Once red/green incremental compilation lands we should be able to
|
||||
// remove this because while the crate changes often the lint level map
|
||||
// will change rarely.
|
||||
self.dep_graph.with_ignore(|| {
|
||||
let sets = self.lint_levels(LOCAL_CRATE);
|
||||
loop {
|
||||
if let Some(pair) = sets.level_and_source(lint, id, self.sess) {
|
||||
return pair
|
||||
}
|
||||
let next = self.hir().get_parent_node_by_hir_id(id);
|
||||
if next == id {
|
||||
bug!("lint traversal reached the root of the crate");
|
||||
}
|
||||
id = next;
|
||||
/// Walks upwards from `id` to find a node which might change lint levels with attributes.
|
||||
/// It stops at `bound` and just returns it if reached.
|
||||
pub fn maybe_lint_level_root_bounded(
|
||||
self,
|
||||
mut id: hir::HirId,
|
||||
bound: hir::HirId,
|
||||
) -> hir::HirId {
|
||||
loop {
|
||||
if id == bound {
|
||||
return bound;
|
||||
}
|
||||
})
|
||||
if lint::maybe_lint_level_root(self, id) {
|
||||
return id;
|
||||
}
|
||||
let next = self.hir().get_parent_node_by_hir_id(id);
|
||||
if next == id {
|
||||
bug!("lint traversal reached the root of the crate");
|
||||
}
|
||||
id = next;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lint_level_at_node(
|
||||
self,
|
||||
lint: &'static Lint,
|
||||
mut id: hir::HirId
|
||||
) -> (lint::Level, lint::LintSource) {
|
||||
let sets = self.lint_levels(LOCAL_CRATE);
|
||||
loop {
|
||||
if let Some(pair) = sets.level_and_source(lint, id, self.sess) {
|
||||
return pair
|
||||
}
|
||||
let next = self.hir().get_parent_node_by_hir_id(id);
|
||||
if next == id {
|
||||
bug!("lint traversal reached the root of the crate");
|
||||
}
|
||||
id = next;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn struct_span_lint_hir<S: Into<MultiSpan>>(self,
|
||||
|
|
|
@ -71,6 +71,13 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let br_string = |br: ty::BoundRegion| {
|
||||
match br {
|
||||
ty::BrNamed(_, name) => format!(" {}", name),
|
||||
_ => String::new(),
|
||||
}
|
||||
};
|
||||
|
||||
match *self {
|
||||
CyclicTy(_) => write!(f, "cyclic type of infinite size"),
|
||||
Mismatch => write!(f, "types differ"),
|
||||
|
@ -105,15 +112,13 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
|||
}
|
||||
RegionsInsufficientlyPolymorphic(br, _) => {
|
||||
write!(f,
|
||||
"expected bound lifetime parameter{}{}, found concrete lifetime",
|
||||
if br.is_named() { " " } else { "" },
|
||||
br)
|
||||
"expected bound lifetime parameter{}, found concrete lifetime",
|
||||
br_string(br))
|
||||
}
|
||||
RegionsOverlyPolymorphic(br, _) => {
|
||||
write!(f,
|
||||
"expected concrete lifetime, found bound lifetime parameter{}{}",
|
||||
if br.is_named() { " " } else { "" },
|
||||
br)
|
||||
"expected concrete lifetime, found bound lifetime parameter{}",
|
||||
br_string(br))
|
||||
}
|
||||
RegionsPlaceholderMismatch => {
|
||||
write!(f, "one type is more general than the other")
|
||||
|
@ -125,9 +130,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
|||
Traits(values) => ty::tls::with(|tcx| {
|
||||
report_maybe_different(f,
|
||||
&format!("trait `{}`",
|
||||
tcx.item_path_str(values.expected)),
|
||||
tcx.def_path_str(values.expected)),
|
||||
&format!("trait `{}`",
|
||||
tcx.item_path_str(values.found)))
|
||||
tcx.def_path_str(values.found)))
|
||||
}),
|
||||
IntMismatch(ref values) => {
|
||||
write!(f, "expected `{:?}`, found `{:?}`",
|
||||
|
@ -146,8 +151,8 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
|||
}
|
||||
ProjectionMismatched(ref values) => ty::tls::with(|tcx| {
|
||||
write!(f, "expected {}, found {}",
|
||||
tcx.item_path_str(values.expected),
|
||||
tcx.item_path_str(values.found))
|
||||
tcx.def_path_str(values.expected),
|
||||
tcx.def_path_str(values.found))
|
||||
}),
|
||||
ProjectionBoundsLength(ref values) => {
|
||||
write!(f, "expected {} associated type bindings, found {}",
|
||||
|
@ -169,8 +174,8 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
|
|||
ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => self.to_string().into(),
|
||||
ty::Tuple(ref tys) if tys.is_empty() => self.to_string().into(),
|
||||
|
||||
ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)).into(),
|
||||
ty::Foreign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)).into(),
|
||||
ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
|
||||
ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
|
||||
ty::Array(_, n) => match n {
|
||||
ty::LazyConst::Evaluated(n) => match n.assert_usize(tcx) {
|
||||
Some(n) => format!("array of {} elements", n).into(),
|
||||
|
@ -185,7 +190,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
|
|||
let tymut_string = tymut.to_string();
|
||||
if tymut_string == "_" || //unknown type name,
|
||||
tymut_string.len() > 10 || //name longer than saying "reference",
|
||||
region.to_string() != "" //... or a complex type
|
||||
region.to_string() != "'_" //... or a complex type
|
||||
{
|
||||
format!("{}reference", match mutbl {
|
||||
hir::Mutability::MutMutable => "mutable ",
|
||||
|
@ -199,7 +204,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
|
|||
ty::FnPtr(_) => "fn pointer".into(),
|
||||
ty::Dynamic(ref inner, ..) => {
|
||||
if let Some(principal) = inner.principal() {
|
||||
format!("trait {}", tcx.item_path_str(principal.def_id())).into()
|
||||
format!("trait {}", tcx.def_path_str(principal.def_id())).into()
|
||||
} else {
|
||||
"trait".into()
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::hir::Unsafety;
|
||||
use crate::hir::def::Namespace;
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::ty::{self, Ty, PolyFnSig, TypeFoldable, SubstsRef, TyCtxt};
|
||||
use crate::ty::print::{FmtPrinter, Printer};
|
||||
use crate::traits;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_macros::HashStable;
|
||||
use crate::util::ppaux;
|
||||
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
|
@ -175,7 +176,13 @@ impl<'tcx> InstanceDef<'tcx> {
|
|||
|
||||
impl<'tcx> fmt::Display for Instance<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ppaux::parameterized(f, self.substs, self.def_id(), &[])?;
|
||||
ty::tls::with(|tcx| {
|
||||
let substs = tcx.lift(&self.substs).expect("could not lift for printing");
|
||||
FmtPrinter::new(tcx, &mut *f, Namespace::ValueNS)
|
||||
.print_def_path(self.def_id(), substs)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
match self.def {
|
||||
InstanceDef::Item(_) => Ok(()),
|
||||
InstanceDef::VtableShim(_) => {
|
||||
|
|
|
@ -1,573 +0,0 @@
|
|||
use crate::hir::map::DefPathData;
|
||||
use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use crate::ty::{self, DefIdTree, Ty, TyCtxt};
|
||||
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
|
||||
use syntax::ast;
|
||||
use syntax::symbol::{keywords, LocalInternedString, Symbol};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fmt::Debug;
|
||||
|
||||
thread_local! {
|
||||
static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
|
||||
static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
|
||||
static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
|
||||
}
|
||||
|
||||
/// Enforces that item_path_str always returns an absolute path and
|
||||
/// also enables "type-based" impl paths. This is used when building
|
||||
/// symbols that contain types, where we want the crate name to be
|
||||
/// part of the symbol.
|
||||
pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
|
||||
FORCE_ABSOLUTE.with(|force| {
|
||||
let old = force.get();
|
||||
force.set(true);
|
||||
let result = f();
|
||||
force.set(old);
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
/// Force us to name impls with just the filename/line number. We
|
||||
/// normally try to use types. But at some points, notably while printing
|
||||
/// cycle errors, this can result in extra or suboptimal error output,
|
||||
/// so this variable disables that check.
|
||||
pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
|
||||
FORCE_IMPL_FILENAME_LINE.with(|force| {
|
||||
let old = force.get();
|
||||
force.set(true);
|
||||
let result = f();
|
||||
force.set(old);
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
/// Adds the `crate::` prefix to paths where appropriate.
|
||||
pub fn with_crate_prefix<F: FnOnce() -> R, R>(f: F) -> R {
|
||||
SHOULD_PREFIX_WITH_CRATE.with(|flag| {
|
||||
let old = flag.get();
|
||||
flag.set(true);
|
||||
let result = f();
|
||||
flag.set(old);
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
/// Returns a string identifying this `DefId`. This string is
|
||||
/// suitable for user output. It is relative to the current crate
|
||||
/// root, unless with_forced_absolute_paths was used.
|
||||
pub fn item_path_str(self, def_id: DefId) -> String {
|
||||
let mode = FORCE_ABSOLUTE.with(|force| {
|
||||
if force.get() {
|
||||
RootMode::Absolute
|
||||
} else {
|
||||
RootMode::Local
|
||||
}
|
||||
});
|
||||
let mut buffer = LocalPathBuffer::new(mode);
|
||||
debug!("item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
|
||||
self.push_item_path(&mut buffer, def_id, false);
|
||||
buffer.into_string()
|
||||
}
|
||||
|
||||
/// Returns a string identifying this local node-id.
|
||||
pub fn node_path_str(self, id: ast::NodeId) -> String {
|
||||
self.item_path_str(self.hir().local_def_id(id))
|
||||
}
|
||||
|
||||
/// Returns a string identifying this def-id. This string is
|
||||
/// suitable for user output. It always begins with a crate identifier.
|
||||
pub fn absolute_item_path_str(self, def_id: DefId) -> String {
|
||||
let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
|
||||
debug!("absolute_item_path_str: buffer={:?} def_id={:?}", buffer, def_id);
|
||||
self.push_item_path(&mut buffer, def_id, false);
|
||||
buffer.into_string()
|
||||
}
|
||||
|
||||
/// Returns the "path" to a particular crate. This can proceed in
|
||||
/// various ways, depending on the `root_mode` of the `buffer`.
|
||||
/// (See `RootMode` enum for more details.)
|
||||
///
|
||||
/// `pushed_prelude_crate` argument should be `true` when the buffer
|
||||
/// has had a prelude crate pushed to it. If this is the case, then
|
||||
/// we do not want to prepend `crate::` (as that would not be a valid
|
||||
/// path).
|
||||
pub fn push_krate_path<T>(self, buffer: &mut T, cnum: CrateNum, pushed_prelude_crate: bool)
|
||||
where T: ItemPathBuffer + Debug
|
||||
{
|
||||
debug!(
|
||||
"push_krate_path: buffer={:?} cnum={:?} LOCAL_CRATE={:?}",
|
||||
buffer, cnum, LOCAL_CRATE
|
||||
);
|
||||
match *buffer.root_mode() {
|
||||
RootMode::Local => {
|
||||
// In local mode, when we encounter a crate other than
|
||||
// LOCAL_CRATE, execution proceeds in one of two ways:
|
||||
//
|
||||
// 1. for a direct dependency, where user added an
|
||||
// `extern crate` manually, we put the `extern
|
||||
// crate` as the parent. So you wind up with
|
||||
// something relative to the current crate.
|
||||
// 2. for an extern inferred from a path or an indirect crate,
|
||||
// where there is no explicit `extern crate`, we just prepend
|
||||
// the crate name.
|
||||
//
|
||||
// Returns `None` for the local crate.
|
||||
if cnum != LOCAL_CRATE {
|
||||
let opt_extern_crate = self.extern_crate(cnum.as_def_id());
|
||||
if let Some(ExternCrate {
|
||||
src: ExternCrateSource::Extern(def_id),
|
||||
direct: true,
|
||||
..
|
||||
}) = *opt_extern_crate
|
||||
{
|
||||
debug!("push_krate_path: def_id={:?}", def_id);
|
||||
self.push_item_path(buffer, def_id, pushed_prelude_crate);
|
||||
} else {
|
||||
let name = self.crate_name(cnum).as_str();
|
||||
debug!("push_krate_path: name={:?}", name);
|
||||
buffer.push(&name);
|
||||
}
|
||||
} else if self.sess.rust_2018() && !pushed_prelude_crate {
|
||||
SHOULD_PREFIX_WITH_CRATE.with(|flag| {
|
||||
// We only add the `crate::` keyword where appropriate. In particular,
|
||||
// when we've not previously pushed a prelude crate to this path.
|
||||
if flag.get() {
|
||||
buffer.push(&keywords::Crate.name().as_str())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
RootMode::Absolute => {
|
||||
// In absolute mode, just write the crate name
|
||||
// unconditionally.
|
||||
let name = self.original_crate_name(cnum).as_str();
|
||||
debug!("push_krate_path: original_name={:?}", name);
|
||||
buffer.push(&name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If possible, this pushes a global path resolving to `external_def_id` that is visible
|
||||
/// from at least one local module and returns true. If the crate defining `external_def_id` is
|
||||
/// declared with an `extern crate`, the path is guaranteed to use the `extern crate`.
|
||||
pub fn try_push_visible_item_path<T>(
|
||||
self,
|
||||
buffer: &mut T,
|
||||
external_def_id: DefId,
|
||||
pushed_prelude_crate: bool,
|
||||
) -> bool
|
||||
where T: ItemPathBuffer + Debug
|
||||
{
|
||||
debug!(
|
||||
"try_push_visible_item_path: buffer={:?} external_def_id={:?}",
|
||||
buffer, external_def_id
|
||||
);
|
||||
let visible_parent_map = self.visible_parent_map(LOCAL_CRATE);
|
||||
|
||||
let (mut cur_def, mut cur_path) = (external_def_id, Vec::<LocalInternedString>::new());
|
||||
loop {
|
||||
debug!(
|
||||
"try_push_visible_item_path: cur_def={:?} cur_path={:?} CRATE_DEF_INDEX={:?}",
|
||||
cur_def, cur_path, CRATE_DEF_INDEX,
|
||||
);
|
||||
// If `cur_def` is a direct or injected extern crate, push the path to the crate
|
||||
// followed by the path to the item within the crate and return.
|
||||
if cur_def.index == CRATE_DEF_INDEX {
|
||||
match *self.extern_crate(cur_def) {
|
||||
Some(ExternCrate {
|
||||
src: ExternCrateSource::Extern(def_id),
|
||||
direct: true,
|
||||
..
|
||||
}) => {
|
||||
debug!("try_push_visible_item_path: def_id={:?}", def_id);
|
||||
self.push_item_path(buffer, def_id, pushed_prelude_crate);
|
||||
cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
|
||||
return true;
|
||||
}
|
||||
None => {
|
||||
buffer.push(&self.crate_name(cur_def.krate).as_str());
|
||||
cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
|
||||
return true;
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
let mut cur_def_key = self.def_key(cur_def);
|
||||
debug!("try_push_visible_item_path: cur_def_key={:?}", cur_def_key);
|
||||
|
||||
// For a UnitStruct or TupleStruct we want the name of its parent rather than <unnamed>.
|
||||
if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data {
|
||||
let parent = DefId {
|
||||
krate: cur_def.krate,
|
||||
index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"),
|
||||
};
|
||||
|
||||
cur_def_key = self.def_key(parent);
|
||||
}
|
||||
|
||||
let visible_parent = visible_parent_map.get(&cur_def).cloned();
|
||||
let actual_parent = self.parent(cur_def);
|
||||
|
||||
let data = cur_def_key.disambiguated_data.data;
|
||||
debug!(
|
||||
"try_push_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}",
|
||||
data, visible_parent, actual_parent,
|
||||
);
|
||||
let symbol = match data {
|
||||
// In order to output a path that could actually be imported (valid and visible),
|
||||
// we need to handle re-exports correctly.
|
||||
//
|
||||
// For example, take `std::os::unix::process::CommandExt`, this trait is actually
|
||||
// defined at `std::sys::unix::ext::process::CommandExt` (at time of writing).
|
||||
//
|
||||
// `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
|
||||
// private so the "true" path to `CommandExt` isn't accessible.
|
||||
//
|
||||
// In this case, the `visible_parent_map` will look something like this:
|
||||
//
|
||||
// (child) -> (parent)
|
||||
// `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
|
||||
// `std::sys::unix::ext::process` -> `std::sys::unix::ext`
|
||||
// `std::sys::unix::ext` -> `std::os`
|
||||
//
|
||||
// This is correct, as the visible parent of `std::sys::unix::ext` is in fact
|
||||
// `std::os`.
|
||||
//
|
||||
// When printing the path to `CommandExt` and looking at the `cur_def_key` that
|
||||
// corresponds to `std::sys::unix::ext`, we would normally print `ext` and then go
|
||||
// to the parent - resulting in a mangled path like
|
||||
// `std::os::ext::process::CommandExt`.
|
||||
//
|
||||
// Instead, we must detect that there was a re-export and instead print `unix`
|
||||
// (which is the name `std::sys::unix::ext` was re-exported as in `std::os`). To
|
||||
// do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
|
||||
// the visible parent (`std::os`). If these do not match, then we iterate over
|
||||
// the children of the visible parent (as was done when computing
|
||||
// `visible_parent_map`), looking for the specific child we currently have and then
|
||||
// have access to the re-exported name.
|
||||
DefPathData::Module(actual_name) |
|
||||
DefPathData::TypeNs(actual_name) if visible_parent != actual_parent => {
|
||||
visible_parent
|
||||
.and_then(|parent| {
|
||||
self.item_children(parent)
|
||||
.iter()
|
||||
.find(|child| child.def.def_id() == cur_def)
|
||||
.map(|child| child.ident.as_str())
|
||||
})
|
||||
.unwrap_or_else(|| actual_name.as_str())
|
||||
},
|
||||
_ => {
|
||||
data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
|
||||
// Re-exported `extern crate` (#43189).
|
||||
if let DefPathData::CrateRoot = data {
|
||||
self.original_crate_name(cur_def.krate).as_str()
|
||||
} else {
|
||||
Symbol::intern("<unnamed>").as_str()
|
||||
}
|
||||
})
|
||||
},
|
||||
};
|
||||
debug!("try_push_visible_item_path: symbol={:?}", symbol);
|
||||
cur_path.push(symbol);
|
||||
|
||||
match visible_parent {
|
||||
Some(def) => cur_def = def,
|
||||
None => return false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId, pushed_prelude_crate: bool)
|
||||
where T: ItemPathBuffer + Debug
|
||||
{
|
||||
debug!(
|
||||
"push_item_path: buffer={:?} def_id={:?} pushed_prelude_crate={:?}",
|
||||
buffer, def_id, pushed_prelude_crate
|
||||
);
|
||||
match *buffer.root_mode() {
|
||||
RootMode::Local if !def_id.is_local() =>
|
||||
if self.try_push_visible_item_path(buffer, def_id, pushed_prelude_crate) { return },
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let key = self.def_key(def_id);
|
||||
debug!("push_item_path: key={:?}", key);
|
||||
match key.disambiguated_data.data {
|
||||
DefPathData::CrateRoot => {
|
||||
assert!(key.parent.is_none());
|
||||
self.push_krate_path(buffer, def_id.krate, pushed_prelude_crate);
|
||||
}
|
||||
|
||||
DefPathData::Impl => {
|
||||
self.push_impl_path(buffer, def_id, pushed_prelude_crate);
|
||||
}
|
||||
|
||||
// Unclear if there is any value in distinguishing these.
|
||||
// Probably eventually (and maybe we would even want
|
||||
// finer-grained distinctions, e.g., between enum/struct).
|
||||
data @ DefPathData::Misc |
|
||||
data @ DefPathData::TypeNs(..) |
|
||||
data @ DefPathData::Trait(..) |
|
||||
data @ DefPathData::TraitAlias(..) |
|
||||
data @ DefPathData::AssocTypeInTrait(..) |
|
||||
data @ DefPathData::AssocTypeInImpl(..) |
|
||||
data @ DefPathData::AssocExistentialInImpl(..) |
|
||||
data @ DefPathData::ValueNs(..) |
|
||||
data @ DefPathData::Module(..) |
|
||||
data @ DefPathData::TypeParam(..) |
|
||||
data @ DefPathData::LifetimeParam(..) |
|
||||
data @ DefPathData::ConstParam(..) |
|
||||
data @ DefPathData::EnumVariant(..) |
|
||||
data @ DefPathData::Field(..) |
|
||||
data @ DefPathData::AnonConst |
|
||||
data @ DefPathData::MacroDef(..) |
|
||||
data @ DefPathData::ClosureExpr |
|
||||
data @ DefPathData::ImplTrait |
|
||||
data @ DefPathData::GlobalMetaData(..) => {
|
||||
let parent_did = self.parent_def_id(def_id).unwrap();
|
||||
|
||||
// Keep track of whether we are one recursion away from the `CrateRoot` and
|
||||
// pushing the name of a prelude crate. If we are, we'll want to know this when
|
||||
// printing the `CrateRoot` so we don't prepend a `crate::` to paths.
|
||||
let mut is_prelude_crate = false;
|
||||
if let DefPathData::CrateRoot = self.def_key(parent_did).disambiguated_data.data {
|
||||
if self.extern_prelude.contains_key(&data.as_interned_str().as_symbol()) {
|
||||
is_prelude_crate = true;
|
||||
}
|
||||
}
|
||||
|
||||
self.push_item_path(
|
||||
buffer, parent_did, pushed_prelude_crate || is_prelude_crate
|
||||
);
|
||||
buffer.push(&data.as_interned_str().as_symbol().as_str());
|
||||
},
|
||||
|
||||
DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}`
|
||||
let parent_def_id = self.parent_def_id(def_id).unwrap();
|
||||
self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_impl_path<T>(
|
||||
self,
|
||||
buffer: &mut T,
|
||||
impl_def_id: DefId,
|
||||
pushed_prelude_crate: bool,
|
||||
)
|
||||
where T: ItemPathBuffer + Debug
|
||||
{
|
||||
debug!("push_impl_path: buffer={:?} impl_def_id={:?}", buffer, impl_def_id);
|
||||
let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
|
||||
|
||||
// Always use types for non-local impls, where types are always
|
||||
// available, and filename/line-number is mostly uninteresting.
|
||||
let use_types = !impl_def_id.is_local() || {
|
||||
// Otherwise, use filename/line-number if forced.
|
||||
let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
|
||||
!force_no_types
|
||||
};
|
||||
|
||||
if !use_types {
|
||||
return self.push_impl_path_fallback(buffer, impl_def_id, pushed_prelude_crate);
|
||||
}
|
||||
|
||||
// Decide whether to print the parent path for the impl.
|
||||
// Logically, since impls are global, it's never needed, but
|
||||
// users may find it useful. Currently, we omit the parent if
|
||||
// the impl is either in the same module as the self-type or
|
||||
// as the trait.
|
||||
let self_ty = self.type_of(impl_def_id);
|
||||
let in_self_mod = match characteristic_def_id_of_type(self_ty) {
|
||||
None => false,
|
||||
Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id),
|
||||
};
|
||||
|
||||
let impl_trait_ref = self.impl_trait_ref(impl_def_id);
|
||||
let in_trait_mod = match impl_trait_ref {
|
||||
None => false,
|
||||
Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
|
||||
};
|
||||
|
||||
if !in_self_mod && !in_trait_mod {
|
||||
// If the impl is not co-located with either self-type or
|
||||
// trait-type, then fallback to a format that identifies
|
||||
// the module more clearly.
|
||||
self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
|
||||
if let Some(trait_ref) = impl_trait_ref {
|
||||
buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
|
||||
} else {
|
||||
buffer.push(&format!("<impl {}>", self_ty));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, try to give a good form that would be valid language
|
||||
// syntax. Preferably using associated item notation.
|
||||
|
||||
if let Some(trait_ref) = impl_trait_ref {
|
||||
// Trait impls.
|
||||
buffer.push(&format!("<{} as {}>", self_ty, trait_ref));
|
||||
return;
|
||||
}
|
||||
|
||||
// Inherent impls. Try to print `Foo::bar` for an inherent
|
||||
// impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
|
||||
// anything other than a simple path.
|
||||
match self_ty.sty {
|
||||
ty::Adt(adt_def, substs) => {
|
||||
if substs.types().next().is_none() { // ignore regions
|
||||
self.push_item_path(buffer, adt_def.did, pushed_prelude_crate);
|
||||
} else {
|
||||
buffer.push(&format!("<{}>", self_ty));
|
||||
}
|
||||
}
|
||||
|
||||
ty::Foreign(did) => self.push_item_path(buffer, did, pushed_prelude_crate),
|
||||
|
||||
ty::Bool |
|
||||
ty::Char |
|
||||
ty::Int(_) |
|
||||
ty::Uint(_) |
|
||||
ty::Float(_) |
|
||||
ty::Str => {
|
||||
buffer.push(&self_ty.to_string());
|
||||
}
|
||||
|
||||
_ => {
|
||||
buffer.push(&format!("<{}>", self_ty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_impl_path_fallback<T>(
|
||||
self,
|
||||
buffer: &mut T,
|
||||
impl_def_id: DefId,
|
||||
pushed_prelude_crate: bool,
|
||||
)
|
||||
where T: ItemPathBuffer + Debug
|
||||
{
|
||||
// If no type info is available, fall back to
|
||||
// pretty printing some span information. This should
|
||||
// only occur very early in the compiler pipeline.
|
||||
let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
|
||||
self.push_item_path(buffer, parent_def_id, pushed_prelude_crate);
|
||||
let hir_id = self.hir().as_local_hir_id(impl_def_id).unwrap();
|
||||
let item = self.hir().expect_item_by_hir_id(hir_id);
|
||||
let span_str = self.sess.source_map().span_to_string(item.span);
|
||||
buffer.push(&format!("<impl at {}>", span_str));
|
||||
}
|
||||
|
||||
/// Returns the `DefId` of `def_id`'s parent in the def tree. If
|
||||
/// this returns `None`, then `def_id` represents a crate root or
|
||||
/// inlined root.
|
||||
pub fn parent_def_id(self, def_id: DefId) -> Option<DefId> {
|
||||
let key = self.def_key(def_id);
|
||||
key.parent.map(|index| DefId { krate: def_id.krate, index: index })
|
||||
}
|
||||
}
|
||||
|
||||
/// As a heuristic, when we see an impl, if we see that the
|
||||
/// 'self type' is a type defined in the same module as the impl,
|
||||
/// we can omit including the path to the impl itself. This
|
||||
/// function tries to find a "characteristic `DefId`" for a
|
||||
/// type. It's just a heuristic so it makes some questionable
|
||||
/// decisions and we may want to adjust it later.
|
||||
pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
|
||||
match ty.sty {
|
||||
ty::Adt(adt_def, _) => Some(adt_def.did),
|
||||
|
||||
ty::Dynamic(data, ..) => data.principal_def_id(),
|
||||
|
||||
ty::Array(subty, _) |
|
||||
ty::Slice(subty) => characteristic_def_id_of_type(subty),
|
||||
|
||||
ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
|
||||
|
||||
ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
|
||||
|
||||
ty::Tuple(ref tys) => tys.iter()
|
||||
.filter_map(|ty| characteristic_def_id_of_type(ty))
|
||||
.next(),
|
||||
|
||||
ty::FnDef(def_id, _) |
|
||||
ty::Closure(def_id, _) |
|
||||
ty::Generator(def_id, _, _) |
|
||||
ty::Foreign(def_id) => Some(def_id),
|
||||
|
||||
ty::Bool |
|
||||
ty::Char |
|
||||
ty::Int(_) |
|
||||
ty::Uint(_) |
|
||||
ty::Str |
|
||||
ty::FnPtr(_) |
|
||||
ty::Projection(_) |
|
||||
ty::Placeholder(..) |
|
||||
ty::UnnormalizedProjection(..) |
|
||||
ty::Param(_) |
|
||||
ty::Opaque(..) |
|
||||
ty::Infer(_) |
|
||||
ty::Bound(..) |
|
||||
ty::Error |
|
||||
ty::GeneratorWitness(..) |
|
||||
ty::Never |
|
||||
ty::Float(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Unifying Trait for different kinds of item paths we might
|
||||
/// construct. The basic interface is that components get pushed: the
|
||||
/// instance can also customize how we handle the root of a crate.
|
||||
pub trait ItemPathBuffer {
|
||||
fn root_mode(&self) -> &RootMode;
|
||||
fn push(&mut self, text: &str);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RootMode {
|
||||
/// Try to make a path relative to the local crate. In
|
||||
/// particular, local paths have no prefix, and if the path comes
|
||||
/// from an extern crate, start with the path to the `extern
|
||||
/// crate` declaration.
|
||||
Local,
|
||||
|
||||
/// Always prepend the crate name to the path, forming an absolute
|
||||
/// path from within a given set of crates.
|
||||
Absolute,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LocalPathBuffer {
|
||||
root_mode: RootMode,
|
||||
str: String,
|
||||
}
|
||||
|
||||
impl LocalPathBuffer {
|
||||
fn new(root_mode: RootMode) -> LocalPathBuffer {
|
||||
LocalPathBuffer {
|
||||
root_mode,
|
||||
str: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_string(self) -> String {
|
||||
self.str
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemPathBuffer for LocalPathBuffer {
|
||||
fn root_mode(&self) -> &RootMode {
|
||||
&self.root_mode
|
||||
}
|
||||
|
||||
fn push(&mut self, text: &str) {
|
||||
if !self.str.is_empty() {
|
||||
self.str.push_str("::");
|
||||
}
|
||||
self.str.push_str(text);
|
||||
}
|
||||
}
|
|
@ -95,10 +95,10 @@ mod erase_regions;
|
|||
pub mod fast_reject;
|
||||
pub mod fold;
|
||||
pub mod inhabitedness;
|
||||
pub mod item_path;
|
||||
pub mod layout;
|
||||
pub mod _match;
|
||||
pub mod outlives;
|
||||
pub mod print;
|
||||
pub mod query;
|
||||
pub mod relate;
|
||||
pub mod steal;
|
||||
|
@ -1000,7 +1000,7 @@ impl<'a, 'gcx, 'tcx> Generics {
|
|||
}
|
||||
|
||||
/// Bounds on generics.
|
||||
#[derive(Clone, Default, HashStable)]
|
||||
#[derive(Clone, Default, Debug, HashStable)]
|
||||
pub struct GenericPredicates<'tcx> {
|
||||
pub parent: Option<DefId>,
|
||||
pub predicates: Vec<(Predicate<'tcx>, Span)>,
|
||||
|
@ -1505,7 +1505,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
/// `[[], [U:Bar<T>]]`. Now if there were some particular reference
|
||||
/// like `Foo<isize,usize>`, then the `InstantiatedPredicates` would be `[[],
|
||||
/// [usize:Bar<isize>]]`.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InstantiatedPredicates<'tcx> {
|
||||
pub predicates: Vec<Predicate<'tcx>>,
|
||||
}
|
||||
|
@ -2055,7 +2055,7 @@ impl ReprOptions {
|
|||
}
|
||||
|
||||
// This is here instead of layout because the choice must make it into metadata.
|
||||
if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) {
|
||||
if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.def_path_str(did))) {
|
||||
flags.insert(ReprFlags::IS_LINEAR);
|
||||
}
|
||||
ReprOptions { int: size, align: max_align, pack: min_pack, flags: flags }
|
||||
|
@ -2892,14 +2892,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef {
|
||||
match def {
|
||||
Def::Variant(did) | Def::VariantCtor(did, ..) => {
|
||||
let enum_did = self.parent_def_id(did).unwrap();
|
||||
let enum_did = self.parent(did).unwrap();
|
||||
self.adt_def(enum_did).variant_with_id(did)
|
||||
}
|
||||
Def::Struct(did) | Def::Union(did) => {
|
||||
self.adt_def(did).non_enum_variant()
|
||||
}
|
||||
Def::StructCtor(ctor_did, ..) => {
|
||||
let did = self.parent_def_id(ctor_did).expect("struct ctor has no parent");
|
||||
let did = self.parent(ctor_did).expect("struct ctor has no parent");
|
||||
self.adt_def(did).non_enum_variant()
|
||||
}
|
||||
_ => bug!("expect_variant_def used with unexpected def {:?}", def)
|
||||
|
|
327
src/librustc/ty/print/mod.rs
Normal file
327
src/librustc/ty/print/mod.rs
Normal file
|
@ -0,0 +1,327 @@
|
|||
use crate::hir::map::{DefPathData, DisambiguatedDefPathData};
|
||||
use crate::hir::def_id::{CrateNum, DefId};
|
||||
use crate::ty::{self, DefIdTree, Ty, TyCtxt};
|
||||
use crate::ty::subst::{Kind, Subst};
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
// `pretty` is a separate module only for organization.
|
||||
mod pretty;
|
||||
pub use self::pretty::*;
|
||||
|
||||
pub trait Print<'gcx, 'tcx, P> {
|
||||
type Output;
|
||||
type Error;
|
||||
|
||||
fn print(&self, cx: P) -> Result<Self::Output, Self::Error>;
|
||||
}
|
||||
|
||||
/// Interface for outputting user-facing "type-system entities"
|
||||
/// (paths, types, lifetimes, constants, etc.) as a side-effect
|
||||
/// (e.g. formatting, like `PrettyPrinter` implementors do) or by
|
||||
/// constructing some alternative representation (e.g. an AST),
|
||||
/// which the associated types allow passing through the methods.
|
||||
///
|
||||
/// For pretty-printing/formatting in particular, see `PrettyPrinter`.
|
||||
// FIXME(eddyb) find a better name, this is more general than "printing".
|
||||
pub trait Printer<'gcx: 'tcx, 'tcx>: Sized {
|
||||
type Error;
|
||||
|
||||
type Path;
|
||||
type Region;
|
||||
type Type;
|
||||
type DynExistential;
|
||||
|
||||
fn tcx(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
|
||||
|
||||
fn print_def_path(
|
||||
self,
|
||||
def_id: DefId,
|
||||
substs: &'tcx [Kind<'tcx>],
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
self.default_print_def_path(def_id, substs)
|
||||
}
|
||||
fn print_impl_path(
|
||||
self,
|
||||
impl_def_id: DefId,
|
||||
substs: &'tcx [Kind<'tcx>],
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref)
|
||||
}
|
||||
|
||||
fn print_region(
|
||||
self,
|
||||
region: ty::Region<'_>,
|
||||
) -> Result<Self::Region, Self::Error>;
|
||||
|
||||
fn print_type(
|
||||
self,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Self::Type, Self::Error>;
|
||||
|
||||
fn print_dyn_existential(
|
||||
self,
|
||||
predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
|
||||
) -> Result<Self::DynExistential, Self::Error>;
|
||||
|
||||
fn path_crate(
|
||||
self,
|
||||
cnum: CrateNum,
|
||||
) -> Result<Self::Path, Self::Error>;
|
||||
fn path_qualified(
|
||||
self,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error>;
|
||||
|
||||
fn path_append_impl(
|
||||
self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
disambiguated_data: &DisambiguatedDefPathData,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error>;
|
||||
fn path_append(
|
||||
self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
disambiguated_data: &DisambiguatedDefPathData,
|
||||
) -> Result<Self::Path, Self::Error>;
|
||||
fn path_generic_args(
|
||||
self,
|
||||
print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
|
||||
args: &[Kind<'tcx>],
|
||||
) -> Result<Self::Path, Self::Error>;
|
||||
|
||||
// Defaults (should not be overriden):
|
||||
|
||||
fn default_print_def_path(
|
||||
self,
|
||||
def_id: DefId,
|
||||
substs: &'tcx [Kind<'tcx>],
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs);
|
||||
let key = self.tcx().def_key(def_id);
|
||||
debug!("default_print_def_path: key={:?}", key);
|
||||
|
||||
match key.disambiguated_data.data {
|
||||
DefPathData::CrateRoot => {
|
||||
assert!(key.parent.is_none());
|
||||
self.path_crate(def_id.krate)
|
||||
}
|
||||
|
||||
DefPathData::Impl => {
|
||||
let generics = self.tcx().generics_of(def_id);
|
||||
let mut self_ty = self.tcx().type_of(def_id);
|
||||
let mut impl_trait_ref = self.tcx().impl_trait_ref(def_id);
|
||||
if substs.len() >= generics.count() {
|
||||
self_ty = self_ty.subst(self.tcx(), substs);
|
||||
impl_trait_ref = impl_trait_ref.subst(self.tcx(), substs);
|
||||
}
|
||||
self.print_impl_path(def_id, substs, self_ty, impl_trait_ref)
|
||||
}
|
||||
|
||||
_ => {
|
||||
let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
|
||||
|
||||
let mut parent_substs = substs;
|
||||
let mut trait_qualify_parent = false;
|
||||
if !substs.is_empty() {
|
||||
let generics = self.tcx().generics_of(def_id);
|
||||
parent_substs = &substs[..generics.parent_count.min(substs.len())];
|
||||
|
||||
match key.disambiguated_data.data {
|
||||
// Closures' own generics are only captures, don't print them.
|
||||
DefPathData::ClosureExpr => {}
|
||||
|
||||
// If we have any generic arguments to print, we do that
|
||||
// on top of the same path, but without its own generics.
|
||||
_ => if !generics.params.is_empty() && substs.len() >= generics.count() {
|
||||
let args = self.generic_args_to_print(generics, substs);
|
||||
return self.path_generic_args(
|
||||
|cx| cx.print_def_path(def_id, parent_substs),
|
||||
args,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(eddyb) try to move this into the parent's printing
|
||||
// logic, instead of doing it when printing the child.
|
||||
trait_qualify_parent =
|
||||
generics.has_self &&
|
||||
generics.parent == Some(parent_def_id) &&
|
||||
parent_substs.len() == generics.parent_count &&
|
||||
self.tcx().generics_of(parent_def_id).parent_count == 0;
|
||||
}
|
||||
|
||||
self.path_append(
|
||||
|cx: Self| if trait_qualify_parent {
|
||||
let trait_ref = ty::TraitRef::new(
|
||||
parent_def_id,
|
||||
cx.tcx().intern_substs(parent_substs),
|
||||
);
|
||||
cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
|
||||
} else {
|
||||
cx.print_def_path(parent_def_id, parent_substs)
|
||||
},
|
||||
&key.disambiguated_data,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generic_args_to_print(
|
||||
&self,
|
||||
generics: &'tcx ty::Generics,
|
||||
substs: &'tcx [Kind<'tcx>],
|
||||
) -> &'tcx [Kind<'tcx>] {
|
||||
let mut own_params = generics.parent_count..generics.count();
|
||||
|
||||
// Don't print args for `Self` parameters (of traits).
|
||||
if generics.has_self && own_params.start == 0 {
|
||||
own_params.start = 1;
|
||||
}
|
||||
|
||||
// Don't print args that are the defaults of their respective parameters.
|
||||
own_params.end -= generics.params.iter().rev().take_while(|param| {
|
||||
match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => false,
|
||||
ty::GenericParamDefKind::Type { has_default, .. } => {
|
||||
has_default && substs[param.index as usize] == Kind::from(
|
||||
self.tcx().type_of(param.def_id).subst(self.tcx(), substs)
|
||||
)
|
||||
}
|
||||
ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
|
||||
}
|
||||
}).count();
|
||||
|
||||
&substs[own_params]
|
||||
}
|
||||
|
||||
fn default_print_impl_path(
|
||||
self,
|
||||
impl_def_id: DefId,
|
||||
_substs: &'tcx [Kind<'tcx>],
|
||||
self_ty: Ty<'tcx>,
|
||||
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
|
||||
) -> Result<Self::Path, Self::Error> {
|
||||
debug!("default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}",
|
||||
impl_def_id, self_ty, impl_trait_ref);
|
||||
|
||||
let key = self.tcx().def_key(impl_def_id);
|
||||
let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
|
||||
|
||||
// Decide whether to print the parent path for the impl.
|
||||
// Logically, since impls are global, it's never needed, but
|
||||
// users may find it useful. Currently, we omit the parent if
|
||||
// the impl is either in the same module as the self-type or
|
||||
// as the trait.
|
||||
let in_self_mod = match characteristic_def_id_of_type(self_ty) {
|
||||
None => false,
|
||||
Some(ty_def_id) => self.tcx().parent(ty_def_id) == Some(parent_def_id),
|
||||
};
|
||||
let in_trait_mod = match impl_trait_ref {
|
||||
None => false,
|
||||
Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == Some(parent_def_id),
|
||||
};
|
||||
|
||||
if !in_self_mod && !in_trait_mod {
|
||||
// If the impl is not co-located with either self-type or
|
||||
// trait-type, then fallback to a format that identifies
|
||||
// the module more clearly.
|
||||
self.path_append_impl(
|
||||
|cx| cx.print_def_path(parent_def_id, &[]),
|
||||
&key.disambiguated_data,
|
||||
self_ty,
|
||||
impl_trait_ref,
|
||||
)
|
||||
} else {
|
||||
// Otherwise, try to give a good form that would be valid language
|
||||
// syntax. Preferably using associated item notation.
|
||||
self.path_qualified(self_ty, impl_trait_ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// As a heuristic, when we see an impl, if we see that the
|
||||
/// 'self type' is a type defined in the same module as the impl,
|
||||
/// we can omit including the path to the impl itself. This
|
||||
/// function tries to find a "characteristic `DefId`" for a
|
||||
/// type. It's just a heuristic so it makes some questionable
|
||||
/// decisions and we may want to adjust it later.
|
||||
pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
|
||||
match ty.sty {
|
||||
ty::Adt(adt_def, _) => Some(adt_def.did),
|
||||
|
||||
ty::Dynamic(data, ..) => data.principal_def_id(),
|
||||
|
||||
ty::Array(subty, _) |
|
||||
ty::Slice(subty) => characteristic_def_id_of_type(subty),
|
||||
|
||||
ty::RawPtr(mt) => characteristic_def_id_of_type(mt.ty),
|
||||
|
||||
ty::Ref(_, ty, _) => characteristic_def_id_of_type(ty),
|
||||
|
||||
ty::Tuple(ref tys) => tys.iter()
|
||||
.filter_map(|ty| characteristic_def_id_of_type(ty))
|
||||
.next(),
|
||||
|
||||
ty::FnDef(def_id, _) |
|
||||
ty::Closure(def_id, _) |
|
||||
ty::Generator(def_id, _, _) |
|
||||
ty::Foreign(def_id) => Some(def_id),
|
||||
|
||||
ty::Bool |
|
||||
ty::Char |
|
||||
ty::Int(_) |
|
||||
ty::Uint(_) |
|
||||
ty::Str |
|
||||
ty::FnPtr(_) |
|
||||
ty::Projection(_) |
|
||||
ty::Placeholder(..) |
|
||||
ty::UnnormalizedProjection(..) |
|
||||
ty::Param(_) |
|
||||
ty::Opaque(..) |
|
||||
ty::Infer(_) |
|
||||
ty::Bound(..) |
|
||||
ty::Error |
|
||||
ty::GeneratorWitness(..) |
|
||||
ty::Never |
|
||||
ty::Float(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> for ty::RegionKind {
|
||||
type Output = P::Region;
|
||||
type Error = P::Error;
|
||||
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
|
||||
cx.print_region(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> for ty::Region<'_> {
|
||||
type Output = P::Region;
|
||||
type Error = P::Error;
|
||||
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
|
||||
cx.print_region(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P> for Ty<'tcx> {
|
||||
type Output = P::Type;
|
||||
type Error = P::Error;
|
||||
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
|
||||
cx.print_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx: 'tcx, 'tcx, P: Printer<'gcx, 'tcx>> Print<'gcx, 'tcx, P>
|
||||
for &'tcx ty::List<ty::ExistentialPredicate<'tcx>>
|
||||
{
|
||||
type Output = P::DynExistential;
|
||||
type Error = P::Error;
|
||||
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
|
||||
cx.print_dyn_existential(self)
|
||||
}
|
||||
}
|
1621
src/librustc/ty/print/pretty.rs
Normal file
1621
src/librustc/ty/print/pretty.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -71,7 +71,7 @@ pub(super) trait QueryDescription<'tcx>: QueryAccessors<'tcx> {
|
|||
impl<'tcx, M: QueryAccessors<'tcx, Key=DefId>> QueryDescription<'tcx> for M {
|
||||
default fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> {
|
||||
if !tcx.sess.verbose() {
|
||||
format!("processing `{}`", tcx.item_path_str(def_id)).into()
|
||||
format!("processing `{}`", tcx.def_path_str(def_id)).into()
|
||||
} else {
|
||||
let name = unsafe { ::std::intrinsics::type_name::<M>() };
|
||||
format!("processing {:?} with query `{}`", def_id, name).into()
|
||||
|
@ -301,7 +301,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::layout_raw<'tcx> {
|
|||
impl<'tcx> QueryDescription<'tcx> for queries::super_predicates_of<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> {
|
||||
format!("computing the supertraits of `{}`",
|
||||
tcx.item_path_str(def_id)).into()
|
||||
tcx.def_path_str(def_id)).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,7 +322,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::type_param_predicates<'tcx> {
|
|||
impl<'tcx> QueryDescription<'tcx> for queries::coherent_trait<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> {
|
||||
format!("coherence checking all impls of trait `{}`",
|
||||
tcx.item_path_str(def_id)).into()
|
||||
tcx.def_path_str(def_id)).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,7 +359,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::inferred_outlives_crate<'tcx> {
|
|||
impl<'tcx> QueryDescription<'tcx> for queries::mir_shims<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def: ty::InstanceDef<'tcx>) -> Cow<'static, str> {
|
||||
format!("generating MIR shim for `{}`",
|
||||
tcx.item_path_str(def.def_id())).into()
|
||||
tcx.def_path_str(def.def_id())).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -394,7 +394,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> {
|
|||
) -> Cow<'static, str> {
|
||||
format!(
|
||||
"const-evaluating + checking `{}`",
|
||||
tcx.item_path_str(key.value.instance.def.def_id()),
|
||||
tcx.def_path_str(key.value.instance.def.def_id()),
|
||||
).into()
|
||||
}
|
||||
|
||||
|
@ -415,7 +415,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::const_eval_raw<'tcx> {
|
|||
fn describe(tcx: TyCtxt<'_, '_, '_>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
|
||||
-> Cow<'static, str>
|
||||
{
|
||||
format!("const-evaluating `{}`", tcx.item_path_str(key.value.instance.def.def_id())).into()
|
||||
format!("const-evaluating `{}`", tcx.def_path_str(key.value.instance.def.def_id())).into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -513,7 +513,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::trait_of_item<'tcx> {
|
|||
impl<'tcx> QueryDescription<'tcx> for queries::const_is_rvalue_promotable_to_static<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> {
|
||||
format!("const checking if rvalue is promotable to static `{}`",
|
||||
tcx.item_path_str(def_id)).into()
|
||||
tcx.def_path_str(def_id)).into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -532,21 +532,21 @@ impl<'tcx> QueryDescription<'tcx> for queries::const_is_rvalue_promotable_to_sta
|
|||
impl<'tcx> QueryDescription<'tcx> for queries::rvalue_promotable_map<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> {
|
||||
format!("checking which parts of `{}` are promotable to static",
|
||||
tcx.item_path_str(def_id)).into()
|
||||
tcx.def_path_str(def_id)).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::is_mir_available<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> {
|
||||
format!("checking if item is mir available: `{}`",
|
||||
tcx.item_path_str(def_id)).into()
|
||||
tcx.def_path_str(def_id)).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::codegen_fulfill_obligation<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>,
|
||||
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Cow<'static, str> {
|
||||
format!("checking if `{}` fulfills its obligations", tcx.item_path_str(key.1.def_id()))
|
||||
format!("checking if `{}` fulfills its obligations", tcx.def_path_str(key.1.def_id()))
|
||||
.into()
|
||||
}
|
||||
|
||||
|
@ -565,19 +565,19 @@ impl<'tcx> QueryDescription<'tcx> for queries::codegen_fulfill_obligation<'tcx>
|
|||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::trait_impls_of<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> {
|
||||
format!("trait impls of `{}`", tcx.item_path_str(def_id)).into()
|
||||
format!("trait impls of `{}`", tcx.def_path_str(def_id)).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::is_object_safe<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> {
|
||||
format!("determine object safety of trait `{}`", tcx.item_path_str(def_id)).into()
|
||||
format!("determine object safety of trait `{}`", tcx.def_path_str(def_id)).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn_raw<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> {
|
||||
format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id)).into()
|
||||
format!("checking if item is const fn: `{}`", tcx.def_path_str(def_id)).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -883,7 +883,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> {
|
|||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::vtable_methods<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, key: ty::PolyTraitRef<'tcx> ) -> Cow<'static, str> {
|
||||
format!("finding all methods for trait {}", tcx.item_path_str(key.def_id())).into()
|
||||
format!("finding all methods for trait {}", tcx.def_path_str(key.def_id())).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -927,7 +927,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::optimized_mir<'tcx> {
|
|||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::substitute_normalize_and_test_predicates<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, key: (DefId, SubstsRef<'tcx>)) -> Cow<'static, str> {
|
||||
format!("testing substituted normalized predicates:`{}`", tcx.item_path_str(key.0)).into()
|
||||
format!("testing substituted normalized predicates:`{}`", tcx.def_path_str(key.0)).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -945,7 +945,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::target_features_whitelist<'tcx> {
|
|||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::instance_def_size_estimate<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, def: ty::InstanceDef<'tcx>) -> Cow<'static, str> {
|
||||
format!("estimating size for `{}`", tcx.item_path_str(def.def_id())).into()
|
||||
format!("estimating size for `{}`", tcx.def_path_str(def.def_id())).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
|
||||
use crate::dep_graph::{DepNodeIndex, DepNode, DepKind, SerializedDepNodeIndex};
|
||||
use crate::ty::tls;
|
||||
use crate::ty::{TyCtxt};
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use crate::ty::query::Query;
|
||||
use crate::ty::query::config::{QueryConfig, QueryDescription};
|
||||
use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo};
|
||||
use crate::ty::item_path;
|
||||
|
||||
use crate::util::common::{profq_msg, ProfileQueriesMsg, QueryMsg};
|
||||
|
||||
|
@ -299,7 +298,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
// sometimes cycles itself, leading to extra cycle errors.
|
||||
// (And cycle errors around impls tend to occur during the
|
||||
// collect/coherence phases anyhow.)
|
||||
item_path::with_forced_impl_filename_line(|| {
|
||||
ty::print::with_forced_impl_filename_line(|| {
|
||||
let span = fix_span(stack[1 % stack.len()].span, &stack[0].query);
|
||||
let mut err = struct_span_err!(self.sess,
|
||||
span,
|
||||
|
|
|
@ -351,10 +351,8 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
|||
where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
|
||||
{
|
||||
let tcx = relation.tcx();
|
||||
let a_sty = &a.sty;
|
||||
let b_sty = &b.sty;
|
||||
debug!("super_relate_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
|
||||
match (a_sty, b_sty) {
|
||||
debug!("super_relate_tys: a={:?} b={:?}", a, b);
|
||||
match (&a.sty, &b.sty) {
|
||||
(&ty::Infer(_), _) |
|
||||
(_, &ty::Infer(_)) =>
|
||||
{
|
||||
|
|
|
@ -3,17 +3,288 @@
|
|||
//! hand, though we've recently added some macros (e.g.,
|
||||
//! `BraceStructLiftImpl!`) to help with the tedium.
|
||||
|
||||
use crate::hir::def::Namespace;
|
||||
use crate::mir::ProjectionKind;
|
||||
use crate::mir::interpret::ConstValue;
|
||||
use crate::ty::{self, Lift, Ty, TyCtxt, ConstVid, InferConst};
|
||||
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use crate::ty::print::{FmtPrinter, Printer};
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
use smallvec::SmallVec;
|
||||
use crate::mir::interpret;
|
||||
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
|
||||
impl fmt::Debug for ty::GenericParamDef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let type_name = match self.kind {
|
||||
ty::GenericParamDefKind::Lifetime => "Lifetime",
|
||||
ty::GenericParamDefKind::Type {..} => "Type",
|
||||
ty::GenericParamDefKind::Const => "Const",
|
||||
};
|
||||
write!(f, "{}({}, {:?}, {})",
|
||||
type_name,
|
||||
self.name,
|
||||
self.def_id,
|
||||
self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::TraitDef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ty::tls::with(|tcx| {
|
||||
FmtPrinter::new(tcx, f, Namespace::TypeNS)
|
||||
.print_def_path(self.def_id, &[])?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::AdtDef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ty::tls::with(|tcx| {
|
||||
FmtPrinter::new(tcx, f, Namespace::TypeNS)
|
||||
.print_def_path(self.did, &[])?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::ClosureUpvar<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ClosureUpvar({:?},{:?})",
|
||||
self.def,
|
||||
self.ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::UpvarId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let name = ty::tls::with(|tcx| {
|
||||
tcx.hir().name_by_hir_id(self.var_path.hir_id)
|
||||
});
|
||||
write!(f, "UpvarId({:?};`{}`;{:?})",
|
||||
self.var_path.hir_id,
|
||||
name,
|
||||
self.closure_expr_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::UpvarBorrow<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "UpvarBorrow({:?}, {:?})",
|
||||
self.kind, self.region)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::ExistentialTraitRef<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::adjustment::Adjustment<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?} -> {}", self.kind, self.target)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::BoundRegion {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
|
||||
ty::BrFresh(n) => write!(f, "BrFresh({:?})", n),
|
||||
ty::BrNamed(did, name) => {
|
||||
write!(f, "BrNamed({:?}:{:?}, {})",
|
||||
did.krate, did.index, name)
|
||||
}
|
||||
ty::BrEnv => write!(f, "BrEnv"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::RegionKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ty::ReEarlyBound(ref data) => {
|
||||
write!(f, "ReEarlyBound({}, {})",
|
||||
data.index,
|
||||
data.name)
|
||||
}
|
||||
|
||||
ty::ReClosureBound(ref vid) => {
|
||||
write!(f, "ReClosureBound({:?})", vid)
|
||||
}
|
||||
|
||||
ty::ReLateBound(binder_id, ref bound_region) => {
|
||||
write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region)
|
||||
}
|
||||
|
||||
ty::ReFree(ref fr) => fr.fmt(f),
|
||||
|
||||
ty::ReScope(id) => write!(f, "ReScope({:?})", id),
|
||||
|
||||
ty::ReStatic => write!(f, "ReStatic"),
|
||||
|
||||
ty::ReVar(ref vid) => vid.fmt(f),
|
||||
|
||||
ty::RePlaceholder(placeholder) => {
|
||||
write!(f, "RePlaceholder({:?})", placeholder)
|
||||
}
|
||||
|
||||
ty::ReEmpty => write!(f, "ReEmpty"),
|
||||
|
||||
ty::ReErased => write!(f, "ReErased"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::FreeRegion {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ReFree({:?}, {:?})", self.scope, self.bound_region)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::Variance {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match *self {
|
||||
ty::Covariant => "+",
|
||||
ty::Contravariant => "-",
|
||||
ty::Invariant => "o",
|
||||
ty::Bivariant => "*",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::FnSig<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "({:?}; c_variadic: {})->{:?}",
|
||||
self.inputs(), self.c_variadic, self.output())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::TyVid {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "_#{}t", self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "_#{}c", self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::IntVid {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "_#{}i", self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::FloatVid {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "_#{}f", self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::RegionVid {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "'_#{}r", self.index())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::InferTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ty::TyVar(ref v) => v.fmt(f),
|
||||
ty::IntVar(ref v) => v.fmt(f),
|
||||
ty::FloatVar(ref v) => v.fmt(f),
|
||||
ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
|
||||
ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
|
||||
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::IntVarValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ty::IntType(ref v) => v.fmt(f),
|
||||
ty::UintType(ref v) => v.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::FloatVarValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::TraitRef<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// FIXME(#59188) this is used across the compiler to print
|
||||
// a `TraitRef` qualified (with the Self type explicit),
|
||||
// instead of having a different way to make that choice.
|
||||
write!(f, "<{} as {}>", self.self_ty(), self)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Ty<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::ParamTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}/#{}", self.name, self.idx)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::ParamConst {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}/#{}", self.name, self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::TraitPredicate<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "TraitPredicate({:?})", self.trait_ref)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::ProjectionPredicate<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::Predicate<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ty::Predicate::Trait(ref a) => a.fmt(f),
|
||||
ty::Predicate::Subtype(ref pair) => pair.fmt(f),
|
||||
ty::Predicate::RegionOutlives(ref pair) => pair.fmt(f),
|
||||
ty::Predicate::TypeOutlives(ref pair) => pair.fmt(f),
|
||||
ty::Predicate::Projection(ref pair) => pair.fmt(f),
|
||||
ty::Predicate::WellFormed(ty) => write!(f, "WellFormed({:?})", ty),
|
||||
ty::Predicate::ObjectSafe(trait_def_id) => {
|
||||
write!(f, "ObjectSafe({:?})", trait_def_id)
|
||||
}
|
||||
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
|
||||
write!(f, "ClosureKind({:?}, {:?}, {:?})",
|
||||
closure_def_id, closure_substs, kind)
|
||||
}
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Atomic structs
|
||||
//
|
||||
|
@ -48,10 +319,14 @@ CloneTypeFoldableAndLiftImpls! {
|
|||
// really meant to be folded. In general, we can only fold a fully
|
||||
// general `Region`.
|
||||
crate::ty::BoundRegion,
|
||||
crate::ty::Placeholder<crate::ty::BoundRegion>,
|
||||
crate::ty::ClosureKind,
|
||||
crate::ty::FreeRegion,
|
||||
crate::ty::InferTy,
|
||||
crate::ty::IntVarValue,
|
||||
crate::ty::ParamConst,
|
||||
crate::ty::ParamTy,
|
||||
crate::ty::RegionVid,
|
||||
crate::ty::UniverseIndex,
|
||||
crate::ty::Variance,
|
||||
::syntax_pos::Span,
|
||||
|
@ -60,6 +335,7 @@ CloneTypeFoldableAndLiftImpls! {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// Lift implementations
|
||||
|
||||
// FIXME(eddyb) replace all the uses of `Option::map` with `?`.
|
||||
impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
|
||||
type Lifted = (A::Lifted, B::Lifted);
|
||||
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
|
@ -156,6 +432,23 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> {
|
||||
type Lifted = ty::ExistentialPredicate<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
match self {
|
||||
ty::ExistentialPredicate::Trait(x) => {
|
||||
tcx.lift(x).map(ty::ExistentialPredicate::Trait)
|
||||
}
|
||||
ty::ExistentialPredicate::Projection(x) => {
|
||||
tcx.lift(x).map(ty::ExistentialPredicate::Projection)
|
||||
}
|
||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||
Some(ty::ExistentialPredicate::AutoTrait(*def_id))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
|
||||
type Lifted = ty::TraitPredicate<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
|
||||
|
@ -480,6 +773,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
BraceStructLiftImpl! {
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::TypeAndMut<'a> {
|
||||
type Lifted = ty::TypeAndMut<'tcx>;
|
||||
ty, mutbl
|
||||
}
|
||||
}
|
||||
|
||||
BraceStructLiftImpl! {
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::Instance<'a> {
|
||||
type Lifted = ty::Instance<'tcx>;
|
||||
|
|
|
@ -9,7 +9,7 @@ use polonius_engine::Atom;
|
|||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_macros::HashStable;
|
||||
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef, Kind, UnpackedKind};
|
||||
use crate::ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{self, AdtDef, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv};
|
||||
use crate::util::captures::Captures;
|
||||
use crate::mir::interpret::{Scalar, Pointer};
|
||||
|
@ -84,7 +84,7 @@ impl BoundRegion {
|
|||
|
||||
/// N.B., if you change this, you'll probably want to change the corresponding
|
||||
/// AST structure in `libsyntax/ast.rs` as well.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug,
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
|
||||
RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub enum TyKind<'tcx> {
|
||||
/// The primitive boolean type. Written as `bool`.
|
||||
|
@ -383,9 +383,10 @@ impl<'tcx> ClosureSubsts<'tcx> {
|
|||
///
|
||||
/// If you have an inference context, use `infcx.closure_sig()`.
|
||||
pub fn closure_sig(self, def_id: DefId, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> ty::PolyFnSig<'tcx> {
|
||||
match self.closure_sig_ty(def_id, tcx).sty {
|
||||
let ty = self.closure_sig_ty(def_id, tcx);
|
||||
match ty.sty {
|
||||
ty::FnPtr(sig) => sig,
|
||||
ref t => bug!("closure_sig_ty is not a fn-ptr: {:?}", t),
|
||||
_ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1590,7 +1591,7 @@ impl RegionKind {
|
|||
pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_, '_, '_>) -> DefId {
|
||||
match self {
|
||||
ty::ReEarlyBound(br) => {
|
||||
tcx.parent_def_id(br.def_id).unwrap()
|
||||
tcx.parent(br.def_id).unwrap()
|
||||
}
|
||||
ty::ReFree(fr) => fr.scope,
|
||||
_ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
|
||||
|
@ -1910,7 +1911,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
|||
|
||||
pub fn is_machine(&self) -> bool {
|
||||
match self.sty {
|
||||
Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => false,
|
||||
Int(..) | Uint(..) | Float(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ use smallvec::SmallVec;
|
|||
use rustc_macros::HashStable;
|
||||
|
||||
use core::intrinsics;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::cmp::Ordering;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::num::NonZeroUsize;
|
||||
|
@ -70,6 +70,16 @@ impl<'tcx> UnpackedKind<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Kind<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.unpack() {
|
||||
UnpackedKind::Lifetime(lt) => lt.fmt(f),
|
||||
UnpackedKind::Type(ty) => ty.fmt(f),
|
||||
UnpackedKind::Const(ct) => ct.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Ord for Kind<'tcx> {
|
||||
fn cmp(&self, other: &Kind<'_>) -> Ordering {
|
||||
self.unpack().cmp(&other.unpack())
|
||||
|
@ -115,34 +125,14 @@ impl<'tcx> Kind<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for Kind<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.unpack() {
|
||||
UnpackedKind::Lifetime(lt) => write!(f, "{:?}", lt),
|
||||
UnpackedKind::Type(ty) => write!(f, "{:?}", ty),
|
||||
UnpackedKind::Const(ct) => write!(f, "{:?}", ct),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for Kind<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.unpack() {
|
||||
UnpackedKind::Lifetime(lt) => write!(f, "{}", lt),
|
||||
UnpackedKind::Type(ty) => write!(f, "{}", ty),
|
||||
UnpackedKind::Const(ct) => write!(f, "{}", ct),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for Kind<'a> {
|
||||
type Lifted = Kind<'tcx>;
|
||||
|
||||
fn lift_to_tcx<'cx, 'gcx>(&self, tcx: TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
match self.unpack() {
|
||||
UnpackedKind::Lifetime(lt) => lt.lift_to_tcx(tcx).map(|lt| lt.into()),
|
||||
UnpackedKind::Type(ty) => ty.lift_to_tcx(tcx).map(|ty| ty.into()),
|
||||
UnpackedKind::Const(ct) => ct.lift_to_tcx(tcx).map(|ct| ct.into()),
|
||||
UnpackedKind::Lifetime(lt) => tcx.lift(<).map(|lt| lt.into()),
|
||||
UnpackedKind::Type(ty) => tcx.lift(&ty).map(|ty| ty.into()),
|
||||
UnpackedKind::Const(ct) => tcx.lift(&ct).map(|ct| ct.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::hir::{self, Node};
|
|||
use crate::mir::interpret::{sign_extend, truncate};
|
||||
use crate::ich::NodeIdHashingMode;
|
||||
use crate::traits::{self, ObligationCause};
|
||||
use crate::ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable};
|
||||
use crate::ty::{self, DefIdTree, Ty, TyCtxt, GenericParamDefKind, TypeFoldable};
|
||||
use crate::ty::subst::{Subst, InternalSubsts, SubstsRef, UnpackedKind};
|
||||
use crate::ty::query::TyCtxtAt;
|
||||
use crate::ty::TyKind::*;
|
||||
|
@ -563,7 +563,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
|
||||
let mut def_id = def_id;
|
||||
while self.is_closure(def_id) {
|
||||
def_id = self.parent_def_id(def_id).unwrap_or_else(|| {
|
||||
def_id = self.parent(def_id).unwrap_or_else(|| {
|
||||
bug!("closure {:?} has no parent", def_id);
|
||||
});
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,4 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fs;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::mem;
|
||||
|
@ -20,12 +21,12 @@ pub enum ProfileCategory {
|
|||
Other,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum ProfilerEvent {
|
||||
QueryStart { query_name: &'static str, category: ProfileCategory, time: u64 },
|
||||
QueryEnd { query_name: &'static str, category: ProfileCategory, time: u64 },
|
||||
GenericActivityStart { category: ProfileCategory, time: u64 },
|
||||
GenericActivityEnd { category: ProfileCategory, time: u64 },
|
||||
GenericActivityStart { category: ProfileCategory, label: Cow<'static, str>, time: u64 },
|
||||
GenericActivityEnd { category: ProfileCategory, label: Cow<'static, str>, time: u64 },
|
||||
IncrementalLoadResultStart { query_name: &'static str, time: u64 },
|
||||
IncrementalLoadResultEnd { query_name: &'static str, time: u64 },
|
||||
QueryCacheHit { query_name: &'static str, category: ProfileCategory, time: u64 },
|
||||
|
@ -75,17 +76,27 @@ impl SelfProfiler {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn start_activity(&mut self, category: ProfileCategory) {
|
||||
pub fn start_activity(
|
||||
&mut self,
|
||||
category: ProfileCategory,
|
||||
label: impl Into<Cow<'static, str>>,
|
||||
) {
|
||||
self.record(ProfilerEvent::GenericActivityStart {
|
||||
category,
|
||||
label: label.into(),
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn end_activity(&mut self, category: ProfileCategory) {
|
||||
pub fn end_activity(
|
||||
&mut self,
|
||||
category: ProfileCategory,
|
||||
label: impl Into<Cow<'static, str>>,
|
||||
) {
|
||||
self.record(ProfilerEvent::GenericActivityEnd {
|
||||
category,
|
||||
label: label.into(),
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
}
|
||||
|
@ -273,11 +284,12 @@ impl SelfProfiler {
|
|||
nanos,
|
||||
thread_id,
|
||||
).unwrap(),
|
||||
GenericActivityStart { category, time: _ } =>
|
||||
GenericActivityStart { category, label, time: _ } =>
|
||||
write!(file,
|
||||
"{{
|
||||
\"GenericActivityStart\": {{\
|
||||
\"category\": \"{:?}\",\
|
||||
\"label\": \"{}\",\
|
||||
\"time\": {{\
|
||||
\"secs\": {},\
|
||||
\"nanos\": {}\
|
||||
|
@ -286,15 +298,17 @@ impl SelfProfiler {
|
|||
}}\
|
||||
}}",
|
||||
category,
|
||||
label,
|
||||
secs,
|
||||
nanos,
|
||||
thread_id,
|
||||
).unwrap(),
|
||||
GenericActivityEnd { category, time: _ } =>
|
||||
GenericActivityEnd { category, label, time: _ } =>
|
||||
write!(file,
|
||||
"{{\
|
||||
\"GenericActivityEnd\": {{\
|
||||
\"category\": \"{:?}\",\
|
||||
\"label\": \"{}\",\
|
||||
\"time\": {{\
|
||||
\"secs\": {},\
|
||||
\"nanos\": {}\
|
||||
|
@ -303,6 +317,7 @@ impl SelfProfiler {
|
|||
}}\
|
||||
}}",
|
||||
category,
|
||||
label,
|
||||
secs,
|
||||
nanos,
|
||||
thread_id,
|
||||
|
@ -418,7 +433,7 @@ impl SelfProfiler {
|
|||
secs,
|
||||
nanos,
|
||||
thread_id,
|
||||
).unwrap()
|
||||
).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,268 +0,0 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
|
||||
const OUTPUT_WIDTH_IN_PX: u64 = 1000;
|
||||
const TIME_LINE_HEIGHT_IN_PX: u64 = 20;
|
||||
const TIME_LINE_HEIGHT_STRIDE_IN_PX: usize = 30;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Timing {
|
||||
start: Instant,
|
||||
end: Instant,
|
||||
work_package_kind: WorkPackageKind,
|
||||
name: String,
|
||||
events: Vec<(String, Instant)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
|
||||
pub struct TimelineId(pub usize);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct PerThread {
|
||||
timings: Vec<Timing>,
|
||||
open_work_package: Option<(Instant, WorkPackageKind, String)>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TimeGraph {
|
||||
data: Arc<Mutex<FxHashMap<TimelineId, PerThread>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct WorkPackageKind(pub &'static [&'static str]);
|
||||
|
||||
pub struct Timeline {
|
||||
token: Option<RaiiToken>,
|
||||
}
|
||||
|
||||
struct RaiiToken {
|
||||
graph: TimeGraph,
|
||||
timeline: TimelineId,
|
||||
events: Vec<(String, Instant)>,
|
||||
// The token must not be Send:
|
||||
_marker: PhantomData<*const ()>
|
||||
}
|
||||
|
||||
|
||||
impl Drop for RaiiToken {
|
||||
fn drop(&mut self) {
|
||||
self.graph.end(self.timeline, mem::replace(&mut self.events, Vec::new()));
|
||||
}
|
||||
}
|
||||
|
||||
impl TimeGraph {
|
||||
pub fn new() -> TimeGraph {
|
||||
TimeGraph {
|
||||
data: Arc::new(Mutex::new(FxHashMap::default()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&self,
|
||||
timeline: TimelineId,
|
||||
work_package_kind: WorkPackageKind,
|
||||
name: &str) -> Timeline {
|
||||
{
|
||||
let mut table = self.data.lock().unwrap();
|
||||
|
||||
let data = table.entry(timeline).or_insert(PerThread {
|
||||
timings: Vec::new(),
|
||||
open_work_package: None,
|
||||
});
|
||||
|
||||
assert!(data.open_work_package.is_none());
|
||||
data.open_work_package = Some((Instant::now(), work_package_kind, name.to_string()));
|
||||
}
|
||||
|
||||
Timeline {
|
||||
token: Some(RaiiToken {
|
||||
graph: self.clone(),
|
||||
timeline,
|
||||
events: Vec::new(),
|
||||
_marker: PhantomData,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn end(&self, timeline: TimelineId, events: Vec<(String, Instant)>) {
|
||||
let end = Instant::now();
|
||||
|
||||
let mut table = self.data.lock().unwrap();
|
||||
let data = table.get_mut(&timeline).unwrap();
|
||||
|
||||
if let Some((start, work_package_kind, name)) = data.open_work_package.take() {
|
||||
data.timings.push(Timing {
|
||||
start,
|
||||
end,
|
||||
work_package_kind,
|
||||
name,
|
||||
events,
|
||||
});
|
||||
} else {
|
||||
bug!("end timing without start?")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump(&self, output_filename: &str) {
|
||||
let table = self.data.lock().unwrap();
|
||||
|
||||
for data in table.values() {
|
||||
assert!(data.open_work_package.is_none());
|
||||
}
|
||||
|
||||
let mut threads: Vec<PerThread> =
|
||||
table.values().map(|data| data.clone()).collect();
|
||||
|
||||
threads.sort_by_key(|timeline| timeline.timings[0].start);
|
||||
|
||||
let earliest_instant = threads[0].timings[0].start;
|
||||
let latest_instant = threads.iter()
|
||||
.map(|timeline| timeline.timings
|
||||
.last()
|
||||
.unwrap()
|
||||
.end)
|
||||
.max()
|
||||
.unwrap();
|
||||
let max_distance = distance(earliest_instant, latest_instant);
|
||||
|
||||
let mut file = File::create(format!("{}.html", output_filename)).unwrap();
|
||||
|
||||
writeln!(file, "
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
#threads a {{
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
}}
|
||||
#threads {{
|
||||
height: {total_height}px;
|
||||
width: {width}px;
|
||||
}}
|
||||
|
||||
.timeline {{
|
||||
display: none;
|
||||
width: {width}px;
|
||||
position: relative;
|
||||
}}
|
||||
|
||||
.timeline:target {{
|
||||
display: block;
|
||||
}}
|
||||
|
||||
.event {{
|
||||
position: absolute;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id='threads'>
|
||||
",
|
||||
total_height = threads.len() * TIME_LINE_HEIGHT_STRIDE_IN_PX,
|
||||
width = OUTPUT_WIDTH_IN_PX,
|
||||
).unwrap();
|
||||
|
||||
let mut color = 0;
|
||||
for (line_index, thread) in threads.iter().enumerate() {
|
||||
let line_top = line_index * TIME_LINE_HEIGHT_STRIDE_IN_PX;
|
||||
|
||||
for span in &thread.timings {
|
||||
let start = distance(earliest_instant, span.start);
|
||||
let end = distance(earliest_instant, span.end);
|
||||
|
||||
let start = normalize(start, max_distance, OUTPUT_WIDTH_IN_PX);
|
||||
let end = normalize(end, max_distance, OUTPUT_WIDTH_IN_PX);
|
||||
|
||||
let colors = span.work_package_kind.0;
|
||||
|
||||
writeln!(file, "<a href='#timing{}'
|
||||
style='top:{}px; \
|
||||
left:{}px; \
|
||||
width:{}px; \
|
||||
height:{}px; \
|
||||
background:{};'>{}</a>",
|
||||
color,
|
||||
line_top,
|
||||
start,
|
||||
end - start,
|
||||
TIME_LINE_HEIGHT_IN_PX,
|
||||
colors[color % colors.len()],
|
||||
span.name,
|
||||
).unwrap();
|
||||
|
||||
color += 1;
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(file, "
|
||||
</div>
|
||||
").unwrap();
|
||||
|
||||
let mut idx = 0;
|
||||
for thread in threads.iter() {
|
||||
for timing in &thread.timings {
|
||||
let colors = timing.work_package_kind.0;
|
||||
let height = TIME_LINE_HEIGHT_STRIDE_IN_PX * timing.events.len();
|
||||
writeln!(file, "<div class='timeline'
|
||||
id='timing{}'
|
||||
style='background:{};height:{}px;'>",
|
||||
idx,
|
||||
colors[idx % colors.len()],
|
||||
height).unwrap();
|
||||
idx += 1;
|
||||
let max = distance(timing.start, timing.end);
|
||||
for (i, &(ref event, time)) in timing.events.iter().enumerate() {
|
||||
let i = i as u64;
|
||||
let time = distance(timing.start, time);
|
||||
let at = normalize(time, max, OUTPUT_WIDTH_IN_PX);
|
||||
writeln!(file, "<span class='event'
|
||||
style='left:{}px;\
|
||||
top:{}px;'>{}</span>",
|
||||
at,
|
||||
TIME_LINE_HEIGHT_IN_PX * i,
|
||||
event).unwrap();
|
||||
}
|
||||
writeln!(file, "</div>").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(file, "
|
||||
</body>
|
||||
</html>
|
||||
").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl Timeline {
|
||||
pub fn noop() -> Timeline {
|
||||
Timeline { token: None }
|
||||
}
|
||||
|
||||
/// Record an event which happened at this moment on this timeline.
|
||||
///
|
||||
/// Events are displayed in the eventual HTML output where you can click on
|
||||
/// a particular timeline and it'll expand to all of the events that
|
||||
/// happened on that timeline. This can then be used to drill into a
|
||||
/// particular timeline and see what events are happening and taking the
|
||||
/// most time.
|
||||
pub fn record(&mut self, name: &str) {
|
||||
if let Some(ref mut token) = self.token {
|
||||
token.events.push((name.to_string(), Instant::now()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn distance(zero: Instant, x: Instant) -> u64 {
|
||||
|
||||
let duration = x.duration_since(zero);
|
||||
(duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64) // / div
|
||||
}
|
||||
|
||||
fn normalize(distance: u64, max: u64, max_pixels: u64) -> u64 {
|
||||
(max_pixels * distance) / max
|
||||
}
|
||||
|
|
@ -1406,7 +1406,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
out.push('(');
|
||||
self.append_loan_path_to_string(&lp_base, out);
|
||||
out.push_str(DOWNCAST_PRINTED_OPERATOR);
|
||||
out.push_str(&self.tcx.item_path_str(variant_def_id));
|
||||
out.push_str(&self.tcx.def_path_str(variant_def_id));
|
||||
out.push(')');
|
||||
}
|
||||
|
||||
|
@ -1443,7 +1443,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
out.push('(');
|
||||
self.append_autoderefd_loan_path_to_string(&lp_base, out);
|
||||
out.push_str(DOWNCAST_PRINTED_OPERATOR);
|
||||
out.push_str(&self.tcx.item_path_str(variant_def_id));
|
||||
out.push_str(&self.tcx.def_path_str(variant_def_id));
|
||||
out.push(')');
|
||||
}
|
||||
|
||||
|
@ -1523,7 +1523,7 @@ impl<'tcx> fmt::Debug for LoanPath<'tcx> {
|
|||
|
||||
LpDowncast(ref lp, variant_def_id) => {
|
||||
let variant_str = if variant_def_id.is_local() {
|
||||
ty::tls::with(|tcx| tcx.item_path_str(variant_def_id))
|
||||
ty::tls::with(|tcx| tcx.def_path_str(variant_def_id))
|
||||
} else {
|
||||
format!("{:?}", variant_def_id)
|
||||
};
|
||||
|
@ -1558,7 +1558,7 @@ impl<'tcx> fmt::Display for LoanPath<'tcx> {
|
|||
|
||||
LpDowncast(ref lp, variant_def_id) => {
|
||||
let variant_str = if variant_def_id.is_local() {
|
||||
ty::tls::with(|tcx| tcx.item_path_str(variant_def_id))
|
||||
ty::tls::with(|tcx| tcx.def_path_str(variant_def_id))
|
||||
} else {
|
||||
format!("{:?}", variant_def_id)
|
||||
};
|
||||
|
|
|
@ -3,7 +3,6 @@ use crate::back::write::{self, DiagnosticHandlers, with_llvm_pmb, save_temp_bitc
|
|||
to_llvm_opt_settings};
|
||||
use crate::llvm::archive_ro::ArchiveRO;
|
||||
use crate::llvm::{self, True, False};
|
||||
use crate::time_graph::Timeline;
|
||||
use crate::{ModuleLlvm, LlvmCodegenBackend};
|
||||
use rustc_codegen_ssa::back::symbol_export;
|
||||
use rustc_codegen_ssa::back::write::{ModuleConfig, CodegenContext, FatLTOInput};
|
||||
|
@ -16,6 +15,7 @@ use rustc::hir::def_id::LOCAL_CRATE;
|
|||
use rustc::middle::exported_symbols::SymbolExportLevel;
|
||||
use rustc::session::config::{self, Lto};
|
||||
use rustc::util::common::time_ext;
|
||||
use rustc::util::profiling::ProfileCategory;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
|
||||
|
||||
|
@ -37,7 +37,6 @@ pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
|
|||
}
|
||||
|
||||
fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
timeline: &mut Timeline,
|
||||
diag_handler: &Handler)
|
||||
-> Result<(Vec<CString>, Vec<(SerializedModule<ModuleBuffer>, CString)>), FatalError>
|
||||
{
|
||||
|
@ -68,7 +67,8 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
.iter()
|
||||
.filter_map(symbol_filter)
|
||||
.collect::<Vec<CString>>();
|
||||
timeline.record("whitelist");
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
|
||||
"generate_symbol_white_list_for_thinlto");
|
||||
info!("{} symbols to preserve in this crate", symbol_white_list.len());
|
||||
|
||||
// If we're performing LTO for the entire crate graph, then for each of our
|
||||
|
@ -97,6 +97,8 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
}
|
||||
|
||||
for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
|
||||
format!("load: {}", path.display()));
|
||||
let exported_symbols = cgcx.exported_symbols
|
||||
.as_ref().expect("needs exported symbols for LTO");
|
||||
symbol_white_list.extend(
|
||||
|
@ -121,7 +123,6 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
let bc = SerializedModule::FromRlib(bc);
|
||||
upstream_modules.push((bc, CString::new(id).unwrap()));
|
||||
}
|
||||
timeline.record(&format!("load: {}", path.display()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,12 +133,11 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
/// for further optimization.
|
||||
pub(crate) fn run_fat(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
modules: Vec<FatLTOInput<LlvmCodegenBackend>>,
|
||||
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
|
||||
timeline: &mut Timeline)
|
||||
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>)
|
||||
-> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError>
|
||||
{
|
||||
let diag_handler = cgcx.create_diag_handler();
|
||||
let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, timeline, &diag_handler)?;
|
||||
let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, &diag_handler)?;
|
||||
let symbol_white_list = symbol_white_list.iter()
|
||||
.map(|c| c.as_ptr())
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -148,7 +148,6 @@ pub(crate) fn run_fat(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
cached_modules,
|
||||
upstream_modules,
|
||||
&symbol_white_list,
|
||||
timeline,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -157,12 +156,11 @@ pub(crate) fn run_fat(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
/// can simply be copied over from the incr. comp. cache.
|
||||
pub(crate) fn run_thin(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
modules: Vec<(String, ThinBuffer)>,
|
||||
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
|
||||
timeline: &mut Timeline)
|
||||
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>)
|
||||
-> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError>
|
||||
{
|
||||
let diag_handler = cgcx.create_diag_handler();
|
||||
let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, timeline, &diag_handler)?;
|
||||
let (symbol_white_list, upstream_modules) = prepare_lto(cgcx, &diag_handler)?;
|
||||
let symbol_white_list = symbol_white_list.iter()
|
||||
.map(|c| c.as_ptr())
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -175,8 +173,7 @@ pub(crate) fn run_thin(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
modules,
|
||||
upstream_modules,
|
||||
cached_modules,
|
||||
&symbol_white_list,
|
||||
timeline)
|
||||
&symbol_white_list)
|
||||
}
|
||||
|
||||
pub(crate) fn prepare_thin(
|
||||
|
@ -192,8 +189,7 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
mut modules: Vec<FatLTOInput<LlvmCodegenBackend>>,
|
||||
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
|
||||
mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
|
||||
symbol_white_list: &[*const libc::c_char],
|
||||
timeline: &mut Timeline)
|
||||
symbol_white_list: &[*const libc::c_char])
|
||||
-> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError>
|
||||
{
|
||||
info!("going for a fat lto");
|
||||
|
@ -303,7 +299,6 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
write::llvm_err(&diag_handler, &msg)
|
||||
})
|
||||
})?;
|
||||
timeline.record(&format!("link {:?}", name));
|
||||
serialized_bitcode.push(bc_decoded);
|
||||
}
|
||||
drop(linker);
|
||||
|
@ -325,7 +320,6 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
}
|
||||
save_temp_bitcode(&cgcx, &module, "lto.after-nounwind");
|
||||
}
|
||||
timeline.record("passes");
|
||||
}
|
||||
|
||||
Ok(LtoModuleCodegen::Fat {
|
||||
|
@ -395,8 +389,7 @@ fn thin_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
modules: Vec<(String, ThinBuffer)>,
|
||||
serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
|
||||
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
|
||||
symbol_white_list: &[*const libc::c_char],
|
||||
timeline: &mut Timeline)
|
||||
symbol_white_list: &[*const libc::c_char])
|
||||
-> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError>
|
||||
{
|
||||
unsafe {
|
||||
|
@ -422,7 +415,6 @@ fn thin_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
});
|
||||
thin_buffers.push(buffer);
|
||||
module_names.push(cname);
|
||||
timeline.record(&name);
|
||||
}
|
||||
|
||||
// FIXME: All upstream crates are deserialized internally in the
|
||||
|
@ -475,7 +467,6 @@ fn thin_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
})?;
|
||||
|
||||
info!("thin LTO data created");
|
||||
timeline.record("data");
|
||||
|
||||
let import_map = if cgcx.incr_comp_session_dir.is_some() {
|
||||
ThinLTOImports::from_thin_lto_data(data)
|
||||
|
@ -486,7 +477,6 @@ fn thin_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
ThinLTOImports::default()
|
||||
};
|
||||
info!("thin LTO import map loaded");
|
||||
timeline.record("import-map-loaded");
|
||||
|
||||
let data = ThinData(data);
|
||||
|
||||
|
@ -691,7 +681,6 @@ impl Drop for ThinBuffer {
|
|||
pub unsafe fn optimize_thin_module(
|
||||
thin_module: &mut ThinModule<LlvmCodegenBackend>,
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
timeline: &mut Timeline
|
||||
) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
|
||||
let diag_handler = cgcx.create_diag_handler();
|
||||
let tm = (cgcx.tm_factory.0)().map_err(|e| {
|
||||
|
@ -738,9 +727,10 @@ pub unsafe fn optimize_thin_module(
|
|||
// Like with "fat" LTO, get some better optimizations if landing pads
|
||||
// are disabled by removing all landing pads.
|
||||
if cgcx.no_landing_pads {
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
|
||||
"LLVM_remove_landing_pads");
|
||||
llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
|
||||
save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind");
|
||||
timeline.record("nounwind");
|
||||
}
|
||||
|
||||
// Up next comes the per-module local analyses that we do for Thin LTO.
|
||||
|
@ -756,25 +746,21 @@ pub unsafe fn optimize_thin_module(
|
|||
return Err(write::llvm_err(&diag_handler, msg))
|
||||
}
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
|
||||
timeline.record("rename");
|
||||
if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) {
|
||||
let msg = "failed to prepare thin LTO module";
|
||||
return Err(write::llvm_err(&diag_handler, msg))
|
||||
}
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve");
|
||||
timeline.record("resolve");
|
||||
if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) {
|
||||
let msg = "failed to prepare thin LTO module";
|
||||
return Err(write::llvm_err(&diag_handler, msg))
|
||||
}
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize");
|
||||
timeline.record("internalize");
|
||||
if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) {
|
||||
let msg = "failed to prepare thin LTO module";
|
||||
return Err(write::llvm_err(&diag_handler, msg))
|
||||
}
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-import");
|
||||
timeline.record("import");
|
||||
|
||||
// Ok now this is a bit unfortunate. This is also something you won't
|
||||
// find upstream in LLVM's ThinLTO passes! This is a hack for now to
|
||||
|
@ -807,7 +793,6 @@ pub unsafe fn optimize_thin_module(
|
|||
// fixed in LLVM.
|
||||
llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-patch");
|
||||
timeline.record("patch");
|
||||
|
||||
// Alright now that we've done everything related to the ThinLTO
|
||||
// analysis it's time to run some optimizations! Here we use the same
|
||||
|
@ -818,7 +803,6 @@ pub unsafe fn optimize_thin_module(
|
|||
let config = cgcx.config(module.kind);
|
||||
run_pass_manager(cgcx, &module, config, true);
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
|
||||
timeline.record("thin-done");
|
||||
}
|
||||
Ok(module)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ use crate::back::bytecode::{self, RLIB_BYTECODE_EXTENSION};
|
|||
use crate::back::lto::ThinBuffer;
|
||||
use crate::base;
|
||||
use crate::consts;
|
||||
use crate::time_graph::Timeline;
|
||||
use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
|
||||
use crate::llvm_util;
|
||||
use crate::ModuleLlvm;
|
||||
|
@ -19,6 +18,7 @@ use rustc::session::Session;
|
|||
use rustc::ty::TyCtxt;
|
||||
use rustc_codegen_ssa::{ModuleCodegen, CompiledModule};
|
||||
use rustc::util::common::time_ext;
|
||||
use rustc::util::profiling::ProfileCategory;
|
||||
use rustc_fs_util::{path_to_c_string, link_or_copy};
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use errors::{Handler, FatalError};
|
||||
|
@ -305,8 +305,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
|
|||
pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
diag_handler: &Handler,
|
||||
module: &ModuleCodegen<ModuleLlvm>,
|
||||
config: &ModuleConfig,
|
||||
timeline: &mut Timeline)
|
||||
config: &ModuleConfig)
|
||||
-> Result<(), FatalError>
|
||||
{
|
||||
let llmod = module.module_llvm.llmod();
|
||||
|
@ -415,19 +414,24 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
diag_handler.abort_if_errors();
|
||||
|
||||
// Finally, run the actual optimization passes
|
||||
time_ext(config.time_passes,
|
||||
None,
|
||||
&format!("llvm function passes [{}]", module_name.unwrap()),
|
||||
|| {
|
||||
llvm::LLVMRustRunFunctionPassManager(fpm, llmod)
|
||||
});
|
||||
timeline.record("fpm");
|
||||
time_ext(config.time_passes,
|
||||
None,
|
||||
&format!("llvm module passes [{}]", module_name.unwrap()),
|
||||
|| {
|
||||
llvm::LLVMRunPassManager(mpm, llmod)
|
||||
});
|
||||
{
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_function_passes");
|
||||
time_ext(config.time_passes,
|
||||
None,
|
||||
&format!("llvm function passes [{}]", module_name.unwrap()),
|
||||
|| {
|
||||
llvm::LLVMRustRunFunctionPassManager(fpm, llmod)
|
||||
});
|
||||
}
|
||||
{
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_module_passes");
|
||||
time_ext(config.time_passes,
|
||||
None,
|
||||
&format!("llvm module passes [{}]", module_name.unwrap()),
|
||||
|| {
|
||||
llvm::LLVMRunPassManager(mpm, llmod)
|
||||
});
|
||||
}
|
||||
|
||||
// Deallocate managers that we're now done with
|
||||
llvm::LLVMDisposePassManager(fpm);
|
||||
|
@ -439,11 +443,10 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
diag_handler: &Handler,
|
||||
module: ModuleCodegen<ModuleLlvm>,
|
||||
config: &ModuleConfig,
|
||||
timeline: &mut Timeline)
|
||||
config: &ModuleConfig)
|
||||
-> Result<CompiledModule, FatalError>
|
||||
{
|
||||
timeline.record("codegen");
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "codegen");
|
||||
{
|
||||
let llmod = module.module_llvm.llmod();
|
||||
let llcx = &*module.module_llvm.llcx;
|
||||
|
@ -494,29 +497,30 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
|
||||
|
||||
if write_bc || config.emit_bc_compressed || config.embed_bitcode {
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_make_bitcode");
|
||||
let thin = ThinBuffer::new(llmod);
|
||||
let data = thin.data();
|
||||
timeline.record("make-bc");
|
||||
|
||||
if write_bc {
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_bitcode");
|
||||
if let Err(e) = fs::write(&bc_out, data) {
|
||||
diag_handler.err(&format!("failed to write bytecode: {}", e));
|
||||
}
|
||||
timeline.record("write-bc");
|
||||
}
|
||||
|
||||
if config.embed_bitcode {
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_embed_bitcode");
|
||||
embed_bitcode(cgcx, llcx, llmod, Some(data));
|
||||
timeline.record("embed-bc");
|
||||
}
|
||||
|
||||
if config.emit_bc_compressed {
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen,
|
||||
"LLVM_compress_bitcode");
|
||||
let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
|
||||
let data = bytecode::encode(&module.name, data);
|
||||
if let Err(e) = fs::write(&dst, data) {
|
||||
diag_handler.err(&format!("failed to write bytecode: {}", e));
|
||||
}
|
||||
timeline.record("compress-bc");
|
||||
}
|
||||
} else if config.embed_bitcode_marker {
|
||||
embed_bitcode(cgcx, llcx, llmod, None);
|
||||
|
@ -525,6 +529,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()),
|
||||
|| -> Result<(), FatalError> {
|
||||
if config.emit_ir {
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_ir");
|
||||
let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
|
||||
let out = path_to_c_string(&out);
|
||||
|
||||
|
@ -563,10 +568,10 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback);
|
||||
llvm::LLVMDisposePassManager(cpm);
|
||||
});
|
||||
timeline.record("ir");
|
||||
}
|
||||
|
||||
if config.emit_asm || asm_to_obj {
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_asm");
|
||||
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
|
||||
|
||||
// We can't use the same module for asm and binary output, because that triggers
|
||||
|
@ -581,19 +586,18 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
|||
write_output_file(diag_handler, tm, cpm, llmod, &path,
|
||||
llvm::FileType::AssemblyFile)
|
||||
})?;
|
||||
timeline.record("asm");
|
||||
}
|
||||
|
||||
if write_obj {
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_obj");
|
||||
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
||||
write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
|
||||
llvm::FileType::ObjectFile)
|
||||
})?;
|
||||
timeline.record("obj");
|
||||
} else if asm_to_obj {
|
||||
let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_asm_to_obj");
|
||||
let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
|
||||
run_assembler(cgcx, diag_handler, &assembly, &obj_out);
|
||||
timeline.record("asm_to_obj");
|
||||
|
||||
if !config.emit_asm && !cgcx.save_temps {
|
||||
drop(fs::remove_file(&assembly));
|
||||
|
|
|
@ -513,8 +513,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
|
||||
},
|
||||
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
|
||||
let sty = &arg_tys[0].sty;
|
||||
match float_type_width(sty) {
|
||||
match float_type_width(arg_tys[0]) {
|
||||
Some(_width) =>
|
||||
match name {
|
||||
"fadd_fast" => self.fadd_fast(args[0].immediate(), args[1].immediate()),
|
||||
|
@ -528,7 +527,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
span_invalid_monomorphization_error(
|
||||
tcx.sess, span,
|
||||
&format!("invalid monomorphization of `{}` intrinsic: \
|
||||
expected basic float type, found `{}`", name, sty));
|
||||
expected basic float type, found `{}`", name, arg_tys[0]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1473,8 +1472,8 @@ fn generic_simd_intrinsic(
|
|||
require!(false, "expected element type `{}` of second argument `{}` \
|
||||
to be a pointer to the element type `{}` of the first \
|
||||
argument `{}`, found `{}` != `*_ {}`",
|
||||
arg_tys[1].simd_type(tcx).sty, arg_tys[1], in_elem, in_ty,
|
||||
arg_tys[1].simd_type(tcx).sty, in_elem);
|
||||
arg_tys[1].simd_type(tcx), arg_tys[1], in_elem, in_ty,
|
||||
arg_tys[1].simd_type(tcx), in_elem);
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
|
@ -1488,7 +1487,7 @@ fn generic_simd_intrinsic(
|
|||
_ => {
|
||||
require!(false, "expected element type `{}` of third argument `{}` \
|
||||
to be a signed integer type",
|
||||
arg_tys[2].simd_type(tcx).sty, arg_tys[2]);
|
||||
arg_tys[2].simd_type(tcx), arg_tys[2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1573,8 +1572,8 @@ fn generic_simd_intrinsic(
|
|||
require!(false, "expected element type `{}` of second argument `{}` \
|
||||
to be a pointer to the element type `{}` of the first \
|
||||
argument `{}`, found `{}` != `*mut {}`",
|
||||
arg_tys[1].simd_type(tcx).sty, arg_tys[1], in_elem, in_ty,
|
||||
arg_tys[1].simd_type(tcx).sty, in_elem);
|
||||
arg_tys[1].simd_type(tcx), arg_tys[1], in_elem, in_ty,
|
||||
arg_tys[1].simd_type(tcx), in_elem);
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
|
@ -1588,7 +1587,7 @@ fn generic_simd_intrinsic(
|
|||
_ => {
|
||||
require!(false, "expected element type `{}` of third argument `{}` \
|
||||
to be a signed integer type",
|
||||
arg_tys[2].simd_type(tcx).sty, arg_tys[2]);
|
||||
arg_tys[2].simd_type(tcx), arg_tys[2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1904,7 +1903,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
|
|||
return_error!(
|
||||
"expected element type `{}` of vector type `{}` \
|
||||
to be a signed or unsigned integer type",
|
||||
arg_tys[0].simd_type(tcx).sty, arg_tys[0]
|
||||
arg_tys[0].simd_type(tcx), arg_tys[0]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
@ -1954,10 +1953,10 @@ fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, boo
|
|||
}
|
||||
}
|
||||
|
||||
// Returns the width of a float TypeVariant
|
||||
// Returns the width of a float Ty
|
||||
// Returns None if the type is not a float
|
||||
fn float_type_width<'tcx>(sty: &ty::TyKind<'tcx>) -> Option<u64> {
|
||||
match *sty {
|
||||
fn float_type_width(ty: Ty<'_>) -> Option<u64> {
|
||||
match ty.sty {
|
||||
ty::Float(t) => Some(t.bit_width() as u64),
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#![allow(unused_attributes)]
|
||||
#![feature(libc)]
|
||||
#![feature(nll)]
|
||||
#![feature(range_contains)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(concat_idents)]
|
||||
|
@ -53,7 +52,6 @@ use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModul
|
|||
use rustc_codegen_ssa::CompiledModule;
|
||||
use errors::{FatalError, Handler};
|
||||
use rustc::dep_graph::WorkProduct;
|
||||
use rustc::util::time_graph::Timeline;
|
||||
use syntax_pos::symbol::InternedString;
|
||||
use rustc::mir::mono::Stats;
|
||||
pub use llvm_util::target_features;
|
||||
|
@ -66,7 +64,6 @@ use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
|
|||
use rustc::session::Session;
|
||||
use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::util::time_graph;
|
||||
use rustc::util::profiling::ProfileCategory;
|
||||
use rustc::util::common::ErrorReported;
|
||||
use rustc_mir::monomorphize;
|
||||
|
@ -167,42 +164,37 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||
cgcx: &CodegenContext<Self>,
|
||||
modules: Vec<FatLTOInput<Self>>,
|
||||
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
|
||||
timeline: &mut Timeline
|
||||
) -> Result<LtoModuleCodegen<Self>, FatalError> {
|
||||
back::lto::run_fat(cgcx, modules, cached_modules, timeline)
|
||||
back::lto::run_fat(cgcx, modules, cached_modules)
|
||||
}
|
||||
fn run_thin_lto(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
modules: Vec<(String, Self::ThinBuffer)>,
|
||||
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
|
||||
timeline: &mut Timeline
|
||||
) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
|
||||
back::lto::run_thin(cgcx, modules, cached_modules, timeline)
|
||||
back::lto::run_thin(cgcx, modules, cached_modules)
|
||||
}
|
||||
unsafe fn optimize(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
diag_handler: &Handler,
|
||||
module: &ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
timeline: &mut Timeline
|
||||
) -> Result<(), FatalError> {
|
||||
back::write::optimize(cgcx, diag_handler, module, config, timeline)
|
||||
back::write::optimize(cgcx, diag_handler, module, config)
|
||||
}
|
||||
unsafe fn optimize_thin(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
thin: &mut ThinModule<Self>,
|
||||
timeline: &mut Timeline
|
||||
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
|
||||
back::lto::optimize_thin_module(thin, cgcx, timeline)
|
||||
back::lto::optimize_thin_module(thin, cgcx)
|
||||
}
|
||||
unsafe fn codegen(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
diag_handler: &Handler,
|
||||
module: ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
timeline: &mut Timeline
|
||||
) -> Result<CompiledModule, FatalError> {
|
||||
back::write::codegen(cgcx, diag_handler, module, config, timeline)
|
||||
back::write::codegen(cgcx, diag_handler, module, config)
|
||||
}
|
||||
fn prepare_thin(
|
||||
module: ModuleCodegen<Self::Module>
|
||||
|
@ -336,12 +328,12 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
|
||||
// Run the linker on any artifacts that resulted from the LLVM run.
|
||||
// This should produce either a finished executable or library.
|
||||
sess.profiler(|p| p.start_activity(ProfileCategory::Linking));
|
||||
sess.profiler(|p| p.start_activity(ProfileCategory::Linking, "link_crate"));
|
||||
time(sess, "linking", || {
|
||||
back::link::link_binary(sess, &codegen_results,
|
||||
outputs, &codegen_results.crate_name.as_str());
|
||||
});
|
||||
sess.profiler(|p| p.end_activity(ProfileCategory::Linking));
|
||||
sess.profiler(|p| p.end_activity(ProfileCategory::Linking, "link_crate"));
|
||||
|
||||
// Now that we won't touch anything in the incremental compilation directory
|
||||
// any more, we can finalize it (which involves renaming it)
|
||||
|
|
|
@ -382,20 +382,19 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
|
||||
if self.sess.target.target.options.is_like_osx {
|
||||
// Write a plain, newline-separated list of symbols
|
||||
let res = (|| -> io::Result<()> {
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
for sym in self.info.exports[&crate_type].iter() {
|
||||
debug!(" _{}", sym);
|
||||
writeln!(f, "_{}", sym)?;
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
};
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to write lib.def file: {}", e));
|
||||
}
|
||||
} else {
|
||||
// Write an LD version script
|
||||
let res = (|| -> io::Result<()> {
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
writeln!(f, "{{\n global:")?;
|
||||
for sym in self.info.exports[&crate_type].iter() {
|
||||
|
@ -403,8 +402,7 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
writeln!(f, " {};", sym)?;
|
||||
}
|
||||
writeln!(f, "\n local:\n *;\n}};")?;
|
||||
Ok(())
|
||||
})();
|
||||
};
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to write version script: {}", e));
|
||||
}
|
||||
|
@ -644,7 +642,7 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
tmpdir: &Path,
|
||||
crate_type: CrateType) {
|
||||
let path = tmpdir.join("lib.def");
|
||||
let res = (|| -> io::Result<()> {
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
|
||||
// Start off with the standard module name header and then go
|
||||
|
@ -655,8 +653,7 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
debug!(" _{}", symbol);
|
||||
writeln!(f, " {}", symbol)?;
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
};
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to write lib.def file: {}", e));
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ use super::write::CodegenContext;
|
|||
use crate::traits::*;
|
||||
use crate::ModuleCodegen;
|
||||
|
||||
use rustc::util::time_graph::Timeline;
|
||||
use rustc_errors::FatalError;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
@ -67,7 +66,6 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
|
|||
pub unsafe fn optimize(
|
||||
&mut self,
|
||||
cgcx: &CodegenContext<B>,
|
||||
timeline: &mut Timeline
|
||||
) -> Result<ModuleCodegen<B::Module>, FatalError> {
|
||||
match *self {
|
||||
LtoModuleCodegen::Fat { ref mut module, .. } => {
|
||||
|
@ -75,11 +73,10 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
|
|||
{
|
||||
let config = cgcx.config(module.kind);
|
||||
B::run_lto_pass_manager(cgcx, &module, config, false);
|
||||
timeline.record("fat-done");
|
||||
}
|
||||
Ok(module)
|
||||
}
|
||||
LtoModuleCodegen::Thin(ref mut thin) => B::optimize_thin(cgcx, thin, timeline),
|
||||
LtoModuleCodegen::Thin(ref mut thin) => B::optimize_thin(cgcx, thin),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue