Merge remote-tracking branch 'upstream/master' into asm-compile-tests

This commit is contained in:
Denys Zariaiev 2019-03-16 23:40:43 +01:00
commit 60f1644fd2
478 changed files with 5339 additions and 4185 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,5 @@
#![feature(box_syntax)]
#![feature(cell_update)]
#![feature(copied)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(dec2flt)]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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![(

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(_) => {

View file

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

View file

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

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

@ -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(_)) =>
{

View file

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

View file

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

View file

@ -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(&lt).map(|lt| lt.into()),
UnpackedKind::Type(ty) => tcx.lift(&ty).map(|ty| ty.into()),
UnpackedKind::Const(ct) => tcx.lift(&ct).map(|ct| ct.into()),
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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