diff --git a/.travis.yml b/.travis.yml index 7985b6c0e191f..7a8772d7abd63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,20 +12,27 @@ git: depth: 2 submodules: false +env: + global: + - CI_JOB_NAME=$TRAVIS_JOB_NAME + matrix: fast_finish: true include: # Images used in testing PR and try-build should be run first. - env: IMAGE=x86_64-gnu-llvm-6.0 RUST_BACKTRACE=1 + name: x86_64-gnu-llvm-6.0 if: type = pull_request OR branch = auto - env: IMAGE=dist-x86_64-linux DEPLOY=1 + name: dist-x86_64-linux if: branch = try OR branch = auto # "alternate" deployments, these are "nightlies" but have LLVM assertions # turned on, they're deployed to a different location primarily for # additional testing. - - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1 CI_JOB_NAME=dist-x86_64-linux-alt + - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1 + name: dist-x86_64-linux-alt if: branch = try OR branch = auto - env: > @@ -37,9 +44,9 @@ matrix: MACOSX_DEPLOYMENT_TARGET=10.7 NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 - CI_JOB_NAME=dist-x86_64-apple-alt os: osx osx_image: xcode9.3-moar + name: dist-x86_64-apple-alt if: branch = auto # macOS builders. These are placed near the beginning because they are very @@ -60,9 +67,9 @@ matrix: MACOSX_STD_DEPLOYMENT_TARGET=10.7 NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 - CI_JOB_NAME=x86_64-apple os: osx osx_image: xcode9.3-moar + name: x86_64-apple if: branch = auto - env: > @@ -74,9 +81,9 @@ matrix: MACOSX_STD_DEPLOYMENT_TARGET=10.7 NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 - CI_JOB_NAME=i686-apple os: osx osx_image: xcode9.3-moar + name: i686-apple if: branch = auto # OSX builders producing releases. These do not run the full test suite and @@ -95,9 +102,9 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 DIST_REQUIRE_ALL_TOOLS=1 - CI_JOB_NAME=dist-i686-apple os: osx osx_image: xcode9.3-moar + name: dist-i686-apple if: branch = auto - env: > @@ -110,81 +117,116 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 DIST_REQUIRE_ALL_TOOLS=1 - CI_JOB_NAME=dist-x86_64-apple os: osx osx_image: xcode9.3-moar + name: dist-x86_64-apple if: branch = auto # Linux builders, remaining docker images - env: IMAGE=arm-android + name: arm-android if: branch = auto - env: IMAGE=armhf-gnu + name: armhf-gnu if: branch = auto - env: IMAGE=dist-various-1 DEPLOY=1 + name: dist-various-1 if: branch = auto - env: IMAGE=dist-various-2 DEPLOY=1 + name: dist-various-2 if: branch = auto - env: IMAGE=dist-aarch64-linux DEPLOY=1 + name: dist-aarch64-linux if: branch = auto - env: IMAGE=dist-android DEPLOY=1 + name: dist-android if: branch = auto - env: IMAGE=dist-arm-linux DEPLOY=1 + name: dist-arm-linux if: branch = auto - env: IMAGE=dist-armhf-linux DEPLOY=1 + name: dist-armhf-linux if: branch = auto - env: IMAGE=dist-armv7-linux DEPLOY=1 + name: dist-armv7-linux if: branch = auto - env: IMAGE=dist-i586-gnu-i586-i686-musl DEPLOY=1 + name: dist-i586-gnu-i586-i686-musl if: branch = auto - env: IMAGE=dist-i686-freebsd DEPLOY=1 + name: dist-i686-freebsd if: branch = auto - env: IMAGE=dist-i686-linux DEPLOY=1 + name: dist-i686-linux if: branch = auto - env: IMAGE=dist-mips-linux DEPLOY=1 + name: dist-mips-linux if: branch = auto - env: IMAGE=dist-mips64-linux DEPLOY=1 + name: dist-mips64-linux if: branch = auto - env: IMAGE=dist-mips64el-linux DEPLOY=1 + name: dist-mips64el-linux if: branch = auto - env: IMAGE=dist-mipsel-linux DEPLOY=1 + name: dist-mipsel-linux if: branch = auto - env: IMAGE=dist-powerpc-linux DEPLOY=1 + name: dist-powerpc-linux if: branch = auto - env: IMAGE=dist-powerpc64-linux DEPLOY=1 + name: dist-powerpc64-linux if: branch = auto - env: IMAGE=dist-powerpc64le-linux DEPLOY=1 + name: dist-powerpc64le-linux if: branch = auto - env: IMAGE=dist-s390x-linux DEPLOY=1 + name: dist-s390x-linux if: branch = auto - env: IMAGE=dist-x86_64-freebsd DEPLOY=1 + name: dist-x86_64-freebsd if: branch = auto - env: IMAGE=dist-x86_64-musl DEPLOY=1 + name: dist-x86_64-musl if: branch = auto - env: IMAGE=dist-x86_64-netbsd DEPLOY=1 + name: dist-x86_64-netbsd if: branch = auto - env: IMAGE=asmjs + name: asmjs if: branch = auto - env: IMAGE=i686-gnu + name: i686-gnu if: branch = auto - env: IMAGE=i686-gnu-nopt + name: i686-gnu-nopt if: branch = auto - env: IMAGE=test-various + name: test-various if: branch = auto - env: IMAGE=x86_64-gnu + name: x86_64-gnu if: branch = auto - env: IMAGE=x86_64-gnu-full-bootstrap + name: x86_64-gnu-full-bootstrap if: branch = auto - env: IMAGE=x86_64-gnu-aux + name: x86_64-gnu-aux if: branch = auto - env: IMAGE=x86_64-gnu-tools + name: x86_64-gnu-tools if: branch = auto OR (type = pull_request AND commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri|cargo)\b)/) - env: IMAGE=x86_64-gnu-debug + name: x86_64-gnu-debug if: branch = auto - env: IMAGE=x86_64-gnu-nopt + name: x86_64-gnu-nopt if: branch = auto - env: IMAGE=x86_64-gnu-distcheck + name: x86_64-gnu-distcheck if: branch = auto - env: IMAGE=mingw-check + name: mingw-check if: type = pull_request OR branch = auto - stage: publish toolstate diff --git a/appveyor.yml b/appveyor.yml index d70ad54b1c812..040e21cba9682 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,34 +7,34 @@ environment: matrix: # 32/64 bit MSVC tests - - MSYS_BITS: 64 + - CI_JOB_NAME: x86_64-msvc + MSYS_BITS: 64 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler SCRIPT: python x.py test - CI_JOB_NAME: x86_64-msvc - - MSYS_BITS: 32 + - CI_JOB_NAME: i686-msvc-1 + MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc SCRIPT: make appveyor-subset-1 - CI_JOB_NAME: i686-msvc-1 - - MSYS_BITS: 32 + - CI_JOB_NAME: i686-msvc-2 + MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc SCRIPT: make appveyor-subset-2 - CI_JOB_NAME: i686-msvc-2 # MSVC aux tests - - MSYS_BITS: 64 + - CI_JOB_NAME: x86_64-msvc-aux + MSYS_BITS: 64 RUST_CHECK_TARGET: check-aux EXCLUDE_CARGO=1 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc - CI_JOB_NAME: x86_64-msvc-aux - - MSYS_BITS: 64 + - CI_JOB_NAME: x86_64-msvc-cargo + MSYS_BITS: 64 SCRIPT: python x.py test src/tools/cargotest src/tools/cargo RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc - CI_JOB_NAME: x86_64-msvc-cargo # MSVC tools tests - - MSYS_BITS: 64 + - CI_JOB_NAME: x86_64-msvc-tools + MSYS_BITS: 64 SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json --enable-test-miri - CI_JOB_NAME: x86_64-msvc-tools # 32/64-bit MinGW builds. # @@ -49,30 +49,31 @@ environment: # bucket, but they cleraly didn't originate there! The downloads originally # came from the mingw-w64 SourceForge download site. Unfortunately # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. - - MSYS_BITS: 32 + - CI_JOB_NAME: i686-mingw-1 + MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make appveyor-subset-1 MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 - CI_JOB_NAME: i686-mingw-1 - - MSYS_BITS: 32 + - CI_JOB_NAME: i686-mingw-2 + MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make appveyor-subset-2 MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 - CI_JOB_NAME: i686-mingw-2 - - MSYS_BITS: 64 + - CI_JOB_NAME: x86_64-mingw + MSYS_BITS: 64 SCRIPT: python x.py test RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 - CI_JOB_NAME: x86_64-mingw # 32/64 bit MSVC and GNU deployment - - RUST_CONFIGURE_ARGS: > + - CI_JOB_NAME: dist-x86_64-msvc + RUST_CONFIGURE_ARGS: > --build=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools @@ -80,9 +81,9 @@ environment: SCRIPT: python x.py dist 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: > + - CI_JOB_NAME: dist-i686-msvc + RUST_CONFIGURE_ARGS: > --build=i686-pc-windows-msvc --target=i586-pc-windows-msvc --enable-full-tools @@ -90,8 +91,8 @@ environment: SCRIPT: python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 - CI_JOB_NAME: dist-i686-msvc - - MSYS_BITS: 32 + - CI_JOB_NAME: dist-i686-mingw + MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools SCRIPT: python x.py dist MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror @@ -99,8 +100,8 @@ environment: MINGW_DIR: mingw32 DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 - CI_JOB_NAME: dist-i686-mingw - - MSYS_BITS: 64 + - CI_JOB_NAME: dist-x86_64-mingw + MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror @@ -108,14 +109,13 @@ environment: MINGW_DIR: mingw64 DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 - CI_JOB_NAME: dist-x86_64-mingw # "alternate" deployment, see .travis.yml for more info - - MSYS_BITS: 64 + - CI_JOB_NAME: dist-x86_64-msvc-alt + MSYS_BITS: 64 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler SCRIPT: python x.py dist DEPLOY_ALT: 1 - CI_JOB_NAME: dist-x86_64-msvc-alt matrix: fast_finish: true diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ffd23e72e80a6..daa6749f87f3e 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -408,11 +408,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 ), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), Kind::Doc => describe!( diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 3343716419ff4..97e6ee25ec7a0 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -78,6 +78,7 @@ status_check() { check_dispatch $1 beta clippy-driver src/tools/clippy # these tools are not required for beta to successfully branch check_dispatch $1 nightly miri src/tools/miri + check_dispatch $1 nightly embedded-book src/doc/embedded-book } # If this PR is intended to update one of these tools, do not let the build pass diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index 1d4a3edc1ac42..0930f8dacd494 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -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); diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index f14750089c956..844afe870766b 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -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))); diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index feba46b0fad78..b54c128a0249a 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -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 = 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| { diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index b33a564218888..f2dc19a42296a 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -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); diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 7e93d84fe3b97..7e75b8c4f28c8 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -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"); diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 6e4ca1d90e642..545332bcd6a2f 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -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::::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]; diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 16ddc1444fcf9..e0fe10a55f55c 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -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 { diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 94bed3708369a..7de94d25c7618 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -567,6 +567,32 @@ pub trait Ord: Eq + PartialOrd { 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")] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 81a8d001dd9cb..4f71c8e794954 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -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 { /// The lower bound of the range (inclusive). @@ -95,8 +95,6 @@ impl> Range { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!(!(3..5).contains(&2)); @@ -112,7 +110,7 @@ impl> Range { /// 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(&self, item: &U) -> bool where Idx: PartialOrd, @@ -175,7 +173,7 @@ impl> Range { /// /// [`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 { /// The lower bound of the range (inclusive). @@ -196,8 +194,6 @@ impl> RangeFrom { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!(!(3..).contains(&2)); @@ -208,7 +204,7 @@ impl> RangeFrom { /// 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(&self, item: &U) -> bool where Idx: PartialOrd, @@ -280,8 +276,6 @@ impl> RangeTo { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!( (..5).contains(&-1_000_000_000)); @@ -292,7 +286,7 @@ impl> RangeTo { /// 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(&self, item: &U) -> bool where Idx: PartialOrd, @@ -329,7 +323,7 @@ impl> RangeTo { /// 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 { pub(crate) start: Idx, @@ -365,7 +359,8 @@ impl RangeInclusiveEquality for T { impl PartialEq for RangeInclusive { #[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 RangeInclusive { #[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> RangeInclusive { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!(!(3..=5).contains(&2)); @@ -496,7 +493,7 @@ impl> RangeInclusive { /// 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(&self, item: &U) -> bool where Idx: PartialOrd, @@ -609,15 +606,12 @@ impl fmt::Debug for RangeToInclusive { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeToInclusive { /// 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> RangeToInclusive { /// 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(&self, item: &U) -> bool where Idx: PartialOrd, @@ -730,14 +724,11 @@ pub trait RangeBounds { #[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 { /// 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(&self, item: &U) -> bool where T: PartialOrd, @@ -757,9 +748,7 @@ pub trait RangeBounds { 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 RangeBounds for (Bound, Bound) { match *self { (Included(ref start), _) => Included(start), (Excluded(ref start), _) => Excluded(start), - (Unbounded, _) => Unbounded, + (Unbounded, _) => Unbounded, } } @@ -843,7 +832,7 @@ impl RangeBounds for (Bound, Bound) { match *self { (_, Included(ref end)) => Included(end), (_, Excluded(ref end)) => Excluded(end), - (_, Unbounded) => Unbounded, + (_, Unbounded) => Unbounded, } } } diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs index b16416022c04e..56f295dff8e43 100644 --- a/src/libcore/tests/cell.rs +++ b/src/libcore/tests/cell.rs @@ -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(); diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index a9db9b35d8d80..a3f0b02e2fe33 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -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), diff --git a/src/libcore/tests/num/bignum.rs b/src/libcore/tests/num/bignum.rs index 956c22c998219..b873f1dd0652f 100644 --- a/src/libcore/tests/num/bignum.rs +++ b/src/libcore/tests/num/bignum.rs @@ -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); } diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index 87ce2720c5918..b059b134868d9 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -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 = 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 = None; x.unwrap(); diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index bbc8568517667..1fab07526a07f 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -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 = 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"); diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 31d16e0e32057..ac9c17a0f7c35 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -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. diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index 09aae4583482f..6efd22572dc18 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -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); } diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 91161ca477e39..ae6d8078fd236 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -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_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(self, rhs: Duration) -> f64 { - self.as_float_secs() / rhs.as_float_secs() + pub fn div_duration_f32(self, rhs: Duration) -> f32 { + self.as_secs_f32() / rhs.as_secs_f32() } } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 96f0beafa005f..ab10536038872 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -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, + 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"); - }; + } } diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index d4ee60eee6310..80fef910cc718 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -101,8 +101,7 @@ impl AllocationExtra<(), ()> for () { impl Allocation { /// 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 Allocation { 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 DerefMut for Relocations { //////////////////////////////////////////////////////////////////////////////// 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, @@ -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) diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 0a295c202e655..c75788ecb4fbd 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -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)] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 7c7698ddd3d73..6b4b437930d26 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -2,7 +2,6 @@ #![feature(custom_attribute)] #![allow(unused_attributes)] -#![feature(range_contains)] #![cfg_attr(unix, feature(libc))] #![feature(nll)] #![feature(optin_builtin_traits)] diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 88b936afaa4c1..6ea200d4e4fad 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -700,24 +700,29 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // relocations overlapping the edges; those would not be handled correctly). let relocations = { let relocations = self.get(src.alloc_id)?.relocations(self, src, size); - let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); - for i in 0..length { - new_relocations.extend( - relocations - .iter() - .map(|&(offset, reloc)| { - // compute offset for current repetition - let dest_offset = dest.offset + (i * size); - ( - // shift offsets from source allocation to destination allocation - offset + dest_offset - src.offset, - reloc, - ) - }) - ); - } + if relocations.is_empty() { + // nothing to copy, ignore even the `length` loop + Vec::new() + } else { + let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); + for i in 0..length { + new_relocations.extend( + relocations + .iter() + .map(|&(offset, reloc)| { + // compute offset for current repetition + let dest_offset = dest.offset + (i * size); + ( + // shift offsets from source allocation to destination allocation + offset + dest_offset - src.offset, + reloc, + ) + }) + ); + } - new_relocations + new_relocations + } }; let tcx = self.tcx.tcx; @@ -784,20 +789,65 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // The bits have to be saved locally before writing to dest in case src and dest overlap. assert_eq!(size.bytes() as usize as u64, size.bytes()); - let undef_mask = self.get(src.alloc_id)?.undef_mask.clone(); - let dest_allocation = self.get_mut(dest.alloc_id)?; + let undef_mask = &self.get(src.alloc_id)?.undef_mask; + + // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`), + // a naive undef mask copying algorithm would repeatedly have to read the undef mask from + // the source and write it to the destination. Even if we optimized the memory accesses, + // we'd be doing all of this `repeat` times. + // Therefor we precompute a compressed version of the undef mask of the source value and + // then write it back `repeat` times without computing any more information from the source. + + // a precomputed cache for ranges of defined/undefined bits + // 0000010010001110 will become + // [5, 1, 2, 1, 3, 3, 1] + // where each element toggles the state + let mut ranges = smallvec::SmallVec::<[u64; 1]>::new(); + let first = undef_mask.get(src.offset); + let mut cur_len = 1; + let mut cur = first; + for i in 1..size.bytes() { + // FIXME: optimize to bitshift the current undef block's bits and read the top bit + if undef_mask.get(src.offset + Size::from_bytes(i)) == cur { + cur_len += 1; + } else { + ranges.push(cur_len); + cur_len = 1; + cur = !cur; + } + } - for i in 0..size.bytes() { - let defined = undef_mask.get(src.offset + Size::from_bytes(i)); + // now fill in all the data + let dest_allocation = self.get_mut(dest.alloc_id)?; + // an optimization where we can just overwrite an entire range of definedness bits if + // they are going to be uniformly `1` or `0`. + if ranges.is_empty() { + dest_allocation.undef_mask.set_range_inbounds( + dest.offset, + dest.offset + size * repeat, + first, + ); + return Ok(()) + } - for j in 0..repeat { - dest_allocation.undef_mask.set( - dest.offset + Size::from_bytes(i + (size.bytes() * j)), - defined + // remember to fill in the trailing bits + ranges.push(cur_len); + + for mut j in 0..repeat { + j *= size.bytes(); + j += dest.offset.bytes(); + let mut cur = first; + for range in &ranges { + let old_j = j; + j += range; + dest_allocation.undef_mask.set_range_inbounds( + Size::from_bytes(old_j), + Size::from_bytes(j), + cur, ); + cur = !cur; } } - Ok(()) } } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 0b735b4b39cf5..c45e694ebf832 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,7 +14,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(const_fn)] #![feature(decl_macro)] #![feature(exhaustive_patterns)] -#![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_attrs)] #![feature(never_type)] diff --git a/src/librustc_target/spec/uefi_base.rs b/src/librustc_target/spec/uefi_base.rs index 631966c09a498..956767a22a0e1 100644 --- a/src/librustc_target/spec/uefi_base.rs +++ b/src/librustc_target/spec/uefi_base.rs @@ -59,7 +59,7 @@ pub fn opts() -> TargetOptions { singlethread: true, emit_debug_gdb_scripts: false, - linker: Some("lld-link".to_string()), + linker: Some("rust-lld".to_string()), lld_flavor: LldFlavor::Link, pre_link_args, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 28c79ce0c74e8..94981dd1218c3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5288,6 +5288,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(original_span.with_lo(original_span.hi() - BytePos(1))) } + // Rewrite `SelfCtor` to `StructCtor` + pub fn rewrite_self_ctor(&self, def: Def, span: Span) -> (Def, DefId, Ty<'tcx>) { + let tcx = self.tcx; + if let Def::SelfCtor(impl_def_id) = def { + let ty = self.impl_self_ty(span, impl_def_id).ty; + let adt_def = ty.ty_adt_def(); + + match adt_def { + Some(adt_def) if adt_def.has_ctor() => { + let variant = adt_def.non_enum_variant(); + let def = Def::StructCtor(variant.did, variant.ctor_kind); + (def, variant.did, tcx.type_of(variant.did)) + } + _ => { + let mut err = tcx.sess.struct_span_err(span, + "the `Self` constructor can only be used with tuple or unit structs"); + if let Some(adt_def) = adt_def { + match adt_def.adt_kind() { + AdtKind::Enum => { + err.help("did you mean to use one of the enum's variants?"); + }, + AdtKind::Struct | + AdtKind::Union => { + err.span_suggestion( + span, + "use curly brackets", + String::from("Self { /* fields */ }"), + Applicability::HasPlaceholders, + ); + } + } + } + err.emit(); + + (def, impl_def_id, tcx.types.err) + } + } + } else { + let def_id = def.def_id(); + + // The things we are substituting into the type should not contain + // escaping late-bound regions, and nor should the base type scheme. + let ty = tcx.type_of(def_id); + (def, def_id, ty) + } + } + // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. pub fn instantiate_value_path(&self, @@ -5307,6 +5354,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tcx = self.tcx; + match def { + Def::Local(nid) | Def::Upvar(nid, ..) => { + let hid = self.tcx.hir().node_to_hir_id(nid); + let ty = self.local_ty(span, hid).decl_ty; + let ty = self.normalize_associated_types_in(span, &ty); + self.write_ty(hir_id, ty); + return (ty, def); + } + _ => {} + } + + let (def, def_id, ty) = self.rewrite_self_ctor(def, span); let path_segs = AstConv::def_ids_for_path_segments(self, segments, self_ty, def); let mut user_self_ty = None; @@ -5368,17 +5427,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { user_self_ty = None; } - match def { - Def::Local(nid) | Def::Upvar(nid, ..) => { - let hid = self.tcx.hir().node_to_hir_id(nid); - let ty = self.local_ty(span, hid).decl_ty; - let ty = self.normalize_associated_types_in(span, &ty); - self.write_ty(hir_id, ty); - return (ty, def); - } - _ => {} - } - // Now we have to compare the types that the user *actually* // provided against the types that were *expected*. If the user // did not provide any types, then we want to substitute inference @@ -5411,53 +5459,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.generics_of(*def_id).has_self }).unwrap_or(false); - let mut new_def = def; - let (def_id, ty) = match def { - Def::SelfCtor(impl_def_id) => { - let ty = self.impl_self_ty(span, impl_def_id).ty; - let adt_def = ty.ty_adt_def(); - - match adt_def { - Some(adt_def) if adt_def.has_ctor() => { - let variant = adt_def.non_enum_variant(); - new_def = Def::StructCtor(variant.did, variant.ctor_kind); - (variant.did, tcx.type_of(variant.did)) - } - _ => { - let mut err = tcx.sess.struct_span_err(span, - "the `Self` constructor can only be used with tuple or unit structs"); - if let Some(adt_def) = adt_def { - match adt_def.adt_kind() { - AdtKind::Enum => { - err.help("did you mean to use one of the enum's variants?"); - }, - AdtKind::Struct | - AdtKind::Union => { - err.span_suggestion( - span, - "use curly brackets", - String::from("Self { /* fields */ }"), - Applicability::HasPlaceholders, - ); - } - } - } - err.emit(); - - (impl_def_id, tcx.types.err) - } - } - } - _ => { - let def_id = def.def_id(); - - // The things we are substituting into the type should not contain - // escaping late-bound regions, and nor should the base type scheme. - let ty = tcx.type_of(def_id); - (def_id, ty) - } - }; - let substs = AstConv::create_substs_for_generic_args( tcx, def_id, @@ -5573,7 +5574,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty_substituted); self.write_substs(hir_id, substs); - (ty_substituted, new_def) + (ty_substituted, def) } fn check_rustc_args_require_const(&self, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fefff1f3a7593..0fa6b6baec79d 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,7 +1,8 @@ -use rustc::lint as lint; -use rustc::hir; -use rustc::hir::def::Def; +use errors::Applicability; +use rustc::hir::def::{Def, Namespace::{self, *}, PerNS}; use rustc::hir::def_id::DefId; +use rustc::hir; +use rustc::lint as lint; use rustc::ty; use syntax; use syntax::ast::{self, Ident}; @@ -35,22 +36,9 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { } } -#[derive(Debug)] -enum PathKind { - /// Either a value or type, but not a macro - Unknown, - /// Macro - Macro, - /// Values, functions, consts, statics (everything in the value namespace) - Value, - /// Types, traits (everything in the type namespace) - Type, -} - struct LinkCollector<'a, 'tcx> { cx: &'a DocContext<'tcx>, mod_ids: Vec, - is_nightly_build: bool, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { @@ -58,16 +46,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { LinkCollector { cx, mod_ids: Vec::new(), - is_nightly_build: UnstableFeatures::from_environment().is_nightly_build(), } } - /// Resolves a given string as a path, along with whether or not it is - /// in the value namespace. Also returns an optional URL fragment in the case - /// of variants and methods. + /// Resolves a string as a path within a particular namespace. Also returns an optional + /// URL fragment in the case of variants and methods. fn resolve(&self, path_str: &str, - is_val: bool, + ns: Namespace, current_item: &Option, parent_id: Option) -> Result<(Def, Option), ()> @@ -78,11 +64,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // path. if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) { // FIXME: `with_scope` requires the `NodeId` of a module. - let result = cx.enter_resolver(|resolver| resolver.with_scope(id, - |resolver| { - resolver.resolve_str_path_error(DUMMY_SP, - &path_str, is_val) - })); + let result = cx.enter_resolver(|resolver| { + resolver.with_scope(id, |resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns == ValueNS) + }) + }); if let Ok(result) = result { // In case this is a trait item, skip the @@ -95,16 +81,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => return Ok((result.def, None)) }; - if value != is_val { + if value != (ns == ValueNS) { return Err(()) } - } else if let Some(prim) = is_primitive(path_str, is_val) { + } else if let Some(prim) = is_primitive(path_str, ns) { return Ok((prim, Some(path_str.to_owned()))) } else { // If resolution failed, it may still be a method // because methods are not handled by the resolver // If so, bail when we're not looking for a value. - if !is_val { + if ns != ValueNS { return Err(()) } } @@ -128,7 +114,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { path = name.clone(); } } - if let Some(prim) = is_primitive(&path, false) { + if let Some(prim) = is_primitive(&path, TypeNS) { let did = primitive_impl(cx, &path).ok_or(())?; return cx.tcx.associated_items(did) .find(|item| item.ident.name == item_name) @@ -152,8 +138,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .find(|item| item.ident.name == item_name); if let Some(item) = item { let out = match item.kind { - ty::AssociatedKind::Method if is_val => "method", - ty::AssociatedKind::Const if is_val => "associatedconstant", + ty::AssociatedKind::Method if ns == ValueNS => "method", + ty::AssociatedKind::Const if ns == ValueNS => "associatedconstant", _ => return Err(()) }; Ok((ty.def, Some(format!("{}.{}", out, item_name)))) @@ -190,9 +176,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .find(|item| item.ident.name == item_name); if let Some(item) = item { let kind = match item.kind { - ty::AssociatedKind::Const if is_val => "associatedconstant", - ty::AssociatedKind::Type if !is_val => "associatedtype", - ty::AssociatedKind::Method if is_val => { + ty::AssociatedKind::Const if ns == ValueNS => "associatedconstant", + ty::AssociatedKind::Type if ns == TypeNS => "associatedtype", + ty::AssociatedKind::Method if ns == ValueNS => { if item.defaultness.has_value() { "method" } else { @@ -279,10 +265,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { look_for_tests(&cx, &dox, &item, true); - if !self.is_nightly_build { - return None; - } - for (ori_link, link_range) in markdown_links(&dox) { // Bail early for real links. if ori_link.contains('/') { @@ -290,28 +272,28 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } let link = ori_link.replace("`", ""); let (def, fragment) = { - let mut kind = PathKind::Unknown; + let mut kind = None; let path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"].iter() .find(|p| link.starts_with(**p)) { - kind = PathKind::Type; + kind = Some(TypeNS); link.trim_start_matches(prefix) } else if let Some(prefix) = ["const@", "static@", "value@", "function@", "mod@", "fn@", "module@", "method@"] .iter().find(|p| link.starts_with(**p)) { - kind = PathKind::Value; + kind = Some(ValueNS); link.trim_start_matches(prefix) } else if link.ends_with("()") { - kind = PathKind::Value; + kind = Some(ValueNS); link.trim_end_matches("()") } else if link.starts_with("macro@") { - kind = PathKind::Macro; + kind = Some(MacroNS); link.trim_start_matches("macro@") } else if link.ends_with('!') { - kind = PathKind::Macro; + kind = Some(MacroNS); link.trim_end_matches('!') } else { &link[..] @@ -323,8 +305,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } match kind { - PathKind::Value => { - if let Ok(def) = self.resolve(path_str, true, ¤t_item, parent_node) { + Some(ns @ ValueNS) => { + if let Ok(def) = self.resolve(path_str, ns, ¤t_item, parent_node) { def } else { resolution_failure(cx, &item.attrs, path_str, &dox, link_range); @@ -334,8 +316,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { continue; } } - PathKind::Type => { - if let Ok(def) = self.resolve(path_str, false, ¤t_item, parent_node) { + Some(ns @ TypeNS) => { + if let Ok(def) = self.resolve(path_str, ns, ¤t_item, parent_node) { def } else { resolution_failure(cx, &item.attrs, path_str, &dox, link_range); @@ -343,62 +325,49 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { continue; } } - PathKind::Unknown => { + None => { // Try everything! - if let Some(macro_def) = macro_resolve(cx, path_str) { - if let Ok(type_def) = - self.resolve(path_str, false, ¤t_item, parent_node) - { - let (type_kind, article, type_disambig) - = type_ns_kind(type_def.0, path_str); - ambiguity_error(cx, &item.attrs, path_str, - article, type_kind, &type_disambig, - "a", "macro", &format!("macro@{}", path_str)); - continue; - } else if let Ok(value_def) = - self.resolve(path_str, true, ¤t_item, parent_node) - { - let (value_kind, value_disambig) - = value_ns_kind(value_def.0, path_str) - .expect("struct and mod cases should have been \ - caught in previous branch"); - ambiguity_error(cx, &item.attrs, path_str, - "a", value_kind, &value_disambig, - "a", "macro", &format!("macro@{}", path_str)); - } - (macro_def, None) - } else if let Ok(type_def) = - self.resolve(path_str, false, ¤t_item, parent_node) - { - // It is imperative we search for not-a-value first - // Otherwise we will find struct ctors for when we are looking - // for structs, and the link won't work if there is something in - // both namespaces. - if let Ok(value_def) = - self.resolve(path_str, true, ¤t_item, parent_node) - { - let kind = value_ns_kind(value_def.0, path_str); - if let Some((value_kind, value_disambig)) = kind { - let (type_kind, article, type_disambig) - = type_ns_kind(type_def.0, path_str); - ambiguity_error(cx, &item.attrs, path_str, - article, type_kind, &type_disambig, - "a", value_kind, &value_disambig); - continue; - } - } - type_def - } else if let Ok(value_def) = - self.resolve(path_str, true, ¤t_item, parent_node) - { - value_def - } else { + let candidates = PerNS { + macro_ns: macro_resolve(cx, path_str).map(|def| (def, None)), + type_ns: self + .resolve(path_str, TypeNS, ¤t_item, parent_node) + .ok(), + value_ns: self + .resolve(path_str, ValueNS, ¤t_item, parent_node) + .ok() + .and_then(|(def, fragment)| { + // Constructors are picked up in the type namespace. + match def { + Def::StructCtor(..) + | Def::VariantCtor(..) + | Def::SelfCtor(..) => None, + _ => Some((def, fragment)) + } + }), + }; + + if candidates.is_empty() { resolution_failure(cx, &item.attrs, path_str, &dox, link_range); // this could just be a normal link continue; } + + let is_unambiguous = candidates.clone().present_items().count() == 1; + if is_unambiguous { + candidates.present_items().next().unwrap() + } else { + ambiguity_error( + cx, + &item.attrs, + path_str, + &dox, + link_range, + candidates.map(|candidate| candidate.map(|(def, _)| def)), + ); + continue; + } } - PathKind::Macro => { + Some(MacroNS) => { if let Some(def) = macro_resolve(cx, path_str) { (def, None) } else { @@ -505,59 +474,114 @@ fn resolution_failure( diag.emit(); } -fn ambiguity_error(cx: &DocContext<'_>, attrs: &Attributes, - path_str: &str, - article1: &str, kind1: &str, disambig1: &str, - article2: &str, kind2: &str, disambig2: &str) { +fn ambiguity_error( + cx: &DocContext<'_>, + attrs: &Attributes, + path_str: &str, + dox: &str, + link_range: Option>, + candidates: PerNS>, +) { let sp = span_of_attrs(attrs); - cx.sess() - .struct_span_warn(sp, - &format!("`{}` is both {} {} and {} {}", - path_str, article1, kind1, - article2, kind2)) - .help(&format!("try `{}` if you want to select the {}, \ - or `{}` if you want to \ - select the {}", - disambig1, kind1, disambig2, - kind2)) - .emit(); -} -/// Given a def, returns its name and disambiguator -/// for a value namespace. -/// -/// Returns `None` for things which cannot be ambiguous since -/// they exist in both namespaces (structs and modules). -fn value_ns_kind(def: Def, path_str: &str) -> Option<(&'static str, String)> { - match def { - // Structs, variants, and mods exist in both namespaces; skip them. - Def::StructCtor(..) | Def::Mod(..) | Def::Variant(..) | - Def::VariantCtor(..) | Def::SelfCtor(..) - => None, - Def::Fn(..) - => Some(("function", format!("{}()", path_str))), - Def::Method(..) - => Some(("method", format!("{}()", path_str))), - Def::Const(..) - => Some(("const", format!("const@{}", path_str))), - Def::Static(..) - => Some(("static", format!("static@{}", path_str))), - _ => Some(("value", format!("value@{}", path_str))), + let mut msg = format!("`{}` is ", path_str); + + let candidates = [TypeNS, ValueNS, MacroNS].iter().filter_map(|&ns| { + candidates[ns].map(|def| (def, ns)) + }).collect::>(); + match candidates.as_slice() { + [(first_def, _), (second_def, _)] => { + msg += &format!( + "both {} {} and {} {}", + first_def.article(), + first_def.kind_name(), + second_def.article(), + second_def.kind_name(), + ); + } + _ => { + let mut candidates = candidates.iter().peekable(); + while let Some((def, _)) = candidates.next() { + if candidates.peek().is_some() { + msg += &format!("{} {}, ", def.article(), def.kind_name()); + } else { + msg += &format!("and {} {}", def.article(), def.kind_name()); + } + } + } } -} -/// Given a def, returns its name, the article to be used, and a disambiguator -/// for the type namespace. -fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String) { - let (kind, article) = match def { - // We can still have non-tuple structs. - Def::Struct(..) => ("struct", "a"), - Def::Enum(..) => ("enum", "an"), - Def::Trait(..) => ("trait", "a"), - Def::Union(..) => ("union", "a"), - _ => ("type", "a"), - }; - (kind, article, format!("{}@{}", kind, path_str)) + let mut diag = cx.tcx.struct_span_lint_hir( + lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, + hir::CRATE_HIR_ID, + sp, + &msg, + ); + + if let Some(link_range) = link_range { + if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) { + diag.set_span(sp); + diag.span_label(sp, "ambiguous link"); + + for (def, ns) in candidates { + let (action, mut suggestion) = match def { + Def::Method(..) | Def::Fn(..) => { + ("add parentheses", format!("{}()", path_str)) + } + Def::Macro(..) => { + ("add an exclamation mark", format!("{}!", path_str)) + } + _ => { + let type_ = match (def, ns) { + (Def::Const(..), _) => "const", + (Def::Static(..), _) => "static", + (Def::Struct(..), _) => "struct", + (Def::Enum(..), _) => "enum", + (Def::Union(..), _) => "union", + (Def::Trait(..), _) => "trait", + (Def::Mod(..), _) => "module", + (_, TypeNS) => "type", + (_, ValueNS) => "value", + (_, MacroNS) => "macro", + }; + + // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` + ("prefix with the item type", format!("{}@{}", type_, path_str)) + } + }; + + if dox.bytes().nth(link_range.start) == Some(b'`') { + suggestion = format!("`{}`", suggestion); + } + + diag.span_suggestion( + sp, + &format!("to link to the {}, {}", def.kind_name(), action), + suggestion, + Applicability::MaybeIncorrect, + ); + } + } else { + // blah blah blah\nblah\nblah [blah] blah blah\nblah blah + // ^ ~~~~ + // | link_range + // last_new_line_offset + let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1); + let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); + + // Print the line containing the `link_range` and manually mark it with '^'s. + diag.note(&format!( + "the link appears in this line:\n\n{line}\n\ + {indicator: Option { - if is_val { - None - } else { +fn is_primitive(path_str: &str, ns: Namespace) -> Option { + if ns == TypeNS { PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) + } else { + None } } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index f6cd9e82abd40..a2b12d00a78c2 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -956,6 +956,27 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + /// Returns max if self is greater than max, and min if self is less than min. + /// Otherwise this returns self. Panics if min > max, min equals NaN, or max equals NaN. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// assert!((-3.0f32).clamp(-2.0f32, 1.0f32) == -2.0f32); + /// assert!((0.0f32).clamp(-2.0f32, 1.0f32) == 0.0f32); + /// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32); + /// ``` + #[unstable(feature = "clamp", issue = "44095")] + #[inline] + pub fn clamp(self, min: f32, max: f32) -> f32 { + assert!(min <= max); + let mut x = self; + if x < min { x = min; } + if x > max { x = max; } + x + } + } #[cfg(test)] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 8ff97ab828a73..be5cd92d4167b 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -878,6 +878,27 @@ impl f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + /// Returns max if self is greater than max, and min if self is less than min. + /// Otherwise this returns self. Panics if min > max, min equals NaN, or max equals NaN. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// assert!((-3.0f64).clamp(-2.0f64, 1.0f64) == -2.0f64); + /// assert!((0.0f64).clamp(-2.0f64, 1.0f64) == 0.0f64); + /// assert!((2.0f64).clamp(-2.0f64, 1.0f64) == 1.0f64); + /// ``` + #[unstable(feature = "clamp", issue = "44095")] + #[inline] + pub fn clamp(self, min: f64, max: f64) -> f64 { + assert!(min <= max); + let mut x = self; + if x < min { x = min; } + if x > max { x = max; } + x + } + // Solaris/Illumos requires a wrapper around log, log2, and log10 functions // because of their non-standard behavior (e.g., log(-n) returns -Inf instead // of expected NaN). diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index e31680f23f1da..fc8ac9a0b3e00 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -221,7 +221,7 @@ #![cfg_attr(test, feature(print_internals, set_stdio, test, update_panic_count))] #![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"), - feature(global_asm, range_contains, slice_index_methods, + feature(global_asm, slice_index_methods, decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))] // std is implemented with unstable features, many of which are internal @@ -245,6 +245,7 @@ #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] #![feature(checked_duration_since)] +#![feature(clamp)] #![feature(compiler_builtins_lib)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 568400093440c..ad86acbb47de4 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -8,7 +8,7 @@ //! //! The [`Command`] struct is used to configure and spawn processes: //! -//! ``` +//! ```no_run //! use std::process::Command; //! //! let output = Command::new("echo") diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 6d7093ac33ea7..4c86f70ad871d 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -712,13 +712,6 @@ mod tests { assert_almost_eq!(a - second + second, a); assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); - // A difference of 80 and 800 years cannot fit inside a 32-bit time_t - if !(cfg!(unix) && crate::mem::size_of::() <= 4) { - let eighty_years = second * 60 * 60 * 24 * 365 * 80; - assert_almost_eq!(a - eighty_years + eighty_years, a); - assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a); - } - let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); @@ -747,8 +740,8 @@ mod tests { #[test] fn since_epoch() { let ts = SystemTime::now(); - let a = ts.duration_since(UNIX_EPOCH).unwrap(); - let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap(); + let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap(); + let b = ts.duration_since(UNIX_EPOCH).unwrap(); assert!(b > a); assert_eq!(b - a, Duration::new(1, 0)); diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 4ce308d015c00..80a7bde606afa 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -178,9 +178,11 @@ impl TokenStream { while let Some((pos, ts)) = iter.next() { if let Some((_, next)) = iter.peek() { let sp = match (&ts, &next) { - ((TokenTree::Token(_, token::Token::Comma), NonJoint), _) | - (_, (TokenTree::Token(_, token::Token::Comma), NonJoint)) => continue, - ((TokenTree::Token(sp, _), NonJoint), _) => *sp, + (_, (TokenTree::Token(_, token::Token::Comma), _)) => continue, + ((TokenTree::Token(sp, token_left), NonJoint), + (TokenTree::Token(_, token_right), _)) + if (token_left.is_ident() || token_left.is_lit()) && + (token_right.is_ident() || token_right.is_lit()) => *sp, ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(), _ => continue, }; diff --git a/src/test/run-pass-fulldeps/undef_mask.rs b/src/test/run-pass-fulldeps/undef_mask.rs new file mode 100644 index 0000000000000..cf6e6f7231638 --- /dev/null +++ b/src/test/run-pass-fulldeps/undef_mask.rs @@ -0,0 +1,26 @@ +// ignore-cross-compile +// ignore-stage1 + +#![feature(rustc_private)] + +extern crate rustc; + +use rustc::mir::interpret::UndefMask; +use rustc::ty::layout::Size; + +fn main() { + let mut mask = UndefMask::new(Size::from_bytes(500), false); + assert!(!mask.get(Size::from_bytes(499))); + mask.set(Size::from_bytes(499), true); + assert!(mask.get(Size::from_bytes(499))); + mask.set_range_inbounds(Size::from_bytes(100), Size::from_bytes(256), true); + for i in 0..100 { + assert!(!mask.get(Size::from_bytes(i))); + } + for i in 100..256 { + assert!(mask.get(Size::from_bytes(i))); + } + for i in 256..499 { + assert!(!mask.get(Size::from_bytes(i))); + } +} diff --git a/src/test/run-pass/issue-55809.rs b/src/test/run-pass/issue-55809.rs new file mode 100644 index 0000000000000..86b0977bebe1d --- /dev/null +++ b/src/test/run-pass/issue-55809.rs @@ -0,0 +1,30 @@ +// edition:2018 +// run-pass + +#![feature(async_await, await_macro, futures_api)] + +trait Foo { } + +impl Foo for () { } + +impl<'a, T> Foo for &'a mut T where T: Foo { } + +async fn foo_async(_v: T) -> u8 where T: Foo { + 0 +} + +async fn bad(v: T) -> u8 where T: Foo { + await!(foo_async(v)) +} + +async fn async_main() { + let mut v = (); + + let _ = await!(bad(&mut v)); + let _ = await!(foo_async(&mut v)); + let _ = await!(bad(v)); +} + +fn main() { + let _ = async_main(); +} diff --git a/src/test/run-pass/issues/issue-57924.rs b/src/test/run-pass/issues/issue-57924.rs new file mode 100644 index 0000000000000..232596334b0ed --- /dev/null +++ b/src/test/run-pass/issues/issue-57924.rs @@ -0,0 +1,9 @@ +pub struct Gcm(E); + +impl Gcm { + pub fn crash(e: E) -> Self { + Self::(e) + } +} + +fn main() {} diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.rs b/src/test/rustdoc-ui/intra-links-ambiguity.rs new file mode 100644 index 0000000000000..7316fcdad6772 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-ambiguity.rs @@ -0,0 +1,36 @@ +#![deny(intra_doc_link_resolution_failure)] +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +pub fn ambiguous() {} + +pub struct ambiguous {} + +#[macro_export] +macro_rules! multi_conflict { () => {} } + +#[allow(non_camel_case_types)] +pub struct multi_conflict {} + +pub fn multi_conflict() {} + +pub mod type_and_value {} + +pub const type_and_value: i32 = 0; + +pub mod foo { + pub enum bar {} + + pub fn bar() {} +} + +/// [`ambiguous`] is ambiguous. //~ERROR `ambiguous` +/// +/// [ambiguous] is ambiguous. //~ERROR ambiguous +/// +/// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` +/// +/// Ambiguous [type_and_value]. //~ERROR type_and_value +/// +/// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar` +pub struct Docs {} diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr new file mode 100644 index 0000000000000..ad63f13493ddb --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr @@ -0,0 +1,82 @@ +error: `ambiguous` is both a struct and a function + --> $DIR/intra-links-ambiguity.rs:27:6 + | +LL | /// [`ambiguous`] is ambiguous. //~ERROR `ambiguous` + | ^^^^^^^^^^^ ambiguous link + | +note: lint level defined here + --> $DIR/intra-links-ambiguity.rs:1:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the struct, prefix with the item type + | +LL | /// [`struct@ambiguous`] is ambiguous. //~ERROR `ambiguous` + | ^^^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// [`ambiguous()`] is ambiguous. //~ERROR `ambiguous` + | ^^^^^^^^^^^^^ + +error: `ambiguous` is both a struct and a function + --> $DIR/intra-links-ambiguity.rs:29:6 + | +LL | /// [ambiguous] is ambiguous. //~ERROR ambiguous + | ^^^^^^^^^ ambiguous link +help: to link to the struct, prefix with the item type + | +LL | /// [struct@ambiguous] is ambiguous. //~ERROR ambiguous + | ^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// [ambiguous()] is ambiguous. //~ERROR ambiguous + | ^^^^^^^^^^^ + +error: `multi_conflict` is a struct, a function, and a macro + --> $DIR/intra-links-ambiguity.rs:31:6 + | +LL | /// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` + | ^^^^^^^^^^^^^^^^ ambiguous link +help: to link to the struct, prefix with the item type + | +LL | /// [`struct@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// [`multi_conflict()`] is a three-way conflict. //~ERROR `multi_conflict` + | ^^^^^^^^^^^^^^^^^^ +help: to link to the macro, add an exclamation mark + | +LL | /// [`multi_conflict!`] is a three-way conflict. //~ERROR `multi_conflict` + | ^^^^^^^^^^^^^^^^^ + +error: `type_and_value` is both a module and a constant + --> $DIR/intra-links-ambiguity.rs:33:16 + | +LL | /// Ambiguous [type_and_value]. //~ERROR type_and_value + | ^^^^^^^^^^^^^^ ambiguous link +help: to link to the module, prefix with the item type + | +LL | /// Ambiguous [module@type_and_value]. //~ERROR type_and_value + | ^^^^^^^^^^^^^^^^^^^^^ +help: to link to the constant, prefix with the item type + | +LL | /// Ambiguous [const@type_and_value]. //~ERROR type_and_value + | ^^^^^^^^^^^^^^^^^^^^ + +error: `foo::bar` is both an enum and a function + --> $DIR/intra-links-ambiguity.rs:35:42 + | +LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar` + | ^^^^^^^^^^ ambiguous link +help: to link to the enum, prefix with the item type + | +LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`]. //~ERROR `foo::bar` + | ^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// Ambiguous non-implied shortcut link [`foo::bar()`]. //~ERROR `foo::bar` + | ^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/rustdoc/intra-links.rs b/src/test/rustdoc/intra-links.rs index 9139fc51b092e..c356ab3a8ac52 100644 --- a/src/test/rustdoc/intra-links.rs +++ b/src/test/rustdoc/intra-links.rs @@ -22,6 +22,7 @@ //! * [`ThisType::this_method`](ThisType::this_method) //! * [`ThisEnum`](ThisEnum) //! * [`ThisEnum::ThisVariant`](ThisEnum::ThisVariant) +//! * [`ThisEnum::ThisVariantCtor`](ThisEnum::ThisVariantCtor) //! * [`ThisTrait`](ThisTrait) //! * [`ThisTrait::this_associated_method`](ThisTrait::this_associated_method) //! * [`ThisTrait::ThisAssociatedType`](ThisTrait::ThisAssociatedType) @@ -50,7 +51,7 @@ pub struct ThisType; impl ThisType { pub fn this_method() {} } -pub enum ThisEnum { ThisVariant, } +pub enum ThisEnum { ThisVariant, ThisVariantCtor(u32), } pub trait ThisTrait { type ThisAssociatedType; const THIS_ASSOCIATED_CONST: u8; diff --git a/src/test/ui/macros/missing-comma.rs b/src/test/ui/macros/missing-comma.rs index 1e146875bcc76..2b411aba8a2ee 100644 --- a/src/test/ui/macros/missing-comma.rs +++ b/src/test/ui/macros/missing-comma.rs @@ -6,6 +6,11 @@ macro_rules! foo { ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident) => (); } +macro_rules! bar { + ($lvl:expr, $($arg:tt)+) => {} +} + + fn main() { println!("{}" a); //~^ ERROR expected token: `,` @@ -17,4 +22,6 @@ fn main() { //~^ ERROR no rules expected the token `d` foo!(a, b, c d e); //~^ ERROR no rules expected the token `d` + bar!(Level::Error, ); + //~^ ERROR unexpected end of macro invocation } diff --git a/src/test/ui/macros/missing-comma.stderr b/src/test/ui/macros/missing-comma.stderr index 5881e0b7b68c6..424fefd00f873 100644 --- a/src/test/ui/macros/missing-comma.stderr +++ b/src/test/ui/macros/missing-comma.stderr @@ -1,11 +1,11 @@ error: expected token: `,` - --> $DIR/missing-comma.rs:10:19 + --> $DIR/missing-comma.rs:15:19 | LL | println!("{}" a); | ^ error: no rules expected the token `b` - --> $DIR/missing-comma.rs:12:12 + --> $DIR/missing-comma.rs:17:12 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -16,7 +16,7 @@ LL | foo!(a b); | help: missing comma here error: no rules expected the token `e` - --> $DIR/missing-comma.rs:14:21 + --> $DIR/missing-comma.rs:19:21 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -27,7 +27,7 @@ LL | foo!(a, b, c, d e); | help: missing comma here error: no rules expected the token `d` - --> $DIR/missing-comma.rs:16:18 + --> $DIR/missing-comma.rs:21:18 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -38,7 +38,7 @@ LL | foo!(a, b, c d, e); | help: missing comma here error: no rules expected the token `d` - --> $DIR/missing-comma.rs:18:18 + --> $DIR/missing-comma.rs:23:18 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -46,5 +46,14 @@ LL | macro_rules! foo { LL | foo!(a, b, c d e); | ^ no rules expected this token in macro call -error: aborting due to 5 previous errors +error: unexpected end of macro invocation + --> $DIR/missing-comma.rs:25:23 + | +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | bar!(Level::Error, ); + | ^ missing tokens in macro arguments + +error: aborting due to 6 previous errors diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs new file mode 100644 index 0000000000000..3d042d442d531 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs @@ -0,0 +1,70 @@ +// This test is ensuring that type ascriptions on let bindings +// constrain both: +// +// 1. the input expression on the right-hand side (after any potential +// coercion, and allowing for covariance), *and* +// +// 2. the bindings (if any) nested within the pattern on the left-hand +// side (and here, the type-constraint is *invariant*). + +#![feature(nll)] + +#![allow(dead_code, unused_mut)] +type PairUncoupled<'a, 'b, T> = (&'a T, &'b T); +type PairCoupledRegions<'a, T> = (&'a T, &'a T); +type PairCoupledTypes = (T, T); + +fn uncoupled_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((mut y, mut _z),): (PairUncoupled,) = ((s, &_x),); // ok + // Above compiling does *not* imply below would compile. + // ::std::mem::swap(&mut y, &mut _z); + y +} + +fn swap_regions((mut y, mut _z): PairCoupledRegions) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledRegions,) = ((s, &_x),); + // If above line compiled, so should line below ... + + // swap_regions((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR lifetime may not live long enough +} + +fn swap_types((mut y, mut _z): PairCoupledTypes<&u32>) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledTypes<&u32>,) = ((s, &_x),); + // If above line compiled, so should line below ... + + // swap_types((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR lifetime may not live long enough +} + +fn swap_wilds((mut y, mut _z): PairCoupledTypes<&u32>) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledTypes<_>,) = ((s, &_x),); + // If above line compiled, so should line below + // swap_wilds((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR lifetime may not live long enough +} + +fn main() { + uncoupled_lhs(&3, &4); + coupled_regions_lhs(&3, &4); + coupled_types_lhs(&3, &4); + coupled_wilds_lhs(&3, &4); +} diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr new file mode 100644 index 0000000000000..5929707e41e10 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr @@ -0,0 +1,29 @@ +error: lifetime may not live long enough + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:35:5 + | +LL | fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:49:5 + | +LL | fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:62:5 + | +LL | fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/suggestions/return-without-lifetime.rs b/src/test/ui/suggestions/return-without-lifetime.rs new file mode 100644 index 0000000000000..9bfce11be9ea3 --- /dev/null +++ b/src/test/ui/suggestions/return-without-lifetime.rs @@ -0,0 +1,10 @@ +struct Thing<'a>(&'a ()); +struct Foo<'a>(&usize); +//~^ ERROR missing lifetime specifier + +fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } +//~^ ERROR missing lifetime specifier +fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } +//~^ ERROR missing lifetime specifier + +fn main() {} diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr new file mode 100644 index 0000000000000..7f5ff95938e30 --- /dev/null +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -0,0 +1,25 @@ +error[E0106]: missing lifetime specifier + --> $DIR/return-without-lifetime.rs:2:16 + | +LL | struct Foo<'a>(&usize); + | ^ help: consider using the named lifetime: `&'a` + +error[E0106]: missing lifetime specifier + --> $DIR/return-without-lifetime.rs:5:34 + | +LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } + | ^ help: consider using the named lifetime: `&'a` + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from + +error[E0106]: missing lifetime specifier + --> $DIR/return-without-lifetime.rs:7:35 + | +LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } + | ^ help: consider using the named lifetime: `&'a` + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index fb6132a5358ef..f2a585e627307 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -12,7 +12,7 @@ except ImportError: import urllib.request as urllib2 -# List of people to ping when the status of a tool changed. +# List of people to ping when the status of a tool or a book changed. MAINTAINERS = { 'miri': '@oli-obk @RalfJung @eddyb', 'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch', @@ -22,6 +22,10 @@ 'nomicon': '@frewsxcv @Gankro', 'reference': '@steveklabnik @Havvy @matthewjasper @alercah', 'rust-by-example': '@steveklabnik @marioidival @projektir', + 'embedded-book': ( + '@adamgreig @andre-richter @jamesmunns @korken89 ' + '@ryankurte @thejpster @therealprof' + ), } REPOS = { @@ -33,6 +37,7 @@ 'nomicon': 'https://github.com/rust-lang-nursery/nomicon', 'reference': 'https://github.com/rust-lang-nursery/reference', 'rust-by-example': 'https://github.com/rust-lang/rust-by-example', + 'embedded-book': 'https://github.com/rust-embedded/book', } @@ -70,7 +75,7 @@ def issue( cc @{}, the PR reviewer, and @rust-lang/compiler -- nominating for prioritization. - ''').format(relevant_pr_number, tool, REPOS[tool], relevant_pr_user, pr_reviewer), + ''').format(relevant_pr_number, tool, REPOS.get(tool), relevant_pr_user, pr_reviewer), 'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number), 'assignees': assignees, 'labels': ['T-compiler', 'I-nominated'], @@ -137,7 +142,7 @@ def update_latest( if build_failed: try: issue( - tool, MAINTAINERS.get(tool), + tool, MAINTAINERS.get(tool, ''), relevant_pr_number, relevant_pr_user, pr_reviewer, ) except IOError as e: