diff options
757 files changed, 17728 insertions, 5059 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3c95226aeb..355f2829215 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -102,9 +102,6 @@ jobs: - name: install MSYS2 run: src/ci/scripts/install-msys2.sh if: success() && !env.SKIP_JOB - - name: install MSYS2 packages - run: src/ci/scripts/install-msys2-packages.sh - if: success() && !env.SKIP_JOB - name: install MinGW run: src/ci/scripts/install-mingw.sh if: success() && !env.SKIP_JOB @@ -212,9 +209,6 @@ jobs: - name: install MSYS2 run: src/ci/scripts/install-msys2.sh if: success() && !env.SKIP_JOB - - name: install MSYS2 packages - run: src/ci/scripts/install-msys2-packages.sh - if: success() && !env.SKIP_JOB - name: install MinGW run: src/ci/scripts/install-mingw.sh if: success() && !env.SKIP_JOB @@ -564,9 +558,6 @@ jobs: - name: install MSYS2 run: src/ci/scripts/install-msys2.sh if: success() && !env.SKIP_JOB - - name: install MSYS2 packages - run: src/ci/scripts/install-msys2-packages.sh - if: success() && !env.SKIP_JOB - name: install MinGW run: src/ci/scripts/install-mingw.sh if: success() && !env.SKIP_JOB diff --git a/.mailmap b/.mailmap index 9639c117496..15ca403456a 100644 --- a/.mailmap +++ b/.mailmap @@ -266,6 +266,7 @@ Tim Chevalier <chevalier@alum.wellesley.edu> <catamorphism@gmail.com> Tim JIANG <p90eri@gmail.com> Tim Joseph Dumol <tim@timdumol.com> Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com> +Trevor Spiteri <tspiteri@ieee.org> <trevor.spiteri@um.edu.mt> Ty Overby <ty@pre-alpha.com> Ulrik Sverdrup <bluss@users.noreply.github.com> bluss <bluss@users.noreply.github.com> Ulrik Sverdrup <bluss@users.noreply.github.com> bluss <bluss> diff --git a/Cargo.lock b/Cargo.lock index 07c354a3324..bbbcf797f75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,6 +49,12 @@ dependencies = [ ] [[package]] +name = "annotate-snippets" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5" + +[[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -276,7 +282,7 @@ checksum = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010" [[package]] name = "cargo" -version = "0.46.0" +version = "0.47.0" dependencies = [ "anyhow", "atty", @@ -636,9 +642,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702af8463c84fd83dd76a307ebd47ab3cc866e847bebd4a1deeb6bcc4a658327" +checksum = "7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c" dependencies = [ "cc", "rustc-std-workspace-core", @@ -1842,9 +1848,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.12.5+1.0.0" +version = "0.12.7+1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eadeec65514971355bf7134967a543f71372f35b53ac6c7143e7bd157f07535" +checksum = "bcd07968649bcb7b9351ecfde53ca4d27673cccfdf57c84255ec18710f3153e0" dependencies = [ "cc", "libc", @@ -3316,7 +3322,7 @@ version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c374e89b3c9714869ef86076942155383804ba6778c26be2169d324563c31f9" dependencies = [ - "annotate-snippets", + "annotate-snippets 0.6.1", "atty", "log", "rustc-ap-rustc_data_structures", @@ -3810,7 +3816,7 @@ version = "0.0.0" name = "rustc_errors" version = "0.0.0" dependencies = [ - "annotate-snippets", + "annotate-snippets 0.8.0", "atty", "log", "rustc_data_structures", @@ -4477,7 +4483,7 @@ dependencies = [ name = "rustfmt-nightly" version = "1.4.15" dependencies = [ - "annotate-snippets", + "annotate-snippets 0.6.1", "bytecount", "cargo_metadata 0.8.0", "derive-new", diff --git a/RELEASES.md b/RELEASES.md index a37379330db..3ae3417a9b4 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -25,7 +25,7 @@ Compiler -------- - [Rustc now respects the `-C codegen-units` flag in incremental mode.][70156] Additionally when in incremental mode rustc defaults to 256 codegen units. -- [Refactored `catch_unwind`, to have zero-cost unless unwinding is enabled and +- [Refactored `catch_unwind` to have zero-cost, unless unwinding is enabled and a panic is thrown.][67502] - [Added tier 3\* support for the `aarch64-unknown-none` and `aarch64-unknown-none-softfloat` targets.][68334] diff --git a/config.toml.example b/config.toml.example index cf8fe4e082a..d995554913f 100644 --- a/config.toml.example +++ b/config.toml.example @@ -69,7 +69,7 @@ # the same format as above, but since these targets are experimental, they are # not built by default and the experimental Rust compilation targets that depend # on them will not work unless the user opts in to building them. -#experimental-targets = "" +#experimental-targets = "AVR" # Cap the number of parallel linker invocations when compiling LLVM. # This can be useful when building LLVM with debug info, which significantly diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ffdd8485181..c4f29927cf4 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -52,6 +52,8 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { /// it's been assembled. type Output: Clone; + /// Whether this step is run by default as part of its respective phase. + /// `true` here can still be overwritten by `should_run` calling `default_condition`. const DEFAULT: bool = false; /// If true, then this rule should be skipped if --target was specified, but --host was not diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index a236edf971f..ab16ca3732c 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -37,7 +37,9 @@ use crate::{Build, GitRepo}; // try to infer the archiver path from the C compiler path. // In the future this logic should be replaced by calling into the `cc` crate. fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> { - if let Some(ar) = env::var_os("AR") { + if let Some(ar) = env::var_os(format!("AR_{}", target.replace("-", "_"))) { + Some(PathBuf::from(ar)) + } else if let Some(ar) = env::var_os("AR") { Some(PathBuf::from(ar)) } else if target.contains("msvc") { None diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index b3999118e3d..c09b73b0420 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -983,7 +983,13 @@ pub fn stream_cargo( for line in stdout.lines() { let line = t!(line); match serde_json::from_str::<CargoMessage<'_>>(&line) { - Ok(msg) => cb(msg), + Ok(msg) => { + if builder.config.json_output { + // Forward JSON to stdout. + println!("{}", line); + } + cb(msg) + } // If this was informational, just print it out and continue Err(_) => println!("{}", line), } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 5b6e9534843..252a6316e57 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -144,7 +144,7 @@ impl Step for Llvm { let llvm_exp_targets = match builder.config.llvm_experimental_targets { Some(ref s) => s, - None => "", + None => "AVR", }; let assertions = if builder.config.llvm_assertions { "ON" } else { "OFF" }; diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index a99e39ed354..aeabb227cf5 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -154,6 +154,7 @@ impl Step for Cargotest { fn run(self, builder: &Builder<'_>) { let compiler = builder.compiler(self.stage, self.host); builder.ensure(compile::Rustc { compiler, target: compiler.host }); + let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host }); // Note that this is a short, cryptic, and not scoped directory name. This // is currently to minimize the length of path on Windows where we otherwise @@ -165,7 +166,7 @@ impl Step for Cargotest { let mut cmd = builder.tool_cmd(Tool::CargoTest); try_run( builder, - cmd.arg(&builder.initial_cargo) + cmd.arg(&cargo) .arg(&out_dir) .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler)), @@ -553,7 +554,7 @@ impl Step for Clippy { builder.add_rustc_lib_path(compiler, &mut cargo); - try_run(builder, &mut cargo.into()); + builder.run(&mut cargo.into()); } } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 6cd9f9029c9..9c95de0a81e 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -595,6 +595,7 @@ macro_rules! tool_extended { $toolstate:ident, $path:expr, $tool_name:expr, + stable = $stable:expr, $extra_deps:block;)+) => { $( #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -606,17 +607,22 @@ macro_rules! tool_extended { impl Step for $name { type Output = Option<PathBuf>; - const DEFAULT: bool = true; + const DEFAULT: bool = true; // Overwritten below const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; run.path($path).default_condition( builder.config.extended - && builder.config.tools.as_ref().map_or(true, |tools| { - tools.iter().any(|tool| match tool.as_ref() { - "clippy" => $tool_name == "clippy-driver", - x => $tool_name == x, + && builder.config.tools.as_ref().map_or( + // By default, on nightly/dev enable all tools, else only + // build stable tools. + $stable || builder.build.unstable_features(), + // If `tools` is set, search list for this tool. + |tools| { + tools.iter().any(|tool| match tool.as_ref() { + "clippy" => $tool_name == "clippy-driver", + x => $tool_name == x, }) }), ) @@ -652,12 +658,12 @@ macro_rules! tool_extended { // Note: tools need to be also added to `Builder::get_step_descriptions` in `build.rs` // to make `./x.py build <tool>` work. tool_extended!((self, builder), - Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", {}; - CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", {}; - Clippy, clippy, "src/tools/clippy", "clippy-driver", {}; - Miri, miri, "src/tools/miri", "miri", {}; - CargoMiri, miri, "src/tools/miri/cargo-miri", "cargo-miri", {}; - Rls, rls, "src/tools/rls", "rls", { + Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", stable=true, {}; + CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", stable=true, {}; + Clippy, clippy, "src/tools/clippy", "clippy-driver", stable=true, {}; + Miri, miri, "src/tools/miri", "miri", stable=false, {}; + CargoMiri, miri, "src/tools/miri/cargo-miri", "cargo-miri", stable=false, {}; + Rls, rls, "src/tools/rls", "rls", stable=true, { builder.ensure(Clippy { compiler: self.compiler, target: self.target, @@ -665,7 +671,7 @@ tool_extended!((self, builder), }); self.extra_features.push("clippy".to_owned()); }; - Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", {}; + Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, {}; ); impl<'a> Builder<'a> { diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml index 85ff3e52a84..e43116c06b6 100644 --- a/src/ci/azure-pipelines/steps/run.yml +++ b/src/ci/azure-pipelines/steps/run.yml @@ -82,10 +82,6 @@ steps: displayName: Install msys2 condition: and(succeeded(), not(variables.SKIP_JOB)) -- bash: src/ci/scripts/install-msys2-packages.sh - displayName: Install msys2 packages - condition: and(succeeded(), not(variables.SKIP_JOB)) - - bash: src/ci/scripts/install-mingw.sh displayName: Install MinGW condition: and(succeeded(), not(variables.SKIP_JOB)) diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile index 5864b5ffab2..43f5581f996 100644 --- a/src/ci/docker/dist-various-2/Dockerfile +++ b/src/ci/docker/dist-various-2/Dockerfile @@ -28,6 +28,29 @@ RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y --no RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7924C5513486 RUN add-apt-repository -y 'deb http://apt.dilos.org/dilos dilos2 main' +ENV \ + AR_x86_64_fuchsia=x86_64-fuchsia-ar \ + CC_x86_64_fuchsia=x86_64-fuchsia-clang \ + CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \ + AR_aarch64_fuchsia=aarch64-fuchsia-ar \ + CC_aarch64_fuchsia=aarch64-fuchsia-clang \ + CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \ + AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \ + CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \ + CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \ + AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \ + CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \ + CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \ + CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-7 \ + CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-7 \ + AR_x86_64_fortanix_unknown_sgx=ar \ + CC_x86_64_fortanix_unknown_sgx=x86_64-fortanix-unknown-sgx-clang-11 \ + CFLAGS_x86_64_fortanix_unknown_sgx="-mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ + CXX_x86_64_fortanix_unknown_sgx=x86_64-fortanix-unknown-sgx-clang++-11 \ + CXXFLAGS_x86_64_fortanix_unknown_sgx="-mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ + CC=gcc-7 \ + CXX=g++-7 + WORKDIR /build COPY scripts/musl.sh /build RUN env \ @@ -46,9 +69,11 @@ COPY dist-various-2/build-solaris-toolchain.sh /tmp/ RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/ +COPY dist-various-2/x86_64-fortanix-unknown-sgx-clang-wrap.sh /usr/bin/x86_64-fortanix-unknown-sgx-clang-11 +RUN ln -s /usr/bin/x86_64-fortanix-unknown-sgx-clang-11 /usr/bin/x86_64-fortanix-unknown-sgx-clang++-11 # We pass the commit id of the port of LLVM's libunwind to the build script. # Any update to the commit id here, should cause the container image to be re-built from this point on. -RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "5125c169b30837208a842f85f7ae44a83533bd0e" +RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "800f95131fe6acd20b96b6f4723ca3c820f3d379" COPY dist-various-2/build-wasi-toolchain.sh /tmp/ RUN /tmp/build-wasi-toolchain.sh @@ -56,24 +81,6 @@ RUN /tmp/build-wasi-toolchain.sh COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV \ - AR_x86_64_fuchsia=x86_64-fuchsia-ar \ - CC_x86_64_fuchsia=x86_64-fuchsia-clang \ - CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \ - AR_aarch64_fuchsia=aarch64-fuchsia-ar \ - CC_aarch64_fuchsia=aarch64-fuchsia-clang \ - CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \ - AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \ - CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \ - CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \ - AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \ - CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \ - CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \ - CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-7 \ - CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-7 \ - CC=gcc-7 \ - CXX=g++-7 - ENV CARGO_TARGET_X86_64_FUCHSIA_AR /usr/local/bin/llvm-ar ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \ -C link-arg=--sysroot=/usr/local/x86_64-fuchsia \ diff --git a/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh b/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh index 725ec341b94..4294b1ef93d 100755 --- a/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh @@ -13,12 +13,15 @@ url="https://github.com/fortanix/llvm-project/archive/${1}.tar.gz" repo_name="llvm-project" install_prereq() { + curl https://apt.llvm.org/llvm-snapshot.gpg.key|apt-key add - + add-apt-repository -y 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main' apt-get update apt-get install -y --no-install-recommends \ build-essential \ ca-certificates \ cmake \ - git + git \ + clang-11 } build_unwind() { @@ -35,7 +38,14 @@ build_unwind() { # Build libunwind mkdir -p build cd build + target_CC="CC_${target//-/_}" + target_CXX="CXX_${target//-/_}" + target_CFLAGS="CFLAGS_${target//-/_}" + target_CXXFLAGS="CXXFLAGS_${target//-/_}" cmake -DCMAKE_BUILD_TYPE="RELEASE" -DRUST_SGX=1 -G "Unix Makefiles" \ + -DCMAKE_C_COMPILER="${!target_CC}" -DCMAKE_CXX_COMPILER="${!target_CXX}" \ + -DCMAKE_C_FLAGS="${!target_CFLAGS}" -DCMAKE_CXX_FLAGS="${!target_CXXFLAGS}" \ + -DCMAKE_C_COMPILER_TARGET=$target -DCMAKE_CXX_COMPILER_TARGET=$target \ -DLLVM_ENABLE_WARNINGS=1 -DLIBUNWIND_ENABLE_WERROR=1 -DLIBUNWIND_ENABLE_PEDANTIC=0 \ -DLLVM_PATH=../../llvm/ ../ make unwind_static diff --git a/src/ci/docker/dist-various-2/x86_64-fortanix-unknown-sgx-clang-wrap.sh b/src/ci/docker/dist-various-2/x86_64-fortanix-unknown-sgx-clang-wrap.sh new file mode 100755 index 00000000000..c4ff44c37b1 --- /dev/null +++ b/src/ci/docker/dist-various-2/x86_64-fortanix-unknown-sgx-clang-wrap.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +args=("$@") + +for i in "${!args[@]}"; do + # x86_64-fortanix-unknown-sgx doesn't have a C sysroot for things like + # stdint.h and the C++ STL. Unlike GCC, clang will not use the host's + # sysroot instead. Force it. + if [ "${args[$i]}" = "--target=x86_64-fortanix-unknown-sgx" ]; then + args[$i]="--target=x86_64-unknown-linux-gnu" + fi +done + +exec "${0/x86_64-fortanix-unknown-sgx-clang/clang}" "${args[@]}" diff --git a/src/ci/docker/scripts/musl-toolchain.sh b/src/ci/docker/scripts/musl-toolchain.sh index 74ba2f0eadb..1ae412340cb 100644 --- a/src/ci/docker/scripts/musl-toolchain.sh +++ b/src/ci/docker/scripts/musl-toolchain.sh @@ -3,7 +3,7 @@ # # Versions of the toolchain components are configurable in `musl-cross-make/Makefile` and # musl unlike GLIBC is forward compatible so upgrading it shouldn't break old distributions. -# Right now we have: Binutils 2.27, GCC 6.4.0, musl 1.1.22. +# Right now we have: Binutils 2.31.1, GCC 9.2.0, musl 1.1.24. set -ex hide_output() { @@ -33,11 +33,13 @@ shift # Apparently applying `-fPIC` everywhere allows them to link successfully. export CFLAGS="-fPIC $CFLAGS" -git clone https://github.com/richfelker/musl-cross-make -b v0.9.8 +git clone https://github.com/richfelker/musl-cross-make # -b v0.9.9 cd musl-cross-make +# A few commits ahead of v0.9.9 to include the cowpatch fix: +git checkout a54eb56f33f255dfca60be045f12a5cfaf5a72a9 -hide_output make -j$(nproc) TARGET=$TARGET -hide_output make install TARGET=$TARGET OUTPUT=$OUTPUT +hide_output make -j$(nproc) TARGET=$TARGET MUSL_VER=1.1.24 +hide_output make install TARGET=$TARGET MUSL_VER=1.1.24 OUTPUT=$OUTPUT cd - diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index d847c407aba..58393a5719a 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -24,7 +24,7 @@ shift # Apparently applying `-fPIC` everywhere allows them to link successfully. export CFLAGS="-fPIC $CFLAGS" -MUSL=musl-1.1.22 +MUSL=musl-1.1.24 # may have been downloaded in a previous run if [ ! -d $MUSL ]; then diff --git a/src/ci/docker/wasm32/Dockerfile b/src/ci/docker/wasm32/Dockerfile index 91c492d03c1..8232539edda 100644 --- a/src/ci/docker/wasm32/Dockerfile +++ b/src/ci/docker/wasm32/Dockerfile @@ -27,6 +27,9 @@ ENV PATH=$PATH:/emsdk-portable ENV PATH=$PATH:/emsdk-portable/upstream/emscripten/ ENV PATH=$PATH:/emsdk-portable/node/12.9.1_64bit/bin/ ENV BINARYEN_ROOT=/emsdk-portable/upstream/ +ENV EMSDK=/emsdk-portable +ENV EM_CONFIG=/emsdk-portable/.emscripten +ENV EM_CACHE=/emsdk-portable/upstream/emscripten/cache ENV TARGETS=wasm32-unknown-emscripten diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 92fec593a54..590845b33cd 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -147,10 +147,6 @@ x--expand-yaml-anchors--remove: run: src/ci/scripts/install-msys2.sh <<: *step - - name: install MSYS2 packages - run: src/ci/scripts/install-msys2-packages.sh - <<: *step - - name: install MinGW run: src/ci/scripts/install-mingw.sh <<: *step diff --git a/src/ci/scripts/install-msys2-packages.sh b/src/ci/scripts/install-msys2-packages.sh deleted file mode 100755 index ff7479c05d0..00000000000 --- a/src/ci/scripts/install-msys2-packages.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -set -euo pipefail -IFS=$'\n\t' - -source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" - -if isWindows; then - pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar \ - binutils - - # Detect the native Python version installed on the agent. On GitHub - # Actions, the C:\hostedtoolcache\windows\Python directory contains a - # subdirectory for each installed Python version. - # - # The -V flag of the sort command sorts the input by version number. - native_python_version="$(ls /c/hostedtoolcache/windows/Python | sort -Vr | head -n 1)" - - # Make sure we use the native python interpreter instead of some msys equivalent - # one way or another. The msys interpreters seem to have weird path conversions - # baked in which break LLVM's build system one way or another, so let's use the - # native version which keeps everything as native as possible. - python_home="/c/hostedtoolcache/windows/Python/${native_python_version}/x64" - cp "${python_home}/python.exe" "${python_home}/python3.exe" - ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64" - ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64\\Scripts" -fi diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh index 3c3b5007f86..3a0c965a677 100755 --- a/src/ci/scripts/install-msys2.sh +++ b/src/ci/scripts/install-msys2.sh @@ -1,10 +1,6 @@ #!/bin/bash # Download and install MSYS2, needed primarily for the test suite (run-make) but # also used by the MinGW toolchain for assembling things. -# -# FIXME: we should probe the default azure image and see if we can use the MSYS2 -# toolchain there. (if there's even one there). For now though this gets the job -# done. set -euo pipefail IFS=$'\n\t' @@ -12,17 +8,26 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isWindows; then - # Pre-followed the api/v2 URL to the CDN since the API can be a bit flakey - curl -sSL https://packages.chocolatey.org/msys2.20190524.0.0.20191030.nupkg > \ - msys2.nupkg - curl -sSL https://packages.chocolatey.org/chocolatey-core.extension.1.3.5.1.nupkg > \ - chocolatey-core.extension.nupkg - choco install -s . msys2 \ - --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath" -y --no-progress - rm msys2.nupkg chocolatey-core.extension.nupkg - mkdir -p "$(ciCheckoutPath)/msys2/home/${USERNAME}" - ciCommandAddPath "$(ciCheckoutPath)/msys2/usr/bin" + msys2Path="c:/msys64" + mkdir -p "${msys2Path}/home/${USERNAME}" + ciCommandAddPath "${msys2Path}/usr/bin" echo "switching shell to use our own bash" - ciCommandSetEnv CI_OVERRIDE_SHELL "$(ciCheckoutPath)/msys2/usr/bin/bash.exe" + ciCommandSetEnv CI_OVERRIDE_SHELL "${msys2Path}/usr/bin/bash.exe" + + # Detect the native Python version installed on the agent. On GitHub + # Actions, the C:\hostedtoolcache\windows\Python directory contains a + # subdirectory for each installed Python version. + # + # The -V flag of the sort command sorts the input by version number. + native_python_version="$(ls /c/hostedtoolcache/windows/Python | sort -Vr | head -n 1)" + + # Make sure we use the native python interpreter instead of some msys equivalent + # one way or another. The msys interpreters seem to have weird path conversions + # baked in which break LLVM's build system one way or another, so let's use the + # native version which keeps everything as native as possible. + python_home="/c/hostedtoolcache/windows/Python/${native_python_version}/x64" + cp "${python_home}/python.exe" "${python_home}/python3.exe" + ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64" + ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64\\Scripts" fi diff --git a/src/doc/book b/src/doc/book -Subproject e8a4714a9d8a6136a59b8e63544e149683876e3 +Subproject 30cd9dfe71c446de63826bb4472627af45acc9d diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject 0a8ab5046829733eb03df0738c4fafaa9b36b34 +Subproject 82bec5877c77cfad530ca11095db4456d757f66 diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject d1517d4e3f29264c5c67bce2658516bb5202c80 +Subproject bfe1ab96d717d1dda50e499b360f2e2f57e1750 diff --git a/src/doc/reference b/src/doc/reference -Subproject becdca9477c9eafa96a4eea5156fe7a2730d9dd +Subproject 5d40ba5c2515caffa7790cda621239dc21ef5a7 diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index efadae1c5fb..18010bebcf0 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -416,7 +416,7 @@ without including it in your main documentation. For example, you could write th `lib.rs` to test your README as part of your doctests: ```rust,ignore -#![feature(extern_doc)] +#![feature(external_doc)] #[doc(include="../README.md")] #[cfg(doctest)] diff --git a/src/doc/unstable-book/src/compiler-flags/profile.md b/src/doc/unstable-book/src/compiler-flags/profile.md index 452aca51532..7973b3e4f2f 100644 --- a/src/doc/unstable-book/src/compiler-flags/profile.md +++ b/src/doc/unstable-book/src/compiler-flags/profile.md @@ -12,10 +12,16 @@ For example: ```Bash cargo new testgcov --bin cd testgcov -export RUSTFLAGS="-Zprofile" +export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" +export CARGO_INCREMENTAL=0 cargo build cargo run ``` Once you've built and run your program, files with the `gcno` (after build) and `gcda` (after execution) extensions will be created. You can parse them with [llvm-cov gcov](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/mozilla/grcov). + +Please note that `RUSTFLAGS` by default applies to everything that cargo builds and runs during a build! +When the `--target` flag is explicitly passed to cargo, the `RUSTFLAGS` no longer apply to build scripts and procedural macros. +For more fine-grained control consider passing a `RUSTC_WRAPPER` program to cargo that only adds the profiling flags to +rustc for the specific crates you want to profile. diff --git a/src/doc/unstable-book/src/compiler-flags/report-time.md b/src/doc/unstable-book/src/compiler-flags/report-time.md index ed4e9c6b568..68265d8a9e8 100644 --- a/src/doc/unstable-book/src/compiler-flags/report-time.md +++ b/src/doc/unstable-book/src/compiler-flags/report-time.md @@ -22,7 +22,7 @@ Available options: ```sh --report-time [plain|colored] - Show execution time of each test. Awailable values: + Show execution time of each test. Available values: plain = do not colorize the execution time (default); colored = colorize output according to the `color` parameter value; diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index ea560a6d709..fbb40f1d2f3 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -201,7 +201,7 @@ fn mul(a: u64, b: u64) -> u128 { ); } - (hi as u128) << 64 + lo as u128 + ((hi as u128) << 64) + lo as u128 } ``` @@ -382,7 +382,9 @@ The macro will initially be supported only on ARM, AArch64, x86, x86-64 and RISC The assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported. -As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after any named arguments if any. Explicit register operands cannot be used by placeholders in the template string. All other operands must appear at least once in the template string, otherwise a compiler error is generated. +As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any. + +Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated. The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler. diff --git a/src/doc/unstable-book/src/library-features/default-free-fn.md b/src/doc/unstable-book/src/library-features/default-free-fn.md new file mode 100644 index 00000000000..5dff73a94dd --- /dev/null +++ b/src/doc/unstable-book/src/library-features/default-free-fn.md @@ -0,0 +1,45 @@ +# `default_free_fn` + +The tracking issue for this feature is: [#73014] + +[#73014]: https://github.com/rust-lang/rust/issues/73014 + +------------------------ + +Adds a free `default()` function to the `std::default` module. This function +just forwards to [`Default::default()`], but may remove repetition of the word +"default" from the call site. + +Here is an example: + +```rust +#![feature(default_free_fn)] +use std::default::default; + +#[derive(Default)] +struct AppConfig { + foo: FooConfig, + bar: BarConfig, +} + +#[derive(Default)] +struct FooConfig { + foo: i32, +} + +#[derive(Default)] +struct BarConfig { + bar: f32, + baz: u8, +} + +fn main() { + let options = AppConfig { + foo: default(), + bar: BarConfig { + bar: 10.1, + ..default() + }, + }; +} +``` diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 56e284a12fa..805dbfe2775 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -9,7 +9,7 @@ use core::ptr::{NonNull, Unique}; use core::slice; use crate::alloc::{ - handle_alloc_error, AllocErr, + handle_alloc_error, AllocInit::{self, *}, AllocRef, Global, Layout, ReallocPlacement::{self, *}, @@ -118,6 +118,30 @@ impl<T> RawVec<T, Global> { RawVec::from_raw_parts(slice.as_mut_ptr(), slice.len()) } } + + /// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`. + /// + /// Note that this will correctly reconstitute any `cap` changes + /// that may have been performed. (See description of type for details.) + /// + /// # Safety + /// + /// * `len` must be greater than or equal to the most recently requested capacity, and + /// * `len` must be less than or equal to `self.capacity()`. + /// + /// Note, that the requested capacity and `self.capacity()` could differ, as + /// an allocator could overallocate and return a greater memory block than requested. + pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>]> { + // Sanity-check one half of the safety requirement (we cannot check the other half). + debug_assert!( + len <= self.capacity(), + "`len` must be smaller than or equal to `self.capacity()`" + ); + + let me = ManuallyDrop::new(self); + let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len); + Box::from_raw(slice) + } } impl<T, A: AllocRef> RawVec<T, A> { @@ -211,13 +235,13 @@ impl<T, A: AllocRef> RawVec<T, A> { } } - /// Ensures that the buffer contains at least enough space to hold - /// `used_capacity + needed_extra_capacity` elements. If it doesn't already have - /// enough capacity, will reallocate enough space plus comfortable slack - /// space to get amortized `O(1)` behavior. Will limit this behavior - /// if it would needlessly cause itself to panic. + /// Ensures that the buffer contains at least enough space to hold `len + + /// additional` elements. If it doesn't already have enough capacity, will + /// reallocate enough space plus comfortable slack space to get amortized + /// `O(1)` behavior. Will limit this behavior if it would needlessly cause + /// itself to panic. /// - /// If `used_capacity` exceeds `self.capacity()`, this may fail to actually allocate + /// If `len` exceeds `self.capacity()`, this may fail to actually allocate /// the requested space. This is not really unsafe, but the unsafe /// code *you* write that relies on the behavior of this function may break. /// @@ -263,8 +287,8 @@ impl<T, A: AllocRef> RawVec<T, A> { /// # vector.push_all(&[1, 3, 5, 7, 9]); /// # } /// ``` - pub fn reserve(&mut self, used_capacity: usize, needed_extra_capacity: usize) { - match self.try_reserve(used_capacity, needed_extra_capacity) { + pub fn reserve(&mut self, len: usize, additional: usize) { + match self.try_reserve(len, additional) { Err(CapacityOverflow) => capacity_overflow(), Err(AllocError { layout, .. }) => handle_alloc_error(layout), Ok(()) => { /* yay */ } @@ -272,55 +296,23 @@ impl<T, A: AllocRef> RawVec<T, A> { } /// The same as `reserve`, but returns on errors instead of panicking or aborting. - pub fn try_reserve( - &mut self, - used_capacity: usize, - needed_extra_capacity: usize, - ) -> Result<(), TryReserveError> { - if self.needs_to_grow(used_capacity, needed_extra_capacity) { - self.grow_amortized(used_capacity, needed_extra_capacity, MayMove) + pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { + if self.needs_to_grow(len, additional) { + self.grow_amortized(len, additional) } else { Ok(()) } } - /// Attempts to ensure that the buffer contains at least enough space to hold - /// `used_capacity + needed_extra_capacity` elements. If it doesn't already have - /// enough capacity, will reallocate in place enough space plus comfortable slack - /// space to get amortized `O(1)` behavior. Will limit this behaviour - /// if it would needlessly cause itself to panic. + /// Ensures that the buffer contains at least enough space to hold `len + + /// additional` elements. If it doesn't already, will reallocate the + /// minimum possible amount of memory necessary. Generally this will be + /// exactly the amount of memory necessary, but in principle the allocator + /// is free to give back more than we asked for. /// - /// If `used_capacity` exceeds `self.capacity()`, this may fail to actually allocate - /// the requested space. This is not really unsafe, but the unsafe - /// code *you* write that relies on the behavior of this function may break. - /// - /// Returns `true` if the reallocation attempt has succeeded. - /// - /// # Panics - /// - /// * Panics if the requested capacity exceeds `usize::MAX` bytes. - /// * Panics on 32-bit platforms if the requested capacity exceeds - /// `isize::MAX` bytes. - pub fn reserve_in_place(&mut self, used_capacity: usize, needed_extra_capacity: usize) -> bool { - // This is more readable than putting this in one line: - // `!self.needs_to_grow(...) || self.grow(...).is_ok()` - if self.needs_to_grow(used_capacity, needed_extra_capacity) { - self.grow_amortized(used_capacity, needed_extra_capacity, InPlace).is_ok() - } else { - true - } - } - - /// Ensures that the buffer contains at least enough space to hold - /// `used_capacity + needed_extra_capacity` elements. If it doesn't already, - /// will reallocate the minimum possible amount of memory necessary. - /// Generally this will be exactly the amount of memory necessary, - /// but in principle the allocator is free to give back more than what - /// we asked for. - /// - /// If `used_capacity` exceeds `self.capacity()`, this may fail to actually allocate - /// the requested space. This is not really unsafe, but the unsafe - /// code *you* write that relies on the behavior of this function may break. + /// If `len` exceeds `self.capacity()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe code + /// *you* write that relies on the behavior of this function may break. /// /// # Panics /// @@ -331,8 +323,8 @@ impl<T, A: AllocRef> RawVec<T, A> { /// # Aborts /// /// Aborts on OOM. - pub fn reserve_exact(&mut self, used_capacity: usize, needed_extra_capacity: usize) { - match self.try_reserve_exact(used_capacity, needed_extra_capacity) { + pub fn reserve_exact(&mut self, len: usize, additional: usize) { + match self.try_reserve_exact(len, additional) { Err(CapacityOverflow) => capacity_overflow(), Err(AllocError { layout, .. }) => handle_alloc_error(layout), Ok(()) => { /* yay */ } @@ -342,14 +334,10 @@ impl<T, A: AllocRef> RawVec<T, A> { /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. pub fn try_reserve_exact( &mut self, - used_capacity: usize, - needed_extra_capacity: usize, + len: usize, + additional: usize, ) -> Result<(), TryReserveError> { - if self.needs_to_grow(used_capacity, needed_extra_capacity) { - self.grow_exact(used_capacity, needed_extra_capacity) - } else { - Ok(()) - } + if self.needs_to_grow(len, additional) { self.grow_exact(len, additional) } else { Ok(()) } } /// Shrinks the allocation down to the specified amount. If the given amount @@ -374,8 +362,8 @@ impl<T, A: AllocRef> RawVec<T, A> { impl<T, A: AllocRef> RawVec<T, A> { /// Returns if the buffer needs to grow to fulfill the needed extra capacity. /// Mainly used to make inlining reserve-calls possible without inlining `grow`. - fn needs_to_grow(&self, used_capacity: usize, needed_extra_capacity: usize) -> bool { - needed_extra_capacity > self.capacity().wrapping_sub(used_capacity) + fn needs_to_grow(&self, len: usize, additional: usize) -> bool { + additional > self.capacity().wrapping_sub(len) } fn capacity_from_bytes(excess: usize) -> usize { @@ -395,14 +383,9 @@ impl<T, A: AllocRef> RawVec<T, A> { // so that all of the code that depends on `T` is within it, while as much // of the code that doesn't depend on `T` as possible is in functions that // are non-generic over `T`. - fn grow_amortized( - &mut self, - used_capacity: usize, - needed_extra_capacity: usize, - placement: ReallocPlacement, - ) -> Result<(), TryReserveError> { + fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { // This is ensured by the calling contexts. - debug_assert!(needed_extra_capacity > 0); + debug_assert!(additional > 0); if mem::size_of::<T>() == 0 { // Since we return a capacity of `usize::MAX` when `elem_size` is @@ -411,8 +394,7 @@ impl<T, A: AllocRef> RawVec<T, A> { } // Nothing we can really do about these checks, sadly. - let required_cap = - used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?; + let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; // This guarantees exponential growth. The doubling cannot overflow // because `cap <= isize::MAX` and the type of `cap` is `usize`. @@ -437,7 +419,7 @@ impl<T, A: AllocRef> RawVec<T, A> { let new_layout = Layout::array::<T>(cap); // `finish_grow` is non-generic over `T`. - let memory = finish_grow(new_layout, placement, self.current_memory(), &mut self.alloc)?; + let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; self.set_memory(memory); Ok(()) } @@ -445,22 +427,18 @@ impl<T, A: AllocRef> RawVec<T, A> { // The constraints on this method are much the same as those on // `grow_amortized`, but this method is usually instantiated less often so // it's less critical. - fn grow_exact( - &mut self, - used_capacity: usize, - needed_extra_capacity: usize, - ) -> Result<(), TryReserveError> { + fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { if mem::size_of::<T>() == 0 { // Since we return a capacity of `usize::MAX` when the type size is // 0, getting to here necessarily means the `RawVec` is overfull. return Err(CapacityOverflow); } - let cap = used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?; + let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; let new_layout = Layout::array::<T>(cap); // `finish_grow` is non-generic over `T`. - let memory = finish_grow(new_layout, MayMove, self.current_memory(), &mut self.alloc)?; + let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; self.set_memory(memory); Ok(()) } @@ -494,7 +472,6 @@ impl<T, A: AllocRef> RawVec<T, A> { // much smaller than the number of `T` types.) fn finish_grow<A>( new_layout: Result<Layout, LayoutErr>, - placement: ReallocPlacement, current_memory: Option<(NonNull<u8>, Layout)>, alloc: &mut A, ) -> Result<MemoryBlock, TryReserveError> @@ -508,44 +485,15 @@ where let memory = if let Some((ptr, old_layout)) = current_memory { debug_assert_eq!(old_layout.align(), new_layout.align()); - unsafe { alloc.grow(ptr, old_layout, new_layout.size(), placement, Uninitialized) } + unsafe { alloc.grow(ptr, old_layout, new_layout.size(), MayMove, Uninitialized) } } else { - match placement { - MayMove => alloc.alloc(new_layout, Uninitialized), - InPlace => Err(AllocErr), - } + alloc.alloc(new_layout, Uninitialized) } .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?; Ok(memory) } -impl<T> RawVec<T, Global> { - /// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`. - /// - /// Note that this will correctly reconstitute any `cap` changes - /// that may have been performed. (See description of type for details.) - /// - /// # Safety - /// - /// * `len` must be greater than or equal to the most recently requested capacity, and - /// * `len` must be less than or equal to `self.capacity()`. - /// - /// Note, that the requested capacity and `self.capacity()` could differ, as - /// an allocator could overallocate and return a greater memory block than requested. - pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>]> { - // Sanity-check one half of the safety requirement (we cannot check the other half). - debug_assert!( - len <= self.capacity(), - "`len` must be smaller than or equal to `self.capacity()`" - ); - - let me = ManuallyDrop::new(self); - let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len); - Box::from_raw(slice) - } -} - unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec<T, A> { /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. fn drop(&mut self) { diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 925bc7d3c02..0327a9f9a96 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -2034,7 +2034,7 @@ trait RcBoxPtr<T: ?Sized> { // The reference count will never be zero when this is called; // nevertheless, we insert an abort here to hint LLVM at // an otherwise missed optimization. - if strong == 0 || strong == usize::max_value() { + if strong == 0 || strong == usize::MAX { abort(); } self.inner().strong.set(strong + 1); @@ -2058,7 +2058,7 @@ trait RcBoxPtr<T: ?Sized> { // The reference count will never be zero when this is called; // nevertheless, we insert an abort here to hint LLVM at // an otherwise missed optimization. - if weak == 0 || weak == usize::max_value() { + if weak == 0 || weak == usize::MAX { abort(); } self.inner().weak.set(weak + 1); diff --git a/src/liballoc/rc/tests.rs b/src/liballoc/rc/tests.rs index 56788bb56d5..e88385faf4f 100644 --- a/src/liballoc/rc/tests.rs +++ b/src/liballoc/rc/tests.rs @@ -407,14 +407,14 @@ fn test_from_vec() { fn test_downcast() { use std::any::Any; - let r1: Rc<dyn Any> = Rc::new(i32::max_value()); + let r1: Rc<dyn Any> = Rc::new(i32::MAX); let r2: Rc<dyn Any> = Rc::new("abc"); assert!(r1.clone().downcast::<u32>().is_err()); let r1i32 = r1.downcast::<i32>(); assert!(r1i32.is_ok()); - assert_eq!(r1i32.unwrap(), Rc::new(i32::max_value())); + assert_eq!(r1i32.unwrap(), Rc::new(i32::MAX)); assert!(r2.clone().downcast::<i32>().is_err()); diff --git a/src/liballoc/sync/tests.rs b/src/liballoc/sync/tests.rs index a2bb651e2b7..6f08cd7f123 100644 --- a/src/liballoc/sync/tests.rs +++ b/src/liballoc/sync/tests.rs @@ -465,14 +465,14 @@ fn test_from_vec() { fn test_downcast() { use std::any::Any; - let r1: Arc<dyn Any + Send + Sync> = Arc::new(i32::max_value()); + let r1: Arc<dyn Any + Send + Sync> = Arc::new(i32::MAX); let r2: Arc<dyn Any + Send + Sync> = Arc::new("abc"); assert!(r1.clone().downcast::<u32>().is_err()); let r1i32 = r1.downcast::<i32>(); assert!(r1i32.is_ok()); - assert_eq!(r1i32.unwrap(), Arc::new(i32::max_value())); + assert_eq!(r1i32.unwrap(), Arc::new(i32::MAX)); assert!(r2.clone().downcast::<i32>().is_err()); diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index b703df6f3cb..eee98d45340 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -566,13 +566,13 @@ mod slice_index { data: "hello"; // note: using 0 specifically ensures that the result of overflowing is 0..0, // so that `get` doesn't simply return None for the wrong reason. - bad: data[0..=usize::max_value()]; + bad: data[0..=usize::MAX]; message: "maximum usize"; } in mod rangetoinclusive { data: "hello"; - bad: data[..=usize::max_value()]; + bad: data[..=usize::MAX]; message: "maximum usize"; } } diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index b73fd95ab6a..a9813a8704f 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -68,7 +68,7 @@ fn test_reserve() { #[test] fn test_zst_capacity() { - assert_eq!(Vec::<()>::new().capacity(), usize::max_value()); + assert_eq!(Vec::<()>::new().capacity(), usize::MAX); } #[test] @@ -563,19 +563,19 @@ fn test_drain_inclusive_range() { #[test] fn test_drain_max_vec_size() { - let mut v = Vec::<()>::with_capacity(usize::max_value()); + let mut v = Vec::<()>::with_capacity(usize::MAX); unsafe { - v.set_len(usize::max_value()); + v.set_len(usize::MAX); } - for _ in v.drain(usize::max_value() - 1..) {} - assert_eq!(v.len(), usize::max_value() - 1); + for _ in v.drain(usize::MAX - 1..) {} + assert_eq!(v.len(), usize::MAX - 1); - let mut v = Vec::<()>::with_capacity(usize::max_value()); + let mut v = Vec::<()>::with_capacity(usize::MAX); unsafe { - v.set_len(usize::max_value()); + v.set_len(usize::MAX); } - for _ in v.drain(usize::max_value() - 1..=usize::max_value() - 1) {} - assert_eq!(v.len(), usize::max_value() - 1); + for _ in v.drain(usize::MAX - 1..=usize::MAX - 1) {} + assert_eq!(v.len(), usize::MAX - 1); } #[test] diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 96923ea47f3..2226737757b 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1906,6 +1906,22 @@ unsafe impl<T: ?Sized> IsZero for Option<Box<T>> { //////////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] +impl<T> ops::Deref for Vec<T> { + type Target = [T]; + + fn deref(&self) -> &[T] { + unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T> ops::DerefMut for Vec<T> { + fn deref_mut(&mut self) -> &mut [T] { + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] impl<T: Clone> Clone for Vec<T> { #[cfg(not(test))] fn clone(&self) -> Vec<T> { @@ -1961,22 +1977,6 @@ impl<T, I: SliceIndex<[T]>> IndexMut<I> for Vec<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> ops::Deref for Vec<T> { - type Target = [T]; - - fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T> ops::DerefMut for Vec<T> { - fn deref_mut(&mut self) -> &mut [T] { - unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] impl<T> FromIterator<T> for Vec<T> { #[inline] fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> { @@ -2628,6 +2628,13 @@ impl<T> IntoIter<T> { } } +#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] +impl<T> AsRef<[T]> for IntoIter<T> { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: Send> Send for IntoIter<T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -2970,12 +2977,12 @@ impl<T> Drain<'_, T> { } /// Makes room for inserting more elements before the tail. - unsafe fn move_tail(&mut self, extra_capacity: usize) { + unsafe fn move_tail(&mut self, additional: usize) { let vec = self.vec.as_mut(); - let used_capacity = self.tail_start + self.tail_len; - vec.buf.reserve(used_capacity, extra_capacity); + let len = self.tail_start + self.tail_len; + vec.buf.reserve(len, additional); - let new_tail_start = self.tail_start + extra_capacity; + let new_tail_start = self.tail_start + additional; let src = vec.as_ptr().add(self.tail_start); let dst = vec.as_mut_ptr().add(new_tail_start); ptr::copy(src, dst, self.tail_len); diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index c4c1d2824b0..c4293ed7bcf 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -778,18 +778,13 @@ impl<T: ?Sized> RefCell<T> { /// /// An example of panic: /// - /// ``` + /// ```should_panic /// use std::cell::RefCell; - /// use std::thread; - /// - /// let result = thread::spawn(move || { - /// let c = RefCell::new(5); - /// let m = c.borrow_mut(); /// - /// let b = c.borrow(); // this causes a panic - /// }).join(); + /// let c = RefCell::new(5); /// - /// assert!(result.is_err()); + /// let m = c.borrow_mut(); + /// let b = c.borrow(); // this causes a panic /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -858,18 +853,13 @@ impl<T: ?Sized> RefCell<T> { /// /// An example of panic: /// - /// ``` + /// ```should_panic /// use std::cell::RefCell; - /// use std::thread; - /// - /// let result = thread::spawn(move || { - /// let c = RefCell::new(5); - /// let m = c.borrow(); /// - /// let b = c.borrow_mut(); // this causes a panic - /// }).join(); + /// let c = RefCell::new(5); + /// let m = c.borrow(); /// - /// assert!(result.is_err()); + /// let b = c.borrow_mut(); // this causes a panic /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1163,8 +1153,8 @@ impl<'b> BorrowRef<'b> { // Incrementing borrow can result in a non-reading value (<= 0) in these cases: // 1. It was < 0, i.e. there are writing borrows, so we can't allow a read borrow // due to Rust's reference aliasing rules - // 2. It was isize::max_value() (the max amount of reading borrows) and it overflowed - // into isize::min_value() (the max amount of writing borrows) so we can't allow + // 2. It was isize::MAX (the max amount of reading borrows) and it overflowed + // into isize::MIN (the max amount of writing borrows) so we can't allow // an additional read borrow because isize can't represent so many read borrows // (this can only happen if you mem::forget more than a small constant amount of // `Ref`s, which is not good practice) @@ -1172,7 +1162,7 @@ impl<'b> BorrowRef<'b> { } else { // Incrementing borrow can result in a reading value (> 0) in these cases: // 1. It was = 0, i.e. it wasn't borrowed, and we are taking the first read borrow - // 2. It was > 0 and < isize::max_value(), i.e. there were read borrows, and isize + // 2. It was > 0 and < isize::MAX, i.e. there were read borrows, and isize // is large enough to represent having one more read borrow borrow.set(b); Some(BorrowRef { borrow }) @@ -1198,7 +1188,7 @@ impl Clone for BorrowRef<'_> { debug_assert!(is_reading(borrow)); // Prevent the borrow counter from overflowing into // a writing borrow. - assert!(borrow != isize::max_value()); + assert!(borrow != isize::MAX); self.borrow.set(borrow + 1); BorrowRef { borrow: self.borrow } } @@ -1489,7 +1479,7 @@ impl<'b> BorrowRefMut<'b> { let borrow = self.borrow.get(); debug_assert!(is_writing(borrow)); // Prevent the borrow counter from underflowing. - assert!(borrow != isize::min_value()); + assert!(borrow != isize::MIN); self.borrow.set(borrow - 1); BorrowRefMut { borrow: self.borrow } } diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index 87c56c4b0a1..d7e39946148 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -278,16 +278,11 @@ impl fmt::Display for CharTryFromError { /// /// Passing a large radix, causing a panic: /// -/// ``` -/// use std::thread; +/// ```should_panic /// use std::char; /// -/// let result = thread::spawn(|| { -/// // this panics -/// let c = char::from_digit(1, 37); -/// }).join(); -/// -/// assert!(result.is_err()); +/// // this panics +/// let c = char::from_digit(1, 37); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index bf09b28ff69..dd2f01c679f 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -229,16 +229,11 @@ impl char { /// /// Passing a large radix, causing a panic: /// - /// ``` - /// use std::thread; + /// ```should_panic /// use std::char; /// - /// let result = thread::spawn(|| { - /// // this panics - /// let c = char::from_digit(1, 37); - /// }).join(); - /// - /// assert!(result.is_err()); + /// // this panics + /// char::from_digit(1, 37); /// ``` #[unstable(feature = "assoc_char_funcs", reason = "recently added", issue = "71763")] #[inline] @@ -282,15 +277,9 @@ impl char { /// /// Passing a large radix, causing a panic: /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// // this panics - /// '1'.is_digit(37); - /// }).join(); - /// - /// assert!(result.is_err()); + /// ```should_panic + /// // this panics + /// '1'.is_digit(37); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -337,14 +326,9 @@ impl char { /// /// Passing a large radix, causing a panic: /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// '1'.to_digit(37); - /// }).join(); - /// - /// assert!(result.is_err()); + /// ```should_panic + /// // this panics + /// '1'.to_digit(37); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -646,17 +630,11 @@ impl char { /// /// A buffer that's too small: /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// let mut b = [0; 1]; - /// - /// // this panics - /// 'ß'.encode_utf8(&mut b); - /// }).join(); + /// ```should_panic + /// let mut b = [0; 1]; /// - /// assert!(result.is_err()); + /// // this panics + /// 'ß'.encode_utf8(&mut b); /// ``` #[stable(feature = "unicode_encode_char", since = "1.15.0")] #[inline] @@ -687,17 +665,11 @@ impl char { /// /// A buffer that's too small: /// - /// ``` - /// use std::thread; - /// - /// let result = thread::spawn(|| { - /// let mut b = [0; 1]; - /// - /// // this panics - /// '𝕊'.encode_utf16(&mut b); - /// }).join(); + /// ```should_panic + /// let mut b = [0; 1]; /// - /// assert!(result.is_err()); + /// // this panics + /// '𝕊'.encode_utf16(&mut b); /// ``` #[stable(feature = "unicode_encode_char", since = "1.15.0")] #[inline] diff --git a/src/libcore/convert/num.rs b/src/libcore/convert/num.rs index 6dd0522f7f6..5ff52a9a11b 100644 --- a/src/libcore/convert/num.rs +++ b/src/libcore/convert/num.rs @@ -217,7 +217,7 @@ macro_rules! try_from_upper_bounded { /// is outside of the range of the target type. #[inline] fn try_from(u: $source) -> Result<Self, Self::Error> { - if u > (Self::max_value() as $source) { + if u > (Self::MAX as $source) { Err(TryFromIntError(())) } else { Ok(u as Self) @@ -239,8 +239,8 @@ macro_rules! try_from_both_bounded { /// is outside of the range of the target type. #[inline] fn try_from(u: $source) -> Result<Self, Self::Error> { - let min = Self::min_value() as $source; - let max = Self::max_value() as $source; + let min = Self::MIN as $source; + let max = Self::MAX as $source; if u < min || u > max { Err(TryFromIntError(())) } else { diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 06402a05d26..9a8d65cd4e0 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -115,6 +115,50 @@ pub trait Default: Sized { fn default() -> Self; } +/// Return the default value of a type according to the `Default` trait. +/// +/// The type to return is inferred from context; this is equivalent to +/// `Default::default()` but shorter to type. +/// +/// For example: +/// ``` +/// #![feature(default_free_fn)] +/// +/// use std::default::default; +/// +/// #[derive(Default)] +/// struct AppConfig { +/// foo: FooConfig, +/// bar: BarConfig, +/// } +/// +/// #[derive(Default)] +/// struct FooConfig { +/// foo: i32, +/// } +/// +/// #[derive(Default)] +/// struct BarConfig { +/// bar: f32, +/// baz: u8, +/// } +/// +/// fn main() { +/// let options = AppConfig { +/// foo: default(), +/// bar: BarConfig { +/// bar: 10.1, +/// ..default() +/// }, +/// }; +/// } +/// ``` +#[unstable(feature = "default_free_fn", issue = "73014")] +#[inline] +pub fn default<T: Default>() -> T { + Default::default() +} + /// Derive macro generating an impl of the trait `Default`. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 7d21f9a9a66..fe05e914e6d 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -145,7 +145,6 @@ #![feature(associated_type_bounds)] #![feature(const_type_id)] #![feature(const_caller_location)] -#![feature(option_zip)] #![feature(no_niche)] // rust-lang/rust#68303 #[prelude_import] diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 010f2958e36..d1f5cb44913 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -808,7 +808,7 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T { /// Disposes of a value. /// -/// This does call the argument's implementation of [`Drop`][drop]. +/// This does so by calling the argument's implementation of [`Drop`][drop]. /// /// This effectively does nothing for types which implement `Copy`, e.g. /// integers. Such values are copied and _then_ moved into the function, so the diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index c164e893b4f..b1317bc2121 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -750,9 +750,9 @@ $EndFeature, " } doc_comment! { - concat!("Unchecked integer addition. Computes `self + rhs, assuming overflow + concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), -"::max_value()` or `self + rhs < ", stringify!($SelfT), "::min_value()`."), +"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -792,9 +792,9 @@ $EndFeature, " } doc_comment! { - concat!("Unchecked integer subtraction. Computes `self - rhs, assuming overflow + concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), -"::max_value()` or `self - rhs < ", stringify!($SelfT), "::min_value()`."), +"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -834,9 +834,9 @@ $EndFeature, " } doc_comment! { - concat!("Unchecked integer multiplication. Computes `self * rhs, assuming overflow + concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), -"::max_value()` or `self * rhs < ", stringify!($SelfT), "::min_value()`."), +"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -871,7 +871,7 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn checked_div(self, rhs: Self) -> Option<Self> { - if rhs == 0 || (self == Self::min_value() && rhs == -1) { + if rhs == 0 || (self == Self::MIN && rhs == -1) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -900,7 +900,7 @@ assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); without modifying the original"] #[inline] pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> { - if rhs == 0 || (self == Self::min_value() && rhs == -1) { + if rhs == 0 || (self == Self::MIN && rhs == -1) { None } else { Some(self.div_euclid(rhs)) @@ -929,7 +929,7 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn checked_rem(self, rhs: Self) -> Option<Self> { - if rhs == 0 || (self == Self::min_value() && rhs == -1) { + if rhs == 0 || (self == Self::MIN && rhs == -1) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -957,7 +957,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); without modifying the original"] #[inline] pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> { - if rhs == 0 || (self == Self::min_value() && rhs == -1) { + if rhs == 0 || (self == Self::MIN && rhs == -1) { None } else { Some(self.rem_euclid(rhs)) @@ -1236,9 +1236,9 @@ $EndFeature, " match self.checked_mul(rhs) { Some(x) => x, None => if (self < 0) == (rhs < 0) { - Self::max_value() + Self::MAX } else { - Self::min_value() + Self::MIN } } } @@ -1267,8 +1267,8 @@ $EndFeature, " pub const fn saturating_pow(self, exp: u32) -> Self { match self.checked_pow(exp) { Some(x) => x, - None if self < 0 && exp % 2 == 1 => Self::min_value(), - None => Self::max_value(), + None if self < 0 && exp % 2 == 1 => Self::MIN, + None => Self::MAX, } } } @@ -1738,7 +1738,7 @@ $EndFeature, " #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - if self == Self::min_value() && rhs == -1 { + if self == Self::MIN && rhs == -1 { (self, true) } else { (self / rhs, false) @@ -1771,7 +1771,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringi #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - if self == Self::min_value() && rhs == -1 { + if self == Self::MIN && rhs == -1 { (self, true) } else { (self.div_euclid(rhs), false) @@ -1805,7 +1805,7 @@ $EndFeature, " #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if self == Self::min_value() && rhs == -1 { + if self == Self::MIN && rhs == -1 { (0, true) } else { (self % rhs, false) @@ -1838,7 +1838,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); without modifying the original"] #[inline] pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - if self == Self::min_value() && rhs == -1 { + if self == Self::MIN && rhs == -1 { (0, true) } else { (self.rem_euclid(rhs), false) @@ -1869,8 +1869,8 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($Self #[allow(unused_attributes)] #[allow_internal_unstable(const_if_match)] pub const fn overflowing_neg(self) -> (Self, bool) { - if self == Self::min_value() { - (Self::min_value(), true) + if self == Self::MIN { + (Self::MIN, true) } else { (-self, false) } @@ -1952,7 +1952,7 @@ $EndFeature, " #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] #[inline] pub const fn overflowing_abs(self) -> (Self, bool) { - (self.wrapping_abs(), self == Self::min_value()) + (self.wrapping_abs(), self == Self::MIN) } } @@ -2986,9 +2986,9 @@ assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeat } doc_comment! { - concat!("Unchecked integer addition. Computes `self + rhs, assuming overflow + concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), -"::max_value()` or `self + rhs < ", stringify!($SelfT), "::min_value()`."), +"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -3026,9 +3026,9 @@ assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " } doc_comment! { - concat!("Unchecked integer subtraction. Computes `self - rhs, assuming overflow + concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), -"::max_value()` or `self - rhs < ", stringify!($SelfT), "::min_value()`."), +"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -3066,9 +3066,9 @@ assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, " } doc_comment! { - concat!("Unchecked integer multiplication. Computes `self * rhs, assuming overflow + concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), -"::max_value()` or `self * rhs < ", stringify!($SelfT), "::min_value()`."), +"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -3309,7 +3309,8 @@ Basic usage: ``` ", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); -assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, " +assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);", +$EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] @@ -3366,7 +3367,7 @@ assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($Se pub const fn saturating_mul(self, rhs: Self) -> Self { match self.checked_mul(rhs) { Some(x) => x, - None => Self::max_value(), + None => Self::MAX, } } } @@ -3393,7 +3394,7 @@ $EndFeature, " pub const fn saturating_pow(self, exp: u32) -> Self { match self.checked_pow(exp) { Some(x) => x, - None => Self::max_value(), + None => Self::MAX, } } } @@ -4080,7 +4081,7 @@ Basic usage: } } - doc_comment! { + doc_comment! { concat!("Performs Euclidean division. Since, for the positive integers, all common @@ -4178,7 +4179,7 @@ assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " // (such as intel pre-haswell) have more efficient ctlz // intrinsics when the argument is non-zero. let z = unsafe { intrinsics::ctlz_nonzero(p) }; - <$SelfT>::max_value() >> z + <$SelfT>::MAX >> z } doc_comment! { @@ -5160,9 +5161,9 @@ trait FromStrRadixHelper: PartialOrd + Copy { macro_rules! doit { ($($t:ty)*) => ($(impl FromStrRadixHelper for $t { #[inline] - fn min_value() -> Self { Self::min_value() } + fn min_value() -> Self { Self::MIN } #[inline] - fn max_value() -> Self { Self::max_value() } + fn max_value() -> Self { Self::MAX } #[inline] fn from_u32(u: u32) -> Self { u as Self } #[inline] diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index bb648ba8c25..f6acb8f8b9a 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -694,7 +694,7 @@ Basic usage: #![feature(wrapping_int_impl)] use std::num::Wrapping; -let n = Wrapping(", stringify!($t), "::max_value()) >> 2; +let n = Wrapping(", stringify!($t), "::MAX) >> 2; assert_eq!(n.leading_zeros(), 3); ```"), @@ -723,8 +723,7 @@ use std::num::Wrapping; assert_eq!(Wrapping(100", stringify!($t), ").abs(), Wrapping(100)); assert_eq!(Wrapping(-100", stringify!($t), ").abs(), Wrapping(100)); -assert_eq!(Wrapping(", stringify!($t), "::min_value()).abs(), Wrapping(", stringify!($t), -"::min_value())); +assert_eq!(Wrapping(", stringify!($t), "::MIN).abs(), Wrapping(", stringify!($t), "::MIN)); assert_eq!(Wrapping(-128i8).abs().0 as u8, 128u8); ```"), #[inline] @@ -823,7 +822,7 @@ Basic usage: #![feature(wrapping_int_impl)] use std::num::Wrapping; -let n = Wrapping(", stringify!($t), "::max_value()) >> 2; +let n = Wrapping(", stringify!($t), "::MAX) >> 2; assert_eq!(n.leading_zeros(), 2); ```"), diff --git a/src/libcore/option.rs b/src/libcore/option.rs index e8483875c97..5f0a12678ff 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -926,7 +926,6 @@ impl<T> Option<T> { /// # Examples /// /// ``` - /// #![feature(option_zip)] /// let x = Some(1); /// let y = Some("hi"); /// let z = None::<u8>; @@ -934,9 +933,12 @@ impl<T> Option<T> { /// assert_eq!(x.zip(y), Some((1, "hi"))); /// assert_eq!(x.zip(z), None); /// ``` - #[unstable(feature = "option_zip", issue = "70086")] + #[stable(feature = "option_zip_option", since = "1.46.0")] pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> { - self.zip_with(other, |a, b| (a, b)) + match (self, other) { + (Some(a), Some(b)) => Some((a, b)), + _ => None, + } } /// Zips `self` and another `Option` with function `f`. diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index 835183d171a..e39d18d7733 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -291,7 +291,7 @@ impl<T: ?Sized> *const T { T: Sized, { let pointee_size = mem::size_of::<T>(); - assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); + assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); intrinsics::ptr_offset_from(self, origin) } @@ -336,7 +336,7 @@ impl<T: ?Sized> *const T { T: Sized, { let pointee_size = mem::size_of::<T>(); - assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); + assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); let d = isize::wrapping_sub(self as _, origin as _); d.wrapping_div(pointee_size as _) diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index ecc70adda41..1be05d5efff 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -1128,7 +1128,7 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize { // // Note, that we use wrapping operations here intentionally – the original formula // uses e.g., subtraction `mod n`. It is entirely fine to do them `mod - // usize::max_value()` instead, because we take the result `mod n` at the end + // usize::MAX` instead, because we take the result `mod n` at the end // anyway. inverse = inverse.wrapping_mul(2usize.wrapping_sub(x.wrapping_mul(inverse))); if going_mod >= m { @@ -1193,7 +1193,7 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize { } // Cannot be aligned at all. - usize::max_value() + usize::MAX } /// Compares raw pointers for equality. @@ -1345,14 +1345,24 @@ macro_rules! fnptr_impls_safety_abi { #[stable(feature = "fnptr_impls", since = "1.4.0")] impl<Ret, $($Arg),*> fmt::Pointer for $FnTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(*self as *const ()), f) + // HACK: The intermediate cast as usize is required for AVR + // so that the address space of the source function pointer + // is preserved in the final function pointer. + // + // https://github.com/avr-rust/rust/issues/143 + fmt::Pointer::fmt(&(*self as usize as *const ()), f) } } #[stable(feature = "fnptr_impls", since = "1.4.0")] impl<Ret, $($Arg),*> fmt::Debug for $FnTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(*self as *const ()), f) + // HACK: The intermediate cast as usize is required for AVR + // so that the address space of the source function pointer + // is preserved in the final function pointer. + // + // https://github.com/avr-rust/rust/issues/143 + fmt::Pointer::fmt(&(*self as usize as *const ()), f) } } } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ff333f77334..21ba2b5abcf 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -409,7 +409,7 @@ impl<T> [T] { /// The returned range is half-open, which means that the end pointer /// points *one past* the last element of the slice. This way, an empty /// slice is represented by two equal pointers, and the difference between - /// the two pointers represents the size of the size. + /// the two pointers represents the size of the slice. /// /// See [`as_ptr`] for warnings on using these pointers. The end pointer /// requires extra caution, as it does not point to a valid element in the @@ -464,7 +464,7 @@ impl<T> [T] { /// The returned range is half-open, which means that the end pointer /// points *one past* the last element of the slice. This way, an empty /// slice is represented by two equal pointers, and the difference between - /// the two pointers represents the size of the size. + /// the two pointers represents the size of the slice. /// /// See [`as_mut_ptr`] for warnings on using these pointers. The end /// pointer requires extra caution, as it does not point to a valid element @@ -3043,16 +3043,12 @@ impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> { #[inline] fn get(self, slice: &[T]) -> Option<&[T]> { - if *self.end() == usize::max_value() { - None - } else { - (*self.start()..self.end() + 1).get(slice) - } + if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if *self.end() == usize::max_value() { + if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get_mut(slice) @@ -3071,7 +3067,7 @@ impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> { #[inline] fn index(self, slice: &[T]) -> &[T] { - if *self.end() == usize::max_value() { + if *self.end() == usize::MAX { slice_index_overflow_fail(); } (*self.start()..self.end() + 1).index(slice) @@ -3079,7 +3075,7 @@ impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> { #[inline] fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if *self.end() == usize::max_value() { + if *self.end() == usize::MAX { slice_index_overflow_fail(); } (*self.start()..self.end() + 1).index_mut(slice) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 316c2cd55ac..6c4b28499a6 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1651,7 +1651,7 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // Ascii case, try to skip forward quickly. // When the pointer is aligned, read 2 words of data per iteration // until we find a word containing a non-ascii byte. - if align != usize::max_value() && align.wrapping_sub(index) % usize_bytes == 0 { + if align != usize::MAX && align.wrapping_sub(index) % usize_bytes == 0 { let ptr = v.as_ptr(); while index < blocks_end { // SAFETY: since `align - index` and `ascii_block_size` are @@ -2083,7 +2083,7 @@ mod traits { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if *self.end() == usize::max_value() { + if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) @@ -2091,7 +2091,7 @@ mod traits { } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if *self.end() == usize::max_value() { + if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get_mut(slice) @@ -2107,14 +2107,14 @@ mod traits { } #[inline] fn index(self, slice: &str) -> &Self::Output { - if *self.end() == usize::max_value() { + if *self.end() == usize::MAX { str_index_overflow_fail(); } (*self.start()..self.end() + 1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if *self.end() == usize::max_value() { + if *self.end() == usize::MAX { str_index_overflow_fail(); } (*self.start()..self.end() + 1).index_mut(slice) @@ -2140,11 +2140,11 @@ mod traits { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if self.end == usize::max_value() { None } else { (..self.end + 1).get(slice) } + if self.end == usize::MAX { None } else { (..self.end + 1).get(slice) } } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.end == usize::max_value() { None } else { (..self.end + 1).get_mut(slice) } + if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { @@ -2156,14 +2156,14 @@ mod traits { } #[inline] fn index(self, slice: &str) -> &Self::Output { - if self.end == usize::max_value() { + if self.end == usize::MAX { str_index_overflow_fail(); } (..self.end + 1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if self.end == usize::max_value() { + if self.end == usize::MAX { str_index_overflow_fail(); } (..self.end + 1).index_mut(slice) diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 1a2b612b2f9..263d6b5efdf 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -60,6 +60,43 @@ use crate::slice::memchr; /// The trait itself acts as a builder for an associated /// `Searcher` type, which does the actual work of finding /// occurrences of the pattern in a string. +/// +/// Depending on the type of the pattern, the behaviour of methods like +/// [`str::find`] and [`str::contains`] can change. The table below describes +/// some of those behaviours. +/// +/// | Pattern type | Match condition | +/// |--------------------------|-------------------------------------------| +/// | `&str` | is substring | +/// | `char` | is contained in string | +/// | `&[char] | any char in slice is contained in string | +/// | `F: FnMut(char) -> bool` | `F` returns `true` for a char in string | +/// | `&&str` | is substring | +/// | `&String` | is substring | +/// +/// # Examples +/// ``` +/// // &str +/// assert_eq!("abaaa".find("ba"), Some(1)); +/// assert_eq!("abaaa".find("bac"), None); +/// +/// // char +/// assert_eq!("abaaa".find('a'), Some(0)); +/// assert_eq!("abaaa".find('b'), Some(1)); +/// assert_eq!("abaaa".find('c'), None); +/// +/// // &[char] +/// assert_eq!("ab".find(&['b', 'a'][..]), Some(0)); +/// assert_eq!("abaaa".find(&['a', 'z'][..]), Some(0)); +/// assert_eq!("abaaa".find(&['c', 'd'][..]), None); +/// +/// // FnMut(char) -> bool +/// assert_eq!("abcdef_z".find(|ch| ch > 'd' && ch < 'y'), Some(4)); +/// assert_eq!("abcddd_z".find(|ch| ch > 'd' && ch < 'y'), None); +/// ``` +/// +/// [`str::find`]: ../../../std/primitive.str.html#method.find +/// [`str::contains`]: ../../../std/primitive.str.html#method.contains pub trait Pattern<'a>: Sized { /// Associated searcher for this pattern type Searcher: Searcher<'a>; diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 477cb24d6be..1cd68f2881b 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -2623,15 +2623,7 @@ unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T { /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(target_arch = "wasm32", allow(unused_variables))] pub fn fence(order: Ordering) { - // On wasm32 it looks like fences aren't implemented in LLVM yet in that - // they will cause LLVM to abort. The wasm instruction set doesn't have - // fences right now. There's discussion online about the best way for tools - // to conventionally implement fences at - // https://github.com/WebAssembly/tool-conventions/issues/59. We should - // follow that discussion and implement a solution when one comes about! - #[cfg(not(target_arch = "wasm32"))] // SAFETY: using an atomic fence is safe. unsafe { match order { diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index 181bbb8e187..939f1325c84 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -140,8 +140,8 @@ macro_rules! test_impl_from { ($fn_name: ident, $Small: ty, $Large: ty) => { #[test] fn $fn_name() { - let small_max = <$Small>::max_value(); - let small_min = <$Small>::min_value(); + let small_max = <$Small>::MAX; + let small_min = <$Small>::MIN; let large_max: $Large = small_max.into(); let large_min: $Large = small_min.into(); assert_eq!(large_max as $Small, small_max); @@ -248,8 +248,8 @@ macro_rules! test_impl_try_from_always_ok { ($fn_name:ident, $source:ty, $target: ty) => { #[test] fn $fn_name() { - let max = <$source>::max_value(); - let min = <$source>::min_value(); + let max = <$source>::MAX; + let min = <$source>::MIN; let zero: $source = 0; assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), max as $target); assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), min as $target); @@ -361,8 +361,8 @@ macro_rules! test_impl_try_from_signed_to_unsigned_upper_ok { ($fn_name:ident, $source:ty, $target:ty) => { #[test] fn $fn_name() { - let max = <$source>::max_value(); - let min = <$source>::min_value(); + let max = <$source>::MAX; + let min = <$source>::MIN; let zero: $source = 0; let neg_one: $source = -1; assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), max as $target); @@ -426,8 +426,8 @@ macro_rules! test_impl_try_from_unsigned_to_signed_upper_err { ($fn_name:ident, $source:ty, $target:ty) => { #[test] fn $fn_name() { - let max = <$source>::max_value(); - let min = <$source>::min_value(); + let max = <$source>::MAX; + let min = <$source>::MIN; let zero: $source = 0; assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), min as $target); @@ -487,11 +487,11 @@ macro_rules! test_impl_try_from_same_sign_err { ($fn_name:ident, $source:ty, $target:ty) => { #[test] fn $fn_name() { - let max = <$source>::max_value(); - let min = <$source>::min_value(); + let max = <$source>::MAX; + let min = <$source>::MIN; let zero: $source = 0; - let t_max = <$target>::max_value(); - let t_min = <$target>::min_value(); + let t_max = <$target>::MAX; + let t_min = <$target>::MIN; assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); if min != 0 { assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); @@ -576,11 +576,11 @@ macro_rules! test_impl_try_from_signed_to_unsigned_err { ($fn_name:ident, $source:ty, $target:ty) => { #[test] fn $fn_name() { - let max = <$source>::max_value(); - let min = <$source>::min_value(); + let max = <$source>::MAX; + let min = <$source>::MIN; let zero: $source = 0; - let t_max = <$target>::max_value(); - let t_min = <$target>::min_value(); + let t_max = <$target>::MAX; + let t_min = <$target>::MIN; assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target); diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index a008b3319f3..9fea34d668f 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -357,7 +357,7 @@ fn align_offset_weird_strides() { unsafe fn test_weird_stride<T>(ptr: *const T, align: usize) -> bool { let numptr = ptr as usize; - let mut expected = usize::max_value(); + let mut expected = usize::MAX; // Naive but definitely correct way to find the *first* aligned element of stride::<T>. for el in 0..align { if (numptr + el * ::std::mem::size_of::<T>()) % align == 0 { diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 54a585415bc..cd46117f763 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -1691,8 +1691,8 @@ fn test_copy_within_panics_src_inverted() { #[should_panic(expected = "attempted to index slice up to maximum usize")] fn test_copy_within_panics_src_out_of_bounds() { let mut bytes = *b"Hello, World!"; - // an inclusive range ending at usize::max_value() would make src_end overflow - bytes.copy_within(usize::max_value()..=usize::max_value(), 0); + // an inclusive range ending at usize::MAX would make src_end overflow + bytes.copy_within(usize::MAX..=usize::MAX, 0); } #[test] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 09a069ab313..ba3adc4a135 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -133,9 +133,9 @@ impl Neg for Round { pub type ExpInt = i16; // \c ilogb error results. -pub const IEK_INF: ExpInt = ExpInt::max_value(); -pub const IEK_NAN: ExpInt = ExpInt::min_value(); -pub const IEK_ZERO: ExpInt = ExpInt::min_value() + 1; +pub const IEK_INF: ExpInt = ExpInt::MAX; +pub const IEK_NAN: ExpInt = ExpInt::MIN; +pub const IEK_ZERO: ExpInt = ExpInt::MIN + 1; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct ParseError(pub &'static str); diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index e5b06cf225d..2d8bb7d1e8e 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -2997,8 +2997,8 @@ fn scalbn() { assert!(smallest_f64.scalbn(2099).is_infinite()); // Test for integer overflows when adding to exponent. - assert!(smallest_f64.scalbn(-ExpInt::max_value()).is_pos_zero()); - assert!(largest_f64.scalbn(ExpInt::max_value()).is_infinite()); + assert!(smallest_f64.scalbn(-ExpInt::MAX).is_pos_zero()); + assert!(largest_f64.scalbn(ExpInt::MAX).is_infinite()); assert!(largest_denormal_f64.bitwise_eq(largest_denormal_f64.scalbn(0),)); assert!(neg_largest_denormal_f64.bitwise_eq(neg_largest_denormal_f64.scalbn(0),)); diff --git a/src/librustc_arena/lib.rs b/src/librustc_arena/lib.rs index bbe80c26dcb..4a2a0de0e21 100644 --- a/src/librustc_arena/lib.rs +++ b/src/librustc_arena/lib.rs @@ -146,18 +146,18 @@ impl<T> TypedArena<T> { } #[inline] - fn can_allocate(&self, len: usize) -> bool { - let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize; - let at_least_bytes = len.checked_mul(mem::size_of::<T>()).unwrap(); - available_capacity_bytes >= at_least_bytes + fn can_allocate(&self, additional: usize) -> bool { + let available_bytes = self.end.get() as usize - self.ptr.get() as usize; + let additional_bytes = additional.checked_mul(mem::size_of::<T>()).unwrap(); + available_bytes >= additional_bytes } /// Ensures there's enough space in the current chunk to fit `len` objects. #[inline] - fn ensure_capacity(&self, len: usize) { - if !self.can_allocate(len) { - self.grow(len); - debug_assert!(self.can_allocate(len)); + fn ensure_capacity(&self, additional: usize) { + if !self.can_allocate(additional) { + self.grow(additional); + debug_assert!(self.can_allocate(additional)); } } @@ -214,36 +214,31 @@ impl<T> TypedArena<T> { /// Grows the arena. #[inline(never)] #[cold] - fn grow(&self, n: usize) { + fn grow(&self, additional: usize) { unsafe { - // We need the element size in to convert chunk sizes (ranging from + // We need the element size to convert chunk sizes (ranging from // PAGE to HUGE_PAGE bytes) to element counts. let elem_size = cmp::max(1, mem::size_of::<T>()); let mut chunks = self.chunks.borrow_mut(); - let (chunk, mut new_capacity); + let mut new_cap; if let Some(last_chunk) = chunks.last_mut() { let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; - let currently_used_cap = used_bytes / mem::size_of::<T>(); - last_chunk.entries = currently_used_cap; - if last_chunk.storage.reserve_in_place(currently_used_cap, n) { - self.end.set(last_chunk.end()); - return; - } else { - // If the previous chunk's capacity is less than HUGE_PAGE - // bytes, then this chunk will be least double the previous - // chunk's size. - new_capacity = last_chunk.storage.capacity(); - if new_capacity < HUGE_PAGE / elem_size { - new_capacity = new_capacity.checked_mul(2).unwrap(); - } + last_chunk.entries = used_bytes / mem::size_of::<T>(); + + // If the previous chunk's capacity is less than HUGE_PAGE + // bytes, then this chunk will be least double the previous + // chunk's size. + new_cap = last_chunk.storage.capacity(); + if new_cap < HUGE_PAGE / elem_size { + new_cap = new_cap.checked_mul(2).unwrap(); } } else { - new_capacity = PAGE / elem_size; + new_cap = PAGE / elem_size; } - // Also ensure that this chunk can fit `n`. - new_capacity = cmp::max(n, new_capacity); + // Also ensure that this chunk can fit `additional`. + new_cap = cmp::max(additional, new_cap); - chunk = TypedArenaChunk::<T>::new(new_capacity); + let chunk = TypedArenaChunk::<T>::new(new_cap); self.ptr.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); @@ -347,31 +342,28 @@ impl DroplessArena { #[inline(never)] #[cold] - fn grow(&self, needed_bytes: usize) { + fn grow(&self, additional: usize) { unsafe { let mut chunks = self.chunks.borrow_mut(); - let (chunk, mut new_capacity); + let mut new_cap; if let Some(last_chunk) = chunks.last_mut() { - let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; - if last_chunk.storage.reserve_in_place(used_bytes, needed_bytes) { - self.end.set(last_chunk.end()); - return; - } else { - // If the previous chunk's capacity is less than HUGE_PAGE - // bytes, then this chunk will be least double the previous - // chunk's size. - new_capacity = last_chunk.storage.capacity(); - if new_capacity < HUGE_PAGE { - new_capacity = new_capacity.checked_mul(2).unwrap(); - } + // There is no need to update `last_chunk.entries` because that + // field isn't used by `DroplessArena`. + + // If the previous chunk's capacity is less than HUGE_PAGE + // bytes, then this chunk will be least double the previous + // chunk's size. + new_cap = last_chunk.storage.capacity(); + if new_cap < HUGE_PAGE { + new_cap = new_cap.checked_mul(2).unwrap(); } } else { - new_capacity = PAGE; + new_cap = PAGE; } - // Also ensure that this chunk can fit `needed_bytes`. - new_capacity = cmp::max(needed_bytes, new_capacity); + // Also ensure that this chunk can fit `additional`. + new_cap = cmp::max(additional, new_cap); - chunk = TypedArenaChunk::<u8>::new(new_capacity); + let chunk = TypedArenaChunk::<u8>::new(new_cap); self.ptr.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); @@ -386,7 +378,7 @@ impl DroplessArena { self.align(align); let future_end = intrinsics::arith_offset(self.ptr.get(), bytes as isize); - if (future_end as *mut u8) >= self.end.get() { + if (future_end as *mut u8) > self.end.get() { self.grow(bytes); } @@ -610,7 +602,7 @@ macro_rules! which_arena_for_type { #[macro_export] macro_rules! declare_arena { - ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { + ([], [$($a:tt $name:ident: $ty:ty, $gen_ty:ty;)*], $tcx:lifetime) => { #[derive(Default)] pub struct Arena<$tcx> { pub dropless: $crate::DroplessArena, @@ -619,17 +611,17 @@ macro_rules! declare_arena { } #[marker] - pub trait ArenaAllocatable {} + pub trait ArenaAllocatable<'tcx> {} - impl<T: Copy> ArenaAllocatable for T {} + impl<'tcx, T: Copy> ArenaAllocatable<'tcx> for T {} - unsafe trait ArenaField<'tcx>: Sized { + unsafe trait ArenaField<'tcx>: Sized + ArenaAllocatable<'tcx> { /// Returns a specific arena to allocate from. /// If `None` is returned, the `DropArena` will be used. fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena<Self>>; } - unsafe impl<'tcx, T> ArenaField<'tcx> for T { + unsafe impl<'tcx, T: ArenaAllocatable<'tcx>> ArenaField<'tcx> for T { #[inline] default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena<Self>> { panic!() @@ -638,18 +630,27 @@ macro_rules! declare_arena { $( #[allow(unused_lifetimes)] - impl<$tcx> ArenaAllocatable for $ty {} - unsafe impl<$tcx> ArenaField<$tcx> for $ty { + impl<$tcx> ArenaAllocatable<$tcx> for $ty {} + unsafe impl<$tcx, '_x, '_y, '_z, '_w> ArenaField<$tcx> for $gen_ty where Self: ArenaAllocatable<$tcx> { #[inline] fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a $crate::TypedArena<Self>> { - $crate::which_arena_for_type!($a[&_arena.$name]) + // SAFETY: We only implement `ArenaAllocatable<$tcx>` for + // `$ty`, so `$ty` and Self are the same type + unsafe { + ::std::mem::transmute::< + Option<&'a $crate::TypedArena<$ty>>, + Option<&'a $crate::TypedArena<Self>>, + >( + $crate::which_arena_for_type!($a[&_arena.$name]) + ) + } } } )* impl<'tcx> Arena<'tcx> { #[inline] - pub fn alloc<T: ArenaAllocatable>(&self, value: T) -> &mut T { + pub fn alloc<T: ArenaAllocatable<'tcx>>(&self, value: T) -> &mut T { if !::std::mem::needs_drop::<T>() { return self.dropless.alloc(value); } @@ -667,7 +668,7 @@ macro_rules! declare_arena { self.dropless.alloc_slice(value) } - pub fn alloc_from_iter<'a, T: ArenaAllocatable>( + pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx>>( &'a self, iter: impl ::std::iter::IntoIterator<Item = T>, ) -> &'a mut [T] { diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index efcf95ec706..62406552e31 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -362,7 +362,11 @@ impl Default for Generics { fn default() -> Generics { Generics { params: Vec::new(), - where_clause: WhereClause { predicates: Vec::new(), span: DUMMY_SP }, + where_clause: WhereClause { + has_where_token: false, + predicates: Vec::new(), + span: DUMMY_SP, + }, span: DUMMY_SP, } } @@ -371,6 +375,11 @@ impl Default for Generics { /// A where-clause in a definition. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct WhereClause { + /// `true` if we ate a `where` token: this can happen + /// if we parsed no predicates (e.g. `struct Foo where {} + /// This allows us to accurately pretty-print + /// in `nt_to_tokenstream` + pub has_where_token: bool, pub predicates: Vec<WherePredicate>, pub span: Span, } @@ -1165,7 +1174,9 @@ pub enum ExprKind { /// and the remaining elements are the rest of the arguments. /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`. - MethodCall(PathSegment, Vec<P<Expr>>), + /// This `Span` is the span of the function, without the dot and receiver + /// (e.g. `foo(a, b)` in `x.foo(a, b)` + MethodCall(PathSegment, Vec<P<Expr>>, Span), /// A tuple (e.g., `(a, b, c, d)`). Tup(Vec<P<Expr>>), /// A binary operation (e.g., `a + b`, `a * b`). @@ -1849,15 +1860,6 @@ impl TyKind { pub fn is_unit(&self) -> bool { if let TyKind::Tup(ref tys) = *self { tys.is_empty() } else { false } } - - /// HACK(type_alias_impl_trait, Centril): A temporary crutch used - /// in lowering to avoid making larger changes there and beyond. - pub fn opaque_top_hack(&self) -> Option<&GenericBounds> { - match self { - Self::ImplTrait(_, bounds) => Some(bounds), - _ => None, - } - } } /// Syntax used to declare a trait object. diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs index 7ececb814a6..2ffef9d48c1 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/src/librustc_ast/mut_visit.rs @@ -786,7 +786,7 @@ pub fn noop_visit_generics<T: MutVisitor>(generics: &mut Generics, vis: &mut T) } pub fn noop_visit_where_clause<T: MutVisitor>(wc: &mut WhereClause, vis: &mut T) { - let WhereClause { predicates, span } = wc; + let WhereClause { has_where_token: _, predicates, span } = wc; visit_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); vis.visit_span(span); } @@ -1111,11 +1111,12 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_expr(f); visit_exprs(args, vis); } - ExprKind::MethodCall(PathSegment { ident, id, args }, exprs) => { + ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => { vis.visit_ident(ident); vis.visit_id(id); visit_opt(args, |args| vis.visit_generic_args(args)); visit_exprs(exprs, vis); + vis.visit_span(span); } ExprKind::Binary(_binop, lhs, rhs) => { vis.visit_expr(lhs); diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs index 075aaa7e5bc..15ae12ebf10 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -392,7 +392,7 @@ impl TokenStream { break; } } - token_trees = out.into_iter().map(|t| TokenTree::Token(t)).collect(); + token_trees = out.into_iter().map(TokenTree::Token).collect(); if token_trees.len() != 1 { debug!("break_tokens: broke {:?} to {:?}", tree, token_trees); } diff --git a/src/librustc_ast/util/parser.rs b/src/librustc_ast/util/parser.rs index b98cc96b3c6..d8b44a22f2c 100644 --- a/src/librustc_ast/util/parser.rs +++ b/src/librustc_ast/util/parser.rs @@ -394,7 +394,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { contains_exterior_struct_lit(&x) } - ast::ExprKind::MethodCall(.., ref exprs) => { + ast::ExprKind::MethodCall(.., ref exprs, _) => { // X { y: 1 }.bar(...) contains_exterior_struct_lit(&exprs[0]) } diff --git a/src/librustc_ast/visit.rs b/src/librustc_ast/visit.rs index 41c02734442..ccab46703df 100644 --- a/src/librustc_ast/visit.rs +++ b/src/librustc_ast/visit.rs @@ -726,7 +726,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(callee_expression); walk_list!(visitor, visit_expr, arguments); } - ExprKind::MethodCall(ref segment, ref arguments) => { + ExprKind::MethodCall(ref segment, ref arguments, _span) => { visitor.visit_path_segment(expression.span, segment); walk_list!(visitor, visit_expr, arguments); } diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index c9037da377e..b7894eb145b 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -39,7 +39,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let f = self.lower_expr(f); hir::ExprKind::Call(f, self.lower_exprs(args)) } - ExprKind::MethodCall(ref seg, ref args) => { + ExprKind::MethodCall(ref seg, ref args, span) => { let hir_seg = self.arena.alloc(self.lower_path_segment( e.span, seg, @@ -50,7 +50,7 @@ impl<'hir> LoweringContext<'_, 'hir> { None, )); let args = self.lower_exprs(args); - hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args) + hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args, span) } ExprKind::Binary(binop, ref lhs, ref rhs) => { let binop = self.lower_binop(binop); @@ -1237,10 +1237,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ) => { assert!(!*late); let out_op_sp = if input { op_sp2 } else { op_sp }; - let msg = &format!( - "use `lateout` instead of \ - `out` to avoid conflict" - ); + let msg = "use `lateout` instead of \ + `out` to avoid conflict"; err.span_help(out_op_sp, msg); } _ => {} diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 47d10f86d03..8cfbd408e22 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -1,5 +1,5 @@ use super::{AnonymousLifetimeMode, LoweringContext, ParamMode}; -use super::{ImplTraitContext, ImplTraitPosition, ImplTraitTypeIdVisitor}; +use super::{ImplTraitContext, ImplTraitPosition}; use crate::Arena; use rustc_ast::ast::*; @@ -7,6 +7,7 @@ use rustc_ast::attr; use rustc_ast::node_id::NodeMap; use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, Visitor}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -165,13 +166,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } ItemKind::MacroDef(..) => SmallVec::new(), ItemKind::Fn(..) | ItemKind::Impl { of_trait: None, .. } => smallvec![i.id], - ItemKind::Static(ref ty, ..) | ItemKind::Const(_, ref ty, ..) => { - let mut ids = smallvec![i.id]; - if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitTypeIdVisitor { ids: &mut ids }.visit_ty(ty); - } - ids - } _ => smallvec![i.id], }; @@ -292,23 +286,25 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)), ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)), - ItemKind::TyAlias(_, ref gen, _, Some(ref ty)) => match ty.kind.opaque_top_hack() { - None => { - let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); - let generics = self.lower_generics(gen, ImplTraitContext::disallowed()); - hir::ItemKind::TyAlias(ty, generics) - } - Some(bounds) => { - let ctx = || ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc); - let ty = hir::OpaqueTy { - generics: self.lower_generics(gen, ctx()), - bounds: self.lower_param_bounds(bounds, ctx()), - impl_trait_fn: None, - origin: hir::OpaqueTyOrigin::TypeAlias, - }; - hir::ItemKind::OpaqueTy(ty) - } - }, + ItemKind::TyAlias(_, ref gen, _, Some(ref ty)) => { + // We lower + // + // type Foo = impl Trait + // + // to + // + // type Foo = Foo1 + // opaque type Foo1: Trait + let ty = self.lower_ty( + ty, + ImplTraitContext::OtherOpaqueTy { + capturable_lifetimes: &mut FxHashSet::default(), + origin: hir::OpaqueTyOrigin::Misc, + }, + ); + let generics = self.lower_generics(gen, ImplTraitContext::disallowed()); + hir::ItemKind::TyAlias(ty, generics) + } ItemKind::TyAlias(_, ref generics, _, None) => { let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err)); let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); @@ -438,8 +434,13 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, body: Option<&Expr>, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { + let mut capturable_lifetimes; let itctx = if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc) + capturable_lifetimes = FxHashSet::default(); + ImplTraitContext::OtherOpaqueTy { + capturable_lifetimes: &mut capturable_lifetimes, + origin: hir::OpaqueTyOrigin::Misc, + } } else { ImplTraitContext::Disallowed(ImplTraitPosition::Binding) }; @@ -844,16 +845,16 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err)); hir::ImplItemKind::TyAlias(ty) } - Some(ty) => match ty.kind.opaque_top_hack() { - None => { - let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); - hir::ImplItemKind::TyAlias(ty) - } - Some(bs) => { - let bs = self.lower_param_bounds(bs, ImplTraitContext::disallowed()); - hir::ImplItemKind::OpaqueTy(bs) - } - }, + Some(ty) => { + let ty = self.lower_ty( + ty, + ImplTraitContext::OtherOpaqueTy { + capturable_lifetimes: &mut FxHashSet::default(), + origin: hir::OpaqueTyOrigin::Misc, + }, + ); + hir::ImplItemKind::TyAlias(ty) + } }; (generics, kind) } @@ -887,12 +888,7 @@ impl<'hir> LoweringContext<'_, 'hir> { defaultness, kind: match &i.kind { AssocItemKind::Const(..) => hir::AssocItemKind::Const, - AssocItemKind::TyAlias(.., ty) => { - match ty.as_deref().and_then(|ty| ty.kind.opaque_top_hack()) { - None => hir::AssocItemKind::Type, - Some(_) => hir::AssocItemKind::OpaqueTy, - } - } + AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type, AssocItemKind::Fn(_, sig, ..) => { hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } } diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 1f8c68f75e9..a722a88a7a1 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -33,7 +33,7 @@ #![feature(array_value_iter)] #![feature(crate_visibility_modifier)] #![feature(marker_trait_attr)] -#![feature(specialization)] // FIXME: min_specialization does not work +#![feature(min_specialization)] #![feature(or_patterns)] #![recursion_limit = "256"] @@ -224,11 +224,30 @@ enum ImplTraitContext<'b, 'a> { /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`. /// - /// We optionally store a `DefId` for the parent item here so we can look up necessary - /// information later. It is `None` when no information about the context should be stored - /// (e.g., for consts and statics). - OpaqueTy(Option<DefId> /* fn def-ID */, hir::OpaqueTyOrigin), - + ReturnPositionOpaqueTy { + /// `DefId` for the parent function, used to look up necessary + /// information later. + fn_def_id: DefId, + /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn, + origin: hir::OpaqueTyOrigin, + }, + /// Impl trait in type aliases, consts and statics. + OtherOpaqueTy { + /// Set of lifetimes that this opaque type can capture, if it uses + /// them. This includes lifetimes bound since we entered this context. + /// For example, in + /// + /// type A<'b> = impl for<'a> Trait<'a, Out = impl Sized + 'a>; + /// + /// the inner opaque type captures `'a` because it uses it. It doesn't + /// need to capture `'b` because it already inherits the lifetime + /// parameter from `A`. + // FIXME(impl_trait): but `required_region_bounds` will ICE later + // anyway. + capturable_lifetimes: &'b mut FxHashSet<hir::LifetimeName>, + /// Origin: Either OpaqueTyOrigin::Misc or OpaqueTyOrigin::Binding, + origin: hir::OpaqueTyOrigin, + }, /// `impl Trait` is not accepted in this position. Disallowed(ImplTraitPosition), } @@ -253,7 +272,12 @@ impl<'a> ImplTraitContext<'_, 'a> { use self::ImplTraitContext::*; match self { Universal(params) => Universal(params), - OpaqueTy(fn_def_id, origin) => OpaqueTy(*fn_def_id, *origin), + ReturnPositionOpaqueTy { fn_def_id, origin } => { + ReturnPositionOpaqueTy { fn_def_id: *fn_def_id, origin: *origin } + } + OtherOpaqueTy { capturable_lifetimes, origin } => { + OtherOpaqueTy { capturable_lifetimes, origin: *origin } + } Disallowed(pos) => Disallowed(*pos), } } @@ -1001,6 +1025,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) } } AssocTyConstraintKind::Bound { ref bounds } => { + let mut capturable_lifetimes; // Piggy-back on the `impl Trait` context to figure out the correct behavior. let (desugar_to_impl_trait, itctx) = match itctx { // We are in the return position: @@ -1010,7 +1035,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so desugar to // // fn foo() -> impl Iterator<Item = impl Debug> - ImplTraitContext::OpaqueTy(..) => (true, itctx), + ImplTraitContext::ReturnPositionOpaqueTy { .. } + | ImplTraitContext::OtherOpaqueTy { .. } => (true, itctx), // We are in the argument position, but within a dyn type: // @@ -1028,7 +1054,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // FIXME: this is only needed until `impl Trait` is allowed in type aliases. ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => { - (true, ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)) + capturable_lifetimes = FxHashSet::default(); + ( + true, + ImplTraitContext::OtherOpaqueTy { + capturable_lifetimes: &mut capturable_lifetimes, + origin: hir::OpaqueTyOrigin::Misc, + }, + ) } // We are in the parameter position, but not within a dyn type: @@ -1270,10 +1303,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::ImplTrait(def_node_id, ref bounds) => { let span = t.span; match itctx { - ImplTraitContext::OpaqueTy(fn_def_id, origin) => { - self.lower_opaque_impl_trait(span, fn_def_id, origin, def_node_id, |this| { - this.lower_param_bounds(bounds, itctx) - }) + ImplTraitContext::ReturnPositionOpaqueTy { fn_def_id, origin } => self + .lower_opaque_impl_trait( + span, + Some(fn_def_id), + origin, + def_node_id, + None, + |this| this.lower_param_bounds(bounds, itctx), + ), + ImplTraitContext::OtherOpaqueTy { ref capturable_lifetimes, origin } => { + // Reset capturable lifetimes, any nested impl trait + // types will inherit lifetimes from this opaque type, + // so don't need to capture them again. + let nested_itctx = ImplTraitContext::OtherOpaqueTy { + capturable_lifetimes: &mut FxHashSet::default(), + origin, + }; + self.lower_opaque_impl_trait( + span, + None, + origin, + def_node_id, + Some(capturable_lifetimes), + |this| this.lower_param_bounds(bounds, nested_itctx), + ) } ImplTraitContext::Universal(in_band_ty_params) => { // Add a definition for the in-band `Param`. @@ -1351,6 +1405,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn_def_id: Option<DefId>, origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, + capturable_lifetimes: Option<&FxHashSet<hir::LifetimeName>>, lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>, ) -> hir::TyKind<'hir> { debug!( @@ -1371,12 +1426,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let hir_bounds = self.with_hir_id_owner(opaque_ty_node_id, lower_bounds); - let (lifetimes, lifetime_defs) = - self.lifetimes_from_impl_trait_bounds(opaque_ty_node_id, opaque_ty_def_id, &hir_bounds); + let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds( + opaque_ty_node_id, + opaque_ty_def_id, + &hir_bounds, + capturable_lifetimes, + ); - debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes,); + debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes); - debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs,); + debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs); self.with_hir_id_owner(opaque_ty_node_id, move |lctx| { let opaque_ty_item = hir::OpaqueTy { @@ -1395,7 +1454,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lctx.generate_opaque_type(opaque_ty_node_id, opaque_ty_item, span, opaque_ty_span); // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. - hir::TyKind::Def(hir::ItemId { id: opaque_ty_id }, lifetimes) + hir::TyKind::OpaqueDef(hir::ItemId { id: opaque_ty_id }, lifetimes) }) } @@ -1433,6 +1492,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { opaque_ty_id: NodeId, parent_def_id: LocalDefId, bounds: hir::GenericBounds<'hir>, + lifetimes_to_include: Option<&FxHashSet<hir::LifetimeName>>, ) -> (&'hir [hir::GenericArg<'hir>], &'hir [hir::GenericParam<'hir>]) { debug!( "lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \ @@ -1453,6 +1513,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { already_defined_lifetimes: FxHashSet<hir::LifetimeName>, output_lifetimes: Vec<hir::GenericArg<'hir>>, output_lifetime_params: Vec<hir::GenericParam<'hir>>, + lifetimes_to_include: Option<&'r FxHashSet<hir::LifetimeName>>, } impl<'r, 'a, 'v, 'hir> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a, 'hir> { @@ -1538,6 +1599,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if !self.currently_bound_lifetimes.contains(&name) && !self.already_defined_lifetimes.contains(&name) + && self.lifetimes_to_include.map_or(true, |lifetimes| lifetimes.contains(&name)) { self.already_defined_lifetimes.insert(name); @@ -1591,6 +1653,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { already_defined_lifetimes: FxHashSet::default(), output_lifetimes: Vec::new(), output_lifetime_params: Vec::new(), + lifetimes_to_include, }; for bound in bounds { @@ -1614,15 +1677,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { visitor.visit_ty(ty); } } - let parent_def_id = self.current_hir_id_owner.last().unwrap().0; let ty = l.ty.as_ref().map(|t| { + let mut capturable_lifetimes; self.lower_ty( t, if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy( - Some(parent_def_id.to_def_id()), - hir::OpaqueTyOrigin::Misc, - ) + capturable_lifetimes = FxHashSet::default(); + ImplTraitContext::OtherOpaqueTy { + capturable_lifetimes: &mut capturable_lifetimes, + origin: hir::OpaqueTyOrigin::Binding, + } } else { ImplTraitContext::Disallowed(ImplTraitPosition::Binding) }, @@ -1725,7 +1789,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { FnRetTy::Ty(ref ty) => { let context = match in_band_ty_params { Some((def_id, _)) if impl_trait_return_allow => { - ImplTraitContext::OpaqueTy(Some(def_id), hir::OpaqueTyOrigin::FnReturn) + ImplTraitContext::ReturnPositionOpaqueTy { + fn_def_id: def_id, + origin: hir::OpaqueTyOrigin::FnReturn, + } } _ => ImplTraitContext::disallowed(), }; @@ -1944,7 +2011,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Foo = impl Trait` is, internally, created as a child of the // async fn, so the *type parameters* are inherited. It's // only the lifetime parameters that we must supply. - let opaque_ty_ref = hir::TyKind::Def(hir::ItemId { id: opaque_ty_id }, generic_args); + let opaque_ty_ref = hir::TyKind::OpaqueDef(hir::ItemId { id: opaque_ty_id }, generic_args); let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref); hir::FnRetTy::Return(self.arena.alloc(opaque_ty)) } @@ -1962,8 +2029,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the // `impl Future` opaque type that `async fn` implicitly // generates. - let context = - ImplTraitContext::OpaqueTy(Some(fn_def_id), hir::OpaqueTyOrigin::FnReturn); + let context = ImplTraitContext::ReturnPositionOpaqueTy { + fn_def_id, + origin: hir::OpaqueTyOrigin::FnReturn, + }; self.lower_ty(ty, context) } FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), @@ -2113,7 +2182,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { default: default.as_ref().map(|x| { self.lower_ty( x, - ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc), + ImplTraitContext::OtherOpaqueTy { + capturable_lifetimes: &mut FxHashSet::default(), + origin: hir::OpaqueTyOrigin::Misc, + }, ) }), synthetic: param @@ -2169,8 +2241,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &NodeMap::default(), itctx.reborrow(), ); + let trait_ref = self.with_in_scope_lifetime_defs(&p.bound_generic_params, |this| { - this.lower_trait_ref(&p.trait_ref, itctx) + // Any impl Trait types defined within this scope can capture + // lifetimes bound on this predicate. + let lt_def_names = p.bound_generic_params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(hir::LifetimeName::Param( + ParamName::Plain(param.ident.normalize_to_macros_2_0()), + )), + _ => None, + }); + if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx { + capturable_lifetimes.extend(lt_def_names.clone()); + } + + let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow()); + + if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx { + for param in lt_def_names { + capturable_lifetimes.remove(¶m); + } + } + res }); hir::PolyTraitRef { bound_generic_params, trait_ref, span: p.span } diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index ffd741a7b37..a7b0c9cf81b 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -121,6 +121,14 @@ impl<'a> PostExpansionVisitor<'a> { "amdgpu-kernel ABI is experimental and subject to change" ); } + "avr-interrupt" | "avr-non-blocking-interrupt" => { + gate_feature_post!( + &self, + abi_avr_interrupt, + span, + "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change" + ); + } "efiapi" => { gate_feature_post!( &self, diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 872126646f3..b1abc08aa67 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1818,7 +1818,7 @@ impl<'a> State<'a> { ast::ExprKind::Call(ref func, ref args) => { self.print_expr_call(func, &args[..]); } - ast::ExprKind::MethodCall(ref segment, ref args) => { + ast::ExprKind::MethodCall(ref segment, ref args, _) => { self.print_expr_method_call(segment, &args[..]); } ast::ExprKind::Binary(op, ref lhs, ref rhs) => { @@ -2593,7 +2593,7 @@ impl<'a> State<'a> { } crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) { - if where_clause.predicates.is_empty() { + if where_clause.predicates.is_empty() && !where_clause.has_where_token { return; } @@ -2739,7 +2739,11 @@ impl<'a> State<'a> { } let generics = ast::Generics { params: Vec::new(), - where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP }, + where_clause: ast::WhereClause { + has_where_token: false, + predicates: Vec::new(), + span: rustc_span::DUMMY_SP, + }, span: rustc_span::DUMMY_SP, }; let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }; diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index aabd5b5b5c3..480ee97f205 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -391,7 +391,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast used[*pos] = true; } - let named_pos: FxHashSet<usize> = args.named_args.values().cloned().collect(); + let named_pos: FxHashMap<usize, Symbol> = + args.named_args.iter().map(|(&sym, &idx)| (idx, sym)).collect(); let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span)); let mut template = vec![]; for piece in unverified_pieces { @@ -405,7 +406,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast let operand_idx = match arg.position { parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => { if idx >= args.operands.len() - || named_pos.contains(&idx) + || named_pos.contains_key(&idx) || args.reg_args.contains(&idx) { let msg = format!("invalid reference to argument at index {}", idx); @@ -426,7 +427,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast }; err.note(&msg); - if named_pos.contains(&idx) { + if named_pos.contains_key(&idx) { err.span_label(args.operands[idx].1, "named argument"); err.span_note( args.operands[idx].1, @@ -457,7 +458,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast let mut chars = arg.format.ty.chars(); let mut modifier = chars.next(); - if !chars.next().is_none() { + if chars.next().is_some() { let span = arg .format .ty_span @@ -480,27 +481,31 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast } } - let operands = args.operands; - let unused_operands: Vec<_> = used - .into_iter() - .enumerate() - .filter(|&(_, used)| !used) - .map(|(idx, _)| { - if named_pos.contains(&idx) { - // named argument - (operands[idx].1, "named argument never used") + let mut unused_operands = vec![]; + let mut help_str = String::new(); + for (idx, used) in used.into_iter().enumerate() { + if !used { + let msg = if let Some(sym) = named_pos.get(&idx) { + help_str.push_str(&format!(" {{{}}}", sym)); + "named argument never used" } else { - // positional argument - (operands[idx].1, "argument never used") - } - }) - .collect(); + help_str.push_str(&format!(" {{{}}}", idx)); + "argument never used" + }; + unused_operands.push((args.operands[idx].1, msg)); + } + } match unused_operands.len() { 0 => {} 1 => { let (sp, msg) = unused_operands.into_iter().next().unwrap(); let mut err = ecx.struct_span_err(sp, msg); err.span_label(sp, msg); + err.help(&format!( + "if this argument is intentionally unused, \ + consider using it in an asm comment: `\"/*{} */\"`", + help_str + )); err.emit(); } _ => { @@ -511,6 +516,11 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast for (sp, msg) in unused_operands { err.span_label(sp, msg); } + err.help(&format!( + "if these arguments are intentionally unused, \ + consider using them in an asm comment: `\"/*{} */\"`", + help_str + )); err.emit(); } } @@ -521,7 +531,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast parser.line_spans.iter().map(|span| template_span.from_inner(*span)).collect() }; - let inline_asm = ast::InlineAsm { template, operands, options: args.options, line_spans }; + let inline_asm = + ast::InlineAsm { template, operands: args.operands, options: args.options, line_spans }; P(ast::Expr { id: ast::DUMMY_NODE_ID, kind: ast::ExprKind::InlineAsm(P(inline_asm)), diff --git a/src/librustc_builtin_macros/deriving/generic/ty.rs b/src/librustc_builtin_macros/deriving/generic/ty.rs index 62cbdb19a88..609feb6f259 100644 --- a/src/librustc_builtin_macros/deriving/generic/ty.rs +++ b/src/librustc_builtin_macros/deriving/generic/ty.rs @@ -216,7 +216,11 @@ fn mk_ty_param( } fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics { - Generics { params, where_clause: ast::WhereClause { predicates: Vec::new(), span }, span } + Generics { + params, + where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span }, + span, + } } /// Lifetimes and bounds on type parameters diff --git a/src/librustc_builtin_macros/source_util.rs b/src/librustc_builtin_macros/source_util.rs index 67145c6bf43..1b164eae5a3 100644 --- a/src/librustc_builtin_macros/source_util.rs +++ b/src/librustc_builtin_macros/source_util.rs @@ -122,6 +122,7 @@ pub fn expand_include<'cx>( struct ExpandResult<'a> { p: Parser<'a>, + node_id: ast::NodeId, } impl<'a> base::MacResult for ExpandResult<'a> { fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> { @@ -130,7 +131,7 @@ pub fn expand_include<'cx>( self.p.sess.buffer_lint( &INCOMPLETE_INCLUDE, self.p.token.span, - ast::CRATE_NODE_ID, + self.node_id, "include macro expected single expression in source", ); } @@ -158,7 +159,7 @@ pub fn expand_include<'cx>( } } - Box::new(ExpandResult { p }) + Box::new(ExpandResult { p, node_id: cx.resolver.lint_node_id(cx.current_expansion.id) }) } // include_str! : read the given file, insert it as a literal string expr diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 8e9c5f25ccb..099c402703d 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -375,6 +375,8 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { match self.conv { Conv::C | Conv::Rust => llvm::CCallConv, Conv::AmdGpuKernel => llvm::AmdGpuKernel, + Conv::AvrInterrupt => llvm::AvrInterrupt, + Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, Conv::ArmAapcs => llvm::ArmAapcsCallConv, Conv::Msp430Intr => llvm::Msp430Intr, Conv::PtxKernel => llvm::PtxKernel, diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 02a9294930d..26f5334668b 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -16,7 +16,7 @@ use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, Mo use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_errors::{FatalError, Handler}; +use rustc_errors::{FatalError, Handler, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; @@ -242,6 +242,7 @@ impl<'a> Drop for DiagnosticHandlers<'a> { fn report_inline_asm( cgcx: &CodegenContext<LlvmCodegenBackend>, msg: String, + level: llvm::DiagnosticLevel, mut cookie: c_uint, source: Option<(String, Vec<InnerSpan>)>, ) { @@ -251,7 +252,12 @@ fn report_inline_asm( if matches!(cgcx.lto, Lto::Fat | Lto::Thin) { cookie = 0; } - cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, source); + let level = match level { + llvm::DiagnosticLevel::Error => Level::Error, + llvm::DiagnosticLevel::Warning => Level::Warning, + llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, + }; + cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source); } unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void, cookie: c_uint) { @@ -264,6 +270,7 @@ unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void // diagnostics. let mut have_source = false; let mut buffer = String::new(); + let mut level = llvm::DiagnosticLevel::Error; let mut loc = 0; let mut ranges = [0; 8]; let mut num_ranges = ranges.len() / 2; @@ -273,6 +280,7 @@ unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void diag, msg, buffer, + &mut level, &mut loc, ranges.as_mut_ptr(), &mut num_ranges, @@ -290,7 +298,7 @@ unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void (buffer, spans) }); - report_inline_asm(cgcx, msg, cookie, source); + report_inline_asm(cgcx, msg, level, cookie, source); } unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) { @@ -301,7 +309,13 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void match llvm::diagnostic::Diagnostic::unpack(info) { llvm::diagnostic::InlineAsm(inline) => { - report_inline_asm(cgcx, llvm::twine_to_string(inline.message), inline.cookie, None); + report_inline_asm( + cgcx, + llvm::twine_to_string(inline.message), + inline.level, + inline.cookie, + None, + ); } llvm::diagnostic::Optimization(opt) => { diff --git a/src/librustc_codegen_llvm/llvm/diagnostic.rs b/src/librustc_codegen_llvm/llvm/diagnostic.rs index 4347cd06532..47f5c94e70c 100644 --- a/src/librustc_codegen_llvm/llvm/diagnostic.rs +++ b/src/librustc_codegen_llvm/llvm/diagnostic.rs @@ -88,6 +88,7 @@ impl OptimizationDiagnostic<'ll> { #[derive(Copy, Clone)] pub struct InlineAsmDiagnostic<'ll> { + pub level: super::DiagnosticLevel, pub cookie: c_uint, pub message: &'ll Twine, pub instruction: Option<&'ll Value>, @@ -98,10 +99,17 @@ impl InlineAsmDiagnostic<'ll> { let mut cookie = 0; let mut message = None; let mut instruction = None; + let mut level = super::DiagnosticLevel::Error; - super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut cookie, &mut message, &mut instruction); + super::LLVMRustUnpackInlineAsmDiagnostic( + di, + &mut level, + &mut cookie, + &mut message, + &mut instruction, + ); - InlineAsmDiagnostic { cookie, message: message.unwrap(), instruction } + InlineAsmDiagnostic { level, cookie, message: message.unwrap(), instruction } } } diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 759c2bf1b85..54cf99e1c6d 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -45,6 +45,8 @@ pub enum CallConv { X86_64_Win64 = 79, X86_VectorCall = 80, X86_Intr = 83, + AvrNonBlockingInterrupt = 84, + AvrInterrupt = 85, AmdGpuKernel = 91, } @@ -489,6 +491,17 @@ pub enum DiagnosticKind { Linker, } +/// LLVMRustDiagnosticLevel +#[derive(Copy, Clone)] +#[repr(C)] +#[allow(dead_code)] // Variants constructed by C++. +pub enum DiagnosticLevel { + Error, + Warning, + Note, + Remark, +} + /// LLVMRustArchiveKind #[derive(Copy, Clone)] #[repr(C)] @@ -2054,6 +2067,7 @@ extern "C" { pub fn LLVMRustUnpackInlineAsmDiagnostic( DI: &'a DiagnosticInfo, + level_out: &mut DiagnosticLevel, cookie_out: &mut c_uint, message_out: &mut Option<&'a Twine>, instruction_out: &mut Option<&'a Value>, @@ -2074,6 +2088,7 @@ extern "C" { d: &SMDiagnostic, message_out: &RustString, buffer_out: &RustString, + level_out: &mut DiagnosticLevel, loc_out: &mut c_uint, ranges_out: *mut c_uint, num_ranges: &mut usize, diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index d9fed998c92..b17c3678207 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -481,10 +481,12 @@ impl<'a> Linker for GccLinker<'a> { match strip { Strip::None => {} Strip::Debuginfo => { - self.linker_arg("--strip-debug"); + // MacOS linker does not support longhand argument --strip-debug + self.linker_arg("-S"); } Strip::Symbols => { - self.linker_arg("--strip-all"); + // MacOS linker does not support longhand argument --strip-all + self.linker_arg("-s"); } } } diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index cb5c95c11fa..c118e5ebdb7 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -1551,7 +1551,7 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B> enum SharedEmitterMessage { Diagnostic(Diagnostic), - InlineAsmError(u32, String, Option<(String, Vec<InnerSpan>)>), + InlineAsmError(u32, String, Level, Option<(String, Vec<InnerSpan>)>), AbortIfErrors, Fatal(String), } @@ -1576,9 +1576,10 @@ impl SharedEmitter { &self, cookie: u32, msg: String, + level: Level, source: Option<(String, Vec<InnerSpan>)>, ) { - drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, source))); + drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source))); } pub fn fatal(&self, msg: &str) { @@ -1631,16 +1632,21 @@ impl SharedEmitterMain { } handler.emit_diagnostic(&d); } - Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, source)) => { + Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { let msg = msg.strip_prefix("error: ").unwrap_or(&msg); + let mut err = match level { + Level::Error => sess.struct_err(&msg), + Level::Warning => sess.struct_warn(&msg), + Level::Note => sess.struct_note_without_error(&msg), + _ => bug!("Invalid inline asm diagnostic level"), + }; + // If the cookie is 0 then we don't have span information. - let mut err = if cookie == 0 { - sess.struct_err(&msg) - } else { + if cookie != 0 { let pos = BytePos::from_u32(cookie); let span = Span::with_root_ctxt(pos, pos); - sess.struct_span_err(span, &msg) + err.set_span(span); }; // Point to the generated assembly if it is available. diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 30a84c4e47b..ef59ad486ee 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -530,6 +530,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args: &Vec<mir::Operand<'tcx>>, destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>, cleanup: Option<mir::BasicBlock>, + fn_span: Span, ) { let span = terminator.source_info.span; // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. @@ -634,7 +635,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if intrinsic == Some("caller_location") { if let Some((_, target)) = destination.as_ref() { - let location = self.get_caller_location(&mut bx, span); + let location = self.get_caller_location(&mut bx, fn_span); if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { location.val.store(&mut bx, tmp); @@ -798,7 +799,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args.len() + 1, "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", ); - let location = self.get_caller_location(&mut bx, span); + let location = self.get_caller_location(&mut bx, fn_span); + debug!( + "codegen_call_terminator({:?}): location={:?} (fn_span {:?})", + terminator, location, fn_span + ); + let last_arg = fn_abi.args.last().unwrap(); self.codegen_argument(&mut bx, location, &mut llargs, last_arg); } @@ -921,12 +927,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { span_bug!(span, "invalid type for asm sym (fn)"); } } - mir::InlineAsmOperand::SymStatic { ref value } => { - if let Some(def_id) = value.check_static_ptr(bx.tcx()) { - InlineAsmOperandRef::SymStatic { def_id } - } else { - span_bug!(span, "invalid type for asm sym (static)"); - } + mir::InlineAsmOperand::SymStatic { def_id } => { + InlineAsmOperandRef::SymStatic { def_id } } }) .collect(); @@ -1016,6 +1018,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ref destination, cleanup, from_hir_call: _, + fn_span, } => { self.codegen_call_terminator( helper, @@ -1025,6 +1028,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args, destination, cleanup, + fn_span, ); } mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Yield { .. } => { diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 574f91e5b4d..11ec62f96ed 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -63,7 +63,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .tcx() .destructure_const(ty::ParamEnv::reveal_all().and(&c)) .fields - .into_iter() + .iter() .map(|field| { if let Some(prim) = field.val.try_to_scalar() { let layout = bx.layout_of(field_ty); diff --git a/src/librustc_data_structures/base_n/tests.rs b/src/librustc_data_structures/base_n/tests.rs index a86f991cd0e..b68ef1eb7f4 100644 --- a/src/librustc_data_structures/base_n/tests.rs +++ b/src/librustc_data_structures/base_n/tests.rs @@ -12,8 +12,8 @@ fn test_encode() { test(35, base); test(36, base); test(37, base); - test(u64::max_value() as u128, base); - test(u128::max_value(), base); + test(u64::MAX as u128, base); + test(u128::MAX, base); for i in 0..1_000 { test(i * 983, base); diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 7abe75a375a..3fb5e04efc9 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -409,6 +409,7 @@ E0718: include_str!("./error_codes/E0718.md"), E0719: include_str!("./error_codes/E0719.md"), E0720: include_str!("./error_codes/E0720.md"), E0723: include_str!("./error_codes/E0723.md"), +E0724: include_str!("./error_codes/E0724.md"), E0725: include_str!("./error_codes/E0725.md"), E0727: include_str!("./error_codes/E0727.md"), E0728: include_str!("./error_codes/E0728.md"), @@ -437,7 +438,10 @@ E0751: include_str!("./error_codes/E0751.md"), E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), E0754: include_str!("./error_codes/E0754.md"), +E0758: include_str!("./error_codes/E0758.md"), E0760: include_str!("./error_codes/E0760.md"), +E0761: include_str!("./error_codes/E0761.md"), +E0762: include_str!("./error_codes/E0762.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard @@ -614,7 +618,6 @@ E0760: include_str!("./error_codes/E0760.md"), E0717, // rustc_promotable without stability attribute // E0721, // `await` keyword E0722, // Malformed `#[optimize]` attribute - E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. E0755, // `#[ffi_pure]` is only allowed on foreign functions diff --git a/src/librustc_error_codes/error_codes/E0207.md b/src/librustc_error_codes/error_codes/E0207.md index 21e7e461c75..cb4f5d5157d 100644 --- a/src/librustc_error_codes/error_codes/E0207.md +++ b/src/librustc_error_codes/error_codes/E0207.md @@ -1,4 +1,4 @@ -A type or lifetime parameter that is specified for `impl` is not constrained. +A type parameter that is specified for `impl` is not constrained. Erroneous code example: @@ -14,7 +14,7 @@ impl<T: Default> Foo { } ``` -Any type parameter or lifetime parameter of an `impl` must meet at least one of +Any type parameter parameter of an `impl` must meet at least one of the following criteria: - it appears in the _implementing type_ of the impl, e.g. `impl<T> Foo<T>` diff --git a/src/librustc_error_codes/error_codes/E0583.md b/src/librustc_error_codes/error_codes/E0583.md index 2dcbbf88556..701900bb0cd 100644 --- a/src/librustc_error_codes/error_codes/E0583.md +++ b/src/librustc_error_codes/error_codes/E0583.md @@ -2,7 +2,7 @@ A file wasn't found for an out-of-line module. Erroneous code example: -```ignore (compile_fail not working here; see Issue #43707) +```compile_fail,E0583 mod file_that_doesnt_exist; // error: file not found for module fn main() {} diff --git a/src/librustc_error_codes/error_codes/E0642.md b/src/librustc_error_codes/error_codes/E0642.md index 592ada6ecad..c790aa154bd 100644 --- a/src/librustc_error_codes/error_codes/E0642.md +++ b/src/librustc_error_codes/error_codes/E0642.md @@ -1,6 +1,6 @@ Trait methods currently cannot take patterns as arguments. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0642 trait Foo { diff --git a/src/librustc_error_codes/error_codes/E0646.md b/src/librustc_error_codes/error_codes/E0646.md index e01dbae8b90..1e9ec7d4380 100644 --- a/src/librustc_error_codes/error_codes/E0646.md +++ b/src/librustc_error_codes/error_codes/E0646.md @@ -1,4 +1,5 @@ It is not possible to define `main` with a where clause. + Erroneous code example: ```compile_fail,E0646 diff --git a/src/librustc_error_codes/error_codes/E0647.md b/src/librustc_error_codes/error_codes/E0647.md index 131db38c00d..8ca6e777f30 100644 --- a/src/librustc_error_codes/error_codes/E0647.md +++ b/src/librustc_error_codes/error_codes/E0647.md @@ -1,4 +1,5 @@ -It is not possible to define `start` with a where clause. +The `start` function was defined with a where clause. + Erroneous code example: ```compile_fail,E0647 diff --git a/src/librustc_error_codes/error_codes/E0648.md b/src/librustc_error_codes/error_codes/E0648.md index 319bae103f3..d99dc19503d 100644 --- a/src/librustc_error_codes/error_codes/E0648.md +++ b/src/librustc_error_codes/error_codes/E0648.md @@ -1,6 +1,15 @@ -`export_name` attributes may not contain null characters (`\0`). +An `export_name` attribute contains null characters (`\0`). + +Erroneous code example: ```compile_fail,E0648 #[export_name="\0foo"] // error: `export_name` may not contain null characters pub fn bar() {} ``` + +To fix this error, remove the null characters: + +``` +#[export_name="foo"] // ok! +pub fn bar() {} +``` diff --git a/src/librustc_error_codes/error_codes/E0666.md b/src/librustc_error_codes/error_codes/E0666.md index 22133683dc5..1a0dc5a5229 100644 --- a/src/librustc_error_codes/error_codes/E0666.md +++ b/src/librustc_error_codes/error_codes/E0666.md @@ -1,21 +1,25 @@ -`impl Trait` types cannot appear nested in the -generic arguments of other `impl Trait` types. +`impl Trait` types cannot appear nested in the generic arguments of other +`impl Trait` types. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0666 trait MyGenericTrait<T> {} trait MyInnerTrait {} -fn foo(bar: impl MyGenericTrait<impl MyInnerTrait>) {} +fn foo( + bar: impl MyGenericTrait<impl MyInnerTrait>, // error! +) {} ``` -Type parameters for `impl Trait` types must be -explicitly defined as named generic parameters: +Type parameters for `impl Trait` types must be explicitly defined as named +generic parameters: ``` trait MyGenericTrait<T> {} trait MyInnerTrait {} -fn foo<T: MyInnerTrait>(bar: impl MyGenericTrait<T>) {} +fn foo<T: MyInnerTrait>( + bar: impl MyGenericTrait<T>, // ok! +) {} ``` diff --git a/src/librustc_error_codes/error_codes/E0724.md b/src/librustc_error_codes/error_codes/E0724.md new file mode 100644 index 00000000000..7a7ba154854 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0724.md @@ -0,0 +1,24 @@ +`#[ffi_returns_twice]` was used on non-foreign function. + +Erroneous code example: + +```compile_fail,E0724 +#![feature(ffi_returns_twice)] +#![crate_type = "lib"] + +#[ffi_returns_twice] // error! +pub fn foo() {} +``` + +`#[ffi_returns_twice]` can only be used on foreign function declarations. +For example, we might correct the previous example by declaring +the function inside of an `extern` block. + +``` +#![feature(ffi_returns_twice)] + +extern { + #[ffi_returns_twice] // ok! + pub fn foo(); +} +``` diff --git a/src/librustc_error_codes/error_codes/E0758.md b/src/librustc_error_codes/error_codes/E0758.md new file mode 100644 index 00000000000..ddca4b3d75f --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0758.md @@ -0,0 +1,20 @@ +A multi-line (doc-)comment is unterminated. + +Erroneous code example: + +```compile_fail,E0758 +/* I am not terminated! +``` + +The same goes for doc comments: + +```compile_fail,E0758 +/*! I am not terminated! +``` + +You need to end your multi-line comment with `*/` in order to fix this error: + +``` +/* I am terminated! */ +/*! I am also terminated! */ +``` diff --git a/src/librustc_error_codes/error_codes/E0761.md b/src/librustc_error_codes/error_codes/E0761.md new file mode 100644 index 00000000000..c01574e413c --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0761.md @@ -0,0 +1,25 @@ +Multiple candidate files were found for an out-of-line module. + +Erroneous code example: + +```rust +// file: ambiguous_module/mod.rs + +fn foo() {} +``` + +```rust +// file: ambiguous_module.rs + +fn foo() {} +``` + +```ignore (multiple source files required for compile_fail) +mod ambiguous_module; // error: file for module `ambiguous_module` + // found at both ambiguous_module.rs and + // ambiguous_module.rs/mod.rs + +fn main() {} +``` + +Please remove this ambiguity by deleting/renaming one of the candidate files. diff --git a/src/librustc_error_codes/error_codes/E0762.md b/src/librustc_error_codes/error_codes/E0762.md new file mode 100644 index 00000000000..b01ded4a866 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0762.md @@ -0,0 +1,13 @@ +A character literal wasn't ended with a quote. + +Erroneous code example: + +```compile_fail,E0762 +static C: char = '●; // error! +``` + +To fix this error, add the missing quote: + +``` +static C: char = '●'; // ok! +``` diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index ed1f43e567d..7f72161aff8 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -17,7 +17,7 @@ rustc_data_structures = { path = "../librustc_data_structures" } unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" -annotate-snippets = "0.6.1" +annotate-snippets = "0.8.0" termize = "0.1.1" [target.'cfg(windows)'.dependencies] diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs index d83175694f4..265ba59cccb 100644 --- a/src/librustc_errors/annotate_snippet_emitter_writer.rs +++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs @@ -8,12 +8,11 @@ use crate::emitter::FileWithAnnotatedLines; use crate::snippet::Line; use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Emitter, Level, SubDiagnostic}; -use annotate_snippets::display_list::DisplayList; -use annotate_snippets::formatter::DisplayListFormatter; +use annotate_snippets::display_list::{DisplayList, FormatOptions}; use annotate_snippets::snippet::*; use rustc_data_structures::sync::Lrc; use rustc_span::source_map::SourceMap; -use rustc_span::{Loc, MultiSpan, SourceFile}; +use rustc_span::{MultiSpan, SourceFile}; /// Generates diagnostics using annotate-snippet pub struct AnnotateSnippetEmitterWriter { @@ -59,112 +58,20 @@ impl Emitter for AnnotateSnippetEmitterWriter { } } -/// Collects all the data needed to generate the data structures needed for the -/// `annotate-snippets` library. -struct DiagnosticConverter<'a> { - source_map: Option<Lrc<SourceMap>>, - level: Level, - message: String, - code: Option<DiagnosticId>, - msp: MultiSpan, - #[allow(dead_code)] - children: &'a [SubDiagnostic], - #[allow(dead_code)] - suggestions: &'a [CodeSuggestion], +/// Provides the source string for the given `line` of `file` +fn source_string(file: Lrc<SourceFile>, line: &Line) -> String { + file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default() } -impl<'a> DiagnosticConverter<'a> { - /// Turns rustc Diagnostic information into a `annotate_snippets::snippet::Snippet`. - fn to_annotation_snippet(&self) -> Option<Snippet> { - if let Some(source_map) = &self.source_map { - // Make sure our primary file comes first - let primary_lo = if let Some(ref primary_span) = self.msp.primary_span().as_ref() { - source_map.lookup_char_pos(primary_span.lo()) - } else { - // FIXME(#59346): Not sure when this is the case and what - // should be done if it happens - return None; - }; - let annotated_files = - FileWithAnnotatedLines::collect_annotations(&self.msp, &self.source_map); - let slices = self.slices_for_files(annotated_files, primary_lo); - - Some(Snippet { - title: Some(Annotation { - label: Some(self.message.to_string()), - id: self.code.clone().map(|c| match c { - DiagnosticId::Error(val) | DiagnosticId::Lint(val) => val, - }), - annotation_type: Self::annotation_type_for_level(self.level), - }), - footer: vec![], - slices, - }) - } else { - // FIXME(#59346): Is it ok to return None if there's no source_map? - None - } - } - - fn slices_for_files( - &self, - annotated_files: Vec<FileWithAnnotatedLines>, - primary_lo: Loc, - ) -> Vec<Slice> { - // FIXME(#64205): Provide a test case where `annotated_files` is > 1 - annotated_files - .iter() - .flat_map(|annotated_file| { - annotated_file - .lines - .iter() - .map(|line| { - let line_source = Self::source_string(annotated_file.file.clone(), &line); - Slice { - source: line_source, - line_start: line.line_index, - origin: Some(primary_lo.file.name.to_string()), - // FIXME(#59346): Not really sure when `fold` should be true or false - fold: false, - annotations: line - .annotations - .iter() - .map(|a| self.annotation_to_source_annotation(a.clone())) - .collect(), - } - }) - .collect::<Vec<Slice>>() - }) - .collect::<Vec<Slice>>() - } - - /// Turns a `crate::snippet::Annotation` into a `SourceAnnotation` - fn annotation_to_source_annotation( - &self, - annotation: crate::snippet::Annotation, - ) -> SourceAnnotation { - SourceAnnotation { - range: (annotation.start_col, annotation.end_col), - label: annotation.label.unwrap_or("".to_string()), - annotation_type: Self::annotation_type_for_level(self.level), - } - } - - /// Provides the source string for the given `line` of `file` - fn source_string(file: Lrc<SourceFile>, line: &Line) -> String { - file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or(String::new()) - } - - /// Maps `Diagnostic::Level` to `snippet::AnnotationType` - fn annotation_type_for_level(level: Level) -> AnnotationType { - match level { - Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error, - Level::Warning => AnnotationType::Warning, - Level::Note => AnnotationType::Note, - Level::Help => AnnotationType::Help, - // FIXME(#59346): Not sure how to map these two levels - Level::Cancelled | Level::FailureNote => AnnotationType::Error, - } +/// Maps `Diagnostic::Level` to `snippet::AnnotationType` +fn annotation_type_for_level(level: Level) -> AnnotationType { + match level { + Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error, + Level::Warning => AnnotationType::Warning, + Level::Note => AnnotationType::Note, + Level::Help => AnnotationType::Help, + // FIXME(#59346): Not sure how to map these two levels + Level::Cancelled | Level::FailureNote => AnnotationType::Error, } } @@ -191,25 +98,83 @@ impl AnnotateSnippetEmitterWriter { message: String, code: &Option<DiagnosticId>, msp: &MultiSpan, - children: &[SubDiagnostic], - suggestions: &[CodeSuggestion], + _children: &[SubDiagnostic], + _suggestions: &[CodeSuggestion], ) { - let converter = DiagnosticConverter { - source_map: self.source_map.clone(), - level: *level, - message, - code: code.clone(), - msp: msp.clone(), - children, - suggestions, - }; - if let Some(snippet) = converter.to_annotation_snippet() { - let dl = DisplayList::from(snippet); - let dlf = DisplayListFormatter::new(true, self.ui_testing); + if let Some(source_map) = &self.source_map { + // Make sure our primary file comes first + let primary_lo = if let Some(ref primary_span) = msp.primary_span().as_ref() { + if primary_span.is_dummy() { + // FIXME(#59346): Not sure when this is the case and what + // should be done if it happens + return; + } else { + source_map.lookup_char_pos(primary_span.lo()) + } + } else { + // FIXME(#59346): Not sure when this is the case and what + // should be done if it happens + return; + }; + let mut annotated_files = + FileWithAnnotatedLines::collect_annotations(msp, &self.source_map); + if let Ok(pos) = + annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) + { + annotated_files.swap(0, pos); + } + // owned: line source, line index, annotations + type Owned = (String, usize, Vec<crate::snippet::Annotation>); + let origin = primary_lo.file.name.to_string(); + let annotated_files: Vec<Owned> = annotated_files + .into_iter() + .flat_map(|annotated_file| { + let file = annotated_file.file; + annotated_file + .lines + .into_iter() + .map(|line| { + (source_string(file.clone(), &line), line.line_index, line.annotations) + }) + .collect::<Vec<Owned>>() + }) + .collect(); + let snippet = Snippet { + title: Some(Annotation { + label: Some(&message), + id: code.as_ref().map(|c| match c { + DiagnosticId::Error(val) | DiagnosticId::Lint(val) => val.as_str(), + }), + annotation_type: annotation_type_for_level(*level), + }), + footer: vec![], + opt: FormatOptions { color: true, anonymized_line_numbers: self.ui_testing }, + slices: annotated_files + .iter() + .map(|(source, line_index, annotations)| { + Slice { + source, + line_start: *line_index, + origin: Some(&origin), + // FIXME(#59346): Not really sure when `fold` should be true or false + fold: false, + annotations: annotations + .iter() + .map(|annotation| SourceAnnotation { + range: (annotation.start_col, annotation.end_col), + label: annotation.label.as_deref().unwrap_or_default(), + annotation_type: annotation_type_for_level(*level), + }) + .collect(), + } + }) + .collect(), + }; // FIXME(#59346): Figure out if we can _always_ print to stderr or not. // `emitter.rs` has the `Destination` enum that lists various possible output // destinations. - eprintln!("{}", dlf.format(&dl)); - }; + eprintln!("{}", DisplayList::from(snippet)) + } + // FIXME(#59346): Is it ok to return None if there's no source_map? } } diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index cff83c3d5cd..acaa26c6ad2 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -296,6 +296,29 @@ impl Diagnostic { self } + pub fn multipart_suggestions( + &mut self, + msg: &str, + suggestions: Vec<Vec<(Span, String)>>, + applicability: Applicability, + ) -> &mut Self { + self.suggestions.push(CodeSuggestion { + substitutions: suggestions + .into_iter() + .map(|suggestion| Substitution { + parts: suggestion + .into_iter() + .map(|(span, snippet)| SubstitutionPart { snippet, span }) + .collect(), + }) + .collect(), + msg: msg.to_owned(), + style: SuggestionStyle::ShowCode, + applicability, + }); + self + } + /// Prints out a message with for a multipart suggestion without showing the suggested code. /// /// This is intended to be used for suggestions that are obvious in what the changes need to diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 2dbd9f4e52f..22bf8fe34aa 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -260,6 +260,19 @@ impl<'a> DiagnosticBuilder<'a> { self } + pub fn multipart_suggestions( + &mut self, + msg: &str, + suggestions: Vec<Vec<(Span, String)>>, + applicability: Applicability, + ) -> &mut Self { + if !self.0.allow_suggestions { + return self; + } + self.0.diagnostic.multipart_suggestions(msg, suggestions, applicability); + self + } + pub fn tool_only_multipart_suggestion( &mut self, msg: &str, diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index e4a560e434a..7261c638ce0 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -581,6 +581,11 @@ impl Handler { DiagnosticBuilder::new(self, Level::Help, msg) } + /// Construct a builder at the `Note` level with the `msg`. + pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_> { + DiagnosticBuilder::new(self, Level::Note, msg) + } + pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: &str) -> FatalError { self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span); FatalError diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 13637e58c93..a57ae798ffc 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -915,6 +915,9 @@ pub trait Resolver { fn check_unused_macros(&mut self); + /// Some parent node that is close enough to the given macro call. + fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId; + fn has_derive_copy(&self, expn_id: ExpnId) -> bool; fn add_derive_copy(&mut self, expn_id: ExpnId); fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>; diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index 6185e014d3c..20d2ea0a215 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -272,7 +272,7 @@ impl<'a> ExtCtxt<'a> { ) -> P<ast::Expr> { args.insert(0, expr); let segment = ast::PathSegment::from_ident(ident.with_span_pos(span)); - self.expr(span, ast::ExprKind::MethodCall(segment, args)) + self.expr(span, ast::ExprKind::MethodCall(segment, args, span)) } pub fn expr_block(&self, b: P<ast::Block>) -> P<ast::Expr> { self.expr(b.span, ast::ExprKind::Block(b, None)) diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 5214ca0dc7f..4e41bd4bbfa 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -1789,6 +1789,7 @@ pub struct ExpansionConfig<'feat> { pub trace_mac: bool, pub should_test: bool, // If false, strip `#[test]` nodes pub keep_macs: bool, + pub span_debug: bool, // If true, use verbose debugging for `proc_macro::Span` } impl<'feat> ExpansionConfig<'feat> { @@ -1800,6 +1801,7 @@ impl<'feat> ExpansionConfig<'feat> { trace_mac: false, should_test: false, keep_macs: false, + span_debug: false, } } diff --git a/src/librustc_expand/mbe/macro_check.rs b/src/librustc_expand/mbe/macro_check.rs index 582c26162ed..ca3e68fa670 100644 --- a/src/librustc_expand/mbe/macro_check.rs +++ b/src/librustc_expand/mbe/macro_check.rs @@ -106,7 +106,7 @@ //! bound. use crate::mbe::{KleeneToken, TokenTree}; -use rustc_ast::ast::NodeId; +use rustc_ast::ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast::token::{DelimToken, Token, TokenKind}; use rustc_data_structures::fx::FxHashMap; use rustc_session::lint::builtin::META_VARIABLE_MISUSE; @@ -626,5 +626,8 @@ fn ops_is_prefix( } fn buffer_lint(sess: &ParseSess, span: MultiSpan, node_id: NodeId, message: &str) { - sess.buffer_lint(&META_VARIABLE_MISUSE, span, node_id, message); + // Macros loaded from other crates have dummy node ids. + if node_id != DUMMY_NODE_ID { + sess.buffer_lint(&META_VARIABLE_MISUSE, span, node_id, message); + } } diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index 0cf092d912b..db8258a7786 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -383,7 +383,7 @@ fn nameize<I: Iterator<Item = NamedMatch>>( } } TokenTree::MetaVarDecl(span, _, id) if id.name == kw::Invalid => { - if sess.missing_fragment_specifiers.borrow_mut().remove(&span) { + if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { return Err((span, "missing fragment specifier".to_string())); } } @@ -566,7 +566,7 @@ fn inner_parse_loop<'root, 'tt>( // We need to match a metavar (but the identifier is invalid)... this is an error TokenTree::MetaVarDecl(span, _, id) if id.name == kw::Invalid => { - if sess.missing_fragment_specifiers.borrow_mut().remove(&span) { + if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { return Error(span, "missing fragment specifier".to_string()); } } diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index ecadf320f87..8cdb5b09c9e 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -474,7 +474,9 @@ pub fn compile_declarative_macro( .map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { - let tt = mbe::quoted::parse(tt.clone().into(), true, sess).pop().unwrap(); + let tt = mbe::quoted::parse(tt.clone().into(), true, sess, def.id) + .pop() + .unwrap(); valid &= check_lhs_nt_follows(sess, features, &def.attrs, &tt); return tt; } @@ -491,7 +493,9 @@ pub fn compile_declarative_macro( .map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { - return mbe::quoted::parse(tt.clone().into(), false, sess).pop().unwrap(); + return mbe::quoted::parse(tt.clone().into(), false, sess, def.id) + .pop() + .unwrap(); } } sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") @@ -509,9 +513,7 @@ pub fn compile_declarative_macro( valid &= check_lhs_no_empty_seq(sess, slice::from_ref(lhs)); } - // We use CRATE_NODE_ID instead of `def.id` otherwise we may emit buffered lints for a node id - // that is not lint-checked and trigger the "failed to process buffered lint here" bug. - valid &= macro_check::check_meta_variables(sess, ast::CRATE_NODE_ID, def.span, &lhses, &rhses); + valid &= macro_check::check_meta_variables(sess, def.id, def.span, &lhses, &rhses); let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules); match transparency_error { diff --git a/src/librustc_expand/mbe/quoted.rs b/src/librustc_expand/mbe/quoted.rs index 3295f5b392d..de66c2ada40 100644 --- a/src/librustc_expand/mbe/quoted.rs +++ b/src/librustc_expand/mbe/quoted.rs @@ -1,6 +1,7 @@ use crate::mbe::macro_parser; use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree}; +use rustc_ast::ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream; use rustc_ast_pretty::pprust; @@ -36,6 +37,7 @@ pub(super) fn parse( input: tokenstream::TokenStream, expect_matchers: bool, sess: &ParseSess, + node_id: NodeId, ) -> Vec<TokenTree> { // Will contain the final collection of `self::TokenTree` let mut result = Vec::new(); @@ -46,7 +48,7 @@ pub(super) fn parse( while let Some(tree) = trees.next() { // Given the parsed tree, if there is a metavar and we are expecting matchers, actually // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`). - let tree = parse_tree(tree, &mut trees, expect_matchers, sess); + let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id); match tree { TokenTree::MetaVar(start_sp, ident) if expect_matchers => { let span = match trees.next() { @@ -65,7 +67,10 @@ pub(super) fn parse( } tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp), }; - sess.missing_fragment_specifiers.borrow_mut().insert(span); + if node_id != DUMMY_NODE_ID { + // Macros loaded from other crates have dummy node ids. + sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id); + } result.push(TokenTree::MetaVarDecl(span, ident, Ident::invalid())); } @@ -96,6 +101,7 @@ fn parse_tree( trees: &mut impl Iterator<Item = tokenstream::TokenTree>, expect_matchers: bool, sess: &ParseSess, + node_id: NodeId, ) -> TokenTree { // Depending on what `tree` is, we could be parsing different parts of a macro match tree { @@ -111,7 +117,7 @@ fn parse_tree( sess.span_diagnostic.span_err(span.entire(), &msg); } // Parse the contents of the sequence itself - let sequence = parse(tts, expect_matchers, sess); + let sequence = parse(tts, expect_matchers, sess, node_id); // Get the Kleene operator and optional separator let (separator, kleene) = parse_sep_and_kleene_op(trees, span.entire(), sess); // Count the number of captured "names" (i.e., named metavars) @@ -158,7 +164,7 @@ fn parse_tree( // descend into the delimited set and further parse it. tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited( span, - Lrc::new(Delimited { delim, tts: parse(tts, expect_matchers, sess) }), + Lrc::new(Delimited { delim, tts: parse(tts, expect_matchers, sess, node_id) }), ), } } diff --git a/src/librustc_expand/module.rs b/src/librustc_expand/module.rs index 82215c7297e..535c1dbad04 100644 --- a/src/librustc_expand/module.rs +++ b/src/librustc_expand/module.rs @@ -291,7 +291,7 @@ pub fn default_submod_path<'a>( let mut err = struct_span_err!( sess.span_diagnostic, span, - E0584, + E0761, "file for module `{}` found at both {} and {}", mod_name, default_path_str, diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index 36af83711f7..ea55674045c 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -352,6 +352,7 @@ pub(crate) struct Rustc<'a> { def_site: Span, call_site: Span, mixed_site: Span, + span_debug: bool, } impl<'a> Rustc<'a> { @@ -362,6 +363,7 @@ impl<'a> Rustc<'a> { def_site: cx.with_def_site_ctxt(expn_data.def_site), call_site: cx.with_call_site_ctxt(expn_data.call_site), mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site), + span_debug: cx.ecfg.span_debug, } } @@ -580,10 +582,10 @@ impl server::Literal for Rustc<'_> { }; // Bounds check the values, preventing addition overflow and OOB spans. - if start > u32::max_value() as usize - || end > u32::max_value() as usize - || (u32::max_value() - start as u32) < span.lo().to_u32() - || (u32::max_value() - end as u32) < span.lo().to_u32() + if start > u32::MAX as usize + || end > u32::MAX as usize + || (u32::MAX - start as u32) < span.lo().to_u32() + || (u32::MAX - end as u32) < span.lo().to_u32() || start >= end || end > length { @@ -646,7 +648,11 @@ impl server::Diagnostic for Rustc<'_> { impl server::Span for Rustc<'_> { fn debug(&mut self, span: Self::Span) -> String { - format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0) + if self.span_debug { + format!("{:?}", span) + } else { + format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0) + } } fn def_site(&mut self) -> Self::Span { self.def_site diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index fd35cb6c3f7..b4935236b6a 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -574,6 +574,9 @@ declare_features! ( /// No longer treat an unsafe function as an unsafe block. (active, unsafe_block_in_unsafe_fn, "1.45.0", Some(71668), None), + /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. + (active, abi_avr_interrupt, "1.45.0", Some(69664), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/librustc_hir/arena.rs b/src/librustc_hir/arena.rs index 6ba39666607..f439db71531 100644 --- a/src/librustc_hir/arena.rs +++ b/src/librustc_hir/arena.rs @@ -12,41 +12,41 @@ macro_rules! arena_types { ($macro:path, $args:tt, $tcx:lifetime) => ( $macro!($args, [ // HIR types - [few] hir_krate: rustc_hir::Crate<$tcx>, - [] arm: rustc_hir::Arm<$tcx>, - [] asm_operand: rustc_hir::InlineAsmOperand<$tcx>, - [] asm_template: rustc_ast::ast::InlineAsmTemplatePiece, - [] attribute: rustc_ast::ast::Attribute, - [] block: rustc_hir::Block<$tcx>, - [] bare_fn_ty: rustc_hir::BareFnTy<$tcx>, - [few] global_asm: rustc_hir::GlobalAsm, - [] generic_arg: rustc_hir::GenericArg<$tcx>, - [] generic_args: rustc_hir::GenericArgs<$tcx>, - [] generic_bound: rustc_hir::GenericBound<$tcx>, - [] generic_param: rustc_hir::GenericParam<$tcx>, - [] expr: rustc_hir::Expr<$tcx>, - [] field: rustc_hir::Field<$tcx>, - [] field_pat: rustc_hir::FieldPat<$tcx>, - [] fn_decl: rustc_hir::FnDecl<$tcx>, - [] foreign_item: rustc_hir::ForeignItem<$tcx>, - [] impl_item_ref: rustc_hir::ImplItemRef<$tcx>, - [few] inline_asm: rustc_hir::InlineAsm<$tcx>, - [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>, - [] local: rustc_hir::Local<$tcx>, - [few] macro_def: rustc_hir::MacroDef<$tcx>, - [] param: rustc_hir::Param<$tcx>, - [] pat: rustc_hir::Pat<$tcx>, - [] path: rustc_hir::Path<$tcx>, - [] path_segment: rustc_hir::PathSegment<$tcx>, - [] poly_trait_ref: rustc_hir::PolyTraitRef<$tcx>, - [] qpath: rustc_hir::QPath<$tcx>, - [] stmt: rustc_hir::Stmt<$tcx>, - [] struct_field: rustc_hir::StructField<$tcx>, - [] trait_item_ref: rustc_hir::TraitItemRef, - [] ty: rustc_hir::Ty<$tcx>, - [] type_binding: rustc_hir::TypeBinding<$tcx>, - [] variant: rustc_hir::Variant<$tcx>, - [] where_predicate: rustc_hir::WherePredicate<$tcx>, + [few] hir_krate: rustc_hir::Crate<$tcx>, rustc_hir::Crate<'_x>; + [] arm: rustc_hir::Arm<$tcx>, rustc_hir::Arm<'_x>; + [] asm_operand: rustc_hir::InlineAsmOperand<$tcx>, rustc_hir::InlineAsmOperand<'_x>; + [] asm_template: rustc_ast::ast::InlineAsmTemplatePiece, rustc_ast::ast::InlineAsmTemplatePiece; + [] attribute: rustc_ast::ast::Attribute, rustc_ast::ast::Attribute; + [] block: rustc_hir::Block<$tcx>, rustc_hir::Block<'_x>; + [] bare_fn_ty: rustc_hir::BareFnTy<$tcx>, rustc_hir::BareFnTy<'_x>; + [few] global_asm: rustc_hir::GlobalAsm, rustc_hir::GlobalAsm; + [] generic_arg: rustc_hir::GenericArg<$tcx>, rustc_hir::GenericArg<'_x>; + [] generic_args: rustc_hir::GenericArgs<$tcx>, rustc_hir::GenericArgs<'_x>; + [] generic_bound: rustc_hir::GenericBound<$tcx>, rustc_hir::GenericBound<'_x>; + [] generic_param: rustc_hir::GenericParam<$tcx>, rustc_hir::GenericParam<'_x>; + [] expr: rustc_hir::Expr<$tcx>, rustc_hir::Expr<'_x>; + [] field: rustc_hir::Field<$tcx>, rustc_hir::Field<'_x>; + [] field_pat: rustc_hir::FieldPat<$tcx>, rustc_hir::FieldPat<'_x>; + [] fn_decl: rustc_hir::FnDecl<$tcx>, rustc_hir::FnDecl<'_x>; + [] foreign_item: rustc_hir::ForeignItem<$tcx>, rustc_hir::ForeignItem<'_x>; + [] impl_item_ref: rustc_hir::ImplItemRef<$tcx>, rustc_hir::ImplItemRef<'_x>; + [few] inline_asm: rustc_hir::InlineAsm<$tcx>, rustc_hir::InlineAsm<'_x>; + [few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>, rustc_hir::LlvmInlineAsm<'_x>; + [] local: rustc_hir::Local<$tcx>, rustc_hir::Local<'_x>; + [few] macro_def: rustc_hir::MacroDef<$tcx>, rustc_hir::MacroDef<'_x>; + [] param: rustc_hir::Param<$tcx>, rustc_hir::Param<'_x>; + [] pat: rustc_hir::Pat<$tcx>, rustc_hir::Pat<'_x>; + [] path: rustc_hir::Path<$tcx>, rustc_hir::Path<'_x>; + [] path_segment: rustc_hir::PathSegment<$tcx>, rustc_hir::PathSegment<'_x>; + [] poly_trait_ref: rustc_hir::PolyTraitRef<$tcx>, rustc_hir::PolyTraitRef<'_x>; + [] qpath: rustc_hir::QPath<$tcx>, rustc_hir::QPath<'_x>; + [] stmt: rustc_hir::Stmt<$tcx>, rustc_hir::Stmt<'_x>; + [] struct_field: rustc_hir::StructField<$tcx>, rustc_hir::StructField<'_x>; + [] trait_item_ref: rustc_hir::TraitItemRef, rustc_hir::TraitItemRef; + [] ty: rustc_hir::Ty<$tcx>, rustc_hir::Ty<'_x>; + [] type_binding: rustc_hir::TypeBinding<$tcx>, rustc_hir::TypeBinding<'_x>; + [] variant: rustc_hir::Variant<$tcx>, rustc_hir::Variant<'_x>; + [] where_predicate: rustc_hir::WherePredicate<$tcx>, rustc_hir::WherePredicate<'_x>; ], $tcx); ) } diff --git a/src/librustc_hir/def.rs b/src/librustc_hir/def.rs index 88049f85f45..af1860ca6bf 100644 --- a/src/librustc_hir/def.rs +++ b/src/librustc_hir/def.rs @@ -54,15 +54,11 @@ pub enum DefKind { /// Refers to the variant itself, `DefKind::Ctor` refers to its constructor if it exists. Variant, Trait, - /// `type Foo = impl Bar;` - OpaqueTy, /// `type Foo = Bar;` TyAlias, ForeignTy, TraitAlias, AssocTy, - /// `type Foo = impl Bar;` - AssocOpaqueTy, TyParam, // Value namespace @@ -83,6 +79,7 @@ pub enum DefKind { Use, ForeignMod, AnonConst, + OpaqueTy, Field, LifetimeParam, GlobalAsm, @@ -115,7 +112,6 @@ impl DefKind { DefKind::TyAlias => "type alias", DefKind::TraitAlias => "trait alias", DefKind::AssocTy => "associated type", - DefKind::AssocOpaqueTy => "associated opaque type", DefKind::Union => "union", DefKind::Trait => "trait", DefKind::ForeignTy => "foreign type", @@ -143,7 +139,6 @@ impl DefKind { match *self { DefKind::AssocTy | DefKind::AssocConst - | DefKind::AssocOpaqueTy | DefKind::AssocFn | DefKind::Enum | DefKind::OpaqueTy @@ -168,7 +163,6 @@ impl DefKind { | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy - | DefKind::AssocOpaqueTy | DefKind::TyParam => ns == Namespace::TypeNS, DefKind::Fn diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs index 2dd5e27ead2..b63dd653c4d 100644 --- a/src/librustc_hir/definitions.rs +++ b/src/librustc_hir/definitions.rs @@ -519,6 +519,12 @@ impl Definitions { let old_index = self.placeholder_field_indices.insert(node_id, index); assert!(old_index.is_none(), "placeholder field index is reset for a node ID"); } + + pub fn lint_node_id(&mut self, expn_id: ExpnId) -> ast::NodeId { + self.invocation_parents + .get(&expn_id) + .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id]) + } } impl DefPathData { diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 1e305c6d32d..634ab32a285 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -1371,7 +1371,7 @@ pub struct Expr<'hir> { // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -rustc_data_structures::static_assert_size!(Expr<'static>, 64); +rustc_data_structures::static_assert_size!(Expr<'static>, 72); impl Expr<'_> { pub fn precedence(&self) -> ExprPrecedence { @@ -1568,12 +1568,14 @@ pub enum ExprKind<'hir> { /// and the remaining elements are the rest of the arguments. /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`. + /// The final `Span` represents the span of the function and arguments + /// (e.g. `foo::<Bar, Baz>(a, b, c, d)` in `x.foo::<Bar, Baz>(a, b, c, d)` /// /// To resolve the called method to a `DefId`, call [`type_dependent_def_id`] with /// the `hir_id` of the `MethodCall` node itself. /// /// [`type_dependent_def_id`]: ../ty/struct.TypeckTables.html#method.type_dependent_def_id - MethodCall(&'hir PathSegment<'hir>, Span, &'hir [Expr<'hir>]), + MethodCall(&'hir PathSegment<'hir>, Span, &'hir [Expr<'hir>], Span), /// A tuple (e.g., `(a, b, c, d)`). Tup(&'hir [Expr<'hir>]), /// A binary operation (e.g., `a + b`, `a * b`). @@ -1919,14 +1921,12 @@ pub enum ImplItemKind<'hir> { Fn(FnSig<'hir>, BodyId), /// An associated type. TyAlias(&'hir Ty<'hir>), - /// An associated `type = impl Trait`. - OpaqueTy(GenericBounds<'hir>), } impl ImplItemKind<'_> { pub fn namespace(&self) -> Namespace { match self { - ImplItemKind::OpaqueTy(..) | ImplItemKind::TyAlias(..) => Namespace::TypeNS, + ImplItemKind::TyAlias(..) => Namespace::TypeNS, ImplItemKind::Const(..) | ImplItemKind::Fn(..) => Namespace::ValueNS, } } @@ -2016,13 +2016,13 @@ pub struct OpaqueTy<'hir> { /// From whence the opaque type came. #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum OpaqueTyOrigin { - /// `type Foo = impl Trait;` - TypeAlias, /// `-> impl Trait` FnReturn, /// `async fn` AsyncFn, - /// Impl trait in bindings, consts, statics, bounds. + /// `let _: impl Trait = ...` + Binding, + /// Impl trait in type aliases, consts, statics, bounds. Misc, } @@ -2048,12 +2048,12 @@ pub enum TyKind<'hir> { /// /// Type parameters may be stored in each `PathSegment`. Path(QPath<'hir>), - /// A type definition itself. This is currently only used for the `type Foo = impl Trait` - /// item that `impl Trait` in return position desugars to. + /// A opaque type definition itself. This is currently only used for the + /// `opaque type Foo: Trait` item that `impl Trait` in desugars to. /// - /// The generic argument list contains the lifetimes (and in the future possibly parameters) - /// that are actually bound on the `impl Trait`. - Def(ItemId, &'hir [GenericArg<'hir>]), + /// The generic argument list contains the lifetimes (and in the future + /// possibly parameters) that are actually bound on the `impl Trait`. + OpaqueDef(ItemId, &'hir [GenericArg<'hir>]), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TraitObject(&'hir [PolyTraitRef<'hir>], Lifetime), @@ -2614,7 +2614,6 @@ pub enum AssocItemKind { Const, Fn { has_self: bool }, Type, - OpaqueTy, } #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs index 97601a3e1ac..23d642731da 100644 --- a/src/librustc_hir/intravisit.rs +++ b/src/librustc_hir/intravisit.rs @@ -690,7 +690,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { TyKind::Path(ref qpath) => { visitor.visit_qpath(qpath, typ.hir_id, typ.span); } - TyKind::Def(item_id, lifetimes) => { + TyKind::OpaqueDef(item_id, lifetimes) => { visitor.visit_nested_item(item_id); walk_list!(visitor, visit_generic_arg, lifetimes); } @@ -1007,10 +1007,6 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt visitor.visit_id(impl_item.hir_id); visitor.visit_ty(ty); } - ImplItemKind::OpaqueTy(bounds) => { - visitor.visit_id(impl_item.hir_id); - walk_list!(visitor, visit_param_bound, bounds); - } } } @@ -1090,7 +1086,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) visitor.visit_expr(callee_expression); walk_list!(visitor, visit_expr, arguments); } - ExprKind::MethodCall(ref segment, _, arguments) => { + ExprKind::MethodCall(ref segment, _, arguments, _) => { visitor.visit_path_segment(expression.span, segment); walk_list!(visitor, visit_expr, arguments); } diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs index e642915b86a..c16b7c63e31 100644 --- a/src/librustc_hir_pretty/lib.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -227,6 +227,28 @@ pub fn path_to_string(segment: &hir::Path<'_>) -> String { to_string(NO_ANN, |s| s.print_path(segment, false)) } +pub fn fn_to_string( + decl: &hir::FnDecl<'_>, + header: hir::FnHeader, + name: Option<Symbol>, + generics: &hir::Generics<'_>, + vis: &hir::Visibility<'_>, + arg_names: &[Ident], + body_id: Option<hir::BodyId>, +) -> String { + to_string(NO_ANN, |s| s.print_fn(decl, header, name, generics, vis, arg_names, body_id)) +} + +pub fn enum_def_to_string( + enum_definition: &hir::EnumDef<'_>, + generics: &hir::Generics<'_>, + name: Symbol, + span: rustc_span::Span, + visibility: &hir::Visibility<'_>, +) -> String { + to_string(NO_ANN, |s| s.print_enum_def(enum_definition, generics, name, span, visibility)) +} + impl<'a> State<'a> { pub fn cbox(&mut self, u: usize) { self.s.cbox(u); @@ -385,7 +407,7 @@ impl<'a> State<'a> { &f.param_names[..], ); } - hir::TyKind::Def(..) => {} + hir::TyKind::OpaqueDef(..) => self.s.word("/*impl Trait*/"), hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false), hir::TyKind::TraitObject(bounds, ref lifetime) => { let mut first = true; @@ -981,12 +1003,6 @@ impl<'a> State<'a> { hir::ImplItemKind::TyAlias(ref ty) => { self.print_associated_type(ii.ident, &ii.generics, None, Some(ty)); } - hir::ImplItemKind::OpaqueTy(bounds) => { - self.word_space("type"); - self.print_ident(ii.ident); - self.print_bounds("= impl", bounds); - self.s.word(";"); - } } self.ann.post(self, AnnNode::SubItem(ii.hir_id)) } @@ -1286,7 +1302,7 @@ impl<'a> State<'a> { hir::ExprKind::Call(ref func, ref args) => { self.print_expr_call(&func, args); } - hir::ExprKind::MethodCall(ref segment, _, ref args) => { + hir::ExprKind::MethodCall(ref segment, _, ref args, _) => { self.print_expr_method_call(segment, args); } hir::ExprKind::Binary(op, ref lhs, ref rhs) => { @@ -2469,7 +2485,7 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool { contains_exterior_struct_lit(&x) } - hir::ExprKind::MethodCall(.., ref exprs) => { + hir::ExprKind::MethodCall(.., ref exprs, _) => { // `X { y: 1 }.bar(...)` contains_exterior_struct_lit(&exprs[0]) } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 9bf992537df..2ee95174dff 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -336,7 +336,6 @@ impl DirtyCleanVisitor<'tcx> { ImplItemKind::Fn(..) => ("Node::ImplItem", LABELS_FN_IN_IMPL), ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL), ImplItemKind::TyAlias(..) => ("NodeImplType", LABELS_CONST_IN_IMPL), - ImplItemKind::OpaqueTy(..) => ("NodeImplType", LABELS_CONST_IN_IMPL), }, _ => self.tcx.sess.span_fatal( attr.span, diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index ab2393918c3..8af526e3ad3 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -56,7 +56,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>> where T: Debug + TypeFoldable<'tcx>, - Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable, + Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, { let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?; let canonical_result = self.canonicalize_response(&query_response); diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index a59a91e3005..12f7a9c0ca5 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -224,9 +224,7 @@ fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str { fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str { match item.kind { hir::ImplItemKind::Fn(..) => "method body", - hir::ImplItemKind::Const(..) - | hir::ImplItemKind::OpaqueTy(..) - | hir::ImplItemKind::TyAlias(..) => "associated item", + hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(..) => "associated item", } } diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index dfc7177921d..ceaec2ba5db 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -107,7 +107,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind { + if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind { if call_span == self.target_span && Some(self.target) == self.infcx.in_progress_tables.and_then(|tables| { @@ -294,7 +294,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // 3 | let _ = x.sum() as f64; // | ^^^ cannot infer type for `S` span - } else if let Some(ExprKind::MethodCall(_, call_span, _)) = + } else if let Some(ExprKind::MethodCall(_, call_span, _, _)) = local_visitor.found_method_call.map(|e| &e.kind) { // Point at the call instead of the whole expression: @@ -550,7 +550,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let error_code = error_code.into(); let mut err = self.tcx.sess.struct_span_err_with_code( local_visitor.target_span, - &format!("type annotations needed"), + "type annotations needed", error_code, ); diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs index acaf4746992..a56401ebb90 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -84,7 +84,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { rustc_hir::intravisit::walk_ty(&mut v, ty); debug!("try_report_named_anon_conflict: ret ty {:?}", ty); - if sub == &ty::ReStatic && (matches!(ty.kind, TyKind::Def(_, _)) || v.0.len() == 1) + if sub == &ty::ReStatic + && (matches!(ty.kind, TyKind::OpaqueDef(_, _)) || v.0.len() == 1) { debug!("try_report_named_anon_conflict: impl Trait + 'static"); // This is an `impl Trait` or `dyn Trait` return that evaluates de need of diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 5f14f799fc7..45aee2b3965 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -77,8 +77,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } _ => {} } - let mut type_param_span: MultiSpan = - visitor.types.iter().cloned().collect::<Vec<_>>().into(); + let mut type_param_span: MultiSpan = visitor.types.to_vec().into(); for &span in &visitor.types { type_param_span.push_span_label( span, diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 892a62855a0..c4f1fa2cb26 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -14,9 +14,9 @@ use rustc_middle::ty::{self, Const, Ty}; use rustc_span::Span; pub use self::FulfillmentErrorCode::*; +pub use self::ImplSource::*; pub use self::ObligationCauseCode::*; pub use self::SelectionError::*; -pub use self::Vtable::*; pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::project::MismatchedProjectionTypes; @@ -30,10 +30,10 @@ crate use self::util::elaborate_predicates; pub use rustc_middle::traits::*; /// An `Obligation` represents some trait reference (e.g., `int: Eq`) for -/// which the vtable must be found. The process of finding a vtable is +/// which the "impl_source" must be found. The process of finding a "impl_source" is /// called "resolving" the `Obligation`. This process consists of /// either identifying an `impl` (e.g., `impl Eq for int`) that -/// provides the required vtable, or else finding a bound that is in +/// satisfies the obligation, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). #[derive(Clone, PartialEq, Eq, Hash)] pub struct Obligation<'tcx, T> { @@ -65,7 +65,7 @@ pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>; pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>; pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>; -pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; +pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>; pub struct FulfillmentError<'tcx> { pub obligation: PredicateObligation<'tcx>, diff --git a/src/librustc_interface/callbacks.rs b/src/librustc_interface/callbacks.rs index 913c67d045e..7fa1a3eb0f5 100644 --- a/src/librustc_interface/callbacks.rs +++ b/src/librustc_interface/callbacks.rs @@ -18,7 +18,7 @@ use std::fmt; fn span_debug(span: rustc_span::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result { tls::with_opt(|tcx| { if let Some(tcx) = tcx { - write!(f, "{}", tcx.sess.source_map().span_to_string(span)) + rustc_span::debug_with_source_map(span, f, tcx.sess.source_map()) } else { rustc_span::default_span_debug(span, f) } diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index a01170db807..1a9bf4e1e8f 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -291,6 +291,7 @@ fn configure_and_expand_inner<'a>( recursion_limit: sess.recursion_limit(), trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, + span_debug: sess.opts.debugging_opts.span_debug, ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; @@ -306,16 +307,21 @@ fn configure_and_expand_inner<'a>( ecx.check_unused_macros(); }); - let mut missing_fragment_specifiers: Vec<_> = - ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect(); - missing_fragment_specifiers.sort(); + let mut missing_fragment_specifiers: Vec<_> = ecx + .parse_sess + .missing_fragment_specifiers + .borrow() + .iter() + .map(|(span, node_id)| (*span, *node_id)) + .collect(); + missing_fragment_specifiers.sort_unstable_by_key(|(span, _)| *span); let recursion_limit_hit = ecx.reduced_recursion_limit.is_some(); - for span in missing_fragment_specifiers { + for (span, node_id) in missing_fragment_specifiers { let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; let msg = "missing fragment specifier"; - resolver.lint_buffer().buffer_lint(lint, ast::CRATE_NODE_ID, span, msg); + resolver.lint_buffer().buffer_lint(lint, node_id, span, msg); } if cfg!(windows) { env::set_var("PATH", &old_path); diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 18cbea858d4..87647f3b0b0 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -506,6 +506,7 @@ fn test_debugging_options_tracking_hash() { untracked!(save_analysis, true); untracked!(self_profile, SwitchWithOptPath::Enabled(None)); untracked!(self_profile_events, Some(vec![String::new()])); + untracked!(span_debug, true); untracked!(span_free_formats, true); untracked!(strip, Strip::None); untracked!(terminal_width, Some(80)); diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index cf90c6d8386..200e7acf802 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -187,9 +187,9 @@ pub fn strip_shebang(input: &str) -> Option<usize> { // Ok, this is a shebang but if the next non-whitespace token is `[` or maybe // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level), // then it may be valid Rust code, so consider it Rust code. - let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).filter(|tok| + let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment { .. }) - ).next(); + ); if next_non_whitespace_token != Some(TokenKind::OpenBracket) { // No other choice than to consider this a shebang. return Some(2 + first_line_tail.len()); diff --git a/src/librustc_lexer/src/unescape.rs b/src/librustc_lexer/src/unescape.rs index 2a9e1b7cbc3..697d25fdb58 100644 --- a/src/librustc_lexer/src/unescape.rs +++ b/src/librustc_lexer/src/unescape.rs @@ -335,7 +335,7 @@ where fn byte_from_char(c: char) -> u8 { let res = c as u32; - assert!(res <= u8::max_value() as u32, "guaranteed because of Mode::ByteStr"); + assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr"); res as u8 } diff --git a/src/librustc_lint/array_into_iter.rs b/src/librustc_lint/array_into_iter.rs index 3eb587c016a..5b282c42034 100644 --- a/src/librustc_lint/array_into_iter.rs +++ b/src/librustc_lint/array_into_iter.rs @@ -24,7 +24,7 @@ declare_lint_pass!( impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIntoIter { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>) { // We only care about method call expressions. - if let hir::ExprKind::MethodCall(call, span, args) = &expr.kind { + if let hir::ExprKind::MethodCall(call, span, args, _) = &expr.kind { if call.ident.name != sym::into_iter { return; } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e17e8b7b964..efe60ce1b88 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1102,6 +1102,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds { hir::ItemKind::TyAlias(ref ty, ref generics) => (&*ty, generics), _ => return, }; + if let hir::TyKind::OpaqueDef(..) = ty.kind { + // Bounds are respected for `type X = impl Trait` + return; + } let mut suggested_changing_assoc_types = false; // There must not be a where clause if !type_alias_generics.where_clause.predicates.is_empty() { @@ -1899,7 +1903,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue { } } } - } else if let hir::ExprKind::MethodCall(_, _, ref args) = expr.kind { + } else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind { // Find problematic calls to `MaybeUninit::assume_init`. let def_id = cx.tables.type_dependent_def_id(expr.hir_id)?; if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 703c2a7a443..a8ecfdd0f3d 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -6,7 +6,6 @@ use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::{is_range_literal, ExprKind, Node}; use rustc_index::vec::Idx; use rustc_middle::mir::interpret::{sign_extend, truncate}; @@ -108,23 +107,23 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>( // warnings are consistent between 32- and 64-bit platforms. fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) { match int_ty { - ast::IntTy::Isize => (i64::min_value() as i128, i64::max_value() as i128), - ast::IntTy::I8 => (i8::min_value() as i64 as i128, i8::max_value() as i128), - ast::IntTy::I16 => (i16::min_value() as i64 as i128, i16::max_value() as i128), - ast::IntTy::I32 => (i32::min_value() as i64 as i128, i32::max_value() as i128), - ast::IntTy::I64 => (i64::min_value() as i128, i64::max_value() as i128), - ast::IntTy::I128 => (i128::min_value() as i128, i128::max_value()), + ast::IntTy::Isize => (i64::MIN as i128, i64::MAX as i128), + ast::IntTy::I8 => (i8::MIN as i64 as i128, i8::MAX as i128), + ast::IntTy::I16 => (i16::MIN as i64 as i128, i16::MAX as i128), + ast::IntTy::I32 => (i32::MIN as i64 as i128, i32::MAX as i128), + ast::IntTy::I64 => (i64::MIN as i128, i64::MAX as i128), + ast::IntTy::I128 => (i128::MIN as i128, i128::MAX), } } fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) { match uint_ty { - ast::UintTy::Usize => (u64::min_value() as u128, u64::max_value() as u128), - ast::UintTy::U8 => (u8::min_value() as u128, u8::max_value() as u128), - ast::UintTy::U16 => (u16::min_value() as u128, u16::max_value() as u128), - ast::UintTy::U32 => (u32::min_value() as u128, u32::max_value() as u128), - ast::UintTy::U64 => (u64::min_value() as u128, u64::max_value() as u128), - ast::UintTy::U128 => (u128::min_value(), u128::max_value()), + ast::UintTy::Usize => (u64::MIN as u128, u64::MAX as u128), + ast::UintTy::U8 => (u8::MIN as u128, u8::MAX as u128), + ast::UintTy::U16 => (u16::MIN as u128, u16::MAX as u128), + ast::UintTy::U32 => (u32::MIN as u128, u32::MAX as u128), + ast::UintTy::U64 => (u64::MIN as u128, u64::MAX as u128), + ast::UintTy::U128 => (u128::MIN, u128::MAX), } } @@ -511,10 +510,6 @@ enum FfiResult<'tcx> { FfiUnsafe { ty: Ty<'tcx>, reason: &'static str, help: Option<&'static str> }, } -fn is_zst<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, ty: Ty<'tcx>) -> bool { - tcx.layout_of(tcx.param_env(did).and(ty)).map(|layout| layout.is_zst()).unwrap_or(false) -} - fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind { ty::FnPtr(_) => true, @@ -523,7 +518,7 @@ fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { for field in field_def.all_fields() { let field_ty = tcx.normalize_erasing_regions(ParamEnv::reveal_all(), field.ty(tcx, substs)); - if is_zst(tcx, field.did, field_ty) { + if field_ty.is_zst(tcx, field.did) { continue; } @@ -653,32 +648,43 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - // We can't completely trust repr(C) and repr(transparent) markings; - // make sure the fields are actually safe. - let mut all_phantom = true; - for field in &def.non_enum_variant().fields { - let field_ty = cx.normalize_erasing_regions( - ParamEnv::reveal_all(), - field.ty(cx, substs), - ); - // repr(transparent) types are allowed to have arbitrary ZSTs, not just - // PhantomData -- skip checking all ZST fields - if def.repr.transparent() && is_zst(cx, field.did, field_ty) { - continue; + if def.repr.transparent() { + // Can assume that only one field is not a ZST, so only check + // that field's type for FFI-safety. + if let Some(field) = + def.transparent_newtype_field(cx, self.cx.param_env) + { + let field_ty = cx.normalize_erasing_regions( + self.cx.param_env, + field.ty(cx, substs), + ); + self.check_type_for_ffi(cache, field_ty) + } else { + FfiSafe } - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => { - all_phantom = false; - } - FfiPhantom(..) => {} - FfiUnsafe { .. } => { - return r; + } else { + // We can't completely trust repr(C) markings; make sure the fields are + // actually safe. + let mut all_phantom = true; + for field in &def.non_enum_variant().fields { + let field_ty = cx.normalize_erasing_regions( + self.cx.param_env, + field.ty(cx, substs), + ); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => { + all_phantom = false; + } + FfiPhantom(..) => {} + FfiUnsafe { .. } => { + return r; + } } } - } - if all_phantom { FfiPhantom(ty) } else { FfiSafe } + if all_phantom { FfiPhantom(ty) } else { FfiSafe } + } } AdtKind::Union => { if !def.repr.c() && !def.repr.transparent() { @@ -708,7 +714,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ); // repr(transparent) types are allowed to have arbitrary ZSTs, not just // PhantomData -- skip checking all ZST fields. - if def.repr.transparent() && is_zst(cx, field.did, field_ty) { + if def.repr.transparent() && field_ty.is_zst(cx, field.did) { continue; } let r = self.check_type_for_ffi(cache, field_ty); @@ -774,7 +780,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ); // repr(transparent) types are allowed to have arbitrary ZSTs, not // just PhantomData -- skip checking all ZST fields. - if def.repr.transparent() && is_zst(cx, field.did, field_ty) { + if def.repr.transparent() && field_ty.is_zst(cx, field.did) { continue; } let r = self.check_type_for_ffi(cache, field_ty); @@ -946,7 +952,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>, is_static: bool) { + fn check_type_for_ffi_and_report_errors( + &mut self, + sp: Span, + ty: Ty<'tcx>, + is_static: bool, + is_return_type: bool, + ) { // We have to check for opaque types before `normalize_erasing_regions`, // which will replace opaque types with their underlying concrete type. if self.check_for_opaque_ty(sp, ty) { @@ -957,19 +969,29 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // it is only OK to use this function because extern fns cannot have // any generic types right now: let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); - // C doesn't really support passing arrays by value. - // The only way to pass an array by value is through a struct. - // So we first test that the top level isn't an array, - // and then recursively check the types inside. + + // C doesn't really support passing arrays by value - the only way to pass an array by value + // is through a struct. So, first test that the top level isn't an array, and then + // recursively check the types inside. if !is_static && self.check_for_array_ty(sp, ty) { return; } + // Don't report FFI errors for unit return types. This check exists here, and not in + // `check_foreign_fn` (where it would make more sense) so that normalization has definitely + // happened. + if is_return_type && ty.is_unit() { + return; + } + match self.check_type_for_ffi(&mut FxHashSet::default(), ty) { FfiResult::FfiSafe => {} FfiResult::FfiPhantom(ty) => { self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None); } + // If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic + // argument, which after substitution, is `()`, then this branch can be hit. + FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => return, FfiResult::FfiUnsafe { ty, reason, help } => { self.emit_ffi_unsafe_type_lint(ty, sp, reason, help); } @@ -982,21 +1004,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let sig = self.cx.tcx.erase_late_bound_regions(&sig); for (input_ty, input_hir) in sig.inputs().iter().zip(decl.inputs) { - self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false); + self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false, false); } if let hir::FnRetTy::Return(ref ret_hir) = decl.output { let ret_ty = sig.output(); - if !ret_ty.is_unit() { - self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false); - } + self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false, true); } } fn check_foreign_static(&mut self, id: hir::HirId, span: Span) { let def_id = self.cx.tcx.hir().local_def_id(id); let ty = self.cx.tcx.type_of(def_id); - self.check_type_for_ffi_and_report_errors(span, ty, true); + self.check_type_for_ffi_and_report_errors(span, ty, true, false); } } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index dea82934313..8196b37391b 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -526,7 +526,7 @@ trait UnusedDelimLint { let (args_to_check, ctx) = match *call_or_other { Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg), // first "argument" is self (which sometimes needs delims) - MethodCall(_, ref args) => (&args[1..], UnusedDelimsCtx::MethodArg), + MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg), // actual catch-all arm _ => { return; diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index e97fa4345fe..ada48bc147e 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -78,6 +78,7 @@ fn main() { "arm", "aarch64", "amdgpu", + "avr", "mips", "powerpc", "systemz", diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index eca1808de3f..79e1a6cc5dc 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -77,6 +77,14 @@ pub fn initialize_available_targets() { LLVMInitializeAMDGPUAsmParser ); init_target!( + llvm_component = "avr", + LLVMInitializeAVRTargetInfo, + LLVMInitializeAVRTarget, + LLVMInitializeAVRTargetMC, + LLVMInitializeAVRAsmPrinter, + LLVMInitializeAVRAsmParser + ); + init_target!( llvm_component = "mips", LLVMInitializeMipsTargetInfo, LLVMInitializeMipsTarget, diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index 41a49a38a19..c17d5311e8f 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -433,7 +433,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { try_load_from_on_disk_cache_stream.extend(quote! { ::rustc_middle::dep_graph::DepKind::#name => { - if <#arg as DepNodeParams<TyCtxt<'_>>>::CAN_RECONSTRUCT_QUERY_KEY { + if <#arg as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key() { debug_assert!($tcx.dep_graph .node_color($dep_node) .map(|c| c.is_green()) @@ -490,7 +490,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { // Add a match arm to force the query given the dep node dep_node_force_stream.extend(quote! { ::rustc_middle::dep_graph::DepKind::#name => { - if <#arg as DepNodeParams<TyCtxt<'_>>>::CAN_RECONSTRUCT_QUERY_KEY { + if <#arg as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key() { if let Some(key) = <#arg as DepNodeParams<TyCtxt<'_>>>::recover($tcx, $dep_node) { force_query::<crate::ty::query::queries::#name<'_>, _>( $tcx, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 7e902f0ade2..b8ebcd6c8a8 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -934,7 +934,7 @@ impl<'a> CrateLoader<'a> { src: ExternCrateSource::Path, span, // to have the least priority in `update_extern_crate` - path_len: usize::max_value(), + path_len: usize::MAX, dependency_of: LOCAL_CRATE, }, ); diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 2a2169880a5..76e39a476c6 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -7,7 +7,7 @@ #![feature(nll)] #![feature(or_patterns)] #![feature(proc_macro_internals)] -#![feature(specialization)] // FIXME: min_specialization ICEs +#![feature(min_specialization)] #![feature(stmt_expr_attributes)] #![recursion_limit = "256"] diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index f5a9dceb782..5b2f000a93f 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -30,7 +30,7 @@ use rustc_middle::mir::{self, interpret, Body, Promoted}; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::util::common::record_time; -use rustc_serialize::{opaque, Decodable, Decoder, SpecializedDecoder}; +use rustc_serialize::{opaque, Decodable, Decoder, SpecializedDecoder, UseSpecializedDecodable}; use rustc_session::Session; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -218,7 +218,7 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) { } } -impl<'a, 'tcx, T: Decodable> Lazy<T> { +impl<'a, 'tcx, T: Decodable> Lazy<T, ()> { fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T { let mut dcx = metadata.decoder(self.position.get()); dcx.lazy_state = LazyState::NodeStart(self.position); @@ -226,7 +226,7 @@ impl<'a, 'tcx, T: Decodable> Lazy<T> { } } -impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> Lazy<[T]> { +impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> Lazy<[T], usize> { fn decode<M: Metadata<'a, 'tcx>>( self, metadata: M, @@ -321,20 +321,20 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { } } -impl<'a, 'tcx, T> SpecializedDecoder<Lazy<T>> for DecodeContext<'a, 'tcx> { +impl<'a, 'tcx, T> SpecializedDecoder<Lazy<T, ()>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<Lazy<T>, Self::Error> { self.read_lazy_with_meta(()) } } -impl<'a, 'tcx, T> SpecializedDecoder<Lazy<[T]>> for DecodeContext<'a, 'tcx> { +impl<'a, 'tcx, T> SpecializedDecoder<Lazy<[T], usize>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<Lazy<[T]>, Self::Error> { let len = self.read_usize()?; if len == 0 { Ok(Lazy::empty()) } else { self.read_lazy_with_meta(len) } } } -impl<'a, 'tcx, I: Idx, T> SpecializedDecoder<Lazy<Table<I, T>>> for DecodeContext<'a, 'tcx> +impl<'a, 'tcx, I: Idx, T> SpecializedDecoder<Lazy<Table<I, T>, usize>> for DecodeContext<'a, 'tcx> where Option<T>: FixedSizeEncoding, { @@ -515,8 +515,9 @@ impl<'a, 'tcx> SpecializedDecoder<Fingerprint> for DecodeContext<'a, 'tcx> { } } -impl<'a, 'tcx, T: Decodable> SpecializedDecoder<mir::ClearCrossCrate<T>> - for DecodeContext<'a, 'tcx> +impl<'a, 'tcx, T> SpecializedDecoder<mir::ClearCrossCrate<T>> for DecodeContext<'a, 'tcx> +where + mir::ClearCrossCrate<T>: UseSpecializedDecodable, { #[inline] fn specialized_decode(&mut self) -> Result<mir::ClearCrossCrate<T>, Self::Error> { @@ -579,7 +580,6 @@ impl EntryKind { EntryKind::ConstParam => DefKind::ConstParam, EntryKind::OpaqueTy => DefKind::OpaqueTy, EntryKind::AssocType(_) => DefKind::AssocTy, - EntryKind::AssocOpaqueTy(_) => DefKind::AssocOpaqueTy, EntryKind::Mod(_) => DefKind::Mod, EntryKind::Variant(_) => DefKind::Variant, EntryKind::Trait(_) => DefKind::Trait, @@ -1145,7 +1145,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { (ty::AssocKind::Fn, data.container, data.has_self) } EntryKind::AssocType(container) => (ty::AssocKind::Type, container, false), - EntryKind::AssocOpaqueTy(container) => (ty::AssocKind::OpaqueTy, container, false), _ => bug!("cannot get associated-item of `{:?}`", def_key), }; diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index 9964c9c94c9..feefdf299a9 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -27,7 +27,7 @@ use rustc_middle::mir::{self, interpret}; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::{self as ty_codec, TyEncoder}; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; -use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder}; +use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder, UseSpecializedEncodable}; use rustc_session::config::CrateType; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -93,13 +93,13 @@ impl<'tcx> Encoder for EncodeContext<'tcx> { } } -impl<'tcx, T> SpecializedEncoder<Lazy<T>> for EncodeContext<'tcx> { +impl<'tcx, T> SpecializedEncoder<Lazy<T, ()>> for EncodeContext<'tcx> { fn specialized_encode(&mut self, lazy: &Lazy<T>) -> Result<(), Self::Error> { self.emit_lazy_distance(*lazy) } } -impl<'tcx, T> SpecializedEncoder<Lazy<[T]>> for EncodeContext<'tcx> { +impl<'tcx, T> SpecializedEncoder<Lazy<[T], usize>> for EncodeContext<'tcx> { fn specialized_encode(&mut self, lazy: &Lazy<[T]>) -> Result<(), Self::Error> { self.emit_usize(lazy.meta)?; if lazy.meta == 0 { @@ -109,7 +109,7 @@ impl<'tcx, T> SpecializedEncoder<Lazy<[T]>> for EncodeContext<'tcx> { } } -impl<'tcx, I: Idx, T> SpecializedEncoder<Lazy<Table<I, T>>> for EncodeContext<'tcx> +impl<'tcx, I: Idx, T> SpecializedEncoder<Lazy<Table<I, T>, usize>> for EncodeContext<'tcx> where Option<T>: FixedSizeEncoding, { @@ -228,8 +228,13 @@ impl<'tcx> SpecializedEncoder<LocalDefId> for EncodeContext<'tcx> { } } -impl<'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'tcx> { - fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { +impl<'a, 'b, 'tcx> SpecializedEncoder<&'a ty::TyS<'b>> for EncodeContext<'tcx> +where + &'a ty::TyS<'b>: UseSpecializedEncodable, +{ + fn specialized_encode(&mut self, ty: &&'a ty::TyS<'b>) -> Result<(), Self::Error> { + debug_assert!(self.tcx.lift(ty).is_some()); + let ty = unsafe { std::mem::transmute::<&&'a ty::TyS<'b>, &&'tcx ty::TyS<'tcx>>(ty) }; ty_codec::encode_with_shorthand(self, ty, |ecx| &mut ecx.type_shorthands) } } @@ -251,12 +256,19 @@ impl<'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'tcx> { } } -impl<'tcx> SpecializedEncoder<&'tcx [(ty::Predicate<'tcx>, Span)]> for EncodeContext<'tcx> { +impl<'a, 'b, 'tcx> SpecializedEncoder<&'a [(ty::Predicate<'b>, Span)]> for EncodeContext<'tcx> { fn specialized_encode( &mut self, - predicates: &&'tcx [(ty::Predicate<'tcx>, Span)], + predicates: &&'a [(ty::Predicate<'b>, Span)], ) -> Result<(), Self::Error> { - ty_codec::encode_spanned_predicates(self, predicates, |ecx| &mut ecx.predicate_shorthands) + debug_assert!(self.tcx.lift(*predicates).is_some()); + let predicates = unsafe { + std::mem::transmute::< + &&'a [(ty::Predicate<'b>, Span)], + &&'tcx [(ty::Predicate<'tcx>, Span)], + >(predicates) + }; + ty_codec::encode_spanned_predicates(self, &predicates, |ecx| &mut ecx.predicate_shorthands) } } @@ -266,7 +278,10 @@ impl<'tcx> SpecializedEncoder<Fingerprint> for EncodeContext<'tcx> { } } -impl<'tcx, T: Encodable> SpecializedEncoder<mir::ClearCrossCrate<T>> for EncodeContext<'tcx> { +impl<'tcx, T> SpecializedEncoder<mir::ClearCrossCrate<T>> for EncodeContext<'tcx> +where + mir::ClearCrossCrate<T>: UseSpecializedEncodable, +{ fn specialized_encode(&mut self, _: &mir::ClearCrossCrate<T>) -> Result<(), Self::Error> { Ok(()) } @@ -693,16 +708,25 @@ impl EncodeContext<'tcx> { vis: &hir::Visibility<'_>, ) { let tcx = self.tcx; - let def_id = tcx.hir().local_def_id(id).to_def_id(); + let def_id = tcx.hir().local_def_id(id); debug!("EncodeContext::encode_info_for_mod({:?})", def_id); let data = ModData { reexports: match tcx.module_exports(def_id) { - Some(exports) => self.lazy(exports), + Some(exports) => { + let hir_map = self.tcx.hir(); + self.lazy( + exports + .iter() + .map(|export| export.map_id(|id| hir_map.as_local_hir_id(id))), + ) + } _ => Lazy::empty(), }, }; + let def_id = def_id.to_def_id(); + record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data))); record!(self.tables.visibility[def_id] <- ty::Visibility::from_hir(vis, id, self.tcx)); record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); @@ -865,7 +889,6 @@ impl EncodeContext<'tcx> { })) } ty::AssocKind::Type => EntryKind::AssocType(container), - ty::AssocKind::OpaqueTy => span_bug!(ast_item.span, "opaque type in trait"), }); record!(self.tables.visibility[def_id] <- trait_item.vis); record!(self.tables.span[def_id] <- ast_item.span); @@ -883,7 +906,6 @@ impl EncodeContext<'tcx> { self.encode_item_type(def_id); } } - ty::AssocKind::OpaqueTy => unreachable!(), } if trait_item.kind == ty::AssocKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); @@ -948,7 +970,6 @@ impl EncodeContext<'tcx> { has_self: impl_item.fn_has_self_parameter, })) } - ty::AssocKind::OpaqueTy => EntryKind::AssocOpaqueTy(container), ty::AssocKind::Type => EntryKind::AssocType(container) }); record!(self.tables.visibility[def_id] <- impl_item.vis); @@ -980,7 +1001,7 @@ impl EncodeContext<'tcx> { let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; needs_inline || is_const_fn || always_encode_mir } - hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(..) => false, + hir::ImplItemKind::TyAlias(..) => false, }; if mir { self.encode_optimized_mir(def_id.expect_local()); @@ -1777,7 +1798,7 @@ impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> { self.prefetch_mir(def_id) } } - hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(..) => (), + hir::ImplItemKind::TyAlias(..) => (), } } } diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index 89d525eb80b..626a436b400 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -308,7 +308,6 @@ enum EntryKind { Impl(Lazy<ImplData>), AssocFn(Lazy<AssocFnData>), AssocType(AssocContainer), - AssocOpaqueTy(AssocContainer), AssocConst(AssocContainer, mir::ConstQualifs, Lazy<RenderedConst>), TraitAlias, } diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs index 75228350c6c..f861d63aba0 100644 --- a/src/librustc_middle/arena.rs +++ b/src/librustc_middle/arena.rs @@ -11,79 +11,109 @@ macro_rules! arena_types { ($macro:path, $args:tt, $tcx:lifetime) => ( $macro!($args, [ - [] layouts: rustc_target::abi::Layout, + [] layouts: rustc_target::abi::Layout, rustc_target::abi::Layout; // AdtDef are interned and compared by address - [] adt_def: rustc_middle::ty::AdtDef, - [decode] tables: rustc_middle::ty::TypeckTables<$tcx>, - [] const_allocs: rustc_middle::mir::interpret::Allocation, + [] adt_def: rustc_middle::ty::AdtDef, rustc_middle::ty::AdtDef; + [decode] tables: rustc_middle::ty::TypeckTables<$tcx>, rustc_middle::ty::TypeckTables<'_x>; + [] const_allocs: rustc_middle::mir::interpret::Allocation, rustc_middle::mir::interpret::Allocation; // Required for the incremental on-disk cache - [few, decode] mir_keys: rustc_hir::def_id::DefIdSet, - [] region_scope_tree: rustc_middle::middle::region::ScopeTree, + [few, decode] mir_keys: rustc_hir::def_id::DefIdSet, rustc_hir::def_id::DefIdSet; + [] region_scope_tree: rustc_middle::middle::region::ScopeTree, rustc_middle::middle::region::ScopeTree; [] dropck_outlives: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::traits::query::DropckOutlivesResult<'tcx> > >, + rustc_middle::infer::canonical::Canonical<'_x, + rustc_middle::infer::canonical::QueryResponse<'_y, + rustc_middle::traits::query::DropckOutlivesResult<'_z> + > + >; [] normalize_projection_ty: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::traits::query::NormalizationResult<'tcx> > >, + rustc_middle::infer::canonical::Canonical<'_x, + rustc_middle::infer::canonical::QueryResponse<'_y, + rustc_middle::traits::query::NormalizationResult<'_z> + > + >; [] implied_outlives_bounds: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, Vec<rustc_middle::traits::query::OutlivesBound<'tcx>> > >, + rustc_middle::infer::canonical::Canonical<'_x, + rustc_middle::infer::canonical::QueryResponse<'_y, + Vec<rustc_middle::traits::query::OutlivesBound<'_z>> + > + >; [] type_op_subtype: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, ()> >, + rustc_middle::infer::canonical::Canonical<'_x, + rustc_middle::infer::canonical::QueryResponse<'_y, ()> + >; [] type_op_normalize_poly_fn_sig: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::PolyFnSig<'tcx>> >, + rustc_middle::infer::canonical::Canonical<'_x, + rustc_middle::infer::canonical::QueryResponse<'_y, rustc_middle::ty::PolyFnSig<'_z>> + >; [] type_op_normalize_fn_sig: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::FnSig<'tcx>> >, + rustc_middle::infer::canonical::Canonical<'_x, + rustc_middle::infer::canonical::QueryResponse<'_y, rustc_middle::ty::FnSig<'_z>> + >; [] type_op_normalize_predicate: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Predicate<'tcx>> >, + rustc_middle::infer::canonical::Canonical<'_x, + rustc_middle::infer::canonical::QueryResponse<'_y, rustc_middle::ty::Predicate<'_z>> + >; [] type_op_normalize_ty: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>> >, - [few] all_traits: Vec<rustc_hir::def_id::DefId>, - [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels, - [few] foreign_module: rustc_middle::middle::cstore::ForeignModule, - [few] foreign_modules: Vec<rustc_middle::middle::cstore::ForeignModule>, - [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>, - [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, - [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>, - [] attribute: rustc_ast::ast::Attribute, - [] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>, - [] hir_id_set: rustc_hir::HirIdSet, + rustc_middle::infer::canonical::Canonical<'_x, + rustc_middle::infer::canonical::QueryResponse<'_y, &'_z rustc_middle::ty::TyS<'_w>> + >; + [few] all_traits: Vec<rustc_hir::def_id::DefId>, Vec<rustc_hir::def_id::DefId>; + [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels, rustc_middle::middle::privacy::AccessLevels; + [few] foreign_module: rustc_middle::middle::cstore::ForeignModule, rustc_middle::middle::cstore::ForeignModule; + [few] foreign_modules: Vec<rustc_middle::middle::cstore::ForeignModule>, Vec<rustc_middle::middle::cstore::ForeignModule>; + [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>, rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>; + [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, rustc_middle::traits::ObjectSafetyViolation; + [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>, rustc_middle::mir::mono::CodegenUnit<'_x>; + [] attribute: rustc_ast::ast::Attribute, rustc_ast::ast::Attribute; + [] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>, rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>; + [] hir_id_set: rustc_hir::HirIdSet, rustc_hir::HirIdSet; // Interned types - [] tys: rustc_middle::ty::TyS<$tcx>, + [] tys: rustc_middle::ty::TyS<$tcx>, rustc_middle::ty::TyS<'_x>; // HIR query types - [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>, - [few] hir_definitions: rustc_hir::definitions::Definitions, - [] hir_owner: rustc_middle::hir::Owner<$tcx>, - [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>, + [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>, rustc_middle::hir::map::IndexedHir<'_x>; + [few] hir_definitions: rustc_hir::definitions::Definitions, rustc_hir::definitions::Definitions; + [] hir_owner: rustc_middle::hir::Owner<$tcx>, rustc_middle::hir::Owner<'_x>; + [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>, rustc_middle::hir::OwnerNodes<'_x>; // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena // (during lowering) and the `librustc_middle` arena (for decoding MIR) - [decode] asm_template: rustc_ast::ast::InlineAsmTemplatePiece, + [decode] asm_template: rustc_ast::ast::InlineAsmTemplatePiece, rustc_ast::ast::InlineAsmTemplatePiece; // This is used to decode the &'tcx [Span] for InlineAsm's line_spans. - [decode] span: rustc_span::Span, + [decode] span: rustc_span::Span, rustc_span::Span; ], $tcx); ) } diff --git a/src/librustc_middle/dep_graph/dep_node.rs b/src/librustc_middle/dep_graph/dep_node.rs index 2c0524fa991..b14f17dee60 100644 --- a/src/librustc_middle/dep_graph/dep_node.rs +++ b/src/librustc_middle/dep_graph/dep_node.rs @@ -128,7 +128,7 @@ macro_rules! define_dep_nodes { // tuple args $({ return <$tuple_arg_ty as DepNodeParams<TyCtxt<'_>>> - ::CAN_RECONSTRUCT_QUERY_KEY; + ::can_reconstruct_query_key(); })* true @@ -304,7 +304,10 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> ]); impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + #[inline] + fn can_reconstruct_query_key() -> bool { + true + } fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { tcx.def_path_hash(*self).0 @@ -320,7 +323,10 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId { } impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + #[inline] + fn can_reconstruct_query_key() -> bool { + true + } fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { self.to_def_id().to_fingerprint(tcx) @@ -336,7 +342,10 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId { } impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum { - const CAN_RECONSTRUCT_QUERY_KEY: bool = true; + #[inline] + fn can_reconstruct_query_key() -> bool { + true + } fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint { let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX }; @@ -353,7 +362,10 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum { } impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { - const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + #[inline] + fn can_reconstruct_query_key() -> bool { + false + } // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full @@ -375,7 +387,10 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) { } impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId { - const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + #[inline] + fn can_reconstruct_query_key() -> bool { + false + } // We actually would not need to specialize the implementation of this // method but it's faster to combine the hashes than to instantiate a full diff --git a/src/librustc_middle/hir/exports.rs b/src/librustc_middle/hir/exports.rs index 83baf6cc433..af48c9e94ff 100644 --- a/src/librustc_middle/hir/exports.rs +++ b/src/librustc_middle/hir/exports.rs @@ -1,7 +1,8 @@ use crate::ty; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Res; -use rustc_hir::def_id::DefIdMap; +use rustc_hir::def_id::LocalDefId; use rustc_macros::HashStable; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -10,7 +11,7 @@ use std::fmt::Debug; /// This is the replacement export map. It maps a module to all of the exports /// within. -pub type ExportMap<Id> = DefIdMap<Vec<Export<Id>>>; +pub type ExportMap<Id> = FxHashMap<LocalDefId, Vec<Export<Id>>>; #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct Export<Id> { diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs index 53e88787323..d1cfc4867a2 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/src/librustc_middle/hir/map/mod.rs @@ -228,7 +228,6 @@ impl<'hir> Map<'hir> { ImplItemKind::Const(..) => DefKind::AssocConst, ImplItemKind::Fn(..) => DefKind::AssocFn, ImplItemKind::TyAlias(..) => DefKind::AssocTy, - ImplItemKind::OpaqueTy(..) => DefKind::AssocOpaqueTy, }, Node::Variant(_) => DefKind::Variant, Node::Ctor(variant_data) => { @@ -335,6 +334,16 @@ impl<'hir> Map<'hir> { } } + pub fn enclosing_body_owner(&self, hir_id: HirId) -> HirId { + for (parent, _) in self.parent_iter(hir_id) { + if let Some(body) = self.maybe_body_owned_by(parent) { + return self.body_owner(body); + } + } + + bug!("no `enclosing_body_owner` for hir_id `{}`", hir_id); + } + /// Returns the `HirId` that corresponds to the definition of /// which this is the body of, i.e., a `fn`, `const` or `static` /// item (possibly associated), a closure, or a `hir::AnonConst`. @@ -537,18 +546,8 @@ impl<'hir> Map<'hir> { /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context. /// Used exclusively for diagnostics, to avoid suggestion function calls. - pub fn is_const_context(&self, hir_id: HirId) -> bool { - let parent_id = self.get_parent_item(hir_id); - match self.get(parent_id) { - Node::Item(&Item { kind: ItemKind::Const(..) | ItemKind::Static(..), .. }) - | Node::TraitItem(&TraitItem { kind: TraitItemKind::Const(..), .. }) - | Node::ImplItem(&ImplItem { kind: ImplItemKind::Const(..), .. }) - | Node::AnonConst(_) => true, - Node::Item(&Item { kind: ItemKind::Fn(ref sig, ..), .. }) => { - sig.header.constness == Constness::Const - } - _ => false, - } + pub fn is_inside_const_context(&self, hir_id: HirId) -> bool { + self.body_const_context(self.local_def_id(self.enclosing_body_owner(hir_id))).is_some() } /// Whether `hir_id` corresponds to a `mod` or a crate. @@ -672,6 +671,8 @@ impl<'hir> Map<'hir> { if let Node::Item(Item { kind: ItemKind::Fn(..) + | ItemKind::Const(..) + | ItemKind::Static(..) | ItemKind::Mod(..) | ItemKind::Enum(..) | ItemKind::Struct(..) @@ -700,11 +701,7 @@ impl<'hir> Map<'hir> { return CRATE_HIR_ID; } match self.get(scope) { - Node::Item(Item { - kind: ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }), - .. - }) - | Node::Block(_) => {} + Node::Block(_) => {} _ => break, } } @@ -1025,9 +1022,6 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { ImplItemKind::TyAlias(_) => { format!("assoc type {} in {}{}", ii.ident, path_str(), id_str) } - ImplItemKind::OpaqueTy(_) => { - format!("assoc opaque type {} in {}{}", ii.ident, path_str(), id_str) - } }, Some(Node::TraitItem(ti)) => { let kind = match ti.kind { diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs index 7c433574d18..62c92e988ba 100644 --- a/src/librustc_middle/lib.rs +++ b/src/librustc_middle/lib.rs @@ -42,7 +42,7 @@ #![feature(option_expect_none)] #![feature(or_patterns)] #![feature(range_is_empty)] -#![feature(specialization)] // FIXME: min_specialization does not work +#![feature(min_specialization)] #![feature(track_caller)] #![feature(trusted_len)] #![feature(vec_remove_item)] diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 98973f1b6fb..84750a9ead0 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -457,8 +457,39 @@ impl<T> ClearCrossCrate<T> { } } -impl<T: Encodable> rustc_serialize::UseSpecializedEncodable for ClearCrossCrate<T> {} -impl<T: Decodable> rustc_serialize::UseSpecializedDecodable for ClearCrossCrate<T> {} +const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; +const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; + +impl<T: Encodable> rustc_serialize::UseSpecializedEncodable for ClearCrossCrate<T> { + #[inline] + fn default_encode<E: rustc_serialize::Encoder>(&self, e: &mut E) -> Result<(), E::Error> { + match *self { + ClearCrossCrate::Clear => TAG_CLEAR_CROSS_CRATE_CLEAR.encode(e), + ClearCrossCrate::Set(ref val) => { + TAG_CLEAR_CROSS_CRATE_SET.encode(e)?; + val.encode(e) + } + } + } +} +impl<T: Decodable> rustc_serialize::UseSpecializedDecodable for ClearCrossCrate<T> { + #[inline] + fn default_decode<D>(d: &mut D) -> Result<ClearCrossCrate<T>, D::Error> + where + D: rustc_serialize::Decoder, + { + let discr = u8::decode(d)?; + + match discr { + TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(ClearCrossCrate::Clear), + TAG_CLEAR_CROSS_CRATE_SET => { + let val = T::decode(d)?; + Ok(ClearCrossCrate::Set(val)) + } + _ => unreachable!(), + } + } +} /// Grouped information about the source code origin of a MIR entity. /// Intended to be inspected by diagnostics and debuginfo. @@ -1131,6 +1162,9 @@ pub enum TerminatorKind<'tcx> { /// `true` if this is from a call in HIR rather than from an overloaded /// operator. True for overloaded function call. from_hir_call: bool, + /// This `Span` is the span of the function, without the dot and receiver + /// (e.g. `foo(a, b)` in `x.foo(a, b)` + fn_span: Span, }, /// Jump to the target if the condition has the expected value, @@ -1240,7 +1274,7 @@ pub enum InlineAsmOperand<'tcx> { value: Box<Constant<'tcx>>, }, SymStatic { - value: Box<Constant<'tcx>>, + def_id: DefId, }, } @@ -1636,9 +1670,11 @@ impl<'tcx> TerminatorKind<'tcx> { InlineAsmOperand::Const { value } => { write!(fmt, "const {:?}", value)?; } - InlineAsmOperand::SymFn { value } - | InlineAsmOperand::SymStatic { value } => { - write!(fmt, "sym {:?}", value)?; + InlineAsmOperand::SymFn { value } => { + write!(fmt, "sym_fn {:?}", value)?; + } + InlineAsmOperand::SymStatic { def_id } => { + write!(fmt, "sym_static {:?}", def_id)?; } } } @@ -1952,8 +1988,6 @@ impl<V, T> ProjectionElem<V, T> { /// and the index is a local. pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; -impl<'tcx> Copy for PlaceElem<'tcx> {} - // At least on 64 bit systems, `PlaceElem` should not be larger than two pointers. #[cfg(target_arch = "x86_64")] static_assert_size!(PlaceElem<'_>, 16); @@ -2449,7 +2483,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { tcx.def_path_str_with_substs(def_id.to_def_id(), substs), ) } else { - format!("[closure@{:?}]", tcx.hir().span(hir_id)) + let span = tcx.hir().span(hir_id); + format!("[closure@{}]", tcx.sess.source_map().span_to_string(span)) }; let mut struct_fmt = fmt.debug_struct(&name); diff --git a/src/librustc_middle/mir/type_foldable.rs b/src/librustc_middle/mir/type_foldable.rs index 97c6d6bf5f4..3f5d528d9e7 100644 --- a/src/librustc_middle/mir/type_foldable.rs +++ b/src/librustc_middle/mir/type_foldable.rs @@ -42,7 +42,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { resume_arg: resume_arg.fold_with(folder), drop, }, - Call { ref func, ref args, ref destination, cleanup, from_hir_call } => { + Call { ref func, ref args, ref destination, cleanup, from_hir_call, fn_span } => { let dest = destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest)); @@ -52,6 +52,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { destination: dest, cleanup, from_hir_call, + fn_span, } } Assert { ref cond, expected, ref msg, target, cleanup } => { diff --git a/src/librustc_middle/mir/visit.rs b/src/librustc_middle/mir/visit.rs index 9f886cbc9fb..5f9fcdca516 100644 --- a/src/librustc_middle/mir/visit.rs +++ b/src/librustc_middle/mir/visit.rs @@ -492,6 +492,7 @@ macro_rules! make_mir_visitor { destination, cleanup: _, from_hir_call: _, + fn_span: _ } => { self.visit_operand(func, source_location); for arg in args { @@ -563,10 +564,10 @@ macro_rules! make_mir_visitor { ); } } - InlineAsmOperand::SymFn { value } - | InlineAsmOperand::SymStatic { value } => { + InlineAsmOperand::SymFn { value } => { self.visit_constant(value, source_location); } + InlineAsmOperand::SymStatic { def_id: _ } => {} } } } diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 5a3ab205fc2..be15e6c576f 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -735,7 +735,7 @@ rustc_queries! { Codegen { query codegen_fulfill_obligation( key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) - ) -> Result<Vtable<'tcx, ()>, ErrorReported> { + ) -> Result<ImplSource<'tcx, ()>, ErrorReported> { cache_on_disk_if { true } desc { |tcx| "checking if `{}` fulfills its obligations", @@ -789,6 +789,17 @@ rustc_queries! { desc { "computing whether `{}` needs drop", env.value } } + /// Query backing `TyS::is_structural_eq_shallow`. + /// + /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types + /// correctly. + query has_structural_eq_impls(ty: Ty<'tcx>) -> bool { + desc { + "computing whether `{:?}` implements `PartialStructuralEq` and `StructuralEq`", + ty + } + } + /// A list of types where the ADT requires drop if and only if any of /// those types require drop. If the ADT is known to always need drop /// then `Err(AlwaysRequiresDrop)` is returned. @@ -865,8 +876,8 @@ rustc_queries! { } Other { - query module_exports(def_id: DefId) -> Option<&'tcx [Export<hir::HirId>]> { - desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id) } + query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export<LocalDefId>]> { + desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) } eval_always } } diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index 9afab5a4d2f..56787304d4e 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -27,9 +27,9 @@ pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, Selecti pub type ChalkCanonicalGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; +pub use self::ImplSource::*; pub use self::ObligationCauseCode::*; pub use self::SelectionError::*; -pub use self::Vtable::*; pub use self::chalk::{ ChalkEnvironmentAndGoal, ChalkEnvironmentClause, RustDefId as ChalkRustDefId, @@ -343,15 +343,10 @@ pub enum SelectionError<'tcx> { /// - `Err(e)`: error `e` occurred pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>; -/// Given the successful resolution of an obligation, the `Vtable` -/// indicates where the vtable comes from. Note that while we call this -/// a "vtable", it does not necessarily indicate dynamic dispatch at -/// runtime. `Vtable` instances just tell the compiler where to find -/// methods, but in generic code those methods are typically statically -/// dispatched -- only when an object is constructed is a `Vtable` -/// instance reified into an actual vtable. +/// Given the successful resolution of an obligation, the `ImplSource` +/// indicates where the impl comes from. /// -/// For example, the vtable may be tied to a specific impl (case A), +/// For example, the obligation may be satisfied by a specific impl (case A), /// or it may be relative to some bound that is in scope (case B). /// /// ``` @@ -363,136 +358,136 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>; /// param: T, /// mixed: Option<T>) { /// -/// // Case A: Vtable points at a specific impl. Only possible when +/// // Case A: ImplSource points at a specific impl. Only possible when /// // type is concretely known. If the impl itself has bounded -/// // type parameters, Vtable will carry resolutions for those as well: -/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])]) +/// // type parameters, ImplSource will carry resolutions for those as well: +/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])]) /// -/// // Case B: Vtable must be provided by caller. This applies when +/// // Case B: ImplSource must be provided by caller. This applies when /// // type is a type parameter. -/// param.clone(); // VtableParam +/// param.clone(); // ImplSourceParam /// /// // Case C: A mix of cases A and B. -/// mixed.clone(); // Vtable(Impl_1, [VtableParam]) +/// mixed.clone(); // ImplSource(Impl_1, [ImplSourceParam]) /// } /// ``` /// /// ### The type parameter `N` /// -/// See explanation on `VtableImplData`. +/// See explanation on `ImplSourceUserDefinedData`. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub enum Vtable<'tcx, N> { - /// Vtable identifying a particular impl. - VtableImpl(VtableImplData<'tcx, N>), +pub enum ImplSource<'tcx, N> { + /// ImplSource identifying a particular impl. + ImplSourceUserDefined(ImplSourceUserDefinedData<'tcx, N>), - /// Vtable for auto trait implementations. + /// ImplSource for auto trait implementations. /// This carries the information and nested obligations with regards /// to an auto implementation for a trait `Trait`. The nested obligations /// ensure the trait implementation holds for all the constituent types. - VtableAutoImpl(VtableAutoImplData<N>), + ImplSourceAutoImpl(ImplSourceAutoImplData<N>), /// Successful resolution to an obligation provided by the caller /// for some type parameter. The `Vec<N>` represents the /// obligations incurred from normalizing the where-clause (if /// any). - VtableParam(Vec<N>), + ImplSourceParam(Vec<N>), /// Virtual calls through an object. - VtableObject(VtableObjectData<'tcx, N>), + ImplSourceObject(ImplSourceObjectData<'tcx, N>), /// Successful resolution for a builtin trait. - VtableBuiltin(VtableBuiltinData<N>), + ImplSourceBuiltin(ImplSourceBuiltinData<N>), - /// Vtable automatically generated for a closure. The `DefId` is the ID - /// of the closure expression. This is a `VtableImpl` in spirit, but the + /// ImplSource automatically generated for a closure. The `DefId` is the ID + /// of the closure expression. This is a `ImplSourceUserDefined` in spirit, but the /// impl is generated by the compiler and does not appear in the source. - VtableClosure(VtableClosureData<'tcx, N>), + ImplSourceClosure(ImplSourceClosureData<'tcx, N>), /// Same as above, but for a function pointer type with the given signature. - VtableFnPointer(VtableFnPointerData<'tcx, N>), + ImplSourceFnPointer(ImplSourceFnPointerData<'tcx, N>), - /// Vtable for a builtin `DeterminantKind` trait implementation. - VtableDiscriminantKind(VtableDiscriminantKindData), + /// ImplSource for a builtin `DeterminantKind` trait implementation. + ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData), - /// Vtable automatically generated for a generator. - VtableGenerator(VtableGeneratorData<'tcx, N>), + /// ImplSource automatically generated for a generator. + ImplSourceGenerator(ImplSourceGeneratorData<'tcx, N>), - /// Vtable for a trait alias. - VtableTraitAlias(VtableTraitAliasData<'tcx, N>), + /// ImplSource for a trait alias. + ImplSourceTraitAlias(ImplSourceTraitAliasData<'tcx, N>), } -impl<'tcx, N> Vtable<'tcx, N> { +impl<'tcx, N> ImplSource<'tcx, N> { pub fn nested_obligations(self) -> Vec<N> { match self { - VtableImpl(i) => i.nested, - VtableParam(n) => n, - VtableBuiltin(i) => i.nested, - VtableAutoImpl(d) => d.nested, - VtableClosure(c) => c.nested, - VtableGenerator(c) => c.nested, - VtableObject(d) => d.nested, - VtableFnPointer(d) => d.nested, - VtableDiscriminantKind(VtableDiscriminantKindData) => Vec::new(), - VtableTraitAlias(d) => d.nested, + ImplSourceUserDefined(i) => i.nested, + ImplSourceParam(n) => n, + ImplSourceBuiltin(i) => i.nested, + ImplSourceAutoImpl(d) => d.nested, + ImplSourceClosure(c) => c.nested, + ImplSourceGenerator(c) => c.nested, + ImplSourceObject(d) => d.nested, + ImplSourceFnPointer(d) => d.nested, + ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(), + ImplSourceTraitAlias(d) => d.nested, } } pub fn borrow_nested_obligations(&self) -> &[N] { match &self { - VtableImpl(i) => &i.nested[..], - VtableParam(n) => &n[..], - VtableBuiltin(i) => &i.nested[..], - VtableAutoImpl(d) => &d.nested[..], - VtableClosure(c) => &c.nested[..], - VtableGenerator(c) => &c.nested[..], - VtableObject(d) => &d.nested[..], - VtableFnPointer(d) => &d.nested[..], - VtableDiscriminantKind(VtableDiscriminantKindData) => &[], - VtableTraitAlias(d) => &d.nested[..], + ImplSourceUserDefined(i) => &i.nested[..], + ImplSourceParam(n) => &n[..], + ImplSourceBuiltin(i) => &i.nested[..], + ImplSourceAutoImpl(d) => &d.nested[..], + ImplSourceClosure(c) => &c.nested[..], + ImplSourceGenerator(c) => &c.nested[..], + ImplSourceObject(d) => &d.nested[..], + ImplSourceFnPointer(d) => &d.nested[..], + ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => &[], + ImplSourceTraitAlias(d) => &d.nested[..], } } - pub fn map<M, F>(self, f: F) -> Vtable<'tcx, M> + pub fn map<M, F>(self, f: F) -> ImplSource<'tcx, M> where F: FnMut(N) -> M, { match self { - VtableImpl(i) => VtableImpl(VtableImplData { + ImplSourceUserDefined(i) => ImplSourceUserDefined(ImplSourceUserDefinedData { impl_def_id: i.impl_def_id, substs: i.substs, nested: i.nested.into_iter().map(f).collect(), }), - VtableParam(n) => VtableParam(n.into_iter().map(f).collect()), - VtableBuiltin(i) => { - VtableBuiltin(VtableBuiltinData { nested: i.nested.into_iter().map(f).collect() }) - } - VtableObject(o) => VtableObject(VtableObjectData { + ImplSourceParam(n) => ImplSourceParam(n.into_iter().map(f).collect()), + ImplSourceBuiltin(i) => ImplSourceBuiltin(ImplSourceBuiltinData { + nested: i.nested.into_iter().map(f).collect(), + }), + ImplSourceObject(o) => ImplSourceObject(ImplSourceObjectData { upcast_trait_ref: o.upcast_trait_ref, vtable_base: o.vtable_base, nested: o.nested.into_iter().map(f).collect(), }), - VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData { + ImplSourceAutoImpl(d) => ImplSourceAutoImpl(ImplSourceAutoImplData { trait_def_id: d.trait_def_id, nested: d.nested.into_iter().map(f).collect(), }), - VtableClosure(c) => VtableClosure(VtableClosureData { + ImplSourceClosure(c) => ImplSourceClosure(ImplSourceClosureData { closure_def_id: c.closure_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), - VtableGenerator(c) => VtableGenerator(VtableGeneratorData { + ImplSourceGenerator(c) => ImplSourceGenerator(ImplSourceGeneratorData { generator_def_id: c.generator_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), - VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData { + ImplSourceFnPointer(p) => ImplSourceFnPointer(ImplSourceFnPointerData { fn_ty: p.fn_ty, nested: p.nested.into_iter().map(f).collect(), }), - VtableDiscriminantKind(VtableDiscriminantKindData) => { - VtableDiscriminantKind(VtableDiscriminantKindData) + ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => { + ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) } - VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData { + ImplSourceTraitAlias(d) => ImplSourceTraitAlias(ImplSourceTraitAliasData { alias_def_id: d.alias_def_id, substs: d.substs, nested: d.nested.into_iter().map(f).collect(), @@ -512,14 +507,14 @@ impl<'tcx, N> Vtable<'tcx, N> { /// is `()`, because codegen only requires a shallow resolution of an /// impl, and nested obligations are satisfied later. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableImplData<'tcx, N> { +pub struct ImplSourceUserDefinedData<'tcx, N> { pub impl_def_id: DefId, pub substs: SubstsRef<'tcx>, pub nested: Vec<N>, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableGeneratorData<'tcx, N> { +pub struct ImplSourceGeneratorData<'tcx, N> { pub generator_def_id: DefId, pub substs: SubstsRef<'tcx>, /// Nested obligations. This can be non-empty if the generator @@ -528,7 +523,7 @@ pub struct VtableGeneratorData<'tcx, N> { } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableClosureData<'tcx, N> { +pub struct ImplSourceClosureData<'tcx, N> { pub closure_def_id: DefId, pub substs: SubstsRef<'tcx>, /// Nested obligations. This can be non-empty if the closure @@ -537,20 +532,18 @@ pub struct VtableClosureData<'tcx, N> { } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableAutoImplData<N> { +pub struct ImplSourceAutoImplData<N> { pub trait_def_id: DefId, pub nested: Vec<N>, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableBuiltinData<N> { +pub struct ImplSourceBuiltinData<N> { pub nested: Vec<N>, } -/// A vtable for some object-safe trait `Foo` automatically derived -/// for the object type `Foo`. #[derive(PartialEq, Eq, Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableObjectData<'tcx, N> { +pub struct ImplSourceObjectData<'tcx, N> { /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, @@ -563,17 +556,17 @@ pub struct VtableObjectData<'tcx, N> { } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableFnPointerData<'tcx, N> { +pub struct ImplSourceFnPointerData<'tcx, N> { pub fn_ty: Ty<'tcx>, pub nested: Vec<N>, } // FIXME(@lcnr): This should be refactored and merged with other builtin vtables. #[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableDiscriminantKindData; +pub struct ImplSourceDiscriminantKindData; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableTraitAliasData<'tcx, N> { +pub struct ImplSourceTraitAliasData<'tcx, N> { pub alias_def_id: DefId, pub substs: SubstsRef<'tcx>, pub nested: Vec<N>, diff --git a/src/librustc_middle/traits/specialization_graph.rs b/src/librustc_middle/traits/specialization_graph.rs index 4f02aaa96ac..f4961617b81 100644 --- a/src/librustc_middle/traits/specialization_graph.rs +++ b/src/librustc_middle/traits/specialization_graph.rs @@ -100,24 +100,11 @@ impl<'tcx> Node { trait_item_kind: ty::AssocKind, trait_def_id: DefId, ) -> Option<ty::AssocItem> { - use crate::ty::AssocKind::*; - tcx.associated_items(self.def_id()) .filter_by_name_unhygienic(trait_item_name.name) .find(move |impl_item| { - match (trait_item_kind, impl_item.kind) { - | (Const, Const) - | (Fn, Fn) - | (Type, Type) - | (Type, OpaqueTy) // assoc. types can be made opaque in impls - => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id), - - | (Const, _) - | (Fn, _) - | (Type, _) - | (OpaqueTy, _) - => false, - } + trait_item_kind == impl_item.kind + && tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id) }) .copied() } diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs index 74f74415294..218bb144469 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/src/librustc_middle/traits/structural_impls.rs @@ -6,99 +6,99 @@ use std::rc::Rc; // Structural impls for the structs in `traits`. -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - super::VtableImpl(ref v) => write!(f, "{:?}", v), + super::ImplSourceUserDefined(ref v) => write!(f, "{:?}", v), - super::VtableAutoImpl(ref t) => write!(f, "{:?}", t), + super::ImplSourceAutoImpl(ref t) => write!(f, "{:?}", t), - super::VtableClosure(ref d) => write!(f, "{:?}", d), + super::ImplSourceClosure(ref d) => write!(f, "{:?}", d), - super::VtableGenerator(ref d) => write!(f, "{:?}", d), + super::ImplSourceGenerator(ref d) => write!(f, "{:?}", d), - super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d), + super::ImplSourceFnPointer(ref d) => write!(f, "ImplSourceFnPointer({:?})", d), - super::VtableDiscriminantKind(ref d) => write!(f, "{:?}", d), + super::ImplSourceDiscriminantKind(ref d) => write!(f, "{:?}", d), - super::VtableObject(ref d) => write!(f, "{:?}", d), + super::ImplSourceObject(ref d) => write!(f, "{:?}", d), - super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n), + super::ImplSourceParam(ref n) => write!(f, "ImplSourceParam({:?})", n), - super::VtableBuiltin(ref d) => write!(f, "{:?}", d), + super::ImplSourceBuiltin(ref d) => write!(f, "{:?}", d), - super::VtableTraitAlias(ref d) => write!(f, "{:?}", d), + super::ImplSourceTraitAlias(ref d) => write!(f, "{:?}", d), } } } -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceUserDefinedData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})", + "ImplSourceUserDefinedData(impl_def_id={:?}, substs={:?}, nested={:?})", self.impl_def_id, self.substs, self.nested ) } } -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceGeneratorData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})", + "ImplSourceGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})", self.generator_def_id, self.substs, self.nested ) } } -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceClosureData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})", + "ImplSourceClosureData(closure_def_id={:?}, substs={:?}, nested={:?})", self.closure_def_id, self.substs, self.nested ) } } -impl<N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> { +impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceBuiltinData<N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "VtableBuiltinData(nested={:?})", self.nested) + write!(f, "ImplSourceBuiltinData(nested={:?})", self.nested) } } -impl<N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData<N> { +impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceAutoImplData<N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableAutoImplData(trait_def_id={:?}, nested={:?})", + "ImplSourceAutoImplData(trait_def_id={:?}, nested={:?})", self.trait_def_id, self.nested ) } } -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})", + "ImplSourceObjectData(upcast={:?}, vtable_base={}, nested={:?})", self.upcast_trait_ref, self.vtable_base, self.nested ) } } -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceFnPointerData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested) + write!(f, "ImplSourceFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested) } } -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", + "ImplSourceTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", self.alias_def_id, self.substs, self.nested ) } @@ -241,63 +241,71 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> { } // For codegen only. -impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { - type Lifted = traits::Vtable<'tcx, ()>; +impl<'a, 'tcx> Lift<'tcx> for traits::ImplSource<'a, ()> { + type Lifted = traits::ImplSource<'tcx, ()>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { match self.clone() { - traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) + traits::ImplSourceUserDefined(traits::ImplSourceUserDefinedData { + impl_def_id, + substs, + nested, + }) => tcx.lift(&substs).map(|substs| { + traits::ImplSourceUserDefined(traits::ImplSourceUserDefinedData { + impl_def_id, + substs, + nested, }) - } - traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)), - traits::VtableGenerator(traits::VtableGeneratorData { + }), + traits::ImplSourceAutoImpl(t) => Some(traits::ImplSourceAutoImpl(t)), + traits::ImplSourceGenerator(traits::ImplSourceGeneratorData { generator_def_id, substs, nested, }) => tcx.lift(&substs).map(|substs| { - traits::VtableGenerator(traits::VtableGeneratorData { + traits::ImplSourceGenerator(traits::ImplSourceGeneratorData { generator_def_id, substs, nested, }) }), - traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableClosure(traits::VtableClosureData { - closure_def_id, - substs, - nested, - }) + traits::ImplSourceClosure(traits::ImplSourceClosureData { + closure_def_id, + substs, + nested, + }) => tcx.lift(&substs).map(|substs| { + traits::ImplSourceClosure(traits::ImplSourceClosureData { + closure_def_id, + substs, + nested, }) - } - traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => { + }), + traits::ImplSourceFnPointer(traits::ImplSourceFnPointerData { fn_ty, nested }) => { tcx.lift(&fn_ty).map(|fn_ty| { - traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) + traits::ImplSourceFnPointer(traits::ImplSourceFnPointerData { fn_ty, nested }) }) } - traits::VtableDiscriminantKind(traits::VtableDiscriminantKindData) => { - Some(traits::VtableDiscriminantKind(traits::VtableDiscriminantKindData)) + traits::ImplSourceDiscriminantKind(traits::ImplSourceDiscriminantKindData) => { + Some(traits::ImplSourceDiscriminantKind(traits::ImplSourceDiscriminantKindData)) } - traits::VtableParam(n) => Some(traits::VtableParam(n)), - traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)), - traits::VtableObject(traits::VtableObjectData { + traits::ImplSourceParam(n) => Some(traits::ImplSourceParam(n)), + traits::ImplSourceBuiltin(n) => Some(traits::ImplSourceBuiltin(n)), + traits::ImplSourceObject(traits::ImplSourceObjectData { upcast_trait_ref, vtable_base, nested, }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| { - traits::VtableObject(traits::VtableObjectData { + traits::ImplSourceObject(traits::ImplSourceObjectData { upcast_trait_ref: trait_ref, vtable_base, nested, }) }), - traits::VtableTraitAlias(traits::VtableTraitAliasData { + traits::ImplSourceTraitAlias(traits::ImplSourceTraitAliasData { alias_def_id, substs, nested, }) => tcx.lift(&substs).map(|substs| { - traits::VtableTraitAlias(traits::VtableTraitAliasData { + traits::ImplSourceTraitAlias(traits::ImplSourceTraitAliasData { alias_def_id, substs, nested, diff --git a/src/librustc_middle/ty/codec.rs b/src/librustc_middle/ty/codec.rs index 8bc69a9d123..1a8e5c45dd2 100644 --- a/src/librustc_middle/ty/codec.rs +++ b/src/librustc_middle/ty/codec.rs @@ -97,7 +97,7 @@ where pub fn encode_spanned_predicates<'tcx, E, C>( encoder: &mut E, - predicates: &'tcx [(ty::Predicate<'tcx>, Span)], + predicates: &[(ty::Predicate<'tcx>, Span)], cache: C, ) -> Result<(), E::Error> where @@ -139,7 +139,7 @@ pub trait TyDecoder<'tcx>: Decoder { } #[inline] -pub fn decode_arena_allocable<D, T: ArenaAllocatable + Decodable>( +pub fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable>( decoder: &mut D, ) -> Result<&'tcx T, D::Error> where @@ -149,7 +149,7 @@ where } #[inline] -pub fn decode_arena_allocable_slice<D, T: ArenaAllocatable + Decodable>( +pub fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable>( decoder: &mut D, ) -> Result<&'tcx [T], D::Error> where @@ -318,18 +318,38 @@ macro_rules! __impl_decoder_methods { macro_rules! impl_arena_allocatable_decoder { ([]$args:tt) => {}; ([decode $(, $attrs:ident)*] - [[$DecoderName:ident [$($typaram:tt),*]], [$name:ident: $ty:ty], $tcx:lifetime]) => { - impl<$($typaram),*> SpecializedDecoder<&$tcx $ty> for $DecoderName<$($typaram),*> { + [[$DecoderName:ident [$($typaram:tt),*]], [$name:ident: $ty:ty, $gen_ty:ty], $tcx:lifetime]) => { + // FIXME(#36588): These impls are horribly unsound as they allow + // the caller to pick any lifetime for `'tcx`, including `'static`. + #[allow(unused_lifetimes)] + impl<'_x, '_y, '_z, '_w, '_a, $($typaram),*> SpecializedDecoder<&'_a $gen_ty> + for $DecoderName<$($typaram),*> + where &'_a $gen_ty: UseSpecializedDecodable + { #[inline] - fn specialized_decode(&mut self) -> Result<&$tcx $ty, Self::Error> { - decode_arena_allocable(self) + fn specialized_decode(&mut self) -> Result<&'_a $gen_ty, Self::Error> { + unsafe { + std::mem::transmute::< + Result<&$tcx $ty, Self::Error>, + Result<&'_a $gen_ty, Self::Error>, + >(decode_arena_allocable(self)) + } } } - impl<$($typaram),*> SpecializedDecoder<&$tcx [$ty]> for $DecoderName<$($typaram),*> { + #[allow(unused_lifetimes)] + impl<'_x, '_y, '_z, '_w, '_a, $($typaram),*> SpecializedDecoder<&'_a [$gen_ty]> + for $DecoderName<$($typaram),*> + where &'_a [$gen_ty]: UseSpecializedDecodable + { #[inline] - fn specialized_decode(&mut self) -> Result<&$tcx [$ty], Self::Error> { - decode_arena_allocable_slice(self) + fn specialized_decode(&mut self) -> Result<&'_a [$gen_ty], Self::Error> { + unsafe { + std::mem::transmute::< + Result<&$tcx [$ty], Self::Error>, + Result<&'_a [$gen_ty], Self::Error>, + >(decode_arena_allocable_slice(self)) + } } } }; @@ -340,9 +360,9 @@ macro_rules! impl_arena_allocatable_decoder { #[macro_export] macro_rules! impl_arena_allocatable_decoders { - ($args:tt, [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { + ($args:tt, [$($a:tt $name:ident: $ty:ty, $gen_ty:ty;)*], $tcx:lifetime) => { $( - impl_arena_allocatable_decoder!($a [$args, [$name: $ty], $tcx]); + impl_arena_allocatable_decoder!($a [$args, [$name: $ty, $gen_ty], $tcx]); )* } } @@ -352,14 +372,15 @@ macro_rules! implement_ty_decoder { ($DecoderName:ident <$($typaram:tt),*>) => { mod __ty_decoder_impl { use std::borrow::Cow; + use std::mem::transmute; - use rustc_serialize::{Decoder, SpecializedDecoder}; + use rustc_serialize::{Decoder, SpecializedDecoder, UseSpecializedDecodable}; use $crate::infer::canonical::CanonicalVarInfos; use $crate::ty; use $crate::ty::codec::*; - use $crate::ty::subst::SubstsRef; - use rustc_hir::def_id::{CrateNum}; + use $crate::ty::subst::InternalSubsts; + use rustc_hir::def_id::CrateNum; use rustc_span::Span; @@ -398,8 +419,7 @@ macro_rules! implement_ty_decoder { } // FIXME(#36588): These impls are horribly unsound as they allow - // the caller to pick any lifetime for `'tcx`, including `'static`, - // by using the unspecialized proxies to them. + // the caller to pick any lifetime for `'tcx`, including `'static`. rustc_hir::arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx); arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx); @@ -411,90 +431,98 @@ macro_rules! implement_ty_decoder { } } - impl<$($typaram),*> SpecializedDecoder<ty::Ty<'tcx>> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<ty::Ty<'tcx>, Self::Error> { - decode_ty(self) + impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x ty::TyS<'_y>> + for $DecoderName<$($typaram),*> + where &'_x ty::TyS<'_y>: UseSpecializedDecodable + { + fn specialized_decode(&mut self) -> Result<&'_x ty::TyS<'_y>, Self::Error> { + unsafe { transmute::<Result<ty::Ty<'tcx>, Self::Error>, Result<&'_x ty::TyS<'_y>, Self::Error>>(decode_ty(self)) } } } - impl<$($typaram),*> SpecializedDecoder<&'tcx [(ty::Predicate<'tcx>, Span)]> - for $DecoderName<$($typaram),*> { + impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x [(ty::Predicate<'_y>, Span)]> + for $DecoderName<$($typaram),*> + where &'_x [(ty::Predicate<'_y>, Span)]: UseSpecializedDecodable { fn specialized_decode(&mut self) - -> Result<&'tcx [(ty::Predicate<'tcx>, Span)], Self::Error> { - decode_spanned_predicates(self) + -> Result<&'_x [(ty::Predicate<'_y>, Span)], Self::Error> + { + unsafe { transmute(decode_spanned_predicates(self)) } } } - impl<$($typaram),*> SpecializedDecoder<SubstsRef<'tcx>> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<SubstsRef<'tcx>, Self::Error> { - decode_substs(self) + impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x InternalSubsts<'_y>> + for $DecoderName<$($typaram),*> + where &'_x InternalSubsts<'_y>: UseSpecializedDecodable { + fn specialized_decode(&mut self) -> Result<&'_x InternalSubsts<'_y>, Self::Error> { + unsafe { transmute(decode_substs(self)) } } } - impl<$($typaram),*> SpecializedDecoder<$crate::mir::Place<'tcx>> + impl<'_x, $($typaram),*> SpecializedDecoder<$crate::mir::Place<'_x>> for $DecoderName<$($typaram),*> { fn specialized_decode( &mut self - ) -> Result<$crate::mir::Place<'tcx>, Self::Error> { - decode_place(self) + ) -> Result<$crate::mir::Place<'_x>, Self::Error> { + unsafe { transmute(decode_place(self)) } } } - impl<$($typaram),*> SpecializedDecoder<ty::Region<'tcx>> + impl<'_x, $($typaram),*> SpecializedDecoder<ty::Region<'_x>> for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<ty::Region<'tcx>, Self::Error> { - decode_region(self) + fn specialized_decode(&mut self) -> Result<ty::Region<'_x>, Self::Error> { + unsafe { transmute(decode_region(self)) } } } - impl<$($typaram),*> SpecializedDecoder<&'tcx ty::List<ty::Ty<'tcx>>> - for $DecoderName<$($typaram),*> { + impl<'_x, '_y, '_z, $($typaram),*> SpecializedDecoder<&'_x ty::List<&'_y ty::TyS<'_z>>> + for $DecoderName<$($typaram),*> + where &'_x ty::List<&'_y ty::TyS<'_z>>: UseSpecializedDecodable { fn specialized_decode(&mut self) - -> Result<&'tcx ty::List<ty::Ty<'tcx>>, Self::Error> { - decode_ty_slice(self) + -> Result<&'_x ty::List<&'_y ty::TyS<'_z>>, Self::Error> { + unsafe { transmute(decode_ty_slice(self)) } } } - impl<$($typaram),*> SpecializedDecoder<&'tcx ty::AdtDef> + impl<'_x, $($typaram),*> SpecializedDecoder<&'_x ty::AdtDef> for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<&'tcx ty::AdtDef, Self::Error> { - decode_adt_def(self) + fn specialized_decode(&mut self) -> Result<&'_x ty::AdtDef, Self::Error> { + unsafe { transmute(decode_adt_def(self)) } } } - impl<$($typaram),*> SpecializedDecoder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>> - for $DecoderName<$($typaram),*> { + impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x ty::List<ty::ExistentialPredicate<'_y>>> + for $DecoderName<$($typaram),*> + where &'_x ty::List<ty::ExistentialPredicate<'_y>>: UseSpecializedDecodable { fn specialized_decode(&mut self) - -> Result<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>, Self::Error> { - decode_existential_predicate_slice(self) + -> Result<&'_x ty::List<ty::ExistentialPredicate<'_y>>, Self::Error> { + unsafe { transmute(decode_existential_predicate_slice(self)) } } } - impl<$($typaram),*> SpecializedDecoder<CanonicalVarInfos<'tcx>> + impl<'_x, $($typaram),*> SpecializedDecoder<CanonicalVarInfos<'_x>> for $DecoderName<$($typaram),*> { fn specialized_decode(&mut self) - -> Result<CanonicalVarInfos<'tcx>, Self::Error> { - decode_canonical_var_infos(self) + -> Result<CanonicalVarInfos<'_x>, Self::Error> { + unsafe { transmute(decode_canonical_var_infos(self)) } } } - impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>> - for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { - decode_const(self) + impl<'_x, '_y, $($typaram),*> SpecializedDecoder<&'_x $crate::ty::Const<'_y>> + for $DecoderName<$($typaram),*> + where &'_x $crate::ty::Const<'_y>: UseSpecializedDecodable { + fn specialized_decode(&mut self) -> Result<&'_x ty::Const<'_y>, Self::Error> { + unsafe { transmute(decode_const(self)) } } } - impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation> + impl<'_x, $($typaram),*> SpecializedDecoder<&'_x $crate::mir::interpret::Allocation> for $DecoderName<$($typaram),*> { fn specialized_decode( &mut self - ) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> { - decode_allocation(self) + ) -> Result<&'_x $crate::mir::interpret::Allocation, Self::Error> { + unsafe { transmute(decode_allocation(self)) } } } } - } + }; } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 089a1613e7d..d5be3508d2d 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -2,7 +2,7 @@ use crate::arena::Arena; use crate::dep_graph::{self, DepConstructor, DepGraph}; -use crate::hir::exports::Export; +use crate::hir::exports::ExportMap; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintSource}; @@ -919,7 +919,7 @@ pub struct GlobalCtxt<'tcx> { trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, StableVec<TraitCandidate>>>, /// Export map produced by name resolution. - export_map: FxHashMap<DefId, Vec<Export<hir::HirId>>>, + export_map: ExportMap<LocalDefId>, pub(crate) untracked_crate: &'tcx hir::Crate<'tcx>, pub(crate) definitions: &'tcx Definitions, diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs index 480420dfdcf..be3bf748225 100644 --- a/src/librustc_middle/ty/error.rs +++ b/src/librustc_middle/ty/error.rs @@ -814,7 +814,7 @@ fn foo(&self) -> Self::T { String::new() } // FIXME: account for `#![feature(specialization)]` for item in &items[..] { match item.kind { - hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => { + hir::AssocItemKind::Type => { // FIXME: account for returning some type in a trait fn impl that has // an assoc type as a return type (#72076). if let hir::Defaultness::Default { has_value: true } = item.defaultness @@ -838,7 +838,7 @@ fn foo(&self) -> Self::T { String::new() } })) => { for item in &items[..] { match item.kind { - hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => { + hir::AssocItemKind::Type => { if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { db.span_label(item.span, "expected this associated type"); return true; diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index e93abd3390a..f5bca90c2bd 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -2529,6 +2529,8 @@ where Msp430Interrupt => Conv::Msp430Intr, X86Interrupt => Conv::X86Intr, AmdGpuKernel => Conv::AmdGpuKernel, + AvrInterrupt => Conv::AvrInterrupt, + AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt, // These API constants ought to be more specific... Cdecl => Conv::C, diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 00c00a63b6b..93ef7317199 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -124,7 +124,7 @@ pub struct ResolverOutputs { pub trait_map: FxHashMap<hir::HirId, Vec<hir::TraitCandidate<hir::HirId>>>, pub maybe_unused_trait_imports: FxHashSet<LocalDefId>, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, - pub export_map: ExportMap<hir::HirId>, + pub export_map: ExportMap<LocalDefId>, pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>, /// Extern prelude entries. The value is `true` if the entry was introduced /// via `extern crate` item and not `--extern` option or compiler built-in. @@ -198,14 +198,13 @@ pub struct AssocItem { pub enum AssocKind { Const, Fn, - OpaqueTy, Type, } impl AssocKind { pub fn namespace(&self) -> Namespace { match *self { - ty::AssocKind::OpaqueTy | ty::AssocKind::Type => Namespace::TypeNS, + ty::AssocKind::Type => Namespace::TypeNS, ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS, } } @@ -215,22 +214,11 @@ impl AssocKind { AssocKind::Const => DefKind::AssocConst, AssocKind::Fn => DefKind::AssocFn, AssocKind::Type => DefKind::AssocTy, - AssocKind::OpaqueTy => DefKind::AssocOpaqueTy, } } } impl AssocItem { - /// Tests whether the associated item admits a non-trivial implementation - /// for ! - pub fn relevant_for_never(&self) -> bool { - match self.kind { - AssocKind::OpaqueTy | AssocKind::Const | AssocKind::Type => true, - // FIXME(canndrew): Be more thorough here, check if any argument is uninhabited. - AssocKind::Fn => !self.fn_has_self_parameter, - } - } - pub fn signature(&self, tcx: TyCtxt<'_>) -> String { match self.kind { ty::AssocKind::Fn => { @@ -241,8 +229,6 @@ impl AssocItem { tcx.fn_sig(self.def_id).skip_binder().to_string() } ty::AssocKind::Type => format!("type {};", self.ident), - // FIXME(type_alias_impl_trait): we should print bounds here too. - ty::AssocKind::OpaqueTy => format!("type {};", self.ident), ty::AssocKind::Const => { format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id)) } @@ -2390,6 +2376,29 @@ impl<'tcx> AdtDef { pub fn sized_constraint(&self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] { tcx.adt_sized_constraint(self.did).0 } + + /// `repr(transparent)` structs can have a single non-ZST field, this function returns that + /// field. + pub fn transparent_newtype_field( + &self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Option<&FieldDef> { + assert!(self.is_struct() && self.repr.transparent()); + + for field in &self.non_enum_variant().fields { + let field_ty = tcx.normalize_erasing_regions( + param_env, + field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.did)), + ); + + if !field_ty.is_zst(tcx, self.did) { + return Some(field); + } + } + + None + } } impl<'tcx> FieldDef { @@ -2558,10 +2567,6 @@ impl<'tcx> TyCtxt<'tcx> { .filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value()) } - pub fn trait_relevant_for_never(self, did: DefId) -> bool { - self.associated_items(did).in_definition_order().any(|item| item.relevant_for_never()) - } - pub fn opt_item_name(self, def_id: DefId) -> Option<Ident> { def_id .as_local() diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 90fb1981617..d782dd07a65 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -605,7 +605,8 @@ pub trait PrettyPrinter<'tcx>: // FIXME(eddyb) should use `def_span`. if let Some(did) = did.as_local() { let hir_id = self.tcx().hir().as_local_hir_id(did); - p!(write("@{:?}", self.tcx().hir().span(hir_id))); + let span = self.tcx().hir().span(hir_id); + p!(write("@{}", self.tcx().sess.source_map().span_to_string(span))); if substs.as_generator().is_valid() { let upvar_tys = substs.as_generator().upvar_tys(); @@ -653,7 +654,8 @@ pub trait PrettyPrinter<'tcx>: if self.tcx().sess.opts.debugging_opts.span_free_formats { p!(write("@"), print_def_path(did.to_def_id(), substs)); } else { - p!(write("@{:?}", self.tcx().hir().span(hir_id))); + let span = self.tcx().hir().span(hir_id); + p!(write("@{}", self.tcx().sess.source_map().span_to_string(span))); } if substs.as_closure().is_valid() { @@ -984,7 +986,7 @@ pub trait PrettyPrinter<'tcx>: let ui_str = ui.name_str(); if data == max { - p!(write("std::{}::MAX", ui_str)) + p!(write("{}::MAX", ui_str)) } else { if print_ty { p!(write("{}{}", data, ui_str)) } else { p!(write("{}", data)) } }; @@ -997,8 +999,8 @@ pub trait PrettyPrinter<'tcx>: let i_str = i.name_str(); match data { - d if d == min => p!(write("std::{}::MIN", i_str)), - d if d == max => p!(write("std::{}::MAX", i_str)), + d if d == min => p!(write("{}::MIN", i_str)), + d if d == max => p!(write("{}::MAX", i_str)), _ => { let data = sign_extend(data, size) as i128; if print_ty { @@ -1362,7 +1364,7 @@ impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { if !self.empty_path { write!(self, "::")?; } - write!(self, "<impl at {:?}>", span)?; + write!(self, "<impl at {}>", self.tcx.sess.source_map().span_to_string(span))?; self.empty_path = false; return Ok(self); diff --git a/src/librustc_middle/ty/query/mod.rs b/src/librustc_middle/ty/query/mod.rs index f61fc65ce39..35d19b7603f 100644 --- a/src/librustc_middle/ty/query/mod.rs +++ b/src/librustc_middle/ty/query/mod.rs @@ -27,7 +27,7 @@ use crate::traits::query::{ OutlivesBound, }; use crate::traits::specialization_graph; -use crate::traits::{self, Vtable}; +use crate::traits::{self, ImplSource}; use crate::ty::steal::Steal; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; diff --git a/src/librustc_middle/ty/query/on_disk_cache.rs b/src/librustc_middle/ty/query/on_disk_cache.rs index 4eae06742d9..5374dff4224 100644 --- a/src/librustc_middle/ty/query/on_disk_cache.rs +++ b/src/librustc_middle/ty/query/on_disk_cache.rs @@ -1,6 +1,6 @@ use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use crate::mir::interpret; use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; -use crate::mir::{self, interpret}; use crate::ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; use crate::ty::context::TyCtxt; use crate::ty::{self, Ty}; @@ -26,9 +26,6 @@ use std::mem; const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; -const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; -const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; - const TAG_NO_EXPN_DATA: u8 = 0; const TAG_EXPN_DATA_SHORTHAND: u8 = 1; const TAG_EXPN_DATA_INLINE: u8 = 2; @@ -667,24 +664,6 @@ impl<'a, 'tcx> SpecializedDecoder<Fingerprint> for CacheDecoder<'a, 'tcx> { } } -impl<'a, 'tcx, T: Decodable> SpecializedDecoder<mir::ClearCrossCrate<T>> - for CacheDecoder<'a, 'tcx> -{ - #[inline] - fn specialized_decode(&mut self) -> Result<mir::ClearCrossCrate<T>, Self::Error> { - let discr = u8::decode(self)?; - - match discr { - TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(mir::ClearCrossCrate::Clear), - TAG_CLEAR_CROSS_CRATE_SET => { - let val = T::decode(self)?; - Ok(mir::ClearCrossCrate::Set(val)) - } - _ => unreachable!(), - } - } -} - //- ENCODING ------------------------------------------------------------------- /// An encoder that can write the incr. comp. cache. @@ -828,17 +807,20 @@ where } } -impl<'a, 'tcx, E> SpecializedEncoder<Ty<'tcx>> for CacheEncoder<'a, 'tcx, E> +impl<'a, 'b, 'c, 'tcx, E> SpecializedEncoder<&'b ty::TyS<'c>> for CacheEncoder<'a, 'tcx, E> where E: 'a + TyEncoder, + &'b ty::TyS<'c>: UseSpecializedEncodable, { #[inline] - fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { + fn specialized_encode(&mut self, ty: &&'b ty::TyS<'c>) -> Result<(), Self::Error> { + debug_assert!(self.tcx.lift(ty).is_some()); + let ty = unsafe { std::mem::transmute::<&&'b ty::TyS<'c>, &&'tcx ty::TyS<'tcx>>(ty) }; ty_codec::encode_with_shorthand(self, ty, |encoder| &mut encoder.type_shorthands) } } -impl<'a, 'tcx, E> SpecializedEncoder<&'tcx [(ty::Predicate<'tcx>, Span)]> +impl<'a, 'b, 'c, 'tcx, E> SpecializedEncoder<&'b [(ty::Predicate<'c>, Span)]> for CacheEncoder<'a, 'tcx, E> where E: 'a + TyEncoder, @@ -846,8 +828,15 @@ where #[inline] fn specialized_encode( &mut self, - predicates: &&'tcx [(ty::Predicate<'tcx>, Span)], + predicates: &&'b [(ty::Predicate<'c>, Span)], ) -> Result<(), Self::Error> { + debug_assert!(self.tcx.lift(*predicates).is_some()); + let predicates = unsafe { + std::mem::transmute::< + &&'b [(ty::Predicate<'c>, Span)], + &&'tcx [(ty::Predicate<'tcx>, Span)], + >(predicates) + }; ty_codec::encode_spanned_predicates(self, predicates, |encoder| { &mut encoder.predicate_shorthands }) @@ -890,23 +879,6 @@ impl<'a, 'tcx> SpecializedEncoder<Fingerprint> for CacheEncoder<'a, 'tcx, opaque } } -impl<'a, 'tcx, E, T> SpecializedEncoder<mir::ClearCrossCrate<T>> for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, - T: Encodable, -{ - #[inline] - fn specialized_encode(&mut self, val: &mir::ClearCrossCrate<T>) -> Result<(), Self::Error> { - match *val { - mir::ClearCrossCrate::Clear => TAG_CLEAR_CROSS_CRATE_CLEAR.encode(self), - mir::ClearCrossCrate::Set(ref val) => { - TAG_CLEAR_CROSS_CRATE_SET.encode(self)?; - val.encode(self) - } - } - } -} - macro_rules! encoder_methods { ($($name:ident($ty:ty);)*) => { #[inline] @@ -995,7 +967,7 @@ fn encode_query_results<'a, 'tcx, Q, E>( query_result_index: &mut EncodedQueryResultIndex, ) -> Result<(), E::Error> where - Q: super::QueryDescription<TyCtxt<'tcx>>, + Q: super::QueryDescription<TyCtxt<'tcx>> + super::QueryAccessors<TyCtxt<'tcx>>, Q::Value: Encodable, E: 'a + TyEncoder, { diff --git a/src/librustc_middle/ty/query/profiling_support.rs b/src/librustc_middle/ty/query/profiling_support.rs index e0d3e764dad..3c446624418 100644 --- a/src/librustc_middle/ty/query/profiling_support.rs +++ b/src/librustc_middle/ty/query/profiling_support.rs @@ -112,30 +112,53 @@ impl<T: Debug> IntoSelfProfilingString for T { } } -impl IntoSelfProfilingString for DefId { +impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T { fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId { + self.spec_to_self_profile_string(builder) + } +} + +#[rustc_specialization_trait] +pub trait SpecIntoSelfProfilingString: Debug { + fn spec_to_self_profile_string( + &self, + builder: &mut QueryKeyStringBuilder<'_, '_, '_>, + ) -> StringId; +} + +impl SpecIntoSelfProfilingString for DefId { + fn spec_to_self_profile_string( + &self, + builder: &mut QueryKeyStringBuilder<'_, '_, '_>, + ) -> StringId { builder.def_id_to_string_id(*self) } } -impl IntoSelfProfilingString for CrateNum { - fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId { +impl SpecIntoSelfProfilingString for CrateNum { + fn spec_to_self_profile_string( + &self, + builder: &mut QueryKeyStringBuilder<'_, '_, '_>, + ) -> StringId { builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX }) } } -impl IntoSelfProfilingString for DefIndex { - fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId { +impl SpecIntoSelfProfilingString for DefIndex { + fn spec_to_self_profile_string( + &self, + builder: &mut QueryKeyStringBuilder<'_, '_, '_>, + ) -> StringId { builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self }) } } -impl<T0, T1> IntoSelfProfilingString for (T0, T1) +impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1) where - T0: IntoSelfProfilingString + Debug, - T1: IntoSelfProfilingString + Debug, + T0: SpecIntoSelfProfilingString, + T1: SpecIntoSelfProfilingString, { - default fn to_self_profile_string( + fn spec_to_self_profile_string( &self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>, ) -> StringId { diff --git a/src/librustc_middle/ty/query/values.rs b/src/librustc_middle/ty/query/values.rs index b01d15c29b2..b1f76ff6a03 100644 --- a/src/librustc_middle/ty/query/values.rs +++ b/src/librustc_middle/ty/query/values.rs @@ -1,4 +1,4 @@ -use crate::ty::{self, AdtSizedConstraint, Ty, TyCtxt}; +use crate::ty::{self, AdtSizedConstraint, Ty, TyCtxt, TyS}; use rustc_span::symbol::Symbol; @@ -13,9 +13,11 @@ impl<'tcx, T> Value<'tcx> for T { } } -impl<'tcx> Value<'tcx> for Ty<'tcx> { - fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.types.err +impl<'tcx> Value<'tcx> for &'_ TyS<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { + // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. + // FIXME: Represent the above fact in the trait system somehow. + unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.types.err) } } } @@ -25,8 +27,14 @@ impl<'tcx> Value<'tcx> for ty::SymbolName { } } -impl<'tcx> Value<'tcx> for AdtSizedConstraint<'tcx> { +impl<'tcx> Value<'tcx> for AdtSizedConstraint<'_> { fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { - AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err])) + // SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`. + // FIXME: Represent the above fact in the trait system somehow. + unsafe { + std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>( + AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err])), + ) + } } } diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs index d507fcbc194..cddd7081ca3 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/src/librustc_middle/ty/relate.rs @@ -250,8 +250,8 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { &b.item_def_id, ))) } else { - let ty = relation.relate(&a.ty, &b.ty)?; - let substs = relation.relate(&a.substs, &b.substs)?; + let ty = relation.relate_with_variance(ty::Invariant, &a.ty, &b.ty)?; + let substs = relation.relate_with_variance(ty::Invariant, &a.substs, &b.substs)?; Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty }) } } @@ -508,16 +508,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>( debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); - let eagerly_eval = |x: &'tcx ty::Const<'tcx>| { - // FIXME(eddyb) this doesn't account for lifetime inference variables - // being erased by `eval`, *nor* for the polymorphic aspect of `eval`. - // That is, we could always use `eval` and it will just return the - // old value back if it doesn't succeed. - if !x.val.needs_infer() { - return x.eval(tcx, relation.param_env()).val; - } - x.val - }; + let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env()).val; // FIXME(eddyb) doesn't look like everything below checks that `a.ty == b.ty`. // We could probably always assert it early, as `const` generic parameters diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 5d4c2a54267..fad96aa86cc 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -2186,6 +2186,11 @@ impl<'tcx> TyS<'tcx> { } } } + + /// Is this a zero-sized type? + pub fn is_zst(&'tcx self, tcx: TyCtxt<'tcx>, did: DefId) -> bool { + tcx.layout_of(tcx.param_env(did).and(self)).map(|layout| layout.is_zst()).unwrap_or(false) + } } /// Typed constant value. @@ -2404,8 +2409,6 @@ impl<'tcx> Const<'tcx> { } } -impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {} - /// Represents a constant in Rust. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)] #[derive(HashStable)] diff --git a/src/librustc_middle/ty/util.rs b/src/librustc_middle/ty/util.rs index c2b794ca4bd..ff284b709c2 100644 --- a/src/librustc_middle/ty/util.rs +++ b/src/librustc_middle/ty/util.rs @@ -705,6 +705,7 @@ impl<'tcx> ty::TyS<'tcx> { /// optimization as well as the rules around static values. Note /// that the `Freeze` trait is not exposed to end users and is /// effectively an implementation detail. + // FIXME: use `TyCtxtAt` instead of separate `Span`. pub fn is_freeze( &'tcx self, tcx: TyCtxt<'tcx>, @@ -778,6 +779,57 @@ impl<'tcx> ty::TyS<'tcx> { } } + /// Returns `true` if equality for this type is both reflexive and structural. + /// + /// Reflexive equality for a type is indicated by an `Eq` impl for that type. + /// + /// Primitive types (`u32`, `str`) have structural equality by definition. For composite data + /// types, equality for the type as a whole is structural when it is the same as equality + /// between all components (fields, array elements, etc.) of that type. For ADTs, structural + /// equality is indicated by an implementation of `PartialStructuralEq` and `StructuralEq` for + /// that type. + /// + /// This function is "shallow" because it may return `true` for a composite type whose fields + /// are not `StructuralEq`. For example, `[T; 4]` has structural equality regardless of `T` + /// because equality for arrays is determined by the equality of each array element. If you + /// want to know whether a given call to `PartialEq::eq` will proceed structurally all the way + /// down, you will need to use a type visitor. + #[inline] + pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool { + match self.kind { + // Look for an impl of both `PartialStructuralEq` and `StructuralEq`. + Adt(..) => tcx.has_structural_eq_impls(self), + + // Primitive types that satisfy `Eq`. + Bool | Char | Int(_) | Uint(_) | Str | Never => true, + + // Composite types that satisfy `Eq` when all of their fields do. + // + // Because this function is "shallow", we return `true` for these composites regardless + // of the type(s) contained within. + Ref(..) | Array(..) | Slice(_) | Tuple(..) => true, + + // Raw pointers use bitwise comparison. + RawPtr(_) | FnPtr(_) => true, + + // Floating point numbers are not `Eq`. + Float(_) => false, + + // Conservatively return `false` for all others... + + // Anonymous function types + FnDef(..) | Closure(..) | Dynamic(..) | Generator(..) => false, + + // Generic or inferred types + // + // FIXME(ecstaticmorse): Maybe we should `bug` here? This should probably only be + // called for known, fully-monomorphized types. + Projection(_) | Opaque(..) | Param(_) | Bound(..) | Placeholder(_) | Infer(_) => false, + + Foreign(_) | GeneratorWitness(..) | Error => false, + } + } + pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { match (&a.kind, &b.kind) { (&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => { @@ -827,7 +879,15 @@ impl<'tcx> ty::TyS<'tcx> { // Find non representable fields with their spans fold_repr(def.all_fields().map(|field| { let ty = field.ty(tcx, substs); - let span = tcx.hir().span_if_local(field.did).unwrap_or(sp); + let span = match field + .did + .as_local() + .map(|id| tcx.hir().as_local_hir_id(id)) + .and_then(|id| tcx.hir().find(id)) + { + Some(hir::Node::Field(field)) => field.ty.span, + _ => sp, + }; match is_type_structurally_recursive( tcx, span, diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs index e04ed8b83de..4d4b6fb9386 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs @@ -495,7 +495,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let closure_id = hir.as_local_hir_id(self.mir_def_id); let fn_call_id = hir.get_parent_node(closure_id); let node = hir.get(fn_call_id); - let item_id = hir.get_parent_item(fn_call_id); + let item_id = hir.enclosing_body_owner(fn_call_id); let mut look_at_return = true; // If we can detect the expression to be an `fn` call where the closure was an argument, // we point at the `fn` definition argument... diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs index 77d16458383..17fa641ae6c 100644 --- a/src/librustc_mir/borrow_check/invalidation.rs +++ b/src/librustc_mir/borrow_check/invalidation.rs @@ -142,6 +142,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { destination, cleanup: _, from_hir_call: _, + fn_span: _, } => { self.consume_operand(location, func); for arg in args { @@ -208,7 +209,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } } InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { value: _ } => {} + | InlineAsmOperand::SymStatic { def_id: _ } => {} } } } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 736cda83ca5..b703237a18e 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -699,6 +699,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc ref destination, cleanup: _, from_hir_call: _, + fn_span: _, } => { self.consume_operand(loc, (func, span), flow_state); for arg in args { @@ -759,7 +760,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc } } InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { value: _ } => {} + | InlineAsmOperand::SymStatic { def_id: _ } => {} } } } diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index 1d373337147..375b3210e8c 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -314,7 +314,7 @@ pub(super) fn dump_mir_results<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, source: MirSource<'tcx>, body: &Body<'tcx>, - regioncx: &RegionInferenceContext<'_>, + regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option<ClosureRegionRequirements<'_>>, ) { if !mir_util::dump_enabled(infcx.tcx, "nll", source.def_id()) { @@ -325,7 +325,7 @@ pub(super) fn dump_mir_results<'a, 'tcx>( match pass_where { // Before the CFG, dump out the values for each region variable. PassWhere::BeforeCFG => { - regioncx.dump_mir(out)?; + regioncx.dump_mir(infcx.tcx, out)?; writeln!(out, "|")?; if let Some(closure_region_requirements) = closure_region_requirements { diff --git a/src/librustc_mir/borrow_check/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/region_infer/dump_mir.rs index 369e5402311..d6e48deb031 100644 --- a/src/librustc_mir/borrow_check/region_infer/dump_mir.rs +++ b/src/librustc_mir/borrow_check/region_infer/dump_mir.rs @@ -4,7 +4,9 @@ //! context internal state. use super::{OutlivesConstraint, RegionInferenceContext}; +use crate::borrow_check::type_check::Locations; use rustc_infer::infer::NLLRegionVariableOrigin; +use rustc_middle::ty::TyCtxt; use std::io::{self, Write}; // Room for "'_#NNNNr" before things get misaligned. @@ -14,7 +16,7 @@ const REGION_WIDTH: usize = 8; impl<'tcx> RegionInferenceContext<'tcx> { /// Write out our state into the `.mir` files. - pub(crate) fn dump_mir(&self, out: &mut dyn Write) -> io::Result<()> { + pub(crate) fn dump_mir(&self, tcx: TyCtxt<'tcx>, out: &mut dyn Write) -> io::Result<()> { writeln!(out, "| Free Region Mapping")?; for region in self.regions() { @@ -48,7 +50,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { writeln!(out, "|")?; writeln!(out, "| Inference Constraints")?; - self.for_each_constraint(&mut |msg| writeln!(out, "| {}", msg))?; + self.for_each_constraint(tcx, &mut |msg| writeln!(out, "| {}", msg))?; Ok(()) } @@ -59,6 +61,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// inference resulted in the values that it did when debugging. fn for_each_constraint( &self, + tcx: TyCtxt<'tcx>, with_msg: &mut dyn FnMut(&str) -> io::Result<()>, ) -> io::Result<()> { for region in self.definitions.indices() { @@ -72,7 +75,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraints.sort(); for constraint in &constraints { let OutlivesConstraint { sup, sub, locations, category } = constraint; - with_msg(&format!("{:?}: {:?} due to {:?} at {:?}", sup, sub, category, locations,))?; + let (name, arg) = match locations { + Locations::All(span) => ("All", tcx.sess.source_map().span_to_string(*span)), + Locations::Single(loc) => ("Single", format!("{:?}", loc)), + }; + with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?; } Ok(()) diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs index f97dff14645..5707127340d 100644 --- a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs @@ -259,7 +259,13 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { .param_env .and(type_op::normalize::Normalize::new(ty)) .fully_perform(self.infcx) - .unwrap_or_else(|_| bug!("failed to normalize {:?}", ty)); + .unwrap_or_else(|_| { + self.infcx + .tcx + .sess + .delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty)); + (self.infcx.tcx.types.err, None) + }); let constraints2 = self.add_implied_bounds(ty); normalized_inputs_and_output.push(ty); constraints1.into_iter().chain(constraints2) diff --git a/src/librustc_mir/const_eval/error.rs b/src/librustc_mir/const_eval/error.rs index b165a69433d..5deae94fe0c 100644 --- a/src/librustc_mir/const_eval/error.rs +++ b/src/librustc_mir/const_eval/error.rs @@ -2,7 +2,7 @@ use std::error::Error; use std::fmt; use rustc_middle::mir::AssertKind; -use rustc_span::Symbol; +use rustc_span::{Span, Symbol}; use super::InterpCx; use crate::interpret::{ConstEvalErr, InterpErrorInfo, Machine}; @@ -53,8 +53,9 @@ impl Error for ConstEvalErrKind {} pub fn error_to_const_error<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>( ecx: &InterpCx<'mir, 'tcx, M>, error: InterpErrorInfo<'tcx>, + span: Option<Span>, ) -> ConstEvalErr<'tcx> { error.print_backtrace(); let stacktrace = ecx.generate_stacktrace(); - ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span } + ConstEvalErr { error: error.kind, stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()) } } diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 695e0741e35..d62300b3f55 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -27,7 +27,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( body: &'mir mir::Body<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); - let tcx = ecx.tcx.tcx; + let tcx = *ecx.tcx; let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack); @@ -81,13 +81,14 @@ fn eval_body_using_ecx<'mir, 'tcx>( /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. pub(super) fn mk_eval_cx<'mir, 'tcx>( tcx: TyCtxt<'tcx>, - span: Span, + root_span: Span, param_env: ty::ParamEnv<'tcx>, can_access_statics: bool, ) -> CompileTimeEvalContext<'mir, 'tcx> { debug!("mk_eval_cx: {:?}", param_env); InterpCx::new( - tcx.at(span), + tcx, + root_span, param_env, CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), MemoryExtra { can_access_statics }, @@ -163,7 +164,7 @@ pub(super) fn op_to_const<'tcx>( 0, ), }; - let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap(); + let len = b.to_machine_usize(ecx).unwrap(); let start = start.try_into().unwrap(); let len: usize = len.try_into().unwrap(); ConstValue::Slice { data, start, end: start + len } @@ -212,7 +213,7 @@ fn validate_and_turn_into_const<'tcx>( })(); val.map_err(|error| { - let err = error_to_const_error(&ecx, error); + let err = error_to_const_error(&ecx, error, None); err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| { diag.note(note_on_undefined_behavior_error()); diag.emit(); @@ -299,9 +300,9 @@ pub fn const_eval_raw_provider<'tcx>( let is_static = tcx.is_static(def_id); - let span = tcx.def_span(cid.instance.def_id()); let mut ecx = InterpCx::new( - tcx.at(span), + tcx, + tcx.def_span(cid.instance.def_id()), key.param_env, CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), MemoryExtra { can_access_statics: is_static }, @@ -309,16 +310,17 @@ pub fn const_eval_raw_provider<'tcx>( let res = ecx.load_mir(cid.instance.def, cid.promoted); res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) - .and_then(|place| { - Ok(RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty }) - }) + .map(|place| RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty }) .map_err(|error| { - let err = error_to_const_error(&ecx, error); + let err = error_to_const_error(&ecx, error, None); // errors in statics are always emitted as fatal errors if is_static { // Ensure that if the above error was either `TooGeneric` or `Reported` // an error must be reported. - let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer"); + let v = err.report_as_error( + ecx.tcx.at(ecx.cur_span()), + "could not evaluate static initializer", + ); // If this is `Reveal:All`, then we need to make sure an error is reported but if // this is `Reveal::UserFacing`, then it's expected that we could get a @@ -374,13 +376,16 @@ pub fn const_eval_raw_provider<'tcx>( // anything else (array lengths, enum initializers, constant patterns) are // reported as hard errors } else { - err.report_as_error(ecx.tcx, "evaluation of constant value failed") + err.report_as_error( + ecx.tcx.at(ecx.cur_span()), + "evaluation of constant value failed", + ) } } } } else { // use of broken constant from other crate - err.report_as_error(ecx.tcx, "could not evaluate constant") + err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant") } }) } diff --git a/src/librustc_mir/dataflow/framework/direction.rs b/src/librustc_mir/dataflow/framework/direction.rs index da4ad9b6168..6c9cb529dc2 100644 --- a/src/librustc_mir/dataflow/framework/direction.rs +++ b/src/librustc_mir/dataflow/framework/direction.rs @@ -467,7 +467,7 @@ impl Direction for Forward { propagate(target, exit_state); } - Call { cleanup, destination, ref func, ref args, from_hir_call: _ } => { + Call { cleanup, destination, ref func, ref args, from_hir_call: _, fn_span: _ } => { if let Some(unwind) = cleanup { if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { propagate(unwind, exit_state); diff --git a/src/librustc_mir/dataflow/framework/tests.rs b/src/librustc_mir/dataflow/framework/tests.rs index 3ed0a9594e7..9349f5133a5 100644 --- a/src/librustc_mir/dataflow/framework/tests.rs +++ b/src/librustc_mir/dataflow/framework/tests.rs @@ -41,6 +41,7 @@ fn mock_body() -> mir::Body<'static> { destination: Some((dummy_place.clone(), mir::START_BLOCK)), cleanup: None, from_hir_call: false, + fn_span: DUMMY_SP, }, ); block(3, mir::TerminatorKind::Return); @@ -53,6 +54,7 @@ fn mock_body() -> mir::Body<'static> { destination: Some((dummy_place.clone(), mir::START_BLOCK)), cleanup: None, from_hir_call: false, + fn_span: DUMMY_SP, }, ); diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index 60823708773..1d49a32e196 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -99,9 +99,6 @@ impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K> where K: BorrowAnalysisKind<'tcx>, { - // The generator transform relies on the fact that this analysis does **not** use "before" - // effects. - fn statement_effect( &self, trans: &mut impl GenKill<Self::Idx>, diff --git a/src/librustc_mir/dataflow/impls/init_locals.rs b/src/librustc_mir/dataflow/impls/init_locals.rs index 726330b1f03..01cb794a2e0 100644 --- a/src/librustc_mir/dataflow/impls/init_locals.rs +++ b/src/librustc_mir/dataflow/impls/init_locals.rs @@ -33,9 +33,6 @@ impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals { } impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals { - // The generator transform relies on the fact that this analysis does **not** use "before" - // effects. - fn statement_effect( &self, trans: &mut impl GenKill<Self::Idx>, diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index ed01d6b01ea..d5def038912 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -30,7 +30,7 @@ pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals}; pub use self::borrows::Borrows; pub use self::init_locals::MaybeInitializedLocals; pub use self::liveness::MaybeLiveLocals; -pub use self::storage_liveness::MaybeStorageLive; +pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive}; /// `MaybeInitializedPlaces` tracks all places that might be /// initialized upon reaching a particular point in the control flow diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 2a2be069b1e..cd04493c092 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -1,9 +1,11 @@ pub use super::*; use crate::dataflow::BottomValue; -use crate::dataflow::{self, GenKill}; +use crate::dataflow::{self, GenKill, Results, ResultsRefCursor}; use crate::util::storage::AlwaysLiveLocals; +use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; +use std::cell::RefCell; #[derive(Clone)] pub struct MaybeStorageLive { @@ -76,3 +78,233 @@ impl BottomValue for MaybeStorageLive { /// bottom = dead const BOTTOM_VALUE: bool = false; } + +type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>; + +/// Dataflow analysis that determines whether each local requires storage at a +/// given location; i.e. whether its storage can go away without being observed. +pub struct MaybeRequiresStorage<'mir, 'tcx> { + body: &'mir Body<'tcx>, + borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>, +} + +impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { + pub fn new( + body: &'mir Body<'tcx>, + borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>, + ) -> Self { + MaybeRequiresStorage { + body, + borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)), + } + } +} + +impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { + type Idx = Local; + + const NAME: &'static str = "requires_storage"; + + fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { + body.local_decls.len() + } + + fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) { + // The resume argument is live on function entry (we don't care about + // the `self` argument) + for arg in body.args_iter().skip(1) { + on_entry.insert(arg); + } + } +} + +impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { + fn before_statement_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + stmt: &mir::Statement<'tcx>, + loc: Location, + ) { + // If a place is borrowed in a statement, it needs storage for that statement. + self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc); + + match &stmt.kind { + StatementKind::StorageDead(l) => trans.kill(*l), + + // If a place is assigned to in a statement, it needs storage for that statement. + StatementKind::Assign(box (place, _)) + | StatementKind::SetDiscriminant { box place, .. } => { + trans.gen(place.local); + } + StatementKind::LlvmInlineAsm(asm) => { + for place in &*asm.outputs { + trans.gen(place.local); + } + } + + // Nothing to do for these. Match exhaustively so this fails to compile when new + // variants are added. + StatementKind::AscribeUserType(..) + | StatementKind::FakeRead(..) + | StatementKind::Nop + | StatementKind::Retag(..) + | StatementKind::StorageLive(..) => {} + } + } + + fn statement_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _: &mir::Statement<'tcx>, + loc: Location, + ) { + // If we move from a place then only stops needing storage *after* + // that statement. + self.check_for_move(trans, loc); + } + + fn before_terminator_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + terminator: &mir::Terminator<'tcx>, + loc: Location, + ) { + // If a place is borrowed in a terminator, it needs storage for that terminator. + self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc); + + match &terminator.kind { + TerminatorKind::Call { destination: Some((place, _)), .. } => { + trans.gen(place.local); + } + + // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for + // that is that a `yield` will return from the function, and `resume_arg` is written + // only when the generator is later resumed. Unlike `Call`, this doesn't require the + // place to have storage *before* the yield, only after. + TerminatorKind::Yield { .. } => {} + + TerminatorKind::InlineAsm { operands, .. } => { + for op in operands { + match op { + InlineAsmOperand::Out { place, .. } + | InlineAsmOperand::InOut { out_place: place, .. } => { + if let Some(place) = place { + trans.gen(place.local); + } + } + InlineAsmOperand::In { .. } + | InlineAsmOperand::Const { .. } + | InlineAsmOperand::SymFn { .. } + | InlineAsmOperand::SymStatic { .. } => {} + } + } + } + + // Nothing to do for these. Match exhaustively so this fails to compile when new + // variants are added. + TerminatorKind::Call { destination: None, .. } + | TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable => {} + } + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + terminator: &mir::Terminator<'tcx>, + loc: Location, + ) { + match &terminator.kind { + // For call terminators the destination requires storage for the call + // and after the call returns successfully, but not after a panic. + // Since `propagate_call_unwind` doesn't exist, we have to kill the + // destination here, and then gen it again in `call_return_effect`. + TerminatorKind::Call { destination: Some((place, _)), .. } => { + trans.kill(place.local); + } + + // Nothing to do for these. Match exhaustively so this fails to compile when new + // variants are added. + TerminatorKind::Call { destination: None, .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::InlineAsm { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable => {} + } + + self.check_for_move(trans, loc); + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _block: BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + return_place: mir::Place<'tcx>, + ) { + trans.gen(return_place.local); + } + + fn yield_resume_effect( + &self, + trans: &mut impl GenKill<Self::Idx>, + _resume_block: BasicBlock, + resume_place: mir::Place<'tcx>, + ) { + trans.gen(resume_place.local); + } +} + +impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { + /// Kill locals that are fully moved and have not been borrowed. + fn check_for_move(&self, trans: &mut impl GenKill<Local>, loc: Location) { + let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals }; + visitor.visit_location(&self.body, loc); + } +} + +impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> { + /// bottom = dead + const BOTTOM_VALUE: bool = false; +} + +struct MoveVisitor<'a, 'mir, 'tcx, T> { + borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>, + trans: &'a mut T, +} + +impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T> +where + T: GenKill<Local>, +{ + fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) { + if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { + let mut borrowed_locals = self.borrowed_locals.borrow_mut(); + borrowed_locals.seek_before_primary_effect(loc); + if !borrowed_locals.contains(*local) { + self.trans.kill(*local); + } + } + } +} diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index c0ab356756a..41c7bd95a96 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -401,6 +401,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { ref destination, cleanup: _, from_hir_call: _, + fn_span: _, } => { self.gather_operand(func); for arg in args { @@ -438,7 +439,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } } InlineAsmOperand::SymFn { value: _ } - | InlineAsmOperand::SymStatic { value: _ } => {} + | InlineAsmOperand::SymStatic { def_id: _ } => {} } } } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 0fd695586eb..cfe856abe36 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -268,11 +268,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (&ty::Array(_, length), &ty::Slice(_)) => { let ptr = self.read_immediate(src)?.to_scalar()?; // u64 cast is from usize to u64, which is always good - let val = Immediate::new_slice( - ptr, - length.eval_usize(self.tcx.tcx, self.param_env), - self, - ); + let val = + Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self); self.write_immediate(val, dest) } (&ty::Dynamic(..), &ty::Dynamic(..)) => { diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 6497e211de3..22f4691c22b 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -33,6 +33,8 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { pub machine: M, /// The results of the type checker, from rustc. + /// The span in this is the "root" of the evaluation, i.e., the const + /// we are evaluating (if this is CTFE). pub tcx: TyCtxtAt<'tcx>, /// Bounds in scope for polymorphic evaluations. @@ -171,15 +173,8 @@ impl<'mir, 'tcx, Tag> Frame<'mir, 'tcx, Tag> { impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> { /// Return the `SourceInfo` of the current instruction. - pub fn current_source_info(&self) -> Option<mir::SourceInfo> { - self.loc.map(|loc| { - let block = &self.body.basic_blocks()[loc.block]; - if loc.statement_index < block.statements.len() { - block.statements[loc.statement_index].source_info - } else { - block.terminator().source_info - } - }) + pub fn current_source_info(&self) -> Option<&mir::SourceInfo> { + self.loc.map(|loc| self.body.source_info(loc)) } } @@ -209,7 +204,7 @@ where } } -impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> { +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> { type Ty = Ty<'tcx>; type TyAndLayout = InterpResult<'tcx, TyAndLayout<'tcx>>; @@ -292,14 +287,15 @@ pub(super) fn from_known_layout<'tcx>( impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn new( - tcx: TyCtxtAt<'tcx>, + tcx: TyCtxt<'tcx>, + root_span: Span, param_env: ty::ParamEnv<'tcx>, machine: M, memory_extra: M::MemoryExtra, ) -> Self { InterpCx { machine, - tcx, + tcx: tcx.at(root_span), param_env, memory: Memory::new(tcx, memory_extra), vtables: FxHashMap::default(), @@ -307,9 +303,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[inline(always)] - pub fn set_span(&mut self, span: Span) { - self.tcx.span = span; - self.memory.tcx.span = span; + pub fn cur_span(&self) -> Span { + self.stack() + .last() + .and_then(|f| f.current_source_info()) + .map(|si| si.span) + .unwrap_or(self.tcx.span) } #[inline(always)] @@ -392,7 +391,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline] pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP) + ty.is_freeze(*self.tcx, self.param_env, self.tcx.span) } pub fn load_mir( @@ -561,7 +560,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let size = size.align_to(align); // Check if this brought us over the size limit. - if size.bytes() >= self.tcx.data_layout().obj_size_bound() { + if size.bytes() >= self.tcx.data_layout.obj_size_bound() { throw_ub!(InvalidMeta("total size is bigger than largest supported object")); } Ok(Some((size, align))) @@ -577,7 +576,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let elem = layout.field(self, 0)?; // Make sure the slice is not too big. - let size = elem.size.checked_mul(len, &*self.tcx).ok_or_else(|| { + let size = elem.size.checked_mul(len, self).ok_or_else(|| { err_ub!(InvalidMeta("slice is bigger than largest supported object")) })?; Ok(Some((size, elem.align.abi))) diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 02a7f24a1e3..3c724c79b40 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -111,7 +111,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>( if let InternMode::Static(mutability) = mode { // For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume // no interior mutability. - let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx.tcx, ecx.param_env, ecx.tcx.span)); + let frozen = ty.map_or(true, |ty| ty.is_freeze(*ecx.tcx, ecx.param_env, ecx.tcx.span)); // For statics, allocation mutability is the combination of the place mutability and // the type mutability. // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere. @@ -253,8 +253,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir // caused (by somehow getting a mutable reference in a `const`). if ref_mutability == Mutability::Mut { match referenced_ty.kind { - ty::Array(_, n) - if n.eval_usize(tcx.tcx, self.ecx.param_env) == 0 => {} + ty::Array(_, n) if n.eval_usize(*tcx, self.ecx.param_env) == 0 => {} ty::Slice(_) if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? == 0 => {} diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 115a472cabe..47e5b8b4fce 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -347,7 +347,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let index = u64::from(self.read_scalar(args[1])?.to_u32()?); let elem = args[2]; let input = args[0]; - let (len, e_ty) = input.layout.ty.simd_size_and_type(self.tcx.tcx); + let (len, e_ty) = input.layout.ty.simd_size_and_type(*self.tcx); assert!( index < len, "Index `{}` must be in bounds of vector type `{}`: `[0, {})`", @@ -374,7 +374,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } sym::simd_extract => { let index = u64::from(self.read_scalar(args[1])?.to_u32()?); - let (len, e_ty) = args[0].layout.ty.simd_size_and_type(self.tcx.tcx); + let (len, e_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx); assert!( index < len, "index `{}` is out-of-bounds of vector type `{}` with length `{}`", diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs index 91b046d7bb2..9adef8c43c7 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -1,6 +1,7 @@ use std::convert::TryFrom; use rustc_hir::lang_items::PanicLocationLangItem; +use rustc_middle::mir::TerminatorKind; use rustc_middle::ty::subst::Subst; use rustc_span::{Span, Symbol}; use rustc_target::abi::LayoutOf; @@ -14,19 +15,39 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a /// frame which is not `#[track_caller]`. crate fn find_closest_untracked_caller_location(&self) -> Span { - self.stack() + let frame = self + .stack() .iter() .rev() // Find first non-`#[track_caller]` frame. - .find(|frame| !frame.instance.def.requires_caller_location(*self.tcx)) + .find(|frame| { + debug!( + "find_closest_untracked_caller_location: checking frame {:?}", + frame.instance + ); + !frame.instance.def.requires_caller_location(*self.tcx) + }) // Assert that there is always such a frame. - .unwrap() - .current_source_info() - // Assert that the frame we look at is actually executing code currently - // (`current_source_info` is None when we are unwinding and the frame does - // not require cleanup). - .unwrap() - .span + .unwrap(); + // Assert that the frame we look at is actually executing code currently + // (`current_source_info` is None when we are unwinding and the frame does + // not require cleanup). + let loc = frame.loc.unwrap(); + // If this is a `Call` terminator, use the `fn_span` instead. + let block = &frame.body.basic_blocks()[loc.block]; + if loc.statement_index == block.statements.len() { + debug!( + "find_closest_untracked_caller_location:: got terminator {:?} ({:?})", + block.terminator(), + block.terminator().kind + ); + if let TerminatorKind::Call { fn_span, .. } = block.terminator().kind { + return fn_span; + } + } + // This is a different terminator (such as `Drop`) or not a terminator at all + // (such as `box`). Use the normal span. + frame.body.source_info(loc).span } /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index d7f64542aa7..8af1a8ac608 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -14,7 +14,7 @@ use std::ptr; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_middle::ty::{self, query::TyCtxtAt, Instance, ParamEnv}; +use rustc_middle::ty::{self, Instance, ParamEnv, TyCtxt}; use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; use super::{ @@ -115,7 +115,7 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { pub extra: M::MemoryExtra, /// Lets us implement `HasDataLayout`, which is awfully convenient. - pub tcx: TyCtxtAt<'tcx>, + pub tcx: TyCtxt<'tcx>, } impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> { @@ -126,7 +126,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> } impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { - pub fn new(tcx: TyCtxtAt<'tcx>, extra: M::MemoryExtra) -> Self { + pub fn new(tcx: TyCtxt<'tcx>, extra: M::MemoryExtra) -> Self { Memory { alloc_map: M::MemoryMap::default(), extra_fn_ptr_map: FxHashMap::default(), @@ -425,7 +425,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { /// `M::tag_allocation`. fn get_global_alloc( memory_extra: &M::MemoryExtra, - tcx: TyCtxtAt<'tcx>, + tcx: TyCtxt<'tcx>, id: AllocId, is_write: bool, ) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> { @@ -455,7 +455,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { throw_unsup!(ReadForeignStatic(def_id)) } trace!("get_global_alloc: Need to compute {:?}", def_id); - let instance = Instance::mono(tcx.tcx, def_id); + let instance = Instance::mono(tcx, def_id); let gid = GlobalId { instance, promoted: None }; // Use the raw query here to break validation cycles. Later uses of the static // will call the full query anyway. @@ -664,14 +664,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) { // Cannot be a closure because it is generic in `Tag`, `Extra`. fn write_allocation_track_relocs<'tcx, Tag: Copy + fmt::Debug, Extra>( - tcx: TyCtxtAt<'tcx>, + tcx: TyCtxt<'tcx>, allocs_to_print: &mut VecDeque<AllocId>, alloc: &Allocation<Tag, Extra>, ) { for &(_, target_id) in alloc.relocations().values() { allocs_to_print.push_back(target_id); } - pretty::write_allocation(tcx.tcx, alloc, &mut std::io::stderr()).unwrap(); + pretty::write_allocation(tcx, alloc, &mut std::io::stderr()).unwrap(); } allocs.sort(); @@ -820,7 +820,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { return Ok(()); } }; - let tcx = self.tcx.tcx; + let tcx = self.tcx; self.get_raw_mut(ptr.alloc_id)?.write_bytes(&tcx, ptr, src) } @@ -846,7 +846,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { return Ok(()); } }; - let tcx = self.tcx.tcx; + let tcx = self.tcx; let allocation = self.get_raw_mut(ptr.alloc_id)?; for idx in 0..len { @@ -888,7 +888,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { let relocations = self.get_raw(src.alloc_id)?.prepare_relocation_copy(self, src, size, dest, length); - let tcx = self.tcx.tcx; + let tcx = self.tcx; // This checks relocation edges on the src. let src_bytes = diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index db4473154c4..38f5988d0eb 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -651,12 +651,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Convert discriminant to variant index, and catch invalid discriminants. let index = match op.layout.ty.kind { ty::Adt(adt, _) => { - adt.discriminants(self.tcx.tcx).find(|(_, var)| var.val == discr_bits) + adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits) } ty::Generator(def_id, substs, _) => { let substs = substs.as_generator(); substs - .discriminants(def_id, self.tcx.tcx) + .discriminants(def_id, *self.tcx) .find(|(_, var)| var.val == discr_bits) } _ => bug!("tagged layout for non-adt non-generator"), diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 3f0800b12b5..24b191e9b53 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -404,7 +404,10 @@ where // to get some code to work that probably ought to work. field_layout.align.abi } - None => bug!("Cannot compute offset for extern type field at non-0 offset"), + None => span_bug!( + self.cur_span(), + "cannot compute offset for extern type field at non-0 offset" + ), }; (base.meta, offset.align_to(align)) } else { @@ -440,7 +443,11 @@ where assert!(!field_layout.is_unsized()); base.offset(offset, MemPlaceMeta::None, field_layout, self) } - _ => bug!("`mplace_index` called on non-array type {:?}", base.layout.ty), + _ => span_bug!( + self.cur_span(), + "`mplace_index` called on non-array type {:?}", + base.layout.ty + ), } } @@ -454,7 +461,7 @@ where let len = base.len(self)?; // also asserts that we have a type where this makes sense let stride = match base.layout.fields { FieldsShape::Array { stride, .. } => stride, - _ => bug!("mplace_array_fields: expected an array layout"), + _ => span_bug!(self.cur_span(), "mplace_array_fields: expected an array layout"), }; let layout = base.layout.field(self, 0)?; let dl = &self.tcx.data_layout; @@ -484,7 +491,9 @@ where // (that have count 0 in their layout). let from_offset = match base.layout.fields { FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked - _ => bug!("Unexpected layout of index access: {:#?}", base.layout), + _ => { + span_bug!(self.cur_span(), "unexpected layout of index access: {:#?}", base.layout) + } }; // Compute meta and new layout @@ -497,7 +506,9 @@ where let len = Scalar::from_machine_usize(inner_len, self); (MemPlaceMeta::Meta(len), base.layout.ty) } - _ => bug!("cannot subslice non-array type: `{:?}`", base.layout.ty), + _ => { + span_bug!(self.cur_span(), "cannot subslice non-array type: `{:?}`", base.layout.ty) + } }; let layout = self.layout_of(ty)?; base.offset(from_offset, meta, layout, self) @@ -768,7 +779,7 @@ where None => return Ok(()), // zero-sized access }; - let tcx = &*self.tcx; + let tcx = *self.tcx; // FIXME: We should check that there are dest.layout.size many bytes available in // memory. The code below is not sufficient, with enough padding it might not // cover all the bytes! @@ -776,12 +787,14 @@ where Immediate::Scalar(scalar) => { match dest.layout.abi { Abi::Scalar(_) => {} // fine - _ => { - bug!("write_immediate_to_mplace: invalid Scalar layout: {:#?}", dest.layout) - } + _ => span_bug!( + self.cur_span(), + "write_immediate_to_mplace: invalid Scalar layout: {:#?}", + dest.layout + ), } self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar( - tcx, + &tcx, ptr, scalar, dest.layout.size, @@ -793,7 +806,8 @@ where // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. let (a, b) = match dest.layout.abi { Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value), - _ => bug!( + _ => span_bug!( + self.cur_span(), "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", dest.layout ), @@ -806,8 +820,8 @@ where // but that does not work: We could be a newtype around a pair, then the // fields do not match the `ScalarPair` components. - self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar(tcx, ptr, a_val, a_size)?; - self.memory.get_raw_mut(b_ptr.alloc_id)?.write_scalar(tcx, b_ptr, b_val, b_size) + self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar(&tcx, ptr, a_val, a_size)?; + self.memory.get_raw_mut(b_ptr.alloc_id)?.write_scalar(&tcx, b_ptr, b_val, b_size) } } } @@ -841,9 +855,9 @@ where ) -> InterpResult<'tcx> { // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. - if !mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout) { + if !mir_assign_valid_types(*self.tcx, src.layout, dest.layout) { span_bug!( - self.tcx.span, + self.cur_span(), "type mismatch when copying!\nsrc: {:?},\ndest: {:?}", src.layout.ty, dest.layout.ty, @@ -898,7 +912,7 @@ where src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { - if mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout) { + if mir_assign_valid_types(*self.tcx, src.layout, dest.layout) { // Fast path: Just use normal `copy_op` return self.copy_op(src, dest); } @@ -910,7 +924,7 @@ where // on `typeck_tables().has_errors` at all const eval entry points. debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); self.tcx.sess.delay_span_bug( - self.tcx.span, + self.cur_span(), "size-changing transmute, should have been caught by transmute checking", ); throw_inval!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 02a709ab1a1..16c6396799e 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -76,7 +76,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { info!("{:?}", stmt); - self.set_span(stmt.source_info.span); use rustc_middle::mir::StatementKind::*; @@ -279,7 +278,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { info!("{:?}", terminator.kind); - self.set_span(terminator.source_info.span); self.eval_terminator(terminator)?; if !self.stack().is_empty() { diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 4a63884be4c..cd7621ea975 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -56,6 +56,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { destination, ref cleanup, from_hir_call: _from_hir_call, + fn_span: _, } => { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index b9f9d37df76..a1d124bb760 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -2,7 +2,7 @@ use std::convert::TryFrom; use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; -use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size}; +use rustc_target::abi::{Align, LayoutOf, Size}; use super::{FnVal, InterpCx, Machine, MemoryKind}; @@ -49,8 +49,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let size = layout.size.bytes(); let align = layout.align.abi.bytes(); + let tcx = *self.tcx; let ptr_size = self.pointer_size(); - let ptr_align = self.tcx.data_layout.pointer_align.abi; + let ptr_align = tcx.data_layout.pointer_align.abi; // ///////////////////////////////////////////////////////////////////////////////////////// // If you touch this code, be sure to also make the corresponding changes to // `get_vtable` in `rust_codegen_llvm/meth.rs`. @@ -60,33 +61,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ptr_align, MemoryKind::Vtable, ); - let tcx = &*self.tcx; - let drop = Instance::resolve_drop_in_place(*tcx, ty); + let drop = Instance::resolve_drop_in_place(tcx, ty); let drop = self.memory.create_fn_alloc(FnVal::Instance(drop)); // No need to do any alignment checks on the memory accesses below, because we know the // allocation is correctly aligned as we created it above. Also we're only offsetting by // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`. let vtable_alloc = self.memory.get_raw_mut(vtable.alloc_id)?; - vtable_alloc.write_ptr_sized(tcx, vtable, drop.into())?; + vtable_alloc.write_ptr_sized(&tcx, vtable, drop.into())?; - let size_ptr = vtable.offset(ptr_size, tcx)?; - vtable_alloc.write_ptr_sized(tcx, size_ptr, Scalar::from_uint(size, ptr_size).into())?; - let align_ptr = vtable.offset(ptr_size * 2, tcx)?; - vtable_alloc.write_ptr_sized(tcx, align_ptr, Scalar::from_uint(align, ptr_size).into())?; + let size_ptr = vtable.offset(ptr_size, &tcx)?; + vtable_alloc.write_ptr_sized(&tcx, size_ptr, Scalar::from_uint(size, ptr_size).into())?; + let align_ptr = vtable.offset(ptr_size * 2, &tcx)?; + vtable_alloc.write_ptr_sized(&tcx, align_ptr, Scalar::from_uint(align, ptr_size).into())?; for (i, method) in methods.iter().enumerate() { if let Some((def_id, substs)) = *method { // resolve for vtable: insert shims where needed let instance = - ty::Instance::resolve_for_vtable(*tcx, self.param_env, def_id, substs) + ty::Instance::resolve_for_vtable(tcx, self.param_env, def_id, substs) .ok_or_else(|| err_inval!(TooGeneric))?; let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); // We cannot use `vtable_allic` as we are creating fn ptrs in this loop. - let method_ptr = vtable.offset(ptr_size * (3 + i as u64), tcx)?; + let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &tcx)?; self.memory.get_raw_mut(vtable.alloc_id)?.write_ptr_sized( - tcx, + &tcx, method_ptr, fn_ptr.into(), )?; @@ -171,7 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { alloc.read_ptr_sized(self, vtable.offset(pointer_size * 2, self)?)?.not_undef()?; let align = u64::try_from(self.force_bits(align, pointer_size)?).unwrap(); - if size >= self.tcx.data_layout().obj_size_bound() { + if size >= self.tcx.data_layout.obj_size_bound() { throw_ub_format!( "invalid vtable: \ size is bigger than largest supported object" diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index f3d3666b99f..994d1e69f2e 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -634,9 +634,19 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } mir::TerminatorKind::InlineAsm { ref operands, .. } => { for op in operands { - if let mir::InlineAsmOperand::SymFn { value } = op { - let fn_ty = self.monomorphize(value.literal.ty); - visit_fn_use(self.tcx, fn_ty, false, &mut self.output); + match *op { + mir::InlineAsmOperand::SymFn { ref value } => { + let fn_ty = self.monomorphize(value.literal.ty); + visit_fn_use(self.tcx, fn_ty, false, &mut self.output); + } + mir::InlineAsmOperand::SymStatic { def_id } => { + let instance = Instance::mono(self.tcx, def_id); + if should_monomorphize_locally(self.tcx, &instance) { + trace!("collecting asm sym static {:?}", def_id); + self.output.push(MonoItem::Static(def_id)); + } + } + _ => {} } } } diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index 28edd87a3ad..76c1c465a8b 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -20,11 +20,12 @@ pub fn custom_coerce_unsize_info<'tcx>( }); match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) { - Ok(traits::VtableImpl(traits::VtableImplData { impl_def_id, .. })) => { - tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap() - } - vtable => { - bug!("invalid `CoerceUnsized` vtable: {:?}", vtable); + Ok(traits::ImplSourceUserDefined(traits::ImplSourceUserDefinedData { + impl_def_id, + .. + })) => tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap(), + impl_source => { + bug!("invalid `CoerceUnsized` impl_source: {:?}", impl_source); } } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index b439e919050..f95fd9b9e90 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -460,6 +460,7 @@ impl CloneShimBuilder<'tcx> { destination: Some((dest, next)), cleanup: Some(cleanup), from_hir_call: true, + fn_span: self.span, }, false, ); @@ -788,6 +789,7 @@ fn build_call_shim<'tcx>( None }, from_hir_call: true, + fn_span: span, }, false, ); diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index 5d604d8e3d7..936c1a84e14 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -2,7 +2,6 @@ //! //! See the `Qualif` trait for more info. -use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_span::DUMMY_SP; @@ -137,10 +136,7 @@ impl Qualif for CustomEq { substs: SubstsRef<'tcx>, ) -> bool { let ty = cx.tcx.mk_ty(ty::Adt(adt, substs)); - let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id.as_local().unwrap()); - cx.tcx - .infer_ctxt() - .enter(|infcx| !traits::type_marked_structural(id, cx.body.span, &infcx, ty)) + !ty.is_structural_eq_shallow(cx.tcx) } } diff --git a/src/librustc_mir/transform/check_packed_ref.rs b/src/librustc_mir/transform/check_packed_ref.rs index faad1a72327..043b2d0d170 100644 --- a/src/librustc_mir/transform/check_packed_ref.rs +++ b/src/librustc_mir/transform/check_packed_ref.rs @@ -51,7 +51,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> { lint_root, source_info.span, |lint| { - lint.build(&format!("reference to packed field is unaligned",)) + lint.build("reference to packed field is unaligned") .note( "fields of packed structs are not properly aligned, and creating \ a misaligned reference is undefined behavior (even if that \ diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 0ff60cbd55d..d50f052d405 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -313,7 +313,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let param_env = tcx.param_env(def_id).with_reveal_all(); let span = tcx.def_span(def_id); - let mut ecx = InterpCx::new(tcx.at(span), param_env, ConstPropMachine::new(), ()); + let mut ecx = InterpCx::new(tcx, span, param_env, ConstPropMachine::new(), ()); let can_const_prop = CanConstProp::check(body); let ret = ecx @@ -404,9 +404,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { match self.ecx.eval_const_to_op(c.literal, None) { Ok(op) => Some(op), Err(error) => { - // Make sure errors point at the constant. - self.ecx.set_span(c.span); - let err = error_to_const_error(&self.ecx, error); + let tcx = self.ecx.tcx.at(c.span); + let err = error_to_const_error(&self.ecx, error, Some(c.span)); if let Some(lint_root) = self.lint_root(source_info) { let lint_only = match c.literal.val { // Promoteds must lint and not error as the user didn't ask for them @@ -418,17 +417,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if lint_only { // Out of backwards compatibility we cannot report hard errors in unused // generic functions using associated constants of the generic parameters. - err.report_as_lint( - self.ecx.tcx, - "erroneous constant used", - lint_root, - Some(c.span), - ); + err.report_as_lint(tcx, "erroneous constant used", lint_root, Some(c.span)); } else { - err.report_as_error(self.ecx.tcx, "erroneous constant used"); + err.report_as_error(tcx, "erroneous constant used"); } } else { - err.report_as_error(self.ecx.tcx, "erroneous constant used"); + err.report_as_error(tcx, "erroneous constant used"); } None } @@ -851,7 +845,6 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { trace!("visit_statement: {:?}", statement); let source_info = statement.source_info; - self.ecx.set_span(source_info.span); self.source_info = Some(source_info); if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind { let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty; @@ -864,7 +857,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { if let Some(value) = self.get_const(place) { if self.should_const_prop(value) { trace!("replacing {:?} with {:?}", rval, value); - self.replace_with_const(rval, value, statement.source_info); + self.replace_with_const(rval, value, source_info); if can_const_prop == ConstPropMode::FullConstProp || can_const_prop == ConstPropMode::OnlyInsideOwnBlock { @@ -927,7 +920,6 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { let source_info = terminator.source_info; - self.ecx.set_span(source_info.span); self.source_info = Some(source_info); self.super_terminator(terminator, location); match &mut terminator.kind { diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 3509a9a5653..25b6a51d91b 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -50,7 +50,7 @@ //! Otherwise it drops all the values in scope at the last suspension point. use crate::dataflow::impls::{ - MaybeBorrowedLocals, MaybeInitializedLocals, MaybeLiveLocals, MaybeStorageLive, + MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, }; use crate::dataflow::{self, Analysis}; use crate::transform::no_landing_pads::no_landing_pads; @@ -444,80 +444,86 @@ fn locals_live_across_suspend_points( movable: bool, ) -> LivenessInfo { let def_id = source.def_id(); + let body_ref: &Body<'_> = &body; // Calculate when MIR locals have live storage. This gives us an upper bound of their // lifetimes. let mut storage_live = MaybeStorageLive::new(always_live_locals.clone()) - .into_engine(tcx, body, def_id) + .into_engine(tcx, body_ref, def_id) .iterate_to_fixpoint() - .into_results_cursor(body); - - let mut init = MaybeInitializedLocals - .into_engine(tcx, body, def_id) - .iterate_to_fixpoint() - .into_results_cursor(body); - - let mut live = MaybeLiveLocals - .into_engine(tcx, body, def_id) - .iterate_to_fixpoint() - .into_results_cursor(body); - - let mut borrowed = MaybeBorrowedLocals::all_borrows() - .into_engine(tcx, body, def_id) + .into_results_cursor(body_ref); + + // Calculate the MIR locals which have been previously + // borrowed (even if they are still active). + let borrowed_locals_results = + MaybeBorrowedLocals::all_borrows().into_engine(tcx, body_ref, def_id).iterate_to_fixpoint(); + + let mut borrowed_locals_cursor = + dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results); + + // Calculate the MIR locals that we actually need to keep storage around + // for. + let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results) + .into_engine(tcx, body_ref, def_id) + .iterate_to_fixpoint(); + let mut requires_storage_cursor = + dataflow::ResultsCursor::new(body_ref, &requires_storage_results); + + // Calculate the liveness of MIR locals ignoring borrows. + let mut liveness = MaybeLiveLocals + .into_engine(tcx, body_ref, def_id) .iterate_to_fixpoint() - .into_results_cursor(body); - - // Liveness across yield points is determined by the following boolean equation, where `live`, - // `init` and `borrowed` come from dataflow and `movable` is a property of the generator. - // Movable generators do not allow borrows to live across yield points, so they don't need to - // store a local simply because it is borrowed. - // - // live_across_yield := (live & init) | (!movable & borrowed) - // - let mut locals_live_across_yield_point = |block| { - live.seek_to_block_end(block); - let mut live_locals = live.get().clone(); - - init.seek_to_block_end(block); - live_locals.intersect(init.get()); - - if !movable { - borrowed.seek_to_block_end(block); - live_locals.union(borrowed.get()); - } - - live_locals - }; + .into_results_cursor(body_ref); let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks()); let mut live_locals_at_suspension_points = Vec::new(); let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len()); for (block, data) in body.basic_blocks().iter_enumerated() { - if !matches!(data.terminator().kind, TerminatorKind::Yield { .. }) { - continue; - } + if let TerminatorKind::Yield { .. } = data.terminator().kind { + let loc = Location { block, statement_index: data.statements.len() }; + + liveness.seek_to_block_end(block); + let mut live_locals = liveness.get().clone(); + + if !movable { + // The `liveness` variable contains the liveness of MIR locals ignoring borrows. + // This is correct for movable generators since borrows cannot live across + // suspension points. However for immovable generators we need to account for + // borrows, so we conseratively assume that all borrowed locals are live until + // we find a StorageDead statement referencing the locals. + // To do this we just union our `liveness` result with `borrowed_locals`, which + // contains all the locals which has been borrowed before this suspension point. + // If a borrow is converted to a raw reference, we must also assume that it lives + // forever. Note that the final liveness is still bounded by the storage liveness + // of the local, which happens using the `intersect` operation below. + borrowed_locals_cursor.seek_before_primary_effect(loc); + live_locals.union(borrowed_locals_cursor.get()); + } - // Store the storage liveness for later use so we can restore the state - // after a suspension point - storage_live.seek_to_block_end(block); - storage_liveness_map[block] = Some(storage_live.get().clone()); + // Store the storage liveness for later use so we can restore the state + // after a suspension point + storage_live.seek_before_primary_effect(loc); + storage_liveness_map[block] = Some(storage_live.get().clone()); - let mut live_locals = locals_live_across_yield_point(block); + // Locals live are live at this point only if they are used across + // suspension points (the `liveness` variable) + // and their storage is required (the `storage_required` variable) + requires_storage_cursor.seek_before_primary_effect(loc); + live_locals.intersect(requires_storage_cursor.get()); - // The combination of `MaybeInitializedLocals` and `MaybeBorrowedLocals` should be strictly - // more precise than `MaybeStorageLive` because they handle `StorageDead` themselves. This - // assumes that the MIR forbids locals from being initialized/borrowed before reaching - // `StorageLive`. - debug_assert!(storage_live.get().superset(&live_locals)); + // The generator argument is ignored. + live_locals.remove(SELF_ARG); - // Ignore the generator's `self` argument since it is handled seperately. - live_locals.remove(SELF_ARG); - debug!("block = {:?}, live_locals = {:?}", block, live_locals); - live_locals_at_any_suspension_point.union(&live_locals); - live_locals_at_suspension_points.push(live_locals); - } + debug!("loc = {:?}, live_locals = {:?}", loc, live_locals); + // Add the locals live at this suspension point to the set of locals which live across + // any suspension points + live_locals_at_any_suspension_point.union(&live_locals); + + live_locals_at_suspension_points.push(live_locals); + } + } debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point); // Renumber our liveness_map bitsets to include only the locals we are @@ -528,11 +534,10 @@ fn locals_live_across_suspend_points( .collect(); let storage_conflicts = compute_storage_conflicts( - body, + body_ref, &live_locals_at_any_suspension_point, always_live_locals.clone(), - init, - borrowed, + requires_storage_results, ); LivenessInfo { @@ -564,37 +569,6 @@ fn renumber_bitset( out } -/// Record conflicts between locals at the current dataflow cursor positions. -/// -/// You need to seek the cursors before calling this function. -fn record_conflicts_at_curr_loc( - local_conflicts: &mut BitMatrix<Local, Local>, - init: &dataflow::ResultsCursor<'mir, 'tcx, MaybeInitializedLocals>, - borrowed: &dataflow::ResultsCursor<'mir, 'tcx, MaybeBorrowedLocals>, -) { - // A local requires storage if it is initialized or borrowed. For now, a local - // becomes uninitialized if it is moved from, but is still considered "borrowed". - // - // requires_storage := init | borrowed - // - // Just like when determining what locals are live at yield points, there is no need - // to look at storage liveness here, since `init | borrowed` is strictly more precise. - // - // FIXME: This function is called in a loop, so it might be better to pass in a temporary - // bitset rather than cloning here. - let mut requires_storage = init.get().clone(); - requires_storage.union(borrowed.get()); - - for local in requires_storage.iter() { - local_conflicts.union_row_with(&requires_storage, local); - } - - // `>1` because the `self` argument always requires storage. - if requires_storage.count() > 1 { - trace!("requires_storage={:?}", requires_storage); - } -} - /// For every saved local, looks for which locals are StorageLive at the same /// time. Generates a bitset for every local of all the other locals that may be /// StorageLive simultaneously with that local. This is used in the layout @@ -603,45 +577,30 @@ fn compute_storage_conflicts( body: &'mir Body<'tcx>, stored_locals: &BitSet<Local>, always_live_locals: storage::AlwaysLiveLocals, - mut init: dataflow::ResultsCursor<'mir, 'tcx, MaybeInitializedLocals>, - mut borrowed: dataflow::ResultsCursor<'mir, 'tcx, MaybeBorrowedLocals>, + requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, ) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> { - debug!("compute_storage_conflicts({:?})", body.span); assert_eq!(body.local_decls.len(), stored_locals.domain_size()); - // Locals that are always live conflict with all other locals. - // - // FIXME: Why do we need to handle locals without `Storage{Live,Dead}` specially here? - // Shouldn't it be enough to know whether they are initialized? - let always_live_locals = always_live_locals.into_inner(); - let mut local_conflicts = BitMatrix::from_row_n(&always_live_locals, body.local_decls.len()); - - // Visit every reachable statement and terminator. The exact order does not matter. When two - // locals are live at the same point in time, add an entry in the conflict matrix. - for (block, data) in traversal::preorder(body) { - // Ignore unreachable blocks. - if data.terminator().kind == TerminatorKind::Unreachable { - continue; - } + debug!("compute_storage_conflicts({:?})", body.span); + debug!("always_live = {:?}", always_live_locals); - // Observe the dataflow state *before* all possible locations (statement or terminator) in - // each basic block... - for statement_index in 0..=data.statements.len() { - let loc = Location { block, statement_index }; - trace!("record conflicts at {:?}", loc); - init.seek_before_primary_effect(loc); - borrowed.seek_before_primary_effect(loc); - record_conflicts_at_curr_loc(&mut local_conflicts, &init, &borrowed); - } + // Locals that are always live or ones that need to be stored across + // suspension points are not eligible for overlap. + let mut ineligible_locals = always_live_locals.into_inner(); + ineligible_locals.intersect(stored_locals); - // ...and then observe the state *after* the terminator effect is applied. As long as - // neither `init` nor `borrowed` has a "before" effect, we will observe all possible - // dataflow states here or in the loop above. - trace!("record conflicts at end of {:?}", block); - init.seek_to_block_end(block); - borrowed.seek_to_block_end(block); - record_conflicts_at_curr_loc(&mut local_conflicts, &init, &borrowed); - } + // Compute the storage conflicts for all eligible locals. + let mut visitor = StorageConflictVisitor { + body, + stored_locals: &stored_locals, + local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), + }; + + // Visit only reachable basic blocks. The exact order is not important. + let reachable_blocks = traversal::preorder(body).map(|(bb, _)| bb); + requires_storage.visit_with(body, reachable_blocks, &mut visitor); + + let local_conflicts = visitor.local_conflicts; // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal). // @@ -653,7 +612,7 @@ fn compute_storage_conflicts( let mut storage_conflicts = BitMatrix::new(stored_locals.count(), stored_locals.count()); for (idx_a, local_a) in stored_locals.iter().enumerate() { let saved_local_a = GeneratorSavedLocal::new(idx_a); - if always_live_locals.contains(local_a) { + if ineligible_locals.contains(local_a) { // Conflicts with everything. storage_conflicts.insert_all_into_row(saved_local_a); } else { @@ -669,6 +628,56 @@ fn compute_storage_conflicts( storage_conflicts } +struct StorageConflictVisitor<'mir, 'tcx, 's> { + body: &'mir Body<'tcx>, + stored_locals: &'s BitSet<Local>, + // FIXME(tmandry): Consider using sparse bitsets here once we have good + // benchmarks for generators. + local_conflicts: BitMatrix<Local, Local>, +} + +impl dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> { + type FlowState = BitSet<Local>; + + fn visit_statement_before_primary_effect( + &mut self, + state: &Self::FlowState, + _statement: &'mir Statement<'tcx>, + loc: Location, + ) { + self.apply_state(state, loc); + } + + fn visit_terminator_before_primary_effect( + &mut self, + state: &Self::FlowState, + _terminator: &'mir Terminator<'tcx>, + loc: Location, + ) { + self.apply_state(state, loc); + } +} + +impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> { + fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) { + // Ignore unreachable blocks. + if self.body.basic_blocks()[loc.block].terminator().kind == TerminatorKind::Unreachable { + return; + } + + let mut eligible_storage_live = flow_state.clone(); + eligible_storage_live.intersect(&self.stored_locals); + + for local in eligible_storage_live.iter() { + self.local_conflicts.union_row_with(&eligible_storage_live, local); + } + + if eligible_storage_live.count() > 1 { + trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live); + } + } +} + /// Validates the typeck view of the generator against the actual set of types retained between /// yield points. fn sanitize_witness<'tcx>( diff --git a/src/librustc_mir/transform/nrvo.rs b/src/librustc_mir/transform/nrvo.rs index ffad1ebea00..1f3d7bb7cc6 100644 --- a/src/librustc_mir/transform/nrvo.rs +++ b/src/librustc_mir/transform/nrvo.rs @@ -111,7 +111,7 @@ fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option<Local> { copied_to_return_place = Some(returned_local); } - return copied_to_return_place; + copied_to_return_place } fn find_local_assigned_to_return_place( @@ -136,7 +136,7 @@ fn find_local_assigned_to_return_place( } } - return None; + None } // If this statement is an assignment of an unprojected local to the return place, diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 2c8ad00fd06..e1311ccd374 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -909,7 +909,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }; match terminator.kind { - TerminatorKind::Call { mut func, mut args, from_hir_call, .. } => { + TerminatorKind::Call { mut func, mut args, from_hir_call, fn_span, .. } => { self.visit_operand(&mut func, loc); for arg in &mut args { self.visit_operand(arg, loc); @@ -925,6 +925,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { cleanup: None, destination: Some((Place::from(new_temp), new_target)), from_hir_call, + fn_span, }, ..terminator }; diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 5c78307d882..4c8fc49099b 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -368,7 +368,14 @@ fn check_terminator( Err((span, "const fn generators are unstable".into())) } - TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => { + TerminatorKind::Call { + func, + args, + from_hir_call: _, + destination: _, + cleanup: _, + fn_span: _, + } => { let fn_ty = func.ty(body, tcx); if let ty::FnDef(def_id, _) = fn_ty.kind { if !crate::const_eval::is_min_const_fn(tcx, def_id) { diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs index 41ffa659441..50136ac3bec 100644 --- a/src/librustc_mir/transform/simplify_try.rs +++ b/src/librustc_mir/transform/simplify_try.rs @@ -99,7 +99,7 @@ fn get_arm_identity_info<'a, 'tcx>(stmts: &'a [Statement<'tcx>]) -> Option<ArmId fn try_eat<'a, 'tcx>( stmt_iter: &mut StmtIter<'a, 'tcx>, test: impl Fn(&'a Statement<'tcx>) -> bool, - mut action: impl FnMut(usize, &'a Statement<'tcx>) -> (), + mut action: impl FnMut(usize, &'a Statement<'tcx>), ) { while stmt_iter.peek().map(|(_, stmt)| test(stmt)).unwrap_or(false) { let (idx, stmt) = stmt_iter.next().unwrap(); @@ -271,7 +271,7 @@ fn optimization_applies<'tcx>( } // Verify the assigment chain consists of the form b = a; c = b; d = c; etc... - if opt_info.field_tmp_assignments.len() == 0 { + if opt_info.field_tmp_assignments.is_empty() { trace!("NO: no assignments found"); } let mut last_assigned_to = opt_info.field_tmp_assignments[0].1; @@ -306,7 +306,11 @@ fn optimization_applies<'tcx>( } impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { - fn run_pass(&self, _: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { + return; + } + trace!("running SimplifyArmIdentity on {:?}", source); let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); for bb in basic_blocks { diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index 1433d39abfb..8150c328316 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -11,6 +11,12 @@ use rustc_middle::{ }; use rustc_span::def_id::DefId; +#[derive(Copy, Clone, Debug)] +enum EdgeKind { + Unwind, + Normal, +} + pub struct Validator { /// Describes at which point in the pipeline this validation is happening. pub when: String, @@ -49,8 +55,31 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - fn check_bb(&self, location: Location, bb: BasicBlock) { - if self.body.basic_blocks().get(bb).is_none() { + fn check_edge(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) { + if let Some(bb) = self.body.basic_blocks().get(bb) { + let src = self.body.basic_blocks().get(location.block).unwrap(); + match (src.is_cleanup, bb.is_cleanup, edge_kind) { + // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges + (false, false, EdgeKind::Normal) + // Non-cleanup blocks can jump to cleanup blocks along unwind edges + | (false, true, EdgeKind::Unwind) + // Cleanup blocks can jump to cleanup blocks along non-unwind edges + | (true, true, EdgeKind::Normal) => {} + // All other jumps are invalid + _ => { + self.fail( + location, + format!( + "{:?} edge to {:?} violates unwind invariants (cleanup {:?} -> {:?})", + edge_kind, + bb, + src.is_cleanup, + bb.is_cleanup, + ) + ) + } + } + } else { self.fail(location, format!("encountered jump to invalid basic block {:?}", bb)) } } @@ -92,7 +121,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { match &terminator.kind { TerminatorKind::Goto { target } => { - self.check_bb(location, *target); + self.check_edge(location, *target, EdgeKind::Normal); } TerminatorKind::SwitchInt { targets, values, .. } => { if targets.len() != values.len() + 1 { @@ -106,19 +135,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } for target in targets { - self.check_bb(location, *target); + self.check_edge(location, *target, EdgeKind::Normal); } } TerminatorKind::Drop { target, unwind, .. } => { - self.check_bb(location, *target); + self.check_edge(location, *target, EdgeKind::Normal); if let Some(unwind) = unwind { - self.check_bb(location, *unwind); + self.check_edge(location, *unwind, EdgeKind::Unwind); } } TerminatorKind::DropAndReplace { target, unwind, .. } => { - self.check_bb(location, *target); + self.check_edge(location, *target, EdgeKind::Normal); if let Some(unwind) = unwind { - self.check_bb(location, *unwind); + self.check_edge(location, *unwind, EdgeKind::Unwind); } } TerminatorKind::Call { func, destination, cleanup, .. } => { @@ -131,10 +160,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ), } if let Some((_, target)) = destination { - self.check_bb(location, *target); + self.check_edge(location, *target, EdgeKind::Normal); } if let Some(cleanup) = cleanup { - self.check_bb(location, *cleanup); + self.check_edge(location, *cleanup, EdgeKind::Unwind); } } TerminatorKind::Assert { cond, target, cleanup, .. } => { @@ -148,30 +177,30 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ), ); } - self.check_bb(location, *target); + self.check_edge(location, *target, EdgeKind::Normal); if let Some(cleanup) = cleanup { - self.check_bb(location, *cleanup); + self.check_edge(location, *cleanup, EdgeKind::Unwind); } } TerminatorKind::Yield { resume, drop, .. } => { - self.check_bb(location, *resume); + self.check_edge(location, *resume, EdgeKind::Normal); if let Some(drop) = drop { - self.check_bb(location, *drop); + self.check_edge(location, *drop, EdgeKind::Normal); } } TerminatorKind::FalseEdge { real_target, imaginary_target } => { - self.check_bb(location, *real_target); - self.check_bb(location, *imaginary_target); + self.check_edge(location, *real_target, EdgeKind::Normal); + self.check_edge(location, *imaginary_target, EdgeKind::Normal); } TerminatorKind::FalseUnwind { real_target, unwind } => { - self.check_bb(location, *real_target); + self.check_edge(location, *real_target, EdgeKind::Normal); if let Some(unwind) = unwind { - self.check_bb(location, *unwind); + self.check_edge(location, *unwind, EdgeKind::Unwind); } } TerminatorKind::InlineAsm { destination, .. } => { if let Some(destination) = destination { - self.check_bb(location, *destination); + self.check_edge(location, *destination, EdgeKind::Normal); } } // Nothing to validate for these. diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 8f27247bfb4..a1345452ca9 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -644,6 +644,7 @@ where destination: Some((unit_temp, succ)), cleanup: unwind.into_option(), from_hir_call: true, + fn_span: self.source_info.span, }, source_info: self.source_info, }), @@ -988,6 +989,7 @@ where destination: Some((unit_temp, target)), cleanup: None, from_hir_call: false, + fn_span: self.source_info.span, }; // FIXME(#43234) let free_block = self.new_block(unwind, call); diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index ff386cb2183..02614044063 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -135,7 +135,7 @@ fn dump_matched_mir_node<'tcx, F>( } writeln!(file)?; extra_data(PassWhere::BeforeCFG, &mut file)?; - write_user_type_annotations(body, &mut file)?; + write_user_type_annotations(tcx, body, &mut file)?; write_mir_fn(tcx, source, body, &mut extra_data, &mut file)?; extra_data(PassWhere::AfterCFG, &mut file)?; }; @@ -351,7 +351,7 @@ fn write_extra<'tcx, F>(tcx: TyCtxt<'tcx>, write: &mut dyn Write, mut visit_op: where F: FnMut(&mut ExtraComments<'tcx>), { - let mut extra_comments = ExtraComments { _tcx: tcx, comments: vec![] }; + let mut extra_comments = ExtraComments { tcx, comments: vec![] }; visit_op(&mut extra_comments); for comment in extra_comments.comments { writeln!(write, "{:A$} // {}", "", comment, A = ALIGN)?; @@ -360,7 +360,7 @@ where } struct ExtraComments<'tcx> { - _tcx: TyCtxt<'tcx>, // don't need it now, but bet we will soon + tcx: TyCtxt<'tcx>, comments: Vec<String>, } @@ -377,7 +377,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { self.super_constant(constant, location); let Constant { span, user_ty, literal } = constant; self.push("mir::Constant"); - self.push(&format!("+ span: {:?}", span)); + self.push(&format!("+ span: {}", self.tcx.sess.source_map().span_to_string(*span))); if let Some(user_ty) = user_ty { self.push(&format!("+ user_ty: {:?}", user_ty)); } @@ -862,12 +862,22 @@ fn write_mir_sig( Ok(()) } -fn write_user_type_annotations(body: &Body<'_>, w: &mut dyn Write) -> io::Result<()> { +fn write_user_type_annotations( + tcx: TyCtxt<'_>, + body: &Body<'_>, + w: &mut dyn Write, +) -> io::Result<()> { if !body.user_type_annotations.is_empty() { writeln!(w, "| User Type Annotations")?; } for (index, annotation) in body.user_type_annotations.iter_enumerated() { - writeln!(w, "| {:?}: {:?} at {:?}", index.index(), annotation.user_ty, annotation.span)?; + writeln!( + w, + "| {:?}: {:?} at {}", + index.index(), + annotation.user_ty, + tcx.sess.source_map().span_to_string(annotation.span) + )?; } if !body.user_type_annotations.is_empty() { writeln!(w, "|")?; diff --git a/src/librustc_mir_build/build/expr/into.rs b/src/librustc_mir_build/build/expr/into.rs index e402b2d1596..0d5bd4c7e61 100644 --- a/src/librustc_mir_build/build/expr/into.rs +++ b/src/librustc_mir_build/build/expr/into.rs @@ -162,7 +162,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); exit_block.unit() } - ExprKind::Call { ty, fun, args, from_hir_call } => { + ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => { let intrinsic = match ty.kind { ty::FnDef(def_id, _) => { let f = ty.fn_sig(this.hir.tcx()); @@ -206,6 +206,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.record_operands_moved(&args); + debug!("into_expr: fn_span={:?}", fn_span); + this.cfg.terminate( block, source_info, @@ -222,6 +224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some((destination, success)) }, from_hir_call, + fn_span }, ); success.unit() @@ -355,8 +358,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { hair::InlineAsmOperand::SymFn { expr } => { mir::InlineAsmOperand::SymFn { value: box this.as_constant(expr) } } - hair::InlineAsmOperand::SymStatic { expr } => { - mir::InlineAsmOperand::SymStatic { value: box this.as_constant(expr) } + hair::InlineAsmOperand::SymStatic { def_id } => { + mir::InlineAsmOperand::SymStatic { def_id } } }) .collect(); diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs index 3b448b0cf27..19948196f25 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/src/librustc_mir_build/build/matches/mod.rs @@ -10,7 +10,7 @@ use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode}; use crate::hair::{self, *}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::{fx::{FxHashMap, FxHashSet}, stack::ensure_sufficient_stack}; use rustc_hir::HirId; use rustc_index::bit_set::BitSet; use rustc_middle::middle::region; @@ -909,30 +909,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { split_or_candidate |= self.simplify_candidate(candidate); } - if split_or_candidate { - // At least one of the candidates has been split into subcandidates. - // We need to change the candidate list to include those. - let mut new_candidates = Vec::new(); + ensure_sufficient_stack(|| { + if split_or_candidate { + // At least one of the candidates has been split into subcandidates. + // We need to change the candidate list to include those. + let mut new_candidates = Vec::new(); - for candidate in candidates { - candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate)); + for candidate in candidates { + candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate)); + } + self.match_simplified_candidates( + span, + start_block, + otherwise_block, + &mut *new_candidates, + fake_borrows, + ); + } else { + self.match_simplified_candidates( + span, + start_block, + otherwise_block, + candidates, + fake_borrows, + ); } - self.match_simplified_candidates( - span, - start_block, - otherwise_block, - &mut *new_candidates, - fake_borrows, - ); - } else { - self.match_simplified_candidates( - span, - start_block, - otherwise_block, - candidates, - fake_borrows, - ); - }; + }); } fn match_simplified_candidates( diff --git a/src/librustc_mir_build/build/matches/simplify.rs b/src/librustc_mir_build/build/matches/simplify.rs index 09543cd1ce4..2917a771a2c 100644 --- a/src/librustc_mir_build/build/matches/simplify.rs +++ b/src/librustc_mir_build/build/matches/simplify.rs @@ -160,13 +160,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ty::Int(ity) => { let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); - let max = truncate(u128::max_value(), size); + let max = truncate(u128::MAX, size); let bias = 1u128 << (size.bits() - 1); (Some((0, max, size)), bias) } ty::Uint(uty) => { let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size(); - let max = truncate(u128::max_value(), size); + let max = truncate(u128::MAX, size); (Some((0, max, size)), 0) } _ => (None, 0), diff --git a/src/librustc_mir_build/build/matches/test.rs b/src/librustc_mir_build/build/matches/test.rs index 74398ca8a40..3e7bfc7d59b 100644 --- a/src/librustc_mir_build/build/matches/test.rs +++ b/src/librustc_mir_build/build/matches/test.rs @@ -443,6 +443,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: Some((eq_result, eq_block)), cleanup: Some(cleanup), from_hir_call: false, + fn_span: source_info.span }, ); diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index d0b35f32122..703f6ef8dc4 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -139,11 +139,11 @@ fn make_mirror_unadjusted<'a, 'tcx>( let kind = match expr.kind { // Here comes the interesting stuff: - hir::ExprKind::MethodCall(_, method_span, ref args) => { + hir::ExprKind::MethodCall(_, method_span, ref args, fn_span) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) let expr = method_callee(cx, expr, method_span, None); let args = args.iter().map(|e| e.to_ref()).collect(); - ExprKind::Call { ty: expr.ty, fun: expr.to_ref(), args, from_hir_call: true } + ExprKind::Call { ty: expr.ty, fun: expr.to_ref(), args, from_hir_call: true, fn_span } } hir::ExprKind::Call(ref fun, ref args) => { @@ -170,6 +170,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( fun: method.to_ref(), args: vec![fun.to_ref(), tupled_args.to_ref()], from_hir_call: true, + fn_span: expr.span, } } else { let adt_data = @@ -215,6 +216,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( fun: fun.to_ref(), args: args.to_ref(), from_hir_call: true, + fn_span: expr.span, } } } @@ -465,25 +467,8 @@ fn make_mirror_unadjusted<'a, 'tcx>( } } - Res::Def(DefKind::Static, id) => { - ty = cx.tcx.static_ptr_ty(id); - let ptr = cx.tcx.create_static_alloc(id); - InlineAsmOperand::SymStatic { - expr: Expr { - ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::StaticRef { - literal: ty::Const::from_scalar( - cx.tcx, - Scalar::Ptr(ptr.into()), - ty, - ), - def_id: id, - }, - } - .to_ref(), - } + Res::Def(DefKind::Static, def_id) => { + InlineAsmOperand::SymStatic { def_id } } _ => { @@ -1024,7 +1009,7 @@ fn overloaded_operator<'a, 'tcx>( args: Vec<ExprRef<'tcx>>, ) -> ExprKind<'tcx> { let fun = method_callee(cx, expr, expr.span, None); - ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false } + ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false, fn_span: expr.span } } fn overloaded_place<'a, 'tcx>( @@ -1060,7 +1045,13 @@ fn overloaded_place<'a, 'tcx>( temp_lifetime, ty: ref_ty, span: expr.span, - kind: ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false }, + kind: ExprKind::Call { + ty: fun.ty, + fun: fun.to_ref(), + args, + from_hir_call: false, + fn_span: expr.span, + }, }; // construct and return a deref wrapper `*foo()` diff --git a/src/librustc_mir_build/hair/mod.rs b/src/librustc_mir_build/hair/mod.rs index c869699bb20..ccff510f2d4 100644 --- a/src/librustc_mir_build/hair/mod.rs +++ b/src/librustc_mir_build/hair/mod.rs @@ -146,6 +146,9 @@ crate enum ExprKind<'tcx> { // Whether this is from a call in HIR, rather than from an overloaded // operator. True for overloaded function call. from_hir_call: bool, + /// This `Span` is the span of the function, without the dot and receiver + /// (e.g. `foo(a, b)` in `x.foo(a, b)` + fn_span: Span, }, Deref { arg: ExprRef<'tcx>, @@ -374,7 +377,7 @@ crate enum InlineAsmOperand<'tcx> { expr: ExprRef<'tcx>, }, SymStatic { - expr: ExprRef<'tcx>, + def_id: DefId, }, } diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 2de6d9fe3d4..dc7d8098e55 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -1519,7 +1519,7 @@ fn all_constructors<'a, 'tcx>( } ty::Uint(uty) => { let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size(); - let max = truncate(u128::max_value(), size); + let max = truncate(u128::MAX, size); vec![make_range(0, max)] } _ => { diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs index 9e3f75fdc07..46b687d76e5 100644 --- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs @@ -80,7 +80,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { - traits::type_marked_structural(self.id, self.span, &self.infcx, ty) + ty.is_structural_eq_shallow(self.infcx.tcx) } fn to_pat( diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index 7e59f06e44a..84b3335a0f6 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -191,7 +191,15 @@ impl<'a> StringReader<'a> { "unterminated block comment" }; let last_bpos = self.pos; - self.fatal_span_(start, last_bpos, msg).raise(); + self.sess + .span_diagnostic + .struct_span_fatal_with_code( + self.mk_sp(start, last_bpos), + msg, + error_code!(E0758), + ) + .emit(); + FatalError.raise(); } if is_doc_comment { @@ -317,7 +325,15 @@ impl<'a> StringReader<'a> { let (lit_kind, mode, prefix_len, postfix_len) = match kind { rustc_lexer::LiteralKind::Char { terminated } => { if !terminated { - self.fatal_span_(start, suffix_start, "unterminated character literal").raise() + self.sess + .span_diagnostic + .struct_span_fatal_with_code( + self.mk_sp(start, suffix_start), + "unterminated character literal", + error_code!(E0762), + ) + .emit(); + FatalError.raise(); } (token::Char, Mode::Char, 1, 1) // ' ' } @@ -393,7 +409,7 @@ impl<'a> StringReader<'a> { let content_end = suffix_start - BytePos(postfix_len); let id = self.symbol_from_to(content_start, content_end); self.validate_literal_escape(mode, content_start, content_end); - return (lit_kind, id); + (lit_kind, id) } pub fn pos(&self) -> BytePos { diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 660a63841bc..8792605c08d 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -936,7 +936,7 @@ impl<'a> Parser<'a> { } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) { // The current token is in the same line as the prior token, not recoverable. } else if [token::Comma, token::Colon].contains(&self.token.kind) - && &self.prev_token.kind == &token::CloseDelim(token::Paren) + && self.prev_token.kind == token::CloseDelim(token::Paren) { // Likely typo: The current token is on a new line and is expected to be // `.`, `;`, `?`, or an operator after a close delimiter token. diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index e0c37284839..49a5c880176 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -639,7 +639,7 @@ impl<'a> Parser<'a> { ExprKind::Index(_, _) => "indexing", ExprKind::Try(_) => "?", ExprKind::Field(_, _) => "a field access", - ExprKind::MethodCall(_, _) => "a method call", + ExprKind::MethodCall(_, _, _) => "a method call", ExprKind::Call(_, _) => "a function call", ExprKind::Await(_) => "`.await`", ExprKind::Err => return Ok(with_postfix), @@ -865,6 +865,7 @@ impl<'a> Parser<'a> { return self.mk_await_expr(self_arg, lo); } + let fn_span_lo = self.token.span; let segment = self.parse_path_segment(PathStyle::Expr)?; self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren)); @@ -873,8 +874,9 @@ impl<'a> Parser<'a> { let mut args = self.parse_paren_expr_seq()?; args.insert(0, self_arg); + let fn_span = fn_span_lo.to(self.prev_token.span); let span = lo.to(self.prev_token.span); - Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args), AttrVec::new())) + Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span), AttrVec::new())) } else { // Field access `expr.f` if let Some(args) = segment.args { diff --git a/src/librustc_parse/parser/generics.rs b/src/librustc_parse/parser/generics.rs index 8e8f864728c..04b64d93c70 100644 --- a/src/librustc_parse/parser/generics.rs +++ b/src/librustc_parse/parser/generics.rs @@ -157,6 +157,7 @@ impl<'a> Parser<'a> { Ok(ast::Generics { params, where_clause: WhereClause { + has_where_token: false, predicates: Vec::new(), span: self.prev_token.span.shrink_to_hi(), }, @@ -170,12 +171,16 @@ impl<'a> Parser<'a> { /// where T : Trait<U, V> + 'b, 'a : 'b /// ``` pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> { - let mut where_clause = - WhereClause { predicates: Vec::new(), span: self.prev_token.span.shrink_to_hi() }; + let mut where_clause = WhereClause { + has_where_token: false, + predicates: Vec::new(), + span: self.prev_token.span.shrink_to_hi(), + }; if !self.eat_keyword(kw::Where) { return Ok(where_clause); } + where_clause.has_where_token = true; let lo = self.prev_token.span; // We are considering adding generics to the `where` keyword as an alternative higher-rank diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index c00b6084829..47ae92c48bd 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -193,7 +193,7 @@ impl TokenCursor { tree, self.stack.len() ); - collecting.buf.push(tree.clone().into()) + collecting.buf.push(tree.clone()) } } @@ -675,7 +675,7 @@ impl<'a> Parser<'a> { // If this was a missing `@` in a binding pattern // bail with a suggestion // https://github.com/rust-lang/rust/issues/72373 - if self.prev_token.is_ident() && &self.token.kind == &token::DotDot { + if self.prev_token.is_ident() && self.token.kind == token::DotDot { let msg = format!( "if you meant to bind the contents of \ the rest of the array pattern into `{}`, use `@`", @@ -1193,7 +1193,7 @@ impl<'a> Parser<'a> { let mut collected_tokens = if let Some(collecting) = self.token_cursor.collecting.take() { collecting.buf } else { - let msg = format!("our vector went away?"); + let msg = "our vector went away?"; debug!("collect_tokens: {}", msg); self.sess.span_diagnostic.delay_span_bug(self.token.span, &msg); // This can happen due to a bad interaction of two unrelated recovery mechanisms diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index b54731d8881..80681c14375 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -37,7 +37,7 @@ fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) Target::Method(MethodKind::Inherent) } } - hir::ImplItemKind::TyAlias(..) | hir::ImplItemKind::OpaqueTy(..) => Target::AssocTy, + hir::ImplItemKind::TyAlias(..) => Target::AssocTy, } } diff --git a/src/librustc_passes/dead.rs b/src/librustc_passes/dead.rs index 1dcf0e7c7a9..503fbb64db8 100644 --- a/src/librustc_passes/dead.rs +++ b/src/librustc_passes/dead.rs @@ -304,7 +304,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { } fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if let TyKind::Def(item_id, _) = ty.kind { + if let TyKind::OpaqueDef(item_id, _) = ty.kind { let item = self.tcx.hir().expect_item(item_id.id); intravisit::walk_item(self, item); } @@ -668,7 +668,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> { } self.visit_nested_body(body_id) } - hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(..) => {} + hir::ImplItemKind::TyAlias(..) => {} } } diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs index 93344e907c3..e2bfcf18edb 100644 --- a/src/librustc_passes/intrinsicck.rs +++ b/src/librustc_passes/intrinsicck.rs @@ -232,7 +232,7 @@ impl ExprVisitor<'tcx> { // size). if let Some((in_expr, Some(in_asm_ty))) = tied_input { if in_asm_ty != asm_ty { - let msg = &format!("incompatible types for asm inout argument"); + let msg = "incompatible types for asm inout argument"; let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg); err.span_label( in_expr.span, diff --git a/src/librustc_passes/layout_test.rs b/src/librustc_passes/layout_test.rs index c0826f8cc60..2419e696596 100644 --- a/src/librustc_passes/layout_test.rs +++ b/src/librustc_passes/layout_test.rs @@ -27,8 +27,7 @@ impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> { ItemKind::TyAlias(..) | ItemKind::Enum(..) | ItemKind::Struct(..) - | ItemKind::Union(..) - | ItemKind::OpaqueTy(..) => { + | ItemKind::Union(..) => { for attr in self.tcx.get_attrs(item_def_id.to_def_id()).iter() { if attr.check_name(sym::rustc_layout) { self.dump_layout_of(item_def_id, item, attr); @@ -83,9 +82,11 @@ impl LayoutTest<'tcx> { } sym::debug => { + let normalized_ty = + self.tcx.normalize_erasing_regions(param_env.with_reveal_all(), ty); self.tcx.sess.span_err( item.span, - &format!("layout_of({:?}) = {:#?}", ty, *ty_layout), + &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout), ); } diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 55978afc594..ff5dabd5418 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -1198,7 +1198,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&f, succ) } - hir::ExprKind::MethodCall(.., ref args) => { + hir::ExprKind::MethodCall(.., ref args, _) => { let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id(); let succ = if self.ir.tcx.is_ty_uninhabited_from( m, diff --git a/src/librustc_passes/reachable.rs b/src/librustc_passes/reachable.rs index cac71b3836c..c9a4428c007 100644 --- a/src/librustc_passes/reachable.rs +++ b/src/librustc_passes/reachable.rs @@ -180,7 +180,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } } } - hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(_) => false, + hir::ImplItemKind::TyAlias(_) => false, } } Some(_) => false, @@ -289,7 +289,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { self.visit_nested_body(body) } } - hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(_) => {} + hir::ImplItemKind::TyAlias(_) => {} }, Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., body, _, _), .. }) => { self.visit_nested_body(body); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index cb896810951..3c1b56a9ef4 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -615,7 +615,6 @@ impl EmbargoVisitor<'tcx> { // public, or are not namespaced at all. DefKind::AssocConst | DefKind::AssocTy - | DefKind::AssocOpaqueTy | DefKind::ConstParam | DefKind::Ctor(_, _) | DefKind::Enum @@ -1302,7 +1301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { return; } } - hir::ExprKind::MethodCall(_, span, _) => { + hir::ExprKind::MethodCall(_, span, _, _) => { // Method calls have to be checked specially. self.span = span; if let Some(def_id) = self.tables.type_dependent_def_id(expr.hir_id) { @@ -1333,11 +1332,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { _ => None, }; let def = def.filter(|(kind, _)| match kind { - DefKind::AssocFn - | DefKind::AssocConst - | DefKind::AssocTy - | DefKind::AssocOpaqueTy - | DefKind::Static => true, + DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static => true, _ => false, }); if let Some((kind, def_id)) = def { @@ -1602,9 +1597,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => { self.access_levels.is_reachable(impl_item_ref.id.hir_id) } - hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(_) => { - false - } + hir::ImplItemKind::TyAlias(_) => false, } }); @@ -1952,9 +1945,6 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { let (check_ty, is_assoc_ty) = match assoc_item_kind { AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false), AssocItemKind::Type => (defaultness.has_value(), true), - // `ty()` for opaque types is the underlying type, - // it's not a part of interface, so we skip it. - AssocItemKind::OpaqueTy => (false, true), }; check.in_assoc_ty = is_assoc_ty; check.generics().predicates(); diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/src/librustc_query_system/dep_graph/dep_node.rs index d8875f8ac64..002b0f9c165 100644 --- a/src/librustc_query_system/dep_graph/dep_node.rs +++ b/src/librustc_query_system/dep_graph/dep_node.rs @@ -91,7 +91,7 @@ impl<K: DepKind> fmt::Debug for DepNode<K> { } pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized { - const CAN_RECONSTRUCT_QUERY_KEY: bool; + fn can_reconstruct_query_key() -> bool; /// This method turns the parameters of a DepNodeConstructor into an opaque /// Fingerprint to be used in DepNode. @@ -108,7 +108,7 @@ pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized { /// This method tries to recover the query key from the given `DepNode`, /// something which is needed when forcing `DepNode`s during red-green /// evaluation. The query system will only call this method if - /// `CAN_RECONSTRUCT_QUERY_KEY` is `true`. + /// `can_reconstruct_query_key()` is `true`. /// It is always valid to return `None` here, in which case incremental /// compilation will treat the query as having changed instead of forcing it. fn recover(tcx: Ctxt, dep_node: &DepNode<Ctxt::DepKind>) -> Option<Self>; @@ -118,7 +118,10 @@ impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T where T: HashStable<Ctxt::StableHashingContext> + fmt::Debug, { - default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + #[inline] + default fn can_reconstruct_query_key() -> bool { + false + } default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint { let mut hcx = tcx.create_stable_hashing_context(); diff --git a/src/librustc_query_system/lib.rs b/src/librustc_query_system/lib.rs index 8e350d3ba26..12450a4ccd3 100644 --- a/src/librustc_query_system/lib.rs +++ b/src/librustc_query_system/lib.rs @@ -4,7 +4,7 @@ #![feature(const_panic)] #![feature(core_intrinsics)] #![feature(hash_raw_entry)] -#![feature(specialization)] // FIXME: min_specialization rejects `default const` +#![feature(min_specialization)] #![feature(stmt_expr_attributes)] #![feature(vec_remove_item)] diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 9ee3d989bf3..e633bd1843e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -95,24 +95,30 @@ impl<'a> Resolver<'a> { } crate fn get_module(&mut self, def_id: DefId) -> Module<'a> { + // If this is a local module, it will be in `module_map`, no need to recalculate it. if let Some(def_id) = def_id.as_local() { return self.module_map[&def_id]; } + // Cache module resolution if let Some(&module) = self.extern_module_map.get(&def_id) { return module; } let (name, parent) = if def_id.index == CRATE_DEF_INDEX { + // This is the crate root (self.cstore().crate_name_untracked(def_id.krate), None) } else { let def_key = self.cstore().def_key(def_id); ( + // This unwrap is safe: crates must always have a name def_key.disambiguated_data.data.get_opt_name().unwrap(), + // This unwrap is safe since we know this isn't the root Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id })), ) }; + // Allocate and return a new module with the information we found let kind = ModuleKind::Def(DefKind::Mod, def_id, name); let module = self.arenas.alloc_module(ModuleData::new( parent, @@ -740,12 +746,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } // These items live in the type namespace. - ItemKind::TyAlias(_, _, _, ref ty) => { - let def_kind = match ty.as_deref().and_then(|ty| ty.kind.opaque_top_hack()) { - None => DefKind::TyAlias, - Some(_) => DefKind::OpaqueTy, - }; - let res = Res::Def(def_kind, self.r.definitions.local_def_id(item.id).to_def_id()); + ItemKind::TyAlias(..) => { + let res = Res::Def( + DefKind::TyAlias, + self.r.definitions.local_def_id(item.id).to_def_id(), + ); self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } @@ -911,8 +916,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { | DefKind::ForeignTy | DefKind::OpaqueTy | DefKind::TraitAlias - | DefKind::AssocTy - | DefKind::AssocOpaqueTy, + | DefKind::AssocTy, _, ) | Res::PrimTy(..) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index cbb2878011c..bd2ce5a72e8 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -629,6 +629,7 @@ impl<'a> Resolver<'a> { &mut self, lookup_ident: Ident, namespace: Namespace, + parent_scope: &ParentScope<'a>, start_module: Module<'a>, crate_name: Ident, filter_fn: FilterFn, @@ -655,7 +656,11 @@ impl<'a> Resolver<'a> { } // collect results based on the filter function - if ident.name == lookup_ident.name && ns == namespace { + // avoid suggesting anything from the same module in which we are resolving + if ident.name == lookup_ident.name + && ns == namespace + && !ptr::eq(in_module, parent_scope.module) + { let res = name_binding.res(); if filter_fn(res) { // create the path @@ -680,7 +685,9 @@ impl<'a> Resolver<'a> { Res::Def(DefKind::Ctor(..), did) => this.parent(did), _ => res.opt_def_id(), }; - candidates.push(ImportSuggestion { did, descr: res.descr(), path }); + if candidates.iter().all(|v: &ImportSuggestion| v.did != did) { + candidates.push(ImportSuggestion { did, descr: res.descr(), path }); + } } } } @@ -722,6 +729,7 @@ impl<'a> Resolver<'a> { &mut self, lookup_ident: Ident, namespace: Namespace, + parent_scope: &ParentScope<'a>, filter_fn: FilterFn, ) -> Vec<ImportSuggestion> where @@ -730,6 +738,7 @@ impl<'a> Resolver<'a> { let mut suggestions = self.lookup_import_candidates_from_module( lookup_ident, namespace, + parent_scope, self.graph_root, Ident::with_dummy_span(kw::Crate), &filter_fn, @@ -754,6 +763,7 @@ impl<'a> Resolver<'a> { suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, namespace, + parent_scope, crate_root, ident, &filter_fn, diff --git a/src/librustc_resolve/imports.rs b/src/librustc_resolve/imports.rs index a1e05d21b58..74a8b7e2f55 100644 --- a/src/librustc_resolve/imports.rs +++ b/src/librustc_resolve/imports.rs @@ -1393,8 +1393,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let is_good_import = binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion(); if is_good_import || binding.is_macro_def() { - let res = binding.res(); - if res != Res::Err { + let res = binding.res().map_id(|id| this.definitions.local_def_id(id)); + if res != def::Res::Err { reexports.push(Export { ident, res, span: binding.span, vis: binding.vis }); } } @@ -1467,7 +1467,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if !reexports.is_empty() { if let Some(def_id) = module.def_id() { - self.r.export_map.insert(def_id, reexports); + // Call to `expect_local` should be fine because current + // code is only called for local modules. + self.r.export_map.insert(def_id.expect_local(), reexports); } } } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 49177906647..7166fef2d13 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -2117,7 +2117,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::Field(ref subexpression, _) => { self.resolve_expr(subexpression, Some(expr)); } - ExprKind::MethodCall(ref segment, ref arguments) => { + ExprKind::MethodCall(ref segment, ref arguments, _) => { let mut arguments = arguments.iter(); self.resolve_expr(arguments.next().unwrap(), Some(expr)); for argument in arguments { diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index b1a1f8725a1..ed7adefcb8c 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -212,7 +212,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { let ident = path.last().unwrap().ident; let candidates = self .r - .lookup_import_candidates(ident, ns, is_expected) + .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected) .drain(..) .filter(|ImportSuggestion { did, .. }| { match (did, res.and_then(|res| res.opt_def_id())) { @@ -223,7 +223,8 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { .collect::<Vec<_>>(); let crate_def_id = DefId::local(CRATE_DEF_INDEX); if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) { - let enum_candidates = self.r.lookup_import_candidates(ident, ns, is_enum_variant); + let enum_candidates = + self.r.lookup_import_candidates(ident, ns, &self.parent_scope, is_enum_variant); let mut enum_candidates = enum_candidates .iter() .map(|suggestion| import_candidate_to_enum_paths(&suggestion)) diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index a3fbb28f22a..5bbf8703f0b 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -258,6 +258,9 @@ enum Elide { Exact(Region), /// Less or more than one lifetime were found, error on unspecified. Error(Vec<ElisionFailureInfo>), + /// Forbid lifetime elision inside of a larger scope where it would be + /// permitted. For example, in let position impl trait. + Forbid, } #[derive(Clone, Debug)] @@ -396,15 +399,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE }; self.with(scope, |_, this| intravisit::walk_item(this, item)); } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => { - // Currently opaque type declarations are just generated from `impl Trait` - // items. Doing anything on this node is irrelevant, as we currently don't need - // it. + hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => { + // Opaque types are visited when we visit the + // `TyKind::OpaqueDef`, so that they have the lifetimes from + // their parent opaque_ty in scope. } hir::ItemKind::TyAlias(_, ref generics) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - impl_trait_fn: None, ref generics, .. - }) | hir::ItemKind::Enum(_, ref generics) | hir::ItemKind::Struct(_, ref generics) | hir::ItemKind::Union(_, ref generics) @@ -557,23 +557,35 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.with(scope, |_, this| this.visit_ty(&mt.ty)); } - hir::TyKind::Def(item_id, lifetimes) => { + hir::TyKind::OpaqueDef(item_id, lifetimes) => { // Resolve the lifetimes in the bounds to the lifetime defs in the generics. // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to // `type MyAnonTy<'b> = impl MyTrait<'b>;` // ^ ^ this gets resolved in the scope of // the opaque_ty generics - let (generics, bounds) = match self.tcx.hir().expect_item(item_id.id).kind { + let opaque_ty = self.tcx.hir().expect_item(item_id.id); + let (generics, bounds) = match opaque_ty.kind { // Named opaque `impl Trait` types are reached via `TyKind::Path`. // This arm is for `impl Trait` in the types of statics, constants and locals. hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => { intravisit::walk_ty(self, ty); + + // Elided lifetimes are not allowed in non-return + // position impl Trait + let scope = Scope::Elision { elide: Elide::Forbid, s: self.scope }; + self.with(scope, |_, this| { + intravisit::walk_item(this, opaque_ty); + }); + return; } // RPIT (return position impl trait) - hir::ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, bounds, .. }) => { - (generics, bounds) - } + hir::ItemKind::OpaqueTy(hir::OpaqueTy { + impl_trait_fn: Some(_), + ref generics, + bounds, + .. + }) => (generics, bounds), ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), }; @@ -797,43 +809,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.visit_ty(ty); }); } - OpaqueTy(bounds) => { - let generics = &impl_item.generics; - let mut index = self.next_early_index(); - let mut next_early_index = index; - debug!("visit_ty: index = {}", index); - let lifetimes = generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::early(&self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } => { - next_early_index += 1; - None - } - GenericParamKind::Const { .. } => { - next_early_index += 1; - None - } - }) - .collect(); - - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: self.scope, - track_lifetime_uses: true, - opaque_type_parent: true, - }; - self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_param_bound(bound); - } - }); - } Const(_, _) => { // Only methods and types support generics. assert!(impl_item.generics.params.is_empty()); @@ -2367,6 +2342,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } break Some(e); } + Elide::Forbid => break None, }; for lifetime_ref in lifetime_refs { self.insert_lifetime(lifetime_ref, lifetime); @@ -2667,8 +2643,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // going to make a fresh name, so we cannot // necessarily replace a single-use lifetime with // `'_`. - Scope::Elision { elide: Elide::Exact(_), .. } => break false, - Scope::Elision { elide: Elide::Error(_), .. } => break false, + Scope::Elision { + elide: Elide::Exact(_) | Elide::Error(_) | Elide::Forbid, .. + } => break false, Scope::ObjectLifetimeDefault { s, .. } => scope = s, } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 00a5d08d6a9..61792e039c7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -878,7 +878,7 @@ pub struct Resolver<'a> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap<LocalDefId, CrateNum>, - export_map: ExportMap<NodeId>, + export_map: ExportMap<LocalDefId>, trait_map: TraitMap<NodeId>, /// A map from nodes to anonymous modules. @@ -1281,18 +1281,7 @@ impl<'a> Resolver<'a> { pub fn into_outputs(self) -> ResolverOutputs { let definitions = self.definitions; let extern_crate_map = self.extern_crate_map; - let export_map = self - .export_map - .into_iter() - .map(|(k, v)| { - ( - k, - v.into_iter() - .map(|e| e.map_id(|id| definitions.node_id_to_hir_id(id))) - .collect(), - ) - }) - .collect(); + let export_map = self.export_map; let trait_map = self .trait_map .into_iter() @@ -1330,18 +1319,7 @@ impl<'a> Resolver<'a> { definitions: self.definitions.clone(), cstore: Box::new(self.cstore().clone()), extern_crate_map: self.extern_crate_map.clone(), - export_map: self - .export_map - .iter() - .map(|(&k, v)| { - ( - k, - v.iter() - .map(|e| e.map_id(|id| self.definitions.node_id_to_hir_id(id))) - .collect(), - ) - }) - .collect(), + export_map: self.export_map.clone(), trait_map: self .trait_map .iter() @@ -2257,7 +2235,8 @@ impl<'a> Resolver<'a> { Res::Def(DefKind::Mod, _) => true, _ => false, }; - let mut candidates = self.lookup_import_candidates(ident, TypeNS, is_mod); + let mut candidates = + self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod); candidates.sort_by_cached_key(|c| { (c.path.segments.len(), pprust::path_to_string(&c.path)) }); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 394d8dc4e11..1b49722355e 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -288,7 +288,8 @@ impl<'a> base::Resolver for Resolver<'a> { // Derives are not included when `invocations` are collected, so we have to add them here. let parent_scope = &ParentScope { derives, ..parent_scope }; - let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?; + let node_id = self.lint_node_id(eager_expansion_root); + let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, node_id, force)?; let span = invoc.span(); invoc_id.set_expn_data(ext.expn_data( @@ -338,6 +339,10 @@ impl<'a> base::Resolver for Resolver<'a> { } } + fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId { + self.definitions.lint_node_id(expn_id) + } + fn has_derive_copy(&self, expn_id: ExpnId) -> bool { self.containers_deriving_copy.contains(&expn_id) } @@ -390,6 +395,7 @@ impl<'a> Resolver<'a> { path: &ast::Path, kind: MacroKind, parent_scope: &ParentScope<'a>, + node_id: NodeId, force: bool, ) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> { let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force) @@ -430,7 +436,7 @@ impl<'a> Resolver<'a> { _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), }; - self.check_stability_and_deprecation(&ext, path); + self.check_stability_and_deprecation(&ext, path, node_id); Ok(if ext.macro_kind() != kind { let expected = kind.descr_expected(); @@ -984,13 +990,17 @@ impl<'a> Resolver<'a> { } } - fn check_stability_and_deprecation(&mut self, ext: &SyntaxExtension, path: &ast::Path) { + fn check_stability_and_deprecation( + &mut self, + ext: &SyntaxExtension, + path: &ast::Path, + node_id: NodeId, + ) { let span = path.span; if let Some(stability) = &ext.stability { if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level { let feature = stability.feature; if !self.active_features.contains(&feature) && !span.allows_unstable(feature) { - let node_id = ast::CRATE_NODE_ID; let lint_buffer = &mut self.lint_buffer; let soft_handler = |lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a5e61ab9ab0..e63e31e03c9 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -20,7 +20,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind as HirDefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir_pretty::{bounds_to_string, generic_params_to_string, ty_to_string}; +use rustc_hir_pretty::{bounds_to_string, fn_to_string, generic_params_to_string, ty_to_string}; use rustc_middle::hir::map::Map; use rustc_middle::span_bug; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; @@ -199,21 +199,23 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { self.dumper.compilation_opts(data); } - fn write_sub_paths(&mut self, path: &'tcx hir::Path<'tcx>) { - for seg in path.segments { + fn write_segments(&mut self, segments: impl IntoIterator<Item = &'tcx hir::PathSegment<'tcx>>) { + for seg in segments { if let Some(data) = self.save_ctxt.get_path_segment_data(seg) { self.dumper.dump_ref(data); } } } + fn write_sub_paths(&mut self, path: &'tcx hir::Path<'tcx>) { + self.write_segments(path.segments) + } + // As write_sub_paths, but does not process the last ident in the path (assuming it // will be processed elsewhere). See note on write_sub_paths about global. fn write_sub_paths_truncated(&mut self, path: &'tcx hir::Path<'tcx>) { - for seg in &path.segments[..path.segments.len() - 1] { - if let Some(data) = self.save_ctxt.get_path_segment_data(seg) { - self.dumper.dump_ref(data); - } + if let [segments @ .., _] = path.segments { + self.write_segments(segments) } } @@ -274,7 +276,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } v.process_generic_params(&generics, &method_data.qualname, hir_id); - method_data.value = crate::make_signature(&sig.decl, &generics); + method_data.value = + fn_to_string(sig.decl, sig.header, Some(ident.name), generics, vis, &[], None); method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt); v.dumper.dump_def(&access_from_vis!(v.save_ctxt, vis, hir_id), method_data); @@ -641,7 +644,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { self.nest_tables(map.local_def_id(item.hir_id), |v| { v.visit_ty(&typ); if let &Some(ref trait_ref) = trait_ref { - v.process_path(trait_ref.hir_ref_id, &trait_ref.path); + v.process_path(trait_ref.hir_ref_id, &hir::QPath::Resolved(None, &trait_ref.path)); } v.process_generic_params(generics, "", item.hir_id); for impl_item in impl_items { @@ -744,7 +747,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - fn dump_path_ref(&mut self, id: hir::HirId, path: &hir::Path<'tcx>) { + fn dump_path_ref(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) { let path_data = self.save_ctxt.get_path_data(id, path); if let Some(path_data) = path_data { self.dumper.dump_ref(path_data); @@ -758,14 +761,30 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - fn process_path(&mut self, id: hir::HirId, path: &'tcx hir::Path<'tcx>) { - if self.span.filter_generated(path.span) { + fn process_path(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) { + let span = match path { + hir::QPath::Resolved(_, path) => path.span, + hir::QPath::TypeRelative(_, segment) => segment.ident.span, + }; + if self.span.filter_generated(span) { return; } self.dump_path_ref(id, path); // Type arguments - for seg in path.segments { + let segments = match path { + hir::QPath::Resolved(ty, path) => { + if let Some(ty) = ty { + self.visit_ty(ty); + } + path.segments + } + hir::QPath::TypeRelative(ty, segment) => { + self.visit_ty(ty); + std::slice::from_ref(*segment) + } + }; + for seg in segments { if let Some(ref generic_args) = seg.args { for arg in generic_args.args { if let hir::GenericArg::Type(ref ty) = arg { @@ -775,7 +794,9 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - self.write_sub_paths_truncated(path); + if let hir::QPath::Resolved(_, path) = path { + self.write_sub_paths_truncated(path); + } } fn process_struct_lit( @@ -929,9 +950,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } for (id, ref path) in collector.collected_paths { - if let hir::QPath::Resolved(_, path) = path { - self.process_path(id, path); - } + self.process_path(id, path); } } @@ -1083,7 +1102,6 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { impl_item.span, ); } - hir::ImplItemKind::OpaqueTy(..) => {} hir::ImplItemKind::TyAlias(ref ty) => { // FIXME: uses of the assoc type should ideally point to this // 'def' and the name here should be a ref to the def in the @@ -1133,7 +1151,10 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { fn process_bounds(&mut self, bounds: hir::GenericBounds<'tcx>) { for bound in bounds { if let hir::GenericBound::Trait(ref trait_ref, _) = *bound { - self.process_path(trait_ref.trait_ref.hir_ref_id, &trait_ref.trait_ref.path) + self.process_path( + trait_ref.trait_ref.hir_ref_id, + &hir::QPath::Resolved(None, &trait_ref.trait_ref.path), + ) } } } @@ -1328,13 +1349,16 @@ impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> { fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { self.process_macro_use(t.span); match t.kind { - hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { + hir::TyKind::Path(ref path) => { if generated_code(t.span) { return; } if let Some(id) = self.lookup_def_id(t.hir_id) { - let sub_span = path.segments.last().unwrap().ident.span; + let sub_span = match path { + hir::QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span, + hir::QPath::TypeRelative(_, segment) => segment.ident.span, + }; let span = self.span_from_span(sub_span); self.dumper.dump_ref(Ref { kind: RefKind::Type, @@ -1343,8 +1367,10 @@ impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> { }); } - self.write_sub_paths_truncated(path); - intravisit::walk_path(self, path); + if let hir::QPath::Resolved(_, path) = path { + self.write_sub_paths_truncated(path); + } + intravisit::walk_qpath(self, path, t.hir_id, t.span); } hir::TyKind::Array(ref ty, ref anon_const) => { self.visit_ty(ty); @@ -1353,6 +1379,10 @@ impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> { v.visit_expr(&map.body(anon_const.body).value) }); } + hir::TyKind::OpaqueDef(item_id, _) => { + let item = self.tcx.hir().item(item_id.id); + self.nest_tables(self.tcx.hir().local_def_id(item_id.id), |v| v.visit_item(item)); + } _ => intravisit::walk_ty(self, t), } } @@ -1373,7 +1403,9 @@ impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> { let res = self.save_ctxt.get_path_res(hir_expr.hir_id); self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *base) } - hir::ExprKind::MethodCall(ref seg, _, args) => self.process_method_call(ex, seg, args), + hir::ExprKind::MethodCall(ref seg, _, args, _) => { + self.process_method_call(ex, seg, args) + } hir::ExprKind::Field(ref sub_ex, _) => { self.visit_expr(&sub_ex); @@ -1430,8 +1462,8 @@ impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> { self.visit_expr(&arm.body); } - fn visit_path(&mut self, p: &'tcx hir::Path<'tcx>, id: hir::HirId) { - self.process_path(id, p); + fn visit_qpath(&mut self, path: &'tcx hir::QPath<'tcx>, id: hir::HirId, _: Span) { + self.process_path(id, path); } fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 8c7731c18e9..12d2c8c7eb9 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -13,11 +13,11 @@ use rustc_ast::ast::{self}; use rustc_ast::util::comments::strip_doc_comment_decoration; use rustc_ast_pretty::pprust::attribute_to_string; use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind as HirDefKind, Res}; +use rustc_hir::def::{DefKind as HirDefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; -use rustc_hir_pretty::ty_to_string; +use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string}; use rustc_middle::hir::map::Map; use rustc_middle::middle::cstore::ExternCrate; use rustc_middle::middle::privacy::AccessLevels; @@ -135,7 +135,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id(); let qualname = format!("::{}", self.tcx.def_path_str(def_id)); match item.kind { - hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { + hir::ForeignItemKind::Fn(ref decl, arg_names, ref generics) => { filter!(self.span_utils, item.ident.span); Some(Data::DefData(Def { @@ -144,7 +144,23 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { span: self.span_from_span(item.ident.span), name: item.ident.to_string(), qualname, - value: make_signature(decl, generics), + value: fn_to_string( + decl, + hir::FnHeader { + // functions in extern block are implicitly unsafe + unsafety: hir::Unsafety::Unsafe, + // functions in extern block cannot be const + constness: hir::Constness::NotConst, + abi: self.tcx.hir().get_foreign_abi(item.hir_id), + // functions in extern block cannot be async + asyncness: hir::IsAsync::NotAsync, + }, + Some(item.ident.name), + generics, + &item.vis, + arg_names, + None, + ), parent: None, children: vec![], decl_id: None, @@ -191,7 +207,15 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { span: self.span_from_span(item.ident.span), name: item.ident.to_string(), qualname, - value: make_signature(&sig.decl, generics), + value: fn_to_string( + sig.decl, + sig.header, + Some(item.ident.name), + generics, + &item.vis, + &[], + None, + ), parent: None, children: vec![], decl_id: None, @@ -268,13 +292,12 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { attributes: lower_attributes(item.attrs.to_vec(), self), })) } - hir::ItemKind::Enum(ref def, _) => { + hir::ItemKind::Enum(ref def, ref generics) => { let name = item.ident.to_string(); let qualname = format!("::{}", self.tcx.def_path_str(def_id)); filter!(self.span_utils, item.ident.span); - let variants_str = - def.variants.iter().map(|v| v.ident.to_string()).collect::<Vec<_>>().join(", "); - let value = format!("{}::{{{}}}", name, variants_str); + let value = + enum_def_to_string(def, generics, item.ident.name, item.span, &item.vis); Some(Data::DefData(Def { kind: DefKind::Enum, id: id_from_def_id(def_id), @@ -534,10 +557,14 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { } } } - hir::ExprKind::Struct(hir::QPath::Resolved(_, path), ..) => { + hir::ExprKind::Struct(qpath, ..) => { + let segment = match qpath { + hir::QPath::Resolved(_, path) => path.segments.last().unwrap(), + hir::QPath::TypeRelative(_, segment) => segment, + }; match self.tables.expr_ty_adjusted(&hir_node).kind { ty::Adt(def, _) if !def.is_enum() => { - let sub_span = path.segments.last().unwrap().ident.span; + let sub_span = segment.ident.span; filter!(self.span_utils, sub_span); let span = self.span_from_span(sub_span); Some(Data::RefData(Ref { @@ -575,12 +602,12 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { ref_id: def_id.or(decl_id).map(id_from_def_id).unwrap_or_else(null_id), })) } - hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => { + hir::ExprKind::Path(ref path) => { self.get_path_data(expr.hir_id, path).map(Data::RefData) } _ => { // FIXME - bug!(); + bug!("invalid expression: {:?}", expr); } } } @@ -627,8 +654,12 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { } } - pub fn get_path_data(&self, id: hir::HirId, path: &hir::Path<'_>) -> Option<Ref> { - path.segments.last().and_then(|seg| { + pub fn get_path_data(&self, id: hir::HirId, path: &hir::QPath<'_>) -> Option<Ref> { + let segment = match path { + hir::QPath::Resolved(_, path) => path.segments.last(), + hir::QPath::TypeRelative(_, segment) => Some(*segment), + }; + segment.and_then(|seg| { self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id)) }) } @@ -667,7 +698,6 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { | HirDefKind::TyAlias | HirDefKind::ForeignTy | HirDefKind::TraitAlias - | HirDefKind::AssocOpaqueTy | HirDefKind::AssocTy | HirDefKind::Trait | HirDefKind::OpaqueTy @@ -677,20 +707,16 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { Res::Def(HirDefKind::ConstParam, def_id) => { Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(def_id) }) } - Res::Def(HirDefKind::Ctor(CtorOf::Struct, ..), def_id) => { - // This is a reference to a tuple struct where the def_id points + Res::Def(HirDefKind::Ctor(_, ..), def_id) => { + // This is a reference to a tuple struct or an enum variant where the def_id points // to an invisible constructor function. That is not a very useful - // def, so adjust to point to the tuple struct itself. + // def, so adjust to point to the tuple struct or enum variant itself. let parent_def_id = self.tcx.parent(def_id).unwrap(); Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(parent_def_id) }) } - Res::Def( - HirDefKind::Static - | HirDefKind::Const - | HirDefKind::AssocConst - | HirDefKind::Ctor(..), - _, - ) => Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(res.def_id()) }), + Res::Def(HirDefKind::Static | HirDefKind::Const | HirDefKind::AssocConst, _) => { + Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(res.def_id()) }) + } Res::Def(HirDefKind::AssocFn, decl_id) => { let def_id = if decl_id.is_local() { let ti = self.tcx.associated_item(decl_id); @@ -840,31 +866,6 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { } } -fn make_signature(decl: &hir::FnDecl<'_>, generics: &hir::Generics<'_>) -> String { - let mut sig = "fn ".to_owned(); - if !generics.params.is_empty() { - sig.push('<'); - sig.push_str( - &generics - .params - .iter() - .map(|param| param.name.ident().to_string()) - .collect::<Vec<_>>() - .join(", "), - ); - sig.push_str("> "); - } - sig.push('('); - sig.push_str(&decl.inputs.iter().map(ty_to_string).collect::<Vec<_>>().join(", ")); - sig.push(')'); - match decl.output { - hir::FnRetTy::DefaultReturn(_) => sig.push_str(" -> ()"), - hir::FnRetTy::Return(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))), - } - - sig -} - // An AST visitor for collecting paths (e.g., the names of structs) and formal // variables (idents) from patterns. struct PathCollector<'l> { @@ -1084,7 +1085,7 @@ fn id_from_hir_id(id: hir::HirId, scx: &SaveContext<'_, '_>) -> rls_data::Id { } fn null_id() -> rls_data::Id { - rls_data::Id { krate: u32::max_value(), index: u32::max_value() } + rls_data::Id { krate: u32::MAX, index: u32::MAX } } fn lower_attributes( diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 6fec5cdba8b..cd2a5deeb2d 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -281,6 +281,22 @@ impl<'hir> Sig for hir::Ty<'hir> { }) } } + hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => { + let nested_ty = ty.make(offset + 1, id, scx)?; + let prefix = format!("<{}>::", nested_ty.text,); + + let name = path_segment_to_string(segment); + let res = scx.get_path_res(id.ok_or("Missing id for Path")?); + let id = id_from_def_id(res.def_id()); + + let start = offset + prefix.len(); + let end = start + name.len(); + Ok(Signature { + text: prefix + &name, + defs: vec![], + refs: vec![SigElement { id, start, end }], + }) + } hir::TyKind::TraitObject(bounds, ..) => { // FIXME recurse into bounds let bounds: Vec<hir::GenericBound<'_>> = bounds @@ -308,11 +324,11 @@ impl<'hir> Sig for hir::Ty<'hir> { let text = format!("[{}; {}]", nested_ty.text, expr); Ok(replace_text(nested_ty, text)) } - hir::TyKind::Typeof(_) - | hir::TyKind::Infer - | hir::TyKind::Def(..) - | hir::TyKind::Path(..) - | hir::TyKind::Err => Err("Ty"), + hir::TyKind::OpaqueDef(item_id, _) => { + let item = scx.tcx.hir().item(item_id.id); + item.make(offset, Some(item_id.id), scx) + } + hir::TyKind::Typeof(_) | hir::TyKind::Infer | hir::TyKind::Err => Err("Ty"), } } } diff --git a/src/librustc_serialize/lib.rs b/src/librustc_serialize/lib.rs index 7261d631a6f..3dc3e783820 100644 --- a/src/librustc_serialize/lib.rs +++ b/src/librustc_serialize/lib.rs @@ -10,7 +10,7 @@ Core encoding and decoding interfaces. test(attr(allow(unused_variables), deny(warnings))) )] #![feature(box_syntax)] -#![feature(specialization)] // FIXME: min_specialization does not work +#![feature(min_specialization)] #![feature(never_type)] #![feature(nll)] #![feature(associated_type_bounds)] diff --git a/src/librustc_serialize/serialize.rs b/src/librustc_serialize/serialize.rs index e80d16bb0c7..29c5737ad89 100644 --- a/src/librustc_serialize/serialize.rs +++ b/src/librustc_serialize/serialize.rs @@ -635,24 +635,6 @@ impl<T> Decodable for PhantomData<T> { } } -impl<'a, T: ?Sized + Encodable> Encodable for &'a T { - fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { - (**self).encode(s) - } -} - -impl<T: ?Sized + Encodable> Encodable for Box<T> { - fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { - (**self).encode(s) - } -} - -impl<T: Decodable> Decodable for Box<T> { - fn decode<D: Decoder>(d: &mut D) -> Result<Box<T>, D::Error> { - Ok(box Decodable::decode(d)?) - } -} - impl<T: Decodable> Decodable for Box<[T]> { fn decode<D: Decoder>(d: &mut D) -> Result<Box<[T]>, D::Error> { let v: Vec<T> = Decodable::decode(d)?; @@ -1008,8 +990,20 @@ impl<T: UseSpecializedDecodable> Decodable for T { // for this exact reason. // May be fixable in a simpler fashion via the // more complex lattice model for specialization. -impl<'a, T: ?Sized + Encodable> UseSpecializedEncodable for &'a T {} -impl<T: ?Sized + Encodable> UseSpecializedEncodable for Box<T> {} -impl<T: Decodable> UseSpecializedDecodable for Box<T> {} +impl<'a, T: ?Sized + Encodable> UseSpecializedEncodable for &'a T { + fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { + (**self).encode(s) + } +} +impl<T: ?Sized + Encodable> UseSpecializedEncodable for Box<T> { + fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { + (**self).encode(s) + } +} +impl<T: Decodable> UseSpecializedDecodable for Box<T> { + fn default_decode<D: Decoder>(d: &mut D) -> Result<Box<T>, D::Error> { + Ok(box Decodable::decode(d)?) + } +} impl<'a, T: Decodable> UseSpecializedDecodable for &'a T {} impl<'a, T: Decodable> UseSpecializedDecodable for &'a [T] {} diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 5bdd7b67723..411a6eecbba 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -1031,7 +1031,7 @@ pub fn get_cmd_lint_options( // HACK: forbid is always specified last, so it can't be overridden. // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is // fixed and `forbid` works as expected. - usize::max_value() + usize::MAX } else { passed_arg_pos }; diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index bb0d6e1a47e..58388bafbed 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -606,6 +606,7 @@ declare_lint_pass! { INLINE_NO_SANITIZE, ASM_SUB_REGISTER, UNSAFE_OP_IN_UNSAFE_FN, + INCOMPLETE_INCLUDE, ] } diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index a38e7f063d7..d22c6ec9d7d 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -996,6 +996,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "make the current crate share its generic instantiations"), show_span: Option<String> = (None, parse_opt_string, [TRACKED], "show spans for compiler debugging (expr|pat|ty)"), + span_debug: bool = (false, parse_bool, [UNTRACKED], + "forward proc_macro::Span's `Debug` impl to `Span`"), // o/w tests have closure@path span_free_formats: bool = (false, parse_bool, [UNTRACKED], "exclude spans when debug-printing compiler state (default: no)"), diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs index 233761dbed7..ddbc95fb1b0 100644 --- a/src/librustc_session/parse.rs +++ b/src/librustc_session/parse.rs @@ -119,7 +119,7 @@ pub struct ParseSess { pub unstable_features: UnstableFeatures, pub config: CrateConfig, pub edition: Edition, - pub missing_fragment_specifiers: Lock<FxHashSet<Span>>, + pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>, /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. pub raw_identifier_spans: Lock<Vec<Span>>, /// Used to determine and report recursive module inclusions. @@ -150,7 +150,7 @@ impl ParseSess { unstable_features: UnstableFeatures::from_environment(), config: FxHashSet::default(), edition: ExpnId::root().expn_data().edition, - missing_fragment_specifiers: Lock::new(FxHashSet::default()), + missing_fragment_specifiers: Default::default(), raw_identifier_spans: Lock::new(Vec::new()), included_mod_stack: Lock::new(vec![]), source_map, diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 048033846a1..06d7d4f14d8 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -441,6 +441,9 @@ impl Session { pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { self.diagnostic().span_note_without_error(sp, msg) } + pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_> { + self.diagnostic().struct_note_without_error(msg) + } pub fn diagnostic(&self) -> &rustc_errors::Handler { &self.parse_sess.span_diagnostic diff --git a/src/librustc_span/def_id.rs b/src/librustc_span/def_id.rs index fad9f2f6130..0a70be1f152 100644 --- a/src/librustc_span/def_id.rs +++ b/src/librustc_span/def_id.rs @@ -133,6 +133,8 @@ impl rustc_serialize::UseSpecializedDecodable for DefIndex {} /// A `DefId` identifies a particular *definition*, by combining a crate /// index and a def index. +/// +/// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] pub struct DefId { pub krate: CrateNum, diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index fbab99b2f8f..96240066834 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -726,10 +726,18 @@ pub fn with_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> f() } +pub fn debug_with_source_map( + span: Span, + f: &mut fmt::Formatter<'_>, + source_map: &SourceMap, +) -> fmt::Result { + write!(f, "{} ({:?})", source_map.span_to_string(span), span.ctxt()) +} + pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result { GLOBALS.with(|globals| { if let Some(source_map) = &*globals.source_map.borrow() { - write!(f, "{}", source_map.span_to_string(span)) + debug_with_source_map(span, f, source_map) } else { f.debug_struct("Span") .field("lo", &span.lo()) @@ -1250,7 +1258,7 @@ impl SourceFile { hasher.finish::<u128>() }; let end_pos = start_pos.to_usize() + src.len(); - assert!(end_pos <= u32::max_value() as usize); + assert!(end_pos <= u32::MAX as usize); let (lines, multibyte_chars, non_narrow_chars) = analyze_source_file::analyze_source_file(&src[..], start_pos); diff --git a/src/librustc_span/source_map.rs b/src/librustc_span/source_map.rs index c33c1dd29cb..4b5bce1db26 100644 --- a/src/librustc_span/source_map.rs +++ b/src/librustc_span/source_map.rs @@ -819,9 +819,7 @@ impl SourceMap { // Disregard indexes that are at the start or end of their spans, they can't fit bigger // characters. - if (!forwards && end_index == usize::min_value()) - || (forwards && start_index == usize::max_value()) - { + if (!forwards && end_index == usize::MIN) || (forwards && start_index == usize::MAX) { debug!("find_width_of_character_at_span: start or end of span, cannot be multibyte"); return 1; } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index d165409696e..fea5880f01e 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -120,6 +120,7 @@ symbols! { abi_unadjusted, abi_vectorcall, abi_x86_interrupt, + abi_avr_interrupt, abort, aborts, address, diff --git a/src/librustc_target/abi/call/avr.rs b/src/librustc_target/abi/call/avr.rs new file mode 100644 index 00000000000..c1f7a1e3af5 --- /dev/null +++ b/src/librustc_target/abi/call/avr.rs @@ -0,0 +1,59 @@ +//! LLVM-frontend specific AVR calling convention implementation. +//! +//! # Current calling convention ABI +//! +//! Inherited from Clang's `clang::DefaultABIInfo` implementation - self described +//! as +//! +//! > the default implementation for ABI specific details. This implementation +//! > provides information which results in +//! > self-consistent and sensible LLVM IR generation, but does not +//! > conform to any particular ABI. +//! > +//! > - Doxygen Doxumentation of `clang::DefaultABIInfo` +//! +//! This calling convention may not match AVR-GCC in all cases. +//! +//! In the future, an AVR-GCC compatible argument classification ABI should be +//! adopted in both Rust and Clang. +//! +//! *NOTE*: Currently, this module implements the same calling convention +//! that clang with AVR currently does - the default, simple, unspecialized +//! ABI implementation available to all targets. This ABI is not +//! binary-compatible with AVR-GCC. Once LLVM [PR46140](https://bugs.llvm.org/show_bug.cgi?id=46140) +//! is completed, this module should be updated to match so that both Clang +//! and Rust emit code to the same AVR-GCC compatible ABI. +//! +//! In particular, both Clang and Rust may not have the same semantics +//! when promoting arguments to indirect references as AVR-GCC. It is important +//! to note that the core AVR ABI implementation within LLVM itself is ABI +//! compatible with AVR-GCC - Rust and AVR-GCC only differ in the small amount +//! of compiler frontend specific calling convention logic implemented here. + +use crate::abi::call::{ArgAbi, FnAbi}; + +fn classify_ret_ty<Ty>(ret: &mut ArgAbi<'_, Ty>) { + if ret.layout.is_aggregate() { + ret.make_indirect(); + } +} + +fn classify_arg_ty<Ty>(arg: &mut ArgAbi<'_, Ty>) { + if arg.layout.is_aggregate() { + arg.make_indirect(); + } +} + +pub fn compute_abi_info<Ty>(fty: &mut FnAbi<'_, Ty>) { + if !fty.ret.is_ignore() { + classify_ret_ty(&mut fty.ret); + } + + for arg in &mut fty.args { + if arg.is_ignore() { + continue; + } + + classify_arg_ty(arg); + } +} diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 0303312d057..8f7e2bba5aa 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -5,6 +5,7 @@ use crate::spec::{self, HasTargetSpec}; mod aarch64; mod amdgpu; mod arm; +mod avr; mod hexagon; mod mips; mod mips64; @@ -525,6 +526,8 @@ pub enum Conv { X86_64Win64, AmdGpuKernel, + AvrInterrupt, + AvrNonBlockingInterrupt, } /// Metadata describing how the arguments to a native function @@ -580,6 +583,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "aarch64" => aarch64::compute_abi_info(cx, self), "amdgpu" => amdgpu::compute_abi_info(cx, self), "arm" => arm::compute_abi_info(cx, self), + "avr" => avr::compute_abi_info(self), "mips" => mips::compute_abi_info(cx, self), "mips64" => mips64::compute_abi_info(cx, self), "powerpc" => powerpc::compute_abi_info(self), diff --git a/src/librustc_target/spec/aarch64_apple_ios.rs b/src/librustc_target/spec/aarch64_apple_ios.rs index eac2c3e6aa4..1447716ca84 100644 --- a/src/librustc_target/spec/aarch64_apple_ios.rs +++ b/src/librustc_target/spec/aarch64_apple_ios.rs @@ -15,7 +15,7 @@ pub fn target() -> TargetResult { target_vendor: "apple".to_string(), linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { - features: "+neon,+fp-armv8,+cyclone".to_string(), + features: "+neon,+fp-armv8,+apple-a7".to_string(), eliminate_frame_pointer: false, max_atomic_width: Some(128), abi_blacklist: super::arm_base::abi_blacklist(), diff --git a/src/librustc_target/spec/aarch64_apple_tvos.rs b/src/librustc_target/spec/aarch64_apple_tvos.rs index f1cd14ffd11..21f660ac8b8 100644 --- a/src/librustc_target/spec/aarch64_apple_tvos.rs +++ b/src/librustc_target/spec/aarch64_apple_tvos.rs @@ -15,7 +15,7 @@ pub fn target() -> TargetResult { target_vendor: "apple".to_string(), linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { - features: "+neon,+fp-armv8,+cyclone".to_string(), + features: "+neon,+fp-armv8,+apple-a7".to_string(), eliminate_frame_pointer: false, max_atomic_width: Some(128), abi_blacklist: super::arm_base::abi_blacklist(), diff --git a/src/librustc_target/spec/abi.rs b/src/librustc_target/spec/abi.rs index 1736063cc5f..a5c874bb4ac 100644 --- a/src/librustc_target/spec/abi.rs +++ b/src/librustc_target/spec/abi.rs @@ -11,6 +11,15 @@ pub enum Abi { // N.B., this ordering MUST match the AbiDatas array below. // (This is ensured by the test indices_are_correct().) + // Multiplatform / generic ABIs + // + // These ABIs come first because every time we add a new ABI, we + // have to re-bless all the hashing tests. These are used in many + // places, so giving them stable values reduces test churn. The + // specific values are meaningless. + Rust = 0, + C = 1, + // Single platform ABIs Cdecl, Stdcall, @@ -25,10 +34,10 @@ pub enum Abi { X86Interrupt, AmdGpuKernel, EfiApi, + AvrInterrupt, + AvrNonBlockingInterrupt, // Multiplatform / generic ABIs - Rust, - C, System, RustIntrinsic, RustCall, @@ -49,6 +58,9 @@ pub struct AbiData { #[allow(non_upper_case_globals)] const AbiDatas: &[AbiData] = &[ + // Cross-platform ABIs + AbiData { abi: Abi::Rust, name: "Rust", generic: true }, + AbiData { abi: Abi::C, name: "C", generic: true }, // Platform-specific ABIs AbiData { abi: Abi::Cdecl, name: "cdecl", generic: false }, AbiData { abi: Abi::Stdcall, name: "stdcall", generic: false }, @@ -63,9 +75,13 @@ const AbiDatas: &[AbiData] = &[ AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt", generic: false }, AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel", generic: false }, AbiData { abi: Abi::EfiApi, name: "efiapi", generic: false }, + AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt", generic: false }, + AbiData { + abi: Abi::AvrNonBlockingInterrupt, + name: "avr-non-blocking-interrupt", + generic: false, + }, // Cross-platform ABIs - AbiData { abi: Abi::Rust, name: "Rust", generic: true }, - AbiData { abi: Abi::C, name: "C", generic: true }, AbiData { abi: Abi::System, name: "system", generic: true }, AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true }, AbiData { abi: Abi::RustCall, name: "rust-call", generic: true }, diff --git a/src/librustc_target/spec/apple_sdk_base.rs b/src/librustc_target/spec/apple_sdk_base.rs index c7cff17b154..b07c2aef1ca 100644 --- a/src/librustc_target/spec/apple_sdk_base.rs +++ b/src/librustc_target/spec/apple_sdk_base.rs @@ -122,7 +122,7 @@ fn target_cpu(arch: Arch) -> String { match arch { Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher Armv7s => "cortex-a9", - Arm64 => "cyclone", + Arm64 => "apple-a7", I386 => "yonah", X86_64 => "core2", X86_64_macabi => "core2", diff --git a/src/librustc_target/spec/avr_unknown_unknown.rs b/src/librustc_target/spec/avr_unknown_unknown.rs new file mode 100644 index 00000000000..f90a8def0aa --- /dev/null +++ b/src/librustc_target/spec/avr_unknown_unknown.rs @@ -0,0 +1,17 @@ +use crate::spec::{LinkerFlavor, Target, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "avr-unknown-unknown".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "16".to_string(), + data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(), + arch: "avr".to_string(), + linker_flavor: LinkerFlavor::Gcc, + target_os: "unknown".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + target_c_int_width: 16.to_string(), + options: super::freestanding_base::opts(), + }) +} diff --git a/src/librustc_target/spec/freestanding_base.rs b/src/librustc_target/spec/freestanding_base.rs new file mode 100644 index 00000000000..5402ea074fa --- /dev/null +++ b/src/librustc_target/spec/freestanding_base.rs @@ -0,0 +1,30 @@ +use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions}; +use std::default::Default; + +pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + + args.insert( + LinkerFlavor::Gcc, + vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + "-Wl,--as-needed".to_string(), + ], + ); + + TargetOptions { + dynamic_linking: false, + executables: true, + linker_is_gnu: true, + has_rpath: false, + pre_link_args: args, + position_independent_executables: false, + ..Default::default() + } +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index f329c8c06cc..29250f21383 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -54,6 +54,7 @@ mod arm_base; mod cloudabi_base; mod dragonfly_base; mod freebsd_base; +mod freestanding_base; mod fuchsia_base; mod haiku_base; mod hermit_base; @@ -579,6 +580,8 @@ supported_targets! { ("aarch64-fuchsia", aarch64_fuchsia), ("x86_64-fuchsia", x86_64_fuchsia), + ("avr-unknown-unknown", avr_unknown_unknown), + ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), ("aarch64-unknown-redox", aarch64_unknown_redox), diff --git a/src/librustc_target/spec/windows_gnu_base.rs b/src/librustc_target/spec/windows_gnu_base.rs index f556bf03f02..680dbbad4b0 100644 --- a/src/librustc_target/spec/windows_gnu_base.rs +++ b/src/librustc_target/spec/windows_gnu_base.rs @@ -17,20 +17,21 @@ pub fn opts() -> TargetOptions { let mut late_link_args = LinkArgs::new(); let mut late_link_args_dynamic = LinkArgs::new(); let mut late_link_args_static = LinkArgs::new(); + // Order of `late_link_args*` was found through trial and error to work with various + // mingw-w64 versions (not tested on the CI). It's expected to change from time to time. late_link_args.insert( LinkerFlavor::Gcc, vec![ + "-lmsvcrt".to_string(), "-lmingwex".to_string(), "-lmingw32".to_string(), - "-lmsvcrt".to_string(), // mingw's msvcrt is a weird hybrid import library and static library. // And it seems that the linker fails to use import symbols from msvcrt // that are required from functions in msvcrt in certain cases. For example // `_fmode` that is used by an implementation of `__p__fmode` in x86_64. - // Listing the library twice seems to fix that, and seems to also be done - // by mingw's gcc (Though not sure if it's done on purpose, or by mistake). + // The library is purposely listed twice to fix that. // - // See https://github.com/rust-lang/rust/pull/47483 + // See https://github.com/rust-lang/rust/pull/47483 for some more details. "-lmsvcrt".to_string(), "-luser32".to_string(), "-lkernel32".to_string(), diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs index 475a33af29c..81974769caf 100644 --- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs +++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs @@ -61,7 +61,8 @@ pub fn target() -> Result<Target, String> { max_atomic_width: Some(64), panic_strategy: PanicStrategy::Unwind, cpu: "x86-64".into(), - features: "+rdrnd,+rdseed".into(), + features: "+rdrnd,+rdseed,+lvi-cfi,+lvi-load-hardening".into(), + llvm_args: vec!["--x86-experimental-lvi-inline-asm-hardening".into()], position_independent_executables: true, pre_link_args: iter::once(( LinkerFlavor::Lld(LldFlavor::Ld), diff --git a/src/librustc_trait_selection/infer.rs b/src/librustc_trait_selection/infer.rs index 66df4fe9511..f244785b49d 100644 --- a/src/librustc_trait_selection/infer.rs +++ b/src/librustc_trait_selection/infer.rs @@ -90,7 +90,7 @@ pub trait InferCtxtBuilderExt<'tcx> { where K: TypeFoldable<'tcx>, R: Debug + TypeFoldable<'tcx>, - Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable; + Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>; } impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { @@ -118,7 +118,7 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> { where K: TypeFoldable<'tcx>, R: Debug + TypeFoldable<'tcx>, - Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable, + Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>, { self.enter_with_canonical( DUMMY_SP, diff --git a/src/librustc_trait_selection/lib.rs b/src/librustc_trait_selection/lib.rs index 044239b047a..ea886cd1f9e 100644 --- a/src/librustc_trait_selection/lib.rs +++ b/src/librustc_trait_selection/lib.rs @@ -16,7 +16,6 @@ #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(or_patterns)] -#![feature(option_zip)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 19caf64c63f..d53a0ec9ef8 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -11,7 +11,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::infer::{self, InferCtxt, InferOk}; use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; -use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config::nightly_options; use rustc_span::Span; @@ -133,9 +133,9 @@ pub trait InferCtxtExt<'tcx> { fn generate_member_constraint( &self, concrete_ty: Ty<'tcx>, - opaque_type_generics: &ty::Generics, opaque_defn: &OpaqueTypeDecl<'tcx>, opaque_type_def_id: DefId, + first_own_region_index: usize, ); /*private*/ @@ -405,7 +405,24 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty); - let opaque_type_generics = tcx.generics_of(def_id); + let first_own_region = match opaque_defn.origin { + hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => { + // We lower + // + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> + // + // into + // + // type foo::<'p0..'pn>::Foo<'q0..'qm> + // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. + // + // For these types we onlt iterate over `'l0..lm` below. + tcx.generics_of(def_id).parent_count + } + // These opaque type inherit all lifetime parameters from their + // parent, so we have to check them all. + hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::Misc => 0, + }; let span = tcx.def_span(def_id); @@ -427,12 +444,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); } if let GenerateMemberConstraints::IfNoStaticBound = mode { - self.generate_member_constraint( - concrete_ty, - opaque_type_generics, - opaque_defn, - def_id, - ); + self.generate_member_constraint(concrete_ty, opaque_defn, def_id, first_own_region); } return; } @@ -445,29 +457,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // `['a]` for the first impl trait and `'b` for the // second. let mut least_region = None; - for param in &opaque_type_generics.params { - match param.kind { - GenericParamDefKind::Lifetime => {} - _ => continue, - } - // Get the value supplied for this region from the substs. - let subst_arg = opaque_defn.substs.region_at(param.index as usize); + for subst_arg in &opaque_defn.substs[first_own_region..] { + let subst_region = match subst_arg.unpack() { + GenericArgKind::Lifetime(r) => r, + GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue, + }; // Compute the least upper bound of it with the other regions. debug!("constrain_opaque_types: least_region={:?}", least_region); - debug!("constrain_opaque_types: subst_arg={:?}", subst_arg); + debug!("constrain_opaque_types: subst_region={:?}", subst_region); match least_region { - None => least_region = Some(subst_arg), + None => least_region = Some(subst_region), Some(lr) => { - if free_region_relations.sub_free_regions(self.tcx, lr, subst_arg) { + if free_region_relations.sub_free_regions(self.tcx, lr, subst_region) { // keep the current least region - } else if free_region_relations.sub_free_regions(self.tcx, subst_arg, lr) { - // switch to `subst_arg` - least_region = Some(subst_arg); + } else if free_region_relations.sub_free_regions(self.tcx, subst_region, lr) { + // switch to `subst_region` + least_region = Some(subst_region); } else { // There are two regions (`lr` and - // `subst_arg`) which are not relatable. We + // `subst_region`) which are not relatable. We // can't find a best choice. Therefore, // instead of creating a single bound like // `'r: 'a` (which is our preferred choice), @@ -476,13 +486,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // regions that appear in the impl trait. // For now, enforce a feature gate outside of async functions. - self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_arg); + self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_region); return self.generate_member_constraint( concrete_ty, - opaque_type_generics, opaque_defn, def_id, + first_own_region, ); } } @@ -494,12 +504,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let GenerateMemberConstraints::IfNoStaticBound = mode { if least_region != tcx.lifetimes.re_static { - self.generate_member_constraint( - concrete_ty, - opaque_type_generics, - opaque_defn, - def_id, - ); + self.generate_member_constraint(concrete_ty, opaque_defn, def_id, first_own_region); } } concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { @@ -518,22 +523,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn generate_member_constraint( &self, concrete_ty: Ty<'tcx>, - opaque_type_generics: &ty::Generics, opaque_defn: &OpaqueTypeDecl<'tcx>, opaque_type_def_id: DefId, + first_own_region: usize, ) { // Create the set of choice regions: each region in the hidden // type can be equal to any of the region parameters of the // opaque type definition. let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new( - opaque_type_generics - .params + opaque_defn.substs[first_own_region..] .iter() - .filter(|param| match param.kind { - GenericParamDefKind::Lifetime => true, - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => false, + .filter_map(|arg| match arg.unpack() { + GenericArgKind::Lifetime(r) => Some(r), + GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, }) - .map(|param| opaque_defn.substs.region_at(param.index as usize)) .chain(std::iter::once(self.tcx.lifetimes.re_static)) .collect(), ); @@ -574,7 +577,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { hir::OpaqueTyOrigin::AsyncFn => return false, // Otherwise, generate the label we'll use in the error message. - hir::OpaqueTyOrigin::TypeAlias + hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::Misc => "impl Trait", }; @@ -1064,21 +1067,10 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { ), origin, ), - _ => (def_scope_default(), hir::OpaqueTyOrigin::TypeAlias), - }, - Some(Node::ImplItem(item)) => match item.kind { - hir::ImplItemKind::OpaqueTy(_) => ( - may_define_opaque_type( - tcx, - self.parent_def_id.expect_local(), - opaque_hir_id, - ), - hir::OpaqueTyOrigin::TypeAlias, - ), - _ => (def_scope_default(), hir::OpaqueTyOrigin::TypeAlias), + _ => (def_scope_default(), hir::OpaqueTyOrigin::Misc), }, _ => bug!( - "expected (impl) item, found {}", + "expected item, found {}", tcx.hir().node_to_string(opaque_hir_id), ), }; diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs index 433e1e46f6b..da945a19185 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/src/librustc_trait_selection/traits/auto_trait.rs @@ -96,7 +96,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { )); match result { - Ok(Some(Vtable::VtableImpl(_))) => { + Ok(Some(ImplSource::ImplSourceUserDefined(_))) => { debug!( "find_auto_trait_generics({:?}): \ manual impl found, bailing out", @@ -304,11 +304,15 @@ impl AutoTraitFinder<'tcx> { let result = select.select(&obligation); match &result { - &Ok(Some(ref vtable)) => { + &Ok(Some(ref impl_source)) => { // If we see an explicit negative impl (e.g., `impl !Send for MyStruct`), // we immediately bail out, since it's impossible for us to continue. - if let Vtable::VtableImpl(VtableImplData { impl_def_id, .. }) = vtable { + if let ImplSource::ImplSourceUserDefined(ImplSourceUserDefinedData { + impl_def_id, + .. + }) = impl_source + { // Blame 'tidy' for the weird bracket placement. if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative { debug!( @@ -320,7 +324,7 @@ impl AutoTraitFinder<'tcx> { } } - let obligations = vtable.clone().nested_obligations().into_iter(); + let obligations = impl_source.clone().nested_obligations().into_iter(); if !self.evaluate_nested_obligations( ty, diff --git a/src/librustc_trait_selection/traits/codegen/mod.rs b/src/librustc_trait_selection/traits/codegen/mod.rs index b2e46bc6da1..cf575d3eca9 100644 --- a/src/librustc_trait_selection/traits/codegen/mod.rs +++ b/src/librustc_trait_selection/traits/codegen/mod.rs @@ -5,14 +5,14 @@ use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::{ - FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable, + FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, }; use rustc_errors::ErrorReported; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, TyCtxt}; -/// Attempts to resolve an obligation to a vtable. The result is -/// a shallow vtable resolution, meaning that we do not +/// Attempts to resolve an obligation to a `ImplSource`. The result is +/// a shallow `ImplSource` resolution, meaning that we do not /// (necessarily) resolve all nested obligations on the impl. Note /// that type check should guarantee to us that all nested /// obligations *could be* resolved if we wanted to. @@ -20,7 +20,7 @@ use rustc_middle::ty::{self, TyCtxt}; pub fn codegen_fulfill_obligation<'tcx>( ty: TyCtxt<'tcx>, (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), -) -> Result<Vtable<'tcx, ()>, ErrorReported> { +) -> Result<ImplSource<'tcx, ()>, ErrorReported> { // Remove any references to regions; this helps improve caching. let trait_ref = ty.erase_regions(&trait_ref); @@ -69,14 +69,14 @@ pub fn codegen_fulfill_obligation<'tcx>( // all nested obligations. This is because they can inform the // inference of the impl's type parameters. let mut fulfill_cx = FulfillmentContext::new(); - let vtable = selection.map(|predicate| { + let impl_source = selection.map(|predicate| { debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); fulfill_cx.register_predicate_obligation(&infcx, predicate); }); - let vtable = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &vtable); + let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source); - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - Ok(vtable) + info!("Cache miss: {:?} => {:?}", trait_ref, impl_source); + Ok(impl_source) }) } diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 1b72a4bf84f..d31e04cffd5 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -1747,24 +1747,41 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { pub fn recursive_type_with_infinite_size_error( tcx: TyCtxt<'tcx>, type_def_id: DefId, -) -> DiagnosticBuilder<'tcx> { + spans: Vec<Span>, +) { assert!(type_def_id.is_local()); let span = tcx.hir().span_if_local(type_def_id).unwrap(); let span = tcx.sess.source_map().guess_head_span(span); - let mut err = struct_span_err!( - tcx.sess, - span, - E0072, - "recursive type `{}` has infinite size", - tcx.def_path_str(type_def_id) - ); + let path = tcx.def_path_str(type_def_id); + let mut err = + struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path); err.span_label(span, "recursive type has infinite size"); - err.help(&format!( - "insert indirection (e.g., a `Box`, `Rc`, or `&`) \ - at some point to make `{}` representable", - tcx.def_path_str(type_def_id) - )); - err + for &span in &spans { + err.span_label(span, "recursive without indirection"); + } + let msg = format!( + "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable", + path, + ); + if spans.len() <= 4 { + err.multipart_suggestion( + &msg, + spans + .iter() + .flat_map(|&span| { + vec![ + (span.shrink_to_lo(), "Box<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ] + .into_iter() + }) + .collect(), + Applicability::HasPlaceholders, + ); + } else { + err.help(&msg); + } + err.emit(); } /// Summarizes information diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 51c62dbb88c..4a08a3426c1 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -334,12 +334,12 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } match self.selcx.select(&trait_obligation) { - Ok(Some(vtable)) => { + Ok(Some(impl_source)) => { debug!( "selecting trait `{:?}` at depth {} yielded Ok(Some)", data, obligation.recursion_depth ); - ProcessResult::Changed(mk_pending(vtable.nested_obligations())) + ProcessResult::Changed(mk_pending(impl_source.nested_obligations())) } Ok(None) => { debug!( diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index 958ba69a826..9ab87e6b6ca 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -38,9 +38,9 @@ use rustc_span::Span; use std::fmt::Debug; pub use self::FulfillmentErrorCode::*; +pub use self::ImplSource::*; pub use self::ObligationCauseCode::*; pub use self::SelectionError::*; -pub use self::Vtable::*; pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; pub use self::coherence::{OrphanCheckErr, OverlapResult}; @@ -60,7 +60,6 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapError; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; pub use self::structural_match::search_for_structural_match_violation; -pub use self::structural_match::type_marked_structural; pub use self::structural_match::NonStructuralMatchTy; pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; @@ -553,6 +552,7 @@ fn type_implements_trait<'tcx>( pub fn provide(providers: &mut ty::query::Providers<'_>) { object_safety::provide(providers); + structural_match::provide(providers); *providers = ty::query::Providers { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 1126480b02a..9492c3c3409 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -11,11 +11,11 @@ use super::PredicateObligation; use super::Selection; use super::SelectionContext; use super::SelectionError; -use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; use super::{ - VtableClosureData, VtableDiscriminantKindData, VtableFnPointerData, VtableGeneratorData, - VtableImplData, + ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, + ImplSourceGeneratorData, ImplSourceUserDefinedData, }; +use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; @@ -25,7 +25,7 @@ use rustc_errors::ErrorReported; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::Subst; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_span::symbol::{sym, Ident}; @@ -974,8 +974,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); let _ = selcx.infcx().commit_if_ok(|_| { - let vtable = match selcx.select(&trait_obligation) { - Ok(Some(vtable)) => vtable, + let impl_source = match selcx.select(&trait_obligation) { + Ok(Some(impl_source)) => impl_source, Ok(None) => { candidate_set.mark_ambiguous(); return Err(()); @@ -987,16 +987,16 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( } }; - let eligible = match &vtable { - super::VtableClosure(_) - | super::VtableGenerator(_) - | super::VtableFnPointer(_) - | super::VtableObject(_) - | super::VtableTraitAlias(_) => { - debug!("assemble_candidates_from_impls: vtable={:?}", vtable); + let eligible = match &impl_source { + super::ImplSourceClosure(_) + | super::ImplSourceGenerator(_) + | super::ImplSourceFnPointer(_) + | super::ImplSourceObject(_) + | super::ImplSourceTraitAlias(_) => { + debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source); true } - super::VtableImpl(impl_data) => { + super::ImplSourceUserDefined(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in // codegen (i.e., projection mode is not "any"), and the @@ -1048,7 +1048,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( } } } - super::VtableDiscriminantKind(..) => { + super::ImplSourceDiscriminantKind(..) => { // While `DiscriminantKind` is automatically implemented for every type, // the concrete discriminant may not be known yet. // @@ -1088,7 +1088,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Error => false, } } - super::VtableParam(..) => { + super::ImplSourceParam(..) => { // This case tell us nothing about the value of an // associated type. Consider: // @@ -1116,18 +1116,18 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // in `assemble_candidates_from_param_env`. false } - super::VtableAutoImpl(..) | super::VtableBuiltin(..) => { + super::ImplSourceAutoImpl(..) | super::ImplSourceBuiltin(..) => { // These traits have no associated types. span_bug!( obligation.cause.span, "Cannot project an associated type from `{:?}`", - vtable + impl_source ); } }; if eligible { - if candidate_set.push_candidate(ProjectionTyCandidate::Select(vtable)) { + if candidate_set.push_candidate(ProjectionTyCandidate::Select(impl_source)) { Ok(()) } else { Err(()) @@ -1152,8 +1152,8 @@ fn confirm_candidate<'cx, 'tcx>( confirm_param_env_candidate(selcx, obligation, poly_projection) } - ProjectionTyCandidate::Select(vtable) => { - confirm_select_candidate(selcx, obligation, obligation_trait_ref, vtable) + ProjectionTyCandidate::Select(impl_source) => { + confirm_select_candidate(selcx, obligation, obligation_trait_ref, impl_source) } } } @@ -1162,26 +1162,29 @@ fn confirm_select_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, obligation_trait_ref: &ty::TraitRef<'tcx>, - vtable: Selection<'tcx>, + impl_source: Selection<'tcx>, ) -> Progress<'tcx> { - match vtable { - super::VtableImpl(data) => confirm_impl_candidate(selcx, obligation, data), - super::VtableGenerator(data) => confirm_generator_candidate(selcx, obligation, data), - super::VtableClosure(data) => confirm_closure_candidate(selcx, obligation, data), - super::VtableFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), - super::VtableDiscriminantKind(data) => { + match impl_source { + super::ImplSourceUserDefined(data) => confirm_impl_candidate(selcx, obligation, data), + super::ImplSourceGenerator(data) => confirm_generator_candidate(selcx, obligation, data), + super::ImplSourceClosure(data) => confirm_closure_candidate(selcx, obligation, data), + super::ImplSourceFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), + super::ImplSourceDiscriminantKind(data) => { confirm_discriminant_kind_candidate(selcx, obligation, data) } - super::VtableObject(_) => confirm_object_candidate(selcx, obligation, obligation_trait_ref), - super::VtableAutoImpl(..) - | super::VtableParam(..) - | super::VtableBuiltin(..) - | super::VtableTraitAlias(..) => { - // we don't create Select candidates with this kind of resolution + super::ImplSourceObject(_) => { + confirm_object_candidate(selcx, obligation, obligation_trait_ref) + } + super::ImplSourceAutoImpl(..) + | super::ImplSourceParam(..) + | super::ImplSourceBuiltin(..) + | super::ImplSourceTraitAlias(..) => + // we don't create Select candidates with this kind of resolution + { span_bug!( obligation.cause.span, "Cannot project an associated type from `{:?}`", - vtable + impl_source ) } } @@ -1255,9 +1258,9 @@ fn confirm_object_candidate<'cx, 'tcx>( fn confirm_generator_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, + impl_source: ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>, ) -> Progress<'tcx> { - let gen_sig = vtable.substs.as_generator().poly_sig(); + let gen_sig = impl_source.substs.as_generator().poly_sig(); let Normalized { value: gen_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -1301,14 +1304,14 @@ fn confirm_generator_candidate<'cx, 'tcx>( }); confirm_param_env_candidate(selcx, obligation, predicate) - .with_addl_obligations(vtable.nested) + .with_addl_obligations(impl_source.nested) .with_addl_obligations(obligations) } fn confirm_discriminant_kind_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - _: VtableDiscriminantKindData, + _: ImplSourceDiscriminantKindData, ) -> Progress<'tcx> { let tcx = selcx.tcx(); @@ -1339,9 +1342,9 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>( fn confirm_fn_pointer_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, + fn_pointer_impl_source: ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, ) -> Progress<'tcx> { - let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); + let fn_type = selcx.infcx().shallow_resolve(fn_pointer_impl_source.fn_ty); let sig = fn_type.fn_sig(selcx.tcx()); let Normalized { value: sig, obligations } = normalize_with_depth( selcx, @@ -1352,16 +1355,16 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>( ); confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) - .with_addl_obligations(fn_pointer_vtable.nested) + .with_addl_obligations(fn_pointer_impl_source.nested) .with_addl_obligations(obligations) } fn confirm_closure_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>, + impl_source: ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, ) -> Progress<'tcx> { - let closure_sig = vtable.substs.as_closure().sig(); + let closure_sig = impl_source.substs.as_closure().sig(); let Normalized { value: closure_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -1376,7 +1379,7 @@ fn confirm_closure_candidate<'cx, 'tcx>( ); confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No) - .with_addl_obligations(vtable.nested) + .with_addl_obligations(impl_source.nested) .with_addl_obligations(obligations) } @@ -1446,11 +1449,11 @@ fn confirm_param_env_candidate<'cx, 'tcx>( fn confirm_impl_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>, + impl_impl_source: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>, ) -> Progress<'tcx> { let tcx = selcx.tcx(); - let VtableImplData { impl_def_id, substs, nested } = impl_vtable; + let ImplSourceUserDefinedData { impl_def_id, substs, nested } = impl_impl_source; let assoc_item_id = obligation.predicate.item_def_id; let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); @@ -1474,12 +1477,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node); - let ty = if let ty::AssocKind::OpaqueTy = assoc_ty.item.kind { - let item_substs = InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); - tcx.mk_opaque(assoc_ty.item.def_id, item_substs) - } else { - tcx.type_of(assoc_ty.item.def_id) - }; + let ty = tcx.type_of(assoc_ty.item.def_id); if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { tcx.sess .delay_span_bug(DUMMY_SP, "impl item and trait item have different parameter counts"); @@ -1512,7 +1510,7 @@ fn assoc_ty_def( // cycle error if the specialization graph is currently being built. let impl_node = specialization_graph::Node::Impl(impl_def_id); for item in impl_node.items(tcx) { - if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy) + if matches!(item.kind, ty::AssocKind::Type) && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) { return Ok(specialization_graph::LeafDef { diff --git a/src/librustc_trait_selection/traits/select/candidate_assembly.rs b/src/librustc_trait_selection/traits/select/candidate_assembly.rs index d42c31a5474..9045451056b 100644 --- a/src/librustc_trait_selection/traits/select/candidate_assembly.rs +++ b/src/librustc_trait_selection/traits/select/candidate_assembly.rs @@ -331,6 +331,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<(), SelectionError<'tcx>> { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); + // Essentially any user-written impl will match with an error type, + // so creating `ImplCandidates` isn't useful. However, we might + // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized) + // This helps us avoid overflow: see issue #72839 + // Since compilation is already guaranteed to fail, this is just + // to try to show the 'nicest' possible errors to the user. + if obligation.references_error() { + return Ok(()); + } + self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/src/librustc_trait_selection/traits/select/confirmation.rs index 65bb9b7cda9..f8d26c06a21 100644 --- a/src/librustc_trait_selection/traits/select/confirmation.rs +++ b/src/librustc_trait_selection/traits/select/confirmation.rs @@ -24,18 +24,19 @@ use crate::traits::OutputTypeParameterMismatch; use crate::traits::Selection; use crate::traits::TraitNotObjectSafe; use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation}; -use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation}; -use crate::traits::{Obligation, ObligationCause}; -use crate::traits::{SelectionError, Unimplemented}; use crate::traits::{ - VtableAutoImpl, VtableBuiltin, VtableClosure, VtableDiscriminantKind, VtableFnPointer, - VtableGenerator, VtableImpl, VtableObject, VtableParam, VtableTraitAlias, + ImplSourceAutoImpl, ImplSourceBuiltin, ImplSourceClosure, ImplSourceDiscriminantKind, + ImplSourceFnPointer, ImplSourceGenerator, ImplSourceObject, ImplSourceParam, + ImplSourceTraitAlias, ImplSourceUserDefined, }; use crate::traits::{ - VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableDiscriminantKindData, - VtableFnPointerData, VtableGeneratorData, VtableImplData, VtableObjectData, - VtableTraitAliasData, + ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, + ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData, + ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceUserDefinedData, }; +use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation}; +use crate::traits::{Obligation, ObligationCause}; +use crate::traits::{SelectionError, Unimplemented}; use super::BuiltinImplConditions; use super::SelectionCandidate::{self, *}; @@ -54,65 +55,67 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match candidate { BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); - Ok(VtableBuiltin(data)) + Ok(ImplSourceBuiltin(data)) } ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param); - Ok(VtableParam(obligations)) + Ok(ImplSourceParam(obligations)) } ImplCandidate(impl_def_id) => { - Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id))) + Ok(ImplSourceUserDefined(self.confirm_impl_candidate(obligation, impl_def_id))) } AutoImplCandidate(trait_def_id) => { let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); - Ok(VtableAutoImpl(data)) + Ok(ImplSourceAutoImpl(data)) } ProjectionCandidate => { self.confirm_projection_candidate(obligation); - Ok(VtableParam(Vec::new())) + Ok(ImplSourceParam(Vec::new())) } ClosureCandidate => { let vtable_closure = self.confirm_closure_candidate(obligation)?; - Ok(VtableClosure(vtable_closure)) + Ok(ImplSourceClosure(vtable_closure)) } GeneratorCandidate => { let vtable_generator = self.confirm_generator_candidate(obligation)?; - Ok(VtableGenerator(vtable_generator)) + Ok(ImplSourceGenerator(vtable_generator)) } FnPointerCandidate => { let data = self.confirm_fn_pointer_candidate(obligation)?; - Ok(VtableFnPointer(data)) + Ok(ImplSourceFnPointer(data)) } - DiscriminantKindCandidate => Ok(VtableDiscriminantKind(VtableDiscriminantKindData)), + DiscriminantKindCandidate => { + Ok(ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData)) + } TraitAliasCandidate(alias_def_id) => { let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); - Ok(VtableTraitAlias(data)) + Ok(ImplSourceTraitAlias(data)) } ObjectCandidate => { let data = self.confirm_object_candidate(obligation); - Ok(VtableObject(data)) + Ok(ImplSourceObject(data)) } BuiltinObjectCandidate => { // This indicates something like `Trait + Send: Send`. In this case, we know that // this holds because that's what the object type is telling us, and there's really // no additional obligations to prove and no types in particular to unify, etc. - Ok(VtableParam(Vec::new())) + Ok(ImplSourceParam(Vec::new())) } BuiltinUnsizeCandidate => { let data = self.confirm_builtin_unsize_candidate(obligation)?; - Ok(VtableBuiltin(data)) + Ok(ImplSourceBuiltin(data)) } } } @@ -152,7 +155,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, has_nested: bool, - ) -> VtableBuiltinData<PredicateObligation<'tcx>> { + ) -> ImplSourceBuiltinData<PredicateObligation<'tcx>> { debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested); let lang_items = self.tcx().lang_items(); @@ -188,7 +191,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("confirm_builtin_candidate: obligations={:?}", obligations); - VtableBuiltinData { nested: obligations } + ImplSourceBuiltinData { nested: obligations } } /// This handles the case where a `auto trait Foo` impl is being used. @@ -200,7 +203,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, trait_def_id: DefId, - ) -> VtableAutoImplData<PredicateObligation<'tcx>> { + ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> { debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); let types = obligation.predicate.map_bound(|inner| { @@ -216,7 +219,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, trait_def_id: DefId, nested: ty::Binder<Vec<Ty<'tcx>>>, - ) -> VtableAutoImplData<PredicateObligation<'tcx>> { + ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> { debug!("vtable_auto_impl: nested={:?}", nested); ensure_sufficient_stack(|| { let cause = obligation.derived_cause(BuiltinDerivedObligation); @@ -249,7 +252,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("vtable_auto_impl: obligations={:?}", obligations); - VtableAutoImplData { trait_def_id, nested: obligations } + ImplSourceAutoImplData { trait_def_id, nested: obligations } }) } @@ -257,7 +260,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, impl_def_id: DefId, - ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { + ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id); // First, create the substitutions by matching the impl again, @@ -285,7 +288,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause: ObligationCause<'tcx>, recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, - ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { + ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { debug!( "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})", impl_def_id, substs, recursion_depth, @@ -311,13 +314,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V` impl_obligations.append(&mut substs.obligations); - VtableImplData { impl_def_id, substs: substs.value, nested: impl_obligations } + ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: impl_obligations } } fn confirm_object_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> VtableObjectData<'tcx, PredicateObligation<'tcx>> { + ) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> { debug!("confirm_object_candidate({:?})", obligation); // FIXME(nmatsakis) skipping binder here seems wrong -- we should @@ -366,13 +369,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum(); } - VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested } + ImplSourceObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested } } fn confirm_fn_pointer_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { + ) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> + { debug!("confirm_fn_pointer_candidate({:?})", obligation); // Okay to skip binder; it is reintroduced below. @@ -403,14 +407,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.predicate.to_poly_trait_ref(), trait_ref, )?; - Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations }) + Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested: obligations }) } fn confirm_trait_alias_candidate( &mut self, obligation: &TraitObligation<'tcx>, alias_def_id: DefId, - ) -> VtableTraitAliasData<'tcx, PredicateObligation<'tcx>> { + ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> { debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id); self.infcx.commit_unconditionally(|_| { @@ -433,14 +437,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_def_id, trait_obligations ); - VtableTraitAliasData { alias_def_id, substs, nested: trait_obligations } + ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations } }) } fn confirm_generator_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { + ) -> Result<ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> + { // Okay to skip binder because the substs on generator types never // touch bound regions, they just capture the in-scope // type/region parameters. @@ -476,13 +481,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_ref, )?); - Ok(VtableGeneratorData { generator_def_id, substs, nested: obligations }) + Ok(ImplSourceGeneratorData { generator_def_id, substs, nested: obligations }) } fn confirm_closure_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { + ) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { debug!("confirm_closure_candidate({:?})", obligation); let kind = self @@ -533,7 +538,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { )); } - Ok(VtableClosureData { closure_def_id, substs, nested: obligations }) + Ok(ImplSourceClosureData { closure_def_id, substs, nested: obligations }) } /// In the case of closure types and fn pointers, @@ -578,7 +583,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_builtin_unsize_candidate( &mut self, obligation: &TraitObligation<'tcx>, - ) -> Result<VtableBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { let tcx = self.tcx(); // `assemble_candidates_for_unsizing` should ensure there are no late-bound @@ -815,6 +820,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!(), }; - Ok(VtableBuiltinData { nested }) + Ok(ImplSourceBuiltinData { nested }) } } diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index def99a7b5b5..7ebf30f61c0 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -1104,6 +1104,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // who might care about this case, like coherence, should use // that function). if candidates.is_empty() { + // If there's an error type, 'downgrade' our result from + // `Err(Unimplemented)` to `Ok(None)`. This helps us avoid + // emitting additional spurious errors, since we're guaranteed + // to have emitted at least one. + if stack.obligation.references_error() { + debug!("no results for error type, treating as ambiguous"); + return Ok(None); + } return Err(Unimplemented); } diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index b877049fcf6..e59fbd313c8 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -1,10 +1,11 @@ use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::ObligationCause; -use crate::traits::{self, ConstPatternStructural, TraitEngine}; +use crate::traits::{self, TraitEngine}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::lang_items::{StructuralPeqTraitLangItem, StructuralTeqTraitLangItem}; +use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_span::Span; @@ -45,14 +46,14 @@ pub enum NonStructuralMatchTy<'tcx> { /// that arose when the requirement was not enforced completely, see /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307. pub fn search_for_structural_match_violation<'tcx>( - id: hir::HirId, + _id: hir::HirId, span: Span, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, ) -> Option<NonStructuralMatchTy<'tcx>> { // FIXME: we should instead pass in an `infcx` from the outside. tcx.infer_ctxt().enter(|infcx| { - let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() }; + let mut search = Search { infcx, span, found: None, seen: FxHashSet::default() }; ty.visit_with(&mut search); search.found }) @@ -65,27 +66,26 @@ pub fn search_for_structural_match_violation<'tcx>( /// /// Note that this does *not* recursively check if the substructure of `adt_ty` /// implements the traits. -pub fn type_marked_structural( - id: hir::HirId, - span: Span, +fn type_marked_structural( infcx: &InferCtxt<'_, 'tcx>, adt_ty: Ty<'tcx>, + cause: ObligationCause<'tcx>, ) -> bool { let mut fulfillment_cx = traits::FulfillmentContext::new(); - let cause = ObligationCause::new(span, id, ConstPatternStructural); // require `#[derive(PartialEq)]` - let structural_peq_def_id = infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(span)); + let structural_peq_def_id = + infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(cause.span)); fulfillment_cx.register_bound( infcx, ty::ParamEnv::empty(), adt_ty, structural_peq_def_id, - cause, + cause.clone(), ); // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.) - let cause = ObligationCause::new(span, id, ConstPatternStructural); - let structural_teq_def_id = infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(span)); + let structural_teq_def_id = + infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(cause.span)); fulfillment_cx.register_bound( infcx, ty::ParamEnv::empty(), @@ -110,7 +110,6 @@ pub fn type_marked_structural( /// find instances of ADTs (specifically structs or enums) that do not implement /// the structural-match traits (`StructuralPartialEq` and `StructuralEq`). struct Search<'a, 'tcx> { - id: hir::HirId, span: Span, infcx: InferCtxt<'a, 'tcx>, @@ -129,7 +128,7 @@ impl Search<'a, 'tcx> { } fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool { - type_marked_structural(self.id, self.span, &self.infcx, adt_ty) + adt_ty.is_structural_eq_shallow(self.tcx()) } } @@ -251,7 +250,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { // fields of ADT. let tcx = self.tcx(); for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) { - if field_ty.visit_with(self) { + let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); + debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); + + if ty.visit_with(self) { // found an ADT without structural-match; halt visiting! assert!(self.found.is_some()); return true; @@ -263,3 +265,12 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { false } } + +pub fn provide(providers: &mut Providers<'_>) { + providers.has_structural_eq_impls = |tcx, ty| { + tcx.infer_ctxt().enter(|infcx| { + let cause = ObligationCause::dummy(); + type_marked_structural(&infcx, ty, cause) + }) + }; +} diff --git a/src/librustc_trait_selection/traits/util.rs b/src/librustc_trait_selection/traits/util.rs index f6f0c62c120..8b5b4128e66 100644 --- a/src/librustc_trait_selection/traits/util.rs +++ b/src/librustc_trait_selection/traits/util.rs @@ -297,7 +297,7 @@ pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<' /// `object.upcast_trait_ref`) within the vtable for `object`. pub fn get_vtable_index_of_object_method<N>( tcx: TyCtxt<'tcx>, - object: &super::VtableObjectData<'tcx, N>, + object: &super::ImplSourceObjectData<'tcx, N>, method_def_id: DefId, ) -> usize { // Count number of methods preceding the one we are selecting and diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs index a793031d402..0acf7691681 100644 --- a/src/librustc_ty/instance.rs +++ b/src/librustc_ty/instance.rs @@ -84,9 +84,9 @@ fn resolve_associated_item<'tcx>( // Now that we know which impl is being used, we can dispatch to // the actual function: Ok(match vtbl { - traits::VtableImpl(impl_data) => { + traits::ImplSourceUserDefined(impl_data) => { debug!( - "resolving VtableImpl: {:?}, {:?}, {:?}, {:?}", + "resolving ImplSourceUserDefined: {:?}, {:?}, {:?}, {:?}", param_env, trait_item, rcvr_substs, impl_data ); assert!(!rcvr_substs.needs_infer()); @@ -181,11 +181,11 @@ fn resolve_associated_item<'tcx>( Some(ty::Instance::new(leaf_def.item.def_id, substs)) } - traits::VtableGenerator(generator_data) => Some(Instance { + traits::ImplSourceGenerator(generator_data) => Some(Instance { def: ty::InstanceDef::Item(generator_data.generator_def_id), substs: generator_data.substs, }), - traits::VtableClosure(closure_data) => { + traits::ImplSourceClosure(closure_data) => { let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); Some(Instance::resolve_closure( tcx, @@ -194,7 +194,7 @@ fn resolve_associated_item<'tcx>( trait_closure_kind, )) } - traits::VtableFnPointer(ref data) => { + traits::ImplSourceFnPointer(ref data) => { // `FnPtrShim` requires a monomorphic aka concrete type. if data.fn_ty.needs_subst() { return Ok(None); @@ -205,11 +205,11 @@ fn resolve_associated_item<'tcx>( substs: rcvr_substs, }) } - traits::VtableObject(ref data) => { + traits::ImplSourceObject(ref data) => { let index = traits::get_vtable_index_of_object_method(tcx, data, def_id); Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) } - traits::VtableBuiltin(..) => { + traits::ImplSourceBuiltin(..) => { if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() { // FIXME(eddyb) use lang items for methods instead of names. let name = tcx.item_name(def_id); @@ -236,10 +236,10 @@ fn resolve_associated_item<'tcx>( None } } - traits::VtableAutoImpl(..) - | traits::VtableParam(..) - | traits::VtableTraitAlias(..) - | traits::VtableDiscriminantKind(..) => None, + traits::ImplSourceAutoImpl(..) + | traits::ImplSourceParam(..) + | traits::ImplSourceTraitAlias(..) + | traits::ImplSourceDiscriminantKind(..) => None, }) } diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index 3da5da2d9ef..99094246a63 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -85,7 +85,6 @@ fn associated_item_from_trait_item_ref( hir::AssocItemKind::Const => (ty::AssocKind::Const, false), hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), hir::AssocItemKind::Type => (ty::AssocKind::Type, false), - hir::AssocItemKind::OpaqueTy => bug!("only impls can have opaque types"), }; ty::AssocItem { @@ -110,7 +109,6 @@ fn associated_item_from_impl_item_ref( hir::AssocItemKind::Const => (ty::AssocKind::Const, false), hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), hir::AssocItemKind::Type => (ty::AssocKind::Type, false), - hir::AssocItemKind::OpaqueTy => (ty::AssocKind::OpaqueTy, false), }; ty::AssocItem { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f1dc7e53906..267f3d9f3ef 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -2838,9 +2838,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself)); self.res_to_ty(opt_self_ty, path, false) } - hir::TyKind::Def(item_id, ref lifetimes) => { - let did = tcx.hir().local_def_id(item_id.id); - self.impl_trait_ty_to_ty(did.to_def_id(), lifetimes) + hir::TyKind::OpaqueDef(item_id, ref lifetimes) => { + let opaque_ty = tcx.hir().expect_item(item_id.id); + let def_id = tcx.hir().local_def_id(item_id.id).to_def_id(); + + match opaque_ty.kind { + hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => { + self.impl_trait_ty_to_ty(def_id, lifetimes, impl_trait_fn.is_some()) + } + ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), + } } hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); @@ -2893,6 +2900,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, def_id: DefId, lifetimes: &[hir::GenericArg<'_>], + replace_parent_lifetimes: bool, ) -> Ty<'tcx> { debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes); let tcx = self.tcx(); @@ -2914,9 +2922,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { _ => bug!(), } } else { - // Replace all parent lifetimes with `'static`. match param.kind { - GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), + // For RPIT (return position impl trait), only lifetimes + // mentioned in the impl Trait predicate are captured by + // the opaque type, so the lifetime parameters from the + // parent item need to be replaced with `'static`. + // + // For `impl Trait` in the types of statics, constants, + // locals and type aliases. These capture all parent + // lifetimes, so they can use their identity subst. + GenericParamDefKind::Lifetime if replace_parent_lifetimes => { + tcx.lifetimes.re_static.into() + } _ => tcx.mk_param_from_def(param), } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a324bd03eca..15ec92568fb 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -657,7 +657,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // be silent, as it causes a type mismatch later. } - Ok(Some(vtable)) => queue.extend(vtable.nested_obligations()), + Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), } } @@ -1377,7 +1377,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } if let Some(expr) = expression { - fcx.emit_coerce_suggestions(&mut err, expr, found, expected); + fcx.emit_coerce_suggestions(&mut err, expr, found, expected, None); } // Error possibly reported in `check_assign` so avoid emitting error again. @@ -1494,7 +1494,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let mut is_object_safe = false; if let hir::FnRetTy::Return(ty) = fn_output { // Get the return type. - if let hir::TyKind::Def(..) = ty.kind { + if let hir::TyKind::OpaqueDef(..) = ty.kind { let ty = AstConv::ast_ty_to_ty(fcx, ty); // Get the `impl Trait`'s `DefId`. if let ty::Opaque(def_id, _) = ty.kind { diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 29cd9681295..5f8fcaadfdb 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -1165,6 +1165,6 @@ fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { match impl_item.kind { ty::AssocKind::Const => "const", ty::AssocKind::Fn => "method", - ty::AssocKind::Type | ty::AssocKind::OpaqueTy => "type", + ty::AssocKind::Type => "type", } } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 700b9359d06..019b4ca6606 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -15,6 +15,8 @@ use rustc_span::Span; use super::method::probe; +use std::fmt; + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn emit_coerce_suggestions( &self, @@ -22,10 +24,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) { self.annotate_expected_due_to_let_ty(err, expr); self.suggest_compatible_variants(err, expr, expected, expr_ty); - self.suggest_deref_ref_or_into(err, expr, expected, expr_ty); + self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr); if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) { return; } @@ -100,9 +103,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> Ty<'tcx> { - let (ty, err) = self.demand_coerce_diag(expr, checked_ty, expected, allow_two_phase); + let (ty, err) = + self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase); if let Some(mut err) = err { err.emit(); } @@ -119,6 +124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) { let expected = self.resolve_vars_with_obligations(expected); @@ -139,7 +145,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return (expected, None); } - self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected); + self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr); (expected, Some(err)) } @@ -305,7 +311,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (method_path, method_span, method_expr) = match (hir, closure_params_len) { ( Some(Node::Expr(hir::Expr { - kind: hir::ExprKind::MethodCall(path, span, expr), + kind: hir::ExprKind::MethodCall(path, span, expr, _), .. })), 1, @@ -455,7 +461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if self.can_coerce(ref_ty, expected) { let mut sugg_sp = sp; - if let hir::ExprKind::MethodCall(ref segment, sp, ref args) = expr.kind { + if let hir::ExprKind::MethodCall(ref segment, sp, ref args, _) = expr.kind { let clone_trait = self.tcx.require_lang_item(CloneTraitLangItem, Some(sp)); if let ([arg], Some(true), sym::clone) = ( &args[..], @@ -669,17 +675,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool { - if self.tcx.hir().is_const_context(expr.hir_id) { - // Shouldn't suggest `.into()` on `const`s. - // FIXME(estebank): modify once we decide to suggest `as` casts - return false; - } if self.tcx.sess.source_map().is_imported(expr.span) { // Ignore if span is from within a macro. return false; } + let src = if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) { + src + } else { + return false; + }; + // If casting this expression to a given numeric type would be appropriate in case of a type // mismatch. // @@ -708,6 +716,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { String::new() }; + if let hir::ExprKind::Call(path, args) = &expr.kind { if let (hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), 1) = (&path.kind, args.len()) @@ -743,228 +752,250 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = format!("you can convert an `{}` to `{}`", checked_ty, expected_ty); let cast_msg = format!("you can cast an `{} to `{}`", checked_ty, expected_ty); - let try_msg = format!("{} and panic if the converted value wouldn't fit", msg); let lit_msg = format!( "change the type of the numeric literal from `{}` to `{}`", checked_ty, expected_ty, ); - let needs_paren = expr.precedence().order() < (PREC_POSTFIX as i8); - - if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) { - let cast_suggestion = format!( - "{}{}{}{} as {}", - prefix, - if needs_paren { "(" } else { "" }, - src, - if needs_paren { ")" } else { "" }, - expected_ty, - ); - let try_into_suggestion = format!( - "{}{}{}{}.try_into().unwrap()", - prefix, - if needs_paren { "(" } else { "" }, - src, - if needs_paren { ")" } else { "" }, - ); - let into_suggestion = format!( - "{}{}{}{}.into()", - prefix, - if needs_paren { "(" } else { "" }, - src, - if needs_paren { ")" } else { "" }, - ); - let suffix_suggestion = format!( - "{}{}{}{}", - if needs_paren { "(" } else { "" }, - if let (ty::Int(_) | ty::Uint(_), ty::Float(_)) = - (&expected_ty.kind, &checked_ty.kind,) + let with_opt_paren: fn(&dyn fmt::Display) -> String = + if expr.precedence().order() < PREC_POSTFIX { + |s| format!("({})", s) + } else { + |s| s.to_string() + }; + + let cast_suggestion = format!("{}{} as {}", prefix, with_opt_paren(&src), expected_ty); + let into_suggestion = format!("{}{}.into()", prefix, with_opt_paren(&src)); + let suffix_suggestion = with_opt_paren(&format_args!( + "{}{}", + if matches!( + (&expected_ty.kind, &checked_ty.kind), + (ty::Int(_) | ty::Uint(_), ty::Float(_)) + ) { + // Remove fractional part from literal, for example `42.0f32` into `42` + let src = src.trim_end_matches(&checked_ty.to_string()); + src.split('.').next().unwrap() + } else { + src.trim_end_matches(&checked_ty.to_string()) + }, + expected_ty, + )); + let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| { + if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false } + }; + + let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id); + + let suggest_fallible_into_or_lhs_from = + |err: &mut DiagnosticBuilder<'_>, exp_to_found_is_fallible: bool| { + // If we know the expression the expected type is derived from, we might be able + // to suggest a widening conversion rather than a narrowing one (which may + // panic). For example, given x: u8 and y: u32, if we know the span of "x", + // x > y + // can be given the suggestion "u32::from(x) > y" rather than + // "x > y.try_into().unwrap()". + let lhs_expr_and_src = expected_ty_expr.and_then(|expr| { + match self.tcx.sess.source_map().span_to_snippet(expr.span).ok() { + Some(src) => Some((expr, src)), + None => None, + } + }); + let (span, msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) = + (lhs_expr_and_src, exp_to_found_is_fallible) { - // Remove fractional part from literal, for example `42.0f32` into `42` - let src = src.trim_end_matches(&checked_ty.to_string()); - src.split('.').next().unwrap() + let msg = format!( + "you can convert `{}` from `{}` to `{}`, matching the type of `{}`", + lhs_src, expected_ty, checked_ty, src + ); + let suggestion = format!("{}::from({})", checked_ty, lhs_src,); + (lhs_expr.span, msg, suggestion) } else { - src.trim_end_matches(&checked_ty.to_string()) - }, - expected_ty, - if needs_paren { ")" } else { "" }, - ); - let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| { - if let hir::ExprKind::Lit(lit) = &expr.kind { - lit.node.is_suffixed() + let msg = format!("{} and panic if the converted value wouldn't fit", msg); + let suggestion = + format!("{}{}.try_into().unwrap()", prefix, with_opt_paren(&src)); + (expr.span, msg, suggestion) + }; + err.span_suggestion(span, &msg, suggestion, Applicability::MachineApplicable); + }; + + let suggest_to_change_suffix_or_into = + |err: &mut DiagnosticBuilder<'_>, + found_to_exp_is_fallible: bool, + exp_to_found_is_fallible: bool| { + let msg = if literal_is_ty_suffixed(expr) { + &lit_msg + } else if in_const_context { + // Do not recommend `into` or `try_into` in const contexts. + return; + } else if found_to_exp_is_fallible { + return suggest_fallible_into_or_lhs_from(err, exp_to_found_is_fallible); } else { - false - } + &msg + }; + let suggestion = if literal_is_ty_suffixed(expr) { + suffix_suggestion.clone() + } else { + into_suggestion.clone() + }; + err.span_suggestion(expr.span, msg, suggestion, Applicability::MachineApplicable); }; - let suggest_to_change_suffix_or_into = - |err: &mut DiagnosticBuilder<'_>, is_fallible: bool| { + match (&expected_ty.kind, &checked_ty.kind) { + (&ty::Int(ref exp), &ty::Int(ref found)) => { + let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) + { + (Some(exp), Some(found)) if exp < found => (true, false), + (Some(exp), Some(found)) if exp > found => (false, true), + (None, Some(8 | 16)) => (false, true), + (Some(8 | 16), None) => (true, false), + (None, _) | (_, None) => (true, true), + _ => (false, false), + }; + suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); + true + } + (&ty::Uint(ref exp), &ty::Uint(ref found)) => { + let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) + { + (Some(exp), Some(found)) if exp < found => (true, false), + (Some(exp), Some(found)) if exp > found => (false, true), + (None, Some(8 | 16)) => (false, true), + (Some(8 | 16), None) => (true, false), + (None, _) | (_, None) => (true, true), + _ => (false, false), + }; + suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); + true + } + (&ty::Int(exp), &ty::Uint(found)) => { + let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) + { + (Some(exp), Some(found)) if found < exp => (false, true), + (None, Some(8)) => (false, true), + _ => (true, true), + }; + suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); + true + } + (&ty::Uint(exp), &ty::Int(found)) => { + let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) + { + (Some(exp), Some(found)) if found > exp => (true, false), + (Some(8), None) => (true, false), + _ => (true, true), + }; + suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); + true + } + (&ty::Float(ref exp), &ty::Float(ref found)) => { + if found.bit_width() < exp.bit_width() { + suggest_to_change_suffix_or_into(err, false, true); + } else if literal_is_ty_suffixed(expr) { err.span_suggestion( expr.span, - if literal_is_ty_suffixed(expr) { - &lit_msg - } else if is_fallible { - &try_msg - } else { - &msg - }, - if literal_is_ty_suffixed(expr) { - suffix_suggestion.clone() - } else if is_fallible { - try_into_suggestion - } else { - into_suggestion.clone() - }, + &lit_msg, + suffix_suggestion, Applicability::MachineApplicable, ); - }; - - match (&expected_ty.kind, &checked_ty.kind) { - (&ty::Int(ref exp), &ty::Int(ref found)) => { - let is_fallible = match (exp.bit_width(), found.bit_width()) { - (Some(exp), Some(found)) if exp < found => true, - (None, Some(8 | 16)) => false, - (None, _) | (_, None) => true, - _ => false, - }; - suggest_to_change_suffix_or_into(err, is_fallible); - true - } - (&ty::Uint(ref exp), &ty::Uint(ref found)) => { - let is_fallible = match (exp.bit_width(), found.bit_width()) { - (Some(exp), Some(found)) if exp < found => true, - (None, Some(8 | 16)) => false, - (None, _) | (_, None) => true, - _ => false, - }; - suggest_to_change_suffix_or_into(err, is_fallible); - true - } - (&ty::Int(exp), &ty::Uint(found)) => { - let is_fallible = match (exp.bit_width(), found.bit_width()) { - (Some(exp), Some(found)) if found < exp => false, - (None, Some(8)) => false, - _ => true, - }; - suggest_to_change_suffix_or_into(err, is_fallible); - true - } - (&ty::Uint(_), &ty::Int(_)) => { - suggest_to_change_suffix_or_into(err, true); - true - } - (&ty::Float(ref exp), &ty::Float(ref found)) => { - if found.bit_width() < exp.bit_width() { - suggest_to_change_suffix_or_into(err, false); - } else if literal_is_ty_suffixed(expr) { - err.span_suggestion( - expr.span, - &lit_msg, - suffix_suggestion, - Applicability::MachineApplicable, - ); - } else if can_cast { - // Missing try_into implementation for `f64` to `f32` - err.span_suggestion( - expr.span, - &format!("{}, producing the closest possible value", cast_msg), - cast_suggestion, - Applicability::MaybeIncorrect, // lossy conversion - ); - } - true + } else if can_cast { + // Missing try_into implementation for `f64` to `f32` + err.span_suggestion( + expr.span, + &format!("{}, producing the closest possible value", cast_msg), + cast_suggestion, + Applicability::MaybeIncorrect, // lossy conversion + ); } - (&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => { - if literal_is_ty_suffixed(expr) { - err.span_suggestion( - expr.span, - &lit_msg, - suffix_suggestion, - Applicability::MachineApplicable, - ); - } else if can_cast { - // Missing try_into implementation for `{float}` to `{integer}` - err.span_suggestion( - expr.span, - &format!("{}, rounding the float towards zero", msg), - cast_suggestion, - Applicability::MaybeIncorrect, // lossy conversion - ); - } - true + true + } + (&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => { + if literal_is_ty_suffixed(expr) { + err.span_suggestion( + expr.span, + &lit_msg, + suffix_suggestion, + Applicability::MachineApplicable, + ); + } else if can_cast { + // Missing try_into implementation for `{float}` to `{integer}` + err.span_suggestion( + expr.span, + &format!("{}, rounding the float towards zero", msg), + cast_suggestion, + Applicability::MaybeIncorrect, // lossy conversion + ); } - (&ty::Float(ref exp), &ty::Uint(ref found)) => { - // if `found` is `None` (meaning found is `usize`), don't suggest `.into()` - if exp.bit_width() > found.bit_width().unwrap_or(256) { - err.span_suggestion( - expr.span, - &format!( - "{}, producing the floating point representation of the integer", - msg, - ), - into_suggestion, - Applicability::MachineApplicable, - ); - } else if literal_is_ty_suffixed(expr) { - err.span_suggestion( - expr.span, - &lit_msg, - suffix_suggestion, - Applicability::MachineApplicable, - ); - } else { - // Missing try_into implementation for `{integer}` to `{float}` - err.span_suggestion( - expr.span, - &format!( - "{}, producing the floating point representation of the integer, + true + } + (&ty::Float(ref exp), &ty::Uint(ref found)) => { + // if `found` is `None` (meaning found is `usize`), don't suggest `.into()` + if exp.bit_width() > found.bit_width().unwrap_or(256) { + err.span_suggestion( + expr.span, + &format!( + "{}, producing the floating point representation of the integer", + msg, + ), + into_suggestion, + Applicability::MachineApplicable, + ); + } else if literal_is_ty_suffixed(expr) { + err.span_suggestion( + expr.span, + &lit_msg, + suffix_suggestion, + Applicability::MachineApplicable, + ); + } else { + // Missing try_into implementation for `{integer}` to `{float}` + err.span_suggestion( + expr.span, + &format!( + "{}, producing the floating point representation of the integer, rounded if necessary", - cast_msg, - ), - cast_suggestion, - Applicability::MaybeIncorrect, // lossy conversion - ); - } - true + cast_msg, + ), + cast_suggestion, + Applicability::MaybeIncorrect, // lossy conversion + ); } - (&ty::Float(ref exp), &ty::Int(ref found)) => { - // if `found` is `None` (meaning found is `isize`), don't suggest `.into()` - if exp.bit_width() > found.bit_width().unwrap_or(256) { - err.span_suggestion( - expr.span, - &format!( - "{}, producing the floating point representation of the integer", - &msg, - ), - into_suggestion, - Applicability::MachineApplicable, - ); - } else if literal_is_ty_suffixed(expr) { - err.span_suggestion( - expr.span, - &lit_msg, - suffix_suggestion, - Applicability::MachineApplicable, - ); - } else { - // Missing try_into implementation for `{integer}` to `{float}` - err.span_suggestion( - expr.span, - &format!( - "{}, producing the floating point representation of the integer, \ - rounded if necessary", - &msg, - ), - cast_suggestion, - Applicability::MaybeIncorrect, // lossy conversion - ); - } - true + true + } + (&ty::Float(ref exp), &ty::Int(ref found)) => { + // if `found` is `None` (meaning found is `isize`), don't suggest `.into()` + if exp.bit_width() > found.bit_width().unwrap_or(256) { + err.span_suggestion( + expr.span, + &format!( + "{}, producing the floating point representation of the integer", + &msg, + ), + into_suggestion, + Applicability::MachineApplicable, + ); + } else if literal_is_ty_suffixed(expr) { + err.span_suggestion( + expr.span, + &lit_msg, + suffix_suggestion, + Applicability::MachineApplicable, + ); + } else { + // Missing try_into implementation for `{integer}` to `{float}` + err.span_suggestion( + expr.span, + &format!( + "{}, producing the floating point representation of the integer, \ + rounded if necessary", + &msg, + ), + cast_suggestion, + Applicability::MaybeIncorrect, // lossy conversion + ); } - _ => false, + true } - } else { - false + _ => false, } } } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 266e9b21d69..bc3ef73d851 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { let expr = expr.peel_drop_temps(); - self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty); + self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None); extend_err(&mut err); // Error possibly reported in `check_assign` so avoid emitting error again. err.emit_unless(self.is_assign_to_bool(expr, expected_ty)); @@ -98,10 +98,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> Ty<'tcx> { let ty = self.check_expr_with_hint(expr, expected); // checks don't need two phase - self.demand_coerce(expr, ty, expected, AllowTwoPhase::No) + self.demand_coerce(expr, ty, expected, expected_ty_expr, AllowTwoPhase::No) } pub(super) fn check_expr_with_hint( @@ -182,7 +183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Call(ref callee, _) => { self.warn_if_unreachable(expr.hir_id, callee.span, "call") } - ExprKind::MethodCall(_, ref span, _) => { + ExprKind::MethodCall(_, ref span, _, _) => { self.warn_if_unreachable(expr.hir_id, *span, "call") } _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression"), @@ -262,7 +263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::Block(ref body, _) => self.check_block_with_expected(&body, expected), ExprKind::Call(ref callee, ref args) => self.check_call(expr, &callee, args, expected), - ExprKind::MethodCall(ref segment, span, ref args) => { + ExprKind::MethodCall(ref segment, span, ref args, _) => { self.check_method_call(expr, segment, span, args, expected, needs) } ExprKind::Cast(ref e, ref t) => self.check_expr_cast(e, t, expr), @@ -776,7 +777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: &Span, ) -> Ty<'tcx> { let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); - let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty); + let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs)); let expected_ty = expected.coercion_target_type(self, expr.span); if expected_ty == self.tcx.types.bool { @@ -1026,7 +1027,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (element_ty, t) = match uty { Some(uty) => { - self.check_expr_coercable_to_type(&element, uty); + self.check_expr_coercable_to_type(&element, uty, None); (uty, uty) } None => { @@ -1063,7 +1064,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds { Some(ref fs) if i < fs.len() => { let ety = fs[i].expect_ty(); - self.check_expr_coercable_to_type(&e, ety); + self.check_expr_coercable_to_type(&e, ety, None); ety } _ => self.check_expr_with_expectation(&e, NoExpectation), @@ -1237,7 +1238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Make sure to give a type to the field even if there's // an error, so we can continue type-checking. - self.check_expr_coercable_to_type(&field.expr, field_type); + self.check_expr_coercable_to_type(&field.expr, field_type, None); } // Make sure the programmer specified correct number of fields. @@ -1735,7 +1736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match self.lookup_indexing(expr, base, base_t, idx_t, needs) { Some((index_ty, element_ty)) => { // two-phase not needed because index_ty is never mutable - self.demand_coerce(idx, idx_t, index_ty, AllowTwoPhase::No); + self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); element_ty } None => { @@ -1788,7 +1789,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { match self.resume_yield_tys { Some((resume_ty, yield_ty)) => { - self.check_expr_coercable_to_type(&value, yield_ty); + self.check_expr_coercable_to_type(&value, yield_ty, None); resume_ty } @@ -1797,7 +1798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // information. Hence, we check the source of the yield expression here and check its // value's type against `()` (this check should always hold). None if src.is_await() => { - self.check_expr_coercable_to_type(&value, self.tcx.mk_unit()); + self.check_expr_coercable_to_type(&value, self.tcx.mk_unit(), None); self.tcx.mk_unit() } _ => { @@ -1836,11 +1837,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match ty.kind { ty::FnDef(..) => { let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx)); - self.demand_coerce(expr, ty, fnptr_ty, AllowTwoPhase::No); + self.demand_coerce(expr, ty, fnptr_ty, None, AllowTwoPhase::No); } ty::Ref(_, base_ty, mutbl) => { let ptr_ty = self.tcx.mk_ptr(ty::TypeAndMut { ty: base_ty, mutbl }); - self.demand_coerce(expr, ty, ptr_ty, AllowTwoPhase::No); + self.demand_coerce(expr, ty, ptr_ty, None, AllowTwoPhase::No); } _ => {} } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 91562d576ea..a2e6c8793cb 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1303,7 +1303,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .at(&ObligationCause::dummy(), self.param_env) .sup(candidate.xform_self_ty, self_ty); match self.select_trait_candidate(trait_ref) { - Ok(Some(traits::Vtable::VtableImpl(ref impl_data))) => { + Ok(Some(traits::ImplSource::ImplSourceUserDefined(ref impl_data))) => { // If only a single impl matches, make the error message point // to that impl. ImplSource(impl_data.impl_def_id) @@ -1384,10 +1384,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if self.probe(|_| { match self.select_trait_candidate(trait_ref) { Err(_) => return true, - Ok(Some(vtable)) - if !vtable.borrow_nested_obligations().is_empty() => + Ok(Some(impl_source)) + if !impl_source.borrow_nested_obligations().is_empty() => { - for obligation in vtable.borrow_nested_obligations() { + for obligation in impl_source.borrow_nested_obligations() { // Determine exactly which obligation wasn't met, so // that we can give more context in the error. if !self.predicate_may_hold(&obligation) { @@ -1556,7 +1556,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { match self.mode { Mode::MethodCall => item.fn_has_self_parameter, Mode::Path => match item.kind { - ty::AssocKind::OpaqueTy | ty::AssocKind::Type => false, + ty::AssocKind::Type => false, ty::AssocKind::Fn | ty::AssocKind::Const => true, }, } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 7ca3eb884d8..67bdd04d371 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -158,9 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let path = self.tcx.def_path_str(trait_ref.def_id); let ty = match item.kind { - ty::AssocKind::Const - | ty::AssocKind::Type - | ty::AssocKind::OpaqueTy => rcvr_ty, + ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty, ty::AssocKind::Fn => self .tcx .fn_sig(item.def_id) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e5bca374677..a409e20953d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -31,9 +31,6 @@ can be broken down into several distinct phases: final assignments of the various region variables if there is some flexibility. -- vtable: find and records the impls to use for each trait bound that - appears on a type parameter. - - writeback: writes the final types within a function body, replacing type variables with their final inferred types. These final types are written into the `tcx.node_types` table, which should *never* contain @@ -1049,7 +1046,7 @@ fn typeck_tables_of_with_fallback<'tcx>( // Gather locals in statics (because of block expressions). GatherLocalsVisitor { fcx: &fcx, parent_id: id }.visit_body(body); - fcx.check_expr_coercable_to_type(&body.value, revealed_ty); + fcx.check_expr_coercable_to_type(&body.value, revealed_ty, None); fcx.write_ty(id, revealed_ty); @@ -1946,7 +1943,6 @@ fn check_specialization_validity<'tcx>( let kind = match impl_item.kind { hir::ImplItemKind::Const(..) => ty::AssocKind::Const, hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, - hir::ImplItemKind::OpaqueTy(..) => ty::AssocKind::OpaqueTy, hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type, }; @@ -2117,7 +2113,7 @@ fn check_impl_items_against_trait<'tcx>( err.emit() } } - hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(_) => { + hir::ImplItemKind::TyAlias(_) => { let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); if ty_trait_item.kind == ty::AssocKind::Type { compare_ty_impl( @@ -2370,8 +2366,6 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { ) } ty::AssocKind::Type => format!("type {} = Type;", assoc.ident), - // FIXME(type_alias_impl_trait): we should print bounds here too. - ty::AssocKind::OpaqueTy => format!("type {} = Type;", assoc.ident), ty::AssocKind::Const => { let ty = tcx.type_of(assoc.def_id); let val = expr::ty_kind_suggestion(ty).unwrap_or("value"); @@ -2393,11 +2387,7 @@ fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bo // caught by case 1. match rty.is_representable(tcx, sp) { Representability::SelfRecursive(spans) => { - let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id()); - for span in spans { - err.span_label(span, "recursive without indirection"); - } - err.emit(); + recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans); return false; } Representability::Representable | Representability::ContainsRecursive => (), @@ -3915,7 +3905,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg_unit: bool| { let (span, start_span, args) = match &expr.kind { hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]), - hir::ExprKind::MethodCall(path_segment, span, args) => ( + hir::ExprKind::MethodCall(path_segment, span, args, _) => ( *span, // `sp` doesn't point at the whole `foo.bar()`, only at `bar`. path_segment @@ -4070,7 +4060,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("check_closures={}", check_closures); // More awful hacks: before we check argument types, try to do - // an "opportunistic" vtable resolution of any trait bounds on + // an "opportunistic" trait resolution of any trait bounds on // the call. This helps coercions. if check_closures { self.select_obligations_where_possible(false, |errors| { @@ -4126,7 +4116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); // We're processing function arguments so we definitely want to use // two-phase borrows. - self.demand_coerce(&arg, checked_ty, coerce_ty, AllowTwoPhase::Yes); + self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes); final_arg_types.push((i, checked_ty, coerce_ty)); // 3. Relate the expected type and the formal one, @@ -4544,7 +4534,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype(init.span, local_ty, init_ty); init_ty } else { - self.check_expr_coercable_to_type(init, local_ty) + self.check_expr_coercable_to_type(init, local_ty, None) } } @@ -5030,6 +5020,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) { if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) { err.span_suggestion(sp, msg, suggestion, applicability); @@ -5040,7 +5031,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sp = self.sess().source_map().guess_head_span(sp); err.span_label(sp, &format!("{} defined here", found)); } - } else if !self.check_for_cast(err, expr, found, expected) { + } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) { let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span); let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); @@ -5094,7 +5085,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, ) { - if self.tcx.hir().is_const_context(expr.hir_id) { + if self.tcx.hir().is_inside_const_context(expr.hir_id) { // Do not suggest `Box::new` in const context. return; } @@ -5131,7 +5122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> bool { // Handle #68197. - if self.tcx.hir().is_const_context(expr.hir_id) { + if self.tcx.hir().is_inside_const_context(expr.hir_id) { // Do not suggest `Box::new` in const context. return false; } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index d89993e3547..a3a27dc138b 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -57,9 +57,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { // && and || are a simple case. - self.check_expr_coercable_to_type(lhs_expr, tcx.types.bool); + self.check_expr_coercable_to_type(lhs_expr, tcx.types.bool, None); let lhs_diverges = self.diverges.get(); - self.check_expr_coercable_to_type(rhs_expr, tcx.types.bool); + self.check_expr_coercable_to_type(rhs_expr, tcx.types.bool, None); // Depending on the LHS' value, the RHS can never execute. self.diverges.set(lhs_diverges); @@ -170,7 +170,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::MiscVariable, span: lhs_expr.span, }); - self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No) + self.demand_coerce(lhs_expr, lhs_ty, fresh_var, Some(rhs_expr), AllowTwoPhase::No) } IsAssign::Yes => { // rust-lang/rust#52126: We have to use strict @@ -196,7 +196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign)); // see `NB` above - let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); + let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr)); let rhs_ty = self.resolve_vars_with_obligations(rhs_ty); let return_ty = match result { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 7d9bf975c69..f3297ed6743 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -316,9 +316,6 @@ fn check_associated_item( fcx.register_wf_obligation(ty.into(), span, code.clone()); } } - ty::AssocKind::OpaqueTy => { - // Do nothing: opaque types check themselves. - } } implied_bounds @@ -804,14 +801,14 @@ fn check_where_clauses<'tcx, 'fcx>( traits::Obligation::new(cause, fcx.param_env, pred) }); - let mut predicates = predicates.instantiate_identity(fcx.tcx); + let predicates = predicates.instantiate_identity(fcx.tcx); - if let Some((return_ty, span)) = return_ty { - let opaque_types = check_opaque_types(tcx, fcx, def_id.expect_local(), span, return_ty); - for _ in 0..opaque_types.len() { - predicates.spans.push(span); + if let Some((mut return_ty, span)) = return_ty { + if return_ty.has_infer_types_or_consts() { + fcx.select_obligations_where_possible(false, |_| {}); + return_ty = fcx.resolve_vars_if_possible(&return_ty); } - predicates.predicates.extend(opaque_types); + check_opaque_types(tcx, fcx, def_id.expect_local(), span, return_ty); } let predicates = fcx.normalize_associated_types_in(span, &predicates); @@ -883,119 +880,117 @@ fn check_opaque_types<'fcx, 'tcx>( fn_def_id: LocalDefId, span: Span, ty: Ty<'tcx>, -) -> Vec<ty::Predicate<'tcx>> { +) { trace!("check_opaque_types(ty={:?})", ty); - let mut substituted_predicates = Vec::new(); ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: fcx.tcx, ty_op: |ty| { if let ty::Opaque(def_id, substs) = ty.kind { trace!("check_opaque_types: opaque_ty, {:?}, {:?}", def_id, substs); let generics = tcx.generics_of(def_id); - // Only check named `impl Trait` types defined in this crate. - // FIXME(eddyb) is `generics.parent.is_none()` correct? It seems - // potentially risky wrt associated types in `impl`s. - if generics.parent.is_none() && def_id.is_local() { - let opaque_hir_id = tcx.hir().as_local_hir_id(def_id.expect_local()); - if may_define_opaque_type(tcx, fn_def_id, opaque_hir_id) { - trace!("check_opaque_types: may define, generics={:#?}", generics); - let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); - for (i, arg) in substs.iter().enumerate() { - let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind, ty::Param(_)), - - GenericArgKind::Lifetime(region) => { - if let ty::ReStatic = region { - tcx.sess - .struct_span_err( - span, - "non-defining opaque type use in defining scope", - ) - .span_label( - tcx.def_span(generics.param_at(i, tcx).def_id), - "cannot use static lifetime; use a bound lifetime \ - instead or remove the lifetime parameter from the \ - opaque type", - ) - .emit(); - continue; - } - - true - } - - GenericArgKind::Const(ct) => { - matches!(ct.val, ty::ConstKind::Param(_)) - } - }; - - if arg_is_param { - seen_params.entry(arg).or_default().push(i); - } else { - // Prevent `fn foo() -> Foo<u32>` from being defining. - let opaque_param = generics.param_at(i, tcx); + + let opaque_hir_id = if let Some(local_id) = def_id.as_local() { + tcx.hir().as_local_hir_id(local_id) + } else { + // Opaque types from other crates won't have defining uses in this crate. + return ty; + }; + if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) = + tcx.hir().expect_item(opaque_hir_id).kind + { + // No need to check return position impl trait (RPIT) + // because for type and const parameters they are correct + // by construction: we convert + // + // fn foo<P0..Pn>() -> impl Trait + // + // into + // + // type Foo<P0...Pn> + // fn foo<P0..Pn>() -> Foo<P0...Pn>. + // + // For lifetime parameters we convert + // + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> + // + // into + // + // type foo::<'p0..'pn>::Foo<'q0..'qm> + // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. + // + // which would error here on all of the `'static` args. + return ty; + } + if !may_define_opaque_type(tcx, fn_def_id, opaque_hir_id) { + return ty; + } + trace!("check_opaque_types: may define, generics={:#?}", generics); + let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); + for (i, arg) in substs.iter().enumerate() { + let arg_is_param = match arg.unpack() { + GenericArgKind::Type(ty) => matches!(ty.kind, ty::Param(_)), + + GenericArgKind::Lifetime(region) => { + if let ty::ReStatic = region { tcx.sess .struct_span_err( span, "non-defining opaque type use in defining scope", ) - .span_note( - tcx.def_span(opaque_param.def_id), - &format!( - "used non-generic {} `{}` for generic parameter", - opaque_param.kind.descr(), - arg, - ), - ) - .emit(); - } - } // for (arg, param) - - for (_, indices) in seen_params { - if indices.len() > 1 { - let descr = generics.param_at(indices[0], tcx).kind.descr(); - let spans: Vec<_> = indices - .into_iter() - .map(|i| tcx.def_span(generics.param_at(i, tcx).def_id)) - .collect(); - tcx.sess - .struct_span_err( - span, - "non-defining opaque type use in defining scope", + .span_label( + tcx.def_span(generics.param_at(i, tcx).def_id), + "cannot use static lifetime; use a bound lifetime \ + instead or remove the lifetime parameter from the \ + opaque type", ) - .span_note(spans, &format!("{} used multiple times", descr)) .emit(); + continue; } - } - } // if may_define_opaque_type - // Now register the bounds on the parameters of the opaque type - // so the parameters given by the function need to fulfill them. - // - // type Foo<T: Bar> = impl Baz + 'static; - // fn foo<U>() -> Foo<U> { .. *} - // - // becomes - // - // type Foo<T: Bar> = impl Baz + 'static; - // fn foo<U: Bar>() -> Foo<U> { .. *} - let predicates = tcx.predicates_of(def_id); - trace!("check_opaque_types: may define, predicates={:#?}", predicates,); - for &(pred, _) in predicates.predicates { - let substituted_pred = pred.subst(fcx.tcx, substs); - // Avoid duplication of predicates that contain no parameters, for example. - if !predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) { - substituted_predicates.push(substituted_pred); + true } + + GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), + }; + + if arg_is_param { + seen_params.entry(arg).or_default().push(i); + } else { + // Prevent `fn foo() -> Foo<u32>` from being defining. + let opaque_param = generics.param_at(i, tcx); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note( + tcx.def_span(opaque_param.def_id), + &format!( + "used non-generic {} `{}` for generic parameter", + opaque_param.kind.descr(), + arg, + ), + ) + .emit(); } - } // if is_named_opaque_type + } // for (arg, param) + + for (_, indices) in seen_params { + if indices.len() > 1 { + let descr = generics.param_at(indices[0], tcx).kind.descr(); + let spans: Vec<_> = indices + .into_iter() + .map(|i| tcx.def_span(generics.param_at(i, tcx).def_id)) + .collect(); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note(spans, &format!("{} used multiple times", descr)) + .emit(); + } + } } // if let Opaque ty }, lt_op: |lt| lt, ct_op: |ct| ct, }); - substituted_predicates } const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, \ diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 3473dc7a58d..159d3d7a538 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -460,7 +460,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let mut skip_add = false; if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.kind { - if let hir::OpaqueTyOrigin::TypeAlias = opaque_defn.origin { + if let hir::OpaqueTyOrigin::Misc = opaque_defn.origin { if def_id == defin_ty_def_id { debug!( "skipping adding concrete definition for opaque type {:?} {:?}", diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 355b4fc413f..1d59d749634 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -742,7 +742,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::HirId) { hir::ImplItemKind::Fn(..) => { tcx.ensure().fn_sig(def_id); } - hir::ImplItemKind::TyAlias(_) | hir::ImplItemKind::OpaqueTy(_) => { + hir::ImplItemKind::TyAlias(_) => { // Account for `type T = _;` let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_impl_item(impl_item); @@ -1202,22 +1202,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => { impl_trait_fn.or_else(|| { let parent_id = tcx.hir().get_parent_item(hir_id); - if parent_id != hir_id && parent_id != CRATE_HIR_ID { - debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id); - // If this 'impl Trait' is nested inside another 'impl Trait' - // (e.g. `impl Foo<MyType = impl Bar<A>>`), we need to use the 'parent' - // 'impl Trait' for its generic parameters, since we can reference them - // from the 'child' 'impl Trait' - if let Node::Item(hir::Item { kind: ItemKind::OpaqueTy(..), .. }) = - tcx.hir().get(parent_id) - { - Some(tcx.hir().local_def_id(parent_id).to_def_id()) - } else { - None - } - } else { - None - } + assert!(parent_id != hir_id && parent_id != CRATE_HIR_ID); + debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id); + // Opaque types are always nested within another item, and + // inherit the generics of the item. + Some(tcx.hir().local_def_id(parent_id).to_def_id()) }) } _ => None, @@ -1428,7 +1417,7 @@ fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool { Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty), Tup(tys) => tys.iter().any(is_suggestable_infer_ty), Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty), - Def(_, generic_args) => are_suggestable_generic_args(generic_args), + OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args), Path(hir::QPath::TypeRelative(ty, segment)) => { is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.generic_args().args) } @@ -1715,31 +1704,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let ast_generics = match node { Node::TraitItem(item) => &item.generics, - Node::ImplItem(item) => match item.kind { - ImplItemKind::OpaqueTy(ref bounds) => { - ty::print::with_no_queries(|| { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - let opaque_ty = tcx.mk_opaque(def_id, substs); - debug!( - "explicit_predicates_of({:?}): created opaque type {:?}", - def_id, opaque_ty - ); - - // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`. - let bounds = AstConv::compute_bounds( - &icx, - opaque_ty, - bounds, - SizedByDefault::Yes, - tcx.def_span(def_id), - ); - - predicates.extend(bounds.predicates(tcx, opaque_ty)); - &item.generics - }) - } - _ => &item.generics, - }, + Node::ImplItem(item) => &item.generics, Node::Item(item) => { match item.kind { diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs index cf0e3f9cdf5..549a20531e2 100644 --- a/src/librustc_typeck/collect/type_of.rs +++ b/src/librustc_typeck/collect/type_of.rs @@ -64,13 +64,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { icx.to_ty(ty) } } - ImplItemKind::OpaqueTy(_) => { - if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id).to_def_id()).is_none() { - report_assoc_ty_on_inherent_impl(tcx, item.span); - } - - find_opaque_ty_constraints(tcx, def_id.expect_local()) - } ImplItemKind::TyAlias(ref ty) => { if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id).to_def_id()).is_none() { report_assoc_ty_on_inherent_impl(tcx, item.span); @@ -107,26 +100,17 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_adt(def, substs) } + ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::Binding, .. }) => { + let_position_impl_trait_type(tcx, def_id.expect_local()) + } ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }) => { find_opaque_ty_constraints(tcx, def_id.expect_local()) } // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), origin, .. }) => { - let concrete_types = match origin { - OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => { - &tcx.mir_borrowck(owner.expect_local()).concrete_opaque_types - } - OpaqueTyOrigin::Misc => { - // We shouldn't leak borrowck results through impl trait in bindings. - // For example, we shouldn't be able to tell if `x` in - // `let x: impl Sized + 'a = &()` has type `&'static ()` or `&'a ()`. - &tcx.typeck_tables_of(owner.expect_local()).concrete_opaque_types - } - OpaqueTyOrigin::TypeAlias => { - span_bug!(item.span, "Type alias impl trait shouldn't have an owner") - } - }; - let concrete_ty = concrete_types + ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), .. }) => { + let concrete_ty = tcx + .mir_borrowck(owner.expect_local()) + .concrete_opaque_types .get(&def_id) .map(|opaque| opaque.concrete_type) .unwrap_or_else(|| { @@ -155,13 +139,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } }); debug!("concrete_ty = {:?}", concrete_ty); - if concrete_ty.has_erased_regions() { - // FIXME(impl_trait_in_bindings) Handle this case. - tcx.sess.span_fatal( - item.span, - "lifetimes in impl Trait types in bindings are not currently supported", - ); - } concrete_ty } ItemKind::Trait(..) @@ -596,6 +573,60 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { } } +/// Retrieve the inferred concrete type for let position impl trait. +/// +/// This is different to other kinds of impl trait because: +/// +/// 1. We know which function contains the defining use (the function that +/// contains the let statement) +/// 2. We do not currently allow (free) lifetimes in the return type. `let` +/// statements in some statically unreachable code are removed from the MIR +/// by the time we borrow check, and it's not clear how we should handle +/// those. +fn let_position_impl_trait_type(tcx: TyCtxt<'_>, opaque_ty_id: LocalDefId) -> Ty<'_> { + let scope = tcx.hir().get_defining_scope(tcx.hir().as_local_hir_id(opaque_ty_id)); + let scope_def_id = tcx.hir().local_def_id(scope); + + let opaque_ty_def_id = opaque_ty_id.to_def_id(); + + let owner_tables = tcx.typeck_tables_of(scope_def_id); + let concrete_ty = owner_tables + .concrete_opaque_types + .get(&opaque_ty_def_id) + .map(|opaque| opaque.concrete_type) + .unwrap_or_else(|| { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "owner {:?} has no opaque type for {:?} in its tables", + scope_def_id, opaque_ty_id + ), + ); + if let Some(ErrorReported) = owner_tables.tainted_by_errors { + // Some error in the owner fn prevented us from populating the + // `concrete_opaque_types` table. + tcx.types.err + } else { + // We failed to resolve the opaque type or it resolves to + // itself. Return the non-revealed type, which should result in + // E0720. + tcx.mk_opaque( + opaque_ty_def_id, + InternalSubsts::identity_for_item(tcx, opaque_ty_def_id), + ) + } + }); + debug!("concrete_ty = {:?}", concrete_ty); + if concrete_ty.has_erased_regions() { + // FIXME(impl_trait_in_bindings) Handle this case. + tcx.sess.span_fatal( + tcx.hir().span(tcx.hir().as_local_hir_id(opaque_ty_id)), + "lifetimes in impl Trait types in bindings are not currently supported", + ); + } + concrete_ty +} + fn infer_placeholder_type( tcx: TyCtxt<'_>, def_id: LocalDefId, diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index 53973eba229..6baadb8febd 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -185,7 +185,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.consume_exprs(args); } - hir::ExprKind::MethodCall(.., ref args) => { + hir::ExprKind::MethodCall(.., ref args, _) => { // callee.m(args) self.consume_exprs(args); } diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index e13d9ea2b26..37d383db68a 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -140,13 +140,6 @@ fn enforce_impl_params_are_constrained( Vec::new() } } - ty::AssocKind::OpaqueTy => { - // We don't know which lifetimes appear in the actual - // opaque type, so use all of the lifetimes that appear - // in the type's predicates. - let predicates = tcx.predicates_of(def_id).instantiate_identity(tcx); - cgp::parameters_for(&predicates, true) - } ty::AssocKind::Fn | ty::AssocKind::Const => Vec::new(), } }) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dd4df11b1df..adb2ae9a5d6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1138,10 +1138,6 @@ impl Clean<Item> for hir::ImplItem<'_> { let item_type = type_.def_id().and_then(|did| inline::build_ty(cx, did)); TypedefItem(Typedef { type_, generics: Generics::default(), item_type }, true) } - hir::ImplItemKind::OpaqueTy(ref bounds) => OpaqueTyItem( - OpaqueTy { bounds: bounds.clean(cx), generics: Generics::default() }, - true, - ), }; let local_did = cx.tcx.hir().local_def_id(self.hir_id); Item { @@ -1308,7 +1304,6 @@ impl Clean<Item> for ty::AssocItem { ) } } - ty::AssocKind::OpaqueTy => unimplemented!(), }; let visibility = match self.container { @@ -1356,7 +1351,7 @@ impl Clean<Type> for hir::Ty<'_> { Array(box ty.clean(cx), length) } TyKind::Tup(ref tys) => Tuple(tys.clean(cx)), - TyKind::Def(item_id, _) => { + TyKind::OpaqueDef(item_id, _) => { let item = cx.tcx.hir().expect_item(item_id.id); if let hir::ItemKind::OpaqueTy(ref ty) = item.kind { ImplTrait(ty.bounds.clean(cx)) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 38123816527..5c76c840b1d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -85,9 +85,7 @@ pub struct Item { impl fmt::Debug for Item { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let fake = MAX_DEF_ID.with(|m| { - m.borrow().get(&self.def_id.krate).map(|id| self.def_id >= *id).unwrap_or(false) - }); + let fake = self.is_fake(); let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id }; fmt.debug_struct("Item") @@ -238,6 +236,13 @@ impl Item { _ => false, } } + + /// See comments on next_def_id + pub fn is_fake(&self) -> bool { + MAX_DEF_ID.with(|m| { + m.borrow().get(&self.def_id.krate).map(|id| self.def_id >= *id).unwrap_or(false) + }) + } } #[derive(Clone, Debug)] diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 018c0e82c45..f0900c34a4b 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -126,7 +126,7 @@ impl<'a> SourceCollector<'a> { &self.scx.themes, ); self.scx.fs.write(&cur, v.as_bytes())?; - self.scx.local_sources.insert(p.clone(), href); + self.scx.local_sources.insert(p, href); Ok(()) } } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index ac5a2f96b26..953f61a3772 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2374,7 +2374,9 @@ function defocusSearchBar() { if (!next) { return; } - if (next.getElementsByClassName("method").length > 0 && hasClass(e, "impl")) { + if (hasClass(e, "impl") && + (next.getElementsByClassName("method").length > 0 || + next.getElementsByClassName("associatedconstant").length > 0)) { insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]); } }; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 149480ec80f..f5b2f1bb5b1 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -12,6 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty; use rustc_resolve::ParentScope; use rustc_session::lint; +use rustc_span::hygiene::MacroKind; use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; @@ -122,6 +123,42 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } + /// Resolves a string as a macro. + fn macro_resolve(&self, path_str: &str, parent_id: Option<hir::HirId>) -> Option<Res> { + let cx = self.cx; + let path = ast::Path::from_ident(Ident::from_str(path_str)); + cx.enter_resolver(|resolver| { + if let Ok((Some(ext), res)) = resolver.resolve_macro_path( + &path, + None, + &ParentScope::module(resolver.graph_root()), + false, + false, + ) { + if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { + return Some(res.map_id(|_| panic!("unexpected id"))); + } + } + if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { + return Some(res.map_id(|_| panic!("unexpected id"))); + } + if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) { + let module_id = cx.tcx.hir().local_def_id(module_id); + if let Ok((_, res)) = + resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id) + { + // don't resolve builtins like `#[derive]` + if let Res::Def(..) = res { + let res = res.map_id(|_| panic!("unexpected node_id")); + return Some(res); + } + } + } else { + debug!("attempting to resolve item without parent module: {}", path_str); + } + None + }) + } /// 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( @@ -371,6 +408,22 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } +/// Check for resolve collisions between a trait and its derive +/// +/// These are common and we should just resolve to the trait in that case +fn is_derive_trait_collision<T>(ns: &PerNS<Option<(Res, T)>>) -> bool { + if let PerNS { + type_ns: Some((Res::Def(DefKind::Trait, _), _)), + macro_ns: Some((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), + .. + } = *ns + { + true + } else { + false + } +} + impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { fn fold_item(&mut self, mut item: Item) -> Option<Item> { let item_hir_id = if item.is_mod() { @@ -451,7 +504,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { .. }, .. - })) => segments.first().and_then(|seg| Some(seg.ident.to_string())), + })) => segments.first().map(|seg| seg.ident.to_string()), Some(hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Enum(..), .. })) @@ -532,6 +585,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } else if link.starts_with("macro@") { kind = Some(MacroNS); link.trim_start_matches("macro@") + } else if link.starts_with("derive@") { + kind = Some(MacroNS); + link.trim_start_matches("derive@") } else if link.ends_with('!') { kind = Some(MacroNS); link.trim_end_matches('!') @@ -614,8 +670,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } None => { // Try everything! - let candidates = PerNS { - macro_ns: macro_resolve(cx, path_str) + let mut candidates = PerNS { + macro_ns: self + .macro_resolve(path_str, base_node) .map(|res| (res, extra_fragment.clone())), type_ns: match self.resolve( path_str, @@ -668,10 +725,16 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { continue; } - let is_unambiguous = candidates.clone().present_items().count() == 1; - if is_unambiguous { + let len = candidates.clone().present_items().count(); + + if len == 1 { candidates.present_items().next().unwrap() + } else if len == 2 && is_derive_trait_collision(&candidates) { + candidates.type_ns.unwrap() } else { + if is_derive_trait_collision(&candidates) { + candidates.macro_ns = None; + } ambiguity_error( cx, &item, @@ -684,7 +747,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } Some(MacroNS) => { - if let Some(res) = macro_resolve(cx, path_str) { + if let Some(res) = self.macro_resolve(path_str, base_node) { (res, extra_fragment) } else { resolution_failure(cx, &item, path_str, &dox, link_range); @@ -727,28 +790,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } -/// Resolves a string as a macro. -fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> { - let path = ast::Path::from_ident(Ident::from_str(path_str)); - cx.enter_resolver(|resolver| { - if let Ok((Some(ext), res)) = resolver.resolve_macro_path( - &path, - None, - &ParentScope::module(resolver.graph_root()), - false, - false, - ) { - if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { - return Some(res.map_id(|_| panic!("unexpected id"))); - } - } - if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { - return Some(res.map_id(|_| panic!("unexpected id"))); - } - None - }) -} - fn build_diagnostic( cx: &DocContext<'_>, item: &Item, @@ -916,7 +957,7 @@ fn ambiguity_error( Res::Def(DefKind::AssocFn | DefKind::Fn, _) => { ("add parentheses", format!("{}()", path_str)) } - Res::Def(DefKind::Macro(..), _) => { + Res::Def(DefKind::Macro(MacroKind::Bang), _) => { ("add an exclamation mark", format!("{}!", path_str)) } _ => { @@ -930,6 +971,9 @@ fn ambiguity_error( (Res::Def(DefKind::Mod, _), _) => "module", (_, TypeNS) => "type", (_, ValueNS) => "value", + (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => { + "derive" + } (_, MacroNS) => "macro", }; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 4b15a591da7..21aa0ded5a4 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -676,7 +676,11 @@ impl Collector { } fn generate_name(&self, line: usize, filename: &FileName) -> String { - format!("{} - {} (line {})", filename, self.names.join("::"), line) + let mut item_path = self.names.join("::"); + if !item_path.is_empty() { + item_path.push(' '); + } + format!("{} - {}(line {})", filename, item_path, line) } pub fn set_position(&mut self, position: Span) { diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 39d786e5997..6af1cbb34b6 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -20,7 +20,7 @@ panic_unwind = { path = "../libpanic_unwind", optional = true } panic_abort = { path = "../libpanic_abort" } core = { path = "../libcore" } libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.31" } +compiler_builtins = { version = "0.1.32" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } hashbrown = { version = "0.6.2", default-features = false, features = ['rustc-dep-of-std'] } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 8ff19557a30..d752ba89a27 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -916,8 +916,7 @@ impl f32 { #[cfg(test)] mod tests { - use crate::f32; - use crate::f32::*; + use crate::f32::consts; use crate::num::FpCategory as Fp; use crate::num::*; @@ -928,14 +927,14 @@ mod tests { #[test] fn test_min_nan() { - assert_eq!(NAN.min(2.0), 2.0); - assert_eq!(2.0f32.min(NAN), 2.0); + assert_eq!(f32::NAN.min(2.0), 2.0); + assert_eq!(2.0f32.min(f32::NAN), 2.0); } #[test] fn test_max_nan() { - assert_eq!(NAN.max(2.0), 2.0); - assert_eq!(2.0f32.max(NAN), 2.0); + assert_eq!(f32::NAN.max(2.0), 2.0); + assert_eq!(2.0f32.max(f32::NAN), 2.0); } #[test] @@ -1158,52 +1157,52 @@ mod tests { #[test] fn test_abs() { - assert_eq!(INFINITY.abs(), INFINITY); + assert_eq!(f32::INFINITY.abs(), f32::INFINITY); assert_eq!(1f32.abs(), 1f32); assert_eq!(0f32.abs(), 0f32); assert_eq!((-0f32).abs(), 0f32); assert_eq!((-1f32).abs(), 1f32); - assert_eq!(NEG_INFINITY.abs(), INFINITY); - assert_eq!((1f32 / NEG_INFINITY).abs(), 0f32); - assert!(NAN.abs().is_nan()); + assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY); + assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32); + assert!(f32::NAN.abs().is_nan()); } #[test] fn test_signum() { - assert_eq!(INFINITY.signum(), 1f32); + assert_eq!(f32::INFINITY.signum(), 1f32); assert_eq!(1f32.signum(), 1f32); assert_eq!(0f32.signum(), 1f32); assert_eq!((-0f32).signum(), -1f32); assert_eq!((-1f32).signum(), -1f32); - assert_eq!(NEG_INFINITY.signum(), -1f32); - assert_eq!((1f32 / NEG_INFINITY).signum(), -1f32); - assert!(NAN.signum().is_nan()); + assert_eq!(f32::NEG_INFINITY.signum(), -1f32); + assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32); + assert!(f32::NAN.signum().is_nan()); } #[test] fn test_is_sign_positive() { - assert!(INFINITY.is_sign_positive()); + assert!(f32::INFINITY.is_sign_positive()); assert!(1f32.is_sign_positive()); assert!(0f32.is_sign_positive()); assert!(!(-0f32).is_sign_positive()); assert!(!(-1f32).is_sign_positive()); - assert!(!NEG_INFINITY.is_sign_positive()); - assert!(!(1f32 / NEG_INFINITY).is_sign_positive()); - assert!(NAN.is_sign_positive()); - assert!(!(-NAN).is_sign_positive()); + assert!(!f32::NEG_INFINITY.is_sign_positive()); + assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive()); + assert!(f32::NAN.is_sign_positive()); + assert!(!(-f32::NAN).is_sign_positive()); } #[test] fn test_is_sign_negative() { - assert!(!INFINITY.is_sign_negative()); + assert!(!f32::INFINITY.is_sign_negative()); assert!(!1f32.is_sign_negative()); assert!(!0f32.is_sign_negative()); assert!((-0f32).is_sign_negative()); assert!((-1f32).is_sign_negative()); - assert!(NEG_INFINITY.is_sign_negative()); - assert!((1f32 / NEG_INFINITY).is_sign_negative()); - assert!(!NAN.is_sign_negative()); - assert!((-NAN).is_sign_negative()); + assert!(f32::NEG_INFINITY.is_sign_negative()); + assert!((1f32 / f32::NEG_INFINITY).is_sign_negative()); + assert!(!f32::NAN.is_sign_negative()); + assert!((-f32::NAN).is_sign_negative()); } #[test] @@ -1268,13 +1267,13 @@ mod tests { #[test] fn test_sqrt_domain() { - assert!(NAN.sqrt().is_nan()); - assert!(NEG_INFINITY.sqrt().is_nan()); + assert!(f32::NAN.sqrt().is_nan()); + assert!(f32::NEG_INFINITY.sqrt().is_nan()); assert!((-1.0f32).sqrt().is_nan()); assert_eq!((-0.0f32).sqrt(), -0.0); assert_eq!(0.0f32.sqrt(), 0.0); assert_eq!(1.0f32.sqrt(), 1.0); - assert_eq!(INFINITY.sqrt(), INFINITY); + assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY); } #[test] @@ -1523,13 +1522,13 @@ mod tests { #[test] #[should_panic] fn test_clamp_min_is_nan() { - let _ = 1.0f32.clamp(NAN, 1.0); + let _ = 1.0f32.clamp(f32::NAN, 1.0); } #[test] #[should_panic] fn test_clamp_max_is_nan() { - let _ = 1.0f32.clamp(3.0, NAN); + let _ = 1.0f32.clamp(3.0, f32::NAN); } #[test] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index d7845fd2c4d..9cd60d846a7 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -943,8 +943,7 @@ impl f64 { #[cfg(test)] mod tests { - use crate::f64; - use crate::f64::*; + use crate::f64::consts; use crate::num::FpCategory as Fp; use crate::num::*; @@ -955,19 +954,19 @@ mod tests { #[test] fn test_min_nan() { - assert_eq!(NAN.min(2.0), 2.0); - assert_eq!(2.0f64.min(NAN), 2.0); + assert_eq!(f64::NAN.min(2.0), 2.0); + assert_eq!(2.0f64.min(f64::NAN), 2.0); } #[test] fn test_max_nan() { - assert_eq!(NAN.max(2.0), 2.0); - assert_eq!(2.0f64.max(NAN), 2.0); + assert_eq!(f64::NAN.max(2.0), 2.0); + assert_eq!(2.0f64.max(f64::NAN), 2.0); } #[test] fn test_nan() { - let nan: f64 = NAN; + let nan: f64 = f64::NAN; assert!(nan.is_nan()); assert!(!nan.is_infinite()); assert!(!nan.is_finite()); @@ -979,7 +978,7 @@ mod tests { #[test] fn test_infinity() { - let inf: f64 = INFINITY; + let inf: f64 = f64::INFINITY; assert!(inf.is_infinite()); assert!(!inf.is_finite()); assert!(inf.is_sign_positive()); @@ -991,7 +990,7 @@ mod tests { #[test] fn test_neg_infinity() { - let neg_inf: f64 = NEG_INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert!(neg_inf.is_infinite()); assert!(!neg_inf.is_finite()); assert!(!neg_inf.is_sign_positive()); @@ -1043,9 +1042,9 @@ mod tests { #[test] fn test_is_nan() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert!(nan.is_nan()); assert!(!0.0f64.is_nan()); assert!(!5.3f64.is_nan()); @@ -1056,9 +1055,9 @@ mod tests { #[test] fn test_is_infinite() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert!(!nan.is_infinite()); assert!(inf.is_infinite()); assert!(neg_inf.is_infinite()); @@ -1069,9 +1068,9 @@ mod tests { #[test] fn test_is_finite() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert!(!nan.is_finite()); assert!(!inf.is_finite()); assert!(!neg_inf.is_finite()); @@ -1083,9 +1082,9 @@ mod tests { #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn test_is_normal() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; let zero: f64 = 0.0f64; let neg_zero: f64 = -0.0; assert!(!nan.is_normal()); @@ -1101,9 +1100,9 @@ mod tests { #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn test_classify() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; let zero: f64 = 0.0f64; let neg_zero: f64 = -0.0; assert_eq!(nan.classify(), Fp::Nan); @@ -1187,59 +1186,59 @@ mod tests { #[test] fn test_abs() { - assert_eq!(INFINITY.abs(), INFINITY); + assert_eq!(f64::INFINITY.abs(), f64::INFINITY); assert_eq!(1f64.abs(), 1f64); assert_eq!(0f64.abs(), 0f64); assert_eq!((-0f64).abs(), 0f64); assert_eq!((-1f64).abs(), 1f64); - assert_eq!(NEG_INFINITY.abs(), INFINITY); - assert_eq!((1f64 / NEG_INFINITY).abs(), 0f64); - assert!(NAN.abs().is_nan()); + assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY); + assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64); + assert!(f64::NAN.abs().is_nan()); } #[test] fn test_signum() { - assert_eq!(INFINITY.signum(), 1f64); + assert_eq!(f64::INFINITY.signum(), 1f64); assert_eq!(1f64.signum(), 1f64); assert_eq!(0f64.signum(), 1f64); assert_eq!((-0f64).signum(), -1f64); assert_eq!((-1f64).signum(), -1f64); - assert_eq!(NEG_INFINITY.signum(), -1f64); - assert_eq!((1f64 / NEG_INFINITY).signum(), -1f64); - assert!(NAN.signum().is_nan()); + assert_eq!(f64::NEG_INFINITY.signum(), -1f64); + assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64); + assert!(f64::NAN.signum().is_nan()); } #[test] fn test_is_sign_positive() { - assert!(INFINITY.is_sign_positive()); + assert!(f64::INFINITY.is_sign_positive()); assert!(1f64.is_sign_positive()); assert!(0f64.is_sign_positive()); assert!(!(-0f64).is_sign_positive()); assert!(!(-1f64).is_sign_positive()); - assert!(!NEG_INFINITY.is_sign_positive()); - assert!(!(1f64 / NEG_INFINITY).is_sign_positive()); - assert!(NAN.is_sign_positive()); - assert!(!(-NAN).is_sign_positive()); + assert!(!f64::NEG_INFINITY.is_sign_positive()); + assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive()); + assert!(f64::NAN.is_sign_positive()); + assert!(!(-f64::NAN).is_sign_positive()); } #[test] fn test_is_sign_negative() { - assert!(!INFINITY.is_sign_negative()); + assert!(!f64::INFINITY.is_sign_negative()); assert!(!1f64.is_sign_negative()); assert!(!0f64.is_sign_negative()); assert!((-0f64).is_sign_negative()); assert!((-1f64).is_sign_negative()); - assert!(NEG_INFINITY.is_sign_negative()); - assert!((1f64 / NEG_INFINITY).is_sign_negative()); - assert!(!NAN.is_sign_negative()); - assert!((-NAN).is_sign_negative()); + assert!(f64::NEG_INFINITY.is_sign_negative()); + assert!((1f64 / f64::NEG_INFINITY).is_sign_negative()); + assert!(!f64::NAN.is_sign_negative()); + assert!((-f64::NAN).is_sign_negative()); } #[test] fn test_mul_add() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05); assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65); assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2); @@ -1253,9 +1252,9 @@ mod tests { #[test] fn test_recip() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert_eq!(1.0f64.recip(), 1.0); assert_eq!(2.0f64.recip(), 0.5); assert_eq!((-0.4f64).recip(), -2.5); @@ -1267,9 +1266,9 @@ mod tests { #[test] fn test_powi() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert_eq!(1.0f64.powi(1), 1.0); assert_approx_eq!((-3.1f64).powi(2), 9.61); assert_approx_eq!(5.9f64.powi(-2), 0.028727); @@ -1281,9 +1280,9 @@ mod tests { #[test] fn test_powf() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert_eq!(1.0f64.powf(1.0), 1.0); assert_approx_eq!(3.4f64.powf(4.5), 246.408183); assert_approx_eq!(2.7f64.powf(-3.2), 0.041652); @@ -1297,13 +1296,13 @@ mod tests { #[test] fn test_sqrt_domain() { - assert!(NAN.sqrt().is_nan()); - assert!(NEG_INFINITY.sqrt().is_nan()); + assert!(f64::NAN.sqrt().is_nan()); + assert!(f64::NEG_INFINITY.sqrt().is_nan()); assert!((-1.0f64).sqrt().is_nan()); assert_eq!((-0.0f64).sqrt(), -0.0); assert_eq!(0.0f64.sqrt(), 0.0); assert_eq!(1.0f64.sqrt(), 1.0); - assert_eq!(INFINITY.sqrt(), INFINITY); + assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY); } #[test] @@ -1312,9 +1311,9 @@ mod tests { assert_approx_eq!(2.718282, 1.0f64.exp()); assert_approx_eq!(148.413159, 5.0f64.exp()); - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; assert_eq!(inf, inf.exp()); assert_eq!(0.0, neg_inf.exp()); assert!(nan.exp().is_nan()); @@ -1325,9 +1324,9 @@ mod tests { assert_eq!(32.0, 5.0f64.exp2()); assert_eq!(1.0, 0.0f64.exp2()); - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; assert_eq!(inf, inf.exp2()); assert_eq!(0.0, neg_inf.exp2()); assert!(nan.exp2().is_nan()); @@ -1335,9 +1334,9 @@ mod tests { #[test] fn test_ln() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert_approx_eq!(1.0f64.exp().ln(), 1.0); assert!(nan.ln().is_nan()); assert_eq!(inf.ln(), inf); @@ -1350,9 +1349,9 @@ mod tests { #[test] fn test_log() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert_eq!(10.0f64.log(10.0), 1.0); assert_approx_eq!(2.3f64.log(3.5), 0.664858); assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); @@ -1368,9 +1367,9 @@ mod tests { #[test] fn test_log2() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert_approx_eq!(10.0f64.log2(), 3.321928); assert_approx_eq!(2.3f64.log2(), 1.201634); assert_approx_eq!(1.0f64.exp().log2(), 1.442695); @@ -1384,9 +1383,9 @@ mod tests { #[test] fn test_log10() { - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert_eq!(10.0f64.log10(), 1.0); assert_approx_eq!(2.3f64.log10(), 0.361728); assert_approx_eq!(1.0f64.exp().log10(), 0.434294); @@ -1402,9 +1401,9 @@ mod tests { #[test] fn test_to_degrees() { let pi: f64 = consts::PI; - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert_eq!(0.0f64.to_degrees(), 0.0); assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); assert_eq!(pi.to_degrees(), 180.0); @@ -1416,9 +1415,9 @@ mod tests { #[test] fn test_to_radians() { let pi: f64 = consts::PI; - let nan: f64 = NAN; - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; assert_eq!(0.0f64.to_radians(), 0.0); assert_approx_eq!(154.6f64.to_radians(), 2.698279); assert_approx_eq!((-332.31f64).to_radians(), -5.799903); @@ -1433,9 +1432,9 @@ mod tests { assert_eq!(0.0f64.asinh(), 0.0f64); assert_eq!((-0.0f64).asinh(), -0.0f64); - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; assert_eq!(inf.asinh(), inf); assert_eq!(neg_inf.asinh(), neg_inf); assert!(nan.asinh().is_nan()); @@ -1450,9 +1449,9 @@ mod tests { assert_eq!(1.0f64.acosh(), 0.0f64); assert!(0.999f64.acosh().is_nan()); - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; assert_eq!(inf.acosh(), inf); assert!(neg_inf.acosh().is_nan()); assert!(nan.acosh().is_nan()); @@ -1465,9 +1464,9 @@ mod tests { assert_eq!(0.0f64.atanh(), 0.0f64); assert_eq!((-0.0f64).atanh(), -0.0f64); - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; assert_eq!(1.0f64.atanh(), inf); assert_eq!((-1.0f64).atanh(), neg_inf); assert!(2f64.atanh().atanh().is_nan()); @@ -1546,13 +1545,13 @@ mod tests { #[test] #[should_panic] fn test_clamp_min_is_nan() { - let _ = 1.0f64.clamp(NAN, 1.0); + let _ = 1.0f64.clamp(f64::NAN, 1.0); } #[test] #[should_panic] fn test_clamp_max_is_nan() { - let _ = 1.0f64.clamp(3.0, NAN); + let _ = 1.0f64.clamp(3.0, f64::NAN); } #[test] diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 4bac9a4917d..b324b161896 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -395,6 +395,12 @@ impl CString { /// ownership of a string that was allocated by foreign code) is likely to lead /// to undefined behavior or allocator corruption. /// + /// It should be noted that the length isn't just "recomputed," but that + /// the recomputed length must match the original length from the + /// [`into_raw`] call. This means the [`into_raw`]/`from_raw` methods + /// should not be used when passing the string to C functions that can + /// modify the string's length. + /// /// > **Note:** If you need to borrow a string that was allocated by /// > foreign code, use [`CStr`]. If you need to take ownership of /// > a string that was allocated by foreign code, you will need to @@ -440,6 +446,11 @@ impl CString { /// /// Failure to call [`from_raw`] will lead to a memory leak. /// + /// The C side must **not** modify the length of the string (by writing a + /// `NULL` somewhere inside the string or removing the final one) before + /// it makes it back into Rust using [`from_raw`]. See the safety section + /// in [`from_raw`]. + /// /// [`from_raw`]: #method.from_raw /// /// # Examples diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index e986a39eb03..0737008a94c 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -366,7 +366,7 @@ impl<R: Seek> Seek for BufReader<R> { // it should be safe to assume that remainder fits within an i64 as the alternative // means we managed to allocate 8 exbibytes and that's absurd. // But it's not out of the realm of possibility for some weird underlying reader to - // support seeking by i64::min_value() so we need to handle underflow when subtracting + // support seeking by i64::MIN so we need to handle underflow when subtracting // remainder. if let Some(offset) = n.checked_sub(remainder) { result = self.inner.seek(SeekFrom::Current(offset))?; @@ -1268,7 +1268,7 @@ mod tests { self.pos = self.pos.wrapping_add(n as u64); } SeekFrom::End(n) => { - self.pos = u64::max_value().wrapping_add(n as u64); + self.pos = u64::MAX.wrapping_add(n as u64); } } Ok(self.pos) @@ -1277,11 +1277,11 @@ mod tests { let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); - assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::max_value() - 5)); + assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5)); assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); // the following seek will require two underlying seeks let expected = 9223372036854775802; - assert_eq!(reader.seek(SeekFrom::Current(i64::min_value())).ok(), Some(expected)); + assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).ok(), Some(expected)); assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); // seeking to 0 should empty the buffer. assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); @@ -1319,7 +1319,7 @@ mod tests { // The following seek will require two underlying seeks. The first will // succeed but the second will fail. This should still invalidate the // buffer. - assert!(reader.seek(SeekFrom::Current(i64::min_value())).is_err()); + assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err()); assert_eq!(reader.buffer().len(), 0); } diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index f3e3fc81a5d..f4db5f81450 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -963,7 +963,7 @@ mod tests { #[cfg(target_pointer_width = "32")] fn vec_seek_and_write_past_usize_max() { let mut c = Cursor::new(Vec::new()); - c.set_position(<usize>::max_value() as u64 + 1); + c.set_position(usize::MAX as u64 + 1); assert!(c.write_all(&[1, 2, 3]).is_err()); } diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 6fbb0139b0e..a4996d9eee8 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1213,9 +1213,61 @@ mod unsafe_keyword {} // /// Import or rename items from other crates or modules. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// Usually a `use` keyword is used to shorten the path required to refer to a module item. +/// The keyword may appear in modules, blocks and even functions, usually at the top. +/// +/// The most basic usage of the keyword is `use path::to::item;`, +/// though a number of convenient shortcuts are supported: +/// +/// * Simultaneously binding a list of paths with a common prefix, +/// using the glob-like brace syntax `use a::b::{c, d, e::f, g::h::i};` +/// * Simultaneously binding a list of paths with a common prefix and their common parent module, +/// using the [`self`] keyword, such as `use a::b::{self, c, d::e};` +/// * Rebinding the target name as a new local name, using the syntax `use p::q::r as x;`. +/// This can also be used with the last two features: `use a::b::{self as ab, c as abc}`. +/// * Binding all paths matching a given prefix, +/// using the asterisk wildcard syntax `use a::b::*;`. +/// * Nesting groups of the previous features multiple times, +/// such as `use a::b::{self as ab, c, d::{*, e::f}};` +/// * Reexporting with visibility modifiers such as `pub use a::b;` +/// * Importing with `_` to only import the methods of a trait without binding it to a name +/// (to avoid conflict for example): `use ::std::io::Read as _;`. +/// +/// Using path qualifiers like [`crate`], [`super`] or [`self`] is supported: `use crate::a::b;`. +/// +/// Note that when the wildcard `*` is used on a type, it does not import its methods (though +/// for `enum`s it imports the variants, as shown in the example below). +/// +/// ```compile_fail,edition2018 +/// enum ExampleEnum { +/// VariantA, +/// VariantB, +/// } /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// impl ExampleEnum { +/// fn new() -> Self { +/// Self::VariantA +/// } +/// } +/// +/// use ExampleEnum::*; +/// +/// // Compiles. +/// let _ = VariantA; +/// +/// // Does not compile ! +/// let n = new(); +/// ``` +/// +/// For more information on `use` and paths in general, see the [Reference]. +/// +/// The differences about paths and the `use` keyword between the 2015 and 2018 editions +/// can also be found in the [Reference]. +/// +/// [`crate`]: keyword.crate.html +/// [`self`]: keyword.self.html +/// [`super`]: keyword.super.html +/// [Reference]: ../reference/items/use-declarations.html mod use_keyword {} #[doc(keyword = "where")] diff --git a/src/libstd/num.rs b/src/libstd/num.rs index de8acf8d9d4..b496c16a749 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -52,52 +52,43 @@ where #[cfg(test)] mod tests { use crate::ops::Mul; - use crate::u16; - use crate::u32; - use crate::u64; - use crate::u8; - use crate::usize; #[test] fn test_saturating_add_uint() { - use crate::usize::MAX; assert_eq!(3_usize.saturating_add(5_usize), 8_usize); - assert_eq!(3_usize.saturating_add(MAX - 1), MAX); - assert_eq!(MAX.saturating_add(MAX), MAX); - assert_eq!((MAX - 2).saturating_add(1), MAX - 1); + assert_eq!(3_usize.saturating_add(usize::MAX - 1), usize::MAX); + assert_eq!(usize::MAX.saturating_add(usize::MAX), usize::MAX); + assert_eq!((usize::MAX - 2).saturating_add(1), usize::MAX - 1); } #[test] fn test_saturating_sub_uint() { - use crate::usize::MAX; assert_eq!(5_usize.saturating_sub(3_usize), 2_usize); assert_eq!(3_usize.saturating_sub(5_usize), 0_usize); assert_eq!(0_usize.saturating_sub(1_usize), 0_usize); - assert_eq!((MAX - 1).saturating_sub(MAX), 0); + assert_eq!((usize::MAX - 1).saturating_sub(usize::MAX), 0); } #[test] fn test_saturating_add_int() { - use crate::isize::{MAX, MIN}; assert_eq!(3i32.saturating_add(5), 8); - assert_eq!(3isize.saturating_add(MAX - 1), MAX); - assert_eq!(MAX.saturating_add(MAX), MAX); - assert_eq!((MAX - 2).saturating_add(1), MAX - 1); + assert_eq!(3isize.saturating_add(isize::MAX - 1), isize::MAX); + assert_eq!(isize::MAX.saturating_add(isize::MAX), isize::MAX); + assert_eq!((isize::MAX - 2).saturating_add(1), isize::MAX - 1); assert_eq!(3i32.saturating_add(-5), -2); - assert_eq!(MIN.saturating_add(-1), MIN); - assert_eq!((-2isize).saturating_add(-MAX), MIN); + assert_eq!(isize::MIN.saturating_add(-1), isize::MIN); + assert_eq!((-2isize).saturating_add(-isize::MAX), isize::MIN); } #[test] fn test_saturating_sub_int() { - use crate::isize::{MAX, MIN}; assert_eq!(3i32.saturating_sub(5), -2); - assert_eq!(MIN.saturating_sub(1), MIN); - assert_eq!((-2isize).saturating_sub(MAX), MIN); + assert_eq!(isize::MIN.saturating_sub(1), isize::MIN); + assert_eq!((-2isize).saturating_sub(isize::MAX), isize::MIN); assert_eq!(3i32.saturating_sub(-5), 8); - assert_eq!(3isize.saturating_sub(-(MAX - 1)), MAX); - assert_eq!(MAX.saturating_sub(-MAX), MAX); - assert_eq!((MAX - 2).saturating_sub(-1), MAX - 1); + assert_eq!(3isize.saturating_sub(-(isize::MAX - 1)), isize::MAX); + assert_eq!(isize::MAX.saturating_sub(-isize::MAX), isize::MAX); + assert_eq!((isize::MAX - 2).saturating_sub(-1), isize::MAX - 1); } #[test] diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 77e521eae9a..2250c0d4203 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -609,7 +609,6 @@ mod tests { use crate::sync::{Arc, Condvar, Mutex}; use crate::thread; use crate::time::Duration; - use crate::u64; #[test] fn smoke() { diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index e70204d6839..d6cc811154f 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -2176,8 +2176,7 @@ mod tests { #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn very_long_recv_timeout_wont_panic() { let (tx, rx) = channel::<()>(); - let join_handle = - thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::max_value()))); + let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX))); thread::sleep(Duration::from_secs(1)); assert!(tx.send(()).is_ok()); assert_eq!(join_handle.join().unwrap(), Ok(())); diff --git a/src/libstd/sys/cloudabi/condvar.rs b/src/libstd/sys/cloudabi/condvar.rs index 3ba51d77494..dabdc0c9b51 100644 --- a/src/libstd/sys/cloudabi/condvar.rs +++ b/src/libstd/sys/cloudabi/condvar.rs @@ -42,7 +42,7 @@ impl Condvar { let ret = abi::condvar_signal( condvar as *mut abi::condvar, abi::scope::PRIVATE, - abi::nthreads::max_value(), + abi::nthreads::MAX, ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to broadcast on condition variable"); } diff --git a/src/libstd/sys/hermit/condvar.rs b/src/libstd/sys/hermit/condvar.rs index 94e3275448a..132e579b3a5 100644 --- a/src/libstd/sys/hermit/condvar.rs +++ b/src/libstd/sys/hermit/condvar.rs @@ -35,7 +35,7 @@ impl Condvar { pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { let nanos = dur.as_nanos(); - let nanos = cmp::min(i64::max_value() as u128, nanos); + let nanos = cmp::min(i64::MAX as u128, nanos); // add current task to the wait queue let _ = abi::add_queue(self.id(), nanos as i64); diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S index 1f06c9da3a9..2badfc973c9 100644 --- a/src/libstd/sys/sgx/abi/entry.S +++ b/src/libstd/sys/sgx/abi/entry.S @@ -324,7 +324,9 @@ usercall: /* return */ mov %rsi,%rax /* RAX = return value */ /* NOP: mov %rdx,%rdx */ /* RDX = return value */ - ret + pop %r11 + lfence + jmp *%r11 /* The following functions need to be defined externally: @@ -343,20 +345,28 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64 .global get_tcs_addr get_tcs_addr: mov %gs:tcsls_tcs_addr,%rax - ret + pop %r11 + lfence + jmp *%r11 .global get_tls_ptr get_tls_ptr: mov %gs:tcsls_tls_ptr,%rax - ret + pop %r11 + lfence + jmp *%r11 .global set_tls_ptr set_tls_ptr: mov %rdi,%gs:tcsls_tls_ptr - ret + pop %r11 + lfence + jmp *%r11 .global take_debug_panic_buf_ptr take_debug_panic_buf_ptr: xor %rax,%rax xchg %gs:tcsls_debug_panic_buf_ptr,%rax - ret + pop %r11 + lfence + jmp *%r11 diff --git a/src/libstd/sys/unix/android.rs b/src/libstd/sys/unix/android.rs index 8fc2599f0d7..ea05ee3d7ce 100644 --- a/src/libstd/sys/unix/android.rs +++ b/src/libstd/sys/unix/android.rs @@ -95,7 +95,7 @@ pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { match ftruncate64.get() { Some(f) => cvt_r(|| f(fd, size as i64)).map(drop), None => { - if size > i32::max_value() as u64 { + if size > i32::MAX as u64 { Err(io::Error::new(io::ErrorKind::InvalidInput, "cannot truncate >2GB")) } else { cvt_r(|| ftruncate(fd, size as i32)).map(drop) diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index b4896b7ad74..9f1847943f3 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -10,14 +10,10 @@ unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} const TIMESPEC_MAX: libc::timespec = - libc::timespec { tv_sec: <libc::time_t>::max_value(), tv_nsec: 1_000_000_000 - 1 }; + libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 }; fn saturating_cast_to_time_t(value: u64) -> libc::time_t { - if value > <libc::time_t>::max_value() as u64 { - <libc::time_t>::max_value() - } else { - value as libc::time_t - } + if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t } } impl Condvar { diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 32c2ac43129..cd24605ec7a 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -1090,7 +1090,7 @@ impl<'a> Iterator for Incoming<'a> { } fn size_hint(&self) -> (usize, Option<usize>) { - (usize::max_value(), None) + (usize::MAX, None) } } diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 1ef7ffacfcf..c481ca8961f 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -23,11 +23,7 @@ fn max_len() -> usize { // intentionally showing odd behavior by rejecting any read with a size // larger than or equal to INT_MAX. To handle both of these the read // size is capped on both platforms. - if cfg!(target_os = "macos") { - <c_int>::max_value() as usize - 1 - } else { - <ssize_t>::max_value() as usize - } + if cfg!(target_os = "macos") { <c_int>::MAX as usize - 1 } else { <ssize_t>::MAX as usize } } impl FileDesc { @@ -58,7 +54,7 @@ impl FileDesc { libc::readv( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + cmp::min(bufs.len(), c_int::MAX as usize) as c_int, ) })?; Ok(ret as usize) @@ -115,7 +111,7 @@ impl FileDesc { libc::writev( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + cmp::min(bufs.len(), c_int::MAX as usize) as c_int, ) })?; Ok(ret as usize) diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 80cf6a5dbc2..29cdbf05354 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -1196,7 +1196,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { let mut written = 0u64; while written < len { let copy_result = if has_copy_file_range { - let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize; + let bytes_to_copy = cmp::min(len - written, usize::MAX as u64) as usize; let copy_result = unsafe { // We actually don't have to adjust the offsets, // because copy_file_range adjusts the file offset automatically diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index f062bc012f7..3717c660b57 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -148,7 +148,7 @@ impl Socket { timeout = 1; } - let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; + let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int; match unsafe { libc::poll(&mut pollfd, 1, timeout) } { -1 => { @@ -283,8 +283,8 @@ impl Socket { )); } - let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { - libc::time_t::max_value() + let secs = if dur.as_secs() > libc::time_t::MAX as u64 { + libc::time_t::MAX } else { dur.as_secs() as libc::time_t }; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 895ea48e2b4..7b3d69dcaa0 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -171,7 +171,7 @@ impl Thread { unsafe { while secs > 0 || nsecs > 0 { let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, + tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t, tv_nsec: nsecs, }; secs -= ts.tv_sec as u64; diff --git a/src/libstd/sys/vxworks/condvar.rs b/src/libstd/sys/vxworks/condvar.rs index f2a1d681529..5a77966d974 100644 --- a/src/libstd/sys/vxworks/condvar.rs +++ b/src/libstd/sys/vxworks/condvar.rs @@ -10,14 +10,10 @@ unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} const TIMESPEC_MAX: libc::timespec = - libc::timespec { tv_sec: <libc::time_t>::max_value(), tv_nsec: 1_000_000_000 - 1 }; + libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 }; fn saturating_cast_to_time_t(value: u64) -> libc::time_t { - if value > <libc::time_t>::max_value() as u64 { - <libc::time_t>::max_value() - } else { - value as libc::time_t - } + if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t } } impl Condvar { diff --git a/src/libstd/sys/vxworks/fd.rs b/src/libstd/sys/vxworks/fd.rs index 23e9dc428ce..7fa86f0db04 100644 --- a/src/libstd/sys/vxworks/fd.rs +++ b/src/libstd/sys/vxworks/fd.rs @@ -17,7 +17,7 @@ fn max_len() -> usize { // The maximum read limit on most posix-like systems is `SSIZE_MAX`, // with the man page quoting that if the count of bytes to read is // greater than `SSIZE_MAX` the result is "unspecified". - <ssize_t>::max_value() as usize + <ssize_t>::MAX as usize } impl FileDesc { @@ -48,7 +48,7 @@ impl FileDesc { libc::readv( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + cmp::min(bufs.len(), c_int::MAX as usize) as c_int, ) })?; Ok(ret as usize) @@ -98,7 +98,7 @@ impl FileDesc { libc::writev( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + cmp::min(bufs.len(), c_int::MAX as usize) as c_int, ) })?; Ok(ret as usize) diff --git a/src/libstd/sys/vxworks/net.rs b/src/libstd/sys/vxworks/net.rs index de0b15b43a2..32c27ab6e9e 100644 --- a/src/libstd/sys/vxworks/net.rs +++ b/src/libstd/sys/vxworks/net.rs @@ -107,7 +107,7 @@ impl Socket { timeout = 1; } - let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; + let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int; match unsafe { libc::poll(&mut pollfd, 1, timeout) } { -1 => { @@ -220,8 +220,8 @@ impl Socket { )); } - let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { - libc::time_t::max_value() + let secs = if dur.as_secs() > libc::time_t::MAX as u64 { + libc::time_t::MAX } else { dur.as_secs() as libc::time_t }; diff --git a/src/libstd/sys/vxworks/thread.rs b/src/libstd/sys/vxworks/thread.rs index 4d0196e4b4d..24a2e0f965d 100644 --- a/src/libstd/sys/vxworks/thread.rs +++ b/src/libstd/sys/vxworks/thread.rs @@ -96,7 +96,7 @@ impl Thread { unsafe { while secs > 0 || nsecs > 0 { let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, + tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t, tv_nsec: nsecs, }; secs -= ts.tv_sec as u64; diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs index 29fafaaa0b9..4fe9661421b 100644 --- a/src/libstd/sys/wasi/mod.rs +++ b/src/libstd/sys/wasi/mod.rs @@ -64,7 +64,7 @@ pub fn unsupported_err() -> std_io::Error { pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { use std_io::ErrorKind::*; - if errno > u16::max_value() as i32 || errno < 0 { + if errno > u16::MAX as i32 || errno < 0 { return Other; } match errno as u16 { diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs index 0986759b89b..0d39b1cec32 100644 --- a/src/libstd/sys/wasi/thread.rs +++ b/src/libstd/sys/wasi/thread.rs @@ -25,7 +25,7 @@ impl Thread { pub fn sleep(dur: Duration) { let nanos = dur.as_nanos(); - assert!(nanos <= u64::max_value() as u128); + assert!(nanos <= u64::MAX as u128); const USERDATA: wasi::Userdata = 0x0123_45678; diff --git a/src/libstd/sys/wasm/condvar_atomics.rs b/src/libstd/sys/wasm/condvar_atomics.rs index a4021c0ee83..1859cdd5a0e 100644 --- a/src/libstd/sys/wasm/condvar_atomics.rs +++ b/src/libstd/sys/wasm/condvar_atomics.rs @@ -48,7 +48,7 @@ impl Condvar { #[inline] pub unsafe fn notify_all(&self) { self.cnt.fetch_add(1, SeqCst); - wasm32::atomic_notify(self.ptr(), u32::max_value()); // -1 == "wake everyone" + wasm32::atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone" } pub unsafe fn wait(&self, mutex: &Mutex) { @@ -72,7 +72,7 @@ impl Condvar { let ticket = self.cnt.load(SeqCst) as i32; mutex.unlock(); let nanos = dur.as_nanos(); - let nanos = cmp::min(i64::max_value() as u128, nanos); + let nanos = cmp::min(i64::MAX as u128, nanos); // If the return value is 2 then a timeout happened, so we return // `false` as we weren't actually notified. diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 0e0e78a8276..0a11896a004 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -38,7 +38,7 @@ impl Thread { // 2). let mut nanos = dur.as_nanos(); while nanos > 0 { - let amt = cmp::min(i64::max_value() as u128, nanos); + let amt = cmp::min(i64::MAX as u128, nanos); let mut x = 0; let val = unsafe { wasm32::i32_atomic_wait(&mut x, 0, amt as i64) }; debug_assert_eq!(val, 2); diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index 2131cfc2c94..0d4baa3b340 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -70,7 +70,7 @@ impl RawHandle { pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { let mut read = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; let res = cvt(unsafe { c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, ptr::null_mut()) }); @@ -99,7 +99,7 @@ impl RawHandle { pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { let mut read = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; let res = unsafe { let mut overlapped: c::OVERLAPPED = mem::zeroed(); overlapped.Offset = offset as u32; @@ -118,7 +118,7 @@ impl RawHandle { buf: &mut [u8], overlapped: *mut c::OVERLAPPED, ) -> io::Result<Option<usize>> { - let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; let mut amt = 0; let res = cvt(c::ReadFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, overlapped)); match res { @@ -165,7 +165,7 @@ impl RawHandle { pub fn write(&self, buf: &[u8]) -> io::Result<usize> { let mut amt = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; cvt(unsafe { c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, ptr::null_mut()) })?; @@ -183,7 +183,7 @@ impl RawHandle { pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { let mut written = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; unsafe { let mut overlapped: c::OVERLAPPED = mem::zeroed(); overlapped.Offset = offset as u32; diff --git a/src/libstd/sys/windows/io.rs b/src/libstd/sys/windows/io.rs index 5525d283252..fb06df1f80c 100644 --- a/src/libstd/sys/windows/io.rs +++ b/src/libstd/sys/windows/io.rs @@ -12,7 +12,7 @@ pub struct IoSlice<'a> { impl<'a> IoSlice<'a> { #[inline] pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - assert!(buf.len() <= c::ULONG::max_value() as usize); + assert!(buf.len() <= c::ULONG::MAX as usize); IoSlice { vec: c::WSABUF { len: buf.len() as c::ULONG, @@ -49,7 +49,7 @@ pub struct IoSliceMut<'a> { impl<'a> IoSliceMut<'a> { #[inline] pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - assert!(buf.len() <= c::ULONG::max_value() as usize); + assert!(buf.len() <= c::ULONG::MAX as usize); IoSliceMut { vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_mut_ptr() as *mut c::CHAR }, _p: PhantomData, diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 69877e68ba8..d63139d8052 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -295,7 +295,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { .checked_mul(1000) .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)) .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 })) - .map(|ms| if ms > <c::DWORD>::max_value() as u64 { c::INFINITE } else { ms as c::DWORD }) + .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD }) .unwrap_or(c::INFINITE) } diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index a15ded92f08..9e74454bc23 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -228,7 +228,7 @@ impl Socket { fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. - let len = cmp::min(buf.len(), i32::max_value() as usize) as i32; + let len = cmp::min(buf.len(), i32::MAX as usize) as i32; unsafe { match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) { -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), @@ -245,7 +245,7 @@ impl Socket { pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. - let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD; + let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; let mut nread = 0; let mut flags = 0; unsafe { @@ -282,7 +282,7 @@ impl Socket { ) -> io::Result<(usize, SocketAddr)> { let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() }; let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; - let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t; + let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. @@ -313,7 +313,7 @@ impl Socket { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD; + let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; let mut nwritten = 0; unsafe { cvt(c::WSASend( diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index 1c03bc92344..81a5ef95e82 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -271,7 +271,7 @@ impl TcpStream { } pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t; + let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; let ret = cvt(unsafe { c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) })?; @@ -502,7 +502,7 @@ impl UdpSocket { } pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> { - let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t; + let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; let (dstp, dstlen) = dst.into_inner(); let ret = cvt(unsafe { c::sendto( @@ -641,7 +641,7 @@ impl UdpSocket { } pub fn send(&self, buf: &[u8]) -> io::Result<usize> { - let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t; + let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; let ret = cvt(unsafe { c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) })?; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 3134a596756..d435ca68425 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -1530,7 +1530,6 @@ mod tests { use crate::sync::mpsc::{channel, Sender}; use crate::thread::{self, ThreadId}; use crate::time::Duration; - use crate::u32; // !!! These tests are dangerous. If something is buggy, they will hang, !!! // !!! instead of exiting cleanly. This might wedge the buildbots. !!! diff --git a/src/libstd/time.rs b/src/libstd/time.rs index c36e78b1d00..bc3bfde6d75 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -686,7 +686,7 @@ mod tests { // checked_add_duration will not panic on overflow let mut maybe_t = Some(Instant::now()); - let max_duration = Duration::from_secs(u64::max_value()); + let max_duration = Duration::from_secs(u64::MAX); // in case `Instant` can store `>= now + max_duration`. for _ in 0..2 { maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); @@ -766,7 +766,7 @@ mod tests { // checked_add_duration will not panic on overflow let mut maybe_t = Some(SystemTime::UNIX_EPOCH); - let max_duration = Duration::from_secs(u64::max_value()); + let max_duration = Duration::from_secs(u64::MAX); // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`. for _ in 0..2 { maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); diff --git a/src/libtest/cli.rs b/src/libtest/cli.rs index 0cec8050c27..97a659f22d7 100644 --- a/src/libtest/cli.rs +++ b/src/libtest/cli.rs @@ -115,7 +115,7 @@ fn optgroups() -> getopts::Options { .optflagopt( "", "report-time", - "Show execution time of each test. Awailable values: + "Show execution time of each test. Available values: plain = do not colorize the execution time (default); colored = colorize output according to the `color` parameter value; diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index 00749d93d55..f6f16f686e5 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -36,12 +36,6 @@ fn main() { println!("cargo:rustc-link-lib=gcc_pic"); } else if target.contains("pc-windows-gnu") { // This is handled in the target spec with late_link_args_[static|dynamic] - - // cfg!(bootstrap) doesn't work in build scripts - if env::var("RUSTC_STAGE").ok() == Some("0".to_string()) { - println!("cargo:rustc-link-lib=static-nobundle=gcc_eh"); - println!("cargo:rustc-link-lib=static-nobundle=pthread"); - } } else if target.contains("uwp-windows-gnu") { println!("cargo:rustc-link-lib=unwind"); } else if target.contains("fuchsia") { diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 02dcfb8e829..3d252fe70af 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -203,6 +203,12 @@ void LLVMRustAddLastExtensionPasses( #define SUBTARGET_AARCH64 #endif +#ifdef LLVM_COMPONENT_AVR +#define SUBTARGET_AVR SUBTARGET(AVR) +#else +#define SUBTARGET_AVR +#endif + #ifdef LLVM_COMPONENT_MIPS #define SUBTARGET_MIPS SUBTARGET(Mips) #else @@ -249,6 +255,7 @@ void LLVMRustAddLastExtensionPasses( SUBTARGET_X86 \ SUBTARGET_ARM \ SUBTARGET_AARCH64 \ + SUBTARGET_AVR \ SUBTARGET_MIPS \ SUBTARGET_PPC \ SUBTARGET_SYSTEMZ \ diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 6fac2662506..4704622922a 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1094,8 +1094,17 @@ extern "C" void LLVMRustUnpackOptimizationDiagnostic( MessageOS << Opt->getMsg(); } +enum class LLVMRustDiagnosticLevel { + Error, + Warning, + Note, + Remark, +}; + extern "C" void -LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI, unsigned *CookieOut, +LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI, + LLVMRustDiagnosticLevel *LevelOut, + unsigned *CookieOut, LLVMTwineRef *MessageOut, LLVMValueRef *InstructionOut) { // Undefined to call this not on an inline assembly diagnostic! @@ -1105,6 +1114,23 @@ LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI, unsigned *CookieOut, *CookieOut = IA->getLocCookie(); *MessageOut = wrap(&IA->getMsgStr()); *InstructionOut = wrap(IA->getInstruction()); + + switch (IA->getSeverity()) { + case DS_Error: + *LevelOut = LLVMRustDiagnosticLevel::Error; + break; + case DS_Warning: + *LevelOut = LLVMRustDiagnosticLevel::Warning; + break; + case DS_Note: + *LevelOut = LLVMRustDiagnosticLevel::Note; + break; + case DS_Remark: + *LevelOut = LLVMRustDiagnosticLevel::Remark; + break; + default: + report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); + } } extern "C" void LLVMRustWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef DI, @@ -1166,6 +1192,7 @@ extern "C" LLVMRustDiagnosticKind LLVMRustGetDiagInfoKind(LLVMDiagnosticInfoRef DI) { return toRust((DiagnosticKind)unwrap(DI)->getKind()); } + // This is kept distinct from LLVMGetTypeKind, because when // a new type kind is added, the Rust-side enum must be // updated or UB will result. @@ -1219,6 +1246,7 @@ extern "C" void LLVMRustSetInlineAsmDiagnosticHandler( extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RustStringRef MessageOut, RustStringRef BufferOut, + LLVMRustDiagnosticLevel* LevelOut, unsigned* LocOut, unsigned* RangesOut, size_t* NumRanges) { @@ -1226,6 +1254,23 @@ extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RawRustStringOstream MessageOS(MessageOut); MessageOS << D.getMessage(); + switch (D.getKind()) { + case SourceMgr::DK_Error: + *LevelOut = LLVMRustDiagnosticLevel::Error; + break; + case SourceMgr::DK_Warning: + *LevelOut = LLVMRustDiagnosticLevel::Warning; + break; + case SourceMgr::DK_Note: + *LevelOut = LLVMRustDiagnosticLevel::Note; + break; + case SourceMgr::DK_Remark: + *LevelOut = LLVMRustDiagnosticLevel::Remark; + break; + default: + report_fatal_error("Invalid LLVMRustDiagnosticLevel value!"); + } + if (D.getLoc() == SMLoc()) return false; diff --git a/src/test/codegen/abi-main-signature-16bit-c-int.rs b/src/test/codegen/abi-main-signature-16bit-c-int.rs index d7b8c48c33e..4ed491dfb2b 100644 --- a/src/test/codegen/abi-main-signature-16bit-c-int.rs +++ b/src/test/codegen/abi-main-signature-16bit-c-int.rs @@ -10,6 +10,7 @@ // ignore-mips64 // ignore-powerpc // ignore-powerpc64 +// ignore-riscv64 // ignore-s390x // ignore-sparc // ignore-sparc64 diff --git a/src/test/codegen/abi-sysv64.rs b/src/test/codegen/abi-sysv64.rs index 6456ad47615..89c9bcee052 100644 --- a/src/test/codegen/abi-sysv64.rs +++ b/src/test/codegen/abi-sysv64.rs @@ -4,6 +4,7 @@ // ignore-arm // ignore-aarch64 +// ignore-riscv64 sysv64 not supported // compile-flags: -C no-prepopulate-passes diff --git a/src/test/codegen/abi-x86-interrupt.rs b/src/test/codegen/abi-x86-interrupt.rs index db215860f20..25c155c949d 100644 --- a/src/test/codegen/abi-x86-interrupt.rs +++ b/src/test/codegen/abi-x86-interrupt.rs @@ -4,6 +4,7 @@ // ignore-arm // ignore-aarch64 +// ignore-riscv64 x86-interrupt is not supported // compile-flags: -C no-prepopulate-passes diff --git a/src/test/codegen/call-llvm-intrinsics.rs b/src/test/codegen/call-llvm-intrinsics.rs index c7a464a9b0e..24e3d3cd64b 100644 --- a/src/test/codegen/call-llvm-intrinsics.rs +++ b/src/test/codegen/call-llvm-intrinsics.rs @@ -1,5 +1,7 @@ // compile-flags: -C no-prepopulate-passes +// ignore-riscv64 + #![feature(link_llvm_intrinsics)] #![crate_type = "lib"] diff --git a/src/test/codegen/catch-unwind.rs b/src/test/codegen/catch-unwind.rs index 3c9bc35d1c8..7ff9c0d15e0 100644 --- a/src/test/codegen/catch-unwind.rs +++ b/src/test/codegen/catch-unwind.rs @@ -1,5 +1,14 @@ // compile-flags: -O +// On x86 the closure is inlined in foo() producting something like +// define i32 @foo() [...] { +// tail call void @bar() [...] +// ret i32 0 +// } +// On riscv the closure is another function, placed before fn foo so CHECK can't +// find it +// ignore-riscv64 FIXME + #![crate_type = "lib"] extern "C" { diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs index f67487c83ba..adbeae45449 100644 --- a/src/test/codegen/fastcall-inreg.rs +++ b/src/test/codegen/fastcall-inreg.rs @@ -17,6 +17,7 @@ // ignore-powerpc64le // ignore-powerpc // ignore-r600 +// ignore-riscv64 // ignore-amdgcn // ignore-sparc // ignore-sparc64 diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index 018a7ba4756..c23c57c8c59 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -7,6 +7,7 @@ // ignore-mips64 // ignore-powerpc // ignore-powerpc64 +// ignore-riscv64 see codegen/riscv-abi // ignore-windows // See repr-transparent.rs diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs index 56698586720..07e5af11f35 100644 --- a/src/test/codegen/repr-transparent-aggregates-2.rs +++ b/src/test/codegen/repr-transparent-aggregates-2.rs @@ -6,6 +6,7 @@ // ignore-powerpc // ignore-powerpc64 // ignore-powerpc64le +// ignore-riscv64 see codegen/riscv-abi // ignore-s390x // ignore-sparc // ignore-sparc64 diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs index 49fd015624a..7647e019876 100644 --- a/src/test/codegen/repr-transparent.rs +++ b/src/test/codegen/repr-transparent.rs @@ -1,5 +1,8 @@ // compile-flags: -C no-prepopulate-passes +// ignore-riscv64 riscv64 has an i128 type used with test_Vector +// see codegen/riscv-abi for riscv functiona call tests + #![crate_type="lib"] #![feature(repr_simd, transparent_unions)] diff --git a/src/test/codegen/riscv-abi/call-llvm-intrinsics.rs b/src/test/codegen/riscv-abi/call-llvm-intrinsics.rs new file mode 100644 index 00000000000..f100a23a318 --- /dev/null +++ b/src/test/codegen/riscv-abi/call-llvm-intrinsics.rs @@ -0,0 +1,30 @@ +// compile-flags: -C no-prepopulate-passes + +// only-riscv64 + +#![feature(link_llvm_intrinsics)] +#![crate_type = "lib"] + +struct A; + +impl Drop for A { + fn drop(&mut self) { + println!("A"); + } +} + +extern { + #[link_name = "llvm.sqrt.f32"] + fn sqrt(x: f32) -> f32; +} + +pub fn do_call() { + let _a = A; + + unsafe { + // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them + // CHECK: store float 4.000000e+00, float* %{{.}}, align 4 + // CHECK: call float @llvm.sqrt.f32(float %{{.}} + sqrt(4.0); + } +} diff --git a/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs index f0f052fe5c5..180ba07764b 100644 --- a/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs +++ b/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs @@ -39,12 +39,12 @@ pub extern "C" fn f_scalar_4(x: i64) -> i64 { x } -// CHECK: define float @f_fp_scalar_1(float) +// CHECK: define float @f_fp_scalar_1(float %0) #[no_mangle] pub extern "C" fn f_fp_scalar_1(x: f32) -> f32 { x } -// CHECK: define double @f_fp_scalar_2(double) +// CHECK: define double @f_fp_scalar_2(double %0) #[no_mangle] pub extern "C" fn f_fp_scalar_2(x: f64) -> f64 { x @@ -67,7 +67,7 @@ pub struct Tiny { d: u16, } -// CHECK: define void @f_agg_tiny(i64) +// CHECK: define void @f_agg_tiny(i64 %0) #[no_mangle] pub extern "C" fn f_agg_tiny(mut e: Tiny) { e.a += e.b; @@ -86,7 +86,7 @@ pub struct Small { b: *mut i64, } -// CHECK: define void @f_agg_small([2 x i64]) +// CHECK: define void @f_agg_small([2 x i64] %0) #[no_mangle] pub extern "C" fn f_agg_small(mut x: Small) { x.a += unsafe { *x.b }; @@ -104,7 +104,7 @@ pub struct SmallAligned { a: i128, } -// CHECK: define void @f_agg_small_aligned(i128) +// CHECK: define void @f_agg_small_aligned(i128 %0) #[no_mangle] pub extern "C" fn f_agg_small_aligned(mut x: SmallAligned) { x.a += x.a; @@ -130,7 +130,7 @@ pub extern "C" fn f_agg_large_ret(i: i32, j: i8) -> Large { Large { a: 1, b: 2, c: 3, d: 4 } } -// CHECK: define void @f_scalar_stack_1(i64, [2 x i64], i128, %Large* {{.*}}%d, i8 zeroext %e, i8 signext %f, i8 %g, i8 %h) +// CHECK: define void @f_scalar_stack_1(i64 %0, [2 x i64] %1, i128 %2, %Large* {{.*}}%d, i8 zeroext %e, i8 signext %f, i8 %g, i8 %h) #[no_mangle] pub extern "C" fn f_scalar_stack_1( a: Tiny, @@ -144,7 +144,7 @@ pub extern "C" fn f_scalar_stack_1( ) { } -// CHECK: define void @f_scalar_stack_2(%Large* {{.*}}sret{{.*}}, i64 %a, i128, i128, i64 %d, i8 zeroext %e, i8 %f, i8 %g) +// CHECK: define void @f_scalar_stack_2(%Large* {{.*}}sret{{.*}} %0, i64 %a, i128 %1, i128 %2, i64 %d, i8 zeroext %e, i8 %f, i8 %g) #[no_mangle] pub extern "C" fn f_scalar_stack_2( a: u64, diff --git a/src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs index 66a3b9e4952..0b6e1878d4d 100644 --- a/src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs +++ b/src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs @@ -4,7 +4,7 @@ // only-linux #![crate_type = "lib"] -// CHECK: define void @f_fpr_tracking(double, double, double, double, double, double, double, double, i8 zeroext %i) +// CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 zeroext %i) #[no_mangle] pub extern "C" fn f_fpr_tracking( a: f64, @@ -36,7 +36,7 @@ pub struct DoubleFloat { g: f32, } -// CHECK: define void @f_double_s_arg(double) +// CHECK: define void @f_double_s_arg(double %0) #[no_mangle] pub extern "C" fn f_double_s_arg(a: Double) {} @@ -46,7 +46,7 @@ pub extern "C" fn f_ret_double_s() -> Double { Double { f: 1. } } -// CHECK: define void @f_double_double_s_arg({ double, double }) +// CHECK: define void @f_double_double_s_arg({ double, double } %0) #[no_mangle] pub extern "C" fn f_double_double_s_arg(a: DoubleDouble) {} @@ -56,7 +56,7 @@ pub extern "C" fn f_ret_double_double_s() -> DoubleDouble { DoubleDouble { f: 1., g: 2. } } -// CHECK: define void @f_double_float_s_arg({ double, float }) +// CHECK: define void @f_double_float_s_arg({ double, float } %0) #[no_mangle] pub extern "C" fn f_double_float_s_arg(a: DoubleFloat) {} @@ -66,7 +66,7 @@ pub extern "C" fn f_ret_double_float_s() -> DoubleFloat { DoubleFloat { f: 1., g: 2. } } -// CHECK: define void @f_double_double_s_arg_insufficient_fprs(double, double, double, double, double, double, double, [2 x i64]) +// CHECK: define void @f_double_double_s_arg_insufficient_fprs(double %0, double %1, double %2, double %3, double %4, double %5, double %6, [2 x i64] %7) #[no_mangle] pub extern "C" fn f_double_double_s_arg_insufficient_fprs( a: f64, @@ -104,7 +104,7 @@ pub struct DoubleInt64 { i: i64, } -// CHECK: define void @f_double_int8_s_arg({ double, i8 }) +// CHECK: define void @f_double_int8_s_arg({ double, i8 } %0) #[no_mangle] pub extern "C" fn f_double_int8_s_arg(a: DoubleInt8) {} @@ -114,7 +114,7 @@ pub extern "C" fn f_ret_double_int8_s() -> DoubleInt8 { DoubleInt8 { f: 1., i: 2 } } -// CHECK: define void @f_double_int32_s_arg({ double, i32 }) +// CHECK: define void @f_double_int32_s_arg({ double, i32 } %0) #[no_mangle] pub extern "C" fn f_double_int32_s_arg(a: DoubleInt32) {} @@ -124,7 +124,7 @@ pub extern "C" fn f_ret_double_int32_s() -> DoubleInt32 { DoubleInt32 { f: 1., i: 2 } } -// CHECK: define void @f_double_uint8_s_arg({ double, i8 }) +// CHECK: define void @f_double_uint8_s_arg({ double, i8 } %0) #[no_mangle] pub extern "C" fn f_double_uint8_s_arg(a: DoubleUInt8) {} @@ -134,7 +134,7 @@ pub extern "C" fn f_ret_double_uint8_s() -> DoubleUInt8 { DoubleUInt8 { f: 1., i: 2 } } -// CHECK: define void @f_double_int64_s_arg({ double, i64 }) +// CHECK: define void @f_double_int64_s_arg({ double, i64 } %0) #[no_mangle] pub extern "C" fn f_double_int64_s_arg(a: DoubleInt64) {} @@ -144,7 +144,7 @@ pub extern "C" fn f_ret_double_int64_s() -> DoubleInt64 { DoubleInt64 { f: 1., i: 2 } } -// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, [2 x i64]) +// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, [2 x i64] %0) #[no_mangle] pub extern "C" fn f_double_int8_s_arg_insufficient_gprs( a: i32, @@ -159,7 +159,7 @@ pub extern "C" fn f_double_int8_s_arg_insufficient_gprs( ) { } -// CHECK: define void @f_struct_double_int8_insufficient_fprs(float, double, double, double, double, double, double, double, [2 x i64]) +// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, [2 x i64] %8) #[no_mangle] pub extern "C" fn f_struct_double_int8_insufficient_fprs( a: f32, @@ -179,7 +179,7 @@ pub struct DoubleArr1 { a: [f64; 1], } -// CHECK: define void @f_doublearr1_s_arg(double) +// CHECK: define void @f_doublearr1_s_arg(double %0) #[no_mangle] pub extern "C" fn f_doublearr1_s_arg(a: DoubleArr1) {} @@ -194,7 +194,7 @@ pub struct DoubleArr2 { a: [f64; 2], } -// CHECK: define void @f_doublearr2_s_arg({ double, double }) +// CHECK: define void @f_doublearr2_s_arg({ double, double } %0) #[no_mangle] pub extern "C" fn f_doublearr2_s_arg(a: DoubleArr2) {} @@ -214,7 +214,7 @@ pub struct DoubleArr2Tricky1 { g: [Tricky1; 2], } -// CHECK: define void @f_doublearr2_tricky1_s_arg({ double, double }) +// CHECK: define void @f_doublearr2_tricky1_s_arg({ double, double } %0) #[no_mangle] pub extern "C" fn f_doublearr2_tricky1_s_arg(a: DoubleArr2Tricky1) {} @@ -233,7 +233,7 @@ pub struct DoubleArr2Tricky2 { g: [Tricky1; 2], } -// CHECK: define void @f_doublearr2_tricky2_s_arg({ double, double }) +// CHECK: define void @f_doublearr2_tricky2_s_arg({ double, double } %0) #[no_mangle] pub extern "C" fn f_doublearr2_tricky2_s_arg(a: DoubleArr2Tricky2) {} @@ -267,7 +267,7 @@ pub struct CharCharDouble { c: f64, } -// CHECK: define void @f_char_char_double_s_arg([2 x i64]) +// CHECK: define void @f_char_char_double_s_arg([2 x i64] %0) #[no_mangle] pub extern "C" fn f_char_char_double_s_arg(a: CharCharDouble) {} @@ -282,7 +282,7 @@ pub union DoubleU { a: f64, } -// CHECK: define void @f_double_u_arg(i64) +// CHECK: define void @f_double_u_arg(i64 %0) #[no_mangle] pub extern "C" fn f_double_u_arg(a: DoubleU) {} diff --git a/src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs index d843331f425..1cea6e3db2a 100644 --- a/src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs +++ b/src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs @@ -4,7 +4,7 @@ // only-linux #![crate_type = "lib"] -// CHECK: define void @f_fpr_tracking(float, float, float, float, float, float, float, float, i8 zeroext %i) +// CHECK: define void @f_fpr_tracking(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, i8 zeroext %i) #[no_mangle] pub extern "C" fn f_fpr_tracking( a: f32, @@ -30,7 +30,7 @@ pub struct FloatFloat { g: f32, } -// CHECK: define void @f_float_s_arg(float) +// CHECK: define void @f_float_s_arg(float %0) #[no_mangle] pub extern "C" fn f_float_s_arg(a: Float) {} @@ -40,7 +40,7 @@ pub extern "C" fn f_ret_float_s() -> Float { Float { f: 1. } } -// CHECK: define void @f_float_float_s_arg({ float, float }) +// CHECK: define void @f_float_float_s_arg({ float, float } %0) #[no_mangle] pub extern "C" fn f_float_float_s_arg(a: FloatFloat) {} @@ -50,7 +50,7 @@ pub extern "C" fn f_ret_float_float_s() -> FloatFloat { FloatFloat { f: 1., g: 2. } } -// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float, float, float, float, float, float, float, i64) +// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float %0, float %1, float %2, float %3, float %4, float %5, float %6, i64 %7) #[no_mangle] pub extern "C" fn f_float_float_s_arg_insufficient_fprs( a: f32, @@ -88,7 +88,7 @@ pub struct FloatInt64 { i: i64, } -// CHECK: define void @f_float_int8_s_arg({ float, i8 }) +// CHECK: define void @f_float_int8_s_arg({ float, i8 } %0) #[no_mangle] pub extern "C" fn f_float_int8_s_arg(a: FloatInt8) {} @@ -98,7 +98,7 @@ pub extern "C" fn f_ret_float_int8_s() -> FloatInt8 { FloatInt8 { f: 1., i: 2 } } -// CHECK: define void @f_float_int32_s_arg({ float, i32 }) +// CHECK: define void @f_float_int32_s_arg({ float, i32 } %0) #[no_mangle] pub extern "C" fn f_float_int32_s_arg(a: FloatInt32) {} @@ -108,7 +108,7 @@ pub extern "C" fn f_ret_float_int32_s() -> FloatInt32 { FloatInt32 { f: 1., i: 2 } } -// CHECK: define void @f_float_uint8_s_arg({ float, i8 }) +// CHECK: define void @f_float_uint8_s_arg({ float, i8 } %0) #[no_mangle] pub extern "C" fn f_float_uint8_s_arg(a: FloatUInt8) {} @@ -118,7 +118,7 @@ pub extern "C" fn f_ret_float_uint8_s() -> FloatUInt8 { FloatUInt8 { f: 1., i: 2 } } -// CHECK: define void @f_float_int64_s_arg({ float, i64 }) +// CHECK: define void @f_float_int64_s_arg({ float, i64 } %0) #[no_mangle] pub extern "C" fn f_float_int64_s_arg(a: FloatInt64) {} @@ -128,7 +128,7 @@ pub extern "C" fn f_ret_float_int64_s() -> FloatInt64 { FloatInt64 { f: 1., i: 2 } } -// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, i64) +// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, i64 %0) #[no_mangle] pub extern "C" fn f_float_int8_s_arg_insufficient_gprs( a: i32, @@ -143,7 +143,7 @@ pub extern "C" fn f_float_int8_s_arg_insufficient_gprs( ) { } -// CHECK: define void @f_struct_float_int8_insufficient_fprs(float, float, float, float, float, float, float, float, i64) +// CHECK: define void @f_struct_float_int8_insufficient_fprs(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, i64 %8) #[no_mangle] pub extern "C" fn f_struct_float_int8_insufficient_fprs( a: f32, @@ -163,7 +163,7 @@ pub struct FloatArr1 { a: [f32; 1], } -// CHECK: define void @f_floatarr1_s_arg(float) +// CHECK: define void @f_floatarr1_s_arg(float %0) #[no_mangle] pub extern "C" fn f_floatarr1_s_arg(a: FloatArr1) {} @@ -178,7 +178,7 @@ pub struct FloatArr2 { a: [f32; 2], } -// CHECK: define void @f_floatarr2_s_arg({ float, float }) +// CHECK: define void @f_floatarr2_s_arg({ float, float } %0) #[no_mangle] pub extern "C" fn f_floatarr2_s_arg(a: FloatArr2) {} @@ -198,7 +198,7 @@ pub struct FloatArr2Tricky1 { g: [Tricky1; 2], } -// CHECK: define void @f_floatarr2_tricky1_s_arg({ float, float }) +// CHECK: define void @f_floatarr2_tricky1_s_arg({ float, float } %0) #[no_mangle] pub extern "C" fn f_floatarr2_tricky1_s_arg(a: FloatArr2Tricky1) {} @@ -217,7 +217,7 @@ pub struct FloatArr2Tricky2 { g: [Tricky1; 2], } -// CHECK: define void @f_floatarr2_tricky2_s_arg({ float, float }) +// CHECK: define void @f_floatarr2_tricky2_s_arg({ float, float } %0) #[no_mangle] pub extern "C" fn f_floatarr2_tricky2_s_arg(a: FloatArr2Tricky2) {} @@ -234,7 +234,7 @@ pub struct IntFloatInt { c: i32, } -// CHECK: define void @f_int_float_int_s_arg([2 x i64]) +// CHECK: define void @f_int_float_int_s_arg([2 x i64] %0) #[no_mangle] pub extern "C" fn f_int_float_int_s_arg(a: IntFloatInt) {} @@ -251,7 +251,7 @@ pub struct CharCharFloat { c: f32, } -// CHECK: define void @f_char_char_float_s_arg(i64) +// CHECK: define void @f_char_char_float_s_arg(i64 %0) #[no_mangle] pub extern "C" fn f_char_char_float_s_arg(a: CharCharFloat) {} @@ -266,7 +266,7 @@ pub union FloatU { a: f32, } -// CHECK: define void @f_float_u_arg(i64) +// CHECK: define void @f_float_u_arg(i64 %0) #[no_mangle] pub extern "C" fn f_float_u_arg(a: FloatU) {} diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs index b8ebf338cbf..3e3222d4735 100644 --- a/src/test/codegen/stack-probes.rs +++ b/src/test/codegen/stack-probes.rs @@ -5,6 +5,7 @@ // ignore-powerpc // ignore-powerpc64 // ignore-powerpc64le +// ignore-riscv64 // ignore-s390x // ignore-sparc // ignore-sparc64 diff --git a/src/test/codegen/x86_mmx.rs b/src/test/codegen/x86_mmx.rs index a08ba361740..9a58ef1c37a 100644 --- a/src/test/codegen/x86_mmx.rs +++ b/src/test/codegen/x86_mmx.rs @@ -6,6 +6,7 @@ // ignore-powerpc // ignore-powerpc64 // ignore-powerpc64le +// ignore-riscv64 // ignore-sparc // ignore-sparc64 // ignore-s390x diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_div_by_zero/rustc.main.ConstProp.diff index 333bf0e320b..de06e5334e0 100644 --- a/src/test/mir-opt/const_prop/bad_op_div_by_zero/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero/rustc.main.ConstProp.diff @@ -59,7 +59,7 @@ // mir::Constant // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19 - // + literal: Const { ty: i32, val: Value(Scalar(0xffffffff)) } -- _6 = Eq(const 1i32, const std::i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 +- _6 = Eq(const 1i32, const i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } + _6 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 // ty::Const diff --git a/src/test/mir-opt/const_prop/bad_op_mod_by_zero/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_mod_by_zero/rustc.main.ConstProp.diff index c081b46366e..7052c838704 100644 --- a/src/test/mir-opt/const_prop/bad_op_mod_by_zero/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_mod_by_zero/rustc.main.ConstProp.diff @@ -59,7 +59,7 @@ // mir::Constant // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 - // + literal: Const { ty: i32, val: Value(Scalar(0xffffffff)) } -- _6 = Eq(const 1i32, const std::i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 +- _6 = Eq(const 1i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } + _6 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 // ty::Const diff --git a/src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff index 8d08267d75b..8bb28206964 100644 --- a/src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyArmIdentity.diff @@ -26,15 +26,14 @@ } bb3: { -- StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 -- _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 -- StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26 -- _4 = _3; // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26 -- ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 -- discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 -- StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:11:26: 11:27 -- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:11:27: 11:28 -+ _0 = move _1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 + _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 + StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26 + _4 = _3; // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26 + ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:11:26: 11:27 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:11:27: 11:28 goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 } diff --git a/src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff index 23fa9817f80..1226b4feaf4 100644 --- a/src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify-arm/rustc.id.SimplifyBranchSame.diff @@ -26,7 +26,14 @@ } bb3: { - _0 = move _1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 + _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15 + StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26 + _4 = _3; // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26 + ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 + StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:11:26: 11:27 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:11:27: 11:28 goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 } diff --git a/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff index e2a12ca5be2..5a5d67b36d9 100644 --- a/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyArmIdentity.diff @@ -22,15 +22,14 @@ } bb1: { -- StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 -- _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 -- StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24 -- _6 = _5; // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24 -- ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 -- discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 -- StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:19:24: 19:25 -- StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:19:25: 19:26 -+ _0 = move _1; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 + _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 + StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24 + _6 = _5; // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24 + ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:19:24: 19:25 + StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:19:25: 19:26 goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6 } @@ -39,15 +38,14 @@ } bb3: { -- StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 -- _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 -- StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22 -- _4 = _3; // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22 -- ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 -- StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:18:22: 18:23 -- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:18:23: 18:24 -+ _0 = move _1; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 + _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 + StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22 + _4 = _3; // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22 + ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:18:22: 18:23 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:18:23: 18:24 goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6 } diff --git a/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff index 9d1ff22dc51..e8286516261 100644 --- a/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify-arm/rustc.id_result.SimplifyBranchSame.diff @@ -18,27 +18,38 @@ bb0: { _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14 -- switchInt(move _2) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14 -+ goto -> bb1; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14 + switchInt(move _2) -> [0isize: bb3, 1isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:18:9: 18:14 } bb1: { -- _0 = move _1; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 -- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6 -- } -- -- bb2: { -- unreachable; // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12 -- } -- -- bb3: { - _0 = move _1; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 -- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6 -+ goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6 + StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 + _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14 + StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24 + _6 = _5; // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24 + ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25 + StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:19:24: 19:25 + StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:19:25: 19:26 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6 } -- bb4: { -+ bb2: { + bb2: { + unreachable; // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12 + } + + bb3: { + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 + _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13 + StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22 + _4 = _3; // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22 + ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23 + StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:18:22: 18:23 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:18:23: 18:24 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:17:5: 20:6 + } + + bb4: { return; // scope 0 at $DIR/simplify-arm.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff index 64b5f174300..44f475346e0 100644 --- a/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyArmIdentity.diff @@ -49,17 +49,16 @@ } bb2: { -- StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 -- _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 -- _2 = _10; // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15 -- StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -+ _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + _2 = _10; // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 -- StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 -- _11 = _2; // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 -- ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 -- StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10 + StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 + _11 = _2; // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 + ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10 StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 goto -> bb5; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 } diff --git a/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff index 01f57bec71a..c91c55dfb04 100644 --- a/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify-arm/rustc.id_try.SimplifyBranchSame.diff @@ -49,8 +49,16 @@ } bb2: { - _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + _2 = _10; // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15 + StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 + StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 + _11 = _2; // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 + ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 + StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10 StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 goto -> bb5; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 } diff --git a/src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff index 6ccec937b9b..7d3537d0943 100644 --- a/src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try_if_let/rustc.{{impl}}-append.SimplifyArmIdentity.diff @@ -80,12 +80,11 @@ StorageLive(_8); // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 _8 = ((_5 as Some).0: std::ptr::NonNull<Node>); // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 StorageLive(_9); // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 -- StorageLive(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 -- _10 = _8; // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 -- ((_9 as Some).0: std::ptr::NonNull<Node>) = move _10; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 -- discriminant(_9) = 1; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 -- StorageDead(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62 -+ _9 = move _5; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 + StorageLive(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 + _10 = _8; // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 + ((_9 as Some).0: std::ptr::NonNull<Node>) = move _10; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 + discriminant(_9) = 1; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 + StorageDead(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62 StorageLive(_11); // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 StorageLive(_12); // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29 _12 = &mut _4; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29 diff --git a/src/test/pretty/asm.pp b/src/test/pretty/asm.pp index 1723e1cc1cb..4903050e08e 100644 --- a/src/test/pretty/asm.pp +++ b/src/test/pretty/asm.pp @@ -8,6 +8,7 @@ extern crate std; // pretty-mode:expanded // pp-exact:asm.pp +// only-x86_64 pub fn main() { let a: i32; diff --git a/src/test/pretty/asm.rs b/src/test/pretty/asm.rs index 9812f1d97e5..12c32e6721b 100644 --- a/src/test/pretty/asm.rs +++ b/src/test/pretty/asm.rs @@ -2,6 +2,7 @@ // pretty-mode:expanded // pp-exact:asm.pp +// only-x86_64 pub fn main() { let a: i32; diff --git a/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile b/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile new file mode 100644 index 00000000000..50ff3dd56ce --- /dev/null +++ b/src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile @@ -0,0 +1,44 @@ +-include ../tools.mk + +# rust-lang/rust#70924: Test that if we add rust-src component in between two +# incremetnal compiles, the compiler does not ICE on the second. + +# This test uses `ln -s` rather than copying to save testing time, but its +# usage doesn't work on windows. So ignore windows. + +# ignore-windows + +SYSROOT:=$(shell $(RUSTC) --print sysroot) +FAKEROOT=$(TMPDIR)/fakeroot +INCR=$(TMPDIR)/incr + +# Make a local copy of the sysroot; then remove the rust-src part of it, if +# present, for the *first* build. Then put in a facsimile of the rust-src +# component for the second build, in order to expose the ICE from issue #70924. +# +# Note that it is much easier to just do `cp -a $(SYSROOT)/* $(FAKEROOT)` as a +# first step, but I am concerned that would be too expensive in a unit test +# compared to making symbolic links. +# +# Anyway, the pattern you'll see here is: For every prefix in +# root/lib/rustlib/src, link all of prefix parent content, then remove the +# prefix, then loop on the next prefix. This way, we basically create a copy of +# the context around root/lib/rustlib/src, and can freely add/remove the src +# component itself. +all: + mkdir $(FAKEROOT) + ln -s $(SYSROOT)/* $(FAKEROOT) + rm -f $(FAKEROOT)/lib + mkdir $(FAKEROOT)/lib + ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib + rm -f $(FAKEROOT)/lib/rustlib + mkdir $(FAKEROOT)/lib/rustlib + ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib + rm -f $(FAKEROOT)/lib/rustlib/src + mkdir $(FAKEROOT)/lib/rustlib/src + ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src + rm -f $(FAKEROOT)/lib/rustlib/src/rust + $(RUSTC) --sysroot $(FAKEROOT) -C incremental=$(INCR) main.rs + mkdir -p $(FAKEROOT)/lib/rustlib/src/rust/src/libstd + touch $(FAKEROOT)/lib/rustlib/src/rust/src/libstd/lib.rs + $(RUSTC) --sysroot $(FAKEROOT) -C incremental=$(INCR) main.rs diff --git a/src/test/run-make-fulldeps/incr-add-rust-src-component/main.rs b/src/test/run-make-fulldeps/incr-add-rust-src-component/main.rs new file mode 100644 index 00000000000..f6320bcb04a --- /dev/null +++ b/src/test/run-make-fulldeps/incr-add-rust-src-component/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello World"); +} diff --git a/src/test/rustdoc-ui/doctest-output.rs b/src/test/rustdoc-ui/doctest-output.rs new file mode 100644 index 00000000000..f812263c252 --- /dev/null +++ b/src/test/rustdoc-ui/doctest-output.rs @@ -0,0 +1,15 @@ +// compile-flags:--test --test-args=--test-threads=1 +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// check-pass + +//! ``` +//! assert_eq!(1 + 1, 2); +//! ``` + +pub mod foo { + + /// ``` + /// assert_eq!(1 + 1, 2); + /// ``` + pub fn bar() {} +} diff --git a/src/test/rustdoc-ui/doctest-output.stdout b/src/test/rustdoc-ui/doctest-output.stdout new file mode 100644 index 00000000000..9a55bf50196 --- /dev/null +++ b/src/test/rustdoc-ui/doctest-output.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test $DIR/doctest-output.rs - (line 5) ... ok +test $DIR/doctest-output.rs - foo::bar (line 11) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs b/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs new file mode 100644 index 00000000000..04a431d9902 --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs @@ -0,0 +1,35 @@ +// force-host +// no-prefer-dynamic +// compile-flags: --crate-type proc-macro + +#![crate_type="proc-macro"] +#![crate_name="intra_link_proc_macro_macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(DeriveA)] +pub fn a_derive(input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_derive(DeriveB)] +pub fn b_derive(input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_derive(DeriveTrait)] +pub fn trait_derive(input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +pub fn attr_a(input: TokenStream, _args: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +pub fn attr_b(input: TokenStream, _args: TokenStream) -> TokenStream { + input +} diff --git a/src/test/rustdoc/auxiliary/issue-73061.rs b/src/test/rustdoc/auxiliary/issue-73061.rs new file mode 100644 index 00000000000..e05a3bc6d91 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-73061.rs @@ -0,0 +1,17 @@ +//edition:2018 + +#![feature(type_alias_impl_trait)] + +pub trait Foo { + type X: std::future::Future<Output = ()>; + fn x(&self) -> Self::X; +} + +pub struct F; + +impl Foo for F { + type X = impl std::future::Future<Output = ()>; + fn x(&self) -> Self::X { + async {} + } +} diff --git a/src/test/rustdoc/intra-link-proc-macro.rs b/src/test/rustdoc/intra-link-proc-macro.rs new file mode 100644 index 00000000000..7b6ea5d60f8 --- /dev/null +++ b/src/test/rustdoc/intra-link-proc-macro.rs @@ -0,0 +1,27 @@ +// aux-build:intra-link-proc-macro-macro.rs +// build-aux-docs +#![deny(intra_doc_link_resolution_failure)] + +extern crate intra_link_proc_macro_macro; + + +pub use intra_link_proc_macro_macro::{DeriveA, attr_a}; +use intra_link_proc_macro_macro::{DeriveB, attr_b}; + +// @has intra_link_proc_macro/struct.Foo.html +// @has - '//a/@href' '../intra_link_proc_macro/derive.DeriveA.html' +// @has - '//a/@href' '../intra_link_proc_macro/attr.attr_a.html' +// @has - '//a/@href' '../intra_link_proc_macro/trait.DeriveTrait.html' +// @has - '//a/@href' '../intra_link_proc_macro_macro/derive.DeriveB.html' +// @has - '//a/@href' '../intra_link_proc_macro_macro/attr.attr_b.html' +/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait] +pub struct Foo; + +// @has intra_link_proc_macro/struct.Bar.html +// @has - '//a/@href' '../intra_link_proc_macro/derive.DeriveA.html' +// @has - '//a/@href' '../intra_link_proc_macro/attr.attr_a.html' +/// Link to [deriveA](derive@DeriveA) [attr](macro@attr_a) +pub struct Bar; + +// this should not cause ambiguity errors +pub trait DeriveTrait {} diff --git a/src/test/rustdoc/issue-73061-cross-crate-opaque-assoc-type.rs b/src/test/rustdoc/issue-73061-cross-crate-opaque-assoc-type.rs new file mode 100644 index 00000000000..2700f2370ee --- /dev/null +++ b/src/test/rustdoc/issue-73061-cross-crate-opaque-assoc-type.rs @@ -0,0 +1,14 @@ +// Regression test for ICE #73061 + +// aux-build:issue-73061.rs + +extern crate issue_73061; + +pub struct Z; + +impl issue_73061::Foo for Z { + type X = <issue_73061::F as issue_73061::Foo>::X; + fn x(&self) -> Self::X { + issue_73061::F.x() + } +} diff --git a/src/test/rustdoc/show-const-contents.rs b/src/test/rustdoc/show-const-contents.rs index b35f67ef912..814339e198f 100644 --- a/src/test/rustdoc/show-const-contents.rs +++ b/src/test/rustdoc/show-const-contents.rs @@ -28,8 +28,8 @@ pub const CONST_CALC_I32: i32 = 42 + 1; // @!has show_const_contents/constant.CONST_REF_I32.html '; //' pub const CONST_REF_I32: &'static i32 = &42; -// @has show_const_contents/constant.CONST_I32_MAX.html '= i32::max_value(); // 2_147_483_647i32' -pub const CONST_I32_MAX: i32 = i32::max_value(); +// @has show_const_contents/constant.CONST_I32_MAX.html '= i32::MAX; // 2_147_483_647i32' +pub const CONST_I32_MAX: i32 = i32::MAX; // @!has show_const_contents/constant.UNIT.html '= ();' // @!has show_const_contents/constant.UNIT.html '; //' @@ -56,11 +56,11 @@ pub use std::i32::MAX; macro_rules! int_module { ($T:ident) => ( - pub const MIN: $T = $T::min_value(); + pub const MIN: $T = $T::MIN; ) } -// @has show_const_contents/constant.MIN.html '= i16::min_value(); // -32_768i16' +// @has show_const_contents/constant.MIN.html '= i16::MIN; // -32_768i16' int_module!(i16); // @has show_const_contents/constant.ESCAPE.html //pre '= r#"<script>alert("ESCAPE");</script>"#;' diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index cef600bed5f..6da26e6cfbe 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -84,9 +84,9 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { 2 => { let seg = PathSegment::from_ident(Ident::from_str("x")); iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall( - seg.clone(), vec![e, make_x()]))); + seg.clone(), vec![e, make_x()], DUMMY_SP))); iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall( - seg.clone(), vec![make_x(), e]))); + seg.clone(), vec![make_x(), e], DUMMY_SP))); }, 3..=8 => { let op = Spanned { diff --git a/src/test/ui/annotate-snippet/auxiliary/multispan.rs b/src/test/ui/annotate-snippet/auxiliary/multispan.rs new file mode 100644 index 00000000000..c05d15643db --- /dev/null +++ b/src/test/ui/annotate-snippet/auxiliary/multispan.rs @@ -0,0 +1,37 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_diagnostic, proc_macro_span, proc_macro_def_site)] + +extern crate proc_macro; + +use proc_macro::{TokenStream, TokenTree, Span, Diagnostic}; + +fn parse(input: TokenStream) -> Result<(), Diagnostic> { + let mut hi_spans = vec![]; + for tree in input { + if let TokenTree::Ident(ref ident) = tree { + if ident.to_string() == "hi" { + hi_spans.push(ident.span()); + } + } + } + + if !hi_spans.is_empty() { + return Err(Span::def_site() + .error("hello to you, too!") + .span_note(hi_spans, "found these 'hi's")); + } + + Ok(()) +} + +#[proc_macro] +pub fn hello(input: TokenStream) -> TokenStream { + if let Err(diag) = parse(input) { + diag.emit(); + } + + TokenStream::new() +} diff --git a/src/test/ui/annotate-snippet/missing-type.stderr b/src/test/ui/annotate-snippet/missing-type.stderr index 806acf0bed5..c16f022a77f 100644 --- a/src/test/ui/annotate-snippet/missing-type.stderr +++ b/src/test/ui/annotate-snippet/missing-type.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Iter` in this scope - --> $DIR/missing-type.rs:4:11 + --> $DIR/missing-type.rs:4:12 | LL | let x: Iter; | ^^^^ not found in this scope diff --git a/src/test/ui/annotate-snippet/multispan.rs b/src/test/ui/annotate-snippet/multispan.rs new file mode 100644 index 00000000000..325252d7716 --- /dev/null +++ b/src/test/ui/annotate-snippet/multispan.rs @@ -0,0 +1,28 @@ +// aux-build:multispan.rs +// compile-flags: --error-format human-annotate-rs + +#![feature(proc_macro_hygiene)] + +extern crate multispan; + +use multispan::hello; + +fn main() { + // This one emits no error. + hello!(); + + // Exactly one 'hi'. + hello!(hi); //~ ERROR hello to you, too! + + // Now two, back to back. + hello!(hi hi); //~ ERROR hello to you, too! + + // Now three, back to back. + hello!(hi hi hi); //~ ERROR hello to you, too! + + // Now several, with spacing. + hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too! + hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too! + hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too! + hello!(hi good hi and good bye); //~ ERROR hello to you, too! +} diff --git a/src/test/ui/annotate-snippet/multispan.stderr b/src/test/ui/annotate-snippet/multispan.stderr new file mode 100644 index 00000000000..4ac31e32ba7 --- /dev/null +++ b/src/test/ui/annotate-snippet/multispan.stderr @@ -0,0 +1,42 @@ +error: hello to you, too! + --> $DIR/multispan.rs:15:5 + | +LL | hello!(hi); + | ^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:18:5 + | +LL | hello!(hi hi); + | ^^^^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:21:5 + | +LL | hello!(hi hi hi); + | ^^^^^^^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:24:5 + | +LL | hello!(hi hey hi yo hi beep beep hi hi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:25:5 + | +LL | hello!(hi there, hi how are you? hi... hi.); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:26:5 + | +LL | hello!(whoah. hi di hi di ho); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:27:5 + | +LL | hello!(hi good hi and good bye); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | diff --git a/src/test/ui/asm/bad-template.rs b/src/test/ui/asm/bad-template.rs index 0b333eca1ab..21ce8c6236d 100644 --- a/src/test/ui/asm/bad-template.rs +++ b/src/test/ui/asm/bad-template.rs @@ -22,5 +22,7 @@ fn main() { //~^ ERROR invalid reference to argument at index 0 asm!("{:foo}", in(reg) foo); //~^ ERROR asm template modifier must be a single character + asm!("", in(reg) 0, in(reg) 1); + //~^ ERROR multiple unused asm arguments } } diff --git a/src/test/ui/asm/bad-template.stderr b/src/test/ui/asm/bad-template.stderr index 2de76ef8241..1aea7467ed0 100644 --- a/src/test/ui/asm/bad-template.stderr +++ b/src/test/ui/asm/bad-template.stderr @@ -19,6 +19,8 @@ error: argument never used | LL | asm!("{1}", in(reg) foo); | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` --> $DIR/bad-template.rs:13:15 @@ -46,6 +48,8 @@ error: named argument never used | LL | asm!("{}", a = in(reg) foo); | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 1 --> $DIR/bad-template.rs:18:15 @@ -60,6 +64,8 @@ error: named argument never used | LL | asm!("{1}", a = in(reg) foo); | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:21:15 @@ -82,5 +88,15 @@ error: asm template modifier must be a single character LL | asm!("{:foo}", in(reg) foo); | ^^^ -error: aborting due to 10 previous errors +error: multiple unused asm arguments + --> $DIR/bad-template.rs:25:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: aborting due to 11 previous errors diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr index fa422f56bec..583a1057036 100644 --- a/src/test/ui/asm/parse-error.stderr +++ b/src/test/ui/asm/parse-error.stderr @@ -127,6 +127,8 @@ error: argument never used | LL | asm!("{a}", a = const foo, a = const bar); | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: explicit register arguments cannot have names --> $DIR/parse-error.rs:47:18 diff --git a/src/test/ui/asm/srcloc.rs b/src/test/ui/asm/srcloc.rs index 7af6f620a98..402adc50d5b 100644 --- a/src/test/ui/asm/srcloc.rs +++ b/src/test/ui/asm/srcloc.rs @@ -37,5 +37,8 @@ fn main() { asm!(concat!("invalid", "_", "instruction")); //~^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); + //~^ WARN: scale factor without index register is ignored } } diff --git a/src/test/ui/asm/srcloc.stderr b/src/test/ui/asm/srcloc.stderr index 57a4fbb9742..d5d12b00481 100644 --- a/src/test/ui/asm/srcloc.stderr +++ b/src/test/ui/asm/srcloc.stderr @@ -70,5 +70,17 @@ note: instantiated into assembly here LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +warning: scale factor without index register is ignored + --> $DIR/srcloc.rs:41:15 + | +LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:23 + | +LL | movaps %xmm3, (%esi, 2) + | ^ + +error: aborting due to 6 previous errors; 1 warning emitted diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs index 83a3672af49..8cff16aa75f 100644 --- a/src/test/ui/asm/sym.rs +++ b/src/test/ui/asm/sym.rs @@ -1,8 +1,9 @@ // no-system-llvm // only-x86_64 +// only-linux // run-pass -#![feature(asm, track_caller)] +#![feature(asm, track_caller, thread_local)] extern "C" fn f1() -> i32 { 111 @@ -15,9 +16,9 @@ fn f2() -> i32 { } macro_rules! call { - ($func:path) => {{ - let result: i32; + ($func:path) => { unsafe { + let result: i32; asm!("call {}", sym $func, out("rax") result, out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _, @@ -27,12 +28,53 @@ macro_rules! call { out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _, out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _, ); + result } - result - }} + } } +macro_rules! static_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + // LEA performs a RIP-relative address calculation and returns the address + asm!("lea {}, [rip + {}]", out(reg) result, sym $s); + result + } + } +} +macro_rules! static_tls_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + asm!( + " + # Load TLS base address + mov {out}, qword ptr fs:[0] + # Calculate the address of sym in the TLS block. The @tpoff + # relocation gives the offset of the symbol from the start + # of the TLS block. + lea {out}, [{out} + {sym}@tpoff] + ", + out = out(reg) result, + sym = sym $s + ); + result + } + } +} + +static S1: u32 = 111; +#[thread_local] +static S2: u32 = 222; + fn main() { assert_eq!(call!(f1), 111); assert_eq!(call!(f2), 222); + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + std::thread::spawn(|| { + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + }); } diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs index 8b396f23efd..8b5c5219430 100644 --- a/src/test/ui/associated-type-bounds/duplicate.rs +++ b/src/test/ui/associated-type-bounds/duplicate.rs @@ -108,18 +108,12 @@ type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T; type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy; //~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy; //~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy; //~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses type ETAI4 = impl Iterator<Item: Copy, Item: Send>; //~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] //~| ERROR could not find defining uses diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr index 71f6e4ff8b6..712211e60cb 100644 --- a/src/test/ui/associated-type-bounds/duplicate.stderr +++ b/src/test/ui/associated-type-bounds/duplicate.stderr @@ -224,30 +224,6 @@ LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:62:42 - | -LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() } - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:64:42 - | -LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() } - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:66:45 - | -LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() } - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:75:39 | LL | const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty(); @@ -367,12 +343,6 @@ LL | type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T; | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:108:1 - | -LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified --> $DIR/duplicate.rs:108:36 | @@ -381,14 +351,38 @@ LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy; | | | `Item` bound here first +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:62:42 + | +LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:64:42 + | +LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() } + | ---------- ^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + +error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified + --> $DIR/duplicate.rs:66:45 + | +LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() } + | ------------- ^^^^^^^^^^^^^ re-bound here + | | + | `Item` bound here first + error: could not find defining uses - --> $DIR/duplicate.rs:113:1 + --> $DIR/duplicate.rs:108:51 | -LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy; + | ^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:113:36 + --> $DIR/duplicate.rs:111:36 | LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here @@ -396,13 +390,13 @@ LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:118:1 + --> $DIR/duplicate.rs:111:51 | -LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy; + | ^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:118:39 + --> $DIR/duplicate.rs:114:39 | LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -410,13 +404,19 @@ LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:123:1 + --> $DIR/duplicate.rs:114:57 + | +LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy; + | ^^^^^^^^^ + +error: could not find defining uses + --> $DIR/duplicate.rs:117:14 | LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:123:40 + --> $DIR/duplicate.rs:117:40 | LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>; | ---------- ^^^^^^^^^^ re-bound here @@ -424,13 +424,13 @@ LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:128:1 + --> $DIR/duplicate.rs:122:14 | LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:128:40 + --> $DIR/duplicate.rs:122:40 | LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>; | ---------- ^^^^^^^^^^ re-bound here @@ -438,13 +438,13 @@ LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:133:1 + --> $DIR/duplicate.rs:127:14 | LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:133:43 + --> $DIR/duplicate.rs:127:43 | LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -452,7 +452,7 @@ LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:139:36 + --> $DIR/duplicate.rs:133:36 | LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {} | ---------- ^^^^^^^^^^ re-bound here @@ -460,7 +460,7 @@ LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:141:36 + --> $DIR/duplicate.rs:135:36 | LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {} | ---------- ^^^^^^^^^^ re-bound here @@ -468,7 +468,7 @@ LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:143:39 + --> $DIR/duplicate.rs:137:39 | LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -476,7 +476,7 @@ LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:145:34 + --> $DIR/duplicate.rs:139:34 | LL | trait TRS1: Iterator<Item: Copy, Item: Send> {} | ---------- ^^^^^^^^^^ re-bound here @@ -484,7 +484,7 @@ LL | trait TRS1: Iterator<Item: Copy, Item: Send> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:147:34 + --> $DIR/duplicate.rs:141:34 | LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {} | ---------- ^^^^^^^^^^ re-bound here @@ -492,7 +492,7 @@ LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:149:37 + --> $DIR/duplicate.rs:143:37 | LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -500,7 +500,7 @@ LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:151:45 + --> $DIR/duplicate.rs:145:45 | LL | trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {} | ---------- ^^^^^^^^^^ re-bound here @@ -508,7 +508,7 @@ LL | trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:153:45 + --> $DIR/duplicate.rs:147:45 | LL | trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {} | ---------- ^^^^^^^^^^ re-bound here @@ -516,7 +516,7 @@ LL | trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:155:48 + --> $DIR/duplicate.rs:149:48 | LL | trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -524,7 +524,7 @@ LL | trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:157:46 + --> $DIR/duplicate.rs:151:46 | LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {} | ---------- ^^^^^^^^^^ re-bound here @@ -532,7 +532,7 @@ LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:157:46 + --> $DIR/duplicate.rs:151:46 | LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {} | ---------- ^^^^^^^^^^ re-bound here @@ -540,7 +540,7 @@ LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:160:46 + --> $DIR/duplicate.rs:154:46 | LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {} | ---------- ^^^^^^^^^^ re-bound here @@ -548,7 +548,7 @@ LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:160:46 + --> $DIR/duplicate.rs:154:46 | LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {} | ---------- ^^^^^^^^^^ re-bound here @@ -556,7 +556,7 @@ LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:163:49 + --> $DIR/duplicate.rs:157:49 | LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -564,7 +564,7 @@ LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:163:49 + --> $DIR/duplicate.rs:157:49 | LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {} | ------------- ^^^^^^^^^^^^^ re-bound here @@ -572,7 +572,7 @@ LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {} | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:166:43 + --> $DIR/duplicate.rs:160:43 | LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; } | ---------- ^^^^^^^^^^ re-bound here @@ -580,7 +580,7 @@ LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:168:43 + --> $DIR/duplicate.rs:162:43 | LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; } | ---------- ^^^^^^^^^^ re-bound here @@ -588,7 +588,7 @@ LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:170:46 + --> $DIR/duplicate.rs:164:46 | LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; } | ------------- ^^^^^^^^^^^^^ re-bound here @@ -596,7 +596,7 @@ LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; } | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:173:40 + --> $DIR/duplicate.rs:167:40 | LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>; | ---------- ^^^^^^^^^^ re-bound here @@ -604,7 +604,7 @@ LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:177:44 + --> $DIR/duplicate.rs:171:44 | LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>; | ---------- ^^^^^^^^^^ re-bound here @@ -612,7 +612,7 @@ LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>; | `Item` bound here first error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:181:43 + --> $DIR/duplicate.rs:175:43 | LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -620,113 +620,77 @@ LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>; | `Item` bound here first error: could not find defining uses - --> $DIR/duplicate.rs:108:24 - | -LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:108:36 - | -LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:113:24 - | -LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:113:36 - | -LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:118:24 - | -LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:118:39 - | -LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:123:28 + --> $DIR/duplicate.rs:117:28 | LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:123:40 + --> $DIR/duplicate.rs:117:40 | LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:128:28 + --> $DIR/duplicate.rs:122:28 | LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:128:40 + --> $DIR/duplicate.rs:122:40 | LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:133:28 + --> $DIR/duplicate.rs:127:28 | LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>; | ^^^^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:133:43 + --> $DIR/duplicate.rs:127:43 | LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>; | ^^^^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:173:28 + --> $DIR/duplicate.rs:167:28 | LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:173:40 + --> $DIR/duplicate.rs:167:40 | LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:177:32 + --> $DIR/duplicate.rs:171:32 | LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:177:44 + --> $DIR/duplicate.rs:171:44 | LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:181:28 + --> $DIR/duplicate.rs:175:28 | LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>; | ^^^^^^^^^^^^^ error: could not find defining uses - --> $DIR/duplicate.rs:181:43 + --> $DIR/duplicate.rs:175:43 | LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>; | ^^^^^^^^^^^^^ -error: aborting due to 96 previous errors; 1 warning emitted +error: aborting due to 90 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0719`. diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs index 000acf14a3f..636fafc2bc4 100644 --- a/src/test/ui/async-await/async-fn-size-moved-locals.rs +++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs @@ -114,5 +114,5 @@ fn main() { assert_eq!(1026, std::mem::size_of_val(&single_with_noop())); assert_eq!(3078, std::mem::size_of_val(&joined())); assert_eq!(3079, std::mem::size_of_val(&joined_with_noop())); - assert_eq!(6157, std::mem::size_of_val(&mixed_sizes())); + assert_eq!(7181, std::mem::size_of_val(&mixed_sizes())); } diff --git a/src/test/ui/async-await/issue-73050.rs b/src/test/ui/async-await/issue-73050.rs new file mode 100644 index 00000000000..790f24a230b --- /dev/null +++ b/src/test/ui/async-await/issue-73050.rs @@ -0,0 +1,12 @@ +// check-pass +// edition:2018 + +#[allow(unused)] +async fn foo<'a>() { + let _data = &mut [0u8; { 1 + 4 }]; + bar().await +} + +async fn bar() {} + +fn main() {} diff --git a/src/test/ui/async-await/issue-73137.rs b/src/test/ui/async-await/issue-73137.rs new file mode 100644 index 00000000000..18374460df7 --- /dev/null +++ b/src/test/ui/async-await/issue-73137.rs @@ -0,0 +1,42 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/73137> + +// run-pass +// edition:2018 + +#![allow(dead_code)] +#![feature(wake_trait)] +use std::future::Future; +use std::task::{Waker, Wake, Context}; +use std::sync::Arc; + +struct DummyWaker; +impl Wake for DummyWaker { + fn wake(self: Arc<Self>) {} +} + +struct Foo { + a: usize, + b: &'static u32, +} + +#[inline(never)] +fn nop<T>(_: T) {} + +fn main() { + let mut fut = Box::pin(async { + let action = Foo { + b: &42, + a: async { 0 }.await, + }; + + // An error in the generator transform caused `b` to be overwritten with `a` when `b` was + // borrowed. + nop(&action.b); + assert_ne!(0usize, unsafe { std::mem::transmute(action.b) }); + + async {}.await; + }); + let waker = Waker::from(Arc::new(DummyWaker)); + let mut cx = Context::from_waker(&waker); + let _ = fut.as_mut().poll(&mut cx); +} diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index 01d54ac8cc8..8b85adb5845 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `路濫狼á́́` LL | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^^ invalid ABI | - = help: valid ABIs: cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted + = help: valid ABIs: Rust, C, cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted error: aborting due to previous error diff --git a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr index 44e5c6a99f7..93e16bac13b 100644 --- a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr +++ b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr @@ -121,7 +121,7 @@ error[E0308]: mismatched types LL | let _ = Box::new(|x| (x as u8)): Box<dyn Fn(i32) -> _>; | ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::ops::Fn`, found closure | - = note: expected struct `std::boxed::Box<dyn std::ops::Fn(i32) -> _>` + = note: expected struct `std::boxed::Box<dyn std::ops::Fn(i32) -> u8>` found struct `std::boxed::Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:35]>` error: aborting due to 14 previous errors diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs new file mode 100644 index 00000000000..225593c3178 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs @@ -0,0 +1,20 @@ +// Regression test for #72819: ICE due to failure in resolving the const generic in `Arr`'s type +// bounds. + +#![feature(const_generics)] +#![allow(incomplete_features)] +struct Arr<const N: usize> +where Assert::<{N < usize::max_value() / 2}>: IsTrue, +//~^ ERROR constant expression depends on a generic parameter +{ +} + +enum Assert<const CHECK: bool> {} + +trait IsTrue {} + +impl IsTrue for Assert<true> {} + +fn main() { + let x: Arr<{usize::max_value()}> = Arr {}; +} diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr new file mode 100644 index 00000000000..a9f664d0ac8 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-72819-generic-in-const-eval.rs:7:47 + | +LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, + | ^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr index ebdb73c4467..3386e6e588e 100644 --- a/src/test/ui/consts/const-eval/infinite_loop.stderr +++ b/src/test/ui/consts/const-eval/infinite_loop.stderr @@ -23,10 +23,10 @@ LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; = help: add `#![feature(const_if_match)]` to the crate attributes to enable error[E0080]: evaluation of constant value failed - --> $DIR/infinite_loop.rs:8:20 + --> $DIR/infinite_loop.rs:8:17 | LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; - | ^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/const-eval/shift_overflow.rs b/src/test/ui/consts/const-eval/shift_overflow.rs index f7d0f6bd961..e843584b69b 100644 --- a/src/test/ui/consts/const-eval/shift_overflow.rs +++ b/src/test/ui/consts/const-eval/shift_overflow.rs @@ -1,6 +1,6 @@ enum Foo { // test that we detect overflows for non-u32 discriminants - X = 1 << ((u32::max_value() as u64) + 1), //~ ERROR E0080 + X = 1 << ((u32::MAX as u64) + 1), //~ ERROR E0080 Y = 42, } diff --git a/src/test/ui/consts/const-eval/shift_overflow.stderr b/src/test/ui/consts/const-eval/shift_overflow.stderr index 5db231cd5b0..f4840e9ac96 100644 --- a/src/test/ui/consts/const-eval/shift_overflow.stderr +++ b/src/test/ui/consts/const-eval/shift_overflow.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation of constant value failed --> $DIR/shift_overflow.rs:3:9 | -LL | X = 1 << ((u32::max_value() as u64) + 1), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left with overflow +LL | X = 1 << ((u32::MAX as u64) + 1), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left with overflow error: aborting due to previous error diff --git a/src/test/ui/consts/const-int-arithmetic.rs b/src/test/ui/consts/const-int-arithmetic.rs index ab24abeba32..9c94551f744 100644 --- a/src/test/ui/consts/const-int-arithmetic.rs +++ b/src/test/ui/consts/const-int-arithmetic.rs @@ -34,8 +34,8 @@ suite!( C6: 5i8.checked_mul(122), None; C7: (-127i8).checked_mul(-99), None; - C8: (i8::min_value() + 1).checked_div(-1), Some(127); - C9: i8::min_value().checked_div(-1), None; + C8: (i8::MIN + 1).checked_div(-1), Some(127); + C9: i8::MIN.checked_div(-1), None; C10: 1i8.checked_div(0), None; C11: 5i8.checked_rem(2), Some(1); @@ -56,8 +56,8 @@ suite!( C21: i8::MIN.checked_abs(), None; // `const_euclidean_int_methods` - C22: (i8::min_value() + 1).checked_div_euclid(-1), Some(127); - C23: i8::min_value().checked_div_euclid(-1), None; + C22: (i8::MIN + 1).checked_div_euclid(-1), Some(127); + C23: i8::MIN.checked_div_euclid(-1), None; C24: (1i8).checked_div_euclid(0), None; C25: 5i8.checked_rem_euclid(2), Some(1); @@ -72,12 +72,12 @@ suite!( saturating_and_wrapping -> i8 { // `const_saturating_int_methods` C28: 100i8.saturating_add(1), 101; - C29: i8::max_value().saturating_add(100), i8::max_value(); - C30: i8::min_value().saturating_add(-1), i8::min_value(); + C29: i8::MAX.saturating_add(100), i8::MAX; + C30: i8::MIN.saturating_add(-1), i8::MIN; C31: 100i8.saturating_sub(127), -27; - C32: i8::min_value().saturating_sub(100), i8::min_value(); - C33: i8::max_value().saturating_sub(-1), i8::max_value(); + C32: i8::MIN.saturating_sub(100), i8::MIN; + C33: i8::MAX.saturating_sub(-1), i8::MAX; C34: 10i8.saturating_mul(12), 120; C35: i8::MAX.saturating_mul(10), i8::MAX; @@ -85,13 +85,13 @@ suite!( C37: 100i8.saturating_neg(), -100; C38: (-100i8).saturating_neg(), 100; - C39: i8::min_value().saturating_neg(), i8::max_value(); - C40: i8::max_value().saturating_neg(), i8::min_value() + 1; + C39: i8::MIN.saturating_neg(), i8::MAX; + C40: i8::MAX.saturating_neg(), i8::MIN + 1; C57: 100i8.saturating_abs(), 100; C58: (-100i8).saturating_abs(), 100; - C59: i8::min_value().saturating_abs(), i8::max_value(); - C60: (i8::min_value() + 1).saturating_abs(), i8::max_value(); + C59: i8::MIN.saturating_abs(), i8::MAX; + C60: (i8::MIN + 1).saturating_abs(), i8::MAX; // `const_wrapping_int_methods` C41: 100i8.wrapping_div(10), 10; diff --git a/src/test/ui/consts/const-int-conversion-rpass.rs b/src/test/ui/consts/const-int-conversion-rpass.rs index 6484169dd9a..4aaeeaa3885 100644 --- a/src/test/ui/consts/const-int-conversion-rpass.rs +++ b/src/test/ui/consts/const-int-conversion-rpass.rs @@ -6,13 +6,13 @@ const FROM_LE_BYTES: i32 = i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]); const FROM_NE_BYTES: i32 = i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0])); const TO_BE_BYTES: [u8; 4] = 0x12_34_56_78_i32.to_be_bytes(); const TO_LE_BYTES: [u8; 4] = 0x12_34_56_78_i32.to_le_bytes(); -const TO_NE_BYTES: [u8; 4] = i32::min_value().to_be().to_ne_bytes(); +const TO_NE_BYTES: [u8; 4] = i32::MIN.to_be().to_ne_bytes(); fn main() { assert_eq!(REVERSE, 0x1e6a2c48); assert_eq!(FROM_BE_BYTES, 0x12_34_56_78); assert_eq!(FROM_LE_BYTES, 0x78_56_34_12); - assert_eq!(FROM_NE_BYTES, i32::min_value()); + assert_eq!(FROM_NE_BYTES, i32::MIN); assert_eq!(TO_BE_BYTES, [0x12, 0x34, 0x56, 0x78]); assert_eq!(TO_LE_BYTES, [0x78, 0x56, 0x34, 0x12]); assert_eq!(TO_NE_BYTES, [0x80, 0, 0, 0]); diff --git a/src/test/ui/consts/const-int-conversion.rs b/src/test/ui/consts/const-int-conversion.rs index b80e616eae7..5a05a2b3593 100644 --- a/src/test/ui/consts/const-int-conversion.rs +++ b/src/test/ui/consts/const-int-conversion.rs @@ -11,6 +11,6 @@ fn main() { //~^ ERROR temporary value dropped while borrowed let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes()); //~^ ERROR temporary value dropped while borrowed - let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes()); + let d: &'static [u8] = &(i32::MIN.to_be().to_ne_bytes()); //~^ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/const-int-conversion.stderr b/src/test/ui/consts/const-int-conversion.stderr index 237f9627219..61162a79226 100644 --- a/src/test/ui/consts/const-int-conversion.stderr +++ b/src/test/ui/consts/const-int-conversion.stderr @@ -67,8 +67,8 @@ LL | } error[E0716]: temporary value dropped while borrowed --> $DIR/const-int-conversion.rs:14:29 | -LL | let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes()); - | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let d: &'static [u8] = &(i32::MIN.to_be().to_ne_bytes()); + | ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use | | | type annotation requires that borrow lasts for `'static` LL | diff --git a/src/test/ui/consts/const-int-overflowing-rpass.rs b/src/test/ui/consts/const-int-overflowing-rpass.rs index 9be87a6447c..eecb88becab 100644 --- a/src/test/ui/consts/const-int-overflowing-rpass.rs +++ b/src/test/ui/consts/const-int-overflowing-rpass.rs @@ -1,7 +1,7 @@ // run-pass const ADD_A: (u32, bool) = 5u32.overflowing_add(2); -const ADD_B: (u32, bool) = u32::max_value().overflowing_add(1); +const ADD_B: (u32, bool) = u32::MAX.overflowing_add(1); const SUB_A: (u32, bool) = 5u32.overflowing_sub(2); const SUB_B: (u32, bool) = 0u32.overflowing_sub(1); @@ -20,14 +20,14 @@ const NEG_B: (u32, bool) = core::u32::MAX.overflowing_neg(); const ABS_POS: (i32, bool) = 10i32.overflowing_abs(); const ABS_NEG: (i32, bool) = (-10i32).overflowing_abs(); -const ABS_MIN: (i32, bool) = i32::min_value().overflowing_abs(); +const ABS_MIN: (i32, bool) = i32::MIN.overflowing_abs(); fn main() { assert_eq!(ADD_A, (7, false)); assert_eq!(ADD_B, (0, true)); assert_eq!(SUB_A, (3, false)); - assert_eq!(SUB_B, (u32::max_value(), true)); + assert_eq!(SUB_B, (u32::MAX, true)); assert_eq!(MUL_A, (10, false)); assert_eq!(MUL_B, (1410065408, true)); @@ -43,5 +43,5 @@ fn main() { assert_eq!(ABS_POS, (10, false)); assert_eq!(ABS_NEG, (10, false)); - assert_eq!(ABS_MIN, (i32::min_value(), true)); + assert_eq!(ABS_MIN, (i32::MIN, true)); } diff --git a/src/test/ui/consts/const-int-pow-rpass.rs b/src/test/ui/consts/const-int-pow-rpass.rs index b0fba19455b..4f936236dbb 100644 --- a/src/test/ui/consts/const-int-pow-rpass.rs +++ b/src/test/ui/consts/const-int-pow-rpass.rs @@ -20,10 +20,10 @@ const NEXT_POWER_OF_TWO: u32 = 3u32.next_power_of_two(); const CHECKED_NEXT_POWER_OF_TWO_OK: Option<u32> = 3u32.checked_next_power_of_two(); const CHECKED_NEXT_POWER_OF_TWO_OVERFLOW: Option<u32> = - u32::max_value().checked_next_power_of_two(); + u32::MAX.checked_next_power_of_two(); const WRAPPING_NEXT_POWER_OF_TWO: u32 = - u32::max_value().wrapping_next_power_of_two(); + u32::MAX.wrapping_next_power_of_two(); fn main() { assert!(!IS_POWER_OF_TWO_A); @@ -37,7 +37,7 @@ fn main() { assert_eq!(WRAPPING_POW, 217); assert_eq!(OVERFLOWING_POW, (217, true)); - assert_eq!(SATURATING_POW, u8::max_value()); + assert_eq!(SATURATING_POW, u8::MAX); assert_eq!(NEXT_POWER_OF_TWO, 4); diff --git a/src/test/ui/consts/const-int-saturating-arith.rs b/src/test/ui/consts/const-int-saturating-arith.rs index d0a3eccd177..4718120a51b 100644 --- a/src/test/ui/consts/const-int-saturating-arith.rs +++ b/src/test/ui/consts/const-int-saturating-arith.rs @@ -2,33 +2,33 @@ #![feature(const_saturating_int_methods)] const INT_U32_NO: u32 = (42 as u32).saturating_add(2); -const INT_U32: u32 = u32::max_value().saturating_add(1); -const INT_U128: u128 = u128::max_value().saturating_add(1); -const INT_I128: i128 = i128::max_value().saturating_add(1); -const INT_I128_NEG: i128 = i128::min_value().saturating_add(-1); +const INT_U32: u32 = u32::MAX.saturating_add(1); +const INT_U128: u128 = u128::MAX.saturating_add(1); +const INT_I128: i128 = i128::MAX.saturating_add(1); +const INT_I128_NEG: i128 = i128::MIN.saturating_add(-1); const INT_U32_NO_SUB: u32 = (42 as u32).saturating_sub(2); const INT_U32_SUB: u32 = (1 as u32).saturating_sub(2); const INT_I32_NO_SUB: i32 = (-42 as i32).saturating_sub(2); -const INT_I32_NEG_SUB: i32 = i32::min_value().saturating_sub(1); -const INT_I32_POS_SUB: i32 = i32::max_value().saturating_sub(-1); +const INT_I32_NEG_SUB: i32 = i32::MIN.saturating_sub(1); +const INT_I32_POS_SUB: i32 = i32::MAX.saturating_sub(-1); const INT_U128_SUB: u128 = (0 as u128).saturating_sub(1); -const INT_I128_NEG_SUB: i128 = i128::min_value().saturating_sub(1); -const INT_I128_POS_SUB: i128 = i128::max_value().saturating_sub(-1); +const INT_I128_NEG_SUB: i128 = i128::MIN.saturating_sub(1); +const INT_I128_POS_SUB: i128 = i128::MAX.saturating_sub(-1); fn main() { assert_eq!(INT_U32_NO, 44); - assert_eq!(INT_U32, u32::max_value()); - assert_eq!(INT_U128, u128::max_value()); - assert_eq!(INT_I128, i128::max_value()); - assert_eq!(INT_I128_NEG, i128::min_value()); + assert_eq!(INT_U32, u32::MAX); + assert_eq!(INT_U128, u128::MAX); + assert_eq!(INT_I128, i128::MAX); + assert_eq!(INT_I128_NEG, i128::MIN); assert_eq!(INT_U32_NO_SUB, 40); assert_eq!(INT_U32_SUB, 0); assert_eq!(INT_I32_NO_SUB, -44); - assert_eq!(INT_I32_NEG_SUB, i32::min_value()); - assert_eq!(INT_I32_POS_SUB, i32::max_value()); + assert_eq!(INT_I32_NEG_SUB, i32::MIN); + assert_eq!(INT_I32_POS_SUB, i32::MAX); assert_eq!(INT_U128_SUB, 0); - assert_eq!(INT_I128_NEG_SUB, i128::min_value()); - assert_eq!(INT_I128_POS_SUB, i128::max_value()); + assert_eq!(INT_I128_NEG_SUB, i128::MIN); + assert_eq!(INT_I128_POS_SUB, i128::MAX); } diff --git a/src/test/ui/consts/const-int-unchecked.rs b/src/test/ui/consts/const-int-unchecked.rs index fb09f62854d..1596093b2c1 100644 --- a/src/test/ui/consts/const-int-unchecked.rs +++ b/src/test/ui/consts/const-int-unchecked.rs @@ -131,12 +131,12 @@ const _: u16 = unsafe { std::intrinsics::unchecked_mul(300u16, 250u16) }; const _: i32 = unsafe { std::intrinsics::unchecked_div(1, 0) }; //~^ ERROR any use of this value will cause an error -const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::min_value(), -1) }; +const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::MIN, -1) }; //~^ ERROR any use of this value will cause an error const _: i32 = unsafe { std::intrinsics::unchecked_rem(1, 0) }; //~^ ERROR any use of this value will cause an error -const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::min_value(), -1) }; +const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::MIN, -1) }; //~^ ERROR any use of this value will cause an error fn main() {} diff --git a/src/test/ui/consts/const-int-unchecked.stderr b/src/test/ui/consts/const-int-unchecked.stderr index cf70454b6bf..0287b404e7d 100644 --- a/src/test/ui/consts/const-int-unchecked.stderr +++ b/src/test/ui/consts/const-int-unchecked.stderr @@ -355,8 +355,8 @@ LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(1, 0) }; error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:134:25 | -LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::min_value(), -1) }; - | ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- +LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::MIN, -1) }; + | ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | overflow executing `unchecked_div` @@ -371,8 +371,8 @@ LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(1, 0) }; error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:139:25 | -LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::min_value(), -1) }; - | ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- +LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::MIN, -1) }; + | ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | | overflow executing `unchecked_rem` diff --git a/src/test/ui/consts/const-int-wrapping-rpass.rs b/src/test/ui/consts/const-int-wrapping-rpass.rs index 2bbad99a52a..225d1e9393d 100644 --- a/src/test/ui/consts/const-int-wrapping-rpass.rs +++ b/src/test/ui/consts/const-int-wrapping-rpass.rs @@ -1,10 +1,10 @@ // run-pass const ADD_A: u32 = 200u32.wrapping_add(55); -const ADD_B: u32 = 200u32.wrapping_add(u32::max_value()); +const ADD_B: u32 = 200u32.wrapping_add(u32::MAX); const SUB_A: u32 = 100u32.wrapping_sub(100); -const SUB_B: u32 = 100u32.wrapping_sub(u32::max_value()); +const SUB_B: u32 = 100u32.wrapping_sub(u32::MAX); const MUL_A: u8 = 10u8.wrapping_mul(12); const MUL_B: u8 = 25u8.wrapping_mul(12); @@ -20,7 +20,7 @@ const NEG_B: u32 = 1234567890u32.wrapping_neg(); const ABS_POS: i32 = 10i32.wrapping_abs(); const ABS_NEG: i32 = (-10i32).wrapping_abs(); -const ABS_MIN: i32 = i32::min_value().wrapping_abs(); +const ABS_MIN: i32 = i32::MIN.wrapping_abs(); fn main() { assert_eq!(ADD_A, 255); @@ -43,5 +43,5 @@ fn main() { assert_eq!(ABS_POS, 10); assert_eq!(ABS_NEG, 10); - assert_eq!(ABS_MIN, i32::min_value()); + assert_eq!(ABS_MIN, i32::MIN); } diff --git a/src/test/ui/consts/const-match-check.eval1.stderr b/src/test/ui/consts/const-match-check.eval1.stderr index 3850b1d82bf..12ba9cacabf 100644 --- a/src/test/ui/consts/const-match-check.eval1.stderr +++ b/src/test/ui/consts/const-match-check.eval1.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:25:15 | LL | A = { let 0 = 0; 0 }, - | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html diff --git a/src/test/ui/consts/const-match-check.eval2.stderr b/src/test/ui/consts/const-match-check.eval2.stderr index 4e1d50f42d4..2eed7abdc65 100644 --- a/src/test/ui/consts/const-match-check.eval2.stderr +++ b/src/test/ui/consts/const-match-check.eval2.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:31:24 | LL | let x: [i32; { let 0 = 0; 0 }] = []; - | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html diff --git a/src/test/ui/consts/const-match-check.matchck.stderr b/src/test/ui/consts/const-match-check.matchck.stderr index 2aabc0ca494..1fa0cb17fe6 100644 --- a/src/test/ui/consts/const-match-check.matchck.stderr +++ b/src/test/ui/consts/const-match-check.matchck.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:4:22 | LL | const X: i32 = { let 0 = 0; 0 }; - | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html @@ -12,11 +12,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched LL | const X: i32 = { if let 0 = 0 { /* */ } 0 }; | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:8:23 | LL | static Y: i32 = { let 0 = 0; 0 }; - | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html @@ -26,11 +26,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 }; | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:13:26 | LL | const X: i32 = { let 0 = 0; 0 }; - | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html @@ -40,11 +40,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched LL | const X: i32 = { if let 0 = 0 { /* */ } 0 }; | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered --> $DIR/const-match-check.rs:19:26 | LL | const X: i32 = { let 0 = 0; 0 }; - | ^ patterns `std::i32::MIN..=-1i32` and `1i32..=std::i32::MAX` not covered + | ^ patterns `i32::MIN..=-1i32` and `1i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html diff --git a/src/test/ui/consts/const-pattern-irrefutable.rs b/src/test/ui/consts/const-pattern-irrefutable.rs index 60e16aaf895..65f09eb8009 100644 --- a/src/test/ui/consts/const-pattern-irrefutable.rs +++ b/src/test/ui/consts/const-pattern-irrefutable.rs @@ -9,8 +9,8 @@ use foo::d; const a: u8 = 2; fn main() { - let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX - let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX - let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX + let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX + let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX + let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). } diff --git a/src/test/ui/consts/const-pattern-irrefutable.stderr b/src/test/ui/consts/const-pattern-irrefutable.stderr index 863e1372a9b..bb2fdec72ba 100644 --- a/src/test/ui/consts/const-pattern-irrefutable.stderr +++ b/src/test/ui/consts/const-pattern-irrefutable.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered +error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX` not covered --> $DIR/const-pattern-irrefutable.rs:12:9 | LL | const a: u8 = 2; @@ -12,7 +12,7 @@ LL | let a = 4; | = note: the matched value is of type `u8` -error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered +error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX` not covered --> $DIR/const-pattern-irrefutable.rs:13:9 | LL | pub const b: u8 = 2; @@ -26,7 +26,7 @@ LL | let c = 4; | = note: the matched value is of type `u8` -error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=std::u8::MAX` not covered +error[E0005]: refutable pattern in local binding: `0u8..=1u8` and `3u8..=u8::MAX` not covered --> $DIR/const-pattern-irrefutable.rs:14:9 | LL | pub const d: u8 = 2; diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 5fd7fe4480e..0aa30665f59 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -17,8 +17,8 @@ LL | bytes: [u8; std::mem::size_of::<Foo>()] note: ...which requires const-evaluating `std::mem::size_of`... --> $SRC_DIR/libcore/mem/mod.rs:LL:COL | -LL | intrinsics::size_of::<T>() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub const fn size_of<T>() -> usize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `std::intrinsics::size_of`... --> $SRC_DIR/libcore/intrinsics.rs:LL:COL | diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr index be522dd6d5d..8c2190b4e59 100644 --- a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr @@ -1,15 +1,18 @@ error: any use of this value will cause an error - --> $DIR/const_eval_limit_reached.rs:8:11 + --> $DIR/const_eval_limit_reached.rs:8:5 | -LL | / const X: usize = { -LL | | let mut x = 0; -LL | | while x != 1000 { - | | ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) -LL | | -... | -LL | | x -LL | | }; - | |__- +LL | / const X: usize = { +LL | | let mut x = 0; +LL | | while x != 1000 { + | |_____^ +LL | || +LL | || x += 1; +LL | || } + | ||_____^ exceeded interpreter step limit (see `#[const_eval_limit]`) +LL | | +LL | | x +LL | | }; + | |__- | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/enum-discr-type-err.stderr b/src/test/ui/consts/enum-discr-type-err.stderr index 492b79e2e60..9834a99b79a 100644 --- a/src/test/ui/consts/enum-discr-type-err.stderr +++ b/src/test/ui/consts/enum-discr-type-err.stderr @@ -11,10 +11,6 @@ LL | | } | |_- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit - | -LL | $( $v = $s::V.try_into().unwrap(), )* - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/enum-discr-type-err.rs:18:21 @@ -29,10 +25,6 @@ LL | | } | |_- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit - | -LL | $( $v = $s::V.try_into().unwrap(), )* - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/recursive-zst-static.default.stderr b/src/test/ui/consts/recursive-zst-static.default.stderr index d424b22f000..9042c6f6be1 100644 --- a/src/test/ui/consts/recursive-zst-static.default.stderr +++ b/src/test/ui/consts/recursive-zst-static.default.stderr @@ -1,8 +1,8 @@ error[E0391]: cycle detected when const-evaluating `FOO` - --> $DIR/recursive-zst-static.rs:10:18 + --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires const-evaluating `FOO`... --> $DIR/recursive-zst-static.rs:10:1 diff --git a/src/test/ui/consts/recursive-zst-static.unleash.stderr b/src/test/ui/consts/recursive-zst-static.unleash.stderr index d424b22f000..9042c6f6be1 100644 --- a/src/test/ui/consts/recursive-zst-static.unleash.stderr +++ b/src/test/ui/consts/recursive-zst-static.unleash.stderr @@ -1,8 +1,8 @@ error[E0391]: cycle detected when const-evaluating `FOO` - --> $DIR/recursive-zst-static.rs:10:18 + --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires const-evaluating `FOO`... --> $DIR/recursive-zst-static.rs:10:1 diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.rs b/src/test/ui/consts/uninhabited-const-issue-61744.rs index 15436f9c1b2..55f42d84f9c 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.rs +++ b/src/test/ui/consts/uninhabited-const-issue-61744.rs @@ -1,11 +1,11 @@ // build-fail pub const unsafe fn fake_type<T>() -> T { - hint_unreachable() + hint_unreachable() //~ ERROR evaluation of constant value failed } pub const unsafe fn hint_unreachable() -> ! { - fake_type() //~ ERROR evaluation of constant value failed + fake_type() } trait Const { diff --git a/src/test/ui/consts/uninhabited-const-issue-61744.stderr b/src/test/ui/consts/uninhabited-const-issue-61744.stderr index ca232380897..fc908b2b222 100644 --- a/src/test/ui/consts/uninhabited-const-issue-61744.stderr +++ b/src/test/ui/consts/uninhabited-const-issue-61744.stderr @@ -1,9 +1,10 @@ error[E0080]: evaluation of constant value failed - --> $DIR/uninhabited-const-issue-61744.rs:8:5 + --> $DIR/uninhabited-const-issue-61744.rs:4:5 | LL | hint_unreachable() - | ------------------ + | ^^^^^^^^^^^^^^^^^^ | | + | reached the configured maximum number of stack frames | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 @@ -71,9 +72,8 @@ LL | hint_unreachable() | inside `fake_type::<i32>` at $DIR/uninhabited-const-issue-61744.rs:4:5 ... LL | fake_type() - | ^^^^^^^^^^^ + | ----------- | | - | reached the configured maximum number of stack frames | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 diff --git a/src/test/ui/derived-errors/issue-31997-1.stderr b/src/test/ui/derived-errors/issue-31997-1.stderr index a4daf86cc8a..229c5c9e80f 100644 --- a/src/test/ui/derived-errors/issue-31997-1.stderr +++ b/src/test/ui/derived-errors/issue-31997-1.stderr @@ -4,12 +4,10 @@ error[E0433]: failed to resolve: use of undeclared type or module `HashMap` LL | let mut map = HashMap::new(); | ^^^^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this struct | LL | use std::collections::HashMap; | -LL | use std::collections::hash_map::HashMap; - | error: aborting due to previous error diff --git a/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs b/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs index e9c6104e387..4e2cc89948a 100644 --- a/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs +++ b/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs @@ -5,7 +5,7 @@ #[repr(i128)] enum Test { A(Box<u64>) = 0, - B(usize) = u64::max_value() as i128 + 1, + B(usize) = u64::MAX as i128 + 1, } fn main() { diff --git a/src/test/ui/enum-discriminant/repr128.rs b/src/test/ui/enum-discriminant/repr128.rs index 420b6007c6d..eefbc44f585 100644 --- a/src/test/ui/enum-discriminant/repr128.rs +++ b/src/test/ui/enum-discriminant/repr128.rs @@ -8,9 +8,9 @@ use std::marker::DiscriminantKind; enum Signed { Zero = 0, Staircase = 0x01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f, - U64Limit = u64::max_value() as i128 + 1, + U64Limit = u64::MAX as i128 + 1, SmallNegative = -1, - BigNegative = i128::min_value(), + BigNegative = i128::MIN, Next, } @@ -18,7 +18,7 @@ enum Signed { enum Unsigned { Zero = 0, Staircase = 0x01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f, - U64Limit = u64::max_value() as u128 + 1, + U64Limit = u64::MAX as u128 + 1, Next, } @@ -32,13 +32,13 @@ where fn main() { discr(Signed::Zero, 0); discr(Signed::Staircase, 0x01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f); - discr(Signed::U64Limit, u64::max_value() as i128 + 1); + discr(Signed::U64Limit, u64::MAX as i128 + 1); discr(Signed::SmallNegative, -1); - discr(Signed::BigNegative, i128::min_value()); - discr(Signed::Next, i128::min_value() + 1); + discr(Signed::BigNegative, i128::MIN); + discr(Signed::Next, i128::MIN + 1); discr(Unsigned::Zero, 0); discr(Unsigned::Staircase, 0x01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f); - discr(Unsigned::U64Limit, u64::max_value() as u128 + 1); - discr(Unsigned::Next, u64::max_value() as u128 + 2); + discr(Unsigned::U64Limit, u64::MAX as u128 + 1); + discr(Unsigned::Next, u64::MAX as u128 + 2); } diff --git a/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.rs b/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.rs new file mode 100644 index 00000000000..0d7df8182c4 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.rs @@ -0,0 +1,9 @@ +// Test that the AVR interrupt ABI cannot be used when avr_interrupt +// feature gate is not used. + +extern "avr-interrupt" fn foo() {} +//~^ ERROR avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change + +fn main() { + foo(); +} diff --git a/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr b/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr new file mode 100644 index 00000000000..be7040e1491 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-abi-avr-interrupt.stderr @@ -0,0 +1,12 @@ +error[E0658]: avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change + --> $DIR/feature-gate-abi-avr-interrupt.rs:4:8 + | +LL | extern "avr-interrupt" fn foo() {} + | ^^^^^^^^^^^^^^^ + | + = note: see issue #69664 <https://github.com/rust-lang/rust/issues/69664> for more information + = help: add `#![feature(abi_avr_interrupt)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs index 6088331cded..3b6c9791722 100644 --- a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs +++ b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs @@ -9,10 +9,14 @@ trait Bar { impl Bar for () { type Baa = impl Debug; //~ ERROR `impl Trait` in type aliases is unstable - fn define() -> Self::Baa { 0 } + fn define() -> Self::Baa { + 0 + } } -fn define() -> Foo { 0 } +fn define() -> Foo { + 0 +} trait TraitWithDefault { type Assoc = impl Debug; @@ -26,20 +30,20 @@ type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug> //~| ERROR `impl Trait` in type aliases is unstable //~| ERROR `impl Trait` in type aliases is unstable //~| ERROR `impl Trait` in type aliases is unstable -//~| ERROR `impl Trait` not allowed outside of function -//~| ERROR `impl Trait` not allowed outside of function -//~| ERROR `impl Trait` not allowed outside of function + +fn define_multiple() -> NestedFree { + (vec![true], 0u8, 0i32..1) +} impl Bar for u8 { - type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); + type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug> + Debug); //~^ ERROR `impl Trait` in type aliases is unstable //~| ERROR `impl Trait` in type aliases is unstable //~| ERROR `impl Trait` in type aliases is unstable //~| ERROR `impl Trait` in type aliases is unstable - //~| ERROR `impl Trait` not allowed outside of function - //~| ERROR `impl Trait` not allowed outside of function - //~| ERROR `impl Trait` not allowed outside of function - fn define() -> Self::Baa { (vec![true], 0u8, 0i32..1) } + fn define() -> Self::Baa { + (vec![true], 0u8, 0i32..1) + } } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr index 55cd2984ab6..8bab0d0c4a9 100644 --- a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr +++ b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr @@ -17,7 +17,7 @@ LL | type Baa = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: associated type defaults are unstable - --> $DIR/feature-gate-type_alias_impl_trait.rs:18:5 + --> $DIR/feature-gate-type_alias_impl_trait.rs:22:5 | LL | type Assoc = impl Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | type Assoc = impl Debug; = help: add `#![feature(associated_type_defaults)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/feature-gate-type_alias_impl_trait.rs:18:18 + --> $DIR/feature-gate-type_alias_impl_trait.rs:22:18 | LL | type Assoc = impl Debug; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | type Assoc = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/feature-gate-type_alias_impl_trait.rs:24:24 + --> $DIR/feature-gate-type_alias_impl_trait.rs:28:24 | LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); | ^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl D = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/feature-gate-type_alias_impl_trait.rs:24:37 + --> $DIR/feature-gate-type_alias_impl_trait.rs:28:37 | LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); | ^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl D = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/feature-gate-type_alias_impl_trait.rs:24:49 + --> $DIR/feature-gate-type_alias_impl_trait.rs:28:49 | LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,7 +62,7 @@ LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl D = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/feature-gate-type_alias_impl_trait.rs:24:70 + --> $DIR/feature-gate-type_alias_impl_trait.rs:28:70 | LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); | ^^^^^^^^^^ @@ -71,84 +71,48 @@ LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl D = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/feature-gate-type_alias_impl_trait.rs:34:21 + --> $DIR/feature-gate-type_alias_impl_trait.rs:39:21 | -LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); +LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug> + Debug); | ^^^^^^^^^^ | = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/feature-gate-type_alias_impl_trait.rs:34:34 + --> $DIR/feature-gate-type_alias_impl_trait.rs:39:34 | -LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); +LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug> + Debug); | ^^^^^^^^^^ | = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/feature-gate-type_alias_impl_trait.rs:34:46 + --> $DIR/feature-gate-type_alias_impl_trait.rs:39:46 | -LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug> + Debug); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/feature-gate-type_alias_impl_trait.rs:34:67 + --> $DIR/feature-gate-type_alias_impl_trait.rs:39:67 | -LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); +LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug> + Debug); | ^^^^^^^^^^ | = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/feature-gate-type_alias_impl_trait.rs:18:18 + --> $DIR/feature-gate-type_alias_impl_trait.rs:22:18 | LL | type Assoc = impl Debug; | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/feature-gate-type_alias_impl_trait.rs:24:24 - | -LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); - | ^^^^^^^^^^ - -error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/feature-gate-type_alias_impl_trait.rs:24:37 - | -LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); - | ^^^^^^^^^^ - -error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/feature-gate-type_alias_impl_trait.rs:24:49 - | -LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/feature-gate-type_alias_impl_trait.rs:34:21 - | -LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); - | ^^^^^^^^^^ - -error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/feature-gate-type_alias_impl_trait.rs:34:34 - | -LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); - | ^^^^^^^^^^ - -error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/feature-gate-type_alias_impl_trait.rs:34:46 - | -LL | type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 19 previous errors +error: aborting due to 13 previous errors Some errors have detailed explanations: E0562, E0658. For more information about an error, try `rustc --explain E0562`. diff --git a/src/test/ui/ffi_returns_twice.stderr b/src/test/ui/ffi_returns_twice.stderr index 862892e27be..2b7f5694f02 100644 --- a/src/test/ui/ffi_returns_twice.stderr +++ b/src/test/ui/ffi_returns_twice.stderr @@ -6,3 +6,4 @@ LL | #[ffi_returns_twice] error: aborting due to previous error +For more information about this error, try `rustc --explain E0724`. diff --git a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr index ce12b7853b6..e32005e21a8 100644 --- a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr +++ b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in `for` loop binding: `&std::i32::MIN..=0i32` and `&2i32..=std::i32::MAX` not covered +error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0i32` and `&2i32..=i32::MAX` not covered --> $DIR/for-loop-refutable-pattern-error-message.rs:2:9 | LL | for &1 in [1].iter() {} - | ^^ patterns `&std::i32::MIN..=0i32` and `&2i32..=std::i32::MAX` not covered + | ^^ patterns `&i32::MIN..=0i32` and `&2i32..=i32::MAX` not covered | = note: the matched value is of type `&i32` diff --git a/src/test/ui/generator/size-moved-locals.rs b/src/test/ui/generator/size-moved-locals.rs index a5786c2999e..74c60d98154 100644 --- a/src/test/ui/generator/size-moved-locals.rs +++ b/src/test/ui/generator/size-moved-locals.rs @@ -72,6 +72,6 @@ fn overlap_x_and_y() -> impl Generator<Yield = (), Return = ()> { fn main() { assert_eq!(1025, std::mem::size_of_val(&move_before_yield())); assert_eq!(1026, std::mem::size_of_val(&move_before_yield_with_noop())); - assert_eq!(1027, std::mem::size_of_val(&overlap_move_points())); + assert_eq!(2051, std::mem::size_of_val(&overlap_move_points())); assert_eq!(1026, std::mem::size_of_val(&overlap_x_and_y())); } diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr index 6c7a0cdb77a..028bfb89312 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr @@ -70,20 +70,20 @@ LL | m!('a', ..VAL_1 | VAL_2..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `char` -error[E0004]: non-exhaustive patterns: `std::u8::MAX` not covered +error[E0004]: non-exhaustive patterns: `u8::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12 | LL | m!(0, ..core::u8::MAX); - | ^ pattern `std::u8::MAX` not covered + | ^ pattern `u8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u8` -error[E0004]: non-exhaustive patterns: `254u8..=std::u8::MAX` not covered +error[E0004]: non-exhaustive patterns: `254u8..=u8::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `254u8..=std::u8::MAX` not covered + | ^ pattern `254u8..=u8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u8` @@ -97,11 +97,11 @@ LL | m!(0, ALMOST_MIN..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u8` -error[E0004]: non-exhaustive patterns: `std::u8::MAX` not covered +error[E0004]: non-exhaustive patterns: `u8::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12 | LL | m!(0, ..=ALMOST_MAX); - | ^ pattern `std::u8::MAX` not covered + | ^ pattern `u8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u8` @@ -124,20 +124,20 @@ LL | m!(0, ..VAL_1 | VAL_2..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u8` -error[E0004]: non-exhaustive patterns: `std::u16::MAX` not covered +error[E0004]: non-exhaustive patterns: `u16::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12 | LL | m!(0, ..core::u16::MAX); - | ^ pattern `std::u16::MAX` not covered + | ^ pattern `u16::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u16` -error[E0004]: non-exhaustive patterns: `65534u16..=std::u16::MAX` not covered +error[E0004]: non-exhaustive patterns: `65534u16..=u16::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `65534u16..=std::u16::MAX` not covered + | ^ pattern `65534u16..=u16::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u16` @@ -151,11 +151,11 @@ LL | m!(0, ALMOST_MIN..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u16` -error[E0004]: non-exhaustive patterns: `std::u16::MAX` not covered +error[E0004]: non-exhaustive patterns: `u16::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12 | LL | m!(0, ..=ALMOST_MAX); - | ^ pattern `std::u16::MAX` not covered + | ^ pattern `u16::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u16` @@ -178,20 +178,20 @@ LL | m!(0, ..VAL_1 | VAL_2..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u16` -error[E0004]: non-exhaustive patterns: `std::u32::MAX` not covered +error[E0004]: non-exhaustive patterns: `u32::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12 | LL | m!(0, ..core::u32::MAX); - | ^ pattern `std::u32::MAX` not covered + | ^ pattern `u32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u32` -error[E0004]: non-exhaustive patterns: `4294967294u32..=std::u32::MAX` not covered +error[E0004]: non-exhaustive patterns: `4294967294u32..=u32::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `4294967294u32..=std::u32::MAX` not covered + | ^ pattern `4294967294u32..=u32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u32` @@ -205,11 +205,11 @@ LL | m!(0, ALMOST_MIN..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u32` -error[E0004]: non-exhaustive patterns: `std::u32::MAX` not covered +error[E0004]: non-exhaustive patterns: `u32::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12 | LL | m!(0, ..=ALMOST_MAX); - | ^ pattern `std::u32::MAX` not covered + | ^ pattern `u32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u32` @@ -232,20 +232,20 @@ LL | m!(0, ..VAL_1 | VAL_2..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u32` -error[E0004]: non-exhaustive patterns: `std::u64::MAX` not covered +error[E0004]: non-exhaustive patterns: `u64::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12 | LL | m!(0, ..core::u64::MAX); - | ^ pattern `std::u64::MAX` not covered + | ^ pattern `u64::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u64` -error[E0004]: non-exhaustive patterns: `18446744073709551614u64..=std::u64::MAX` not covered +error[E0004]: non-exhaustive patterns: `18446744073709551614u64..=u64::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `18446744073709551614u64..=std::u64::MAX` not covered + | ^ pattern `18446744073709551614u64..=u64::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u64` @@ -259,11 +259,11 @@ LL | m!(0, ALMOST_MIN..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u64` -error[E0004]: non-exhaustive patterns: `std::u64::MAX` not covered +error[E0004]: non-exhaustive patterns: `u64::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12 | LL | m!(0, ..=ALMOST_MAX); - | ^ pattern `std::u64::MAX` not covered + | ^ pattern `u64::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u64` @@ -286,20 +286,20 @@ LL | m!(0, ..VAL_1 | VAL_2..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u64` -error[E0004]: non-exhaustive patterns: `std::u128::MAX` not covered +error[E0004]: non-exhaustive patterns: `u128::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12 | LL | m!(0, ..core::u128::MAX); - | ^ pattern `std::u128::MAX` not covered + | ^ pattern `u128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` -error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454u128..=std::u128::MAX` not covered +error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454u128..=u128::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `340282366920938463463374607431768211454u128..=std::u128::MAX` not covered + | ^ pattern `340282366920938463463374607431768211454u128..=u128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` @@ -313,11 +313,11 @@ LL | m!(0, ALMOST_MIN..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` -error[E0004]: non-exhaustive patterns: `std::u128::MAX` not covered +error[E0004]: non-exhaustive patterns: `u128::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12 | LL | m!(0, ..=ALMOST_MAX); - | ^ pattern `std::u128::MAX` not covered + | ^ pattern `u128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` @@ -340,38 +340,38 @@ LL | m!(0, ..VAL_1 | VAL_2..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` -error[E0004]: non-exhaustive patterns: `std::i8::MAX` not covered +error[E0004]: non-exhaustive patterns: `i8::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12 | LL | m!(0, ..core::i8::MAX); - | ^ pattern `std::i8::MAX` not covered + | ^ pattern `i8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i8` -error[E0004]: non-exhaustive patterns: `126i8..=std::i8::MAX` not covered +error[E0004]: non-exhaustive patterns: `126i8..=i8::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `126i8..=std::i8::MAX` not covered + | ^ pattern `126i8..=i8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i8` -error[E0004]: non-exhaustive patterns: `std::i8::MIN` not covered +error[E0004]: non-exhaustive patterns: `i8::MIN` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12 | LL | m!(0, ALMOST_MIN..); - | ^ pattern `std::i8::MIN` not covered + | ^ pattern `i8::MIN` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i8` -error[E0004]: non-exhaustive patterns: `std::i8::MAX` not covered +error[E0004]: non-exhaustive patterns: `i8::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12 | LL | m!(0, ..=ALMOST_MAX); - | ^ pattern `std::i8::MAX` not covered + | ^ pattern `i8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i8` @@ -394,38 +394,38 @@ LL | m!(0, ..VAL_1 | VAL_2..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i8` -error[E0004]: non-exhaustive patterns: `std::i16::MAX` not covered +error[E0004]: non-exhaustive patterns: `i16::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12 | LL | m!(0, ..core::i16::MAX); - | ^ pattern `std::i16::MAX` not covered + | ^ pattern `i16::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i16` -error[E0004]: non-exhaustive patterns: `32766i16..=std::i16::MAX` not covered +error[E0004]: non-exhaustive patterns: `32766i16..=i16::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `32766i16..=std::i16::MAX` not covered + | ^ pattern `32766i16..=i16::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i16` -error[E0004]: non-exhaustive patterns: `std::i16::MIN` not covered +error[E0004]: non-exhaustive patterns: `i16::MIN` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12 | LL | m!(0, ALMOST_MIN..); - | ^ pattern `std::i16::MIN` not covered + | ^ pattern `i16::MIN` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i16` -error[E0004]: non-exhaustive patterns: `std::i16::MAX` not covered +error[E0004]: non-exhaustive patterns: `i16::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12 | LL | m!(0, ..=ALMOST_MAX); - | ^ pattern `std::i16::MAX` not covered + | ^ pattern `i16::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i16` @@ -448,38 +448,38 @@ LL | m!(0, ..VAL_1 | VAL_2..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i16` -error[E0004]: non-exhaustive patterns: `std::i32::MAX` not covered +error[E0004]: non-exhaustive patterns: `i32::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12 | LL | m!(0, ..core::i32::MAX); - | ^ pattern `std::i32::MAX` not covered + | ^ pattern `i32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` -error[E0004]: non-exhaustive patterns: `2147483646i32..=std::i32::MAX` not covered +error[E0004]: non-exhaustive patterns: `2147483646i32..=i32::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `2147483646i32..=std::i32::MAX` not covered + | ^ pattern `2147483646i32..=i32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` -error[E0004]: non-exhaustive patterns: `std::i32::MIN` not covered +error[E0004]: non-exhaustive patterns: `i32::MIN` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12 | LL | m!(0, ALMOST_MIN..); - | ^ pattern `std::i32::MIN` not covered + | ^ pattern `i32::MIN` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` -error[E0004]: non-exhaustive patterns: `std::i32::MAX` not covered +error[E0004]: non-exhaustive patterns: `i32::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12 | LL | m!(0, ..=ALMOST_MAX); - | ^ pattern `std::i32::MAX` not covered + | ^ pattern `i32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` @@ -502,38 +502,38 @@ LL | m!(0, ..VAL_1 | VAL_2..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` -error[E0004]: non-exhaustive patterns: `std::i64::MAX` not covered +error[E0004]: non-exhaustive patterns: `i64::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12 | LL | m!(0, ..core::i64::MAX); - | ^ pattern `std::i64::MAX` not covered + | ^ pattern `i64::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i64` -error[E0004]: non-exhaustive patterns: `9223372036854775806i64..=std::i64::MAX` not covered +error[E0004]: non-exhaustive patterns: `9223372036854775806i64..=i64::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `9223372036854775806i64..=std::i64::MAX` not covered + | ^ pattern `9223372036854775806i64..=i64::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i64` -error[E0004]: non-exhaustive patterns: `std::i64::MIN` not covered +error[E0004]: non-exhaustive patterns: `i64::MIN` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12 | LL | m!(0, ALMOST_MIN..); - | ^ pattern `std::i64::MIN` not covered + | ^ pattern `i64::MIN` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i64` -error[E0004]: non-exhaustive patterns: `std::i64::MAX` not covered +error[E0004]: non-exhaustive patterns: `i64::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12 | LL | m!(0, ..=ALMOST_MAX); - | ^ pattern `std::i64::MAX` not covered + | ^ pattern `i64::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i64` @@ -556,38 +556,38 @@ LL | m!(0, ..VAL_1 | VAL_2..); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i64` -error[E0004]: non-exhaustive patterns: `std::i128::MAX` not covered +error[E0004]: non-exhaustive patterns: `i128::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12 | LL | m!(0, ..core::i128::MAX); - | ^ pattern `std::i128::MAX` not covered + | ^ pattern `i128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i128` -error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726i128..=std::i128::MAX` not covered +error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726i128..=i128::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `170141183460469231731687303715884105726i128..=std::i128::MAX` not covered + | ^ pattern `170141183460469231731687303715884105726i128..=i128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i128` -error[E0004]: non-exhaustive patterns: `std::i128::MIN` not covered +error[E0004]: non-exhaustive patterns: `i128::MIN` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12 | LL | m!(0, ALMOST_MIN..); - | ^ pattern `std::i128::MIN` not covered + | ^ pattern `i128::MIN` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i128` -error[E0004]: non-exhaustive patterns: `std::i128::MAX` not covered +error[E0004]: non-exhaustive patterns: `i128::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12 | LL | m!(0, ..=ALMOST_MAX); - | ^ pattern `std::i128::MAX` not covered + | ^ pattern `i128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i128` diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index c0539434d02..990210ffb6b 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -16,9 +16,7 @@ LL | Vec::new(); | ^^^ not found in this scope | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -LL | use std::prelude::v1::Vec; +help: consider importing this struct | LL | use std::vec::Vec; | diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index a6012835f44..087f4582b21 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -11,8 +11,6 @@ fn main() { // return type, which can't depend on the obligation. fn cycle1() -> impl Clone { //~^ ERROR cycle detected - //~| ERROR cycle detected - //~| ERROR cycle detected send(cycle2().clone()); //~^ ERROR cannot be sent between threads safely diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 64d02f07048..679b26efe59 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -36,37 +36,37 @@ LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... note: ...which requires computing type of `cycle2::{{opaque}}#0`... - --> $DIR/auto-trait-leak.rs:22:16 + --> $DIR/auto-trait-leak.rs:20:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 + --> $DIR/auto-trait-leak.rs:20:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 + --> $DIR/auto-trait-leak.rs:20:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 + --> $DIR/auto-trait-leak.rs:20:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 + --> $DIR/auto-trait-leak.rs:20:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires building MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 + --> $DIR/auto-trait-leak.rs:20:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 + --> $DIR/auto-trait-leak.rs:20:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,178 +84,8 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error[E0391]: cycle detected when computing type of `cycle1::{{opaque}}#0` - --> $DIR/auto-trait-leak.rs:12:16 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^ - | -note: ...which requires borrow-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing MIR for `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires unsafety-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires computing type of `cycle2::{{opaque}}#0`... - --> $DIR/auto-trait-leak.rs:22:16 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^ -note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `cycle1::{{opaque}}#0`, completing the cycle -note: cycle used when checking item types in top-level module - --> $DIR/auto-trait-leak.rs:1:1 - | -LL | / use std::cell::Cell; -LL | | use std::rc::Rc; -LL | | -LL | | fn send<T: Send>(_: T) {} -... | -LL | | Rc::new(String::from("foo")) -LL | | } - | |_^ - -error[E0391]: cycle detected when computing type of `cycle1::{{opaque}}#0` - --> $DIR/auto-trait-leak.rs:12:16 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^ - | -note: ...which requires borrow-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing MIR for `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires unsafety-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:12:1 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires computing type of `cycle2::{{opaque}}#0`... - --> $DIR/auto-trait-leak.rs:22:16 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^ -note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:22:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `cycle1::{{opaque}}#0`, completing the cycle -note: cycle used when checking item types in top-level module - --> $DIR/auto-trait-leak.rs:1:1 - | -LL | / use std::cell::Cell; -LL | | use std::rc::Rc; -LL | | -LL | | fn send<T: Send>(_: T) {} -... | -LL | | Rc::new(String::from("foo")) -LL | | } - | |_^ - error[E0277]: `std::rc::Rc<std::string::String>` cannot be sent between threads safely - --> $DIR/auto-trait-leak.rs:16:5 + --> $DIR/auto-trait-leak.rs:14:5 | LL | fn send<T: Send>(_: T) {} | ---- required by this bound in `send` @@ -269,7 +99,7 @@ LL | fn cycle2() -> impl Clone { = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>` = note: required because it appears within the type `impl std::clone::Clone` -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0391. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs index c7675781208..cf2773f4ef5 100644 --- a/src/test/ui/impl-trait/auto-trait.rs +++ b/src/test/ui/impl-trait/auto-trait.rs @@ -2,22 +2,24 @@ // the purposes of coherence checking #![feature(type_alias_impl_trait)] -trait OpaqueTrait { } -impl<T> OpaqueTrait for T { } +trait OpaqueTrait {} +impl<T> OpaqueTrait for T {} type OpaqueType = impl OpaqueTrait; -fn mk_opaque() -> OpaqueType { () } +fn mk_opaque() -> OpaqueType { + () +} #[derive(Debug)] struct D<T>(T); -trait AnotherTrait { } -impl<T: Send> AnotherTrait for T { } +trait AnotherTrait {} +impl<T: Send> AnotherTrait for T {} // This is in error, because we cannot assume that `OpaqueType: !Send`. // (We treat opaque types as "foreign types" that could grow more impls // in the future.) impl AnotherTrait for D<OpaqueType> { - //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` + //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>` } fn main() {} diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr index 5e72ca7a47b..16fe1b56b50 100644 --- a/src/test/ui/impl-trait/auto-trait.stderr +++ b/src/test/ui/impl-trait/auto-trait.stderr @@ -1,11 +1,11 @@ -error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`: - --> $DIR/auto-trait.rs:19:1 +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>`: + --> $DIR/auto-trait.rs:21:1 | -LL | impl<T: Send> AnotherTrait for T { } +LL | impl<T: Send> AnotherTrait for T {} | -------------------------------- first implementation here ... LL | impl AnotherTrait for D<OpaqueType> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<impl OpaqueTrait>` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr index 6cb2c9fb892..5131509cdf0 100644 --- a/src/test/ui/impl-trait/issue-55872-1.stderr +++ b/src/test/ui/impl-trait/issue-55872-1.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:12:5 + --> $DIR/issue-55872-1.rs:12:14 | LL | type E = impl Copy; - | ^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `S` + | ^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `S` | = note: required because it appears within the type `(S, T)` = note: the return type of a function must have a statically known size @@ -12,10 +12,10 @@ LL | impl<S: Default + std::marker::Copy> Bar for S { | ^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:12:5 + --> $DIR/issue-55872-1.rs:12:14 | LL | type E = impl Copy; - | ^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `T` | = note: required because it appears within the type `(S, T)` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr index 01371b4d5c6..649109e4c93 100644 --- a/src/test/ui/impl-trait/issue-55872-2.stderr +++ b/src/test/ui/impl-trait/issue-55872-2.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `impl std::future::Future: std::marker::Copy` is not satisfied - --> $DIR/issue-55872-2.rs:13:5 + --> $DIR/issue-55872-2.rs:13:14 | LL | type E = impl Copy; - | ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `impl std::future::Future` + | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `impl std::future::Future` | = note: the return type of a function must have a statically known size diff --git a/src/test/ui/impl-trait/issue-60473.rs b/src/test/ui/impl-trait/issue-60473.rs index 50cf0c8c6d6..2ef86f03d34 100644 --- a/src/test/ui/impl-trait/issue-60473.rs +++ b/src/test/ui/impl-trait/issue-60473.rs @@ -5,13 +5,11 @@ struct A<'a>(&'a ()); -trait Trait<T> { -} +trait Trait<T> {} -impl<T> Trait<T> for () { -} +impl<T> Trait<T> for () {} fn main() { - let x: impl Trait<A> = (); // FIXME: The error doesn't seem correct. - //~^ ERROR: opaque type expands to a recursive type + let x: impl Trait<A> = (); + //~^ ERROR: missing lifetime specifier } diff --git a/src/test/ui/impl-trait/issue-60473.stderr b/src/test/ui/impl-trait/issue-60473.stderr index 2d95be4e52c..367b5db5d2d 100644 --- a/src/test/ui/impl-trait/issue-60473.stderr +++ b/src/test/ui/impl-trait/issue-60473.stderr @@ -1,11 +1,15 @@ -error[E0720]: opaque type expands to a recursive type - --> $DIR/issue-60473.rs:15:12 +error[E0106]: missing lifetime specifier + --> $DIR/issue-60473.rs:13:23 | -LL | let x: impl Trait<A> = (); // FIXME: The error doesn't seem correct. - | ^^^^^^^^^^^^^ expands to a recursive type +LL | let x: impl Trait<A> = (); + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | fn main<'a>() { +LL | let x: impl Trait<A<'a>> = (); | - = note: type resolves to itself error: aborting due to previous error -For more information about this error, try `rustc --explain E0720`. +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/impl-trait/issue-67166.rs b/src/test/ui/impl-trait/issue-67166.rs index de7433a9bfc..efa67558bd7 100644 --- a/src/test/ui/impl-trait/issue-67166.rs +++ b/src/test/ui/impl-trait/issue-67166.rs @@ -4,8 +4,8 @@ #![allow(incomplete_features)] pub fn run() { - let _foo: Box<impl Copy + '_> = Box::new(()); // FIXME: The error doesn't much make sense. - //~^ ERROR: opaque type expands to a recursive type + let _foo: Box<impl Copy + '_> = Box::new(()); + //~^ ERROR: missing lifetime specifier } fn main() {} diff --git a/src/test/ui/impl-trait/issue-67166.stderr b/src/test/ui/impl-trait/issue-67166.stderr index 56cba3cff0b..14c78684e3e 100644 --- a/src/test/ui/impl-trait/issue-67166.stderr +++ b/src/test/ui/impl-trait/issue-67166.stderr @@ -1,11 +1,15 @@ -error[E0720]: opaque type expands to a recursive type - --> $DIR/issue-67166.rs:7:19 +error[E0106]: missing lifetime specifier + --> $DIR/issue-67166.rs:7:31 | -LL | let _foo: Box<impl Copy + '_> = Box::new(()); // FIXME: The error doesn't much make sense. - | ^^^^^^^^^^^^^^ expands to a recursive type +LL | let _foo: Box<impl Copy + '_> = Box::new(()); + | ^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | pub fn run<'a>() { +LL | let _foo: Box<impl Copy + 'a> = Box::new(()); | - = note: type resolves to itself error: aborting due to previous error -For more information about this error, try `rustc --explain E0720`. +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/impl-trait/negative-reasoning.rs b/src/test/ui/impl-trait/negative-reasoning.rs index 4977f9bdbac..d173fe83fb7 100644 --- a/src/test/ui/impl-trait/negative-reasoning.rs +++ b/src/test/ui/impl-trait/negative-reasoning.rs @@ -2,21 +2,22 @@ // other trait #![feature(type_alias_impl_trait)] -trait OpaqueTrait { } -impl<T> OpaqueTrait for T { } +trait OpaqueTrait {} +impl<T> OpaqueTrait for T {} type OpaqueType = impl OpaqueTrait; -fn mk_opaque() -> OpaqueType { () } +fn mk_opaque() -> OpaqueType { + () +} #[derive(Debug)] struct D<T>(T); -trait AnotherTrait { } -impl<T: std::fmt::Debug> AnotherTrait for T { } - +trait AnotherTrait {} +impl<T: std::fmt::Debug> AnotherTrait for T {} // This is in error, because we cannot assume that `OpaqueType: !Debug` impl AnotherTrait for D<OpaqueType> { - //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` + //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>` } fn main() {} diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr index 526a664726a..e43d8c857b2 100644 --- a/src/test/ui/impl-trait/negative-reasoning.stderr +++ b/src/test/ui/impl-trait/negative-reasoning.stderr @@ -1,13 +1,13 @@ -error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`: - --> $DIR/negative-reasoning.rs:18:1 +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<impl OpaqueTrait>`: + --> $DIR/negative-reasoning.rs:19:1 | -LL | impl<T: std::fmt::Debug> AnotherTrait for T { } +LL | impl<T: std::fmt::Debug> AnotherTrait for T {} | ------------------------------------------- first implementation here ... LL | impl AnotherTrait for D<OpaqueType> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<impl OpaqueTrait>` | - = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions + = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `impl OpaqueTrait` in future versions error: aborting due to previous error diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr index 5d9ae6a0301..7addc006e19 100644 --- a/src/test/ui/impl-trait/where-allowed.stderr +++ b/src/test/ui/impl-trait/where-allowed.stderr @@ -256,16 +256,16 @@ LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ error: could not find defining uses - --> $DIR/where-allowed.rs:155:1 + --> $DIR/where-allowed.rs:119:16 | -LL | type InTypeAlias<R> = impl Debug; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type Out = impl Debug; + | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/where-allowed.rs:119:5 + --> $DIR/where-allowed.rs:155:23 | -LL | type Out = impl Debug; - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | type InTypeAlias<R> = impl Debug; + | ^^^^^^^^^^ error: aborting due to 42 previous errors diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index 6bd5e035f57..de0c579f630 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -1,14 +1,14 @@ error[E0391]: cycle detected when const-evaluating `a` - --> $DIR/infinite-recursion-const-fn.rs:3:25 + --> $DIR/infinite-recursion-const-fn.rs:3:1 | LL | const fn a() -> usize { b() } - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires const-evaluating `b`... - --> $DIR/infinite-recursion-const-fn.rs:4:25 + --> $DIR/infinite-recursion-const-fn.rs:4:1 | LL | const fn b() -> usize { a() } - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating `a`, completing the cycle note: cycle used when const-evaluating `ARR::{{constant}}#0` --> $DIR/infinite-recursion-const-fn.rs:5:18 diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 11f82b842ba..6d1df4fda2e 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -6,7 +6,10 @@ LL | enum MList { Cons(isize, MList), Nil } | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `MList` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `MList` representable + | +LL | enum MList { Cons(isize, Box<MList>), Nil } + | ^^^^ ^ error[E0391]: cycle detected when computing drop-check constraints for `MList` --> $DIR/infinite-tag-type-recursion.rs:1:1 diff --git a/src/test/ui/issues/issue-17431-1.stderr b/src/test/ui/issues/issue-17431-1.stderr index eb5a1366e89..58d087ca199 100644 --- a/src/test/ui/issues/issue-17431-1.stderr +++ b/src/test/ui/issues/issue-17431-1.stderr @@ -2,11 +2,14 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-1.rs:1:1 | LL | struct Foo { foo: Option<Option<Foo>> } - | ^^^^^^^^^^ ------------------------ recursive without indirection + | ^^^^^^^^^^ ------------------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable + | +LL | struct Foo { foo: Box<Option<Option<Foo>>> } + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-2.stderr b/src/test/ui/issues/issue-17431-2.stderr index 3a7b0e9ce79..eba4bf6d1d5 100644 --- a/src/test/ui/issues/issue-17431-2.stderr +++ b/src/test/ui/issues/issue-17431-2.stderr @@ -2,21 +2,27 @@ error[E0072]: recursive type `Baz` has infinite size --> $DIR/issue-17431-2.rs:1:1 | LL | struct Baz { q: Option<Foo> } - | ^^^^^^^^^^ -------------- recursive without indirection + | ^^^^^^^^^^ ----------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Baz` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable + | +LL | struct Baz { q: Box<Option<Foo>> } + | ^^^^ ^ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-2.rs:4:1 | LL | struct Foo { q: Option<Baz> } - | ^^^^^^^^^^ -------------- recursive without indirection + | ^^^^^^^^^^ ----------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable + | +LL | struct Foo { q: Box<Option<Baz>> } + | ^^^^ ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17431-3.stderr b/src/test/ui/issues/issue-17431-3.stderr index 675a2e27142..f6b15d0528a 100644 --- a/src/test/ui/issues/issue-17431-3.stderr +++ b/src/test/ui/issues/issue-17431-3.stderr @@ -2,11 +2,14 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-3.rs:3:1 | LL | struct Foo { foo: Mutex<Option<Foo>> } - | ^^^^^^^^^^ ----------------------- recursive without indirection + | ^^^^^^^^^^ ------------------ recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable + | +LL | struct Foo { foo: Box<Mutex<Option<Foo>>> } + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-4.stderr b/src/test/ui/issues/issue-17431-4.stderr index aff9071095c..aa709e1ad51 100644 --- a/src/test/ui/issues/issue-17431-4.stderr +++ b/src/test/ui/issues/issue-17431-4.stderr @@ -2,11 +2,14 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/issue-17431-4.rs:3:1 | LL | struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T> } - | ^^^^^^^^^^^^^ --------------------------- recursive without indirection + | ^^^^^^^^^^^^^ ---------------------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable + | +LL | struct Foo<T> { foo: Box<Option<Option<Foo<T>>>>, marker: marker::PhantomData<T> } + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-5.stderr b/src/test/ui/issues/issue-17431-5.stderr index 537f9f34f55..1558cffb036 100644 --- a/src/test/ui/issues/issue-17431-5.stderr +++ b/src/test/ui/issues/issue-17431-5.stderr @@ -2,11 +2,14 @@ error[E0072]: recursive type `Bar` has infinite size --> $DIR/issue-17431-5.rs:5:1 | LL | struct Bar<T> { x: Bar<Foo> , marker: marker::PhantomData<T> } - | ^^^^^^^^^^^^^ ----------- recursive without indirection + | ^^^^^^^^^^^^^ -------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable + | +LL | struct Bar<T> { x: Box<Bar<Foo>> , marker: marker::PhantomData<T> } + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-6.stderr b/src/test/ui/issues/issue-17431-6.stderr index cb2dab95014..f2aa2a79c82 100644 --- a/src/test/ui/issues/issue-17431-6.stderr +++ b/src/test/ui/issues/issue-17431-6.stderr @@ -6,7 +6,10 @@ LL | enum Foo { X(Mutex<Option<Foo>>) } | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable + | +LL | enum Foo { X(Box<Mutex<Option<Foo>>>) } + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17431-7.stderr b/src/test/ui/issues/issue-17431-7.stderr index de70851da4b..684c3089e85 100644 --- a/src/test/ui/issues/issue-17431-7.stderr +++ b/src/test/ui/issues/issue-17431-7.stderr @@ -6,7 +6,10 @@ LL | enum Foo { Voo(Option<Option<Foo>>) } | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable + | +LL | enum Foo { Voo(Box<Option<Option<Foo>>>) } + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17546.stderr b/src/test/ui/issues/issue-17546.stderr index 8bf40790f0b..95939cf6b38 100644 --- a/src/test/ui/issues/issue-17546.stderr +++ b/src/test/ui/issues/issue-17546.stderr @@ -30,11 +30,10 @@ LL | use std::fmt::Result; | LL | use std::io::Result; | -LL | use std::prelude::v1::Result; - | LL | use std::result::Result; | - and 1 other candidate +LL | use std::thread::Result; + | error[E0573]: expected type, found variant `Result` --> $DIR/issue-17546.rs:30:13 @@ -48,11 +47,10 @@ LL | use std::fmt::Result; | LL | use std::io::Result; | -LL | use std::prelude::v1::Result; - | LL | use std::result::Result; | - and 1 other candidate +LL | use std::thread::Result; + | error[E0573]: expected type, found variant `NoResult` --> $DIR/issue-17546.rs:35:15 diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr index 89df58dd2dc..5e050f27ac5 100644 --- a/src/test/ui/issues/issue-20605.stderr +++ b/src/test/ui/issues/issue-20605.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `dyn std::iter::Iterator<Item = &mut u8>` cannot be known at compilation time +error[E0277]: the size for values of type `dyn std::iter::Iterator<Item = &'a mut u8>` cannot be known at compilation time --> $DIR/issue-20605.rs:2:17 | LL | for item in *things { *item = 0 } | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator<Item = &mut u8>` + = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator<Item = &'a mut u8>` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> = note: required by `std::iter::IntoIterator::into_iter` diff --git a/src/test/ui/issues/issue-2718-a.stderr b/src/test/ui/issues/issue-2718-a.stderr index 0f52c791928..d152ffde4e5 100644 --- a/src/test/ui/issues/issue-2718-a.stderr +++ b/src/test/ui/issues/issue-2718-a.stderr @@ -7,7 +7,10 @@ LL | pub struct Pong(SendPacket<Ping>); | | recursive without indirection | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `pingpong::Pong` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `pingpong::Pong` representable + | +LL | pub struct Pong(Box<SendPacket<Ping>>); + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3008-1.stderr b/src/test/ui/issues/issue-3008-1.stderr index f12274134ee..87ee36df216 100644 --- a/src/test/ui/issues/issue-3008-1.stderr +++ b/src/test/ui/issues/issue-3008-1.stderr @@ -7,7 +7,10 @@ LL | enum Bar { LL | BarSome(Bar) | --- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable + | +LL | BarSome(Box<Bar>) + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3008-2.stderr b/src/test/ui/issues/issue-3008-2.stderr index acc15f4b57c..369a19d37e6 100644 --- a/src/test/ui/issues/issue-3008-2.stderr +++ b/src/test/ui/issues/issue-3008-2.stderr @@ -2,11 +2,14 @@ error[E0072]: recursive type `Bar` has infinite size --> $DIR/issue-3008-2.rs:2:1 | LL | struct Bar { x: Bar } - | ^^^^^^^^^^ ------ recursive without indirection + | ^^^^^^^^^^ --- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable + | +LL | struct Bar { x: Box<Bar> } + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3008-3.stderr b/src/test/ui/issues/issue-3008-3.stderr index d08a3d9708d..0b162eff94a 100644 --- a/src/test/ui/issues/issue-3008-3.stderr +++ b/src/test/ui/issues/issue-3008-3.stderr @@ -6,7 +6,10 @@ LL | enum E2<T> { V2(E2<E1>, marker::PhantomData<T>), } | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `E2` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E2` representable + | +LL | enum E2<T> { V2(Box<E2<E1>>, marker::PhantomData<T>), } + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31910.stderr b/src/test/ui/issues/issue-31910.stderr index c5c988cdaa7..2603c944207 100644 --- a/src/test/ui/issues/issue-31910.stderr +++ b/src/test/ui/issues/issue-31910.stderr @@ -3,11 +3,6 @@ error[E0308]: mismatched types | LL | X = Trait::Number, | ^^^^^^^^^^^^^ expected `isize`, found `i32` - | -help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit - | -LL | X = Trait::Number.try_into().unwrap(), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-32326.stderr b/src/test/ui/issues/issue-32326.stderr index 5967627e51a..0f3d3690b73 100644 --- a/src/test/ui/issues/issue-32326.stderr +++ b/src/test/ui/issues/issue-32326.stderr @@ -8,7 +8,10 @@ LL | Plus(Expr, Expr), | | | recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Expr` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Expr` representable + | +LL | Plus(Box<Expr>, Box<Expr>), + | ^^^^ ^ ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3779.stderr b/src/test/ui/issues/issue-3779.stderr index ba1e842c610..7b17e914216 100644 --- a/src/test/ui/issues/issue-3779.stderr +++ b/src/test/ui/issues/issue-3779.stderr @@ -5,9 +5,12 @@ LL | struct S { | ^^^^^^^^ recursive type has infinite size LL | LL | element: Option<S> - | ------------------ recursive without indirection + | --------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `S` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `S` representable + | +LL | element: Box<Option<S>> + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-44216-add-instant.rs b/src/test/ui/issues/issue-44216-add-instant.rs index c2f3598f645..78cfecf2f32 100644 --- a/src/test/ui/issues/issue-44216-add-instant.rs +++ b/src/test/ui/issues/issue-44216-add-instant.rs @@ -6,5 +6,5 @@ use std::time::{Instant, Duration}; fn main() { let now = Instant::now(); - let _ = now + Duration::from_secs(u64::max_value()); + let _ = now + Duration::from_secs(u64::MAX); } diff --git a/src/test/ui/issues/issue-44216-add-system-time.rs b/src/test/ui/issues/issue-44216-add-system-time.rs index 9a88cb7c189..7e9a3f802ec 100644 --- a/src/test/ui/issues/issue-44216-add-system-time.rs +++ b/src/test/ui/issues/issue-44216-add-system-time.rs @@ -6,5 +6,5 @@ use std::time::{Duration, SystemTime}; fn main() { let now = SystemTime::now(); - let _ = now + Duration::from_secs(u64::max_value()); + let _ = now + Duration::from_secs(u64::MAX); } diff --git a/src/test/ui/issues/issue-44216-sub-instant.rs b/src/test/ui/issues/issue-44216-sub-instant.rs index 2decd88bbc0..e40f80d449d 100644 --- a/src/test/ui/issues/issue-44216-sub-instant.rs +++ b/src/test/ui/issues/issue-44216-sub-instant.rs @@ -6,5 +6,5 @@ use std::time::{Instant, Duration}; fn main() { let now = Instant::now(); - let _ = now - Duration::from_secs(u64::max_value()); + let _ = now - Duration::from_secs(u64::MAX); } diff --git a/src/test/ui/issues/issue-44216-sub-system-time.rs b/src/test/ui/issues/issue-44216-sub-system-time.rs index e58a31a41a5..2c5a000fab6 100644 --- a/src/test/ui/issues/issue-44216-sub-system-time.rs +++ b/src/test/ui/issues/issue-44216-sub-system-time.rs @@ -6,5 +6,5 @@ use std::time::{Duration, SystemTime}; fn main() { let now = SystemTime::now(); - let _ = now - Duration::from_secs(u64::max_value()); + let _ = now - Duration::from_secs(u64::MAX); } diff --git a/src/test/ui/issues/issue-57271.stderr b/src/test/ui/issues/issue-57271.stderr index 4f164624f7a..b7c799e163c 100644 --- a/src/test/ui/issues/issue-57271.stderr +++ b/src/test/ui/issues/issue-57271.stderr @@ -7,7 +7,10 @@ LL | Class(ClassTypeSignature), LL | Array(TypeSignature), | ------------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ObjectType` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ObjectType` representable + | +LL | Array(Box<TypeSignature>), + | ^^^^ ^ error[E0072]: recursive type `TypeSignature` has infinite size --> $DIR/issue-57271.rs:19:1 @@ -18,7 +21,10 @@ LL | Base(BaseType), LL | Object(ObjectType), | ---------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `TypeSignature` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `TypeSignature` representable + | +LL | Object(Box<ObjectType>), + | ^^^^ ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-60662.stdout b/src/test/ui/issues/issue-60662.stdout index 5a4b49cfa1e..cebe834824a 100644 --- a/src/test/ui/issues/issue-60662.stdout +++ b/src/test/ui/issues/issue-60662.stdout @@ -10,5 +10,5 @@ extern crate std; trait Animal { } fn main() { - pub type ServeFut = impl Animal; + pub type ServeFut = /*impl Trait*/; } diff --git a/src/test/ui/issues/issue-72554.stderr b/src/test/ui/issues/issue-72554.stderr index 9db65f4a2ee..9de94c393a7 100644 --- a/src/test/ui/issues/issue-72554.stderr +++ b/src/test/ui/issues/issue-72554.stderr @@ -6,7 +6,10 @@ LL | pub enum ElemDerived { LL | A(ElemDerived) | ----------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ElemDerived` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ElemDerived` representable + | +LL | A(Box<ElemDerived>) + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-72839-error-overflow.rs b/src/test/ui/issues/issue-72839-error-overflow.rs new file mode 100644 index 00000000000..6562d228409 --- /dev/null +++ b/src/test/ui/issues/issue-72839-error-overflow.rs @@ -0,0 +1,19 @@ +// Regression test for issue #72839 +// Tests that we do not overflow during trait selection after +// a type error occurs +use std::ops::Rem; +trait Foo {} +struct MyStruct<T>(T); + +impl<T, U> Rem<MyStruct<T>> for MyStruct<U> where MyStruct<U>: Rem<MyStruct<T>> { + type Output = u8; + fn rem(self, _: MyStruct<T>) -> Self::Output { + panic!() + } +} + +fn main() {} + +fn foo() { + if missing_var % 8 == 0 {} //~ ERROR cannot find +} diff --git a/src/test/ui/issues/issue-72839-error-overflow.stderr b/src/test/ui/issues/issue-72839-error-overflow.stderr new file mode 100644 index 00000000000..c4b6f90ca69 --- /dev/null +++ b/src/test/ui/issues/issue-72839-error-overflow.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `missing_var` in this scope + --> $DIR/issue-72839-error-overflow.rs:18:8 + | +LL | if missing_var % 8 == 0 {} + | ^^^^^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/issues/issue-72933-match-stack-overflow.rs b/src/test/ui/issues/issue-72933-match-stack-overflow.rs new file mode 100644 index 00000000000..aa796bcf5a0 --- /dev/null +++ b/src/test/ui/issues/issue-72933-match-stack-overflow.rs @@ -0,0 +1,5208 @@ +// build-pass +// ignore-tidy-filelength +#![crate_type="rlib"] + +fn banana(v: &str) -> u32 { + match v { + "0" => 0, + "1" => 1, + "2" => 2, + "3" => 3, + "4" => 4, + "5" => 5, + "6" => 6, + "7" => 7, + "8" => 8, + "9" => 9, + "10" => 10, + "11" => 11, + "12" => 12, + "13" => 13, + "14" => 14, + "15" => 15, + "16" => 16, + "17" => 17, + "18" => 18, + "19" => 19, + "20" => 20, + "21" => 21, + "22" => 22, + "23" => 23, + "24" => 24, + "25" => 25, + "26" => 26, + "27" => 27, + "28" => 28, + "29" => 29, + "30" => 30, + "31" => 31, + "32" => 32, + "33" => 33, + "34" => 34, + "35" => 35, + "36" => 36, + "37" => 37, + "38" => 38, + "39" => 39, + "40" => 40, + "41" => 41, + "42" => 42, + "43" => 43, + "44" => 44, + "45" => 45, + "46" => 46, + "47" => 47, + "48" => 48, + "49" => 49, + "50" => 50, + "51" => 51, + "52" => 52, + "53" => 53, + "54" => 54, + "55" => 55, + "56" => 56, + "57" => 57, + "58" => 58, + "59" => 59, + "60" => 60, + "61" => 61, + "62" => 62, + "63" => 63, + "64" => 64, + "65" => 65, + "66" => 66, + "67" => 67, + "68" => 68, + "69" => 69, + "70" => 70, + "71" => 71, + "72" => 72, + "73" => 73, + "74" => 74, + "75" => 75, + "76" => 76, + "77" => 77, + "78" => 78, + "79" => 79, + "80" => 80, + "81" => 81, + "82" => 82, + "83" => 83, + "84" => 84, + "85" => 85, + "86" => 86, + "87" => 87, + "88" => 88, + "89" => 89, + "90" => 90, + "91" => 91, + "92" => 92, + "93" => 93, + "94" => 94, + "95" => 95, + "96" => 96, + "97" => 97, + "98" => 98, + "99" => 99, + "100" => 100, + "101" => 101, + "102" => 102, + "103" => 103, + "104" => 104, + "105" => 105, + "106" => 106, + "107" => 107, + "108" => 108, + "109" => 109, + "110" => 110, + "111" => 111, + "112" => 112, + "113" => 113, + "114" => 114, + "115" => 115, + "116" => 116, + "117" => 117, + "118" => 118, + "119" => 119, + "120" => 120, + "121" => 121, + "122" => 122, + "123" => 123, + "124" => 124, + "125" => 125, + "126" => 126, + "127" => 127, + "128" => 128, + "129" => 129, + "130" => 130, + "131" => 131, + "132" => 132, + "133" => 133, + "134" => 134, + "135" => 135, + "136" => 136, + "137" => 137, + "138" => 138, + "139" => 139, + "140" => 140, + "141" => 141, + "142" => 142, + "143" => 143, + "144" => 144, + "145" => 145, + "146" => 146, + "147" => 147, + "148" => 148, + "149" => 149, + "150" => 150, + "151" => 151, + "152" => 152, + "153" => 153, + "154" => 154, + "155" => 155, + "156" => 156, + "157" => 157, + "158" => 158, + "159" => 159, + "160" => 160, + "161" => 161, + "162" => 162, + "163" => 163, + "164" => 164, + "165" => 165, + "166" => 166, + "167" => 167, + "168" => 168, + "169" => 169, + "170" => 170, + "171" => 171, + "172" => 172, + "173" => 173, + "174" => 174, + "175" => 175, + "176" => 176, + "177" => 177, + "178" => 178, + "179" => 179, + "180" => 180, + "181" => 181, + "182" => 182, + "183" => 183, + "184" => 184, + "185" => 185, + "186" => 186, + "187" => 187, + "188" => 188, + "189" => 189, + "190" => 190, + "191" => 191, + "192" => 192, + "193" => 193, + "194" => 194, + "195" => 195, + "196" => 196, + "197" => 197, + "198" => 198, + "199" => 199, + "200" => 200, + "201" => 201, + "202" => 202, + "203" => 203, + "204" => 204, + "205" => 205, + "206" => 206, + "207" => 207, + "208" => 208, + "209" => 209, + "210" => 210, + "211" => 211, + "212" => 212, + "213" => 213, + "214" => 214, + "215" => 215, + "216" => 216, + "217" => 217, + "218" => 218, + "219" => 219, + "220" => 220, + "221" => 221, + "222" => 222, + "223" => 223, + "224" => 224, + "225" => 225, + "226" => 226, + "227" => 227, + "228" => 228, + "229" => 229, + "230" => 230, + "231" => 231, + "232" => 232, + "233" => 233, + "234" => 234, + "235" => 235, + "236" => 236, + "237" => 237, + "238" => 238, + "239" => 239, + "240" => 240, + "241" => 241, + "242" => 242, + "243" => 243, + "244" => 244, + "245" => 245, + "246" => 246, + "247" => 247, + "248" => 248, + "249" => 249, + "250" => 250, + "251" => 251, + "252" => 252, + "253" => 253, + "254" => 254, + "255" => 255, + "256" => 256, + "257" => 257, + "258" => 258, + "259" => 259, + "260" => 260, + "261" => 261, + "262" => 262, + "263" => 263, + "264" => 264, + "265" => 265, + "266" => 266, + "267" => 267, + "268" => 268, + "269" => 269, + "270" => 270, + "271" => 271, + "272" => 272, + "273" => 273, + "274" => 274, + "275" => 275, + "276" => 276, + "277" => 277, + "278" => 278, + "279" => 279, + "280" => 280, + "281" => 281, + "282" => 282, + "283" => 283, + "284" => 284, + "285" => 285, + "286" => 286, + "287" => 287, + "288" => 288, + "289" => 289, + "290" => 290, + "291" => 291, + "292" => 292, + "293" => 293, + "294" => 294, + "295" => 295, + "296" => 296, + "297" => 297, + "298" => 298, + "299" => 299, + "300" => 300, + "301" => 301, + "302" => 302, + "303" => 303, + "304" => 304, + "305" => 305, + "306" => 306, + "307" => 307, + "308" => 308, + "309" => 309, + "310" => 310, + "311" => 311, + "312" => 312, + "313" => 313, + "314" => 314, + "315" => 315, + "316" => 316, + "317" => 317, + "318" => 318, + "319" => 319, + "320" => 320, + "321" => 321, + "322" => 322, + "323" => 323, + "324" => 324, + "325" => 325, + "326" => 326, + "327" => 327, + "328" => 328, + "329" => 329, + "330" => 330, + "331" => 331, + "332" => 332, + "333" => 333, + "334" => 334, + "335" => 335, + "336" => 336, + "337" => 337, + "338" => 338, + "339" => 339, + "340" => 340, + "341" => 341, + "342" => 342, + "343" => 343, + "344" => 344, + "345" => 345, + "346" => 346, + "347" => 347, + "348" => 348, + "349" => 349, + "350" => 350, + "351" => 351, + "352" => 352, + "353" => 353, + "354" => 354, + "355" => 355, + "356" => 356, + "357" => 357, + "358" => 358, + "359" => 359, + "360" => 360, + "361" => 361, + "362" => 362, + "363" => 363, + "364" => 364, + "365" => 365, + "366" => 366, + "367" => 367, + "368" => 368, + "369" => 369, + "370" => 370, + "371" => 371, + "372" => 372, + "373" => 373, + "374" => 374, + "375" => 375, + "376" => 376, + "377" => 377, + "378" => 378, + "379" => 379, + "380" => 380, + "381" => 381, + "382" => 382, + "383" => 383, + "384" => 384, + "385" => 385, + "386" => 386, + "387" => 387, + "388" => 388, + "389" => 389, + "390" => 390, + "391" => 391, + "392" => 392, + "393" => 393, + "394" => 394, + "395" => 395, + "396" => 396, + "397" => 397, + "398" => 398, + "399" => 399, + "400" => 400, + "401" => 401, + "402" => 402, + "403" => 403, + "404" => 404, + "405" => 405, + "406" => 406, + "407" => 407, + "408" => 408, + "409" => 409, + "410" => 410, + "411" => 411, + "412" => 412, + "413" => 413, + "414" => 414, + "415" => 415, + "416" => 416, + "417" => 417, + "418" => 418, + "419" => 419, + "420" => 420, + "421" => 421, + "422" => 422, + "423" => 423, + "424" => 424, + "425" => 425, + "426" => 426, + "427" => 427, + "428" => 428, + "429" => 429, + "430" => 430, + "431" => 431, + "432" => 432, + "433" => 433, + "434" => 434, + "435" => 435, + "436" => 436, + "437" => 437, + "438" => 438, + "439" => 439, + "440" => 440, + "441" => 441, + "442" => 442, + "443" => 443, + "444" => 444, + "445" => 445, + "446" => 446, + "447" => 447, + "448" => 448, + "449" => 449, + "450" => 450, + "451" => 451, + "452" => 452, + "453" => 453, + "454" => 454, + "455" => 455, + "456" => 456, + "457" => 457, + "458" => 458, + "459" => 459, + "460" => 460, + "461" => 461, + "462" => 462, + "463" => 463, + "464" => 464, + "465" => 465, + "466" => 466, + "467" => 467, + "468" => 468, + "469" => 469, + "470" => 470, + "471" => 471, + "472" => 472, + "473" => 473, + "474" => 474, + "475" => 475, + "476" => 476, + "477" => 477, + "478" => 478, + "479" => 479, + "480" => 480, + "481" => 481, + "482" => 482, + "483" => 483, + "484" => 484, + "485" => 485, + "486" => 486, + "487" => 487, + "488" => 488, + "489" => 489, + "490" => 490, + "491" => 491, + "492" => 492, + "493" => 493, + "494" => 494, + "495" => 495, + "496" => 496, + "497" => 497, + "498" => 498, + "499" => 499, + "500" => 500, + "501" => 501, + "502" => 502, + "503" => 503, + "504" => 504, + "505" => 505, + "506" => 506, + "507" => 507, + "508" => 508, + "509" => 509, + "510" => 510, + "511" => 511, + "512" => 512, + "513" => 513, + "514" => 514, + "515" => 515, + "516" => 516, + "517" => 517, + "518" => 518, + "519" => 519, + "520" => 520, + "521" => 521, + "522" => 522, + "523" => 523, + "524" => 524, + "525" => 525, + "526" => 526, + "527" => 527, + "528" => 528, + "529" => 529, + "530" => 530, + "531" => 531, + "532" => 532, + "533" => 533, + "534" => 534, + "535" => 535, + "536" => 536, + "537" => 537, + "538" => 538, + "539" => 539, + "540" => 540, + "541" => 541, + "542" => 542, + "543" => 543, + "544" => 544, + "545" => 545, + "546" => 546, + "547" => 547, + "548" => 548, + "549" => 549, + "550" => 550, + "551" => 551, + "552" => 552, + "553" => 553, + "554" => 554, + "555" => 555, + "556" => 556, + "557" => 557, + "558" => 558, + "559" => 559, + "560" => 560, + "561" => 561, + "562" => 562, + "563" => 563, + "564" => 564, + "565" => 565, + "566" => 566, + "567" => 567, + "568" => 568, + "569" => 569, + "570" => 570, + "571" => 571, + "572" => 572, + "573" => 573, + "574" => 574, + "575" => 575, + "576" => 576, + "577" => 577, + "578" => 578, + "579" => 579, + "580" => 580, + "581" => 581, + "582" => 582, + "583" => 583, + "584" => 584, + "585" => 585, + "586" => 586, + "587" => 587, + "588" => 588, + "589" => 589, + "590" => 590, + "591" => 591, + "592" => 592, + "593" => 593, + "594" => 594, + "595" => 595, + "596" => 596, + "597" => 597, + "598" => 598, + "599" => 599, + "600" => 600, + "601" => 601, + "602" => 602, + "603" => 603, + "604" => 604, + "605" => 605, + "606" => 606, + "607" => 607, + "608" => 608, + "609" => 609, + "610" => 610, + "611" => 611, + "612" => 612, + "613" => 613, + "614" => 614, + "615" => 615, + "616" => 616, + "617" => 617, + "618" => 618, + "619" => 619, + "620" => 620, + "621" => 621, + "622" => 622, + "623" => 623, + "624" => 624, + "625" => 625, + "626" => 626, + "627" => 627, + "628" => 628, + "629" => 629, + "630" => 630, + "631" => 631, + "632" => 632, + "633" => 633, + "634" => 634, + "635" => 635, + "636" => 636, + "637" => 637, + "638" => 638, + "639" => 639, + "640" => 640, + "641" => 641, + "642" => 642, + "643" => 643, + "644" => 644, + "645" => 645, + "646" => 646, + "647" => 647, + "648" => 648, + "649" => 649, + "650" => 650, + "651" => 651, + "652" => 652, + "653" => 653, + "654" => 654, + "655" => 655, + "656" => 656, + "657" => 657, + "658" => 658, + "659" => 659, + "660" => 660, + "661" => 661, + "662" => 662, + "663" => 663, + "664" => 664, + "665" => 665, + "666" => 666, + "667" => 667, + "668" => 668, + "669" => 669, + "670" => 670, + "671" => 671, + "672" => 672, + "673" => 673, + "674" => 674, + "675" => 675, + "676" => 676, + "677" => 677, + "678" => 678, + "679" => 679, + "680" => 680, + "681" => 681, + "682" => 682, + "683" => 683, + "684" => 684, + "685" => 685, + "686" => 686, + "687" => 687, + "688" => 688, + "689" => 689, + "690" => 690, + "691" => 691, + "692" => 692, + "693" => 693, + "694" => 694, + "695" => 695, + "696" => 696, + "697" => 697, + "698" => 698, + "699" => 699, + "700" => 700, + "701" => 701, + "702" => 702, + "703" => 703, + "704" => 704, + "705" => 705, + "706" => 706, + "707" => 707, + "708" => 708, + "709" => 709, + "710" => 710, + "711" => 711, + "712" => 712, + "713" => 713, + "714" => 714, + "715" => 715, + "716" => 716, + "717" => 717, + "718" => 718, + "719" => 719, + "720" => 720, + "721" => 721, + "722" => 722, + "723" => 723, + "724" => 724, + "725" => 725, + "726" => 726, + "727" => 727, + "728" => 728, + "729" => 729, + "730" => 730, + "731" => 731, + "732" => 732, + "733" => 733, + "734" => 734, + "735" => 735, + "736" => 736, + "737" => 737, + "738" => 738, + "739" => 739, + "740" => 740, + "741" => 741, + "742" => 742, + "743" => 743, + "744" => 744, + "745" => 745, + "746" => 746, + "747" => 747, + "748" => 748, + "749" => 749, + "750" => 750, + "751" => 751, + "752" => 752, + "753" => 753, + "754" => 754, + "755" => 755, + "756" => 756, + "757" => 757, + "758" => 758, + "759" => 759, + "760" => 760, + "761" => 761, + "762" => 762, + "763" => 763, + "764" => 764, + "765" => 765, + "766" => 766, + "767" => 767, + "768" => 768, + "769" => 769, + "770" => 770, + "771" => 771, + "772" => 772, + "773" => 773, + "774" => 774, + "775" => 775, + "776" => 776, + "777" => 777, + "778" => 778, + "779" => 779, + "780" => 780, + "781" => 781, + "782" => 782, + "783" => 783, + "784" => 784, + "785" => 785, + "786" => 786, + "787" => 787, + "788" => 788, + "789" => 789, + "790" => 790, + "791" => 791, + "792" => 792, + "793" => 793, + "794" => 794, + "795" => 795, + "796" => 796, + "797" => 797, + "798" => 798, + "799" => 799, + "800" => 800, + "801" => 801, + "802" => 802, + "803" => 803, + "804" => 804, + "805" => 805, + "806" => 806, + "807" => 807, + "808" => 808, + "809" => 809, + "810" => 810, + "811" => 811, + "812" => 812, + "813" => 813, + "814" => 814, + "815" => 815, + "816" => 816, + "817" => 817, + "818" => 818, + "819" => 819, + "820" => 820, + "821" => 821, + "822" => 822, + "823" => 823, + "824" => 824, + "825" => 825, + "826" => 826, + "827" => 827, + "828" => 828, + "829" => 829, + "830" => 830, + "831" => 831, + "832" => 832, + "833" => 833, + "834" => 834, + "835" => 835, + "836" => 836, + "837" => 837, + "838" => 838, + "839" => 839, + "840" => 840, + "841" => 841, + "842" => 842, + "843" => 843, + "844" => 844, + "845" => 845, + "846" => 846, + "847" => 847, + "848" => 848, + "849" => 849, + "850" => 850, + "851" => 851, + "852" => 852, + "853" => 853, + "854" => 854, + "855" => 855, + "856" => 856, + "857" => 857, + "858" => 858, + "859" => 859, + "860" => 860, + "861" => 861, + "862" => 862, + "863" => 863, + "864" => 864, + "865" => 865, + "866" => 866, + "867" => 867, + "868" => 868, + "869" => 869, + "870" => 870, + "871" => 871, + "872" => 872, + "873" => 873, + "874" => 874, + "875" => 875, + "876" => 876, + "877" => 877, + "878" => 878, + "879" => 879, + "880" => 880, + "881" => 881, + "882" => 882, + "883" => 883, + "884" => 884, + "885" => 885, + "886" => 886, + "887" => 887, + "888" => 888, + "889" => 889, + "890" => 890, + "891" => 891, + "892" => 892, + "893" => 893, + "894" => 894, + "895" => 895, + "896" => 896, + "897" => 897, + "898" => 898, + "899" => 899, + "900" => 900, + "901" => 901, + "902" => 902, + "903" => 903, + "904" => 904, + "905" => 905, + "906" => 906, + "907" => 907, + "908" => 908, + "909" => 909, + "910" => 910, + "911" => 911, + "912" => 912, + "913" => 913, + "914" => 914, + "915" => 915, + "916" => 916, + "917" => 917, + "918" => 918, + "919" => 919, + "920" => 920, + "921" => 921, + "922" => 922, + "923" => 923, + "924" => 924, + "925" => 925, + "926" => 926, + "927" => 927, + "928" => 928, + "929" => 929, + "930" => 930, + "931" => 931, + "932" => 932, + "933" => 933, + "934" => 934, + "935" => 935, + "936" => 936, + "937" => 937, + "938" => 938, + "939" => 939, + "940" => 940, + "941" => 941, + "942" => 942, + "943" => 943, + "944" => 944, + "945" => 945, + "946" => 946, + "947" => 947, + "948" => 948, + "949" => 949, + "950" => 950, + "951" => 951, + "952" => 952, + "953" => 953, + "954" => 954, + "955" => 955, + "956" => 956, + "957" => 957, + "958" => 958, + "959" => 959, + "960" => 960, + "961" => 961, + "962" => 962, + "963" => 963, + "964" => 964, + "965" => 965, + "966" => 966, + "967" => 967, + "968" => 968, + "969" => 969, + "970" => 970, + "971" => 971, + "972" => 972, + "973" => 973, + "974" => 974, + "975" => 975, + "976" => 976, + "977" => 977, + "978" => 978, + "979" => 979, + "980" => 980, + "981" => 981, + "982" => 982, + "983" => 983, + "984" => 984, + "985" => 985, + "986" => 986, + "987" => 987, + "988" => 988, + "989" => 989, + "990" => 990, + "991" => 991, + "992" => 992, + "993" => 993, + "994" => 994, + "995" => 995, + "996" => 996, + "997" => 997, + "998" => 998, + "999" => 999, + "1000" => 1000, + "1001" => 1001, + "1002" => 1002, + "1003" => 1003, + "1004" => 1004, + "1005" => 1005, + "1006" => 1006, + "1007" => 1007, + "1008" => 1008, + "1009" => 1009, + "1010" => 1010, + "1011" => 1011, + "1012" => 1012, + "1013" => 1013, + "1014" => 1014, + "1015" => 1015, + "1016" => 1016, + "1017" => 1017, + "1018" => 1018, + "1019" => 1019, + "1020" => 1020, + "1021" => 1021, + "1022" => 1022, + "1023" => 1023, + "1024" => 1024, + "1025" => 1025, + "1026" => 1026, + "1027" => 1027, + "1028" => 1028, + "1029" => 1029, + "1030" => 1030, + "1031" => 1031, + "1032" => 1032, + "1033" => 1033, + "1034" => 1034, + "1035" => 1035, + "1036" => 1036, + "1037" => 1037, + "1038" => 1038, + "1039" => 1039, + "1040" => 1040, + "1041" => 1041, + "1042" => 1042, + "1043" => 1043, + "1044" => 1044, + "1045" => 1045, + "1046" => 1046, + "1047" => 1047, + "1048" => 1048, + "1049" => 1049, + "1050" => 1050, + "1051" => 1051, + "1052" => 1052, + "1053" => 1053, + "1054" => 1054, + "1055" => 1055, + "1056" => 1056, + "1057" => 1057, + "1058" => 1058, + "1059" => 1059, + "1060" => 1060, + "1061" => 1061, + "1062" => 1062, + "1063" => 1063, + "1064" => 1064, + "1065" => 1065, + "1066" => 1066, + "1067" => 1067, + "1068" => 1068, + "1069" => 1069, + "1070" => 1070, + "1071" => 1071, + "1072" => 1072, + "1073" => 1073, + "1074" => 1074, + "1075" => 1075, + "1076" => 1076, + "1077" => 1077, + "1078" => 1078, + "1079" => 1079, + "1080" => 1080, + "1081" => 1081, + "1082" => 1082, + "1083" => 1083, + "1084" => 1084, + "1085" => 1085, + "1086" => 1086, + "1087" => 1087, + "1088" => 1088, + "1089" => 1089, + "1090" => 1090, + "1091" => 1091, + "1092" => 1092, + "1093" => 1093, + "1094" => 1094, + "1095" => 1095, + "1096" => 1096, + "1097" => 1097, + "1098" => 1098, + "1099" => 1099, + "1100" => 1100, + "1101" => 1101, + "1102" => 1102, + "1103" => 1103, + "1104" => 1104, + "1105" => 1105, + "1106" => 1106, + "1107" => 1107, + "1108" => 1108, + "1109" => 1109, + "1110" => 1110, + "1111" => 1111, + "1112" => 1112, + "1113" => 1113, + "1114" => 1114, + "1115" => 1115, + "1116" => 1116, + "1117" => 1117, + "1118" => 1118, + "1119" => 1119, + "1120" => 1120, + "1121" => 1121, + "1122" => 1122, + "1123" => 1123, + "1124" => 1124, + "1125" => 1125, + "1126" => 1126, + "1127" => 1127, + "1128" => 1128, + "1129" => 1129, + "1130" => 1130, + "1131" => 1131, + "1132" => 1132, + "1133" => 1133, + "1134" => 1134, + "1135" => 1135, + "1136" => 1136, + "1137" => 1137, + "1138" => 1138, + "1139" => 1139, + "1140" => 1140, + "1141" => 1141, + "1142" => 1142, + "1143" => 1143, + "1144" => 1144, + "1145" => 1145, + "1146" => 1146, + "1147" => 1147, + "1148" => 1148, + "1149" => 1149, + "1150" => 1150, + "1151" => 1151, + "1152" => 1152, + "1153" => 1153, + "1154" => 1154, + "1155" => 1155, + "1156" => 1156, + "1157" => 1157, + "1158" => 1158, + "1159" => 1159, + "1160" => 1160, + "1161" => 1161, + "1162" => 1162, + "1163" => 1163, + "1164" => 1164, + "1165" => 1165, + "1166" => 1166, + "1167" => 1167, + "1168" => 1168, + "1169" => 1169, + "1170" => 1170, + "1171" => 1171, + "1172" => 1172, + "1173" => 1173, + "1174" => 1174, + "1175" => 1175, + "1176" => 1176, + "1177" => 1177, + "1178" => 1178, + "1179" => 1179, + "1180" => 1180, + "1181" => 1181, + "1182" => 1182, + "1183" => 1183, + "1184" => 1184, + "1185" => 1185, + "1186" => 1186, + "1187" => 1187, + "1188" => 1188, + "1189" => 1189, + "1190" => 1190, + "1191" => 1191, + "1192" => 1192, + "1193" => 1193, + "1194" => 1194, + "1195" => 1195, + "1196" => 1196, + "1197" => 1197, + "1198" => 1198, + "1199" => 1199, + "1200" => 1200, + "1201" => 1201, + "1202" => 1202, + "1203" => 1203, + "1204" => 1204, + "1205" => 1205, + "1206" => 1206, + "1207" => 1207, + "1208" => 1208, + "1209" => 1209, + "1210" => 1210, + "1211" => 1211, + "1212" => 1212, + "1213" => 1213, + "1214" => 1214, + "1215" => 1215, + "1216" => 1216, + "1217" => 1217, + "1218" => 1218, + "1219" => 1219, + "1220" => 1220, + "1221" => 1221, + "1222" => 1222, + "1223" => 1223, + "1224" => 1224, + "1225" => 1225, + "1226" => 1226, + "1227" => 1227, + "1228" => 1228, + "1229" => 1229, + "1230" => 1230, + "1231" => 1231, + "1232" => 1232, + "1233" => 1233, + "1234" => 1234, + "1235" => 1235, + "1236" => 1236, + "1237" => 1237, + "1238" => 1238, + "1239" => 1239, + "1240" => 1240, + "1241" => 1241, + "1242" => 1242, + "1243" => 1243, + "1244" => 1244, + "1245" => 1245, + "1246" => 1246, + "1247" => 1247, + "1248" => 1248, + "1249" => 1249, + "1250" => 1250, + "1251" => 1251, + "1252" => 1252, + "1253" => 1253, + "1254" => 1254, + "1255" => 1255, + "1256" => 1256, + "1257" => 1257, + "1258" => 1258, + "1259" => 1259, + "1260" => 1260, + "1261" => 1261, + "1262" => 1262, + "1263" => 1263, + "1264" => 1264, + "1265" => 1265, + "1266" => 1266, + "1267" => 1267, + "1268" => 1268, + "1269" => 1269, + "1270" => 1270, + "1271" => 1271, + "1272" => 1272, + "1273" => 1273, + "1274" => 1274, + "1275" => 1275, + "1276" => 1276, + "1277" => 1277, + "1278" => 1278, + "1279" => 1279, + "1280" => 1280, + "1281" => 1281, + "1282" => 1282, + "1283" => 1283, + "1284" => 1284, + "1285" => 1285, + "1286" => 1286, + "1287" => 1287, + "1288" => 1288, + "1289" => 1289, + "1290" => 1290, + "1291" => 1291, + "1292" => 1292, + "1293" => 1293, + "1294" => 1294, + "1295" => 1295, + "1296" => 1296, + "1297" => 1297, + "1298" => 1298, + "1299" => 1299, + "1300" => 1300, + "1301" => 1301, + "1302" => 1302, + "1303" => 1303, + "1304" => 1304, + "1305" => 1305, + "1306" => 1306, + "1307" => 1307, + "1308" => 1308, + "1309" => 1309, + "1310" => 1310, + "1311" => 1311, + "1312" => 1312, + "1313" => 1313, + "1314" => 1314, + "1315" => 1315, + "1316" => 1316, + "1317" => 1317, + "1318" => 1318, + "1319" => 1319, + "1320" => 1320, + "1321" => 1321, + "1322" => 1322, + "1323" => 1323, + "1324" => 1324, + "1325" => 1325, + "1326" => 1326, + "1327" => 1327, + "1328" => 1328, + "1329" => 1329, + "1330" => 1330, + "1331" => 1331, + "1332" => 1332, + "1333" => 1333, + "1334" => 1334, + "1335" => 1335, + "1336" => 1336, + "1337" => 1337, + "1338" => 1338, + "1339" => 1339, + "1340" => 1340, + "1341" => 1341, + "1342" => 1342, + "1343" => 1343, + "1344" => 1344, + "1345" => 1345, + "1346" => 1346, + "1347" => 1347, + "1348" => 1348, + "1349" => 1349, + "1350" => 1350, + "1351" => 1351, + "1352" => 1352, + "1353" => 1353, + "1354" => 1354, + "1355" => 1355, + "1356" => 1356, + "1357" => 1357, + "1358" => 1358, + "1359" => 1359, + "1360" => 1360, + "1361" => 1361, + "1362" => 1362, + "1363" => 1363, + "1364" => 1364, + "1365" => 1365, + "1366" => 1366, + "1367" => 1367, + "1368" => 1368, + "1369" => 1369, + "1370" => 1370, + "1371" => 1371, + "1372" => 1372, + "1373" => 1373, + "1374" => 1374, + "1375" => 1375, + "1376" => 1376, + "1377" => 1377, + "1378" => 1378, + "1379" => 1379, + "1380" => 1380, + "1381" => 1381, + "1382" => 1382, + "1383" => 1383, + "1384" => 1384, + "1385" => 1385, + "1386" => 1386, + "1387" => 1387, + "1388" => 1388, + "1389" => 1389, + "1390" => 1390, + "1391" => 1391, + "1392" => 1392, + "1393" => 1393, + "1394" => 1394, + "1395" => 1395, + "1396" => 1396, + "1397" => 1397, + "1398" => 1398, + "1399" => 1399, + "1400" => 1400, + "1401" => 1401, + "1402" => 1402, + "1403" => 1403, + "1404" => 1404, + "1405" => 1405, + "1406" => 1406, + "1407" => 1407, + "1408" => 1408, + "1409" => 1409, + "1410" => 1410, + "1411" => 1411, + "1412" => 1412, + "1413" => 1413, + "1414" => 1414, + "1415" => 1415, + "1416" => 1416, + "1417" => 1417, + "1418" => 1418, + "1419" => 1419, + "1420" => 1420, + "1421" => 1421, + "1422" => 1422, + "1423" => 1423, + "1424" => 1424, + "1425" => 1425, + "1426" => 1426, + "1427" => 1427, + "1428" => 1428, + "1429" => 1429, + "1430" => 1430, + "1431" => 1431, + "1432" => 1432, + "1433" => 1433, + "1434" => 1434, + "1435" => 1435, + "1436" => 1436, + "1437" => 1437, + "1438" => 1438, + "1439" => 1439, + "1440" => 1440, + "1441" => 1441, + "1442" => 1442, + "1443" => 1443, + "1444" => 1444, + "1445" => 1445, + "1446" => 1446, + "1447" => 1447, + "1448" => 1448, + "1449" => 1449, + "1450" => 1450, + "1451" => 1451, + "1452" => 1452, + "1453" => 1453, + "1454" => 1454, + "1455" => 1455, + "1456" => 1456, + "1457" => 1457, + "1458" => 1458, + "1459" => 1459, + "1460" => 1460, + "1461" => 1461, + "1462" => 1462, + "1463" => 1463, + "1464" => 1464, + "1465" => 1465, + "1466" => 1466, + "1467" => 1467, + "1468" => 1468, + "1469" => 1469, + "1470" => 1470, + "1471" => 1471, + "1472" => 1472, + "1473" => 1473, + "1474" => 1474, + "1475" => 1475, + "1476" => 1476, + "1477" => 1477, + "1478" => 1478, + "1479" => 1479, + "1480" => 1480, + "1481" => 1481, + "1482" => 1482, + "1483" => 1483, + "1484" => 1484, + "1485" => 1485, + "1486" => 1486, + "1487" => 1487, + "1488" => 1488, + "1489" => 1489, + "1490" => 1490, + "1491" => 1491, + "1492" => 1492, + "1493" => 1493, + "1494" => 1494, + "1495" => 1495, + "1496" => 1496, + "1497" => 1497, + "1498" => 1498, + "1499" => 1499, + "1500" => 1500, + "1501" => 1501, + "1502" => 1502, + "1503" => 1503, + "1504" => 1504, + "1505" => 1505, + "1506" => 1506, + "1507" => 1507, + "1508" => 1508, + "1509" => 1509, + "1510" => 1510, + "1511" => 1511, + "1512" => 1512, + "1513" => 1513, + "1514" => 1514, + "1515" => 1515, + "1516" => 1516, + "1517" => 1517, + "1518" => 1518, + "1519" => 1519, + "1520" => 1520, + "1521" => 1521, + "1522" => 1522, + "1523" => 1523, + "1524" => 1524, + "1525" => 1525, + "1526" => 1526, + "1527" => 1527, + "1528" => 1528, + "1529" => 1529, + "1530" => 1530, + "1531" => 1531, + "1532" => 1532, + "1533" => 1533, + "1534" => 1534, + "1535" => 1535, + "1536" => 1536, + "1537" => 1537, + "1538" => 1538, + "1539" => 1539, + "1540" => 1540, + "1541" => 1541, + "1542" => 1542, + "1543" => 1543, + "1544" => 1544, + "1545" => 1545, + "1546" => 1546, + "1547" => 1547, + "1548" => 1548, + "1549" => 1549, + "1550" => 1550, + "1551" => 1551, + "1552" => 1552, + "1553" => 1553, + "1554" => 1554, + "1555" => 1555, + "1556" => 1556, + "1557" => 1557, + "1558" => 1558, + "1559" => 1559, + "1560" => 1560, + "1561" => 1561, + "1562" => 1562, + "1563" => 1563, + "1564" => 1564, + "1565" => 1565, + "1566" => 1566, + "1567" => 1567, + "1568" => 1568, + "1569" => 1569, + "1570" => 1570, + "1571" => 1571, + "1572" => 1572, + "1573" => 1573, + "1574" => 1574, + "1575" => 1575, + "1576" => 1576, + "1577" => 1577, + "1578" => 1578, + "1579" => 1579, + "1580" => 1580, + "1581" => 1581, + "1582" => 1582, + "1583" => 1583, + "1584" => 1584, + "1585" => 1585, + "1586" => 1586, + "1587" => 1587, + "1588" => 1588, + "1589" => 1589, + "1590" => 1590, + "1591" => 1591, + "1592" => 1592, + "1593" => 1593, + "1594" => 1594, + "1595" => 1595, + "1596" => 1596, + "1597" => 1597, + "1598" => 1598, + "1599" => 1599, + "1600" => 1600, + "1601" => 1601, + "1602" => 1602, + "1603" => 1603, + "1604" => 1604, + "1605" => 1605, + "1606" => 1606, + "1607" => 1607, + "1608" => 1608, + "1609" => 1609, + "1610" => 1610, + "1611" => 1611, + "1612" => 1612, + "1613" => 1613, + "1614" => 1614, + "1615" => 1615, + "1616" => 1616, + "1617" => 1617, + "1618" => 1618, + "1619" => 1619, + "1620" => 1620, + "1621" => 1621, + "1622" => 1622, + "1623" => 1623, + "1624" => 1624, + "1625" => 1625, + "1626" => 1626, + "1627" => 1627, + "1628" => 1628, + "1629" => 1629, + "1630" => 1630, + "1631" => 1631, + "1632" => 1632, + "1633" => 1633, + "1634" => 1634, + "1635" => 1635, + "1636" => 1636, + "1637" => 1637, + "1638" => 1638, + "1639" => 1639, + "1640" => 1640, + "1641" => 1641, + "1642" => 1642, + "1643" => 1643, + "1644" => 1644, + "1645" => 1645, + "1646" => 1646, + "1647" => 1647, + "1648" => 1648, + "1649" => 1649, + "1650" => 1650, + "1651" => 1651, + "1652" => 1652, + "1653" => 1653, + "1654" => 1654, + "1655" => 1655, + "1656" => 1656, + "1657" => 1657, + "1658" => 1658, + "1659" => 1659, + "1660" => 1660, + "1661" => 1661, + "1662" => 1662, + "1663" => 1663, + "1664" => 1664, + "1665" => 1665, + "1666" => 1666, + "1667" => 1667, + "1668" => 1668, + "1669" => 1669, + "1670" => 1670, + "1671" => 1671, + "1672" => 1672, + "1673" => 1673, + "1674" => 1674, + "1675" => 1675, + "1676" => 1676, + "1677" => 1677, + "1678" => 1678, + "1679" => 1679, + "1680" => 1680, + "1681" => 1681, + "1682" => 1682, + "1683" => 1683, + "1684" => 1684, + "1685" => 1685, + "1686" => 1686, + "1687" => 1687, + "1688" => 1688, + "1689" => 1689, + "1690" => 1690, + "1691" => 1691, + "1692" => 1692, + "1693" => 1693, + "1694" => 1694, + "1695" => 1695, + "1696" => 1696, + "1697" => 1697, + "1698" => 1698, + "1699" => 1699, + "1700" => 1700, + "1701" => 1701, + "1702" => 1702, + "1703" => 1703, + "1704" => 1704, + "1705" => 1705, + "1706" => 1706, + "1707" => 1707, + "1708" => 1708, + "1709" => 1709, + "1710" => 1710, + "1711" => 1711, + "1712" => 1712, + "1713" => 1713, + "1714" => 1714, + "1715" => 1715, + "1716" => 1716, + "1717" => 1717, + "1718" => 1718, + "1719" => 1719, + "1720" => 1720, + "1721" => 1721, + "1722" => 1722, + "1723" => 1723, + "1724" => 1724, + "1725" => 1725, + "1726" => 1726, + "1727" => 1727, + "1728" => 1728, + "1729" => 1729, + "1730" => 1730, + "1731" => 1731, + "1732" => 1732, + "1733" => 1733, + "1734" => 1734, + "1735" => 1735, + "1736" => 1736, + "1737" => 1737, + "1738" => 1738, + "1739" => 1739, + "1740" => 1740, + "1741" => 1741, + "1742" => 1742, + "1743" => 1743, + "1744" => 1744, + "1745" => 1745, + "1746" => 1746, + "1747" => 1747, + "1748" => 1748, + "1749" => 1749, + "1750" => 1750, + "1751" => 1751, + "1752" => 1752, + "1753" => 1753, + "1754" => 1754, + "1755" => 1755, + "1756" => 1756, + "1757" => 1757, + "1758" => 1758, + "1759" => 1759, + "1760" => 1760, + "1761" => 1761, + "1762" => 1762, + "1763" => 1763, + "1764" => 1764, + "1765" => 1765, + "1766" => 1766, + "1767" => 1767, + "1768" => 1768, + "1769" => 1769, + "1770" => 1770, + "1771" => 1771, + "1772" => 1772, + "1773" => 1773, + "1774" => 1774, + "1775" => 1775, + "1776" => 1776, + "1777" => 1777, + "1778" => 1778, + "1779" => 1779, + "1780" => 1780, + "1781" => 1781, + "1782" => 1782, + "1783" => 1783, + "1784" => 1784, + "1785" => 1785, + "1786" => 1786, + "1787" => 1787, + "1788" => 1788, + "1789" => 1789, + "1790" => 1790, + "1791" => 1791, + "1792" => 1792, + "1793" => 1793, + "1794" => 1794, + "1795" => 1795, + "1796" => 1796, + "1797" => 1797, + "1798" => 1798, + "1799" => 1799, + "1800" => 1800, + "1801" => 1801, + "1802" => 1802, + "1803" => 1803, + "1804" => 1804, + "1805" => 1805, + "1806" => 1806, + "1807" => 1807, + "1808" => 1808, + "1809" => 1809, + "1810" => 1810, + "1811" => 1811, + "1812" => 1812, + "1813" => 1813, + "1814" => 1814, + "1815" => 1815, + "1816" => 1816, + "1817" => 1817, + "1818" => 1818, + "1819" => 1819, + "1820" => 1820, + "1821" => 1821, + "1822" => 1822, + "1823" => 1823, + "1824" => 1824, + "1825" => 1825, + "1826" => 1826, + "1827" => 1827, + "1828" => 1828, + "1829" => 1829, + "1830" => 1830, + "1831" => 1831, + "1832" => 1832, + "1833" => 1833, + "1834" => 1834, + "1835" => 1835, + "1836" => 1836, + "1837" => 1837, + "1838" => 1838, + "1839" => 1839, + "1840" => 1840, + "1841" => 1841, + "1842" => 1842, + "1843" => 1843, + "1844" => 1844, + "1845" => 1845, + "1846" => 1846, + "1847" => 1847, + "1848" => 1848, + "1849" => 1849, + "1850" => 1850, + "1851" => 1851, + "1852" => 1852, + "1853" => 1853, + "1854" => 1854, + "1855" => 1855, + "1856" => 1856, + "1857" => 1857, + "1858" => 1858, + "1859" => 1859, + "1860" => 1860, + "1861" => 1861, + "1862" => 1862, + "1863" => 1863, + "1864" => 1864, + "1865" => 1865, + "1866" => 1866, + "1867" => 1867, + "1868" => 1868, + "1869" => 1869, + "1870" => 1870, + "1871" => 1871, + "1872" => 1872, + "1873" => 1873, + "1874" => 1874, + "1875" => 1875, + "1876" => 1876, + "1877" => 1877, + "1878" => 1878, + "1879" => 1879, + "1880" => 1880, + "1881" => 1881, + "1882" => 1882, + "1883" => 1883, + "1884" => 1884, + "1885" => 1885, + "1886" => 1886, + "1887" => 1887, + "1888" => 1888, + "1889" => 1889, + "1890" => 1890, + "1891" => 1891, + "1892" => 1892, + "1893" => 1893, + "1894" => 1894, + "1895" => 1895, + "1896" => 1896, + "1897" => 1897, + "1898" => 1898, + "1899" => 1899, + "1900" => 1900, + "1901" => 1901, + "1902" => 1902, + "1903" => 1903, + "1904" => 1904, + "1905" => 1905, + "1906" => 1906, + "1907" => 1907, + "1908" => 1908, + "1909" => 1909, + "1910" => 1910, + "1911" => 1911, + "1912" => 1912, + "1913" => 1913, + "1914" => 1914, + "1915" => 1915, + "1916" => 1916, + "1917" => 1917, + "1918" => 1918, + "1919" => 1919, + "1920" => 1920, + "1921" => 1921, + "1922" => 1922, + "1923" => 1923, + "1924" => 1924, + "1925" => 1925, + "1926" => 1926, + "1927" => 1927, + "1928" => 1928, + "1929" => 1929, + "1930" => 1930, + "1931" => 1931, + "1932" => 1932, + "1933" => 1933, + "1934" => 1934, + "1935" => 1935, + "1936" => 1936, + "1937" => 1937, + "1938" => 1938, + "1939" => 1939, + "1940" => 1940, + "1941" => 1941, + "1942" => 1942, + "1943" => 1943, + "1944" => 1944, + "1945" => 1945, + "1946" => 1946, + "1947" => 1947, + "1948" => 1948, + "1949" => 1949, + "1950" => 1950, + "1951" => 1951, + "1952" => 1952, + "1953" => 1953, + "1954" => 1954, + "1955" => 1955, + "1956" => 1956, + "1957" => 1957, + "1958" => 1958, + "1959" => 1959, + "1960" => 1960, + "1961" => 1961, + "1962" => 1962, + "1963" => 1963, + "1964" => 1964, + "1965" => 1965, + "1966" => 1966, + "1967" => 1967, + "1968" => 1968, + "1969" => 1969, + "1970" => 1970, + "1971" => 1971, + "1972" => 1972, + "1973" => 1973, + "1974" => 1974, + "1975" => 1975, + "1976" => 1976, + "1977" => 1977, + "1978" => 1978, + "1979" => 1979, + "1980" => 1980, + "1981" => 1981, + "1982" => 1982, + "1983" => 1983, + "1984" => 1984, + "1985" => 1985, + "1986" => 1986, + "1987" => 1987, + "1988" => 1988, + "1989" => 1989, + "1990" => 1990, + "1991" => 1991, + "1992" => 1992, + "1993" => 1993, + "1994" => 1994, + "1995" => 1995, + "1996" => 1996, + "1997" => 1997, + "1998" => 1998, + "1999" => 1999, + "2000" => 2000, + "2001" => 2001, + "2002" => 2002, + "2003" => 2003, + "2004" => 2004, + "2005" => 2005, + "2006" => 2006, + "2007" => 2007, + "2008" => 2008, + "2009" => 2009, + "2010" => 2010, + "2011" => 2011, + "2012" => 2012, + "2013" => 2013, + "2014" => 2014, + "2015" => 2015, + "2016" => 2016, + "2017" => 2017, + "2018" => 2018, + "2019" => 2019, + "2020" => 2020, + "2021" => 2021, + "2022" => 2022, + "2023" => 2023, + "2024" => 2024, + "2025" => 2025, + "2026" => 2026, + "2027" => 2027, + "2028" => 2028, + "2029" => 2029, + "2030" => 2030, + "2031" => 2031, + "2032" => 2032, + "2033" => 2033, + "2034" => 2034, + "2035" => 2035, + "2036" => 2036, + "2037" => 2037, + "2038" => 2038, + "2039" => 2039, + "2040" => 2040, + "2041" => 2041, + "2042" => 2042, + "2043" => 2043, + "2044" => 2044, + "2045" => 2045, + "2046" => 2046, + "2047" => 2047, + "2048" => 2048, + "2049" => 2049, + "2050" => 2050, + "2051" => 2051, + "2052" => 2052, + "2053" => 2053, + "2054" => 2054, + "2055" => 2055, + "2056" => 2056, + "2057" => 2057, + "2058" => 2058, + "2059" => 2059, + "2060" => 2060, + "2061" => 2061, + "2062" => 2062, + "2063" => 2063, + "2064" => 2064, + "2065" => 2065, + "2066" => 2066, + "2067" => 2067, + "2068" => 2068, + "2069" => 2069, + "2070" => 2070, + "2071" => 2071, + "2072" => 2072, + "2073" => 2073, + "2074" => 2074, + "2075" => 2075, + "2076" => 2076, + "2077" => 2077, + "2078" => 2078, + "2079" => 2079, + "2080" => 2080, + "2081" => 2081, + "2082" => 2082, + "2083" => 2083, + "2084" => 2084, + "2085" => 2085, + "2086" => 2086, + "2087" => 2087, + "2088" => 2088, + "2089" => 2089, + "2090" => 2090, + "2091" => 2091, + "2092" => 2092, + "2093" => 2093, + "2094" => 2094, + "2095" => 2095, + "2096" => 2096, + "2097" => 2097, + "2098" => 2098, + "2099" => 2099, + "2100" => 2100, + "2101" => 2101, + "2102" => 2102, + "2103" => 2103, + "2104" => 2104, + "2105" => 2105, + "2106" => 2106, + "2107" => 2107, + "2108" => 2108, + "2109" => 2109, + "2110" => 2110, + "2111" => 2111, + "2112" => 2112, + "2113" => 2113, + "2114" => 2114, + "2115" => 2115, + "2116" => 2116, + "2117" => 2117, + "2118" => 2118, + "2119" => 2119, + "2120" => 2120, + "2121" => 2121, + "2122" => 2122, + "2123" => 2123, + "2124" => 2124, + "2125" => 2125, + "2126" => 2126, + "2127" => 2127, + "2128" => 2128, + "2129" => 2129, + "2130" => 2130, + "2131" => 2131, + "2132" => 2132, + "2133" => 2133, + "2134" => 2134, + "2135" => 2135, + "2136" => 2136, + "2137" => 2137, + "2138" => 2138, + "2139" => 2139, + "2140" => 2140, + "2141" => 2141, + "2142" => 2142, + "2143" => 2143, + "2144" => 2144, + "2145" => 2145, + "2146" => 2146, + "2147" => 2147, + "2148" => 2148, + "2149" => 2149, + "2150" => 2150, + "2151" => 2151, + "2152" => 2152, + "2153" => 2153, + "2154" => 2154, + "2155" => 2155, + "2156" => 2156, + "2157" => 2157, + "2158" => 2158, + "2159" => 2159, + "2160" => 2160, + "2161" => 2161, + "2162" => 2162, + "2163" => 2163, + "2164" => 2164, + "2165" => 2165, + "2166" => 2166, + "2167" => 2167, + "2168" => 2168, + "2169" => 2169, + "2170" => 2170, + "2171" => 2171, + "2172" => 2172, + "2173" => 2173, + "2174" => 2174, + "2175" => 2175, + "2176" => 2176, + "2177" => 2177, + "2178" => 2178, + "2179" => 2179, + "2180" => 2180, + "2181" => 2181, + "2182" => 2182, + "2183" => 2183, + "2184" => 2184, + "2185" => 2185, + "2186" => 2186, + "2187" => 2187, + "2188" => 2188, + "2189" => 2189, + "2190" => 2190, + "2191" => 2191, + "2192" => 2192, + "2193" => 2193, + "2194" => 2194, + "2195" => 2195, + "2196" => 2196, + "2197" => 2197, + "2198" => 2198, + "2199" => 2199, + "2200" => 2200, + "2201" => 2201, + "2202" => 2202, + "2203" => 2203, + "2204" => 2204, + "2205" => 2205, + "2206" => 2206, + "2207" => 2207, + "2208" => 2208, + "2209" => 2209, + "2210" => 2210, + "2211" => 2211, + "2212" => 2212, + "2213" => 2213, + "2214" => 2214, + "2215" => 2215, + "2216" => 2216, + "2217" => 2217, + "2218" => 2218, + "2219" => 2219, + "2220" => 2220, + "2221" => 2221, + "2222" => 2222, + "2223" => 2223, + "2224" => 2224, + "2225" => 2225, + "2226" => 2226, + "2227" => 2227, + "2228" => 2228, + "2229" => 2229, + "2230" => 2230, + "2231" => 2231, + "2232" => 2232, + "2233" => 2233, + "2234" => 2234, + "2235" => 2235, + "2236" => 2236, + "2237" => 2237, + "2238" => 2238, + "2239" => 2239, + "2240" => 2240, + "2241" => 2241, + "2242" => 2242, + "2243" => 2243, + "2244" => 2244, + "2245" => 2245, + "2246" => 2246, + "2247" => 2247, + "2248" => 2248, + "2249" => 2249, + "2250" => 2250, + "2251" => 2251, + "2252" => 2252, + "2253" => 2253, + "2254" => 2254, + "2255" => 2255, + "2256" => 2256, + "2257" => 2257, + "2258" => 2258, + "2259" => 2259, + "2260" => 2260, + "2261" => 2261, + "2262" => 2262, + "2263" => 2263, + "2264" => 2264, + "2265" => 2265, + "2266" => 2266, + "2267" => 2267, + "2268" => 2268, + "2269" => 2269, + "2270" => 2270, + "2271" => 2271, + "2272" => 2272, + "2273" => 2273, + "2274" => 2274, + "2275" => 2275, + "2276" => 2276, + "2277" => 2277, + "2278" => 2278, + "2279" => 2279, + "2280" => 2280, + "2281" => 2281, + "2282" => 2282, + "2283" => 2283, + "2284" => 2284, + "2285" => 2285, + "2286" => 2286, + "2287" => 2287, + "2288" => 2288, + "2289" => 2289, + "2290" => 2290, + "2291" => 2291, + "2292" => 2292, + "2293" => 2293, + "2294" => 2294, + "2295" => 2295, + "2296" => 2296, + "2297" => 2297, + "2298" => 2298, + "2299" => 2299, + "2300" => 2300, + "2301" => 2301, + "2302" => 2302, + "2303" => 2303, + "2304" => 2304, + "2305" => 2305, + "2306" => 2306, + "2307" => 2307, + "2308" => 2308, + "2309" => 2309, + "2310" => 2310, + "2311" => 2311, + "2312" => 2312, + "2313" => 2313, + "2314" => 2314, + "2315" => 2315, + "2316" => 2316, + "2317" => 2317, + "2318" => 2318, + "2319" => 2319, + "2320" => 2320, + "2321" => 2321, + "2322" => 2322, + "2323" => 2323, + "2324" => 2324, + "2325" => 2325, + "2326" => 2326, + "2327" => 2327, + "2328" => 2328, + "2329" => 2329, + "2330" => 2330, + "2331" => 2331, + "2332" => 2332, + "2333" => 2333, + "2334" => 2334, + "2335" => 2335, + "2336" => 2336, + "2337" => 2337, + "2338" => 2338, + "2339" => 2339, + "2340" => 2340, + "2341" => 2341, + "2342" => 2342, + "2343" => 2343, + "2344" => 2344, + "2345" => 2345, + "2346" => 2346, + "2347" => 2347, + "2348" => 2348, + "2349" => 2349, + "2350" => 2350, + "2351" => 2351, + "2352" => 2352, + "2353" => 2353, + "2354" => 2354, + "2355" => 2355, + "2356" => 2356, + "2357" => 2357, + "2358" => 2358, + "2359" => 2359, + "2360" => 2360, + "2361" => 2361, + "2362" => 2362, + "2363" => 2363, + "2364" => 2364, + "2365" => 2365, + "2366" => 2366, + "2367" => 2367, + "2368" => 2368, + "2369" => 2369, + "2370" => 2370, + "2371" => 2371, + "2372" => 2372, + "2373" => 2373, + "2374" => 2374, + "2375" => 2375, + "2376" => 2376, + "2377" => 2377, + "2378" => 2378, + "2379" => 2379, + "2380" => 2380, + "2381" => 2381, + "2382" => 2382, + "2383" => 2383, + "2384" => 2384, + "2385" => 2385, + "2386" => 2386, + "2387" => 2387, + "2388" => 2388, + "2389" => 2389, + "2390" => 2390, + "2391" => 2391, + "2392" => 2392, + "2393" => 2393, + "2394" => 2394, + "2395" => 2395, + "2396" => 2396, + "2397" => 2397, + "2398" => 2398, + "2399" => 2399, + "2400" => 2400, + "2401" => 2401, + "2402" => 2402, + "2403" => 2403, + "2404" => 2404, + "2405" => 2405, + "2406" => 2406, + "2407" => 2407, + "2408" => 2408, + "2409" => 2409, + "2410" => 2410, + "2411" => 2411, + "2412" => 2412, + "2413" => 2413, + "2414" => 2414, + "2415" => 2415, + "2416" => 2416, + "2417" => 2417, + "2418" => 2418, + "2419" => 2419, + "2420" => 2420, + "2421" => 2421, + "2422" => 2422, + "2423" => 2423, + "2424" => 2424, + "2425" => 2425, + "2426" => 2426, + "2427" => 2427, + "2428" => 2428, + "2429" => 2429, + "2430" => 2430, + "2431" => 2431, + "2432" => 2432, + "2433" => 2433, + "2434" => 2434, + "2435" => 2435, + "2436" => 2436, + "2437" => 2437, + "2438" => 2438, + "2439" => 2439, + "2440" => 2440, + "2441" => 2441, + "2442" => 2442, + "2443" => 2443, + "2444" => 2444, + "2445" => 2445, + "2446" => 2446, + "2447" => 2447, + "2448" => 2448, + "2449" => 2449, + "2450" => 2450, + "2451" => 2451, + "2452" => 2452, + "2453" => 2453, + "2454" => 2454, + "2455" => 2455, + "2456" => 2456, + "2457" => 2457, + "2458" => 2458, + "2459" => 2459, + "2460" => 2460, + "2461" => 2461, + "2462" => 2462, + "2463" => 2463, + "2464" => 2464, + "2465" => 2465, + "2466" => 2466, + "2467" => 2467, + "2468" => 2468, + "2469" => 2469, + "2470" => 2470, + "2471" => 2471, + "2472" => 2472, + "2473" => 2473, + "2474" => 2474, + "2475" => 2475, + "2476" => 2476, + "2477" => 2477, + "2478" => 2478, + "2479" => 2479, + "2480" => 2480, + "2481" => 2481, + "2482" => 2482, + "2483" => 2483, + "2484" => 2484, + "2485" => 2485, + "2486" => 2486, + "2487" => 2487, + "2488" => 2488, + "2489" => 2489, + "2490" => 2490, + "2491" => 2491, + "2492" => 2492, + "2493" => 2493, + "2494" => 2494, + "2495" => 2495, + "2496" => 2496, + "2497" => 2497, + "2498" => 2498, + "2499" => 2499, + "2500" => 2500, + "2501" => 2501, + "2502" => 2502, + "2503" => 2503, + "2504" => 2504, + "2505" => 2505, + "2506" => 2506, + "2507" => 2507, + "2508" => 2508, + "2509" => 2509, + "2510" => 2510, + "2511" => 2511, + "2512" => 2512, + "2513" => 2513, + "2514" => 2514, + "2515" => 2515, + "2516" => 2516, + "2517" => 2517, + "2518" => 2518, + "2519" => 2519, + "2520" => 2520, + "2521" => 2521, + "2522" => 2522, + "2523" => 2523, + "2524" => 2524, + "2525" => 2525, + "2526" => 2526, + "2527" => 2527, + "2528" => 2528, + "2529" => 2529, + "2530" => 2530, + "2531" => 2531, + "2532" => 2532, + "2533" => 2533, + "2534" => 2534, + "2535" => 2535, + "2536" => 2536, + "2537" => 2537, + "2538" => 2538, + "2539" => 2539, + "2540" => 2540, + "2541" => 2541, + "2542" => 2542, + "2543" => 2543, + "2544" => 2544, + "2545" => 2545, + "2546" => 2546, + "2547" => 2547, + "2548" => 2548, + "2549" => 2549, + "2550" => 2550, + "2551" => 2551, + "2552" => 2552, + "2553" => 2553, + "2554" => 2554, + "2555" => 2555, + "2556" => 2556, + "2557" => 2557, + "2558" => 2558, + "2559" => 2559, + "2560" => 2560, + "2561" => 2561, + "2562" => 2562, + "2563" => 2563, + "2564" => 2564, + "2565" => 2565, + "2566" => 2566, + "2567" => 2567, + "2568" => 2568, + "2569" => 2569, + "2570" => 2570, + "2571" => 2571, + "2572" => 2572, + "2573" => 2573, + "2574" => 2574, + "2575" => 2575, + "2576" => 2576, + "2577" => 2577, + "2578" => 2578, + "2579" => 2579, + "2580" => 2580, + "2581" => 2581, + "2582" => 2582, + "2583" => 2583, + "2584" => 2584, + "2585" => 2585, + "2586" => 2586, + "2587" => 2587, + "2588" => 2588, + "2589" => 2589, + "2590" => 2590, + "2591" => 2591, + "2592" => 2592, + "2593" => 2593, + "2594" => 2594, + "2595" => 2595, + "2596" => 2596, + "2597" => 2597, + "2598" => 2598, + "2599" => 2599, + "2600" => 2600, + "2601" => 2601, + "2602" => 2602, + "2603" => 2603, + "2604" => 2604, + "2605" => 2605, + "2606" => 2606, + "2607" => 2607, + "2608" => 2608, + "2609" => 2609, + "2610" => 2610, + "2611" => 2611, + "2612" => 2612, + "2613" => 2613, + "2614" => 2614, + "2615" => 2615, + "2616" => 2616, + "2617" => 2617, + "2618" => 2618, + "2619" => 2619, + "2620" => 2620, + "2621" => 2621, + "2622" => 2622, + "2623" => 2623, + "2624" => 2624, + "2625" => 2625, + "2626" => 2626, + "2627" => 2627, + "2628" => 2628, + "2629" => 2629, + "2630" => 2630, + "2631" => 2631, + "2632" => 2632, + "2633" => 2633, + "2634" => 2634, + "2635" => 2635, + "2636" => 2636, + "2637" => 2637, + "2638" => 2638, + "2639" => 2639, + "2640" => 2640, + "2641" => 2641, + "2642" => 2642, + "2643" => 2643, + "2644" => 2644, + "2645" => 2645, + "2646" => 2646, + "2647" => 2647, + "2648" => 2648, + "2649" => 2649, + "2650" => 2650, + "2651" => 2651, + "2652" => 2652, + "2653" => 2653, + "2654" => 2654, + "2655" => 2655, + "2656" => 2656, + "2657" => 2657, + "2658" => 2658, + "2659" => 2659, + "2660" => 2660, + "2661" => 2661, + "2662" => 2662, + "2663" => 2663, + "2664" => 2664, + "2665" => 2665, + "2666" => 2666, + "2667" => 2667, + "2668" => 2668, + "2669" => 2669, + "2670" => 2670, + "2671" => 2671, + "2672" => 2672, + "2673" => 2673, + "2674" => 2674, + "2675" => 2675, + "2676" => 2676, + "2677" => 2677, + "2678" => 2678, + "2679" => 2679, + "2680" => 2680, + "2681" => 2681, + "2682" => 2682, + "2683" => 2683, + "2684" => 2684, + "2685" => 2685, + "2686" => 2686, + "2687" => 2687, + "2688" => 2688, + "2689" => 2689, + "2690" => 2690, + "2691" => 2691, + "2692" => 2692, + "2693" => 2693, + "2694" => 2694, + "2695" => 2695, + "2696" => 2696, + "2697" => 2697, + "2698" => 2698, + "2699" => 2699, + "2700" => 2700, + "2701" => 2701, + "2702" => 2702, + "2703" => 2703, + "2704" => 2704, + "2705" => 2705, + "2706" => 2706, + "2707" => 2707, + "2708" => 2708, + "2709" => 2709, + "2710" => 2710, + "2711" => 2711, + "2712" => 2712, + "2713" => 2713, + "2714" => 2714, + "2715" => 2715, + "2716" => 2716, + "2717" => 2717, + "2718" => 2718, + "2719" => 2719, + "2720" => 2720, + "2721" => 2721, + "2722" => 2722, + "2723" => 2723, + "2724" => 2724, + "2725" => 2725, + "2726" => 2726, + "2727" => 2727, + "2728" => 2728, + "2729" => 2729, + "2730" => 2730, + "2731" => 2731, + "2732" => 2732, + "2733" => 2733, + "2734" => 2734, + "2735" => 2735, + "2736" => 2736, + "2737" => 2737, + "2738" => 2738, + "2739" => 2739, + "2740" => 2740, + "2741" => 2741, + "2742" => 2742, + "2743" => 2743, + "2744" => 2744, + "2745" => 2745, + "2746" => 2746, + "2747" => 2747, + "2748" => 2748, + "2749" => 2749, + "2750" => 2750, + "2751" => 2751, + "2752" => 2752, + "2753" => 2753, + "2754" => 2754, + "2755" => 2755, + "2756" => 2756, + "2757" => 2757, + "2758" => 2758, + "2759" => 2759, + "2760" => 2760, + "2761" => 2761, + "2762" => 2762, + "2763" => 2763, + "2764" => 2764, + "2765" => 2765, + "2766" => 2766, + "2767" => 2767, + "2768" => 2768, + "2769" => 2769, + "2770" => 2770, + "2771" => 2771, + "2772" => 2772, + "2773" => 2773, + "2774" => 2774, + "2775" => 2775, + "2776" => 2776, + "2777" => 2777, + "2778" => 2778, + "2779" => 2779, + "2780" => 2780, + "2781" => 2781, + "2782" => 2782, + "2783" => 2783, + "2784" => 2784, + "2785" => 2785, + "2786" => 2786, + "2787" => 2787, + "2788" => 2788, + "2789" => 2789, + "2790" => 2790, + "2791" => 2791, + "2792" => 2792, + "2793" => 2793, + "2794" => 2794, + "2795" => 2795, + "2796" => 2796, + "2797" => 2797, + "2798" => 2798, + "2799" => 2799, + "2800" => 2800, + "2801" => 2801, + "2802" => 2802, + "2803" => 2803, + "2804" => 2804, + "2805" => 2805, + "2806" => 2806, + "2807" => 2807, + "2808" => 2808, + "2809" => 2809, + "2810" => 2810, + "2811" => 2811, + "2812" => 2812, + "2813" => 2813, + "2814" => 2814, + "2815" => 2815, + "2816" => 2816, + "2817" => 2817, + "2818" => 2818, + "2819" => 2819, + "2820" => 2820, + "2821" => 2821, + "2822" => 2822, + "2823" => 2823, + "2824" => 2824, + "2825" => 2825, + "2826" => 2826, + "2827" => 2827, + "2828" => 2828, + "2829" => 2829, + "2830" => 2830, + "2831" => 2831, + "2832" => 2832, + "2833" => 2833, + "2834" => 2834, + "2835" => 2835, + "2836" => 2836, + "2837" => 2837, + "2838" => 2838, + "2839" => 2839, + "2840" => 2840, + "2841" => 2841, + "2842" => 2842, + "2843" => 2843, + "2844" => 2844, + "2845" => 2845, + "2846" => 2846, + "2847" => 2847, + "2848" => 2848, + "2849" => 2849, + "2850" => 2850, + "2851" => 2851, + "2852" => 2852, + "2853" => 2853, + "2854" => 2854, + "2855" => 2855, + "2856" => 2856, + "2857" => 2857, + "2858" => 2858, + "2859" => 2859, + "2860" => 2860, + "2861" => 2861, + "2862" => 2862, + "2863" => 2863, + "2864" => 2864, + "2865" => 2865, + "2866" => 2866, + "2867" => 2867, + "2868" => 2868, + "2869" => 2869, + "2870" => 2870, + "2871" => 2871, + "2872" => 2872, + "2873" => 2873, + "2874" => 2874, + "2875" => 2875, + "2876" => 2876, + "2877" => 2877, + "2878" => 2878, + "2879" => 2879, + "2880" => 2880, + "2881" => 2881, + "2882" => 2882, + "2883" => 2883, + "2884" => 2884, + "2885" => 2885, + "2886" => 2886, + "2887" => 2887, + "2888" => 2888, + "2889" => 2889, + "2890" => 2890, + "2891" => 2891, + "2892" => 2892, + "2893" => 2893, + "2894" => 2894, + "2895" => 2895, + "2896" => 2896, + "2897" => 2897, + "2898" => 2898, + "2899" => 2899, + "2900" => 2900, + "2901" => 2901, + "2902" => 2902, + "2903" => 2903, + "2904" => 2904, + "2905" => 2905, + "2906" => 2906, + "2907" => 2907, + "2908" => 2908, + "2909" => 2909, + "2910" => 2910, + "2911" => 2911, + "2912" => 2912, + "2913" => 2913, + "2914" => 2914, + "2915" => 2915, + "2916" => 2916, + "2917" => 2917, + "2918" => 2918, + "2919" => 2919, + "2920" => 2920, + "2921" => 2921, + "2922" => 2922, + "2923" => 2923, + "2924" => 2924, + "2925" => 2925, + "2926" => 2926, + "2927" => 2927, + "2928" => 2928, + "2929" => 2929, + "2930" => 2930, + "2931" => 2931, + "2932" => 2932, + "2933" => 2933, + "2934" => 2934, + "2935" => 2935, + "2936" => 2936, + "2937" => 2937, + "2938" => 2938, + "2939" => 2939, + "2940" => 2940, + "2941" => 2941, + "2942" => 2942, + "2943" => 2943, + "2944" => 2944, + "2945" => 2945, + "2946" => 2946, + "2947" => 2947, + "2948" => 2948, + "2949" => 2949, + "2950" => 2950, + "2951" => 2951, + "2952" => 2952, + "2953" => 2953, + "2954" => 2954, + "2955" => 2955, + "2956" => 2956, + "2957" => 2957, + "2958" => 2958, + "2959" => 2959, + "2960" => 2960, + "2961" => 2961, + "2962" => 2962, + "2963" => 2963, + "2964" => 2964, + "2965" => 2965, + "2966" => 2966, + "2967" => 2967, + "2968" => 2968, + "2969" => 2969, + "2970" => 2970, + "2971" => 2971, + "2972" => 2972, + "2973" => 2973, + "2974" => 2974, + "2975" => 2975, + "2976" => 2976, + "2977" => 2977, + "2978" => 2978, + "2979" => 2979, + "2980" => 2980, + "2981" => 2981, + "2982" => 2982, + "2983" => 2983, + "2984" => 2984, + "2985" => 2985, + "2986" => 2986, + "2987" => 2987, + "2988" => 2988, + "2989" => 2989, + "2990" => 2990, + "2991" => 2991, + "2992" => 2992, + "2993" => 2993, + "2994" => 2994, + "2995" => 2995, + "2996" => 2996, + "2997" => 2997, + "2998" => 2998, + "2999" => 2999, + "3000" => 3000, + "3001" => 3001, + "3002" => 3002, + "3003" => 3003, + "3004" => 3004, + "3005" => 3005, + "3006" => 3006, + "3007" => 3007, + "3008" => 3008, + "3009" => 3009, + "3010" => 3010, + "3011" => 3011, + "3012" => 3012, + "3013" => 3013, + "3014" => 3014, + "3015" => 3015, + "3016" => 3016, + "3017" => 3017, + "3018" => 3018, + "3019" => 3019, + "3020" => 3020, + "3021" => 3021, + "3022" => 3022, + "3023" => 3023, + "3024" => 3024, + "3025" => 3025, + "3026" => 3026, + "3027" => 3027, + "3028" => 3028, + "3029" => 3029, + "3030" => 3030, + "3031" => 3031, + "3032" => 3032, + "3033" => 3033, + "3034" => 3034, + "3035" => 3035, + "3036" => 3036, + "3037" => 3037, + "3038" => 3038, + "3039" => 3039, + "3040" => 3040, + "3041" => 3041, + "3042" => 3042, + "3043" => 3043, + "3044" => 3044, + "3045" => 3045, + "3046" => 3046, + "3047" => 3047, + "3048" => 3048, + "3049" => 3049, + "3050" => 3050, + "3051" => 3051, + "3052" => 3052, + "3053" => 3053, + "3054" => 3054, + "3055" => 3055, + "3056" => 3056, + "3057" => 3057, + "3058" => 3058, + "3059" => 3059, + "3060" => 3060, + "3061" => 3061, + "3062" => 3062, + "3063" => 3063, + "3064" => 3064, + "3065" => 3065, + "3066" => 3066, + "3067" => 3067, + "3068" => 3068, + "3069" => 3069, + "3070" => 3070, + "3071" => 3071, + "3072" => 3072, + "3073" => 3073, + "3074" => 3074, + "3075" => 3075, + "3076" => 3076, + "3077" => 3077, + "3078" => 3078, + "3079" => 3079, + "3080" => 3080, + "3081" => 3081, + "3082" => 3082, + "3083" => 3083, + "3084" => 3084, + "3085" => 3085, + "3086" => 3086, + "3087" => 3087, + "3088" => 3088, + "3089" => 3089, + "3090" => 3090, + "3091" => 3091, + "3092" => 3092, + "3093" => 3093, + "3094" => 3094, + "3095" => 3095, + "3096" => 3096, + "3097" => 3097, + "3098" => 3098, + "3099" => 3099, + "3100" => 3100, + "3101" => 3101, + "3102" => 3102, + "3103" => 3103, + "3104" => 3104, + "3105" => 3105, + "3106" => 3106, + "3107" => 3107, + "3108" => 3108, + "3109" => 3109, + "3110" => 3110, + "3111" => 3111, + "3112" => 3112, + "3113" => 3113, + "3114" => 3114, + "3115" => 3115, + "3116" => 3116, + "3117" => 3117, + "3118" => 3118, + "3119" => 3119, + "3120" => 3120, + "3121" => 3121, + "3122" => 3122, + "3123" => 3123, + "3124" => 3124, + "3125" => 3125, + "3126" => 3126, + "3127" => 3127, + "3128" => 3128, + "3129" => 3129, + "3130" => 3130, + "3131" => 3131, + "3132" => 3132, + "3133" => 3133, + "3134" => 3134, + "3135" => 3135, + "3136" => 3136, + "3137" => 3137, + "3138" => 3138, + "3139" => 3139, + "3140" => 3140, + "3141" => 3141, + "3142" => 3142, + "3143" => 3143, + "3144" => 3144, + "3145" => 3145, + "3146" => 3146, + "3147" => 3147, + "3148" => 3148, + "3149" => 3149, + "3150" => 3150, + "3151" => 3151, + "3152" => 3152, + "3153" => 3153, + "3154" => 3154, + "3155" => 3155, + "3156" => 3156, + "3157" => 3157, + "3158" => 3158, + "3159" => 3159, + "3160" => 3160, + "3161" => 3161, + "3162" => 3162, + "3163" => 3163, + "3164" => 3164, + "3165" => 3165, + "3166" => 3166, + "3167" => 3167, + "3168" => 3168, + "3169" => 3169, + "3170" => 3170, + "3171" => 3171, + "3172" => 3172, + "3173" => 3173, + "3174" => 3174, + "3175" => 3175, + "3176" => 3176, + "3177" => 3177, + "3178" => 3178, + "3179" => 3179, + "3180" => 3180, + "3181" => 3181, + "3182" => 3182, + "3183" => 3183, + "3184" => 3184, + "3185" => 3185, + "3186" => 3186, + "3187" => 3187, + "3188" => 3188, + "3189" => 3189, + "3190" => 3190, + "3191" => 3191, + "3192" => 3192, + "3193" => 3193, + "3194" => 3194, + "3195" => 3195, + "3196" => 3196, + "3197" => 3197, + "3198" => 3198, + "3199" => 3199, + "3200" => 3200, + "3201" => 3201, + "3202" => 3202, + "3203" => 3203, + "3204" => 3204, + "3205" => 3205, + "3206" => 3206, + "3207" => 3207, + "3208" => 3208, + "3209" => 3209, + "3210" => 3210, + "3211" => 3211, + "3212" => 3212, + "3213" => 3213, + "3214" => 3214, + "3215" => 3215, + "3216" => 3216, + "3217" => 3217, + "3218" => 3218, + "3219" => 3219, + "3220" => 3220, + "3221" => 3221, + "3222" => 3222, + "3223" => 3223, + "3224" => 3224, + "3225" => 3225, + "3226" => 3226, + "3227" => 3227, + "3228" => 3228, + "3229" => 3229, + "3230" => 3230, + "3231" => 3231, + "3232" => 3232, + "3233" => 3233, + "3234" => 3234, + "3235" => 3235, + "3236" => 3236, + "3237" => 3237, + "3238" => 3238, + "3239" => 3239, + "3240" => 3240, + "3241" => 3241, + "3242" => 3242, + "3243" => 3243, + "3244" => 3244, + "3245" => 3245, + "3246" => 3246, + "3247" => 3247, + "3248" => 3248, + "3249" => 3249, + "3250" => 3250, + "3251" => 3251, + "3252" => 3252, + "3253" => 3253, + "3254" => 3254, + "3255" => 3255, + "3256" => 3256, + "3257" => 3257, + "3258" => 3258, + "3259" => 3259, + "3260" => 3260, + "3261" => 3261, + "3262" => 3262, + "3263" => 3263, + "3264" => 3264, + "3265" => 3265, + "3266" => 3266, + "3267" => 3267, + "3268" => 3268, + "3269" => 3269, + "3270" => 3270, + "3271" => 3271, + "3272" => 3272, + "3273" => 3273, + "3274" => 3274, + "3275" => 3275, + "3276" => 3276, + "3277" => 3277, + "3278" => 3278, + "3279" => 3279, + "3280" => 3280, + "3281" => 3281, + "3282" => 3282, + "3283" => 3283, + "3284" => 3284, + "3285" => 3285, + "3286" => 3286, + "3287" => 3287, + "3288" => 3288, + "3289" => 3289, + "3290" => 3290, + "3291" => 3291, + "3292" => 3292, + "3293" => 3293, + "3294" => 3294, + "3295" => 3295, + "3296" => 3296, + "3297" => 3297, + "3298" => 3298, + "3299" => 3299, + "3300" => 3300, + "3301" => 3301, + "3302" => 3302, + "3303" => 3303, + "3304" => 3304, + "3305" => 3305, + "3306" => 3306, + "3307" => 3307, + "3308" => 3308, + "3309" => 3309, + "3310" => 3310, + "3311" => 3311, + "3312" => 3312, + "3313" => 3313, + "3314" => 3314, + "3315" => 3315, + "3316" => 3316, + "3317" => 3317, + "3318" => 3318, + "3319" => 3319, + "3320" => 3320, + "3321" => 3321, + "3322" => 3322, + "3323" => 3323, + "3324" => 3324, + "3325" => 3325, + "3326" => 3326, + "3327" => 3327, + "3328" => 3328, + "3329" => 3329, + "3330" => 3330, + "3331" => 3331, + "3332" => 3332, + "3333" => 3333, + "3334" => 3334, + "3335" => 3335, + "3336" => 3336, + "3337" => 3337, + "3338" => 3338, + "3339" => 3339, + "3340" => 3340, + "3341" => 3341, + "3342" => 3342, + "3343" => 3343, + "3344" => 3344, + "3345" => 3345, + "3346" => 3346, + "3347" => 3347, + "3348" => 3348, + "3349" => 3349, + "3350" => 3350, + "3351" => 3351, + "3352" => 3352, + "3353" => 3353, + "3354" => 3354, + "3355" => 3355, + "3356" => 3356, + "3357" => 3357, + "3358" => 3358, + "3359" => 3359, + "3360" => 3360, + "3361" => 3361, + "3362" => 3362, + "3363" => 3363, + "3364" => 3364, + "3365" => 3365, + "3366" => 3366, + "3367" => 3367, + "3368" => 3368, + "3369" => 3369, + "3370" => 3370, + "3371" => 3371, + "3372" => 3372, + "3373" => 3373, + "3374" => 3374, + "3375" => 3375, + "3376" => 3376, + "3377" => 3377, + "3378" => 3378, + "3379" => 3379, + "3380" => 3380, + "3381" => 3381, + "3382" => 3382, + "3383" => 3383, + "3384" => 3384, + "3385" => 3385, + "3386" => 3386, + "3387" => 3387, + "3388" => 3388, + "3389" => 3389, + "3390" => 3390, + "3391" => 3391, + "3392" => 3392, + "3393" => 3393, + "3394" => 3394, + "3395" => 3395, + "3396" => 3396, + "3397" => 3397, + "3398" => 3398, + "3399" => 3399, + "3400" => 3400, + "3401" => 3401, + "3402" => 3402, + "3403" => 3403, + "3404" => 3404, + "3405" => 3405, + "3406" => 3406, + "3407" => 3407, + "3408" => 3408, + "3409" => 3409, + "3410" => 3410, + "3411" => 3411, + "3412" => 3412, + "3413" => 3413, + "3414" => 3414, + "3415" => 3415, + "3416" => 3416, + "3417" => 3417, + "3418" => 3418, + "3419" => 3419, + "3420" => 3420, + "3421" => 3421, + "3422" => 3422, + "3423" => 3423, + "3424" => 3424, + "3425" => 3425, + "3426" => 3426, + "3427" => 3427, + "3428" => 3428, + "3429" => 3429, + "3430" => 3430, + "3431" => 3431, + "3432" => 3432, + "3433" => 3433, + "3434" => 3434, + "3435" => 3435, + "3436" => 3436, + "3437" => 3437, + "3438" => 3438, + "3439" => 3439, + "3440" => 3440, + "3441" => 3441, + "3442" => 3442, + "3443" => 3443, + "3444" => 3444, + "3445" => 3445, + "3446" => 3446, + "3447" => 3447, + "3448" => 3448, + "3449" => 3449, + "3450" => 3450, + "3451" => 3451, + "3452" => 3452, + "3453" => 3453, + "3454" => 3454, + "3455" => 3455, + "3456" => 3456, + "3457" => 3457, + "3458" => 3458, + "3459" => 3459, + "3460" => 3460, + "3461" => 3461, + "3462" => 3462, + "3463" => 3463, + "3464" => 3464, + "3465" => 3465, + "3466" => 3466, + "3467" => 3467, + "3468" => 3468, + "3469" => 3469, + "3470" => 3470, + "3471" => 3471, + "3472" => 3472, + "3473" => 3473, + "3474" => 3474, + "3475" => 3475, + "3476" => 3476, + "3477" => 3477, + "3478" => 3478, + "3479" => 3479, + "3480" => 3480, + "3481" => 3481, + "3482" => 3482, + "3483" => 3483, + "3484" => 3484, + "3485" => 3485, + "3486" => 3486, + "3487" => 3487, + "3488" => 3488, + "3489" => 3489, + "3490" => 3490, + "3491" => 3491, + "3492" => 3492, + "3493" => 3493, + "3494" => 3494, + "3495" => 3495, + "3496" => 3496, + "3497" => 3497, + "3498" => 3498, + "3499" => 3499, + "3500" => 3500, + "3501" => 3501, + "3502" => 3502, + "3503" => 3503, + "3504" => 3504, + "3505" => 3505, + "3506" => 3506, + "3507" => 3507, + "3508" => 3508, + "3509" => 3509, + "3510" => 3510, + "3511" => 3511, + "3512" => 3512, + "3513" => 3513, + "3514" => 3514, + "3515" => 3515, + "3516" => 3516, + "3517" => 3517, + "3518" => 3518, + "3519" => 3519, + "3520" => 3520, + "3521" => 3521, + "3522" => 3522, + "3523" => 3523, + "3524" => 3524, + "3525" => 3525, + "3526" => 3526, + "3527" => 3527, + "3528" => 3528, + "3529" => 3529, + "3530" => 3530, + "3531" => 3531, + "3532" => 3532, + "3533" => 3533, + "3534" => 3534, + "3535" => 3535, + "3536" => 3536, + "3537" => 3537, + "3538" => 3538, + "3539" => 3539, + "3540" => 3540, + "3541" => 3541, + "3542" => 3542, + "3543" => 3543, + "3544" => 3544, + "3545" => 3545, + "3546" => 3546, + "3547" => 3547, + "3548" => 3548, + "3549" => 3549, + "3550" => 3550, + "3551" => 3551, + "3552" => 3552, + "3553" => 3553, + "3554" => 3554, + "3555" => 3555, + "3556" => 3556, + "3557" => 3557, + "3558" => 3558, + "3559" => 3559, + "3560" => 3560, + "3561" => 3561, + "3562" => 3562, + "3563" => 3563, + "3564" => 3564, + "3565" => 3565, + "3566" => 3566, + "3567" => 3567, + "3568" => 3568, + "3569" => 3569, + "3570" => 3570, + "3571" => 3571, + "3572" => 3572, + "3573" => 3573, + "3574" => 3574, + "3575" => 3575, + "3576" => 3576, + "3577" => 3577, + "3578" => 3578, + "3579" => 3579, + "3580" => 3580, + "3581" => 3581, + "3582" => 3582, + "3583" => 3583, + "3584" => 3584, + "3585" => 3585, + "3586" => 3586, + "3587" => 3587, + "3588" => 3588, + "3589" => 3589, + "3590" => 3590, + "3591" => 3591, + "3592" => 3592, + "3593" => 3593, + "3594" => 3594, + "3595" => 3595, + "3596" => 3596, + "3597" => 3597, + "3598" => 3598, + "3599" => 3599, + "3600" => 3600, + "3601" => 3601, + "3602" => 3602, + "3603" => 3603, + "3604" => 3604, + "3605" => 3605, + "3606" => 3606, + "3607" => 3607, + "3608" => 3608, + "3609" => 3609, + "3610" => 3610, + "3611" => 3611, + "3612" => 3612, + "3613" => 3613, + "3614" => 3614, + "3615" => 3615, + "3616" => 3616, + "3617" => 3617, + "3618" => 3618, + "3619" => 3619, + "3620" => 3620, + "3621" => 3621, + "3622" => 3622, + "3623" => 3623, + "3624" => 3624, + "3625" => 3625, + "3626" => 3626, + "3627" => 3627, + "3628" => 3628, + "3629" => 3629, + "3630" => 3630, + "3631" => 3631, + "3632" => 3632, + "3633" => 3633, + "3634" => 3634, + "3635" => 3635, + "3636" => 3636, + "3637" => 3637, + "3638" => 3638, + "3639" => 3639, + "3640" => 3640, + "3641" => 3641, + "3642" => 3642, + "3643" => 3643, + "3644" => 3644, + "3645" => 3645, + "3646" => 3646, + "3647" => 3647, + "3648" => 3648, + "3649" => 3649, + "3650" => 3650, + "3651" => 3651, + "3652" => 3652, + "3653" => 3653, + "3654" => 3654, + "3655" => 3655, + "3656" => 3656, + "3657" => 3657, + "3658" => 3658, + "3659" => 3659, + "3660" => 3660, + "3661" => 3661, + "3662" => 3662, + "3663" => 3663, + "3664" => 3664, + "3665" => 3665, + "3666" => 3666, + "3667" => 3667, + "3668" => 3668, + "3669" => 3669, + "3670" => 3670, + "3671" => 3671, + "3672" => 3672, + "3673" => 3673, + "3674" => 3674, + "3675" => 3675, + "3676" => 3676, + "3677" => 3677, + "3678" => 3678, + "3679" => 3679, + "3680" => 3680, + "3681" => 3681, + "3682" => 3682, + "3683" => 3683, + "3684" => 3684, + "3685" => 3685, + "3686" => 3686, + "3687" => 3687, + "3688" => 3688, + "3689" => 3689, + "3690" => 3690, + "3691" => 3691, + "3692" => 3692, + "3693" => 3693, + "3694" => 3694, + "3695" => 3695, + "3696" => 3696, + "3697" => 3697, + "3698" => 3698, + "3699" => 3699, + "3700" => 3700, + "3701" => 3701, + "3702" => 3702, + "3703" => 3703, + "3704" => 3704, + "3705" => 3705, + "3706" => 3706, + "3707" => 3707, + "3708" => 3708, + "3709" => 3709, + "3710" => 3710, + "3711" => 3711, + "3712" => 3712, + "3713" => 3713, + "3714" => 3714, + "3715" => 3715, + "3716" => 3716, + "3717" => 3717, + "3718" => 3718, + "3719" => 3719, + "3720" => 3720, + "3721" => 3721, + "3722" => 3722, + "3723" => 3723, + "3724" => 3724, + "3725" => 3725, + "3726" => 3726, + "3727" => 3727, + "3728" => 3728, + "3729" => 3729, + "3730" => 3730, + "3731" => 3731, + "3732" => 3732, + "3733" => 3733, + "3734" => 3734, + "3735" => 3735, + "3736" => 3736, + "3737" => 3737, + "3738" => 3738, + "3739" => 3739, + "3740" => 3740, + "3741" => 3741, + "3742" => 3742, + "3743" => 3743, + "3744" => 3744, + "3745" => 3745, + "3746" => 3746, + "3747" => 3747, + "3748" => 3748, + "3749" => 3749, + "3750" => 3750, + "3751" => 3751, + "3752" => 3752, + "3753" => 3753, + "3754" => 3754, + "3755" => 3755, + "3756" => 3756, + "3757" => 3757, + "3758" => 3758, + "3759" => 3759, + "3760" => 3760, + "3761" => 3761, + "3762" => 3762, + "3763" => 3763, + "3764" => 3764, + "3765" => 3765, + "3766" => 3766, + "3767" => 3767, + "3768" => 3768, + "3769" => 3769, + "3770" => 3770, + "3771" => 3771, + "3772" => 3772, + "3773" => 3773, + "3774" => 3774, + "3775" => 3775, + "3776" => 3776, + "3777" => 3777, + "3778" => 3778, + "3779" => 3779, + "3780" => 3780, + "3781" => 3781, + "3782" => 3782, + "3783" => 3783, + "3784" => 3784, + "3785" => 3785, + "3786" => 3786, + "3787" => 3787, + "3788" => 3788, + "3789" => 3789, + "3790" => 3790, + "3791" => 3791, + "3792" => 3792, + "3793" => 3793, + "3794" => 3794, + "3795" => 3795, + "3796" => 3796, + "3797" => 3797, + "3798" => 3798, + "3799" => 3799, + "3800" => 3800, + "3801" => 3801, + "3802" => 3802, + "3803" => 3803, + "3804" => 3804, + "3805" => 3805, + "3806" => 3806, + "3807" => 3807, + "3808" => 3808, + "3809" => 3809, + "3810" => 3810, + "3811" => 3811, + "3812" => 3812, + "3813" => 3813, + "3814" => 3814, + "3815" => 3815, + "3816" => 3816, + "3817" => 3817, + "3818" => 3818, + "3819" => 3819, + "3820" => 3820, + "3821" => 3821, + "3822" => 3822, + "3823" => 3823, + "3824" => 3824, + "3825" => 3825, + "3826" => 3826, + "3827" => 3827, + "3828" => 3828, + "3829" => 3829, + "3830" => 3830, + "3831" => 3831, + "3832" => 3832, + "3833" => 3833, + "3834" => 3834, + "3835" => 3835, + "3836" => 3836, + "3837" => 3837, + "3838" => 3838, + "3839" => 3839, + "3840" => 3840, + "3841" => 3841, + "3842" => 3842, + "3843" => 3843, + "3844" => 3844, + "3845" => 3845, + "3846" => 3846, + "3847" => 3847, + "3848" => 3848, + "3849" => 3849, + "3850" => 3850, + "3851" => 3851, + "3852" => 3852, + "3853" => 3853, + "3854" => 3854, + "3855" => 3855, + "3856" => 3856, + "3857" => 3857, + "3858" => 3858, + "3859" => 3859, + "3860" => 3860, + "3861" => 3861, + "3862" => 3862, + "3863" => 3863, + "3864" => 3864, + "3865" => 3865, + "3866" => 3866, + "3867" => 3867, + "3868" => 3868, + "3869" => 3869, + "3870" => 3870, + "3871" => 3871, + "3872" => 3872, + "3873" => 3873, + "3874" => 3874, + "3875" => 3875, + "3876" => 3876, + "3877" => 3877, + "3878" => 3878, + "3879" => 3879, + "3880" => 3880, + "3881" => 3881, + "3882" => 3882, + "3883" => 3883, + "3884" => 3884, + "3885" => 3885, + "3886" => 3886, + "3887" => 3887, + "3888" => 3888, + "3889" => 3889, + "3890" => 3890, + "3891" => 3891, + "3892" => 3892, + "3893" => 3893, + "3894" => 3894, + "3895" => 3895, + "3896" => 3896, + "3897" => 3897, + "3898" => 3898, + "3899" => 3899, + "3900" => 3900, + "3901" => 3901, + "3902" => 3902, + "3903" => 3903, + "3904" => 3904, + "3905" => 3905, + "3906" => 3906, + "3907" => 3907, + "3908" => 3908, + "3909" => 3909, + "3910" => 3910, + "3911" => 3911, + "3912" => 3912, + "3913" => 3913, + "3914" => 3914, + "3915" => 3915, + "3916" => 3916, + "3917" => 3917, + "3918" => 3918, + "3919" => 3919, + "3920" => 3920, + "3921" => 3921, + "3922" => 3922, + "3923" => 3923, + "3924" => 3924, + "3925" => 3925, + "3926" => 3926, + "3927" => 3927, + "3928" => 3928, + "3929" => 3929, + "3930" => 3930, + "3931" => 3931, + "3932" => 3932, + "3933" => 3933, + "3934" => 3934, + "3935" => 3935, + "3936" => 3936, + "3937" => 3937, + "3938" => 3938, + "3939" => 3939, + "3940" => 3940, + "3941" => 3941, + "3942" => 3942, + "3943" => 3943, + "3944" => 3944, + "3945" => 3945, + "3946" => 3946, + "3947" => 3947, + "3948" => 3948, + "3949" => 3949, + "3950" => 3950, + "3951" => 3951, + "3952" => 3952, + "3953" => 3953, + "3954" => 3954, + "3955" => 3955, + "3956" => 3956, + "3957" => 3957, + "3958" => 3958, + "3959" => 3959, + "3960" => 3960, + "3961" => 3961, + "3962" => 3962, + "3963" => 3963, + "3964" => 3964, + "3965" => 3965, + "3966" => 3966, + "3967" => 3967, + "3968" => 3968, + "3969" => 3969, + "3970" => 3970, + "3971" => 3971, + "3972" => 3972, + "3973" => 3973, + "3974" => 3974, + "3975" => 3975, + "3976" => 3976, + "3977" => 3977, + "3978" => 3978, + "3979" => 3979, + "3980" => 3980, + "3981" => 3981, + "3982" => 3982, + "3983" => 3983, + "3984" => 3984, + "3985" => 3985, + "3986" => 3986, + "3987" => 3987, + "3988" => 3988, + "3989" => 3989, + "3990" => 3990, + "3991" => 3991, + "3992" => 3992, + "3993" => 3993, + "3994" => 3994, + "3995" => 3995, + "3996" => 3996, + "3997" => 3997, + "3998" => 3998, + "3999" => 3999, + "4000" => 4000, + "4001" => 4001, + "4002" => 4002, + "4003" => 4003, + "4004" => 4004, + "4005" => 4005, + "4006" => 4006, + "4007" => 4007, + "4008" => 4008, + "4009" => 4009, + "4010" => 4010, + "4011" => 4011, + "4012" => 4012, + "4013" => 4013, + "4014" => 4014, + "4015" => 4015, + "4016" => 4016, + "4017" => 4017, + "4018" => 4018, + "4019" => 4019, + "4020" => 4020, + "4021" => 4021, + "4022" => 4022, + "4023" => 4023, + "4024" => 4024, + "4025" => 4025, + "4026" => 4026, + "4027" => 4027, + "4028" => 4028, + "4029" => 4029, + "4030" => 4030, + "4031" => 4031, + "4032" => 4032, + "4033" => 4033, + "4034" => 4034, + "4035" => 4035, + "4036" => 4036, + "4037" => 4037, + "4038" => 4038, + "4039" => 4039, + "4040" => 4040, + "4041" => 4041, + "4042" => 4042, + "4043" => 4043, + "4044" => 4044, + "4045" => 4045, + "4046" => 4046, + "4047" => 4047, + "4048" => 4048, + "4049" => 4049, + "4050" => 4050, + "4051" => 4051, + "4052" => 4052, + "4053" => 4053, + "4054" => 4054, + "4055" => 4055, + "4056" => 4056, + "4057" => 4057, + "4058" => 4058, + "4059" => 4059, + "4060" => 4060, + "4061" => 4061, + "4062" => 4062, + "4063" => 4063, + "4064" => 4064, + "4065" => 4065, + "4066" => 4066, + "4067" => 4067, + "4068" => 4068, + "4069" => 4069, + "4070" => 4070, + "4071" => 4071, + "4072" => 4072, + "4073" => 4073, + "4074" => 4074, + "4075" => 4075, + "4076" => 4076, + "4077" => 4077, + "4078" => 4078, + "4079" => 4079, + "4080" => 4080, + "4081" => 4081, + "4082" => 4082, + "4083" => 4083, + "4084" => 4084, + "4085" => 4085, + "4086" => 4086, + "4087" => 4087, + "4088" => 4088, + "4089" => 4089, + "4090" => 4090, + "4091" => 4091, + "4092" => 4092, + "4093" => 4093, + "4094" => 4094, + "4095" => 4095, + "4096" => 4096, + "4097" => 4097, + "4098" => 4098, + "4099" => 4099, + "4100" => 4100, + "4101" => 4101, + "4102" => 4102, + "4103" => 4103, + "4104" => 4104, + "4105" => 4105, + "4106" => 4106, + "4107" => 4107, + "4108" => 4108, + "4109" => 4109, + "4110" => 4110, + "4111" => 4111, + "4112" => 4112, + "4113" => 4113, + "4114" => 4114, + "4115" => 4115, + "4116" => 4116, + "4117" => 4117, + "4118" => 4118, + "4119" => 4119, + "4120" => 4120, + "4121" => 4121, + "4122" => 4122, + "4123" => 4123, + "4124" => 4124, + "4125" => 4125, + "4126" => 4126, + "4127" => 4127, + "4128" => 4128, + "4129" => 4129, + "4130" => 4130, + "4131" => 4131, + "4132" => 4132, + "4133" => 4133, + "4134" => 4134, + "4135" => 4135, + "4136" => 4136, + "4137" => 4137, + "4138" => 4138, + "4139" => 4139, + "4140" => 4140, + "4141" => 4141, + "4142" => 4142, + "4143" => 4143, + "4144" => 4144, + "4145" => 4145, + "4146" => 4146, + "4147" => 4147, + "4148" => 4148, + "4149" => 4149, + "4150" => 4150, + "4151" => 4151, + "4152" => 4152, + "4153" => 4153, + "4154" => 4154, + "4155" => 4155, + "4156" => 4156, + "4157" => 4157, + "4158" => 4158, + "4159" => 4159, + "4160" => 4160, + "4161" => 4161, + "4162" => 4162, + "4163" => 4163, + "4164" => 4164, + "4165" => 4165, + "4166" => 4166, + "4167" => 4167, + "4168" => 4168, + "4169" => 4169, + "4170" => 4170, + "4171" => 4171, + "4172" => 4172, + "4173" => 4173, + "4174" => 4174, + "4175" => 4175, + "4176" => 4176, + "4177" => 4177, + "4178" => 4178, + "4179" => 4179, + "4180" => 4180, + "4181" => 4181, + "4182" => 4182, + "4183" => 4183, + "4184" => 4184, + "4185" => 4185, + "4186" => 4186, + "4187" => 4187, + "4188" => 4188, + "4189" => 4189, + "4190" => 4190, + "4191" => 4191, + "4192" => 4192, + "4193" => 4193, + "4194" => 4194, + "4195" => 4195, + "4196" => 4196, + "4197" => 4197, + "4198" => 4198, + "4199" => 4199, + "4200" => 4200, + "4201" => 4201, + "4202" => 4202, + "4203" => 4203, + "4204" => 4204, + "4205" => 4205, + "4206" => 4206, + "4207" => 4207, + "4208" => 4208, + "4209" => 4209, + "4210" => 4210, + "4211" => 4211, + "4212" => 4212, + "4213" => 4213, + "4214" => 4214, + "4215" => 4215, + "4216" => 4216, + "4217" => 4217, + "4218" => 4218, + "4219" => 4219, + "4220" => 4220, + "4221" => 4221, + "4222" => 4222, + "4223" => 4223, + "4224" => 4224, + "4225" => 4225, + "4226" => 4226, + "4227" => 4227, + "4228" => 4228, + "4229" => 4229, + "4230" => 4230, + "4231" => 4231, + "4232" => 4232, + "4233" => 4233, + "4234" => 4234, + "4235" => 4235, + "4236" => 4236, + "4237" => 4237, + "4238" => 4238, + "4239" => 4239, + "4240" => 4240, + "4241" => 4241, + "4242" => 4242, + "4243" => 4243, + "4244" => 4244, + "4245" => 4245, + "4246" => 4246, + "4247" => 4247, + "4248" => 4248, + "4249" => 4249, + "4250" => 4250, + "4251" => 4251, + "4252" => 4252, + "4253" => 4253, + "4254" => 4254, + "4255" => 4255, + "4256" => 4256, + "4257" => 4257, + "4258" => 4258, + "4259" => 4259, + "4260" => 4260, + "4261" => 4261, + "4262" => 4262, + "4263" => 4263, + "4264" => 4264, + "4265" => 4265, + "4266" => 4266, + "4267" => 4267, + "4268" => 4268, + "4269" => 4269, + "4270" => 4270, + "4271" => 4271, + "4272" => 4272, + "4273" => 4273, + "4274" => 4274, + "4275" => 4275, + "4276" => 4276, + "4277" => 4277, + "4278" => 4278, + "4279" => 4279, + "4280" => 4280, + "4281" => 4281, + "4282" => 4282, + "4283" => 4283, + "4284" => 4284, + "4285" => 4285, + "4286" => 4286, + "4287" => 4287, + "4288" => 4288, + "4289" => 4289, + "4290" => 4290, + "4291" => 4291, + "4292" => 4292, + "4293" => 4293, + "4294" => 4294, + "4295" => 4295, + "4296" => 4296, + "4297" => 4297, + "4298" => 4298, + "4299" => 4299, + "4300" => 4300, + "4301" => 4301, + "4302" => 4302, + "4303" => 4303, + "4304" => 4304, + "4305" => 4305, + "4306" => 4306, + "4307" => 4307, + "4308" => 4308, + "4309" => 4309, + "4310" => 4310, + "4311" => 4311, + "4312" => 4312, + "4313" => 4313, + "4314" => 4314, + "4315" => 4315, + "4316" => 4316, + "4317" => 4317, + "4318" => 4318, + "4319" => 4319, + "4320" => 4320, + "4321" => 4321, + "4322" => 4322, + "4323" => 4323, + "4324" => 4324, + "4325" => 4325, + "4326" => 4326, + "4327" => 4327, + "4328" => 4328, + "4329" => 4329, + "4330" => 4330, + "4331" => 4331, + "4332" => 4332, + "4333" => 4333, + "4334" => 4334, + "4335" => 4335, + "4336" => 4336, + "4337" => 4337, + "4338" => 4338, + "4339" => 4339, + "4340" => 4340, + "4341" => 4341, + "4342" => 4342, + "4343" => 4343, + "4344" => 4344, + "4345" => 4345, + "4346" => 4346, + "4347" => 4347, + "4348" => 4348, + "4349" => 4349, + "4350" => 4350, + "4351" => 4351, + "4352" => 4352, + "4353" => 4353, + "4354" => 4354, + "4355" => 4355, + "4356" => 4356, + "4357" => 4357, + "4358" => 4358, + "4359" => 4359, + "4360" => 4360, + "4361" => 4361, + "4362" => 4362, + "4363" => 4363, + "4364" => 4364, + "4365" => 4365, + "4366" => 4366, + "4367" => 4367, + "4368" => 4368, + "4369" => 4369, + "4370" => 4370, + "4371" => 4371, + "4372" => 4372, + "4373" => 4373, + "4374" => 4374, + "4375" => 4375, + "4376" => 4376, + "4377" => 4377, + "4378" => 4378, + "4379" => 4379, + "4380" => 4380, + "4381" => 4381, + "4382" => 4382, + "4383" => 4383, + "4384" => 4384, + "4385" => 4385, + "4386" => 4386, + "4387" => 4387, + "4388" => 4388, + "4389" => 4389, + "4390" => 4390, + "4391" => 4391, + "4392" => 4392, + "4393" => 4393, + "4394" => 4394, + "4395" => 4395, + "4396" => 4396, + "4397" => 4397, + "4398" => 4398, + "4399" => 4399, + "4400" => 4400, + "4401" => 4401, + "4402" => 4402, + "4403" => 4403, + "4404" => 4404, + "4405" => 4405, + "4406" => 4406, + "4407" => 4407, + "4408" => 4408, + "4409" => 4409, + "4410" => 4410, + "4411" => 4411, + "4412" => 4412, + "4413" => 4413, + "4414" => 4414, + "4415" => 4415, + "4416" => 4416, + "4417" => 4417, + "4418" => 4418, + "4419" => 4419, + "4420" => 4420, + "4421" => 4421, + "4422" => 4422, + "4423" => 4423, + "4424" => 4424, + "4425" => 4425, + "4426" => 4426, + "4427" => 4427, + "4428" => 4428, + "4429" => 4429, + "4430" => 4430, + "4431" => 4431, + "4432" => 4432, + "4433" => 4433, + "4434" => 4434, + "4435" => 4435, + "4436" => 4436, + "4437" => 4437, + "4438" => 4438, + "4439" => 4439, + "4440" => 4440, + "4441" => 4441, + "4442" => 4442, + "4443" => 4443, + "4444" => 4444, + "4445" => 4445, + "4446" => 4446, + "4447" => 4447, + "4448" => 4448, + "4449" => 4449, + "4450" => 4450, + "4451" => 4451, + "4452" => 4452, + "4453" => 4453, + "4454" => 4454, + "4455" => 4455, + "4456" => 4456, + "4457" => 4457, + "4458" => 4458, + "4459" => 4459, + "4460" => 4460, + "4461" => 4461, + "4462" => 4462, + "4463" => 4463, + "4464" => 4464, + "4465" => 4465, + "4466" => 4466, + "4467" => 4467, + "4468" => 4468, + "4469" => 4469, + "4470" => 4470, + "4471" => 4471, + "4472" => 4472, + "4473" => 4473, + "4474" => 4474, + "4475" => 4475, + "4476" => 4476, + "4477" => 4477, + "4478" => 4478, + "4479" => 4479, + "4480" => 4480, + "4481" => 4481, + "4482" => 4482, + "4483" => 4483, + "4484" => 4484, + "4485" => 4485, + "4486" => 4486, + "4487" => 4487, + "4488" => 4488, + "4489" => 4489, + "4490" => 4490, + "4491" => 4491, + "4492" => 4492, + "4493" => 4493, + "4494" => 4494, + "4495" => 4495, + "4496" => 4496, + "4497" => 4497, + "4498" => 4498, + "4499" => 4499, + "4500" => 4500, + "4501" => 4501, + "4502" => 4502, + "4503" => 4503, + "4504" => 4504, + "4505" => 4505, + "4506" => 4506, + "4507" => 4507, + "4508" => 4508, + "4509" => 4509, + "4510" => 4510, + "4511" => 4511, + "4512" => 4512, + "4513" => 4513, + "4514" => 4514, + "4515" => 4515, + "4516" => 4516, + "4517" => 4517, + "4518" => 4518, + "4519" => 4519, + "4520" => 4520, + "4521" => 4521, + "4522" => 4522, + "4523" => 4523, + "4524" => 4524, + "4525" => 4525, + "4526" => 4526, + "4527" => 4527, + "4528" => 4528, + "4529" => 4529, + "4530" => 4530, + "4531" => 4531, + "4532" => 4532, + "4533" => 4533, + "4534" => 4534, + "4535" => 4535, + "4536" => 4536, + "4537" => 4537, + "4538" => 4538, + "4539" => 4539, + "4540" => 4540, + "4541" => 4541, + "4542" => 4542, + "4543" => 4543, + "4544" => 4544, + "4545" => 4545, + "4546" => 4546, + "4547" => 4547, + "4548" => 4548, + "4549" => 4549, + "4550" => 4550, + "4551" => 4551, + "4552" => 4552, + "4553" => 4553, + "4554" => 4554, + "4555" => 4555, + "4556" => 4556, + "4557" => 4557, + "4558" => 4558, + "4559" => 4559, + "4560" => 4560, + "4561" => 4561, + "4562" => 4562, + "4563" => 4563, + "4564" => 4564, + "4565" => 4565, + "4566" => 4566, + "4567" => 4567, + "4568" => 4568, + "4569" => 4569, + "4570" => 4570, + "4571" => 4571, + "4572" => 4572, + "4573" => 4573, + "4574" => 4574, + "4575" => 4575, + "4576" => 4576, + "4577" => 4577, + "4578" => 4578, + "4579" => 4579, + "4580" => 4580, + "4581" => 4581, + "4582" => 4582, + "4583" => 4583, + "4584" => 4584, + "4585" => 4585, + "4586" => 4586, + "4587" => 4587, + "4588" => 4588, + "4589" => 4589, + "4590" => 4590, + "4591" => 4591, + "4592" => 4592, + "4593" => 4593, + "4594" => 4594, + "4595" => 4595, + "4596" => 4596, + "4597" => 4597, + "4598" => 4598, + "4599" => 4599, + "4600" => 4600, + "4601" => 4601, + "4602" => 4602, + "4603" => 4603, + "4604" => 4604, + "4605" => 4605, + "4606" => 4606, + "4607" => 4607, + "4608" => 4608, + "4609" => 4609, + "4610" => 4610, + "4611" => 4611, + "4612" => 4612, + "4613" => 4613, + "4614" => 4614, + "4615" => 4615, + "4616" => 4616, + "4617" => 4617, + "4618" => 4618, + "4619" => 4619, + "4620" => 4620, + "4621" => 4621, + "4622" => 4622, + "4623" => 4623, + "4624" => 4624, + "4625" => 4625, + "4626" => 4626, + "4627" => 4627, + "4628" => 4628, + "4629" => 4629, + "4630" => 4630, + "4631" => 4631, + "4632" => 4632, + "4633" => 4633, + "4634" => 4634, + "4635" => 4635, + "4636" => 4636, + "4637" => 4637, + "4638" => 4638, + "4639" => 4639, + "4640" => 4640, + "4641" => 4641, + "4642" => 4642, + "4643" => 4643, + "4644" => 4644, + "4645" => 4645, + "4646" => 4646, + "4647" => 4647, + "4648" => 4648, + "4649" => 4649, + "4650" => 4650, + "4651" => 4651, + "4652" => 4652, + "4653" => 4653, + "4654" => 4654, + "4655" => 4655, + "4656" => 4656, + "4657" => 4657, + "4658" => 4658, + "4659" => 4659, + "4660" => 4660, + "4661" => 4661, + "4662" => 4662, + "4663" => 4663, + "4664" => 4664, + "4665" => 4665, + "4666" => 4666, + "4667" => 4667, + "4668" => 4668, + "4669" => 4669, + "4670" => 4670, + "4671" => 4671, + "4672" => 4672, + "4673" => 4673, + "4674" => 4674, + "4675" => 4675, + "4676" => 4676, + "4677" => 4677, + "4678" => 4678, + "4679" => 4679, + "4680" => 4680, + "4681" => 4681, + "4682" => 4682, + "4683" => 4683, + "4684" => 4684, + "4685" => 4685, + "4686" => 4686, + "4687" => 4687, + "4688" => 4688, + "4689" => 4689, + "4690" => 4690, + "4691" => 4691, + "4692" => 4692, + "4693" => 4693, + "4694" => 4694, + "4695" => 4695, + "4696" => 4696, + "4697" => 4697, + "4698" => 4698, + "4699" => 4699, + "4700" => 4700, + "4701" => 4701, + "4702" => 4702, + "4703" => 4703, + "4704" => 4704, + "4705" => 4705, + "4706" => 4706, + "4707" => 4707, + "4708" => 4708, + "4709" => 4709, + "4710" => 4710, + "4711" => 4711, + "4712" => 4712, + "4713" => 4713, + "4714" => 4714, + "4715" => 4715, + "4716" => 4716, + "4717" => 4717, + "4718" => 4718, + "4719" => 4719, + "4720" => 4720, + "4721" => 4721, + "4722" => 4722, + "4723" => 4723, + "4724" => 4724, + "4725" => 4725, + "4726" => 4726, + "4727" => 4727, + "4728" => 4728, + "4729" => 4729, + "4730" => 4730, + "4731" => 4731, + "4732" => 4732, + "4733" => 4733, + "4734" => 4734, + "4735" => 4735, + "4736" => 4736, + "4737" => 4737, + "4738" => 4738, + "4739" => 4739, + "4740" => 4740, + "4741" => 4741, + "4742" => 4742, + "4743" => 4743, + "4744" => 4744, + "4745" => 4745, + "4746" => 4746, + "4747" => 4747, + "4748" => 4748, + "4749" => 4749, + "4750" => 4750, + "4751" => 4751, + "4752" => 4752, + "4753" => 4753, + "4754" => 4754, + "4755" => 4755, + "4756" => 4756, + "4757" => 4757, + "4758" => 4758, + "4759" => 4759, + "4760" => 4760, + "4761" => 4761, + "4762" => 4762, + "4763" => 4763, + "4764" => 4764, + "4765" => 4765, + "4766" => 4766, + "4767" => 4767, + "4768" => 4768, + "4769" => 4769, + "4770" => 4770, + "4771" => 4771, + "4772" => 4772, + "4773" => 4773, + "4774" => 4774, + "4775" => 4775, + "4776" => 4776, + "4777" => 4777, + "4778" => 4778, + "4779" => 4779, + "4780" => 4780, + "4781" => 4781, + "4782" => 4782, + "4783" => 4783, + "4784" => 4784, + "4785" => 4785, + "4786" => 4786, + "4787" => 4787, + "4788" => 4788, + "4789" => 4789, + "4790" => 4790, + "4791" => 4791, + "4792" => 4792, + "4793" => 4793, + "4794" => 4794, + "4795" => 4795, + "4796" => 4796, + "4797" => 4797, + "4798" => 4798, + "4799" => 4799, + "4800" => 4800, + "4801" => 4801, + "4802" => 4802, + "4803" => 4803, + "4804" => 4804, + "4805" => 4805, + "4806" => 4806, + "4807" => 4807, + "4808" => 4808, + "4809" => 4809, + "4810" => 4810, + "4811" => 4811, + "4812" => 4812, + "4813" => 4813, + "4814" => 4814, + "4815" => 4815, + "4816" => 4816, + "4817" => 4817, + "4818" => 4818, + "4819" => 4819, + "4820" => 4820, + "4821" => 4821, + "4822" => 4822, + "4823" => 4823, + "4824" => 4824, + "4825" => 4825, + "4826" => 4826, + "4827" => 4827, + "4828" => 4828, + "4829" => 4829, + "4830" => 4830, + "4831" => 4831, + "4832" => 4832, + "4833" => 4833, + "4834" => 4834, + "4835" => 4835, + "4836" => 4836, + "4837" => 4837, + "4838" => 4838, + "4839" => 4839, + "4840" => 4840, + "4841" => 4841, + "4842" => 4842, + "4843" => 4843, + "4844" => 4844, + "4845" => 4845, + "4846" => 4846, + "4847" => 4847, + "4848" => 4848, + "4849" => 4849, + "4850" => 4850, + "4851" => 4851, + "4852" => 4852, + "4853" => 4853, + "4854" => 4854, + "4855" => 4855, + "4856" => 4856, + "4857" => 4857, + "4858" => 4858, + "4859" => 4859, + "4860" => 4860, + "4861" => 4861, + "4862" => 4862, + "4863" => 4863, + "4864" => 4864, + "4865" => 4865, + "4866" => 4866, + "4867" => 4867, + "4868" => 4868, + "4869" => 4869, + "4870" => 4870, + "4871" => 4871, + "4872" => 4872, + "4873" => 4873, + "4874" => 4874, + "4875" => 4875, + "4876" => 4876, + "4877" => 4877, + "4878" => 4878, + "4879" => 4879, + "4880" => 4880, + "4881" => 4881, + "4882" => 4882, + "4883" => 4883, + "4884" => 4884, + "4885" => 4885, + "4886" => 4886, + "4887" => 4887, + "4888" => 4888, + "4889" => 4889, + "4890" => 4890, + "4891" => 4891, + "4892" => 4892, + "4893" => 4893, + "4894" => 4894, + "4895" => 4895, + "4896" => 4896, + "4897" => 4897, + "4898" => 4898, + "4899" => 4899, + "4900" => 4900, + "4901" => 4901, + "4902" => 4902, + "4903" => 4903, + "4904" => 4904, + "4905" => 4905, + "4906" => 4906, + "4907" => 4907, + "4908" => 4908, + "4909" => 4909, + "4910" => 4910, + "4911" => 4911, + "4912" => 4912, + "4913" => 4913, + "4914" => 4914, + "4915" => 4915, + "4916" => 4916, + "4917" => 4917, + "4918" => 4918, + "4919" => 4919, + "4920" => 4920, + "4921" => 4921, + "4922" => 4922, + "4923" => 4923, + "4924" => 4924, + "4925" => 4925, + "4926" => 4926, + "4927" => 4927, + "4928" => 4928, + "4929" => 4929, + "4930" => 4930, + "4931" => 4931, + "4932" => 4932, + "4933" => 4933, + "4934" => 4934, + "4935" => 4935, + "4936" => 4936, + "4937" => 4937, + "4938" => 4938, + "4939" => 4939, + "4940" => 4940, + "4941" => 4941, + "4942" => 4942, + "4943" => 4943, + "4944" => 4944, + "4945" => 4945, + "4946" => 4946, + "4947" => 4947, + "4948" => 4948, + "4949" => 4949, + "4950" => 4950, + "4951" => 4951, + "4952" => 4952, + "4953" => 4953, + "4954" => 4954, + "4955" => 4955, + "4956" => 4956, + "4957" => 4957, + "4958" => 4958, + "4959" => 4959, + "4960" => 4960, + "4961" => 4961, + "4962" => 4962, + "4963" => 4963, + "4964" => 4964, + "4965" => 4965, + "4966" => 4966, + "4967" => 4967, + "4968" => 4968, + "4969" => 4969, + "4970" => 4970, + "4971" => 4971, + "4972" => 4972, + "4973" => 4973, + "4974" => 4974, + "4975" => 4975, + "4976" => 4976, + "4977" => 4977, + "4978" => 4978, + "4979" => 4979, + "4980" => 4980, + "4981" => 4981, + "4982" => 4982, + "4983" => 4983, + "4984" => 4984, + "4985" => 4985, + "4986" => 4986, + "4987" => 4987, + "4988" => 4988, + "4989" => 4989, + "4990" => 4990, + "4991" => 4991, + "4992" => 4992, + "4993" => 4993, + "4994" => 4994, + "4995" => 4995, + "4996" => 4996, + "4997" => 4997, + "4998" => 4998, + "4999" => 4999, + "5000" => 5000, + "5001" => 5001, + "5002" => 5002, + "5003" => 5003, + "5004" => 5004, + "5005" => 5005, + "5006" => 5006, + "5007" => 5007, + "5008" => 5008, + "5009" => 5009, + "5010" => 5010, + "5011" => 5011, + "5012" => 5012, + "5013" => 5013, + "5014" => 5014, + "5015" => 5015, + "5016" => 5016, + "5017" => 5017, + "5018" => 5018, + "5019" => 5019, + "5020" => 5020, + "5021" => 5021, + "5022" => 5022, + "5023" => 5023, + "5024" => 5024, + "5025" => 5025, + "5026" => 5026, + "5027" => 5027, + "5028" => 5028, + "5029" => 5029, + "5030" => 5030, + "5031" => 5031, + "5032" => 5032, + "5033" => 5033, + "5034" => 5034, + "5035" => 5035, + "5036" => 5036, + "5037" => 5037, + "5038" => 5038, + "5039" => 5039, + "5040" => 5040, + "5041" => 5041, + "5042" => 5042, + "5043" => 5043, + "5044" => 5044, + "5045" => 5045, + "5046" => 5046, + "5047" => 5047, + "5048" => 5048, + "5049" => 5049, + "5050" => 5050, + "5051" => 5051, + "5052" => 5052, + "5053" => 5053, + "5054" => 5054, + "5055" => 5055, + "5056" => 5056, + "5057" => 5057, + "5058" => 5058, + "5059" => 5059, + "5060" => 5060, + "5061" => 5061, + "5062" => 5062, + "5063" => 5063, + "5064" => 5064, + "5065" => 5065, + "5066" => 5066, + "5067" => 5067, + "5068" => 5068, + "5069" => 5069, + "5070" => 5070, + "5071" => 5071, + "5072" => 5072, + "5073" => 5073, + "5074" => 5074, + "5075" => 5075, + "5076" => 5076, + "5077" => 5077, + "5078" => 5078, + "5079" => 5079, + "5080" => 5080, + "5081" => 5081, + "5082" => 5082, + "5083" => 5083, + "5084" => 5084, + "5085" => 5085, + "5086" => 5086, + "5087" => 5087, + "5088" => 5088, + "5089" => 5089, + "5090" => 5090, + "5091" => 5091, + "5092" => 5092, + "5093" => 5093, + "5094" => 5094, + "5095" => 5095, + "5096" => 5096, + "5097" => 5097, + "5098" => 5098, + "5099" => 5099, + "5100" => 5100, + "5101" => 5101, + "5102" => 5102, + "5103" => 5103, + "5104" => 5104, + "5105" => 5105, + "5106" => 5106, + "5107" => 5107, + "5108" => 5108, + "5109" => 5109, + "5110" => 5110, + "5111" => 5111, + "5112" => 5112, + "5113" => 5113, + "5114" => 5114, + "5115" => 5115, + "5116" => 5116, + "5117" => 5117, + "5118" => 5118, + "5119" => 5119, + "5120" => 5120, + "5121" => 5121, + "5122" => 5122, + "5123" => 5123, + "5124" => 5124, + "5125" => 5125, + "5126" => 5126, + "5127" => 5127, + "5128" => 5128, + "5129" => 5129, + "5130" => 5130, + "5131" => 5131, + "5132" => 5132, + "5133" => 5133, + "5134" => 5134, + "5135" => 5135, + "5136" => 5136, + "5137" => 5137, + "5138" => 5138, + "5139" => 5139, + "5140" => 5140, + "5141" => 5141, + "5142" => 5142, + "5143" => 5143, + "5144" => 5144, + "5145" => 5145, + "5146" => 5146, + "5147" => 5147, + "5148" => 5148, + "5149" => 5149, + "5150" => 5150, + "5151" => 5151, + "5152" => 5152, + "5153" => 5153, + "5154" => 5154, + "5155" => 5155, + "5156" => 5156, + "5157" => 5157, + "5158" => 5158, + "5159" => 5159, + "5160" => 5160, + "5161" => 5161, + "5162" => 5162, + "5163" => 5163, + "5164" => 5164, + "5165" => 5165, + "5166" => 5166, + "5167" => 5167, + "5168" => 5168, + "5169" => 5169, + "5170" => 5170, + "5171" => 5171, + "5172" => 5172, + "5173" => 5173, + "5174" => 5174, + "5175" => 5175, + "5176" => 5176, + "5177" => 5177, + "5178" => 5178, + "5179" => 5179, + "5180" => 5180, + "5181" => 5181, + "5182" => 5182, + "5183" => 5183, + "5184" => 5184, + "5185" => 5185, + "5186" => 5186, + "5187" => 5187, + "5188" => 5188, + "5189" => 5189, + "5190" => 5190, + "5191" => 5191, + "5192" => 5192, + "5193" => 5193, + "5194" => 5194, + "5195" => 5195, + "5196" => 5196, + "5197" => 5197, + "5198" => 5198, + _ => 5199, + } +} diff --git a/src/test/ui/issues/issue-8460.rs b/src/test/ui/issues/issue-8460.rs index 3fd576a8d35..a7de4bd74aa 100644 --- a/src/test/ui/issues/issue-8460.rs +++ b/src/test/ui/issues/issue-8460.rs @@ -27,21 +27,21 @@ macro_rules! check { fn main() { check![ - isize::min_value() / -isize::one(), - i8::min_value() / -i8::one(), - i16::min_value() / -i16::one(), - i32::min_value() / -i32::one(), - i64::min_value() / -i64::one(), + isize::MIN / -isize::one(), + i8::MIN / -i8::one(), + i16::MIN / -i16::one(), + i32::MIN / -i32::one(), + i64::MIN / -i64::one(), 1isize / isize::zero(), 1i8 / i8::zero(), 1i16 / i16::zero(), 1i32 / i32::zero(), 1i64 / i64::zero(), - isize::min_value() % -isize::one(), - i8::min_value() % -i8::one(), - i16::min_value() % -i16::one(), - i32::min_value() % -i32::one(), - i64::min_value() % -i64::one(), + isize::MIN % -isize::one(), + i8::MIN % -i8::one(), + i16::MIN % -i16::one(), + i32::MIN % -i32::one(), + i64::MIN % -i64::one(), 1isize % isize::zero(), 1i8 % i8::zero(), 1i16 % i16::zero(), diff --git a/src/test/ui/iterators/iter-step-overflow-debug.rs b/src/test/ui/iterators/iter-step-overflow-debug.rs index 5d67c7cbb42..67605d2fcc2 100644 --- a/src/test/ui/iterators/iter-step-overflow-debug.rs +++ b/src/test/ui/iterators/iter-step-overflow-debug.rs @@ -6,14 +6,14 @@ use std::panic; fn main() { let r = panic::catch_unwind(|| { - let mut it = u8::max_value()..; + let mut it = u8::MAX..; it.next().unwrap(); // 255 it.next().unwrap(); }); assert!(r.is_err()); let r = panic::catch_unwind(|| { - let mut it = i8::max_value()..; + let mut it = i8::MAX..; it.next().unwrap(); // 127 it.next().unwrap(); }); diff --git a/src/test/ui/iterators/iter-step-overflow-ndebug.rs b/src/test/ui/iterators/iter-step-overflow-ndebug.rs index a0ad92071b6..33e708769ba 100644 --- a/src/test/ui/iterators/iter-step-overflow-ndebug.rs +++ b/src/test/ui/iterators/iter-step-overflow-ndebug.rs @@ -2,11 +2,11 @@ // compile-flags: -C debug_assertions=no fn main() { - let mut it = u8::max_value()..; + let mut it = u8::MAX..; assert_eq!(it.next().unwrap(), 255); - assert_eq!(it.next().unwrap(), u8::min_value()); + assert_eq!(it.next().unwrap(), u8::MIN); - let mut it = i8::max_value()..; + let mut it = i8::MAX..; assert_eq!(it.next().unwrap(), 127); - assert_eq!(it.next().unwrap(), i8::min_value()); + assert_eq!(it.next().unwrap(), i8::MIN); } diff --git a/src/test/ui/iterators/iter-sum-overflow-debug.rs b/src/test/ui/iterators/iter-sum-overflow-debug.rs index ee4ab4d24c6..b7667d1bbf6 100644 --- a/src/test/ui/iterators/iter-sum-overflow-debug.rs +++ b/src/test/ui/iterators/iter-sum-overflow-debug.rs @@ -6,22 +6,22 @@ use std::panic; fn main() { let r = panic::catch_unwind(|| { - [1, i32::max_value()].iter().sum::<i32>(); + [1, i32::MAX].iter().sum::<i32>(); }); assert!(r.is_err()); let r = panic::catch_unwind(|| { - [2, i32::max_value()].iter().product::<i32>(); + [2, i32::MAX].iter().product::<i32>(); }); assert!(r.is_err()); let r = panic::catch_unwind(|| { - [1, i32::max_value()].iter().cloned().sum::<i32>(); + [1, i32::MAX].iter().cloned().sum::<i32>(); }); assert!(r.is_err()); let r = panic::catch_unwind(|| { - [2, i32::max_value()].iter().cloned().product::<i32>(); + [2, i32::MAX].iter().cloned().product::<i32>(); }); assert!(r.is_err()); } diff --git a/src/test/ui/iterators/iter-sum-overflow-ndebug.rs b/src/test/ui/iterators/iter-sum-overflow-ndebug.rs index 61d63d41fb8..69f4744cc2a 100644 --- a/src/test/ui/iterators/iter-sum-overflow-ndebug.rs +++ b/src/test/ui/iterators/iter-sum-overflow-ndebug.rs @@ -2,13 +2,13 @@ // compile-flags: -C debug_assertions=no fn main() { - assert_eq!([1i32, i32::max_value()].iter().sum::<i32>(), - 1i32.wrapping_add(i32::max_value())); - assert_eq!([2i32, i32::max_value()].iter().product::<i32>(), - 2i32.wrapping_mul(i32::max_value())); + assert_eq!([1i32, i32::MAX].iter().sum::<i32>(), + 1i32.wrapping_add(i32::MAX)); + assert_eq!([2i32, i32::MAX].iter().product::<i32>(), + 2i32.wrapping_mul(i32::MAX)); - assert_eq!([1i32, i32::max_value()].iter().cloned().sum::<i32>(), - 1i32.wrapping_add(i32::max_value())); - assert_eq!([2i32, i32::max_value()].iter().cloned().product::<i32>(), - 2i32.wrapping_mul(i32::max_value())); + assert_eq!([1i32, i32::MAX].iter().cloned().sum::<i32>(), + 1i32.wrapping_add(i32::MAX)); + assert_eq!([2i32, i32::MAX].iter().cloned().product::<i32>(), + 2i32.wrapping_mul(i32::MAX)); } diff --git a/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs b/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs index 429f8e0bc96..04ca7f8a315 100644 --- a/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs +++ b/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs @@ -6,22 +6,22 @@ use std::panic; fn main() { let r = panic::catch_unwind(|| { - [1, i32::max_value()].iter().sum::<i32>(); + [1, i32::MAX].iter().sum::<i32>(); }); assert!(r.is_err()); let r = panic::catch_unwind(|| { - [2, i32::max_value()].iter().product::<i32>(); + [2, i32::MAX].iter().product::<i32>(); }); assert!(r.is_err()); let r = panic::catch_unwind(|| { - [1, i32::max_value()].iter().cloned().sum::<i32>(); + [1, i32::MAX].iter().cloned().sum::<i32>(); }); assert!(r.is_err()); let r = panic::catch_unwind(|| { - [2, i32::max_value()].iter().cloned().product::<i32>(); + [2, i32::MAX].iter().cloned().product::<i32>(); }); assert!(r.is_err()); } diff --git a/src/test/ui/iterators/skip-count-overflow.rs b/src/test/ui/iterators/skip-count-overflow.rs index d8efc948664..64dee3e3c8b 100644 --- a/src/test/ui/iterators/skip-count-overflow.rs +++ b/src/test/ui/iterators/skip-count-overflow.rs @@ -3,6 +3,6 @@ // compile-flags: -C overflow-checks -C opt-level=3 fn main() { - let i = (0..usize::max_value()).chain(0..10).skip(usize::max_value()); + let i = (0..usize::MAX).chain(0..10).skip(usize::MAX); assert_eq!(i.count(), 10); } diff --git a/src/test/ui/lexical-scopes.stderr b/src/test/ui/lexical-scopes.stderr index dce70545170..1e6a35ed479 100644 --- a/src/test/ui/lexical-scopes.stderr +++ b/src/test/ui/lexical-scopes.stderr @@ -3,11 +3,6 @@ error[E0574]: expected struct, variant or union type, found type parameter `T` | LL | let t = T { i: 0 }; | ^ not a struct, variant or union type - | -help: consider importing this struct instead - | -LL | use T; - | error[E0599]: no function or associated item named `f` found for type parameter `Foo` in the current scope --> $DIR/lexical-scopes.rs:10:10 diff --git a/src/test/ui/lint/expansion-time-include.rs b/src/test/ui/lint/expansion-time-include.rs new file mode 100644 index 00000000000..4ea89d5adff --- /dev/null +++ b/src/test/ui/lint/expansion-time-include.rs @@ -0,0 +1,4 @@ +// ignore-test auxiliary file for expansion-time.rs + +1 +2 diff --git a/src/test/ui/lint/expansion-time.rs b/src/test/ui/lint/expansion-time.rs new file mode 100644 index 00000000000..6e420c51f0a --- /dev/null +++ b/src/test/ui/lint/expansion-time.rs @@ -0,0 +1,23 @@ +// check-pass + +#[warn(meta_variable_misuse)] +macro_rules! foo { + ( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator +} + +#[warn(missing_fragment_specifier)] +macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier + //~| WARN this was previously accepted + +#[warn(soft_unstable)] +mod benches { + #[bench] //~ WARN use of unstable library feature 'test' + //~| WARN this was previously accepted + fn foo() {} +} + +#[warn(incomplete_include)] +fn main() { + // WARN see in the stderr file, the warning points to the included file. + include!("expansion-time-include.rs"); +} diff --git a/src/test/ui/lint/expansion-time.stderr b/src/test/ui/lint/expansion-time.stderr new file mode 100644 index 00000000000..e6b5cf67e39 --- /dev/null +++ b/src/test/ui/lint/expansion-time.stderr @@ -0,0 +1,56 @@ +warning: meta-variable repeats with different Kleene operator + --> $DIR/expansion-time.rs:5:29 + | +LL | ( $($i:ident)* ) => { $($i)+ }; + | - ^^ - conflicting repetition + | | + | expected repetition + | +note: the lint level is defined here + --> $DIR/expansion-time.rs:3:8 + | +LL | #[warn(meta_variable_misuse)] + | ^^^^^^^^^^^^^^^^^^^^ + +warning: missing fragment specifier + --> $DIR/expansion-time.rs:9:19 + | +LL | macro_rules! m { ($i) => {} } + | ^^ + | +note: the lint level is defined here + --> $DIR/expansion-time.rs:8:8 + | +LL | #[warn(missing_fragment_specifier)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> + +warning: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable + --> $DIR/expansion-time.rs:14:7 + | +LL | #[bench] + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/expansion-time.rs:12:8 + | +LL | #[warn(soft_unstable)] + | ^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266> + +warning: include macro expected single expression in source + --> $DIR/expansion-time-include.rs:4:1 + | +LL | 2 + | ^ + | +note: the lint level is defined here + --> $DIR/expansion-time.rs:19:8 + | +LL | #[warn(incomplete_include)] + | ^^^^^^^^^^^^^^^^^^ + +warning: 4 warnings emitted + diff --git a/src/test/ui/lint/inline-trait-and-foreign-items.stderr b/src/test/ui/lint/inline-trait-and-foreign-items.stderr index 15aaf8961b7..ae04612a4dd 100644 --- a/src/test/ui/lint/inline-trait-and-foreign-items.stderr +++ b/src/test/ui/lint/inline-trait-and-foreign-items.stderr @@ -62,10 +62,10 @@ LL | type U = impl Trait; | -------------------- not a function or closure error: could not find defining uses - --> $DIR/inline-trait-and-foreign-items.rs:26:5 + --> $DIR/inline-trait-and-foreign-items.rs:26:14 | LL | type U = impl Trait; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: aborting due to 6 previous errors; 2 warnings emitted diff --git a/src/test/ui/lint/lint-ctypes-66202.rs b/src/test/ui/lint/lint-ctypes-66202.rs new file mode 100644 index 00000000000..ebab41d143e --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-66202.rs @@ -0,0 +1,17 @@ +// check-pass + +#![deny(improper_ctypes)] + +// This test checks that return types are normalized before being checked for FFI-safety, and that +// transparent newtype wrappers are FFI-safe if the type being wrapped is FFI-safe. + +#[repr(transparent)] +pub struct W<T>(T); + +extern "C" { + pub fn bare() -> (); + pub fn normalize() -> <() as ToOwned>::Owned; + pub fn transparent() -> W<()>; +} + +fn main() {} diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs index 25d5f8ec68a..3cbc084ecae 100644 --- a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs +++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs @@ -1,5 +1,4 @@ #![feature(type_alias_impl_trait)] - #![deny(improper_ctypes)] type A = impl Fn(); @@ -10,7 +9,7 @@ pub fn ret_closure() -> A { extern "C" { pub fn a(_: A); - //~^ ERROR `extern` block uses type `A`, which is not FFI-safe +//~^ ERROR `extern` block uses type `impl std::ops::Fn<()>`, which is not FFI-safe } fn main() {} diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr index 712095e3208..06dfb7b8fbe 100644 --- a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr +++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr @@ -1,11 +1,11 @@ -error: `extern` block uses type `A`, which is not FFI-safe - --> $DIR/opaque-ty-ffi-unsafe.rs:12:17 +error: `extern` block uses type `impl std::ops::Fn<()>`, which is not FFI-safe + --> $DIR/opaque-ty-ffi-unsafe.rs:11:17 | LL | pub fn a(_: A); | ^ not FFI-safe | note: the lint level is defined here - --> $DIR/opaque-ty-ffi-unsafe.rs:3:9 + --> $DIR/opaque-ty-ffi-unsafe.rs:2:9 | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/match/issue-72896.rs b/src/test/ui/match/issue-72896.rs new file mode 100644 index 00000000000..3a8b8203731 --- /dev/null +++ b/src/test/ui/match/issue-72896.rs @@ -0,0 +1,23 @@ +// run-pass +trait EnumSetType { + type Repr; +} + +enum Enum8 { } +impl EnumSetType for Enum8 { + type Repr = u8; +} + +#[derive(PartialEq, Eq)] +struct EnumSet<T: EnumSetType> { + __enumset_underlying: T::Repr, +} + +const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 }; + +fn main() { + match CONST_SET { + CONST_SET => { /* ok */ } + _ => panic!("match fell through?"), + } +} diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 490633a3fb0..2cb99b75142 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -1,4 +1,4 @@ -error[E0584]: file for module `mod_file_disambig_aux` found at both mod_file_disambig_aux.rs and mod_file_disambig_aux/mod.rs +error[E0761]: file for module `mod_file_disambig_aux` found at both mod_file_disambig_aux.rs and mod_file_disambig_aux/mod.rs --> $DIR/mod_file_disambig.rs:1:1 | LL | mod mod_file_disambig_aux; @@ -14,5 +14,5 @@ LL | assert_eq!(mod_file_aux::bar(), 10); error: aborting due to 2 previous errors -Some errors have detailed explanations: E0433, E0584. +Some errors have detailed explanations: E0433, E0761. For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/no-implicit-prelude-nested.stderr b/src/test/ui/no-implicit-prelude-nested.stderr index 8a26366d751..198b630c52c 100644 --- a/src/test/ui/no-implicit-prelude-nested.stderr +++ b/src/test/ui/no-implicit-prelude-nested.stderr @@ -15,12 +15,10 @@ error[E0404]: expected trait, found derive macro `Clone` LL | impl Clone for Test {} | ^^^^^ not a trait | -help: consider importing one of these items instead +help: consider importing this trait instead | LL | use std::clone::Clone; | -LL | use std::prelude::v1::Clone; - | error[E0405]: cannot find trait `Iterator` in this scope --> $DIR/no-implicit-prelude-nested.rs:13:14 @@ -28,12 +26,10 @@ error[E0405]: cannot find trait `Iterator` in this scope LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this trait | LL | use std::iter::Iterator; | -LL | use std::prelude::v1::Iterator; - | error[E0405]: cannot find trait `ToString` in this scope --> $DIR/no-implicit-prelude-nested.rs:14:14 @@ -41,9 +37,7 @@ error[E0405]: cannot find trait `ToString` in this scope LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope | -help: consider importing one of these items - | -LL | use std::prelude::v1::ToString; +help: consider importing this trait | LL | use std::string::ToString; | @@ -60,12 +54,10 @@ error[E0425]: cannot find function `drop` in this scope LL | drop(2) | ^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this function | LL | use std::mem::drop; | -LL | use std::prelude::v1::drop; - | error[E0405]: cannot find trait `Add` in this scope --> $DIR/no-implicit-prelude-nested.rs:23:10 @@ -84,12 +76,10 @@ error[E0404]: expected trait, found derive macro `Clone` LL | impl Clone for Test {} | ^^^^^ not a trait | -help: consider importing one of these items instead +help: consider importing this trait instead | LL | use std::clone::Clone; | -LL | use std::prelude::v1::Clone; - | error[E0405]: cannot find trait `Iterator` in this scope --> $DIR/no-implicit-prelude-nested.rs:25:10 @@ -97,12 +87,10 @@ error[E0405]: cannot find trait `Iterator` in this scope LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this trait | LL | use std::iter::Iterator; | -LL | use std::prelude::v1::Iterator; - | error[E0405]: cannot find trait `ToString` in this scope --> $DIR/no-implicit-prelude-nested.rs:26:10 @@ -110,9 +98,7 @@ error[E0405]: cannot find trait `ToString` in this scope LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope | -help: consider importing one of these items - | -LL | use std::prelude::v1::ToString; +help: consider importing this trait | LL | use std::string::ToString; | @@ -129,12 +115,10 @@ error[E0425]: cannot find function `drop` in this scope LL | drop(2) | ^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this function | LL | use std::mem::drop; | -LL | use std::prelude::v1::drop; - | error[E0405]: cannot find trait `Add` in this scope --> $DIR/no-implicit-prelude-nested.rs:38:14 @@ -153,12 +137,10 @@ error[E0404]: expected trait, found derive macro `Clone` LL | impl Clone for Test {} | ^^^^^ not a trait | -help: consider importing one of these items instead +help: consider importing this trait instead | LL | use std::clone::Clone; | -LL | use std::prelude::v1::Clone; - | error[E0405]: cannot find trait `Iterator` in this scope --> $DIR/no-implicit-prelude-nested.rs:40:14 @@ -166,12 +148,10 @@ error[E0405]: cannot find trait `Iterator` in this scope LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this trait | LL | use std::iter::Iterator; | -LL | use std::prelude::v1::Iterator; - | error[E0405]: cannot find trait `ToString` in this scope --> $DIR/no-implicit-prelude-nested.rs:41:14 @@ -179,9 +159,7 @@ error[E0405]: cannot find trait `ToString` in this scope LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope | -help: consider importing one of these items - | -LL | use std::prelude::v1::ToString; +help: consider importing this trait | LL | use std::string::ToString; | @@ -198,12 +176,10 @@ error[E0425]: cannot find function `drop` in this scope LL | drop(2) | ^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this function | LL | use std::mem::drop; | -LL | use std::prelude::v1::drop; - | error: aborting due to 18 previous errors diff --git a/src/test/ui/no-implicit-prelude.stderr b/src/test/ui/no-implicit-prelude.stderr index 9cda4f64c79..36a9b65b7d1 100644 --- a/src/test/ui/no-implicit-prelude.stderr +++ b/src/test/ui/no-implicit-prelude.stderr @@ -15,12 +15,10 @@ error[E0404]: expected trait, found derive macro `Clone` LL | impl Clone for Test {} | ^^^^^ not a trait | -help: consider importing one of these items instead +help: consider importing this trait instead | LL | use std::clone::Clone; | -LL | use std::prelude::v1::Clone; - | error[E0405]: cannot find trait `Iterator` in this scope --> $DIR/no-implicit-prelude.rs:12:6 @@ -28,12 +26,10 @@ error[E0405]: cannot find trait `Iterator` in this scope LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this trait | LL | use std::iter::Iterator; | -LL | use std::prelude::v1::Iterator; - | error[E0405]: cannot find trait `ToString` in this scope --> $DIR/no-implicit-prelude.rs:13:6 @@ -41,9 +37,7 @@ error[E0405]: cannot find trait `ToString` in this scope LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope | -help: consider importing one of these items - | -LL | use std::prelude::v1::ToString; +help: consider importing this trait | LL | use std::string::ToString; | @@ -60,12 +54,10 @@ error[E0425]: cannot find function `drop` in this scope LL | drop(2) | ^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this function | LL | use std::mem::drop; | -LL | use std::prelude::v1::drop; - | error: aborting due to 6 previous errors diff --git a/src/test/ui/numbers-arithmetic/i128.rs b/src/test/ui/numbers-arithmetic/i128.rs index ef558c0aa0c..d61a1ab03b6 100644 --- a/src/test/ui/numbers-arithmetic/i128.rs +++ b/src/test/ui/numbers-arithmetic/i128.rs @@ -87,7 +87,7 @@ fn main() { assert_eq!((-z).checked_mul(-z), Some(0x734C_C2F2_A521)); assert_eq!((z).checked_mul(z), Some(0x734C_C2F2_A521)); assert_eq!((k).checked_mul(k), None); - let l: i128 = b(i128::min_value()); + let l: i128 = b(i128::MIN); let o: i128 = b(17); assert_eq!(l.checked_sub(b(2)), None); assert_eq!(l.checked_add(l), None); diff --git a/src/test/ui/numbers-arithmetic/int-abs-overflow.rs b/src/test/ui/numbers-arithmetic/int-abs-overflow.rs index 2bc018445db..10ec3f0c662 100644 --- a/src/test/ui/numbers-arithmetic/int-abs-overflow.rs +++ b/src/test/ui/numbers-arithmetic/int-abs-overflow.rs @@ -5,9 +5,9 @@ use std::thread; fn main() { - assert!(thread::spawn(|| i8::min_value().abs()).join().is_err()); - assert!(thread::spawn(|| i16::min_value().abs()).join().is_err()); - assert!(thread::spawn(|| i32::min_value().abs()).join().is_err()); - assert!(thread::spawn(|| i64::min_value().abs()).join().is_err()); - assert!(thread::spawn(|| isize::min_value().abs()).join().is_err()); + assert!(thread::spawn(|| i8::MIN.abs()).join().is_err()); + assert!(thread::spawn(|| i16::MIN.abs()).join().is_err()); + assert!(thread::spawn(|| i32::MIN.abs()).join().is_err()); + assert!(thread::spawn(|| i64::MIN.abs()).join().is_err()); + assert!(thread::spawn(|| isize::MIN.abs()).join().is_err()); } diff --git a/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs b/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs index e9927304f23..101c5d50b20 100644 --- a/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs +++ b/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs @@ -9,12 +9,12 @@ fn main() { macro_rules! overflow_test { ($t:ident) => ( let r = panic::catch_unwind(|| { - ($t::max_value()).next_power_of_two() + ($t::MAX).next_power_of_two() }); assert!(r.is_err()); let r = panic::catch_unwind(|| { - (($t::max_value() >> 1) + 2).next_power_of_two() + (($t::MAX >> 1) + 2).next_power_of_two() }); assert!(r.is_err()); ) diff --git a/src/test/ui/numbers-arithmetic/promoted_overflow_opt.rs b/src/test/ui/numbers-arithmetic/promoted_overflow_opt.rs index a3b8ff58a73..4785abbc554 100644 --- a/src/test/ui/numbers-arithmetic/promoted_overflow_opt.rs +++ b/src/test/ui/numbers-arithmetic/promoted_overflow_opt.rs @@ -5,5 +5,5 @@ fn main() { let x = &(0u32 - 1); - assert_eq!(*x, u32::max_value()) + assert_eq!(*x, u32::MAX) } diff --git a/src/test/ui/numbers-arithmetic/u128.rs b/src/test/ui/numbers-arithmetic/u128.rs index 0b2305c6e8b..d7e28055b21 100644 --- a/src/test/ui/numbers-arithmetic/u128.rs +++ b/src/test/ui/numbers-arithmetic/u128.rs @@ -53,14 +53,14 @@ fn main() { assert_eq!("10000000000000000000000000000000000000000000000000000000000000000000", format!("{:b}", j)); assert_eq!("340282366920938463463374607431768211455", - format!("{}", u128::max_value())); + format!("{}", u128::MAX)); assert_eq!("147573952589676412928", format!("{:?}", j)); // common traits assert_eq!(x, b(x.clone())); // overflow checks assert_eq!((z).checked_mul(z), Some(0x734C_C2F2_A521)); assert_eq!((k).checked_mul(k), None); - let l: u128 = b(u128::max_value() - 10); + let l: u128 = b(u128::MAX - 10); let o: u128 = b(17); assert_eq!(l.checked_add(b(11)), None); assert_eq!(l.checked_sub(l), Some(0)); diff --git a/src/test/ui/numeric/const-scope.stderr b/src/test/ui/numeric/const-scope.stderr index 6e1990e3a72..d7f18e19b41 100644 --- a/src/test/ui/numeric/const-scope.stderr +++ b/src/test/ui/numeric/const-scope.stderr @@ -3,6 +3,11 @@ error[E0308]: mismatched types | LL | const C: i32 = 1i8; | ^^^ expected `i32`, found `i8` + | +help: change the type of the numeric literal from `i8` to `i32` + | +LL | const C: i32 = 1i32; + | ^^^^ error[E0308]: mismatched types --> $DIR/const-scope.rs:2:15 @@ -17,6 +22,11 @@ LL | let c: i32 = 1i8; | --- ^^^ expected `i32`, found `i8` | | | expected due to this + | +help: change the type of the numeric literal from `i8` to `i32` + | +LL | let c: i32 = 1i32; + | ^^^^ error[E0308]: mismatched types --> $DIR/const-scope.rs:6:17 diff --git a/src/test/ui/numeric/numeric-cast-binop.fixed b/src/test/ui/numeric/numeric-cast-binop.fixed new file mode 100644 index 00000000000..edb085e71d3 --- /dev/null +++ b/src/test/ui/numeric/numeric-cast-binop.fixed @@ -0,0 +1,320 @@ +// run-rustfix + +// The `try_into` suggestion doesn't include this, but we do suggest it after applying it +use std::convert::TryInto; + +#[allow(unused_must_use)] +fn main() { + let x_usize: usize = 1; + let x_u128: u128 = 2; + let x_u64: u64 = 3; + let x_u32: u32 = 4; + let x_u16: u16 = 5; + let x_u8: u8 = 6; + let x_isize: isize = 7; + let x_i64: i64 = 8; + let x_i32: i32 = 9; + let x_i16: i16 = 10; + let x_i8: i8 = 11; + let x_i128: i128 = 12; + + /* u<->u */ + { + u16::from(x_u8) > x_u16; + //~^ ERROR mismatched types + u32::from(x_u8) > x_u32; + //~^ ERROR mismatched types + u64::from(x_u8) > x_u64; + //~^ ERROR mismatched types + u128::from(x_u8) > x_u128; + //~^ ERROR mismatched types + usize::from(x_u8) > x_usize; + //~^ ERROR mismatched types + + x_u16 > x_u8.into(); + //~^ ERROR mismatched types + u32::from(x_u16) > x_u32; + //~^ ERROR mismatched types + u64::from(x_u16) > x_u64; + //~^ ERROR mismatched types + u128::from(x_u16) > x_u128; + //~^ ERROR mismatched types + usize::from(x_u16) > x_usize; + //~^ ERROR mismatched types + + x_u32 > x_u8.into(); + //~^ ERROR mismatched types + x_u32 > x_u16.into(); + //~^ ERROR mismatched types + u64::from(x_u32) > x_u64; + //~^ ERROR mismatched types + u128::from(x_u32) > x_u128; + //~^ ERROR mismatched types + x_u32 > x_usize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_u64 > x_u8.into(); + //~^ ERROR mismatched types + x_u64 > x_u16.into(); + //~^ ERROR mismatched types + x_u64 > x_u32.into(); + //~^ ERROR mismatched types + u128::from(x_u64) > x_u128; + //~^ ERROR mismatched types + x_u64 > x_usize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_u128 > x_u8.into(); + //~^ ERROR mismatched types + x_u128 > x_u16.into(); + //~^ ERROR mismatched types + x_u128 > x_u32.into(); + //~^ ERROR mismatched types + x_u128 > x_u64.into(); + //~^ ERROR mismatched types + x_u128 > x_usize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_usize > x_u8.into(); + //~^ ERROR mismatched types + x_usize > x_u16.into(); + //~^ ERROR mismatched types + x_usize > x_u32.try_into().unwrap(); + //~^ ERROR mismatched types + x_usize > x_u64.try_into().unwrap(); + //~^ ERROR mismatched types + x_usize > x_u128.try_into().unwrap(); + //~^ ERROR mismatched types + } + + /* i<->i */ + { + i16::from(x_i8) > x_i16; + //~^ ERROR mismatched types + i32::from(x_i8) > x_i32; + //~^ ERROR mismatched types + i64::from(x_i8) > x_i64; + //~^ ERROR mismatched types + i128::from(x_i8) > x_i128; + //~^ ERROR mismatched types + isize::from(x_i8) > x_isize; + //~^ ERROR mismatched types + + x_i16 > x_i8.into(); + //~^ ERROR mismatched types + i32::from(x_i16) > x_i32; + //~^ ERROR mismatched types + i64::from(x_i16) > x_i64; + //~^ ERROR mismatched types + i128::from(x_i16) > x_i128; + //~^ ERROR mismatched types + isize::from(x_i16) > x_isize; + //~^ ERROR mismatched types + + x_i32 > x_i8.into(); + //~^ ERROR mismatched types + x_i32 > x_i16.into(); + //~^ ERROR mismatched types + i64::from(x_i32) > x_i64; + //~^ ERROR mismatched types + i128::from(x_i32) > x_i128; + //~^ ERROR mismatched types + x_i32 > x_isize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_i64 > x_i8.into(); + //~^ ERROR mismatched types + x_i64 > x_i16.into(); + //~^ ERROR mismatched types + x_i64 > x_i32.into(); + //~^ ERROR mismatched types + i128::from(x_i64) > x_i128; + //~^ ERROR mismatched types + x_i64 > x_isize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_i128 > x_i8.into(); + //~^ ERROR mismatched types + x_i128 > x_i16.into(); + //~^ ERROR mismatched types + x_i128 > x_i32.into(); + //~^ ERROR mismatched types + x_i128 > x_i64.into(); + //~^ ERROR mismatched types + x_i128 > x_isize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_isize > x_i8.into(); + //~^ ERROR mismatched types + x_isize > x_i16.into(); + //~^ ERROR mismatched types + x_isize > x_i32.try_into().unwrap(); + //~^ ERROR mismatched types + x_isize > x_i64.try_into().unwrap(); + //~^ ERROR mismatched types + x_isize > x_i128.try_into().unwrap(); + //~^ ERROR mismatched types + } + + /* u<->i */ + { + x_u8 > x_i8.try_into().unwrap(); + //~^ ERROR mismatched types + i16::from(x_u8) > x_i16; + //~^ ERROR mismatched types + i32::from(x_u8) > x_i32; + //~^ ERROR mismatched types + i64::from(x_u8) > x_i64; + //~^ ERROR mismatched types + i128::from(x_u8) > x_i128; + //~^ ERROR mismatched types + isize::from(x_u8) > x_isize; + //~^ ERROR mismatched types + + x_u16 > x_i8.try_into().unwrap(); + //~^ ERROR mismatched types + x_u16 > x_i16.try_into().unwrap(); + //~^ ERROR mismatched types + i32::from(x_u16) > x_i32; + //~^ ERROR mismatched types + i64::from(x_u16) > x_i64; + //~^ ERROR mismatched types + i128::from(x_u16) > x_i128; + //~^ ERROR mismatched types + x_u16 > x_isize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_u32 > x_i8.try_into().unwrap(); + //~^ ERROR mismatched types + x_u32 > x_i16.try_into().unwrap(); + //~^ ERROR mismatched types + x_u32 > x_i32.try_into().unwrap(); + //~^ ERROR mismatched types + i64::from(x_u32) > x_i64; + //~^ ERROR mismatched types + i128::from(x_u32) > x_i128; + //~^ ERROR mismatched types + x_u32 > x_isize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_u64 > x_i8.try_into().unwrap(); + //~^ ERROR mismatched types + x_u64 > x_i16.try_into().unwrap(); + //~^ ERROR mismatched types + x_u64 > x_i32.try_into().unwrap(); + //~^ ERROR mismatched types + x_u64 > x_i64.try_into().unwrap(); + //~^ ERROR mismatched types + i128::from(x_u64) > x_i128; + //~^ ERROR mismatched types + x_u64 > x_isize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_u128 > x_i8.try_into().unwrap(); + //~^ ERROR mismatched types + x_u128 > x_i16.try_into().unwrap(); + //~^ ERROR mismatched types + x_u128 > x_i32.try_into().unwrap(); + //~^ ERROR mismatched types + x_u128 > x_i64.try_into().unwrap(); + //~^ ERROR mismatched types + x_u128 > x_i128.try_into().unwrap(); + //~^ ERROR mismatched types + x_u128 > x_isize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_usize > x_i8.try_into().unwrap(); + //~^ ERROR mismatched types + x_usize > x_i16.try_into().unwrap(); + //~^ ERROR mismatched types + x_usize > x_i32.try_into().unwrap(); + //~^ ERROR mismatched types + x_usize > x_i64.try_into().unwrap(); + //~^ ERROR mismatched types + x_usize > x_i128.try_into().unwrap(); + //~^ ERROR mismatched types + x_usize > x_isize.try_into().unwrap(); + //~^ ERROR mismatched types + } + + /* i<->u */ + { + x_i8 > x_u8.try_into().unwrap(); + //~^ ERROR mismatched types + x_i8 > x_u16.try_into().unwrap(); + //~^ ERROR mismatched types + x_i8 > x_u32.try_into().unwrap(); + //~^ ERROR mismatched types + x_i8 > x_u64.try_into().unwrap(); + //~^ ERROR mismatched types + x_i8 > x_u128.try_into().unwrap(); + //~^ ERROR mismatched types + x_i8 > x_usize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_i16 > x_u8.into(); + //~^ ERROR mismatched types + x_i16 > x_u16.try_into().unwrap(); + //~^ ERROR mismatched types + x_i16 > x_u32.try_into().unwrap(); + //~^ ERROR mismatched types + x_i16 > x_u64.try_into().unwrap(); + //~^ ERROR mismatched types + x_i16 > x_u128.try_into().unwrap(); + //~^ ERROR mismatched types + x_i16 > x_usize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_i32 > x_u8.into(); + //~^ ERROR mismatched types + x_i32 > x_u16.into(); + //~^ ERROR mismatched types + x_i32 > x_u32.try_into().unwrap(); + //~^ ERROR mismatched types + x_i32 > x_u64.try_into().unwrap(); + //~^ ERROR mismatched types + x_i32 > x_u128.try_into().unwrap(); + //~^ ERROR mismatched types + x_i32 > x_usize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_i64 > x_u8.into(); + //~^ ERROR mismatched types + x_i64 > x_u16.into(); + //~^ ERROR mismatched types + x_i64 > x_u32.into(); + //~^ ERROR mismatched types + x_i64 > x_u64.try_into().unwrap(); + //~^ ERROR mismatched types + x_i64 > x_u128.try_into().unwrap(); + //~^ ERROR mismatched types + x_i64 > x_usize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_i128 > x_u8.into(); + //~^ ERROR mismatched types + x_i128 > x_u16.into(); + //~^ ERROR mismatched types + x_i128 > x_u32.into(); + //~^ ERROR mismatched types + x_i128 > x_u64.into(); + //~^ ERROR mismatched types + x_i128 > x_u128.try_into().unwrap(); + //~^ ERROR mismatched types + x_i128 > x_usize.try_into().unwrap(); + //~^ ERROR mismatched types + + x_isize > x_u8.into(); + //~^ ERROR mismatched types + x_isize > x_u16.try_into().unwrap(); + //~^ ERROR mismatched types + x_isize > x_u32.try_into().unwrap(); + //~^ ERROR mismatched types + x_isize > x_u64.try_into().unwrap(); + //~^ ERROR mismatched types + x_isize > x_u128.try_into().unwrap(); + //~^ ERROR mismatched types + x_isize > x_usize.try_into().unwrap(); + //~^ ERROR mismatched types + } +} diff --git a/src/test/ui/numeric/numeric-cast-binop.rs b/src/test/ui/numeric/numeric-cast-binop.rs new file mode 100644 index 00000000000..c1ed8de8ad8 --- /dev/null +++ b/src/test/ui/numeric/numeric-cast-binop.rs @@ -0,0 +1,320 @@ +// run-rustfix + +// The `try_into` suggestion doesn't include this, but we do suggest it after applying it +use std::convert::TryInto; + +#[allow(unused_must_use)] +fn main() { + let x_usize: usize = 1; + let x_u128: u128 = 2; + let x_u64: u64 = 3; + let x_u32: u32 = 4; + let x_u16: u16 = 5; + let x_u8: u8 = 6; + let x_isize: isize = 7; + let x_i64: i64 = 8; + let x_i32: i32 = 9; + let x_i16: i16 = 10; + let x_i8: i8 = 11; + let x_i128: i128 = 12; + + /* u<->u */ + { + x_u8 > x_u16; + //~^ ERROR mismatched types + x_u8 > x_u32; + //~^ ERROR mismatched types + x_u8 > x_u64; + //~^ ERROR mismatched types + x_u8 > x_u128; + //~^ ERROR mismatched types + x_u8 > x_usize; + //~^ ERROR mismatched types + + x_u16 > x_u8; + //~^ ERROR mismatched types + x_u16 > x_u32; + //~^ ERROR mismatched types + x_u16 > x_u64; + //~^ ERROR mismatched types + x_u16 > x_u128; + //~^ ERROR mismatched types + x_u16 > x_usize; + //~^ ERROR mismatched types + + x_u32 > x_u8; + //~^ ERROR mismatched types + x_u32 > x_u16; + //~^ ERROR mismatched types + x_u32 > x_u64; + //~^ ERROR mismatched types + x_u32 > x_u128; + //~^ ERROR mismatched types + x_u32 > x_usize; + //~^ ERROR mismatched types + + x_u64 > x_u8; + //~^ ERROR mismatched types + x_u64 > x_u16; + //~^ ERROR mismatched types + x_u64 > x_u32; + //~^ ERROR mismatched types + x_u64 > x_u128; + //~^ ERROR mismatched types + x_u64 > x_usize; + //~^ ERROR mismatched types + + x_u128 > x_u8; + //~^ ERROR mismatched types + x_u128 > x_u16; + //~^ ERROR mismatched types + x_u128 > x_u32; + //~^ ERROR mismatched types + x_u128 > x_u64; + //~^ ERROR mismatched types + x_u128 > x_usize; + //~^ ERROR mismatched types + + x_usize > x_u8; + //~^ ERROR mismatched types + x_usize > x_u16; + //~^ ERROR mismatched types + x_usize > x_u32; + //~^ ERROR mismatched types + x_usize > x_u64; + //~^ ERROR mismatched types + x_usize > x_u128; + //~^ ERROR mismatched types + } + + /* i<->i */ + { + x_i8 > x_i16; + //~^ ERROR mismatched types + x_i8 > x_i32; + //~^ ERROR mismatched types + x_i8 > x_i64; + //~^ ERROR mismatched types + x_i8 > x_i128; + //~^ ERROR mismatched types + x_i8 > x_isize; + //~^ ERROR mismatched types + + x_i16 > x_i8; + //~^ ERROR mismatched types + x_i16 > x_i32; + //~^ ERROR mismatched types + x_i16 > x_i64; + //~^ ERROR mismatched types + x_i16 > x_i128; + //~^ ERROR mismatched types + x_i16 > x_isize; + //~^ ERROR mismatched types + + x_i32 > x_i8; + //~^ ERROR mismatched types + x_i32 > x_i16; + //~^ ERROR mismatched types + x_i32 > x_i64; + //~^ ERROR mismatched types + x_i32 > x_i128; + //~^ ERROR mismatched types + x_i32 > x_isize; + //~^ ERROR mismatched types + + x_i64 > x_i8; + //~^ ERROR mismatched types + x_i64 > x_i16; + //~^ ERROR mismatched types + x_i64 > x_i32; + //~^ ERROR mismatched types + x_i64 > x_i128; + //~^ ERROR mismatched types + x_i64 > x_isize; + //~^ ERROR mismatched types + + x_i128 > x_i8; + //~^ ERROR mismatched types + x_i128 > x_i16; + //~^ ERROR mismatched types + x_i128 > x_i32; + //~^ ERROR mismatched types + x_i128 > x_i64; + //~^ ERROR mismatched types + x_i128 > x_isize; + //~^ ERROR mismatched types + + x_isize > x_i8; + //~^ ERROR mismatched types + x_isize > x_i16; + //~^ ERROR mismatched types + x_isize > x_i32; + //~^ ERROR mismatched types + x_isize > x_i64; + //~^ ERROR mismatched types + x_isize > x_i128; + //~^ ERROR mismatched types + } + + /* u<->i */ + { + x_u8 > x_i8; + //~^ ERROR mismatched types + x_u8 > x_i16; + //~^ ERROR mismatched types + x_u8 > x_i32; + //~^ ERROR mismatched types + x_u8 > x_i64; + //~^ ERROR mismatched types + x_u8 > x_i128; + //~^ ERROR mismatched types + x_u8 > x_isize; + //~^ ERROR mismatched types + + x_u16 > x_i8; + //~^ ERROR mismatched types + x_u16 > x_i16; + //~^ ERROR mismatched types + x_u16 > x_i32; + //~^ ERROR mismatched types + x_u16 > x_i64; + //~^ ERROR mismatched types + x_u16 > x_i128; + //~^ ERROR mismatched types + x_u16 > x_isize; + //~^ ERROR mismatched types + + x_u32 > x_i8; + //~^ ERROR mismatched types + x_u32 > x_i16; + //~^ ERROR mismatched types + x_u32 > x_i32; + //~^ ERROR mismatched types + x_u32 > x_i64; + //~^ ERROR mismatched types + x_u32 > x_i128; + //~^ ERROR mismatched types + x_u32 > x_isize; + //~^ ERROR mismatched types + + x_u64 > x_i8; + //~^ ERROR mismatched types + x_u64 > x_i16; + //~^ ERROR mismatched types + x_u64 > x_i32; + //~^ ERROR mismatched types + x_u64 > x_i64; + //~^ ERROR mismatched types + x_u64 > x_i128; + //~^ ERROR mismatched types + x_u64 > x_isize; + //~^ ERROR mismatched types + + x_u128 > x_i8; + //~^ ERROR mismatched types + x_u128 > x_i16; + //~^ ERROR mismatched types + x_u128 > x_i32; + //~^ ERROR mismatched types + x_u128 > x_i64; + //~^ ERROR mismatched types + x_u128 > x_i128; + //~^ ERROR mismatched types + x_u128 > x_isize; + //~^ ERROR mismatched types + + x_usize > x_i8; + //~^ ERROR mismatched types + x_usize > x_i16; + //~^ ERROR mismatched types + x_usize > x_i32; + //~^ ERROR mismatched types + x_usize > x_i64; + //~^ ERROR mismatched types + x_usize > x_i128; + //~^ ERROR mismatched types + x_usize > x_isize; + //~^ ERROR mismatched types + } + + /* i<->u */ + { + x_i8 > x_u8; + //~^ ERROR mismatched types + x_i8 > x_u16; + //~^ ERROR mismatched types + x_i8 > x_u32; + //~^ ERROR mismatched types + x_i8 > x_u64; + //~^ ERROR mismatched types + x_i8 > x_u128; + //~^ ERROR mismatched types + x_i8 > x_usize; + //~^ ERROR mismatched types + + x_i16 > x_u8; + //~^ ERROR mismatched types + x_i16 > x_u16; + //~^ ERROR mismatched types + x_i16 > x_u32; + //~^ ERROR mismatched types + x_i16 > x_u64; + //~^ ERROR mismatched types + x_i16 > x_u128; + //~^ ERROR mismatched types + x_i16 > x_usize; + //~^ ERROR mismatched types + + x_i32 > x_u8; + //~^ ERROR mismatched types + x_i32 > x_u16; + //~^ ERROR mismatched types + x_i32 > x_u32; + //~^ ERROR mismatched types + x_i32 > x_u64; + //~^ ERROR mismatched types + x_i32 > x_u128; + //~^ ERROR mismatched types + x_i32 > x_usize; + //~^ ERROR mismatched types + + x_i64 > x_u8; + //~^ ERROR mismatched types + x_i64 > x_u16; + //~^ ERROR mismatched types + x_i64 > x_u32; + //~^ ERROR mismatched types + x_i64 > x_u64; + //~^ ERROR mismatched types + x_i64 > x_u128; + //~^ ERROR mismatched types + x_i64 > x_usize; + //~^ ERROR mismatched types + + x_i128 > x_u8; + //~^ ERROR mismatched types + x_i128 > x_u16; + //~^ ERROR mismatched types + x_i128 > x_u32; + //~^ ERROR mismatched types + x_i128 > x_u64; + //~^ ERROR mismatched types + x_i128 > x_u128; + //~^ ERROR mismatched types + x_i128 > x_usize; + //~^ ERROR mismatched types + + x_isize > x_u8; + //~^ ERROR mismatched types + x_isize > x_u16; + //~^ ERROR mismatched types + x_isize > x_u32; + //~^ ERROR mismatched types + x_isize > x_u64; + //~^ ERROR mismatched types + x_isize > x_u128; + //~^ ERROR mismatched types + x_isize > x_usize; + //~^ ERROR mismatched types + } +} diff --git a/src/test/ui/numeric/numeric-cast-binop.stderr b/src/test/ui/numeric/numeric-cast-binop.stderr new file mode 100644 index 00000000000..47be817b789 --- /dev/null +++ b/src/test/ui/numeric/numeric-cast-binop.stderr @@ -0,0 +1,1385 @@ +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:23:16 + | +LL | x_u8 > x_u16; + | ^^^^^ expected `u8`, found `u16` + | +help: you can convert `x_u8` from `u8` to `u16`, matching the type of `x_u16` + | +LL | u16::from(x_u8) > x_u16; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:25:16 + | +LL | x_u8 > x_u32; + | ^^^^^ expected `u8`, found `u32` + | +help: you can convert `x_u8` from `u8` to `u32`, matching the type of `x_u32` + | +LL | u32::from(x_u8) > x_u32; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:27:16 + | +LL | x_u8 > x_u64; + | ^^^^^ expected `u8`, found `u64` + | +help: you can convert `x_u8` from `u8` to `u64`, matching the type of `x_u64` + | +LL | u64::from(x_u8) > x_u64; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:29:16 + | +LL | x_u8 > x_u128; + | ^^^^^^ expected `u8`, found `u128` + | +help: you can convert `x_u8` from `u8` to `u128`, matching the type of `x_u128` + | +LL | u128::from(x_u8) > x_u128; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:31:16 + | +LL | x_u8 > x_usize; + | ^^^^^^^ expected `u8`, found `usize` + | +help: you can convert `x_u8` from `u8` to `usize`, matching the type of `x_usize` + | +LL | usize::from(x_u8) > x_usize; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:34:17 + | +LL | x_u16 > x_u8; + | ^^^^ + | | + | expected `u16`, found `u8` + | help: you can convert an `u8` to `u16`: `x_u8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:36:17 + | +LL | x_u16 > x_u32; + | ^^^^^ expected `u16`, found `u32` + | +help: you can convert `x_u16` from `u16` to `u32`, matching the type of `x_u32` + | +LL | u32::from(x_u16) > x_u32; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:38:17 + | +LL | x_u16 > x_u64; + | ^^^^^ expected `u16`, found `u64` + | +help: you can convert `x_u16` from `u16` to `u64`, matching the type of `x_u64` + | +LL | u64::from(x_u16) > x_u64; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:40:17 + | +LL | x_u16 > x_u128; + | ^^^^^^ expected `u16`, found `u128` + | +help: you can convert `x_u16` from `u16` to `u128`, matching the type of `x_u128` + | +LL | u128::from(x_u16) > x_u128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:42:17 + | +LL | x_u16 > x_usize; + | ^^^^^^^ expected `u16`, found `usize` + | +help: you can convert `x_u16` from `u16` to `usize`, matching the type of `x_usize` + | +LL | usize::from(x_u16) > x_usize; + | ^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:45:17 + | +LL | x_u32 > x_u8; + | ^^^^ + | | + | expected `u32`, found `u8` + | help: you can convert an `u8` to `u32`: `x_u8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:47:17 + | +LL | x_u32 > x_u16; + | ^^^^^ + | | + | expected `u32`, found `u16` + | help: you can convert an `u16` to `u32`: `x_u16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:49:17 + | +LL | x_u32 > x_u64; + | ^^^^^ expected `u32`, found `u64` + | +help: you can convert `x_u32` from `u32` to `u64`, matching the type of `x_u64` + | +LL | u64::from(x_u32) > x_u64; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:51:17 + | +LL | x_u32 > x_u128; + | ^^^^^^ expected `u32`, found `u128` + | +help: you can convert `x_u32` from `u32` to `u128`, matching the type of `x_u128` + | +LL | u128::from(x_u32) > x_u128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:53:17 + | +LL | x_u32 > x_usize; + | ^^^^^^^ expected `u32`, found `usize` + | +help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit + | +LL | x_u32 > x_usize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:56:17 + | +LL | x_u64 > x_u8; + | ^^^^ + | | + | expected `u64`, found `u8` + | help: you can convert an `u8` to `u64`: `x_u8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:58:17 + | +LL | x_u64 > x_u16; + | ^^^^^ + | | + | expected `u64`, found `u16` + | help: you can convert an `u16` to `u64`: `x_u16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:60:17 + | +LL | x_u64 > x_u32; + | ^^^^^ + | | + | expected `u64`, found `u32` + | help: you can convert an `u32` to `u64`: `x_u32.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:62:17 + | +LL | x_u64 > x_u128; + | ^^^^^^ expected `u64`, found `u128` + | +help: you can convert `x_u64` from `u64` to `u128`, matching the type of `x_u128` + | +LL | u128::from(x_u64) > x_u128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:64:17 + | +LL | x_u64 > x_usize; + | ^^^^^^^ expected `u64`, found `usize` + | +help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit + | +LL | x_u64 > x_usize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:67:18 + | +LL | x_u128 > x_u8; + | ^^^^ + | | + | expected `u128`, found `u8` + | help: you can convert an `u8` to `u128`: `x_u8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:69:18 + | +LL | x_u128 > x_u16; + | ^^^^^ + | | + | expected `u128`, found `u16` + | help: you can convert an `u16` to `u128`: `x_u16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:71:18 + | +LL | x_u128 > x_u32; + | ^^^^^ + | | + | expected `u128`, found `u32` + | help: you can convert an `u32` to `u128`: `x_u32.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:73:18 + | +LL | x_u128 > x_u64; + | ^^^^^ + | | + | expected `u128`, found `u64` + | help: you can convert an `u64` to `u128`: `x_u64.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:75:18 + | +LL | x_u128 > x_usize; + | ^^^^^^^ expected `u128`, found `usize` + | +help: you can convert an `usize` to `u128` and panic if the converted value wouldn't fit + | +LL | x_u128 > x_usize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:78:19 + | +LL | x_usize > x_u8; + | ^^^^ + | | + | expected `usize`, found `u8` + | help: you can convert an `u8` to `usize`: `x_u8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:80:19 + | +LL | x_usize > x_u16; + | ^^^^^ + | | + | expected `usize`, found `u16` + | help: you can convert an `u16` to `usize`: `x_u16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:82:19 + | +LL | x_usize > x_u32; + | ^^^^^ expected `usize`, found `u32` + | +help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit + | +LL | x_usize > x_u32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:84:19 + | +LL | x_usize > x_u64; + | ^^^^^ expected `usize`, found `u64` + | +help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit + | +LL | x_usize > x_u64.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:86:19 + | +LL | x_usize > x_u128; + | ^^^^^^ expected `usize`, found `u128` + | +help: you can convert an `u128` to `usize` and panic if the converted value wouldn't fit + | +LL | x_usize > x_u128.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:92:16 + | +LL | x_i8 > x_i16; + | ^^^^^ expected `i8`, found `i16` + | +help: you can convert `x_i8` from `i8` to `i16`, matching the type of `x_i16` + | +LL | i16::from(x_i8) > x_i16; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:94:16 + | +LL | x_i8 > x_i32; + | ^^^^^ expected `i8`, found `i32` + | +help: you can convert `x_i8` from `i8` to `i32`, matching the type of `x_i32` + | +LL | i32::from(x_i8) > x_i32; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:96:16 + | +LL | x_i8 > x_i64; + | ^^^^^ expected `i8`, found `i64` + | +help: you can convert `x_i8` from `i8` to `i64`, matching the type of `x_i64` + | +LL | i64::from(x_i8) > x_i64; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:98:16 + | +LL | x_i8 > x_i128; + | ^^^^^^ expected `i8`, found `i128` + | +help: you can convert `x_i8` from `i8` to `i128`, matching the type of `x_i128` + | +LL | i128::from(x_i8) > x_i128; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:100:16 + | +LL | x_i8 > x_isize; + | ^^^^^^^ expected `i8`, found `isize` + | +help: you can convert `x_i8` from `i8` to `isize`, matching the type of `x_isize` + | +LL | isize::from(x_i8) > x_isize; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:103:17 + | +LL | x_i16 > x_i8; + | ^^^^ + | | + | expected `i16`, found `i8` + | help: you can convert an `i8` to `i16`: `x_i8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:105:17 + | +LL | x_i16 > x_i32; + | ^^^^^ expected `i16`, found `i32` + | +help: you can convert `x_i16` from `i16` to `i32`, matching the type of `x_i32` + | +LL | i32::from(x_i16) > x_i32; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:107:17 + | +LL | x_i16 > x_i64; + | ^^^^^ expected `i16`, found `i64` + | +help: you can convert `x_i16` from `i16` to `i64`, matching the type of `x_i64` + | +LL | i64::from(x_i16) > x_i64; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:109:17 + | +LL | x_i16 > x_i128; + | ^^^^^^ expected `i16`, found `i128` + | +help: you can convert `x_i16` from `i16` to `i128`, matching the type of `x_i128` + | +LL | i128::from(x_i16) > x_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:111:17 + | +LL | x_i16 > x_isize; + | ^^^^^^^ expected `i16`, found `isize` + | +help: you can convert `x_i16` from `i16` to `isize`, matching the type of `x_isize` + | +LL | isize::from(x_i16) > x_isize; + | ^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:114:17 + | +LL | x_i32 > x_i8; + | ^^^^ + | | + | expected `i32`, found `i8` + | help: you can convert an `i8` to `i32`: `x_i8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:116:17 + | +LL | x_i32 > x_i16; + | ^^^^^ + | | + | expected `i32`, found `i16` + | help: you can convert an `i16` to `i32`: `x_i16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:118:17 + | +LL | x_i32 > x_i64; + | ^^^^^ expected `i32`, found `i64` + | +help: you can convert `x_i32` from `i32` to `i64`, matching the type of `x_i64` + | +LL | i64::from(x_i32) > x_i64; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:120:17 + | +LL | x_i32 > x_i128; + | ^^^^^^ expected `i32`, found `i128` + | +help: you can convert `x_i32` from `i32` to `i128`, matching the type of `x_i128` + | +LL | i128::from(x_i32) > x_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:122:17 + | +LL | x_i32 > x_isize; + | ^^^^^^^ expected `i32`, found `isize` + | +help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit + | +LL | x_i32 > x_isize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:125:17 + | +LL | x_i64 > x_i8; + | ^^^^ + | | + | expected `i64`, found `i8` + | help: you can convert an `i8` to `i64`: `x_i8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:127:17 + | +LL | x_i64 > x_i16; + | ^^^^^ + | | + | expected `i64`, found `i16` + | help: you can convert an `i16` to `i64`: `x_i16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:129:17 + | +LL | x_i64 > x_i32; + | ^^^^^ + | | + | expected `i64`, found `i32` + | help: you can convert an `i32` to `i64`: `x_i32.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:131:17 + | +LL | x_i64 > x_i128; + | ^^^^^^ expected `i64`, found `i128` + | +help: you can convert `x_i64` from `i64` to `i128`, matching the type of `x_i128` + | +LL | i128::from(x_i64) > x_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:133:17 + | +LL | x_i64 > x_isize; + | ^^^^^^^ expected `i64`, found `isize` + | +help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit + | +LL | x_i64 > x_isize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:136:18 + | +LL | x_i128 > x_i8; + | ^^^^ + | | + | expected `i128`, found `i8` + | help: you can convert an `i8` to `i128`: `x_i8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:138:18 + | +LL | x_i128 > x_i16; + | ^^^^^ + | | + | expected `i128`, found `i16` + | help: you can convert an `i16` to `i128`: `x_i16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:140:18 + | +LL | x_i128 > x_i32; + | ^^^^^ + | | + | expected `i128`, found `i32` + | help: you can convert an `i32` to `i128`: `x_i32.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:142:18 + | +LL | x_i128 > x_i64; + | ^^^^^ + | | + | expected `i128`, found `i64` + | help: you can convert an `i64` to `i128`: `x_i64.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:144:18 + | +LL | x_i128 > x_isize; + | ^^^^^^^ expected `i128`, found `isize` + | +help: you can convert an `isize` to `i128` and panic if the converted value wouldn't fit + | +LL | x_i128 > x_isize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:147:19 + | +LL | x_isize > x_i8; + | ^^^^ + | | + | expected `isize`, found `i8` + | help: you can convert an `i8` to `isize`: `x_i8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:149:19 + | +LL | x_isize > x_i16; + | ^^^^^ + | | + | expected `isize`, found `i16` + | help: you can convert an `i16` to `isize`: `x_i16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:151:19 + | +LL | x_isize > x_i32; + | ^^^^^ expected `isize`, found `i32` + | +help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit + | +LL | x_isize > x_i32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:153:19 + | +LL | x_isize > x_i64; + | ^^^^^ expected `isize`, found `i64` + | +help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit + | +LL | x_isize > x_i64.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:155:19 + | +LL | x_isize > x_i128; + | ^^^^^^ expected `isize`, found `i128` + | +help: you can convert an `i128` to `isize` and panic if the converted value wouldn't fit + | +LL | x_isize > x_i128.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:161:16 + | +LL | x_u8 > x_i8; + | ^^^^ expected `u8`, found `i8` + | +help: you can convert an `i8` to `u8` and panic if the converted value wouldn't fit + | +LL | x_u8 > x_i8.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:163:16 + | +LL | x_u8 > x_i16; + | ^^^^^ expected `u8`, found `i16` + | +help: you can convert `x_u8` from `u8` to `i16`, matching the type of `x_i16` + | +LL | i16::from(x_u8) > x_i16; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:165:16 + | +LL | x_u8 > x_i32; + | ^^^^^ expected `u8`, found `i32` + | +help: you can convert `x_u8` from `u8` to `i32`, matching the type of `x_i32` + | +LL | i32::from(x_u8) > x_i32; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:167:16 + | +LL | x_u8 > x_i64; + | ^^^^^ expected `u8`, found `i64` + | +help: you can convert `x_u8` from `u8` to `i64`, matching the type of `x_i64` + | +LL | i64::from(x_u8) > x_i64; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:169:16 + | +LL | x_u8 > x_i128; + | ^^^^^^ expected `u8`, found `i128` + | +help: you can convert `x_u8` from `u8` to `i128`, matching the type of `x_i128` + | +LL | i128::from(x_u8) > x_i128; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:171:16 + | +LL | x_u8 > x_isize; + | ^^^^^^^ expected `u8`, found `isize` + | +help: you can convert `x_u8` from `u8` to `isize`, matching the type of `x_isize` + | +LL | isize::from(x_u8) > x_isize; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:174:17 + | +LL | x_u16 > x_i8; + | ^^^^ expected `u16`, found `i8` + | +help: you can convert an `i8` to `u16` and panic if the converted value wouldn't fit + | +LL | x_u16 > x_i8.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:176:17 + | +LL | x_u16 > x_i16; + | ^^^^^ expected `u16`, found `i16` + | +help: you can convert an `i16` to `u16` and panic if the converted value wouldn't fit + | +LL | x_u16 > x_i16.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:178:17 + | +LL | x_u16 > x_i32; + | ^^^^^ expected `u16`, found `i32` + | +help: you can convert `x_u16` from `u16` to `i32`, matching the type of `x_i32` + | +LL | i32::from(x_u16) > x_i32; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:180:17 + | +LL | x_u16 > x_i64; + | ^^^^^ expected `u16`, found `i64` + | +help: you can convert `x_u16` from `u16` to `i64`, matching the type of `x_i64` + | +LL | i64::from(x_u16) > x_i64; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:182:17 + | +LL | x_u16 > x_i128; + | ^^^^^^ expected `u16`, found `i128` + | +help: you can convert `x_u16` from `u16` to `i128`, matching the type of `x_i128` + | +LL | i128::from(x_u16) > x_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:184:17 + | +LL | x_u16 > x_isize; + | ^^^^^^^ expected `u16`, found `isize` + | +help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit + | +LL | x_u16 > x_isize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:187:17 + | +LL | x_u32 > x_i8; + | ^^^^ expected `u32`, found `i8` + | +help: you can convert an `i8` to `u32` and panic if the converted value wouldn't fit + | +LL | x_u32 > x_i8.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:189:17 + | +LL | x_u32 > x_i16; + | ^^^^^ expected `u32`, found `i16` + | +help: you can convert an `i16` to `u32` and panic if the converted value wouldn't fit + | +LL | x_u32 > x_i16.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:191:17 + | +LL | x_u32 > x_i32; + | ^^^^^ expected `u32`, found `i32` + | +help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit + | +LL | x_u32 > x_i32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:193:17 + | +LL | x_u32 > x_i64; + | ^^^^^ expected `u32`, found `i64` + | +help: you can convert `x_u32` from `u32` to `i64`, matching the type of `x_i64` + | +LL | i64::from(x_u32) > x_i64; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:195:17 + | +LL | x_u32 > x_i128; + | ^^^^^^ expected `u32`, found `i128` + | +help: you can convert `x_u32` from `u32` to `i128`, matching the type of `x_i128` + | +LL | i128::from(x_u32) > x_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:197:17 + | +LL | x_u32 > x_isize; + | ^^^^^^^ expected `u32`, found `isize` + | +help: you can convert an `isize` to `u32` and panic if the converted value wouldn't fit + | +LL | x_u32 > x_isize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:200:17 + | +LL | x_u64 > x_i8; + | ^^^^ expected `u64`, found `i8` + | +help: you can convert an `i8` to `u64` and panic if the converted value wouldn't fit + | +LL | x_u64 > x_i8.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:202:17 + | +LL | x_u64 > x_i16; + | ^^^^^ expected `u64`, found `i16` + | +help: you can convert an `i16` to `u64` and panic if the converted value wouldn't fit + | +LL | x_u64 > x_i16.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:204:17 + | +LL | x_u64 > x_i32; + | ^^^^^ expected `u64`, found `i32` + | +help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit + | +LL | x_u64 > x_i32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:206:17 + | +LL | x_u64 > x_i64; + | ^^^^^ expected `u64`, found `i64` + | +help: you can convert an `i64` to `u64` and panic if the converted value wouldn't fit + | +LL | x_u64 > x_i64.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:208:17 + | +LL | x_u64 > x_i128; + | ^^^^^^ expected `u64`, found `i128` + | +help: you can convert `x_u64` from `u64` to `i128`, matching the type of `x_i128` + | +LL | i128::from(x_u64) > x_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:210:17 + | +LL | x_u64 > x_isize; + | ^^^^^^^ expected `u64`, found `isize` + | +help: you can convert an `isize` to `u64` and panic if the converted value wouldn't fit + | +LL | x_u64 > x_isize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:213:18 + | +LL | x_u128 > x_i8; + | ^^^^ expected `u128`, found `i8` + | +help: you can convert an `i8` to `u128` and panic if the converted value wouldn't fit + | +LL | x_u128 > x_i8.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:215:18 + | +LL | x_u128 > x_i16; + | ^^^^^ expected `u128`, found `i16` + | +help: you can convert an `i16` to `u128` and panic if the converted value wouldn't fit + | +LL | x_u128 > x_i16.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:217:18 + | +LL | x_u128 > x_i32; + | ^^^^^ expected `u128`, found `i32` + | +help: you can convert an `i32` to `u128` and panic if the converted value wouldn't fit + | +LL | x_u128 > x_i32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:219:18 + | +LL | x_u128 > x_i64; + | ^^^^^ expected `u128`, found `i64` + | +help: you can convert an `i64` to `u128` and panic if the converted value wouldn't fit + | +LL | x_u128 > x_i64.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:221:18 + | +LL | x_u128 > x_i128; + | ^^^^^^ expected `u128`, found `i128` + | +help: you can convert an `i128` to `u128` and panic if the converted value wouldn't fit + | +LL | x_u128 > x_i128.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:223:18 + | +LL | x_u128 > x_isize; + | ^^^^^^^ expected `u128`, found `isize` + | +help: you can convert an `isize` to `u128` and panic if the converted value wouldn't fit + | +LL | x_u128 > x_isize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:226:19 + | +LL | x_usize > x_i8; + | ^^^^ expected `usize`, found `i8` + | +help: you can convert an `i8` to `usize` and panic if the converted value wouldn't fit + | +LL | x_usize > x_i8.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:228:19 + | +LL | x_usize > x_i16; + | ^^^^^ expected `usize`, found `i16` + | +help: you can convert an `i16` to `usize` and panic if the converted value wouldn't fit + | +LL | x_usize > x_i16.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:230:19 + | +LL | x_usize > x_i32; + | ^^^^^ expected `usize`, found `i32` + | +help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit + | +LL | x_usize > x_i32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:232:19 + | +LL | x_usize > x_i64; + | ^^^^^ expected `usize`, found `i64` + | +help: you can convert an `i64` to `usize` and panic if the converted value wouldn't fit + | +LL | x_usize > x_i64.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:234:19 + | +LL | x_usize > x_i128; + | ^^^^^^ expected `usize`, found `i128` + | +help: you can convert an `i128` to `usize` and panic if the converted value wouldn't fit + | +LL | x_usize > x_i128.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:236:19 + | +LL | x_usize > x_isize; + | ^^^^^^^ expected `usize`, found `isize` + | +help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit + | +LL | x_usize > x_isize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:242:16 + | +LL | x_i8 > x_u8; + | ^^^^ expected `i8`, found `u8` + | +help: you can convert an `u8` to `i8` and panic if the converted value wouldn't fit + | +LL | x_i8 > x_u8.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:244:16 + | +LL | x_i8 > x_u16; + | ^^^^^ expected `i8`, found `u16` + | +help: you can convert an `u16` to `i8` and panic if the converted value wouldn't fit + | +LL | x_i8 > x_u16.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:246:16 + | +LL | x_i8 > x_u32; + | ^^^^^ expected `i8`, found `u32` + | +help: you can convert an `u32` to `i8` and panic if the converted value wouldn't fit + | +LL | x_i8 > x_u32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:248:16 + | +LL | x_i8 > x_u64; + | ^^^^^ expected `i8`, found `u64` + | +help: you can convert an `u64` to `i8` and panic if the converted value wouldn't fit + | +LL | x_i8 > x_u64.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:250:16 + | +LL | x_i8 > x_u128; + | ^^^^^^ expected `i8`, found `u128` + | +help: you can convert an `u128` to `i8` and panic if the converted value wouldn't fit + | +LL | x_i8 > x_u128.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:252:16 + | +LL | x_i8 > x_usize; + | ^^^^^^^ expected `i8`, found `usize` + | +help: you can convert an `usize` to `i8` and panic if the converted value wouldn't fit + | +LL | x_i8 > x_usize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:255:17 + | +LL | x_i16 > x_u8; + | ^^^^ + | | + | expected `i16`, found `u8` + | help: you can convert an `u8` to `i16`: `x_u8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:257:17 + | +LL | x_i16 > x_u16; + | ^^^^^ expected `i16`, found `u16` + | +help: you can convert an `u16` to `i16` and panic if the converted value wouldn't fit + | +LL | x_i16 > x_u16.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:259:17 + | +LL | x_i16 > x_u32; + | ^^^^^ expected `i16`, found `u32` + | +help: you can convert an `u32` to `i16` and panic if the converted value wouldn't fit + | +LL | x_i16 > x_u32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:261:17 + | +LL | x_i16 > x_u64; + | ^^^^^ expected `i16`, found `u64` + | +help: you can convert an `u64` to `i16` and panic if the converted value wouldn't fit + | +LL | x_i16 > x_u64.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:263:17 + | +LL | x_i16 > x_u128; + | ^^^^^^ expected `i16`, found `u128` + | +help: you can convert an `u128` to `i16` and panic if the converted value wouldn't fit + | +LL | x_i16 > x_u128.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:265:17 + | +LL | x_i16 > x_usize; + | ^^^^^^^ expected `i16`, found `usize` + | +help: you can convert an `usize` to `i16` and panic if the converted value wouldn't fit + | +LL | x_i16 > x_usize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:268:17 + | +LL | x_i32 > x_u8; + | ^^^^ + | | + | expected `i32`, found `u8` + | help: you can convert an `u8` to `i32`: `x_u8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:270:17 + | +LL | x_i32 > x_u16; + | ^^^^^ + | | + | expected `i32`, found `u16` + | help: you can convert an `u16` to `i32`: `x_u16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:272:17 + | +LL | x_i32 > x_u32; + | ^^^^^ expected `i32`, found `u32` + | +help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit + | +LL | x_i32 > x_u32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:274:17 + | +LL | x_i32 > x_u64; + | ^^^^^ expected `i32`, found `u64` + | +help: you can convert an `u64` to `i32` and panic if the converted value wouldn't fit + | +LL | x_i32 > x_u64.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:276:17 + | +LL | x_i32 > x_u128; + | ^^^^^^ expected `i32`, found `u128` + | +help: you can convert an `u128` to `i32` and panic if the converted value wouldn't fit + | +LL | x_i32 > x_u128.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:278:17 + | +LL | x_i32 > x_usize; + | ^^^^^^^ expected `i32`, found `usize` + | +help: you can convert an `usize` to `i32` and panic if the converted value wouldn't fit + | +LL | x_i32 > x_usize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:281:17 + | +LL | x_i64 > x_u8; + | ^^^^ + | | + | expected `i64`, found `u8` + | help: you can convert an `u8` to `i64`: `x_u8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:283:17 + | +LL | x_i64 > x_u16; + | ^^^^^ + | | + | expected `i64`, found `u16` + | help: you can convert an `u16` to `i64`: `x_u16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:285:17 + | +LL | x_i64 > x_u32; + | ^^^^^ + | | + | expected `i64`, found `u32` + | help: you can convert an `u32` to `i64`: `x_u32.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:287:17 + | +LL | x_i64 > x_u64; + | ^^^^^ expected `i64`, found `u64` + | +help: you can convert an `u64` to `i64` and panic if the converted value wouldn't fit + | +LL | x_i64 > x_u64.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:289:17 + | +LL | x_i64 > x_u128; + | ^^^^^^ expected `i64`, found `u128` + | +help: you can convert an `u128` to `i64` and panic if the converted value wouldn't fit + | +LL | x_i64 > x_u128.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:291:17 + | +LL | x_i64 > x_usize; + | ^^^^^^^ expected `i64`, found `usize` + | +help: you can convert an `usize` to `i64` and panic if the converted value wouldn't fit + | +LL | x_i64 > x_usize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:294:18 + | +LL | x_i128 > x_u8; + | ^^^^ + | | + | expected `i128`, found `u8` + | help: you can convert an `u8` to `i128`: `x_u8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:296:18 + | +LL | x_i128 > x_u16; + | ^^^^^ + | | + | expected `i128`, found `u16` + | help: you can convert an `u16` to `i128`: `x_u16.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:298:18 + | +LL | x_i128 > x_u32; + | ^^^^^ + | | + | expected `i128`, found `u32` + | help: you can convert an `u32` to `i128`: `x_u32.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:300:18 + | +LL | x_i128 > x_u64; + | ^^^^^ + | | + | expected `i128`, found `u64` + | help: you can convert an `u64` to `i128`: `x_u64.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:302:18 + | +LL | x_i128 > x_u128; + | ^^^^^^ expected `i128`, found `u128` + | +help: you can convert an `u128` to `i128` and panic if the converted value wouldn't fit + | +LL | x_i128 > x_u128.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:304:18 + | +LL | x_i128 > x_usize; + | ^^^^^^^ expected `i128`, found `usize` + | +help: you can convert an `usize` to `i128` and panic if the converted value wouldn't fit + | +LL | x_i128 > x_usize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:307:19 + | +LL | x_isize > x_u8; + | ^^^^ + | | + | expected `isize`, found `u8` + | help: you can convert an `u8` to `isize`: `x_u8.into()` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:309:19 + | +LL | x_isize > x_u16; + | ^^^^^ expected `isize`, found `u16` + | +help: you can convert an `u16` to `isize` and panic if the converted value wouldn't fit + | +LL | x_isize > x_u16.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:311:19 + | +LL | x_isize > x_u32; + | ^^^^^ expected `isize`, found `u32` + | +help: you can convert an `u32` to `isize` and panic if the converted value wouldn't fit + | +LL | x_isize > x_u32.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:313:19 + | +LL | x_isize > x_u64; + | ^^^^^ expected `isize`, found `u64` + | +help: you can convert an `u64` to `isize` and panic if the converted value wouldn't fit + | +LL | x_isize > x_u64.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:315:19 + | +LL | x_isize > x_u128; + | ^^^^^^ expected `isize`, found `u128` + | +help: you can convert an `u128` to `isize` and panic if the converted value wouldn't fit + | +LL | x_isize > x_u128.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-binop.rs:317:19 + | +LL | x_isize > x_usize; + | ^^^^^^^ expected `isize`, found `usize` + | +help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit + | +LL | x_isize > x_usize.try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 132 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs index c8bc4a2a8d5..31b3407a46e 100644 --- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs +++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs @@ -4,15 +4,15 @@ // We wrap patterns in a tuple because top-level or-patterns were special-cased. fn main() { match (0u8, 0u8) { - //~^ ERROR non-exhaustive patterns: `(2u8..=std::u8::MAX, _)` + //~^ ERROR non-exhaustive patterns: `(2u8..=u8::MAX, _)` (0 | 1, 2 | 3) => {} } match ((0u8,),) { - //~^ ERROR non-exhaustive patterns: `((4u8..=std::u8::MAX))` + //~^ ERROR non-exhaustive patterns: `((4u8..=u8::MAX))` ((0 | 1,) | (2 | 3,),) => {} } match (Some(0u8),) { - //~^ ERROR non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))` + //~^ ERROR non-exhaustive patterns: `(Some(2u8..=u8::MAX))` (None | Some(0 | 1),) => {} } } diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr index b45e947f3ea..653f4978ab3 100644 --- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr @@ -1,26 +1,26 @@ -error[E0004]: non-exhaustive patterns: `(2u8..=std::u8::MAX, _)` not covered +error[E0004]: non-exhaustive patterns: `(2u8..=u8::MAX, _)` not covered --> $DIR/exhaustiveness-non-exhaustive.rs:6:11 | LL | match (0u8, 0u8) { - | ^^^^^^^^^^ pattern `(2u8..=std::u8::MAX, _)` not covered + | ^^^^^^^^^^ pattern `(2u8..=u8::MAX, _)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(u8, u8)` -error[E0004]: non-exhaustive patterns: `((4u8..=std::u8::MAX))` not covered +error[E0004]: non-exhaustive patterns: `((4u8..=u8::MAX))` not covered --> $DIR/exhaustiveness-non-exhaustive.rs:10:11 | LL | match ((0u8,),) { - | ^^^^^^^^^ pattern `((4u8..=std::u8::MAX))` not covered + | ^^^^^^^^^ pattern `((4u8..=u8::MAX))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `((u8,),)` -error[E0004]: non-exhaustive patterns: `(Some(2u8..=std::u8::MAX))` not covered +error[E0004]: non-exhaustive patterns: `(Some(2u8..=u8::MAX))` not covered --> $DIR/exhaustiveness-non-exhaustive.rs:14:11 | LL | match (Some(0u8),) { - | ^^^^^^^^^^^^ pattern `(Some(2u8..=std::u8::MAX))` not covered + | ^^^^^^^^^^^^ pattern `(Some(2u8..=u8::MAX))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(std::option::Option<u8>,)` diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr index 351700a6aa5..2eadef9cb5c 100644 --- a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr +++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:4:9 | LL | let 0 | (1 | 2) = 0; - | ^^^^^^^^^^^ patterns `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered + | ^^^^^^^^^^^ patterns `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html @@ -12,11 +12,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched LL | if let 0 | (1 | 2) = 0 { /* */ } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0004]: non-exhaustive patterns: `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered +error[E0004]: non-exhaustive patterns: `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:5:11 | LL | match 0 { - | ^ patterns `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered + | ^ patterns `i32::MIN..=-1i32` and `3i32..=i32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` diff --git a/src/test/ui/parser/issue-8537.stderr b/src/test/ui/parser/issue-8537.stderr index a0793d94653..e33adb239d7 100644 --- a/src/test/ui/parser/issue-8537.stderr +++ b/src/test/ui/parser/issue-8537.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `invalid-ab_isize` LL | "invalid-ab_isize" | ^^^^^^^^^^^^^^^^^^ invalid ABI | - = help: valid ABIs: cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted + = help: valid ABIs: Rust, C, cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted error: aborting due to previous error diff --git a/src/test/ui/parser/lex-bad-char-literals-4.stderr b/src/test/ui/parser/lex-bad-char-literals-4.stderr index 8f8f806f6cf..fec4421c48a 100644 --- a/src/test/ui/parser/lex-bad-char-literals-4.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-4.stderr @@ -1,4 +1,4 @@ -error: unterminated character literal +error[E0762]: unterminated character literal --> $DIR/lex-bad-char-literals-4.rs:4:5 | LL | '● @@ -6,3 +6,4 @@ LL | '● error: aborting due to previous error +For more information about this error, try `rustc --explain E0762`. diff --git a/src/test/ui/parser/lex-bad-char-literals-7.stderr b/src/test/ui/parser/lex-bad-char-literals-7.stderr index ee9aa869352..70ee8087b51 100644 --- a/src/test/ui/parser/lex-bad-char-literals-7.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-7.stderr @@ -10,7 +10,7 @@ error: empty unicode escape (must have at least 1 hex digit) LL | let _: char = '\u{}'; | ^^^^ -error: unterminated character literal +error[E0762]: unterminated character literal --> $DIR/lex-bad-char-literals-7.rs:11:13 | LL | let _ = ' hello // here's a comment @@ -18,3 +18,4 @@ LL | let _ = ' hello // here's a comment error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0762`. diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr index edc5ece558a..6427a30b8f2 100644 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr +++ b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr @@ -10,11 +10,11 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error[E0004]: non-exhaustive patterns: `128u8..=std::u8::MAX` not covered +error[E0004]: non-exhaustive patterns: `128u8..=u8::MAX` not covered --> $DIR/exhaustive_integer_patterns.rs:28:11 | LL | match x { - | ^ pattern `128u8..=std::u8::MAX` not covered + | ^ pattern `128u8..=u8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u8` @@ -34,20 +34,20 @@ error: unreachable pattern LL | -2..=20 => {} | ^^^^^^^ -error[E0004]: non-exhaustive patterns: `std::i8::MIN..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered +error[E0004]: non-exhaustive patterns: `i8::MIN..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered --> $DIR/exhaustive_integer_patterns.rs:41:11 | LL | match x { - | ^ patterns `std::i8::MIN..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered + | ^ patterns `i8::MIN..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i8` -error[E0004]: non-exhaustive patterns: `std::i8::MIN` not covered +error[E0004]: non-exhaustive patterns: `i8::MIN` not covered --> $DIR/exhaustive_integer_patterns.rs:83:11 | LL | match 0i8 { - | ^^^ pattern `std::i8::MIN` not covered + | ^^^ pattern `i8::MIN` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i8` @@ -61,20 +61,20 @@ LL | match 0i16 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i16` -error[E0004]: non-exhaustive patterns: `128u8..=std::u8::MAX` not covered +error[E0004]: non-exhaustive patterns: `128u8..=u8::MAX` not covered --> $DIR/exhaustive_integer_patterns.rs:109:11 | LL | match 0u8 { - | ^^^ pattern `128u8..=std::u8::MAX` not covered + | ^^^ pattern `128u8..=u8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u8` -error[E0004]: non-exhaustive patterns: `(0u8, Some(_))` and `(2u8..=std::u8::MAX, Some(_))` not covered +error[E0004]: non-exhaustive patterns: `(0u8, Some(_))` and `(2u8..=u8::MAX, Some(_))` not covered --> $DIR/exhaustive_integer_patterns.rs:121:11 | LL | match (0u8, Some(())) { - | ^^^^^^^^^^^^^^^ patterns `(0u8, Some(_))` and `(2u8..=std::u8::MAX, Some(_))` not covered + | ^^^^^^^^^^^^^^^ patterns `(0u8, Some(_))` and `(2u8..=u8::MAX, Some(_))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(u8, std::option::Option<()>)` @@ -102,20 +102,20 @@ note: the lint level is defined here LL | #![deny(overlapping_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error[E0004]: non-exhaustive patterns: `std::u128::MAX` not covered +error[E0004]: non-exhaustive patterns: `u128::MAX` not covered --> $DIR/exhaustive_integer_patterns.rs:146:11 | LL | match 0u128 { - | ^^^^^ pattern `std::u128::MAX` not covered + | ^^^^^ pattern `u128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` -error[E0004]: non-exhaustive patterns: `5u128..=std::u128::MAX` not covered +error[E0004]: non-exhaustive patterns: `5u128..=u128::MAX` not covered --> $DIR/exhaustive_integer_patterns.rs:150:11 | LL | match 0u128 { - | ^^^^^ pattern `5u128..=std::u128::MAX` not covered + | ^^^^^ pattern `5u128..=u128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr index 323449eebc5..0e12b89de1b 100644 --- a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr +++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `&[0u8..=64u8, _, _, _]` and `&[66u8..=std::u8::MAX, _, _, _]` not covered +error[E0004]: non-exhaustive patterns: `&[0u8..=64u8, _, _, _]` and `&[66u8..=u8::MAX, _, _, _]` not covered --> $DIR/match-byte-array-patterns-2.rs:4:11 | LL | match buf { - | ^^^ patterns `&[0u8..=64u8, _, _, _]` and `&[66u8..=std::u8::MAX, _, _, _]` not covered + | ^^^ patterns `&[0u8..=64u8, _, _, _]` and `&[66u8..=u8::MAX, _, _, _]` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[u8; 4]` diff --git a/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr index 84cfe1da315..c6a9329f9e8 100644 --- a/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr +++ b/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `std::i32::MIN..=0i32` and `2i32..=std::i32::MAX` not covered +error[E0004]: non-exhaustive patterns: `i32::MIN..=0i32` and `2i32..=i32::MAX` not covered --> $DIR/match-non-exhaustive.rs:2:11 | LL | match 0 { 1 => () } - | ^ patterns `std::i32::MIN..=0i32` and `2i32..=std::i32::MAX` not covered + | ^ patterns `i32::MIN..=0i32` and `2i32..=i32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs index 9947989dc12..9177345bc6f 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs @@ -11,8 +11,8 @@ fn main() { match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered None => {} } - match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, std::i32::MIN..=3i32)` - // and `(_, _, 5i32..=std::i32::MAX)` not covered + match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3i32)` + // and `(_, _, 5i32..=i32::MAX)` not covered (_, _, 4) => {} } match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` not covered diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr index 436a293b6ce..3cdbd8a3433 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -36,11 +36,11 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `std::option::Option<i32>` -error[E0004]: non-exhaustive patterns: `(_, _, std::i32::MIN..=3i32)` and `(_, _, 5i32..=std::i32::MAX)` not covered +error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3i32)` and `(_, _, 5i32..=i32::MAX)` not covered --> $DIR/non-exhaustive-match.rs:14:11 | LL | match (2, 3, 4) { - | ^^^^^^^^^ patterns `(_, _, std::i32::MIN..=3i32)` and `(_, _, 5i32..=std::i32::MAX)` not covered + | ^^^^^^^^^ patterns `(_, _, i32::MIN..=3i32)` and `(_, _, 5i32..=i32::MAX)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(i32, i32, i32)` diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs b/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs index d4afe17ca74..3ef2ead32cb 100644 --- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs +++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs @@ -5,5 +5,5 @@ fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { } fn main() { let (1, (Some(1), 2..=3)) = (1, (None, 2)); - //~^ ERROR refutable pattern in local binding: `(std::i32::MIN..=0i32, _)` and `(2i32..=std::i32::MAX, _)` not covered + //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0i32, _)` and `(2i32..=i32::MAX, _)` not covered } diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr index f5895c01599..ac729ae9f7c 100644 --- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr +++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr @@ -6,11 +6,11 @@ LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { } | = note: the matched value is of type `(isize, (std::option::Option<isize>, isize))` -error[E0005]: refutable pattern in local binding: `(std::i32::MIN..=0i32, _)` and `(2i32..=std::i32::MAX, _)` not covered +error[E0005]: refutable pattern in local binding: `(i32::MIN..=0i32, _)` and `(2i32..=i32::MAX, _)` not covered --> $DIR/refutable-pattern-errors.rs:7:9 | LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)); - | ^^^^^^^^^^^^^^^^^^^^^ patterns `(std::i32::MIN..=0i32, _)` and `(2i32..=std::i32::MAX, _)` not covered + | ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0i32, _)` and `(2i32..=i32::MAX, _)` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html diff --git a/src/test/ui/precise_pointer_size_matching.stderr b/src/test/ui/precise_pointer_size_matching.stderr index 91ea323f07b..7b9e30f40fb 100644 --- a/src/test/ui/precise_pointer_size_matching.stderr +++ b/src/test/ui/precise_pointer_size_matching.stderr @@ -1,17 +1,17 @@ -error[E0004]: non-exhaustive patterns: `std::isize::MIN..=-6isize` and `21isize..=std::isize::MAX` not covered +error[E0004]: non-exhaustive patterns: `isize::MIN..=-6isize` and `21isize..=isize::MAX` not covered --> $DIR/precise_pointer_size_matching.rs:24:11 | LL | match 0isize { - | ^^^^^^ patterns `std::isize::MIN..=-6isize` and `21isize..=std::isize::MAX` not covered + | ^^^^^^ patterns `isize::MIN..=-6isize` and `21isize..=isize::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `isize` -error[E0004]: non-exhaustive patterns: `0usize` and `21usize..=std::usize::MAX` not covered +error[E0004]: non-exhaustive patterns: `0usize` and `21usize..=usize::MAX` not covered --> $DIR/precise_pointer_size_matching.rs:29:11 | LL | match 0usize { - | ^^^^^^ patterns `0usize` and `21usize..=std::usize::MAX` not covered + | ^^^^^^ patterns `0usize` and `21usize..=usize::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `usize` diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.rs b/src/test/ui/privacy/private-in-public-assoc-ty.rs index 62faae1f399..cd7c37cb04b 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.rs +++ b/src/test/ui/privacy/private-in-public-assoc-ty.rs @@ -9,7 +9,9 @@ mod m { trait PrivTr {} impl PrivTr for Priv {} pub trait PubTrAux1<T> {} - pub trait PubTrAux2 { type A; } + pub trait PubTrAux2 { + type A; + } impl<T> PubTrAux1<T> for u8 {} impl PubTrAux2 for u8 { type A = Priv; @@ -41,8 +43,9 @@ mod m { type Exist = impl PrivTr; //~^ ERROR private trait `m::PrivTr` in public interface - //~| ERROR private trait `m::PrivTr` in public interface - fn infer_exist() -> Self::Exist { Priv } + fn infer_exist() -> Self::Exist { + Priv + } } } diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.stderr b/src/test/ui/privacy/private-in-public-assoc-ty.stderr index dd2ea7481f3..1a3ca3f16ed 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.stderr +++ b/src/test/ui/privacy/private-in-public-assoc-ty.stderr @@ -1,5 +1,5 @@ error[E0446]: private type `m::Priv` in public interface - --> $DIR/private-in-public-assoc-ty.rs:15:9 + --> $DIR/private-in-public-assoc-ty.rs:17:9 | LL | struct Priv; | - `m::Priv` declared as private @@ -8,7 +8,7 @@ LL | type A = Priv; | ^^^^^^^^^^^^^^ can't leak private type warning: private trait `m::PrivTr` in public interface (error E0445) - --> $DIR/private-in-public-assoc-ty.rs:21:5 + --> $DIR/private-in-public-assoc-ty.rs:23:5 | LL | / pub trait PubTr { LL | | @@ -24,7 +24,7 @@ LL | | } = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> warning: private type `m::Priv` in public interface (error E0446) - --> $DIR/private-in-public-assoc-ty.rs:21:5 + --> $DIR/private-in-public-assoc-ty.rs:23:5 | LL | / pub trait PubTr { LL | | @@ -39,7 +39,7 @@ LL | | } = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> warning: private type `m::Priv` in public interface (error E0446) - --> $DIR/private-in-public-assoc-ty.rs:21:5 + --> $DIR/private-in-public-assoc-ty.rs:23:5 | LL | / pub trait PubTr { LL | | @@ -54,7 +54,7 @@ LL | | } = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> error[E0446]: private type `m::Priv` in public interface - --> $DIR/private-in-public-assoc-ty.rs:32:9 + --> $DIR/private-in-public-assoc-ty.rs:34:9 | LL | struct Priv; | - `m::Priv` declared as private @@ -63,7 +63,7 @@ LL | type Alias4 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `m::Priv` in public interface - --> $DIR/private-in-public-assoc-ty.rs:39:9 + --> $DIR/private-in-public-assoc-ty.rs:41:9 | LL | struct Priv; | - `m::Priv` declared as private @@ -72,7 +72,7 @@ LL | type Alias1 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0445]: private trait `m::PrivTr` in public interface - --> $DIR/private-in-public-assoc-ty.rs:42:9 + --> $DIR/private-in-public-assoc-ty.rs:44:9 | LL | trait PrivTr {} | - `m::PrivTr` declared as private @@ -80,16 +80,7 @@ LL | trait PrivTr {} LL | type Exist = impl PrivTr; | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait -error[E0445]: private trait `m::PrivTr` in public interface - --> $DIR/private-in-public-assoc-ty.rs:42:9 - | -LL | trait PrivTr {} - | - `m::PrivTr` declared as private -... -LL | type Exist = impl PrivTr; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait - -error: aborting due to 5 previous errors; 3 warnings emitted +error: aborting due to 4 previous errors; 3 warnings emitted Some errors have detailed explanations: E0445, E0446. For more information about an error, try `rustc --explain E0445`. diff --git a/src/test/ui/proc-macro/debug/dump-debug-span-debug.rs b/src/test/ui/proc-macro/debug/dump-debug-span-debug.rs new file mode 100644 index 00000000000..fd34eb974c0 --- /dev/null +++ b/src/test/ui/proc-macro/debug/dump-debug-span-debug.rs @@ -0,0 +1,41 @@ +// run-pass +// aux-build:macro-dump-debug.rs +// compile-flags: -Z span-debug + +extern crate macro_dump_debug; +use macro_dump_debug::dump_debug; + +dump_debug! { + ident // ident + r#ident // raw ident + , // alone punct + ==> // joint punct + () // empty group + [_] // nonempty group + + // unsuffixed literals + 0 + 1.0 + "S" + b"B" + r"R" + r##"R"## + br"BR" + br##"BR"## + 'C' + b'B' + + // suffixed literals + 0q + 1.0q + "S"q + b"B"q + r"R"q + r##"R"##q + br"BR"q + br##"BR"##q + 'C'q + b'B'q +} + +fn main() {} diff --git a/src/test/ui/proc-macro/debug/dump-debug-span-debug.stderr b/src/test/ui/proc-macro/debug/dump-debug-span-debug.stderr new file mode 100644 index 00000000000..2c05bdbc492 --- /dev/null +++ b/src/test/ui/proc-macro/debug/dump-debug-span-debug.stderr @@ -0,0 +1,166 @@ +TokenStream [Ident { ident: "ident", span: $DIR/dump-debug-span-debug.rs:9:5: 9:10 (#0) }, Ident { ident: "r#ident", span: $DIR/dump-debug-span-debug.rs:10:5: 10:12 (#0) }, Punct { ch: ',', spacing: Alone, span: $DIR/dump-debug-span-debug.rs:11:5: 11:6 (#0) }, Punct { ch: '=', spacing: Joint, span: $DIR/dump-debug-span-debug.rs:12:5: 12:7 (#0) }, Punct { ch: '=', spacing: Joint, span: $DIR/dump-debug-span-debug.rs:12:5: 12:7 (#0) }, Punct { ch: '>', spacing: Alone, span: $DIR/dump-debug-span-debug.rs:12:7: 12:8 (#0) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/dump-debug-span-debug.rs:13:5: 13:7 (#0) }, Group { delimiter: Bracket, stream: TokenStream [Ident { ident: "_", span: $DIR/dump-debug-span-debug.rs:14:6: 14:7 (#0) }], span: $DIR/dump-debug-span-debug.rs:14:5: 14:8 (#0) }, Literal { kind: Integer, symbol: "0", suffix: None, span: $DIR/dump-debug-span-debug.rs:17:5: 17:6 (#0) }, Literal { kind: Float, symbol: "1.0", suffix: None, span: $DIR/dump-debug-span-debug.rs:18:5: 18:8 (#0) }, Literal { kind: Str, symbol: "S", suffix: None, span: $DIR/dump-debug-span-debug.rs:19:5: 19:8 (#0) }, Literal { kind: ByteStr, symbol: "B", suffix: None, span: $DIR/dump-debug-span-debug.rs:20:5: 20:9 (#0) }, Literal { kind: StrRaw(0), symbol: "R", suffix: None, span: $DIR/dump-debug-span-debug.rs:21:5: 21:9 (#0) }, Literal { kind: StrRaw(2), symbol: "R", suffix: None, span: $DIR/dump-debug-span-debug.rs:22:5: 22:13 (#0) }, Literal { kind: ByteStrRaw(0), symbol: "BR", suffix: None, span: $DIR/dump-debug-span-debug.rs:23:5: 23:11 (#0) }, Literal { kind: ByteStrRaw(2), symbol: "BR", suffix: None, span: $DIR/dump-debug-span-debug.rs:24:5: 24:15 (#0) }, Literal { kind: Char, symbol: "C", suffix: None, span: $DIR/dump-debug-span-debug.rs:25:5: 25:8 (#0) }, Literal { kind: Byte, symbol: "B", suffix: None, span: $DIR/dump-debug-span-debug.rs:26:5: 26:9 (#0) }, Literal { kind: Integer, symbol: "0", suffix: Some("q"), span: $DIR/dump-debug-span-debug.rs:29:5: 29:7 (#0) }, Literal { kind: Float, symbol: "1.0", suffix: Some("q"), span: $DIR/dump-debug-span-debug.rs:30:5: 30:9 (#0) }, Literal { kind: Str, symbol: "S", suffix: Some("q"), span: $DIR/dump-debug-span-debug.rs:31:5: 31:9 (#0) }, Literal { kind: ByteStr, symbol: "B", suffix: Some("q"), span: $DIR/dump-debug-span-debug.rs:32:5: 32:10 (#0) }, Literal { kind: StrRaw(0), symbol: "R", suffix: Some("q"), span: $DIR/dump-debug-span-debug.rs:33:5: 33:10 (#0) }, Literal { kind: StrRaw(2), symbol: "R", suffix: Some("q"), span: $DIR/dump-debug-span-debug.rs:34:5: 34:14 (#0) }, Literal { kind: ByteStrRaw(0), symbol: "BR", suffix: Some("q"), span: $DIR/dump-debug-span-debug.rs:35:5: 35:12 (#0) }, Literal { kind: ByteStrRaw(2), symbol: "BR", suffix: Some("q"), span: $DIR/dump-debug-span-debug.rs:36:5: 36:16 (#0) }, Literal { kind: Char, symbol: "C", suffix: Some("q"), span: $DIR/dump-debug-span-debug.rs:37:5: 37:9 (#0) }, Literal { kind: Byte, symbol: "B", suffix: Some("q"), span: $DIR/dump-debug-span-debug.rs:38:5: 38:10 (#0) }] +TokenStream [ + Ident { + ident: "ident", + span: $DIR/dump-debug-span-debug.rs:9:5: 9:10 (#0), + }, + Ident { + ident: "r#ident", + span: $DIR/dump-debug-span-debug.rs:10:5: 10:12 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/dump-debug-span-debug.rs:11:5: 11:6 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/dump-debug-span-debug.rs:12:5: 12:7 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/dump-debug-span-debug.rs:12:5: 12:7 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/dump-debug-span-debug.rs:12:7: 12:8 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/dump-debug-span-debug.rs:13:5: 13:7 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "_", + span: $DIR/dump-debug-span-debug.rs:14:6: 14:7 (#0), + }, + ], + span: $DIR/dump-debug-span-debug.rs:14:5: 14:8 (#0), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: $DIR/dump-debug-span-debug.rs:17:5: 17:6 (#0), + }, + Literal { + kind: Float, + symbol: "1.0", + suffix: None, + span: $DIR/dump-debug-span-debug.rs:18:5: 18:8 (#0), + }, + Literal { + kind: Str, + symbol: "S", + suffix: None, + span: $DIR/dump-debug-span-debug.rs:19:5: 19:8 (#0), + }, + Literal { + kind: ByteStr, + symbol: "B", + suffix: None, + span: $DIR/dump-debug-span-debug.rs:20:5: 20:9 (#0), + }, + Literal { + kind: StrRaw(0), + symbol: "R", + suffix: None, + span: $DIR/dump-debug-span-debug.rs:21:5: 21:9 (#0), + }, + Literal { + kind: StrRaw(2), + symbol: "R", + suffix: None, + span: $DIR/dump-debug-span-debug.rs:22:5: 22:13 (#0), + }, + Literal { + kind: ByteStrRaw(0), + symbol: "BR", + suffix: None, + span: $DIR/dump-debug-span-debug.rs:23:5: 23:11 (#0), + }, + Literal { + kind: ByteStrRaw(2), + symbol: "BR", + suffix: None, + span: $DIR/dump-debug-span-debug.rs:24:5: 24:15 (#0), + }, + Literal { + kind: Char, + symbol: "C", + suffix: None, + span: $DIR/dump-debug-span-debug.rs:25:5: 25:8 (#0), + }, + Literal { + kind: Byte, + symbol: "B", + suffix: None, + span: $DIR/dump-debug-span-debug.rs:26:5: 26:9 (#0), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: Some("q"), + span: $DIR/dump-debug-span-debug.rs:29:5: 29:7 (#0), + }, + Literal { + kind: Float, + symbol: "1.0", + suffix: Some("q"), + span: $DIR/dump-debug-span-debug.rs:30:5: 30:9 (#0), + }, + Literal { + kind: Str, + symbol: "S", + suffix: Some("q"), + span: $DIR/dump-debug-span-debug.rs:31:5: 31:9 (#0), + }, + Literal { + kind: ByteStr, + symbol: "B", + suffix: Some("q"), + span: $DIR/dump-debug-span-debug.rs:32:5: 32:10 (#0), + }, + Literal { + kind: StrRaw(0), + symbol: "R", + suffix: Some("q"), + span: $DIR/dump-debug-span-debug.rs:33:5: 33:10 (#0), + }, + Literal { + kind: StrRaw(2), + symbol: "R", + suffix: Some("q"), + span: $DIR/dump-debug-span-debug.rs:34:5: 34:14 (#0), + }, + Literal { + kind: ByteStrRaw(0), + symbol: "BR", + suffix: Some("q"), + span: $DIR/dump-debug-span-debug.rs:35:5: 35:12 (#0), + }, + Literal { + kind: ByteStrRaw(2), + symbol: "BR", + suffix: Some("q"), + span: $DIR/dump-debug-span-debug.rs:36:5: 36:16 (#0), + }, + Literal { + kind: Char, + symbol: "C", + suffix: Some("q"), + span: $DIR/dump-debug-span-debug.rs:37:5: 37:9 (#0), + }, + Literal { + kind: Byte, + symbol: "B", + suffix: Some("q"), + span: $DIR/dump-debug-span-debug.rs:38:5: 38:10 (#0), + }, +] diff --git a/src/test/ui/proc-macro/empty-where-clause.rs b/src/test/ui/proc-macro/empty-where-clause.rs new file mode 100644 index 00000000000..719555c092a --- /dev/null +++ b/src/test/ui/proc-macro/empty-where-clause.rs @@ -0,0 +1,18 @@ +// aux-build:test-macros.rs + +extern crate test_macros; +use test_macros::recollect_attr; + +#[recollect_attr] +struct FieldStruct where { + field: MissingType1 //~ ERROR cannot find +} + +#[recollect_attr] +struct TupleStruct(MissingType2) where; //~ ERROR cannot find + +enum MyEnum where { + Variant(MissingType3) //~ ERROR cannot find +} + +fn main() {} diff --git a/src/test/ui/proc-macro/empty-where-clause.stderr b/src/test/ui/proc-macro/empty-where-clause.stderr new file mode 100644 index 00000000000..192a2b30f0d --- /dev/null +++ b/src/test/ui/proc-macro/empty-where-clause.stderr @@ -0,0 +1,21 @@ +error[E0412]: cannot find type `MissingType1` in this scope + --> $DIR/empty-where-clause.rs:8:12 + | +LL | field: MissingType1 + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `MissingType2` in this scope + --> $DIR/empty-where-clause.rs:12:20 + | +LL | struct TupleStruct(MissingType2) where; + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `MissingType3` in this scope + --> $DIR/empty-where-clause.rs:15:13 + | +LL | Variant(MissingType3) + | ^^^^^^^^^^^^ not found in this scope + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/proc-macro/mixed-site-span.stderr b/src/test/ui/proc-macro/mixed-site-span.stderr index 2b851a76f6a..6244ffc47a6 100644 --- a/src/test/ui/proc-macro/mixed-site-span.stderr +++ b/src/test/ui/proc-macro/mixed-site-span.stderr @@ -27,10 +27,6 @@ LL | pass_dollar_crate!(); | ^^^^^^^^^^^^^^^^^^^^^ not found in `$crate` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing this struct - | -LL | use ItemUse; - | error: aborting due to 4 previous errors diff --git a/src/test/ui/recursion/recursive-enum.stderr b/src/test/ui/recursion/recursive-enum.stderr index e4674b57a6d..ab4709d8e70 100644 --- a/src/test/ui/recursion/recursive-enum.stderr +++ b/src/test/ui/recursion/recursive-enum.stderr @@ -6,7 +6,10 @@ LL | enum List<T> { Cons(T, List<T>), Nil } | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `List` representable + | +LL | enum List<T> { Cons(T, Box<List<T>>), Nil } + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/recursion/recursive-static-definition.stderr b/src/test/ui/recursion/recursive-static-definition.stderr index b724c261a7c..093606e100c 100644 --- a/src/test/ui/recursion/recursive-static-definition.stderr +++ b/src/test/ui/recursion/recursive-static-definition.stderr @@ -1,8 +1,8 @@ error[E0391]: cycle detected when const-evaluating `FOO` - --> $DIR/recursive-static-definition.rs:1:23 + --> $DIR/recursive-static-definition.rs:1:1 | LL | pub static FOO: u32 = FOO; - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires const-evaluating `FOO`... --> $DIR/recursive-static-definition.rs:1:1 diff --git a/src/test/ui/repeat_count.rs b/src/test/ui/repeat_count.rs index aca7af144a9..7e30491f0bd 100644 --- a/src/test/ui/repeat_count.rs +++ b/src/test/ui/repeat_count.rs @@ -22,6 +22,9 @@ fn main() { let f = [0_usize; -1_isize]; //~^ ERROR mismatched types //~| expected `usize`, found `isize` + let f = [0; 4u8]; + //~^ ERROR mismatched types + //~| expected `usize`, found `u8` struct G { g: (), } diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr index 4a2d1d9f921..6a081e23d9d 100644 --- a/src/test/ui/repeat_count.stderr +++ b/src/test/ui/repeat_count.stderr @@ -29,7 +29,7 @@ LL | let e = [0; "foo"]; | ^^^^^ expected `usize`, found `&str` error[E0308]: mismatched types - --> $DIR/repeat_count.rs:28:17 + --> $DIR/repeat_count.rs:31:17 | LL | let g = [0; G { g: () }]; | ^^^^^^^^^^^ expected `usize`, found struct `main::G` @@ -39,24 +39,25 @@ error[E0308]: mismatched types | LL | let f = [0; -4_isize]; | ^^^^^^^^ expected `usize`, found `isize` - | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit - | -LL | let f = [0; (-4_isize).try_into().unwrap()]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/repeat_count.rs:22:23 | LL | let f = [0_usize; -1_isize]; | ^^^^^^^^ expected `usize`, found `isize` + +error[E0308]: mismatched types + --> $DIR/repeat_count.rs:25:17 + | +LL | let f = [0; 4u8]; + | ^^^ expected `usize`, found `u8` | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: change the type of the numeric literal from `u8` to `usize` | -LL | let f = [0_usize; (-1_isize).try_into().unwrap()]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let f = [0; 4usize]; + | ^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0308, E0435. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index 329543114a6..b687f0b0af0 100644 --- a/src/test/ui/resolve/issue-2356.stderr +++ b/src/test/ui/resolve/issue-2356.stderr @@ -14,7 +14,16 @@ error[E0425]: cannot find function `default` in this scope --> $DIR/issue-2356.rs:31:5 | LL | default(); - | ^^^^^^^ help: try: `Self::default` + | ^^^^^^^ + | +help: try + | +LL | Self::default(); + | ^^^^^^^^^^^^^ +help: consider importing this function + | +LL | use std::default::default; + | error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:39:5 diff --git a/src/test/ui/resolve/use_suggestion.stderr b/src/test/ui/resolve/use_suggestion.stderr index 2fd3d5dccd2..72dda940729 100644 --- a/src/test/ui/resolve/use_suggestion.stderr +++ b/src/test/ui/resolve/use_suggestion.stderr @@ -10,12 +10,10 @@ error[E0433]: failed to resolve: use of undeclared type or module `HashMap` LL | let x1 = HashMap::new(); | ^^^^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this struct | LL | use std::collections::HashMap; | -LL | use std::collections::hash_map::HashMap; - | error[E0412]: cannot find type `HashMap` in this scope --> $DIR/use_suggestion.rs:5:13 @@ -23,12 +21,10 @@ error[E0412]: cannot find type `HashMap` in this scope LL | let y1: HashMap; | ^^^^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this struct | LL | use std::collections::HashMap; | -LL | use std::collections::hash_map::HashMap; - | error[E0412]: cannot find type `GooMap` in this scope --> $DIR/use_suggestion.rs:6:13 diff --git a/src/test/ui/resolve/use_suggestion_placement.stderr b/src/test/ui/resolve/use_suggestion_placement.stderr index 9c337f515ad..3f91760fe21 100644 --- a/src/test/ui/resolve/use_suggestion_placement.stderr +++ b/src/test/ui/resolve/use_suggestion_placement.stderr @@ -26,12 +26,10 @@ error[E0412]: cannot find type `HashMap` in this scope LL | type Dict<K, V> = HashMap<K, V>; | ^^^^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing this struct | LL | use std::collections::HashMap; | -LL | use std::collections::hash_map::HashMap; - | error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2091-track-caller/call-chain.rs b/src/test/ui/rfc-2091-track-caller/call-chain.rs new file mode 100644 index 00000000000..3f1c8f7abe8 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/call-chain.rs @@ -0,0 +1,28 @@ +// run-pass + +#![feature(track_caller)] + +use std::panic::Location; + +struct Foo; + +impl Foo { + #[track_caller] + fn check_loc(&self, line: u32, col: u32) -> &Self { + let loc = Location::caller(); + assert_eq!(loc.file(), file!(), "file mismatch"); + assert_eq!(loc.line(), line, "line mismatch"); + assert_eq!(loc.column(), col, "column mismatch"); + self + } +} + +fn main() { + // Tests that when `Location::caller` is used in a method chain, + // it points to the start of the correct call (the first character after the dot) + // instead of to the very first expression in the chain + let foo = Foo; + foo. + check_loc(line!(), 9).check_loc(line!(), 31) + .check_loc(line!(), 10); +} diff --git a/src/test/ui/save-analysis/issue-68621.stderr b/src/test/ui/save-analysis/issue-68621.stderr index 2c5bbd7782b..3af6d0a3e07 100644 --- a/src/test/ui/save-analysis/issue-68621.stderr +++ b/src/test/ui/save-analysis/issue-68621.stderr @@ -1,8 +1,8 @@ error: could not find defining uses - --> $DIR/issue-68621.rs:14:5 + --> $DIR/issue-68621.rs:14:19 | LL | type Future = impl Trait; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/save-analysis/issue-73020.rs b/src/test/ui/save-analysis/issue-73020.rs new file mode 100644 index 00000000000..87ce0933681 --- /dev/null +++ b/src/test/ui/save-analysis/issue-73020.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zsave-analysis +use {self}; //~ ERROR E0431 + +fn main () { +} diff --git a/src/test/ui/save-analysis/issue-73020.stderr b/src/test/ui/save-analysis/issue-73020.stderr new file mode 100644 index 00000000000..5bb3aae9997 --- /dev/null +++ b/src/test/ui/save-analysis/issue-73020.stderr @@ -0,0 +1,9 @@ +error[E0431]: `self` import can only appear in an import list with a non-empty prefix + --> $DIR/issue-73020.rs:2:6 + | +LL | use {self}; + | ^^^^ can only appear in an import list with a non-empty prefix + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0431`. diff --git a/src/test/ui/save-analysis/issue-73022.rs b/src/test/ui/save-analysis/issue-73022.rs new file mode 100644 index 00000000000..9ad89a319ba --- /dev/null +++ b/src/test/ui/save-analysis/issue-73022.rs @@ -0,0 +1,13 @@ +// build-pass +// compile-flags: -Zsave-analysis +enum Enum2 { + Variant8 { _field: bool }, +} + +impl Enum2 { + fn new_variant8() -> Enum2 { + Self::Variant8 { _field: true } + } +} + +fn main() {} diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs index e664ecadda2..b7b3ec99781 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs @@ -20,7 +20,7 @@ extern "platform-intrinsic" { fn main() { // unsigned { - const M: u32 = u32::max_value(); + const M: u32 = u32::MAX; let a = u32x4(1, 2, 3, 4); let b = u32x4(2, 4, 6, 8); @@ -48,8 +48,8 @@ fn main() { // signed { - const MIN: i32 = i32::min_value(); - const MAX: i32 = i32::max_value(); + const MIN: i32 = i32::MIN; + const MAX: i32 = i32::MAX; let a = i32x4(1, 2, 3, 4); let b = i32x4(2, 4, 6, 8); diff --git a/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs b/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs index b28f742a92e..a323bd9e82b 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs @@ -39,7 +39,7 @@ fn main() { let e = 0b_1101; // Check usize / isize - let msize: Tx4<usize> = Tx4(usize::max_value(), 0, usize::max_value(), usize::max_value()); + let msize: Tx4<usize> = Tx4(usize::MAX, 0, usize::MAX, usize::MAX); unsafe { let r: u8 = simd_bitmask(z); diff --git a/src/test/ui/simd/simd-intrinsic-generic-reduction.rs b/src/test/ui/simd/simd-intrinsic-generic-reduction.rs index 4195444a73f..8b5afeac0bc 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-reduction.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-reduction.rs @@ -100,7 +100,7 @@ fn main() { let r: u32 = simd_reduce_max(x); assert_eq!(r, 4_u32); - let t = u32::max_value(); + let t = u32::MAX; let x = u32x4(t, t, t, t); let r: u32 = simd_reduce_and(x); assert_eq!(r, t); diff --git a/src/test/ui/sized-cycle-note.stderr b/src/test/ui/sized-cycle-note.stderr index 95bdc349426..45062c2ea6c 100644 --- a/src/test/ui/sized-cycle-note.stderr +++ b/src/test/ui/sized-cycle-note.stderr @@ -2,21 +2,27 @@ error[E0072]: recursive type `Baz` has infinite size --> $DIR/sized-cycle-note.rs:9:1 | LL | struct Baz { q: Option<Foo> } - | ^^^^^^^^^^ -------------- recursive without indirection + | ^^^^^^^^^^ ----------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Baz` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable + | +LL | struct Baz { q: Box<Option<Foo>> } + | ^^^^ ^ error[E0072]: recursive type `Foo` has infinite size --> $DIR/sized-cycle-note.rs:11:1 | LL | struct Foo { q: Option<Baz> } - | ^^^^^^^^^^ -------------- recursive without indirection + | ^^^^^^^^^^ ----------- recursive without indirection | | | recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable + | +LL | struct Foo { q: Box<Option<Baz>> } + | ^^^^ ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr index d4a5e7400d2..06493f05142 100644 --- a/src/test/ui/span/E0072.stderr +++ b/src/test/ui/span/E0072.stderr @@ -5,9 +5,12 @@ LL | struct ListNode { | ^^^^^^^^^^^^^^^ recursive type has infinite size LL | head: u8, LL | tail: Option<ListNode>, - | ---------------------- recursive without indirection + | ---------------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable + | +LL | tail: Box<Option<ListNode>>, + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr index dd322fe833b..55128347f74 100644 --- a/src/test/ui/span/multiline-span-E0072.stderr +++ b/src/test/ui/span/multiline-span-E0072.stderr @@ -6,11 +6,14 @@ LL | | ListNode LL | | { LL | | head: u8, LL | | tail: Option<ListNode>, - | | ---------------------- recursive without indirection + | | ---------------- recursive without indirection LL | | } | |_^ recursive type has infinite size | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable + | +LL | tail: Box<Option<ListNode>>, + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/span/recursive-type-field.stderr b/src/test/ui/span/recursive-type-field.stderr index d240872647e..fb1d98b58df 100644 --- a/src/test/ui/span/recursive-type-field.stderr +++ b/src/test/ui/span/recursive-type-field.stderr @@ -4,9 +4,12 @@ error[E0072]: recursive type `Foo` has infinite size LL | struct Foo<'a> { | ^^^^^^^^^^^^^^ recursive type has infinite size LL | bar: Bar<'a>, - | ------------ recursive without indirection + | ------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable + | +LL | bar: Box<Bar<'a>>, + | ^^^^ ^ error[E0072]: recursive type `Bar` has infinite size --> $DIR/recursive-type-field.rs:8:1 @@ -14,18 +17,18 @@ error[E0072]: recursive type `Bar` has infinite size LL | struct Bar<'a> { | ^^^^^^^^^^^^^^ recursive type has infinite size LL | y: (Foo<'a>, Foo<'a>), - | --------------------- recursive without indirection + | ------------------ recursive without indirection LL | z: Option<Bar<'a>>, - | ------------------ recursive without indirection + | --------------- recursive without indirection ... LL | d: [Bar<'a>; 1], - | --------------- recursive without indirection + | ------------ recursive without indirection LL | e: Foo<'a>, - | ---------- recursive without indirection + | ------- recursive without indirection LL | x: Bar<'a>, - | ---------- recursive without indirection + | ------- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable + = help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Bar` representable error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs index 2a11871db8e..21fb8d4a2e6 100644 --- a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs +++ b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs @@ -1,6 +1,6 @@ fn main() { let A = 3; - //~^ ERROR refutable pattern in local binding: `std::i32::MIN..=1i32` and + //~^ ERROR refutable pattern in local binding: `i32::MIN..=1i32` and //~| interpreted as a constant pattern, not a new variable //~| HELP introduce a variable instead //~| SUGGESTION a_var diff --git a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr index 1512eac7667..7a6269da07f 100644 --- a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr +++ b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `std::i32::MIN..=1i32` and `3i32..=std::i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=1i32` and `3i32..=i32::MAX` not covered --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9 | LL | let A = 3; diff --git a/src/test/ui/symbol-names/basic.legacy.stderr b/src/test/ui/symbol-names/basic.legacy.stderr index 895ff5ae54f..dec57e06ea2 100644 --- a/src/test/ui/symbol-names/basic.legacy.stderr +++ b/src/test/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17h81759b0695851718E) +error: symbol-name(_ZN5basic4main17h4272b3de5e868f5aE) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::h81759b0695851718) +error: demangling(basic::main::h4272b3de5e868f5a) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr index 33cacaf2128..52ee3452a48 100644 --- a/src/test/ui/symbol-names/impl1.legacy.stderr +++ b/src/test/ui/symbol-names/impl1.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5impl13foo3Foo3bar17h92cf46db76791039E) +error: symbol-name(_ZN5impl13foo3Foo3bar17ha318160f105e638cE) --> $DIR/impl1.rs:16:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(impl1::foo::Foo::bar::h92cf46db76791039) +error: demangling(impl1::foo::Foo::bar::ha318160f105e638c) --> $DIR/impl1.rs:16:9 | LL | #[rustc_symbol_name] @@ -22,13 +22,13 @@ error: def-path(foo::Foo::bar) LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h90c4a800b1aa0df0E) +error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h6c2dbab6e66f9fa3E) --> $DIR/impl1.rs:34:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::h90c4a800b1aa0df0) +error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::h6c2dbab6e66f9fa3) --> $DIR/impl1.rs:34:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index cdcf89e4e61..380d20d0b12 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -3,8 +3,8 @@ // revisions: legacy v0 //[legacy]compile-flags: -Z symbol-mangling-version=legacy //[v0]compile-flags: -Z symbol-mangling-version=v0 -//[legacy]normalize-stderr-32bit: "h5ef5dfc14aeecbfc" -> "SYMBOL_HASH" -//[legacy]normalize-stderr-64bit: "h9e54d216f70fcbc5" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-32bit: "hee444285569b39c2" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-64bit: "h310ea0259fc3d32d" -> "SYMBOL_HASH" #![feature(optin_builtin_traits, rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr index 0e3a34adbc7..f5699052795 100644 --- a/src/test/ui/symbol-names/issue-60925.legacy.stderr +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hc86312d25b60f6eeE) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h79d9aaa05f4b26d6E) --> $DIR/issue-60925.rs:22:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hc86312d25b60f6ee) +error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h79d9aaa05f4b26d6) --> $DIR/issue-60925.rs:22:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr index b871f79aa1d..9ebf63468e7 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `T: TraitWithAssoc` is not satisfied - --> $DIR/bound_reduction2.rs:10:1 + --> $DIR/bound_reduction2.rs:10:15 | LL | type Foo<V> = impl Trait<V>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitWithAssoc` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `TraitWithAssoc` is not implemented for `T` | help: consider further restricting this bound | diff --git a/src/test/ui/type-alias-impl-trait/declared_but_never_defined.stderr b/src/test/ui/type-alias-impl-trait/declared_but_never_defined.stderr index ae0fee4333b..21c2e8a9db6 100644 --- a/src/test/ui/type-alias-impl-trait/declared_but_never_defined.stderr +++ b/src/test/ui/type-alias-impl-trait/declared_but_never_defined.stderr @@ -1,8 +1,8 @@ error: could not find defining uses - --> $DIR/declared_but_never_defined.rs:6:1 + --> $DIR/declared_but_never_defined.rs:6:12 | LL | type Bar = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr index 0642407aba3..c0cb94b15d0 100644 --- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr +++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr @@ -1,8 +1,8 @@ error: could not find defining uses - --> $DIR/declared_but_not_defined_in_scope.rs:7:5 + --> $DIR/declared_but_not_defined_in_scope.rs:7:20 | LL | pub type Boo = impl ::std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr index 9549074d4bf..76654d7a718 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr @@ -13,10 +13,10 @@ LL | let z: i32 = x; | expected due to this ... LL | type WrongGeneric<T> = impl 'static; - | ------------------------------------ the found opaque type + | ------------ the found opaque type | = note: expected type `i32` - found opaque type `WrongGeneric::<&{integer}>` + found opaque type `impl Sized` error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index e2540e424cb..18d8daa05e6 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -13,16 +13,16 @@ LL | let z: i32 = x; | expected due to this ... LL | type WrongGeneric<T> = impl 'static; - | ------------------------------------ the found opaque type + | ------------ the found opaque type | = note: expected type `i32` - found opaque type `WrongGeneric::<&{integer}>` + found opaque type `impl Sized` error[E0310]: the parameter type `T` may not live long enough - --> $DIR/generic_type_does_not_live_long_enough.rs:9:1 + --> $DIR/generic_type_does_not_live_long_enough.rs:9:24 | LL | type WrongGeneric<T> = impl 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds ... LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> { | - help: consider adding an explicit lifetime bound...: `T: 'static` diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr index f7a04263259..911f592f73f 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr @@ -5,10 +5,10 @@ LL | type Underconstrained<T: Trait> = impl 'static; | ^^^^^^^^^^^^ error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/generic_underconstrained.rs:6:1 + --> $DIR/generic_underconstrained.rs:6:35 | LL | type Underconstrained<T: Trait> = impl 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | ^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` | = note: the return type of a function must have a statically known size help: consider restricting type parameter `T` diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr index ad160abcbd5..247d68ef2a1 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -11,10 +11,10 @@ LL | type Underconstrained2<T: std::fmt::Debug> = impl 'static; | ^^^^^^^^^^^^ error[E0277]: `U` doesn't implement `std::fmt::Debug` - --> $DIR/generic_underconstrained2.rs:5:1 + --> $DIR/generic_underconstrained2.rs:5:45 | LL | type Underconstrained<T: std::fmt::Debug> = impl 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` ... LL | 5u32 | ---- this returned value is of type `u32` @@ -27,10 +27,10 @@ LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> { | ^^^^^^^^^^^^^^^^^ error[E0277]: `V` doesn't implement `std::fmt::Debug` - --> $DIR/generic_underconstrained2.rs:14:1 + --> $DIR/generic_underconstrained2.rs:14:46 | LL | type Underconstrained2<T: std::fmt::Debug> = impl 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` ... LL | 5u32 | ---- this returned value is of type `u32` diff --git a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs new file mode 100644 index 00000000000..bc6543a9229 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs @@ -0,0 +1,18 @@ +// Ensure that we don't ICE if associated type impl trait is used in an impl +// with an unconstrained type parameter. + +#![feature(type_alias_impl_trait)] + +trait X { + type I; + fn f() -> Self::I; +} + +impl<T> X for () { + type I = impl Sized; + //~^ ERROR could not find defining uses + fn f() -> Self::I {} + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr new file mode 100644 index 00000000000..e8b677113db --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr @@ -0,0 +1,15 @@ +error[E0282]: type annotations needed + --> $DIR/impl-with-unconstrained-param.rs:14:23 + | +LL | fn f() -> Self::I {} + | ^^ cannot infer type for type parameter `T` + +error: could not find defining uses + --> $DIR/impl-with-unconstrained-param.rs:12:14 + | +LL | type I = impl Sized; + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs b/src/test/ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs new file mode 100644 index 00000000000..3a7a5da075f --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs @@ -0,0 +1,24 @@ +// Regression test for #57188 + +// check-pass + +#![feature(type_alias_impl_trait)] + +struct Baz<'a> { + source: &'a str, +} + +trait Foo<'a> { + type T: Iterator<Item = Baz<'a>> + 'a; + fn foo(source: &'a str) -> Self::T; +} + +struct Bar; +impl<'a> Foo<'a> for Bar { + type T = impl Iterator<Item = Baz<'a>> + 'a; + fn foo(source: &'a str) -> Self::T { + std::iter::once(Baz { source }) + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr index f648b7bfc99..cc121ac89fb 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr @@ -1,8 +1,8 @@ error[E0631]: type mismatch in closure arguments - --> $DIR/issue-57611-trait-alias.rs:17:5 + --> $DIR/issue-57611-trait-alias.rs:17:16 | LL | type Bar = impl Baz<Self, Self>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r X) -> _` + | ^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r X) -> _` ... LL | |x| x | ----- found signature of `fn(_) -> _` @@ -10,10 +10,10 @@ LL | |x| x = note: the return type of a function must have a statically known size error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-57611-trait-alias.rs:21:9: 21:14] as std::ops::FnOnce<(&'r X,)>>::Output == &'r X` - --> $DIR/issue-57611-trait-alias.rs:17:5 + --> $DIR/issue-57611-trait-alias.rs:17:16 | LL | type Bar = impl Baz<Self, Self>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime + | ^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime | = note: the return type of a function must have a statically known size diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr index 2796c77baa1..bf2d612fcdb 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr @@ -8,20 +8,20 @@ LL | type Item = impl Bug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0277]: the trait bound `(): Bug` is not satisfied - --> $DIR/issue-60371.rs:8:5 + --> $DIR/issue-60371.rs:8:17 | LL | type Item = impl Bug; - | ^^^^^^^^^^^^^^^^^^^^^ the trait `Bug` is not implemented for `()` + | ^^^^^^^^ the trait `Bug` is not implemented for `()` | = help: the following implementations were found: <&() as Bug> = note: the return type of a function must have a statically known size error: could not find defining uses - --> $DIR/issue-60371.rs:8:5 + --> $DIR/issue-60371.rs:8:17 | LL | type Item = impl Bug; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs index 4eb7f7836d8..78def0d1136 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs @@ -17,11 +17,8 @@ where { type BitsIter = IterBitsIter<T, E, u8>; fn iter_bits(self, n: u8) -> Self::BitsIter { - //~^ ERROR non-defining opaque type use in defining scope - //~| ERROR non-defining opaque type use in defining scope - (0u8..n) - .rev() - .map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) + //~^ ERROR non-defining opaque type use in defining scope + (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap()) } } diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.stderr b/src/test/ui/type-alias-impl-trait/issue-60564.stderr index 55984609437..66fa862ef9d 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60564.stderr @@ -4,23 +4,11 @@ error: non-defining opaque type use in defining scope LL | fn iter_bits(self, n: u8) -> Self::BitsIter { | ^^^^^^^^^^^^^^ | -note: used non-generic type `_` for generic parameter - --> $DIR/issue-60564.rs:8:22 - | -LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>; - | ^ - -error: non-defining opaque type use in defining scope - --> $DIR/issue-60564.rs:19:34 - | -LL | fn iter_bits(self, n: u8) -> Self::BitsIter { - | ^^^^^^^^^^^^^^ - | note: used non-generic type `u8` for generic parameter --> $DIR/issue-60564.rs:8:25 | LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>; | ^ -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs b/src/test/ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs new file mode 100644 index 00000000000..36779a0ce89 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs @@ -0,0 +1,38 @@ +// Regression test for #62988 + +// check-pass + +#![feature(type_alias_impl_trait)] + +trait MyTrait { + type AssocType: Send; + fn ret(&self) -> Self::AssocType; +} + +impl MyTrait for () { + type AssocType = impl Send; + fn ret(&self) -> Self::AssocType { + () + } +} + +impl<'a> MyTrait for &'a () { + type AssocType = impl Send; + fn ret(&self) -> Self::AssocType { + () + } +} + +trait MyLifetimeTrait<'a> { + type AssocType: Send + 'a; + fn ret(&self) -> Self::AssocType; +} + +impl<'a> MyLifetimeTrait<'a> for &'a () { + type AssocType = impl Send + 'a; + fn ret(&self) -> Self::AssocType { + *self + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr index bef4d01093c..d07f64c3312 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr @@ -1,10 +1,10 @@ error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:8:5: 8:28] as std::ops::FnOnce<()>>::Output == ()` - --> $DIR/issue-63279.rs:5:1 + --> $DIR/issue-63279.rs:5:16 | LL | type Closure = impl FnOnce(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found `()` + | ^^^^^^^^^^^^^ expected opaque type, found `()` | - = note: expected opaque type `Closure` + = note: expected opaque type `impl std::ops::FnOnce<()>` found unit type `()` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs new file mode 100644 index 00000000000..6732902c09a --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs @@ -0,0 +1,22 @@ +// Regression test for #69136 + +#![feature(type_alias_impl_trait)] + +trait SomeTrait {} + +impl SomeTrait for () {} + +trait WithAssoc<A> { + type AssocType; +} + +impl<T> WithAssoc<T> for () { + type AssocType = (); +} + +type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>; +//~^ ERROR use of undeclared lifetime name `'a` + +fn my_fun() -> Return<()> {} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr new file mode 100644 index 00000000000..fe45e39d938 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr @@ -0,0 +1,11 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:65 + | +LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>; + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `'a,` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-ok.rs b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-ok.rs new file mode 100644 index 00000000000..a6916eda8b0 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-ok.rs @@ -0,0 +1,23 @@ +// Test-pass variant of #69136 + +// check-pass + +#![feature(type_alias_impl_trait)] + +trait SomeTrait {} + +impl SomeTrait for () {} + +trait WithAssoc { + type AssocType; +} + +impl WithAssoc for () { + type AssocType = (); +} + +type Return<'a> = impl WithAssoc<AssocType = impl Sized + 'a>; + +fn my_fun<'a>() -> Return<'a> {} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr index 70c99c944d6..4fbbf347528 100644 --- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/never_reveal_concrete_type.rs:13:27 | LL | type NoReveal = impl std::fmt::Debug; - | ------------------------------------- the found opaque type + | -------------------- the found opaque type ... LL | let _: &'static str = x; | ------------ ^ expected `&str`, found opaque type @@ -10,9 +10,9 @@ LL | let _: &'static str = x; | expected due to this | = note: expected reference `&'static str` - found opaque type `NoReveal` + found opaque type `impl std::fmt::Debug` -error[E0605]: non-primitive cast: `NoReveal` as `&'static str` +error[E0605]: non-primitive cast: `impl std::fmt::Debug` as `&'static str` --> $DIR/never_reveal_concrete_type.rs:14:13 | LL | let _ = x as &'static str; diff --git a/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr index 444e6e8214f..61025e84692 100644 --- a/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr @@ -1,8 +1,8 @@ error: could not find defining uses - --> $DIR/no_inferrable_concrete_type.rs:6:1 + --> $DIR/no_inferrable_concrete_type.rs:6:12 | LL | type Foo = impl Copy; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr index 375c0bc7fe2..d237cc6238a 100644 --- a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr +++ b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/no_revealing_outside_defining_module.rs:15:19 | LL | pub type Boo = impl ::std::fmt::Debug; - | -------------------------------------- the found opaque type + | ---------------------- the found opaque type ... LL | let _: &str = bomp(); | ---- ^^^^^^ expected `&str`, found opaque type @@ -10,20 +10,20 @@ LL | let _: &str = bomp(); | expected due to this | = note: expected reference `&str` - found opaque type `Boo` + found opaque type `impl std::fmt::Debug` error[E0308]: mismatched types --> $DIR/no_revealing_outside_defining_module.rs:19:5 | LL | pub type Boo = impl ::std::fmt::Debug; - | -------------------------------------- the expected opaque type + | ---------------------- the expected opaque type ... LL | fn bomp() -> boo::Boo { - | -------- expected `Boo` because of return type + | -------- expected `impl std::fmt::Debug` because of return type LL | "" | ^^ expected opaque type, found `&str` | - = note: expected opaque type `Boo` + = note: expected opaque type `impl std::fmt::Debug` found reference `&'static str` error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr index 02ab3399ea6..726f4ea6e00 100644 --- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr @@ -1,8 +1,8 @@ error: could not find defining uses - --> $DIR/type-alias-impl-trait-with-cycle-error.rs:3:1 + --> $DIR/type-alias-impl-trait-with-cycle-error.rs:3:12 | LL | type Foo = impl Fn() -> Foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr index e9abb795886..3947cc4d270 100644 --- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr @@ -1,8 +1,8 @@ error: could not find defining uses - --> $DIR/type-alias-impl-trait-with-cycle-error2.rs:7:1 + --> $DIR/type-alias-impl-trait-with-cycle-error2.rs:7:12 | LL | type Foo = impl Bar<Foo, Item = Foo>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/type-alias-nested-impl-trait.rs b/src/test/ui/type-alias-impl-trait/type-alias-nested-impl-trait.rs new file mode 100644 index 00000000000..fd954801dc0 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type-alias-nested-impl-trait.rs @@ -0,0 +1,14 @@ +// run-pass + +#![feature(type_alias_impl_trait)] + +use std::iter::{once, Chain}; + +type I<A> = Chain<A, impl Iterator<Item = &'static str>>; +fn test2<A: Iterator<Item = &'static str>>(x: A) -> I<A> { + x.chain(once("5")) +} + +fn main() { + assert_eq!(vec!["1", "3", "5"], test2(["1", "3"].iter().cloned()).collect::<Vec<_>>()); +} diff --git a/src/test/ui/type/type-recursive.stderr b/src/test/ui/type/type-recursive.stderr index 72bf372e561..d6d32cc5d6f 100644 --- a/src/test/ui/type/type-recursive.stderr +++ b/src/test/ui/type/type-recursive.stderr @@ -5,9 +5,12 @@ LL | struct T1 { | ^^^^^^^^^ recursive type has infinite size LL | foo: isize, LL | foolish: T1 - | ----------- recursive without indirection + | -- recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `T1` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T1` representable + | +LL | foolish: Box<T1> + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr index 746c1033ea3..c54d04de12c 100644 --- a/src/test/ui/union/union-nonrepresentable.stderr +++ b/src/test/ui/union/union-nonrepresentable.stderr @@ -5,9 +5,12 @@ LL | union U { | ^^^^^^^ recursive type has infinite size LL | a: u8, LL | b: U, - | ---- recursive without indirection + | - recursive without indirection | - = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `U` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `U` representable + | +LL | b: Box<U>, + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/unterminated-comment.rs b/src/test/ui/unterminated-comment.rs new file mode 100644 index 00000000000..1cfdfb1fb45 --- /dev/null +++ b/src/test/ui/unterminated-comment.rs @@ -0,0 +1 @@ +/* //~ ERROR E0758 diff --git a/src/test/ui/unterminated-comment.stderr b/src/test/ui/unterminated-comment.stderr new file mode 100644 index 00000000000..c513fafeeb3 --- /dev/null +++ b/src/test/ui/unterminated-comment.stderr @@ -0,0 +1,9 @@ +error[E0758]: unterminated block comment + --> $DIR/unterminated-comment.rs:1:1 + | +LL | /* + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0758`. diff --git a/src/test/ui/unterminated-doc-comment.rs b/src/test/ui/unterminated-doc-comment.rs new file mode 100644 index 00000000000..82546fe73da --- /dev/null +++ b/src/test/ui/unterminated-doc-comment.rs @@ -0,0 +1 @@ +/*! //~ ERROR E0758 diff --git a/src/test/ui/unterminated-doc-comment.stderr b/src/test/ui/unterminated-doc-comment.stderr new file mode 100644 index 00000000000..2d5e537973e --- /dev/null +++ b/src/test/ui/unterminated-doc-comment.stderr @@ -0,0 +1,9 @@ +error[E0758]: unterminated block doc-comment + --> $DIR/unterminated-doc-comment.rs:1:1 + | +LL | /*! + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0758`. diff --git a/src/test/ui/variance/variance-associated-types2.nll.stderr b/src/test/ui/variance/variance-associated-types2.nll.stderr new file mode 100644 index 00000000000..27d1e184416 --- /dev/null +++ b/src/test/ui/variance/variance-associated-types2.nll.stderr @@ -0,0 +1,12 @@ +error: lifetime may not live long enough + --> $DIR/variance-associated-types2.rs:13:12 + | +LL | fn take<'a>(_: &'a u32) { + | -- lifetime `'a` defined here +LL | let _: Box<dyn Foo<Bar = &'a u32>> = make(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | + = help: consider replacing `'a` with `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-associated-types2.rs b/src/test/ui/variance/variance-associated-types2.rs new file mode 100644 index 00000000000..6a095fce7ab --- /dev/null +++ b/src/test/ui/variance/variance-associated-types2.rs @@ -0,0 +1,17 @@ +// Test that dyn Foo<Bar = T> is invariant with respect to T. +// Failure to enforce invariance here can be weaponized, see #71550 for details. + +trait Foo { + type Bar; +} + +fn make() -> Box<dyn Foo<Bar = &'static u32>> { + panic!() +} + +fn take<'a>(_: &'a u32) { + let _: Box<dyn Foo<Bar = &'a u32>> = make(); + //~^ ERROR mismatched types [E0308] +} + +fn main() {} diff --git a/src/test/ui/variance/variance-associated-types2.stderr b/src/test/ui/variance/variance-associated-types2.stderr new file mode 100644 index 00000000000..52cdd6493b0 --- /dev/null +++ b/src/test/ui/variance/variance-associated-types2.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/variance-associated-types2.rs:13:42 + | +LL | let _: Box<dyn Foo<Bar = &'a u32>> = make(); + | ^^^^^^ lifetime mismatch + | + = note: expected trait object `dyn Foo<Bar = &'a u32>` + found trait object `dyn Foo<Bar = &'static u32>` +note: the lifetime `'a` as defined on the function body at 12:9... + --> $DIR/variance-associated-types2.rs:12:9 + | +LL | fn take<'a>(_: &'a u32) { + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/write-to-static-mut-in-static.stderr b/src/test/ui/write-to-static-mut-in-static.stderr index 6c2bd13d433..50dfce3448c 100644 --- a/src/test/ui/write-to-static-mut-in-static.stderr +++ b/src/test/ui/write-to-static-mut-in-static.stderr @@ -5,10 +5,10 @@ LL | pub static mut B: () = unsafe { A = 1; }; | ^^^^^ modifying a static's initial value from another static's initializer error[E0391]: cycle detected when const-evaluating `C` - --> $DIR/write-to-static-mut-in-static.rs:5:34 + --> $DIR/write-to-static-mut-in-static.rs:5:1 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; - | ^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: ...which requires const-evaluating `C`... --> $DIR/write-to-static-mut-in-static.rs:5:1 diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 40ebd52206e25c7a576ee42c137cc06a745a167 +Subproject 79c769c3d7b4c2cf6a93781575b7f592ef97425 diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 3958ba01246..0c80394f03e 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -232,7 +232,8 @@ jobs: matrix: integration: - 'rust-lang/cargo' - - 'rust-lang/rls' + # FIXME: re-enable once fmt_macros is renamed in RLS + # - 'rust-lang/rls' - 'rust-lang/chalk' - 'rust-lang/rustfmt' - 'Marwes/combine' diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 2ac9057199f..adc945a6944 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,88 @@ document. ## Unreleased / In Rust Nightly -[891e1a8...master](https://github.com/rust-lang/rust-clippy/compare/891e1a8...master) +[7ea7cd1...master](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master) + +## Rust 1.45 + +Current beta, release 2020-07-16 + +[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1) + +### New lints + +* [`match_wildcard_for_single_variants`] [#5582](https://github.com/rust-lang/rust-clippy/pull/5582) +* [`unsafe_derive_deserialize`] [#5493](https://github.com/rust-lang/rust-clippy/pull/5493) +* [`if_let_mutex`] [#5332](https://github.com/rust-lang/rust-clippy/pull/5332) +* [`mismatched_target_os`] [#5506](https://github.com/rust-lang/rust-clippy/pull/5506) +* [`await_holding_lock`] [#5439](https://github.com/rust-lang/rust-clippy/pull/5439) +* [`match_on_vec_items`] [#5522](https://github.com/rust-lang/rust-clippy/pull/5522) +* [`manual_async_fn`] [#5576](https://github.com/rust-lang/rust-clippy/pull/5576) +* [`reversed_empty_ranges`] [#5583](https://github.com/rust-lang/rust-clippy/pull/5583) +* [`manual_non_exhaustive`] [#5550](https://github.com/rust-lang/rust-clippy/pull/5550) + +### Moves and Deprecations + +* Downgrade [`match_bool`] to pedantic [#5408](https://github.com/rust-lang/rust-clippy/pull/5408) +* Downgrade [`match_wild_err_arm`] to pedantic and update help messages. [#5622](https://github.com/rust-lang/rust-clippy/pull/5622) +* Downgrade [`useless_let_if_seq`] to nursery. [#5599](https://github.com/rust-lang/rust-clippy/pull/5599) +* Generalize `option_and_then_some` and rename to [`bind_instead_of_map`]. [#5529](https://github.com/rust-lang/rust-clippy/pull/5529) +* Rename `identity_conversion` to [`useless_conversion`]. [#5568](https://github.com/rust-lang/rust-clippy/pull/5568) +* Merge `block_in_if_condition_expr` and `block_in_if_condition_stmt` into [`blocks_in_if_conditions`]. +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563) +* Merge `option_map_unwrap_or`, `option_map_unwrap_or_else` and `result_map_unwrap_or_else` into [`map_unwrap_or`]. +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563) +* Merge `option_unwrap_used` and `result_unwrap_used` into [`unwrap_used`]. +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563) +* Merge `option_expect_used` and `result_expect_used` into [`expect_used`]. +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563) +* Merge `for_loop_over_option` and `for_loop_over_result` into [`for_loops_over_fallibles`]. +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563) + +### Enhancements + +* Avoid running cargo lints when not enabled to improve performance. [#5505](https://github.com/rust-lang/rust-clippy/pull/5505) +* Extend [`useless_conversion`] with `TryFrom` and `TryInto`. [#5631](https://github.com/rust-lang/rust-clippy/pull/5631) +* Lint also in type parameters and where clauses in [`unused_unit`]. [#5592](https://github.com/rust-lang/rust-clippy/pull/5592) +* Do not suggest deriving `Default` in [`new_without_default`]. [#5616](https://github.com/rust-lang/rust-clippy/pull/5616) + +### False Positive Fixes + +* [`while_let_on_iterator`] [#5525](https://github.com/rust-lang/rust-clippy/pull/5525) +* [`empty_line_after_outer_attr`] [#5609](https://github.com/rust-lang/rust-clippy/pull/5609) +* [`unnecessary_unwrap`] [#5558](https://github.com/rust-lang/rust-clippy/pull/5558) +* [`comparison_chain`] [#5596](https://github.com/rust-lang/rust-clippy/pull/5596) +* Don't trigger [`used_underscore_binding`] in await desugaring. [#5535](https://github.com/rust-lang/rust-clippy/pull/5535) +* Don't trigger [`borrowed_box`] on mutable references. [#5491](https://github.com/rust-lang/rust-clippy/pull/5491) +* Allow `1 << 0` in [`identity_op`]. [#5602](https://github.com/rust-lang/rust-clippy/pull/5602) +* Allow `use super::*;` glob imports in [`wildcard_imports`]. [#5564](https://github.com/rust-lang/rust-clippy/pull/5564) +* Whitelist more words in [`doc_markdown`]. [#5611](https://github.com/rust-lang/rust-clippy/pull/5611) +* Skip dev and build deps in [`multiple_crate_versions`]. [#5636](https://github.com/rust-lang/rust-clippy/pull/5636) +* Honor `allow` attribute on arguments in [`ptr_arg`]. [#5647](https://github.com/rust-lang/rust-clippy/pull/5647) +* Honor lint level attributes for [`redundant_field_names`], [`just_underscores_and_digits`], [`many_single_char_names`] +and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/5651) +* Ignore calls to `len` in [`or_fun_call`]. [#4429](https://github.com/rust-lang/rust-clippy/pull/4429) + +### Suggestion Improvements + +* Simplify suggestions in [`manual_memcpy`]. [#5536](https://github.com/rust-lang/rust-clippy/pull/5536) +* Fix suggestion in [`redundant_pattern_matching`] for macros. [#5511](https://github.com/rust-lang/rust-clippy/pull/5511) +* Avoid suggesting `copied()` for mutable references in [`map_clone`]. [#5530](https://github.com/rust-lang/rust-clippy/pull/5530) +* Improve help message for [`clone_double_ref`]. [#5547](https://github.com/rust-lang/rust-clippy/pull/5547) + +### ICE Fixes + +* Fix ICE caused in unwrap module. [#5590](https://github.com/rust-lang/rust-clippy/pull/5590) +* Fix ICE on rustc test issue-69020-assoc-const-arith-overflow.rs [#5499](https://github.com/rust-lang/rust-clippy/pull/5499) + +### Documentation + +* Clarify the documentation of [`unnecessary_mut_passed`]. [#5639](https://github.com/rust-lang/rust-clippy/pull/5639) +* Extend example for [`unneeded_field_pattern`]. [#5541](https://github.com/rust-lang/rust-clippy/pull/5541) ## Rust 1.44 -Current beta, release 2020-06-04 +Current stable, released 2020-06-04 [204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8) @@ -93,7 +170,7 @@ Current beta, release 2020-06-04 ## Rust 1.43 -Current stable, released 2020-04-23 +Released 2020-04-23 [4ee1206...204bb9b](https://github.com/rust-lang/rust-clippy/compare/4ee1206...204bb9b) @@ -1401,6 +1478,7 @@ Released 2018-09-13 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop +[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next @@ -1601,9 +1679,11 @@ Released 2018-09-13 [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation +[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern [`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern +[`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns [`unreachable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreachable [`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal [`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize @@ -1630,6 +1710,7 @@ Released 2018-09-13 [`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute [`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec [`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box +[`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero [`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md index 0f47ac98fd2..9f7bdcb1be7 100644 --- a/src/tools/clippy/CONTRIBUTING.md +++ b/src/tools/clippy/CONTRIBUTING.md @@ -12,14 +12,16 @@ anything, feel free to ask questions on issues or visit the `#clippy` on [Discor All contributors are expected to follow the [Rust Code of Conduct]. -* [Getting started](#getting-started) - * [Finding something to fix/improve](#finding-something-to-fiximprove) -* [Writing code](#writing-code) -* [How Clippy works](#how-clippy-works) -* [Fixing nightly build failures](#fixing-build-failures-caused-by-rust) -* [Issue and PR Triage](#issue-and-pr-triage) -* [Bors and Homu](#bors-and-homu) -* [Contributions](#contributions) +- [Contributing to Clippy](#contributing-to-clippy) + - [Getting started](#getting-started) + - [Finding something to fix/improve](#finding-something-to-fiximprove) + - [Writing code](#writing-code) + - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work) + - [How Clippy works](#how-clippy-works) + - [Fixing build failures caused by Rust](#fixing-build-failures-caused-by-rust) + - [Issue and PR triage](#issue-and-pr-triage) + - [Bors and Homu](#bors-and-homu) + - [Contributions](#contributions) [Discord]: https://discord.gg/rust-lang [Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct @@ -91,6 +93,24 @@ quick read. [rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees [rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories +## Getting code-completion for rustc internals to work + +Unfortunately, [`rust-analyzer`][ra_homepage] does not (yet?) understand how Clippy uses compiler-internals +using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not +available via a `rustup` component at the time of writing. +To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via +`git clone https://github.com/rust-lang/rust/`. +Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies +which rust-analyzer will be able to understand. +Run `cargo dev ra-setup --repo-path <repo-path>` where `<repo-path>` is an absolute path to the rustc repo +you just cloned. +The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to +Clippys `Cargo.toml`s and should allow rust-analyzer to understand most of the types that Clippy uses. +Just make sure to remove the dependencies again before finally making a pull request! + +[ra_homepage]: https://rust-analyzer.github.io/ +[rustc_repo]: https://github.com/rust-lang/rust/ + ## How Clippy works [`clippy_lints/src/lib.rs`][lint_crate_entry] imports all the different lint modules and registers in the [`LintStore`]. diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 6999b6bd740..836897927b0 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -37,7 +37,7 @@ tempfile = { version = "3.1.0", optional = true } lazy_static = "1.0" [dev-dependencies] -cargo_metadata = "0.9.0" +cargo_metadata = "0.9.1" compiletest_rs = { version = "0.5.0", features = ["tmp"] } tester = "0.7" lazy_static = "1.0" diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index 6fdd282c684..5baa31d5cde 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -11,6 +11,7 @@ use walkdir::WalkDir; pub mod fmt; pub mod new_lint; +pub mod ra_setup; pub mod stderr_length_check; pub mod update_lints; @@ -400,7 +401,7 @@ fn test_replace_region_no_changes() { changed: false, new_lines: "123\n456\n789".to_string(), }; - let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, || vec![]); + let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, Vec::new); assert_eq!(expected, result); } diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index d99235f7c07..281037ae37c 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -1,7 +1,7 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] use clap::{App, Arg, SubCommand}; -use clippy_dev::{fmt, new_lint, stderr_length_check, update_lints}; +use clippy_dev::{fmt, new_lint, ra_setup, stderr_length_check, update_lints}; fn main() { let matches = App::new("Clippy developer tooling") @@ -87,6 +87,19 @@ fn main() { SubCommand::with_name("limit_stderr_length") .about("Ensures that stderr files do not grow longer than a certain amount of lines."), ) + .subcommand( + SubCommand::with_name("ra-setup") + .about("Alter dependencies so rust-analyzer can find rustc internals") + .arg( + Arg::with_name("rustc-repo-path") + .long("repo-path") + .short("r") + .help("The path to a rustc repo that will be used for setting the dependencies") + .takes_value(true) + .value_name("path") + .required(true), + ), + ) .get_matches(); match matches.subcommand() { @@ -115,6 +128,7 @@ fn main() { ("limit_stderr_length", _) => { stderr_length_check::check(); }, + ("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")), _ => {}, } } diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index c0b2dac2f60..1e032a7bc20 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -147,6 +147,8 @@ fn get_manifest_contents(lint_name: &str, hint: &str) -> String { name = "{}" version = "0.1.0" publish = false + +[workspace] "#, hint, lint_name ) diff --git a/src/tools/clippy/clippy_dev/src/ra_setup.rs b/src/tools/clippy/clippy_dev/src/ra_setup.rs new file mode 100644 index 00000000000..8617445c8a6 --- /dev/null +++ b/src/tools/clippy/clippy_dev/src/ra_setup.rs @@ -0,0 +1,90 @@ +#![allow(clippy::filter_map)] + +use std::fs; +use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; + +// This module takes an absolute path to a rustc repo and alters the dependencies to point towards +// the respective rustc subcrates instead of using extern crate xyz. +// This allows rust analyzer to analyze rustc internals and show proper information inside clippy +// code. See https://github.com/rust-analyzer/rust-analyzer/issues/3517 and https://github.com/rust-lang/rust-clippy/issues/5514 for details + +pub fn run(rustc_path: Option<&str>) { + // we can unwrap here because the arg is required here + let rustc_path = PathBuf::from(rustc_path.unwrap()); + assert!(rustc_path.is_dir(), "path is not a directory"); + let rustc_source_basedir = rustc_path.join("src"); + assert!( + rustc_source_basedir.is_dir(), + "are you sure the path leads to a rustc repo?" + ); + + let clippy_root_manifest = fs::read_to_string("Cargo.toml").expect("failed to read ./Cargo.toml"); + let clippy_root_lib_rs = fs::read_to_string("src/driver.rs").expect("failed to read ./src/driver.rs"); + inject_deps_into_manifest( + &rustc_source_basedir, + "Cargo.toml", + &clippy_root_manifest, + &clippy_root_lib_rs, + ) + .expect("Failed to inject deps into ./Cargo.toml"); + + let clippy_lints_manifest = + fs::read_to_string("clippy_lints/Cargo.toml").expect("failed to read ./clippy_lints/Cargo.toml"); + let clippy_lints_lib_rs = + fs::read_to_string("clippy_lints/src/lib.rs").expect("failed to read ./clippy_lints/src/lib.rs"); + inject_deps_into_manifest( + &rustc_source_basedir, + "clippy_lints/Cargo.toml", + &clippy_lints_manifest, + &clippy_lints_lib_rs, + ) + .expect("Failed to inject deps into ./clippy_lints/Cargo.toml"); +} + +fn inject_deps_into_manifest( + rustc_source_dir: &PathBuf, + manifest_path: &str, + cargo_toml: &str, + lib_rs: &str, +) -> std::io::Result<()> { + let extern_crates = lib_rs + .lines() + // get the deps + .filter(|line| line.starts_with("extern crate")) + // we have something like "extern crate foo;", we only care about the "foo" + // ↓ ↓ + // extern crate rustc_middle; + .map(|s| &s[13..(s.len() - 1)]); + + let new_deps = extern_crates.map(|dep| { + // format the dependencies that are going to be put inside the Cargo.toml + format!( + "{dep} = {{ path = \"{source_path}/lib{dep}\" }}\n", + dep = dep, + source_path = rustc_source_dir.display() + ) + }); + + // format a new [dependencies]-block with the new deps we need to inject + let mut all_deps = String::from("[dependencies]\n"); + new_deps.for_each(|dep_line| { + all_deps.push_str(&dep_line); + }); + + // replace "[dependencies]" with + // [dependencies] + // dep1 = { path = ... } + // dep2 = { path = ... } + // etc + let new_manifest = cargo_toml.replacen("[dependencies]\n", &all_deps, 1); + + // println!("{}", new_manifest); + let mut file = File::create(manifest_path)?; + file.write_all(new_manifest.as_bytes())?; + + println!("Dependency paths injected: {}", manifest_path); + + Ok(()) +} diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 76baf27fb2d..e959c1a6511 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -17,11 +17,11 @@ keywords = ["clippy", "lint", "plugin"] edition = "2018" [dependencies] -cargo_metadata = "0.9.0" +cargo_metadata = "0.9.1" if_chain = "1.0.0" itertools = "0.9" lazy_static = "1.0.2" -pulldown-cmark = { version = "0.7", default-features = false } +pulldown-cmark = { version = "0.7.1", default-features = false } quine-mc_cluskey = "0.2.2" regex-syntax = "0.6" serde = { version = "1.0", features = ["derive"] } diff --git a/src/tools/clippy/clippy_lints/src/assign_ops.rs b/src/tools/clippy/clippy_lints/src/assign_ops.rs index 05e2650d0b7..13e61fe98ba 100644 --- a/src/tools/clippy/clippy_lints/src/assign_ops.rs +++ b/src/tools/clippy/clippy_lints/src/assign_ops.rs @@ -24,7 +24,11 @@ declare_clippy_lint! { /// let mut a = 5; /// let b = 0; /// // ... + /// // Bad /// a = a + b; + /// + /// // Good + /// a += b; /// ``` pub ASSIGN_OP_PATTERN, style, diff --git a/src/tools/clippy/clippy_lints/src/atomic_ordering.rs b/src/tools/clippy/clippy_lints/src/atomic_ordering.rs index 73b4cef4725..fca9aaaff9d 100644 --- a/src/tools/clippy/clippy_lints/src/atomic_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/atomic_ordering.rs @@ -70,7 +70,7 @@ fn match_ordering_def_path(cx: &LateContext<'_, '_>, did: DefId, orderings: &[&s fn check_atomic_load_store(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(ref method_path, _, args) = &expr.kind; + if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind; let method = method_path.ident.name.as_str(); if type_is_atomic(cx, &args[0]); if method == "load" || method == "store"; diff --git a/src/tools/clippy/clippy_lints/src/await_holding_lock.rs b/src/tools/clippy/clippy_lints/src/await_holding_lock.rs index 832910763e6..a88f922d8e0 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_lock.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_lock.rs @@ -54,18 +54,13 @@ declare_lint_pass!(AwaitHoldingLock => [AWAIT_HOLDING_LOCK]); impl LateLintPass<'_, '_> for AwaitHoldingLock { fn check_body(&mut self, cx: &LateContext<'_, '_>, body: &'_ Body<'_>) { use AsyncGeneratorKind::{Block, Closure, Fn}; - match body.generator_kind { - Some(GeneratorKind::Async(Block)) - | Some(GeneratorKind::Async(Closure)) - | Some(GeneratorKind::Async(Fn)) => { - let body_id = BodyId { - hir_id: body.value.hir_id, - }; - let def_id = cx.tcx.hir().body_owner_def_id(body_id); - let tables = cx.tcx.typeck_tables_of(def_id); - check_interior_types(cx, &tables.generator_interior_types, body.value.span); - }, - _ => {}, + if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind { + let body_id = BodyId { + hir_id: body.value.hir_id, + }; + let def_id = cx.tcx.hir().body_owner_def_id(body_id); + let tables = cx.tcx.typeck_tables_of(def_id); + check_interior_types(cx, &tables.generator_interior_types, body.value.span); } } } diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 8031052e073..f92c564543b 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -247,7 +247,7 @@ fn simplify_not(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<String> { )) }) }, - ExprKind::MethodCall(path, _, args) if args.len() == 1 => { + ExprKind::MethodCall(path, _, args, _) if args.len() == 1 => { let type_of_receiver = cx.tables.expr_ty(&args[0]); if !is_type_diagnostic_item(cx, type_of_receiver, sym!(option_type)) && !is_type_diagnostic_item(cx, type_of_receiver, sym!(result_type)) diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs index 90c00ad098f..531531a654d 100644 --- a/src/tools/clippy/clippy_lints/src/bytecount.rs +++ b/src/tools/clippy/clippy_lints/src/bytecount.rs @@ -38,10 +38,10 @@ declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ByteCount { fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(ref count, _, ref count_args) = expr.kind; + if let ExprKind::MethodCall(ref count, _, ref count_args, _) = expr.kind; if count.ident.name == sym!(count); if count_args.len() == 1; - if let ExprKind::MethodCall(ref filter, _, ref filter_args) = count_args[0].kind; + if let ExprKind::MethodCall(ref filter, _, ref filter_args, _) = count_args[0].kind; if filter.ident.name == sym!(filter); if filter_args.len() == 2; if let ExprKind::Closure(_, _, body_id, _, _) = filter_args[1].kind; @@ -66,7 +66,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ByteCount { if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.tables.expr_ty(needle)).kind { return; } - let haystack = if let ExprKind::MethodCall(ref path, _, ref args) = + let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = filter_args[0].kind { let p = path.ident.name; if (p == sym!(iter) || p == sym!(iter_mut)) && args.len() == 1 { diff --git a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs index 16b46423c8f..c40a387d297 100644 --- a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs +++ b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs @@ -36,13 +36,9 @@ declare_clippy_lint! { "common metadata is defined in `Cargo.toml`" } -fn warning(cx: &LateContext<'_, '_>, message: &str) { - span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message); -} - fn missing_warning(cx: &LateContext<'_, '_>, package: &cargo_metadata::Package, field: &str) { let message = format!("package `{}` is missing `{}` metadata", package.name, field); - warning(cx, &message); + span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); } fn is_empty_str(value: &Option<String>) -> bool { @@ -66,12 +62,7 @@ impl LateLintPass<'_, '_> for CargoCommonMetadata { return; } - let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().no_deps().exec() { - metadata - } else { - warning(cx, "could not read cargo metadata"); - return; - }; + let metadata = unwrap_cargo_metadata!(cx, CARGO_COMMON_METADATA, false); for package in metadata.packages { if is_empty_vec(&package.authors) { diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index d9776dd50a8..88145015ba8 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -58,24 +58,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions { } }; - if_chain! { - if let Some(cv) = result; - if let Some(to_type) = cv.to_type; - - then { + if let Some(cv) = result { + if let Some(to_type) = cv.to_type { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut - applicability); + let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); span_lint_and_sugg( cx, CHECKED_CONVERSIONS, item.span, "Checked cast can be simplified.", "try", - format!("{}::try_from({}).is_ok()", - to_type, - snippet), - applicability + format!("{}::try_from({}).is_ok()", to_type, snippet), + applicability, ); } } @@ -94,7 +88,7 @@ fn double_check<'a>(cx: &LateContext<'_, '_>, left: &'a Expr<'_>, right: &'a Exp let upper = check_upper_bound(l); let lower = check_lower_bound(r); - transpose(upper, lower).and_then(|(l, r)| l.combine(r, cx)) + upper.zip(lower).and_then(|(l, r)| l.combine(r, cx)) }; upper_lower(left, right).or_else(|| upper_lower(right, left)) @@ -137,7 +131,10 @@ impl<'a> Conversion<'a> { /// Checks if the to-type is the same (if there is a type constraint) fn has_compatible_to_type(&self, other: &Self) -> bool { - transpose(self.to_type.as_ref(), other.to_type.as_ref()).map_or(true, |(l, r)| l == r) + match (self.to_type, other.to_type) { + (Some(l), Some(r)) => l == r, + _ => true, + } } /// Try to construct a new conversion if the conversion type is valid @@ -184,7 +181,7 @@ fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> { if_chain! { if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind; if let Some((candidate, check)) = normalize_le_ge(op, left, right); - if let Some((from, to)) = get_types_from_cast(check, MAX_VALUE, INTS); + if let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX"); then { Conversion::try_new(candidate, from, to) @@ -224,7 +221,7 @@ fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> O /// Check for `expr >= (to_type::MIN as from_type)` fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> { - if let Some((from, to)) = get_types_from_cast(check, MIN_VALUE, SINTS) { + if let Some((from, to)) = get_types_from_cast(check, SINTS, "min_value", "MIN") { Conversion::try_new(candidate, from, to) } else { None @@ -232,10 +229,16 @@ fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Op } /// Tries to extract the from- and to-type from a cast expression -fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str]) -> Option<(&'a str, &'a str)> { - // `to_type::maxmin_value() as from_type` +fn get_types_from_cast<'a>( + expr: &'a Expr<'_>, + types: &'a [&str], + func: &'a str, + assoc_const: &'a str, +) -> Option<(&'a str, &'a str)> { + // `to_type::max_value() as from_type` + // or `to_type::MAX as from_type` let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! { - // to_type::maxmin_value(), from_type + // to_type::max_value(), from_type if let ExprKind::Cast(ref limit, ref from_type) = &expr.kind; if let TyKind::Path(ref from_type_path) = &from_type.kind; if let Some(from_sym) = int_ty_to_sym(from_type_path); @@ -247,17 +250,17 @@ fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str]) } }; - // `from_type::from(to_type::maxmin_value())` + // `from_type::from(to_type::max_value())` let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| { if_chain! { - // `from_type::from, to_type::maxmin_value()` + // `from_type::from, to_type::max_value()` if let ExprKind::Call(ref from_func, ref args) = &expr.kind; - // `to_type::maxmin_value()` + // `to_type::max_value()` if args.len() == 1; if let limit = &args[0]; // `from_type::from` if let ExprKind::Path(ref path) = &from_func.kind; - if let Some(from_sym) = get_implementing_type(path, INTS, FROM); + if let Some(from_sym) = get_implementing_type(path, INTS, "from"); then { Some((limit, from_sym)) @@ -268,22 +271,26 @@ fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str]) }); if let Some((limit, from_type)) = limit_from { - if_chain! { - if let ExprKind::Call(ref fun_name, _) = &limit.kind; - // `to_type, maxmin_value` - if let ExprKind::Path(ref path) = &fun_name.kind; - // `to_type` - if let Some(to_type) = get_implementing_type(path, types, func); - - then { - Some((from_type, to_type)) - } else { - None - } + match limit.kind { + // `from_type::from(_)` + ExprKind::Call(path, _) => { + if let ExprKind::Path(ref path) = path.kind { + // `to_type` + if let Some(to_type) = get_implementing_type(path, types, func) { + return Some((from_type, to_type)); + } + } + }, + // `to_type::MAX` + ExprKind::Path(ref path) => { + if let Some(to_type) = get_implementing_type(path, types, assoc_const) { + return Some((from_type, to_type)); + } + }, + _ => {}, } - } else { - None - } + }; + None } /// Gets the type which implements the called function @@ -318,14 +325,6 @@ fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> { } } -/// (Option<T>, Option<U>) -> Option<(T, U)> -fn transpose<T, U>(lhs: Option<T>, rhs: Option<U>) -> Option<(T, U)> { - match (lhs, rhs) { - (Some(l), Some(r)) => Some((l, r)), - _ => None, - } -} - /// Will return the expressions as if they were expr1 <= expr2 fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { match op.node { @@ -336,10 +335,6 @@ fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> O } // Constants -const FROM: &str = "from"; -const MAX_VALUE: &str = "max_value"; -const MIN_VALUE: &str = "min_value"; - const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"]; const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"]; const INTS: &[&str] = &["u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize"]; diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs index 81ddc8c0067..22c5acca064 100644 --- a/src/tools/clippy/clippy_lints/src/consts.rs +++ b/src/tools/clippy/clippy_lints/src/consts.rs @@ -254,11 +254,11 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { if let ["core", "num", int_impl, "max_value"] = *def_path; then { let value = match int_impl { - "<impl i8>" => i8::max_value() as u128, - "<impl i16>" => i16::max_value() as u128, - "<impl i32>" => i32::max_value() as u128, - "<impl i64>" => i64::max_value() as u128, - "<impl i128>" => i128::max_value() as u128, + "<impl i8>" => i8::MAX as u128, + "<impl i16>" => i16::MAX as u128, + "<impl i32>" => i32::MAX as u128, + "<impl i64>" => i64::MAX as u128, + "<impl i128>" => i128::MAX as u128, _ => return None, }; Some(Constant::Int(value)) diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 66722786eab..b6d50bdfa14 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -1,9 +1,9 @@ -use crate::utils::{get_parent_expr, higher, if_sequence, same_tys, snippet, span_lint_and_note, span_lint_and_then}; +use crate::utils::{get_parent_expr, higher, if_sequence, snippet, span_lint_and_note, span_lint_and_then}; use crate::utils::{SpanlessEq, SpanlessHash}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Arm, Block, Expr, ExprKind, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{Ty, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Symbol; use std::collections::hash_map::Entry; @@ -242,15 +242,11 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) { /// Implementation of `MATCH_SAME_ARMS`. fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr<'_>) { - fn same_bindings<'tcx>( - cx: &LateContext<'_, 'tcx>, - lhs: &FxHashMap<Symbol, Ty<'tcx>>, - rhs: &FxHashMap<Symbol, Ty<'tcx>>, - ) -> bool { + fn same_bindings<'tcx>(lhs: &FxHashMap<Symbol, Ty<'tcx>>, rhs: &FxHashMap<Symbol, Ty<'tcx>>) -> bool { lhs.len() == rhs.len() && lhs .iter() - .all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| same_tys(cx, l_ty, r_ty))) + .all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| TyS::same_type(l_ty, r_ty))) } if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind { @@ -269,7 +265,7 @@ fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr<'_>) { (min_index..=max_index).all(|index| arms[index].guard.is_none()) && SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) && // all patterns should have the same bindings - same_bindings(cx, &bindings(cx, &lhs.pat), &bindings(cx, &rhs.pat)) + same_bindings(&bindings(cx, &lhs.pat), &bindings(cx, &rhs.pat)) }; let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect(); diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 68ec07e2bcb..1cd30ae2c63 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if_chain! { if !expr.span.from_expansion(); - if let ExprKind::MethodCall(ref method_name, _, ref args) = &expr.kind; + if let ExprKind::MethodCall(ref method_name, _, ref args, _) = &expr.kind; if args.len() == 1; then { diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs index 7f2ff8b9b26..1eb380a22cc 100644 --- a/src/tools/clippy/clippy_lints/src/double_parens.rs +++ b/src/tools/clippy/clippy_lints/src/double_parens.rs @@ -13,10 +13,24 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad + /// fn simple_double_parens() -> i32 { + /// ((0)) + /// } + /// + /// // Good + /// fn simple_no_parens() -> i32 { + /// 0 + /// } + /// + /// // or + /// /// # fn foo(bar: usize) {} - /// ((0)); + /// // Bad /// foo((0)); - /// ((1, 2)); + /// + /// // Good + /// foo(0); /// ``` pub DOUBLE_PARENS, complexity, @@ -56,7 +70,7 @@ impl EarlyLintPass for DoubleParens { } } }, - ExprKind::MethodCall(_, ref params) => { + ExprKind::MethodCall(_, ref params, _) => { if params.len() == 2 { let param = ¶ms[1]; if let ExprKind::Paren(_) = param.kind { diff --git a/src/tools/clippy/clippy_lints/src/drop_bounds.rs b/src/tools/clippy/clippy_lints/src/drop_bounds.rs index f4966808279..5a7f759486e 100644 --- a/src/tools/clippy/clippy_lints/src/drop_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/drop_bounds.rs @@ -27,6 +27,10 @@ declare_clippy_lint! { /// ```rust /// fn foo<T: Drop>() {} /// ``` + /// Could be written as: + /// ```rust + /// fn foo<T>() {} + /// ``` pub DROP_BOUNDS, correctness, "Bounds of the form `T: Drop` are useless" diff --git a/src/tools/clippy/clippy_lints/src/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/duration_subsec.rs index b35a8facf8b..7171dcef968 100644 --- a/src/tools/clippy/clippy_lints/src/duration_subsec.rs +++ b/src/tools/clippy/clippy_lints/src/duration_subsec.rs @@ -22,8 +22,14 @@ declare_clippy_lint! { /// ```rust /// # use std::time::Duration; /// let dur = Duration::new(5, 0); + /// + /// // Bad /// let _micros = dur.subsec_nanos() / 1_000; /// let _millis = dur.subsec_nanos() / 1_000_000; + /// + /// // Good + /// let _micros = dur.subsec_micros(); + /// let _millis = dur.subsec_millis(); /// ``` pub DURATION_SUBSEC, complexity, @@ -36,7 +42,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DurationSubsec { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.kind; - if let ExprKind::MethodCall(ref method_path, _ , ref args) = left.kind; + if let ExprKind::MethodCall(ref method_path, _ , ref args, _) = left.kind; if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(&args[0])), &paths::DURATION); if let Some((Constant::Int(divisor), _)) = constant(cx, cx.tables, right); then { diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 7b332c761a0..f625058b670 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -103,7 +103,7 @@ fn check_cond<'a, 'tcx, 'b>( check: &'b Expr<'b>, ) -> Option<(&'static str, &'b Expr<'b>, &'b Expr<'b>)> { if_chain! { - if let ExprKind::MethodCall(ref path, _, ref params) = check.kind; + if let ExprKind::MethodCall(ref path, _, ref params, _) = check.kind; if params.len() >= 2; if path.ident.name == sym!(contains_key); if let ExprKind::AddrOf(BorrowKind::Ref, _, ref key) = params[1].kind; @@ -140,7 +140,7 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for InsertVisitor<'a, 'tcx, 'b> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(ref path, _, ref params) = expr.kind; + if let ExprKind::MethodCall(ref path, _, ref params, _) = expr.kind; if params.len() == 3; if path.ident.name == sym!(insert); if get_item_name(self.cx, self.map) == get_item_name(self.cx, ¶ms[0]); diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index a1fed3fb6e2..12b62f5cf97 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -65,7 +65,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant { continue; } }, - ty::Uint(UintTy::Usize) if val > u128::from(u32::max_value()) => {}, + ty::Uint(UintTy::Usize) if val > u128::from(u32::MAX) => {}, _ => continue, } span_lint( diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index a5871cf0cd4..cb0fd59a2d4 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -25,31 +25,47 @@ declare_clippy_lint! { /// BattenbergCake, /// } /// ``` + /// Could be written as: + /// ```rust + /// enum Cake { + /// BlackForest, + /// Hummingbird, + /// Battenberg, + /// } + /// ``` pub ENUM_VARIANT_NAMES, style, "enums where all variants share a prefix/postfix" } declare_clippy_lint! { - /// **What it does:** Detects enumeration variants that are prefixed or suffixed - /// by the same characters. + /// **What it does:** Detects public enumeration variants that are + /// prefixed or suffixed by the same characters. /// - /// **Why is this bad?** Enumeration variant names should specify their variant, + /// **Why is this bad?** Public enumeration variant names should specify their variant, /// not repeat the enumeration name. /// /// **Known problems:** None. /// /// **Example:** /// ```rust - /// enum Cake { + /// pub enum Cake { /// BlackForestCake, /// HummingbirdCake, /// BattenbergCake, /// } /// ``` + /// Could be written as: + /// ```rust + /// pub enum Cake { + /// BlackForest, + /// Hummingbird, + /// Battenberg, + /// } + /// ``` pub PUB_ENUM_VARIANT_NAMES, pedantic, - "enums where all variants share a prefix/postfix" + "public enums where all variants share a prefix/postfix" } declare_clippy_lint! { @@ -66,6 +82,12 @@ declare_clippy_lint! { /// struct BlackForestCake; /// } /// ``` + /// Could be written as: + /// ```rust + /// mod cake { + /// struct BlackForest; + /// } + /// ``` pub MODULE_NAME_REPETITIONS, pedantic, "type names prefixed/postfixed with their containing module's name" diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs index 4e1c1f13140..d7819d737ea 100644 --- a/src/tools/clippy/clippy_lints/src/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/eq_op.rs @@ -39,7 +39,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```ignore + /// // Bad /// &x == y + /// + /// // Good + /// x == *y /// ``` pub OP_REF, style, diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 1ec60a0e6e6..7227683aa5a 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -28,9 +28,16 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # fn foo(bar: usize) {} + /// + /// // Bad /// let x = Box::new(1); /// foo(*x); /// println!("{}", *x); + /// + /// // Good + /// let x = 1; + /// foo(x); + /// println!("{}", x); /// ``` pub BOXED_LOCAL, perf, diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index e3e1136b676..a889856de27 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -26,7 +26,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust,ignore + /// // Bad /// xs.map(|x| foo(x)) + /// + /// // Good + /// xs.map(foo) /// ``` /// where `foo(_)` is a plain function that takes the exact argument type of /// `x`. @@ -67,7 +71,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaReduction { } match expr.kind { - ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args) => { + ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => { for arg in args { check_closure(cx, arg) } @@ -116,7 +120,7 @@ fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { ); if_chain!( - if let ExprKind::MethodCall(ref path, _, ref args) = ex.kind; + if let ExprKind::MethodCall(ref path, _, ref args, _) = ex.kind; // Not the same number of arguments, there is no way the closure is the same as the function return; if args.len() == decl.inputs.len(); diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs index 5206266ccf2..74144fb299d 100644 --- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs +++ b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs @@ -21,11 +21,20 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let mut x = 0; + /// + /// // Bad /// let a = { /// x = 1; /// 1 /// } + x; /// // Unclear whether a is 1 or 2. + /// + /// // Good + /// let tmp = { + /// x = 1; + /// 1 + /// }; + /// let a = tmp + x; /// ``` pub EVAL_ORDER_DEPENDENCE, complexity, diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index 320121b2771..7269e2b52c2 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -32,11 +32,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitWrite { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // match call to unwrap - if let ExprKind::MethodCall(ref unwrap_fun, _, ref unwrap_args) = expr.kind; + if let ExprKind::MethodCall(ref unwrap_fun, _, ref unwrap_args, _) = expr.kind; if unwrap_fun.ident.name == sym!(unwrap); // match call to write_fmt if !unwrap_args.is_empty(); - if let ExprKind::MethodCall(ref write_fun, _, write_args) = + if let ExprKind::MethodCall(ref write_fun, _, write_args, _) = unwrap_args[0].kind; if write_fun.ident.name == sym!(write_fmt); // match calls to std::io::stdout() / std::io::stderr () diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs index 17639cc2a06..92812816461 100644 --- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs +++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs @@ -20,12 +20,31 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// struct Foo(i32); + /// + /// // Bad /// impl From<String> for Foo { /// fn from(s: String) -> Self { /// Foo(s.parse().unwrap()) /// } /// } /// ``` + /// + /// ```rust + /// // Good + /// struct Foo(i32); + /// + /// use std::convert::TryFrom; + /// impl TryFrom<String> for Foo { + /// type Error = (); + /// fn try_from(s: String) -> Result<Self, Self::Error> { + /// if let Ok(parsed) = s.parse() { + /// Ok(Foo(parsed)) + /// } else { + /// Err(()) + /// } + /// } + /// } + /// ``` pub FALLIBLE_IMPL_FROM, nursery, "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`" @@ -120,7 +139,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it move |diag| { diag.help( "`From` is intended for infallible conversions only. \ - Use `TryFrom` if there's a possibility for the conversion to fail."); + Use `TryFrom` if there's a possibility for the conversion to fail."); diag.span_note(fpu.result, "potential failure(s)"); }); } diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index 86317fb8bd5..ad4f66c52c2 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -28,7 +28,6 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust - /// /// let a = 3f32; /// let _ = a.powf(1.0 / 3.0); /// let _ = (1.0 + a).ln(); @@ -38,7 +37,6 @@ declare_clippy_lint! { /// is better expressed as /// /// ```rust - /// /// let a = 3f32; /// let _ = a.cbrt(); /// let _ = a.ln_1p(); @@ -303,7 +301,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if cx.tables.expr_ty(lhs).is_floating_point(); if let Some((value, _)) = constant(cx, cx.tables, rhs); if F32(1.0) == value || F64(1.0) == value; - if let ExprKind::MethodCall(ref path, _, ref method_args) = lhs.kind; + if let ExprKind::MethodCall(ref path, _, ref method_args, _) = lhs.kind; if cx.tables.expr_ty(&method_args[0]).is_floating_point(); if path.ident.name.as_str() == "exp"; then { @@ -483,7 +481,7 @@ fn check_custom_abs(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(ref path, _, args) = &expr.kind { + if let ExprKind::MethodCall(ref path, _, args, _) = &expr.kind { let recv_ty = cx.tables.expr_ty(&args[0]); if recv_ty.is_floating_point() { diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index 5b092526ce4..4cae5ca2c43 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -25,9 +25,13 @@ declare_clippy_lint! { /// /// **Examples:** /// ```rust + /// + /// // Bad /// # let foo = "foo"; - /// format!("foo"); /// format!("{}", foo); + /// + /// // Good + /// format!("foo"); /// ``` pub USELESS_FORMAT, complexity, @@ -100,7 +104,7 @@ fn on_argumentv1_new<'a, 'tcx>( } } else { let snip = snippet(cx, format_args.span, "<arg>"); - if let ExprKind::MethodCall(ref path, _, _) = format_args.kind { + if let ExprKind::MethodCall(ref path, _, _, _) = format_args.kind { if path.ident.name == sym!(to_string) { return Some(format!("{}", snip)); } diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index eb4b7a826f2..156246fb8bb 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -112,12 +112,8 @@ declare_lint_pass!(Formatting => [ impl EarlyLintPass for Formatting { fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { for w in block.stmts.windows(2) { - match (&w[0].kind, &w[1].kind) { - (&StmtKind::Expr(ref first), &StmtKind::Expr(ref second)) - | (&StmtKind::Expr(ref first), &StmtKind::Semi(ref second)) => { - check_missing_else(cx, first, second); - }, - _ => (), + if let (StmtKind::Expr(first), StmtKind::Expr(second) | StmtKind::Semi(second)) = (&w[0].kind, &w[1].kind) { + check_missing_else(cx, first, second); } } } diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs index c24a24733d7..991d129e8f0 100644 --- a/src/tools/clippy/clippy_lints/src/functions.rs +++ b/src/tools/clippy/clippy_lints/src/functions.rs @@ -49,11 +49,11 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ``` rust + /// ```rust /// fn im_too_long() { - /// println!(""); - /// // ... 100 more LoC - /// println!(""); + /// println!(""); + /// // ... 100 more LoC + /// println!(""); /// } /// ``` pub TOO_MANY_LINES, @@ -79,10 +79,16 @@ declare_clippy_lint! { /// `some_argument.get_raw_ptr()`). /// /// **Example:** - /// ```rust + /// ```rust,ignore + /// // Bad /// pub fn foo(x: *const u8) { /// println!("{}", unsafe { *x }); /// } + /// + /// // Good + /// pub unsafe fn foo(x: *const u8) { + /// println!("{}", unsafe { *x }); + /// } /// ``` pub NOT_UNSAFE_PTR_ARG_DEREF, correctness, @@ -550,7 +556,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { } } }, - hir::ExprKind::MethodCall(_, _, args) => { + hir::ExprKind::MethodCall(_, _, args, _) => { let def_id = self.tables.type_dependent_def_id(expr.hir_id).unwrap(); let base_type = self.cx.tcx.type_of(def_id); @@ -604,7 +610,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { return; } match expr.kind { - Call(_, args) | MethodCall(_, _, args) => { + Call(_, args) | MethodCall(_, _, args, _) => { let mut tys = FxHashSet::default(); for arg in args { let def_id = arg.hir_id.owner.to_def_id(); diff --git a/src/tools/clippy/clippy_lints/src/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/get_last_with_len.rs index c32e0a2290d..3629ba623ce 100644 --- a/src/tools/clippy/clippy_lints/src/get_last_with_len.rs +++ b/src/tools/clippy/clippy_lints/src/get_last_with_len.rs @@ -47,7 +47,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for GetLastWithLen { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // Is a method call - if let ExprKind::MethodCall(ref path, _, ref args) = expr.kind; + if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; // Method name is "get" if path.ident.name == sym!(get); @@ -69,7 +69,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for GetLastWithLen { ) = &get_index_arg.kind; // LHS of subtraction is "x.len()" - if let ExprKind::MethodCall(arg_lhs_path, _, lhs_args) = &lhs.kind; + if let ExprKind::MethodCall(arg_lhs_path, _, lhs_args, _) = &lhs.kind; if arg_lhs_path.ident.name == sym!(len); if let Some(arg_lhs_struct) = lhs_args.get(0); diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs index ae92a96d163..04d17c91d63 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs @@ -147,7 +147,7 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { fn is_mutex_lock_call<'a>(cx: &LateContext<'a, '_>, expr: &'a Expr<'_>) -> Option<&'a Expr<'a>> { if_chain! { - if let ExprKind::MethodCall(path, _span, args) = &expr.kind; + if let ExprKind::MethodCall(path, _span, args, _) = &expr.kind; if path.ident.to_string() == "lock"; let ty = cx.tables.expr_ty(&args[0]); if is_type_diagnostic_item(cx, ty, sym!(mutex_type)); diff --git a/src/tools/clippy/clippy_lints/src/if_let_some_result.rs b/src/tools/clippy/clippy_lints/src/if_let_some_result.rs index 9b13f760924..6a1fcdd1ce4 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_some_result.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_some_result.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { if_chain! { //begin checking variables if let ExprKind::Match(ref op, ref body, source) = expr.kind; //test if expr is a match if let MatchSource::IfLetDesugar { .. } = source; //test if it is an If Let - if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok() + if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result<T,E>.ok(, _) if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; if is_type_diagnostic_item(cx, cx.tables.expr_ty(&result_types[0]), sym!(result_type)); diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs index 155a93de4fa..fdaf37e5e08 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -25,13 +25,6 @@ declare_clippy_lint! { /// if i != 0 { /// i -= 1; /// } - /// ``` - /// Use instead: - /// ```rust - /// let end: u32 = 10; - /// let start: u32 = 5; - /// - /// let mut i: u32 = end - start; /// /// // Good /// i = i.saturating_sub(1); diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index cd989c0ea6f..a860a9def24 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -142,7 +142,7 @@ const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { - ExprKind::MethodCall(ref method, _, ref args) => { + ExprKind::MethodCall(ref method, _, ref args, _) => { for &(name, len, heuristic, cap) in &HEURISTICS { if method.ident.name.as_str() == name && args.len() == len { return (match heuristic { @@ -218,7 +218,7 @@ const INFINITE_COLLECTORS: [&[&str]; 8] = [ fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { - ExprKind::MethodCall(ref method, _, ref args) => { + ExprKind::MethodCall(ref method, _, ref args, _) => { for &(name, len) in &COMPLETING_METHODS { if method.ident.name.as_str() == name && args.len() == len { return is_infinite(cx, &args[0]); diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs index d5dbd495680..e91fb0c2f27 100644 --- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs +++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs @@ -10,7 +10,6 @@ use crate::utils::{snippet_opt, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block /// - /// /// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`. /// /// **Known problems:** None. diff --git a/src/tools/clippy/clippy_lints/src/integer_division.rs b/src/tools/clippy/clippy_lints/src/integer_division.rs index fe34d33fe65..d537ef3f323 100644 --- a/src/tools/clippy/clippy_lints/src/integer_division.rs +++ b/src/tools/clippy/clippy_lints/src/integer_division.rs @@ -15,10 +15,13 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust - /// fn main() { - /// let x = 3 / 2; - /// println!("{}", x); - /// } + /// // Bad + /// let x = 3 / 2; + /// println!("{}", x); + /// + /// // Good + /// let x = 3f32 / 2f32; + /// println!("{}", x); /// ``` pub INTEGER_DIVISION, restriction, diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs index e7062b7c16b..c8576bcfcb4 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs @@ -16,6 +16,7 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// fn foo() { /// println!("cake"); /// } @@ -28,6 +29,21 @@ declare_clippy_lint! { /// foo(); // prints "foo" /// } /// ``` + /// + /// ```rust + /// // Good + /// fn foo() { + /// println!("cake"); + /// } + /// + /// fn main() { + /// fn foo() { + /// println!("foo"); + /// } + /// foo(); // prints "foo" + /// foo(); // prints "foo" + /// } + /// ``` pub ITEMS_AFTER_STATEMENTS, pedantic, "blocks where an item comes after a statement" diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 2ec0b5a8d6f..13e85fda8ff 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{get_item_name, higher, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -211,7 +211,7 @@ fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item<'_>, impl_items: &[Imp } fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) { - if let (&ExprKind::MethodCall(ref method_path, _, ref args), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { + if let (&ExprKind::MethodCall(ref method_path, _, ref args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { if name.as_str() == "is_empty" { @@ -259,6 +259,17 @@ fn check_len( /// Checks if this type has an `is_empty` method. fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { + /// Special case ranges until `range_is_empty` is stabilized. See issue 3807. + fn should_skip_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { + higher::range(cx, expr).map_or(false, |_| { + !cx.tcx + .features() + .declared_lib_features + .iter() + .any(|(name, _)| name.as_str() == "range_is_empty") + }) + } + /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssocItem) -> bool { if let ty::AssocKind::Fn = item.kind { @@ -284,6 +295,10 @@ fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { }) } + if should_skip_range(cx, expr) { + return false; + } + let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr)); match ty.kind { ty::Dynamic(ref tt, ..) => { diff --git a/src/tools/clippy/clippy_lints/src/let_and_return.rs b/src/tools/clippy/clippy_lints/src/let_and_return.rs new file mode 100644 index 00000000000..6d3fb317bcf --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/let_and_return.rs @@ -0,0 +1,141 @@ +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::{Block, Expr, ExprKind, PatKind, StmtKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::map::Map; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +use crate::utils::{in_macro, match_qpath, snippet_opt, span_lint_and_then}; + +declare_clippy_lint! { + /// **What it does:** Checks for `let`-bindings, which are subsequently + /// returned. + /// + /// **Why is this bad?** It is just extraneous code. Remove it to make your code + /// more rusty. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// fn foo() -> String { + /// let x = String::new(); + /// x + /// } + /// ``` + /// instead, use + /// ``` + /// fn foo() -> String { + /// String::new() + /// } + /// ``` + pub LET_AND_RETURN, + style, + "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block" +} + +declare_lint_pass!(LetReturn => [LET_AND_RETURN]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetReturn { + fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block<'_>) { + // we need both a let-binding stmt and an expr + if_chain! { + if let Some(retexpr) = block.expr; + if let Some(stmt) = block.stmts.iter().last(); + if let StmtKind::Local(local) = &stmt.kind; + if local.ty.is_none(); + if local.attrs.is_empty(); + if let Some(initexpr) = &local.init; + if let PatKind::Binding(.., ident, _) = local.pat.kind; + if let ExprKind::Path(qpath) = &retexpr.kind; + if match_qpath(qpath, &[&*ident.name.as_str()]); + if !last_statement_borrows(cx, initexpr); + if !in_external_macro(cx.sess(), initexpr.span); + if !in_external_macro(cx.sess(), retexpr.span); + if !in_external_macro(cx.sess(), local.span); + if !in_macro(local.span); + then { + span_lint_and_then( + cx, + LET_AND_RETURN, + retexpr.span, + "returning the result of a `let` binding from a block", + |err| { + err.span_label(local.span, "unnecessary `let` binding"); + + if let Some(snippet) = snippet_opt(cx, initexpr.span) { + err.multipart_suggestion( + "return the expression directly", + vec![ + (local.span, String::new()), + (retexpr.span, snippet), + ], + Applicability::MachineApplicable, + ); + } else { + err.span_help(initexpr.span, "this expression can be directly returned"); + } + }, + ); + } + } + } +} + +fn last_statement_borrows<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + let mut visitor = BorrowVisitor { cx, borrows: false }; + walk_expr(&mut visitor, expr); + visitor.borrows +} + +struct BorrowVisitor<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, + borrows: bool, +} + +impl BorrowVisitor<'_, '_> { + fn fn_def_id(&self, expr: &Expr<'_>) -> Option<DefId> { + match &expr.kind { + ExprKind::MethodCall(..) => self.cx.tables.type_dependent_def_id(expr.hir_id), + ExprKind::Call( + Expr { + kind: ExprKind::Path(qpath), + .. + }, + .., + ) => self.cx.tables.qpath_res(qpath, expr.hir_id).opt_def_id(), + _ => None, + } + } +} + +impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + if self.borrows { + return; + } + + if let Some(def_id) = self.fn_def_id(expr) { + self.borrows = self + .cx + .tcx + .fn_sig(def_id) + .output() + .skip_binder() + .walk() + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); + } + + walk_expr(self, expr); + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } +} diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index b7d928d249f..cd258c7b506 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -1,5 +1,6 @@ // error-pattern:cargo-clippy +#![feature(bindings_after_at)] #![feature(box_syntax)] #![feature(box_patterns)] #![feature(or_patterns)] @@ -12,6 +13,7 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![feature(crate_visibility_modifier)] #![feature(concat_idents)] +#![feature(drain_filter)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) @@ -239,6 +241,7 @@ mod large_const_arrays; mod large_enum_variant; mod large_stack_arrays; mod len_zero; +mod let_and_return; mod let_if_seq; mod let_underscore; mod lifetimes; @@ -318,6 +321,8 @@ mod try_err; mod types; mod unicode; mod unnamed_address; +mod unnecessary_sort_by; +mod unnested_or_patterns; mod unsafe_removed_from_name; mod unused_io_amount; mod unused_self; @@ -325,6 +330,7 @@ mod unwrap; mod use_self; mod useless_conversion; mod vec; +mod vec_resize_to_zero; mod verbose_file_reads; mod wildcard_dependencies; mod wildcard_imports; @@ -594,6 +600,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &large_stack_arrays::LARGE_STACK_ARRAYS, &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, + &let_and_return::LET_AND_RETURN, &let_if_seq::USELESS_LET_IF_SEQ, &let_underscore::LET_UNDERSCORE_LOCK, &let_underscore::LET_UNDERSCORE_MUST_USE, @@ -664,6 +671,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::INTO_ITER_ON_REF, &methods::ITERATOR_STEP_BY_ZERO, &methods::ITER_CLONED_COLLECT, + &methods::ITER_NEXT_SLICE, &methods::ITER_NTH, &methods::ITER_NTH_ZERO, &methods::ITER_SKIP_NEXT, @@ -769,7 +777,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ®ex::INVALID_REGEX, ®ex::REGEX_MACRO, ®ex::TRIVIAL_REGEX, - &returns::LET_AND_RETURN, &returns::NEEDLESS_RETURN, &returns::UNUSED_UNIT, &serde_api::SERDE_API_MISUSE, @@ -832,6 +839,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unicode::ZERO_WIDTH_SPACE, &unnamed_address::FN_ADDRESS_COMPARISONS, &unnamed_address::VTABLE_ADDRESS_COMPARISONS, + &unnecessary_sort_by::UNNECESSARY_SORT_BY, + &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, &unused_io_amount::UNUSED_IO_AMOUNT, &unused_self::UNUSED_SELF, @@ -847,6 +856,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &utils::internal_lints::OUTER_EXPN_EXPN_DATA, &utils::internal_lints::PRODUCE_ICE, &vec::USELESS_VEC, + &vec_resize_to_zero::VEC_RESIZE_TO_ZERO, &verbose_file_reads::VERBOSE_FILE_READS, &wildcard_dependencies::WILDCARD_DEPENDENCIES, &wildcard_imports::ENUM_GLOB_USE, @@ -994,6 +1004,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast); store.register_late_pass(|| box redundant_clone::RedundantClone); store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); + store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy); store.register_late_pass(|| box types::RefToMut); store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); @@ -1016,6 +1027,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box formatting::Formatting); store.register_early_pass(|| box misc_early::MiscEarlyLints); store.register_early_pass(|| box returns::Return); + store.register_late_pass(|| box let_and_return::LetReturn); store.register_early_pass(|| box collapsible_if::CollapsibleIf); store.register_early_pass(|| box items_after_statements::ItemsAfterStatements); store.register_early_pass(|| box precedence::Precedence); @@ -1062,10 +1074,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive); store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); + store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { single_char_binding_names_threshold, }); + store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1164,6 +1178,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::CAST_POSSIBLE_TRUNCATION), LintId::of(&types::CAST_POSSIBLE_WRAP), LintId::of(&types::CAST_PRECISION_LOSS), + LintId::of(&types::CAST_PTR_ALIGNMENT), LintId::of(&types::CAST_SIGN_LOSS), LintId::of(&types::IMPLICIT_HASHER), LintId::of(&types::INVALID_UPCAST_COMPARISONS), @@ -1257,6 +1272,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), + LintId::of(&let_and_return::LET_AND_RETURN), LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), LintId::of(&lifetimes::NEEDLESS_LIFETIMES), @@ -1303,6 +1319,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITERATOR_STEP_BY_ZERO), LintId::of(&methods::ITER_CLONED_COLLECT), + LintId::of(&methods::ITER_NEXT_SLICE), LintId::of(&methods::ITER_NTH), LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), @@ -1381,7 +1398,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(®ex::INVALID_REGEX), LintId::of(®ex::REGEX_MACRO), LintId::of(®ex::TRIVIAL_REGEX), - LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), LintId::of(&serde_api::SERDE_API_MISUSE), @@ -1410,7 +1426,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::ABSURD_EXTREME_COMPARISONS), LintId::of(&types::BORROWED_BOX), LintId::of(&types::BOX_VEC), - LintId::of(&types::CAST_PTR_ALIGNMENT), LintId::of(&types::CAST_REF_TO_MUT), LintId::of(&types::CHAR_LIT_AS_U8), LintId::of(&types::FN_TO_NUMERIC_CAST), @@ -1424,12 +1439,15 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unicode::ZERO_WIDTH_SPACE), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), + LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&useless_conversion::USELESS_CONVERSION), LintId::of(&vec::USELESS_VEC), + LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), LintId::of(&write::PRINTLN_EMPTY_STRING), LintId::of(&write::PRINT_LITERAL), LintId::of(&write::PRINT_WITH_NEWLINE), @@ -1464,6 +1482,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&inherent_to_string::INHERENT_TO_STRING), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), + LintId::of(&let_and_return::LET_AND_RETURN), LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), LintId::of(&loops::EMPTY_LOOP), LintId::of(&loops::FOR_KV_MAP), @@ -1483,6 +1502,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITER_CLONED_COLLECT), + LintId::of(&methods::ITER_NEXT_SLICE), LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), @@ -1515,7 +1535,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(®ex::REGEX_MACRO), LintId::of(®ex::TRIVIAL_REGEX), - LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), @@ -1604,6 +1623,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNIT_ARG), LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), + LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&useless_conversion::USELESS_CONVERSION), LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), @@ -1669,7 +1690,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&transmute::WRONG_TRANSMUTE), LintId::of(&transmuting_null::TRANSMUTING_NULL), LintId::of(&types::ABSURD_EXTREME_COMPARISONS), - LintId::of(&types::CAST_PTR_ALIGNMENT), LintId::of(&types::CAST_REF_TO_MUT), LintId::of(&types::UNIT_CMP), LintId::of(&unicode::ZERO_WIDTH_SPACE), @@ -1677,6 +1697,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), + LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), ]); store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index d80ad47ab24..318d0b69d57 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -379,7 +379,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { TyKind::Path(ref path) => { self.collect_anonymous_lifetimes(path, ty); }, - TyKind::Def(item, _) => { + TyKind::OpaqueDef(item, _) => { let map = self.cx.tcx.hir(); if let ItemKind::OpaqueTy(ref exist_ty) = map.expect_item(item.id).kind { for bound in exist_ty.bounds { diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index ec7c4531ed7..7ba43562d7d 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -24,7 +24,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Bad /// let x: u64 = 61864918973511; + /// + /// // Good + /// let x: u64 = 61_864_918_973_511; /// ``` pub UNREADABLE_LITERAL, pedantic, @@ -44,7 +48,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Probably mistyped /// 2_32; + /// + /// // Good + /// 2_i32; /// ``` pub MISTYPED_LITERAL_SUFFIXES, correctness, @@ -63,7 +71,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Bad /// let x: u64 = 618_64_9189_73_511; + /// + /// // Good + /// let x: u64 = 61_864_918_973_511; /// ``` pub INCONSISTENT_DIGIT_GROUPING, style, diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index 38a5829b3f7..771bc8d0558 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -8,7 +8,7 @@ use crate::utils::{ multispan_sugg, snippet, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, SpanlessEq, }; -use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sugg}; +use crate::utils::{is_type_diagnostic_item, qpath_res, sugg}; use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -24,10 +24,10 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::middle::region; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use rustc_span::BytePos; +use rustc_span::symbol::Symbol; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; use std::iter::{once, Iterator}; use std::mem; @@ -526,7 +526,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Loops { let pat = &arms[0].pat.kind; if let ( &PatKind::TupleStruct(ref qpath, ref pat_args, _), - &ExprKind::MethodCall(ref method_path, _, ref method_args), + &ExprKind::MethodCall(ref method_path, _, ref method_args, _), ) = (pat, &match_expr.kind) { let iter_expr = &method_args[0]; @@ -654,7 +654,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { | ExprKind::Struct(_, _, Some(ref e)) | ExprKind::Repeat(ref e, _) | ExprKind::DropTemps(ref e) => never_loop_expr(e, main_loop_id), - ExprKind::Array(ref es) | ExprKind::MethodCall(_, _, ref es) | ExprKind::Tup(ref es) => { + ExprKind::Array(ref es) | ExprKind::MethodCall(_, _, ref es, _) | ExprKind::Tup(ref es) => { never_loop_expr_all(&mut es.iter(), main_loop_id) }, ExprKind::Call(ref e, ref es) => never_loop_expr_all(&mut once(&**e).chain(es.iter()), main_loop_id), @@ -806,7 +806,7 @@ fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'_>) -> bool { fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if_chain! { - if let ExprKind::MethodCall(method, _, args) = expr.kind; + if let ExprKind::MethodCall(method, _, args, _) = expr.kind; if method.ident.name == sym!(clone); if args.len() == 1; if let Some(arg) = args.get(0); @@ -915,7 +915,7 @@ fn build_manual_memcpy_suggestion<'a, 'tcx>( let print_limit = |end: &Expr<'_>, offset: Offset, var: &Expr<'_>| { if_chain! { - if let ExprKind::MethodCall(method, _, len_args) = end.kind; + if let ExprKind::MethodCall(method, _, len_args, _) = end.kind; if method.ident.name == sym!(len); if len_args.len() == 1; if let Some(arg) = len_args.get(0); @@ -1190,7 +1190,7 @@ fn check_for_loop_range<'a, 'tcx>( fn is_len_call(expr: &Expr<'_>, var: Name) -> bool { if_chain! { - if let ExprKind::MethodCall(ref method, _, ref len_args) = expr.kind; + if let ExprKind::MethodCall(ref method, _, ref len_args, _) = expr.kind; if len_args.len() == 1; if method.ident.name == sym!(len); if let ExprKind::Path(QPath::Resolved(_, ref path)) = len_args[0].kind; @@ -1244,7 +1244,7 @@ fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr<'_>], arg: &Expr<'_>, fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: &Expr<'_>) { let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used - if let ExprKind::MethodCall(ref method, _, ref args) = arg.kind { + if let ExprKind::MethodCall(ref method, _, ref args, _) = arg.kind { // just the receiver, no arguments if args.len() == 1 { let method_name = &*method.ident.as_str(); @@ -1256,7 +1256,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e } else if method_name == "into_iter" && match_trait_method(cx, arg, &paths::INTO_ITERATOR) { let receiver_ty = cx.tables.expr_ty(&args[0]); let receiver_ty_adjusted = cx.tables.expr_ty_adjusted(&args[0]); - if same_tys(cx, receiver_ty, receiver_ty_adjusted) { + if TyS::same_type(receiver_ty, receiver_ty_adjusted) { let mut applicability = Applicability::MachineApplicable; let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); span_lint_and_sugg( @@ -1277,7 +1277,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e mutbl: Mutability::Not, }, ); - if same_tys(cx, receiver_ty_adjusted, ref_receiver_ty) { + if TyS::same_type(receiver_ty_adjusted, ref_receiver_ty) { lint_iter_method(cx, args, arg, method_name) } } @@ -1718,7 +1718,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if_chain! { // a range index op - if let ExprKind::MethodCall(ref meth, _, ref args) = expr.kind; + if let ExprKind::MethodCall(ref meth, _, ref args, _) = expr.kind; if (meth.ident.name == sym!(index) && match_trait_method(self.cx, expr, &paths::INDEX)) || (meth.ident.name == sym!(index_mut) && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); if !self.check(&args[1], &args[0], expr); @@ -1776,7 +1776,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { self.visit_expr(expr); } }, - ExprKind::MethodCall(_, _, args) => { + ExprKind::MethodCall(_, _, args, _) => { let def_id = self.cx.tables.type_dependent_def_id(expr.hir_id).unwrap(); for (ty, expr) in self.cx.tcx.fn_sig(def_id).inputs().skip_binder().iter().zip(args) { self.prefer_mutable = false; @@ -2369,8 +2369,8 @@ const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, 'tcx>) { if_chain! { - if let ExprKind::MethodCall(ref method, _, ref args) = expr.kind; - if let ExprKind::MethodCall(ref chain_method, _, _) = args[0].kind; + if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind; + if let ExprKind::MethodCall(ref chain_method, _, _, _) = args[0].kind; if chain_method.ident.name == sym!(collect) && match_trait_method(cx, &args[0], &paths::ITERATOR); if let Some(ref generic_args) = chain_method.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); @@ -2381,32 +2381,32 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, ' match_type(cx, ty, &paths::BTREEMAP) || is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) { if method.ident.name == sym!(len) { - let span = shorten_needless_collect_span(expr); + let span = shorten_span(expr, sym!(collect)); span_lint_and_sugg( cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, "replace with", - ".count()".to_string(), + "count()".to_string(), Applicability::MachineApplicable, ); } if method.ident.name == sym!(is_empty) { - let span = shorten_needless_collect_span(expr); + let span = shorten_span(expr, sym!(iter)); span_lint_and_sugg( cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, "replace with", - ".next().is_none()".to_string(), + "get(0).is_none()".to_string(), Applicability::MachineApplicable, ); } if method.ident.name == sym!(contains) { let contains_arg = snippet(cx, args[1].span, "??"); - let span = shorten_needless_collect_span(expr); + let span = shorten_span(expr, sym!(collect)); span_lint_and_then( cx, NEEDLESS_COLLECT, @@ -2422,7 +2422,7 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, ' span, "replace with", format!( - ".any(|{}| x == {})", + "any(|{}| x == {})", arg, pred ), Applicability::MachineApplicable, @@ -2435,13 +2435,13 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, ' } } -fn shorten_needless_collect_span(expr: &Expr<'_>) -> Span { - if_chain! { - if let ExprKind::MethodCall(_, _, ref args) = expr.kind; - if let ExprKind::MethodCall(_, ref span, _) = args[0].kind; - then { - return expr.span.with_lo(span.lo() - BytePos(1)); +fn shorten_span(expr: &Expr<'_>, target_fn_name: Symbol) -> Span { + let mut current_expr = expr; + while let ExprKind::MethodCall(ref path, ref span, ref args, _) = current_expr.kind { + if path.ident.name == target_fn_name { + return expr.span.with_lo(span.lo()); } + current_expr = &args[0]; } unreachable!() } diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index cb72a240582..03ab274d9ca 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ManualAsyncFn { fn future_trait_ref<'tcx>(cx: &LateContext<'_, 'tcx>, ty: &'tcx Ty<'tcx>) -> Option<&'tcx TraitRef<'tcx>> { if_chain! { - if let TyKind::Def(item_id, _) = ty.kind; + if let TyKind::OpaqueDef(item_id, _) = ty.kind; let item = cx.tcx.hir().item(item_id.id); if let ItemKind::OpaqueTy(opaque) = &item.kind; if opaque.bounds.len() == 1; diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs index d5adf6b0f0d..8f4fdc685ef 100644 --- a/src/tools/clippy/clippy_lints/src/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/map_clone.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MapClone { } if_chain! { - if let hir::ExprKind::MethodCall(ref method, _, ref args) = e.kind; + if let hir::ExprKind::MethodCall(ref method, _, ref args, _) = e.kind; if args.len() == 2; if method.ident.as_str() == "map"; let ty = cx.tables.expr_ty(&args[0]); @@ -75,7 +75,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MapClone { } } }, - hir::ExprKind::MethodCall(ref method, _, ref obj) => { + hir::ExprKind::MethodCall(ref method, _, ref obj, _) => { if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone" && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index fecd91c7814..8f4b674c04f 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -125,7 +125,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a hir::Expr<'_>) } match expr.kind { - hir::ExprKind::Call(_, _) | hir::ExprKind::MethodCall(_, _, _) => { + hir::ExprKind::Call(_, _) | hir::ExprKind::MethodCall(_, _, _, _) => { // Calls can't be reduced any more Some(expr.span) }, diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index 94380acfcfd..6d7af45a472 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -36,10 +36,17 @@ declare_clippy_lint! { /// ```rust /// # fn bar(stool: &str) {} /// # let x = Some("abc"); + /// + /// // Bad /// match x { /// Some(ref foo) => bar(foo), /// _ => (), /// } + /// + /// // Good + /// if let Some(ref foo) = x { + /// bar(foo); + /// } /// ``` pub SINGLE_MATCH, style, @@ -97,11 +104,19 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust,ignore + /// // Bad /// match x { /// &A(ref y) => foo(y), /// &B => bar(), /// _ => frob(&x), /// } + /// + /// // Good + /// match *x { + /// A(ref y) => foo(y), + /// B => bar(), + /// _ => frob(x), + /// } /// ``` pub MATCH_REF_PATS, style, @@ -197,10 +212,15 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let x: Option<()> = None; + /// + /// // Bad /// let r: Option<&()> = match x { /// None => None, /// Some(ref v) => Some(v), /// }; + /// + /// // Good + /// let r: Option<&()> = x.as_ref(); /// ``` pub MATCH_AS_REF, complexity, @@ -219,10 +239,18 @@ declare_clippy_lint! { /// ```rust /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); + /// + /// // Bad /// match x { /// Foo::A(_) => {}, /// _ => {}, /// } + /// + /// // Good + /// match x { + /// Foo::A(_) => {}, + /// Foo::B(_) => {}, + /// } /// ``` pub WILDCARD_ENUM_MATCH_ARM, restriction, @@ -242,16 +270,14 @@ declare_clippy_lint! { /// ```rust /// # enum Foo { A, B, C } /// # let x = Foo::B; + /// // Bad /// match x { /// Foo::A => {}, /// Foo::B => {}, /// _ => {}, /// } - /// ``` - /// Use instead: - /// ```rust - /// # enum Foo { A, B, C } - /// # let x = Foo::B; + /// + /// // Good /// match x { /// Foo::A => {}, /// Foo::B => {}, @@ -273,10 +299,17 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// match "foo" { /// "a" => {}, /// "bar" | _ => {}, /// } + /// + /// // Good + /// match "foo" { + /// "a" => {}, + /// _ => {}, + /// } /// ``` pub WILDCARD_IN_OR_PATTERNS, complexity, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs index aaed6d75048..4f5c06e785c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -57,7 +57,7 @@ pub fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr< ); } else { match (mm, arith) { - (MinMax::Max, "add") | (MinMax::Max, "mul") | (MinMax::Min, "sub") => (), + (MinMax::Max, "add" | "mul") | (MinMax::Min, "sub") => (), _ => return, } diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 52ca962e7ef..f25a9782813 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -18,7 +18,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -26,12 +26,12 @@ use rustc_span::symbol::{sym, SymbolStr}; use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ - get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy, + get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, - remove_blocks, return_ty, same_tys, single_segment_path, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, - span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, + remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty, + walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -218,7 +218,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let x = Ok::<_, ()>(()); - /// x.ok().expect("why did I do this again?") + /// + /// // Bad + /// x.ok().expect("why did I do this again?"); + /// + /// // Good + /// x.expect("why did I do this again?"); /// ``` pub OK_EXPECT, style, @@ -273,8 +278,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let opt = Some(1); - /// opt.map_or(None, |a| Some(a + 1)) - /// # ; + /// + /// // Bad + /// opt.map_or(None, |a| Some(a + 1)); + /// + /// // Good + /// opt.and_then(|a| Some(a + 1)); /// ``` pub OPTION_MAP_OR_NONE, style, @@ -390,14 +399,19 @@ declare_clippy_lint! { /// **What it does:** Checks for usage of `_.map(_).flatten(_)`, /// /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// single method call using `_.flat_map(_)` /// /// **Known problems:** /// /// **Example:** /// ```rust /// let vec = vec![vec![1]]; + /// + /// // Bad /// vec.iter().map(|x| x.iter()).flatten(); + /// + /// // Good + /// vec.iter().flat_map(|x| x.iter()); /// ``` pub MAP_FLATTEN, pedantic, @@ -417,7 +431,16 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let vec = vec![1]; + /// + /// // Bad /// vec.iter().filter(|x| **x == 0).map(|x| *x * 2); + /// + /// // Good + /// vec.iter().filter_map(|x| if *x == 0 { + /// Some(*x * 2) + /// } else { + /// None + /// }); /// ``` pub FILTER_MAP, pedantic, @@ -634,7 +657,12 @@ declare_clippy_lint! { /// ```rust /// # use std::rc::Rc; /// let x = Rc::new(1); + /// + /// // Bad /// x.clone(); + /// + /// // Good + /// Rc::clone(&x); /// ``` pub CLONE_ON_REF_PTR, restriction, @@ -741,7 +769,12 @@ declare_clippy_lint! { /// **Known problems:** Does not catch multi-byte unicode characters. /// /// **Example:** - /// `_.split("x")` could be `_.split('x')` + /// ```rust,ignore + /// // Bad + /// _.split("x"); + /// + /// // Good + /// _.split('x'); pub SINGLE_CHAR_PATTERN, perf, "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" @@ -964,8 +997,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `.chars().last()` or - /// `.chars().next_back()` on a `str` to check if it ends with a given char. + /// **What it does:** Checks for usage of `_.chars().last()` or + /// `_.chars().next_back()` on a `str` to check if it ends with a given char. /// /// **Why is this bad?** Readability, this can be written more concisely as /// `_.ends_with(_)`. @@ -975,8 +1008,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let name = "_"; - /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-') - /// # ; + /// + /// // Bad + /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); + /// + /// // Good + /// name.ends_with('_') || name.ends_with('-'); /// ``` pub CHARS_LAST_CMP, style, @@ -1044,17 +1081,15 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None }); - /// ``` - /// As there is no transformation of the argument this could be written as: - /// ```rust + /// + /// // As there is no transformation of the argument this could be written as: /// let _ = (0..3).filter(|&x| x > 2); /// ``` /// /// ```rust /// let _ = (0..4).filter_map(|x| Some(x + 1)); - /// ``` - /// As there is no conditional check on the argument this could be written as: - /// ```rust + /// + /// // As there is no conditional check on the argument this could be written as: /// let _ = (0..4).map(|x| x + 1); /// ``` pub UNNECESSARY_FILTER_MAP, @@ -1075,7 +1110,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Bad /// let _ = (&vec![3, 4, 5]).into_iter(); + /// + /// // Good + /// let _ = (&vec![3, 4, 5]).iter(); /// ``` pub INTO_ITER_ON_REF, style, @@ -1242,6 +1281,32 @@ declare_clippy_lint! { "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `iter().next()` on a Slice or an Array + /// + /// **Why is this bad?** These can be shortened into `.get()` + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// # let a = [1, 2, 3]; + /// # let b = vec![1, 2, 3]; + /// a[2..].iter().next(); + /// b.iter().next(); + /// ``` + /// should be written as: + /// ```rust + /// # let a = [1, 2, 3]; + /// # let b = vec![1, 2, 3]; + /// a.get(2); + /// b.get(0); + /// ``` + pub ITER_NEXT_SLICE, + style, + "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`" +} + declare_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, @@ -1273,6 +1338,7 @@ declare_lint_pass!(Methods => [ FIND_MAP, MAP_FLATTEN, ITERATOR_STEP_BY_ZERO, + ITER_NEXT_SLICE, ITER_NTH, ITER_NTH_ZERO, ITER_SKIP_NEXT, @@ -1320,6 +1386,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { }, ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), + ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]), @@ -1336,9 +1403,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1]) }, ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), - ["as_ptr", "unwrap"] | ["as_ptr", "expect"] => { - lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0]) - }, + ["as_ptr", "unwrap" | "expect"] => lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0]), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]), @@ -1351,12 +1416,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]), ["count", "map"] => lint_suspicious_map(cx, expr), ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), - ["unwrap_or", arith @ "checked_add"] - | ["unwrap_or", arith @ "checked_sub"] - | ["unwrap_or", arith @ "checked_mul"] => { + ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..]) }, - ["add"] | ["offset"] | ["sub"] | ["wrapping_offset"] | ["wrapping_add"] | ["wrapping_sub"] => { + ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => { check_pointer_offset(cx, expr, arg_lists[0]) }, ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]), @@ -1366,7 +1429,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { } match expr.kind { - hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args) => { + hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => { lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); @@ -1481,7 +1544,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { let contains_self_ty = |ty: Ty<'tcx>| { ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => same_tys(cx, self_ty, inner_ty), + GenericArgKind::Type(inner_ty) => TyS::same_type(self_ty, inner_ty), GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }) @@ -1508,7 +1571,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { } } - if name == "new" && !same_tys(cx, ret_ty, self_ty) { + if name == "new" && !TyS::same_type(ret_ty, self_ty) { span_lint( cx, NEW_RET_NO_SELF, @@ -1614,7 +1677,7 @@ fn lint_or_fun_call<'a, 'tcx>( or_has_args: bool, span: Span, ) { - if let hir::ExprKind::MethodCall(ref path, _, ref args) = &arg.kind { + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { if path.ident.as_str() == "len" { let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0])); @@ -1688,7 +1751,7 @@ fn lint_or_fun_call<'a, 'tcx>( ); } }, - hir::ExprKind::MethodCall(_, span, ref or_args) => check_general_case( + hir::ExprKind::MethodCall(_, span, ref or_args, _) => check_general_case( cx, name, method_span, @@ -1719,7 +1782,7 @@ fn lint_expect_fun_call( loop { arg_root = match &arg_root.kind { hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, - hir::ExprKind::MethodCall(method_name, _, call_args) => { + hir::ExprKind::MethodCall(method_name, _, call_args, _) => { if call_args.len() == 1 && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref)) && { @@ -1762,8 +1825,7 @@ fn lint_expect_fun_call( hir::ExprKind::Call(fun, _) => { if let hir::ExprKind::Path(ref p) = fun.kind { match cx.tables.qpath_res(p, fun.hir_id) { - hir::def::Res::Def(hir::def::DefKind::Fn, def_id) - | hir::def::Res::Def(hir::def::DefKind::AssocFn, def_id) => matches!( + hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!( cx.tcx.fn_sig(def_id).output().skip_binder().kind, ty::Ref(ty::ReStatic, ..) ), @@ -1940,7 +2002,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir: // &*x is a nop, &x.clone() is not hir::ExprKind::AddrOf(..) => return, // (*x).func() is useless, x.clone().func() can work in case func borrows mutably - hir::ExprKind::MethodCall(_, _, parent_args) if expr.hir_id == parent_args[0].hir_id => return, + hir::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => return, _ => {}, }, @@ -2199,6 +2261,60 @@ fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args } } +fn lint_iter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { + let caller_expr = &iter_args[0]; + + // Skip lint if the `iter().next()` expression is a for loop argument, + // since it is already covered by `&loops::ITER_NEXT_LOOP` + let mut parent_expr_opt = get_parent_expr(cx, expr); + while let Some(parent_expr) = parent_expr_opt { + if higher::for_loop(parent_expr).is_some() { + return; + } + parent_expr_opt = get_parent_expr(cx, parent_expr); + } + + if derefs_to_slice(cx, caller_expr, cx.tables.expr_ty(caller_expr)).is_some() { + // caller is a Slice + if_chain! { + if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind; + if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) + = higher::range(cx, index_expr); + if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind; + if let ast::LitKind::Int(start_idx, _) = start_lit.node; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NEXT_SLICE, + expr.span, + "Using `.iter().next()` on a Slice without end index.", + "try calling", + format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx), + applicability, + ); + } + } + } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(caller_expr), sym!(vec_type)) + || matches!(&walk_ptrs_ty(cx.tables.expr_ty(caller_expr)).kind, ty::Array(_, _)) + { + // caller is a Vec or an Array + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NEXT_SLICE, + expr.span, + "Using `.iter().next()` on an array", + "try calling", + format!( + "{}.get(0)", + snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability) + ), + applicability, + ); + } +} + fn lint_iter_nth<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, @@ -2362,7 +2478,7 @@ fn derefs_to_slice<'a, 'tcx>( } } - if let hir::ExprKind::MethodCall(ref path, _, ref args) = expr.kind { + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { if path.ident.name == sym!(iter) && may_slice(cx, cx.tables.expr_ty(&args[0])) { Some(&args[0]) } else { @@ -3066,7 +3182,7 @@ fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, call_name: &str, a // allow the `as_ref` or `as_mut` if it is followed by another method call if_chain! { if let Some(parent) = get_parent_expr(cx, expr); - if let hir::ExprKind::MethodCall(_, ref span, _) = parent.kind; + if let hir::ExprKind::MethodCall(_, ref span, _, _) = parent.kind; if span != &expr.span; then { return; @@ -3194,7 +3310,7 @@ fn lint_option_as_ref_deref<'a, 'tcx>( let closure_expr = remove_blocks(&closure_body.value); match &closure_expr.kind { - hir::ExprKind::MethodCall(_, _, args) => { + hir::ExprKind::MethodCall(_, _, args, _) => { if_chain! { if args.len() == 1; if let hir::ExprKind::Path(qpath) = &args[0].kind; diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index e1d524c2231..a0947608e60 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -38,10 +38,16 @@ declare_clippy_lint! { /// dereferences, e.g., changing `*x` to `x` within the function. /// /// **Example:** - /// ```rust + /// ```rust,ignore + /// // Bad /// fn foo(ref x: u8) -> bool { /// true /// } + /// + /// // Good + /// fn foo(x: &u8) -> bool { + /// true + /// } /// ``` pub TOPLEVEL_REF_ARG, style, @@ -60,7 +66,11 @@ declare_clippy_lint! { /// ```rust /// # let x = 1.0; /// + /// // Bad /// if x == f32::NAN { } + /// + /// // Good + /// if x.is_nan() { } /// ``` pub CMP_NAN, correctness, @@ -83,8 +93,15 @@ declare_clippy_lint! { /// ```rust /// let x = 1.2331f64; /// let y = 1.2332f64; + /// + /// // Bad /// if y == 1.23f64 { } /// if y != x {} // where both are floats + /// + /// // Good + /// let error = 0.01f64; // Use an epsilon for comparison + /// if (y - 1.23f64).abs() < error { } + /// if (y - x).abs() > error { } /// ``` pub FLOAT_CMP, correctness, @@ -191,7 +208,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Bad /// let a = 0 as *const u32; + /// + /// // Good + /// let a = std::ptr::null::<u32>(); /// ``` pub ZERO_PTR, style, @@ -214,7 +235,13 @@ declare_clippy_lint! { /// ```rust /// let x: f64 = 1.0; /// const ONE: f64 = 1.00; - /// x == ONE; // where both are floats + /// + /// // Bad + /// if x == ONE { } // where both are floats + /// + /// // Good + /// let error = 0.1f64; // Use an epsilon for comparison + /// if (x - ONE).abs() < error { } /// ``` pub FLOAT_CMP_CONST, restriction, @@ -248,17 +275,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints { return; } for arg in iter_input_pats(decl, body) { - match arg.pat.kind { - PatKind::Binding(BindingAnnotation::Ref, ..) | PatKind::Binding(BindingAnnotation::RefMut, ..) => { - span_lint( - cx, - TOPLEVEL_REF_ARG, - arg.pat.span, - "`ref` directly on a function argument is ignored. Consider using a reference type \ - instead.", - ); - }, - _ => {}, + if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind { + span_lint( + cx, + TOPLEVEL_REF_ARG, + arg.pat.span, + "`ref` directly on a function argument is ignored. \ + Consider using a reference type instead.", + ); } } } @@ -521,7 +545,7 @@ fn is_signum(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { } if_chain! { - if let ExprKind::MethodCall(ref method_name, _, ref expressions) = expr.kind; + if let ExprKind::MethodCall(ref method_name, _, ref expressions, _) = expr.kind; if sym!(signum) == method_name.ident.name; // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) @@ -548,7 +572,7 @@ fn is_array(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) { let (arg_ty, snip) = match expr.kind { - ExprKind::MethodCall(.., ref args) if args.len() == 1 => { + ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => { if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) { (cx.tables.expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, "..")) } else { diff --git a/src/tools/clippy/clippy_lints/src/misc_early.rs b/src/tools/clippy/clippy_lints/src/misc_early.rs index 552222eba2e..ad39e59d067 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early.rs @@ -59,7 +59,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// fn foo(a: i32, _a: i32) {} + /// + /// // Good + /// fn bar(a: i32, _b: i32) {} /// ``` pub DUPLICATE_UNDERSCORE_ARGUMENT, style, @@ -77,7 +81,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust,ignore - /// (|| 42)() + /// // Bad + /// let a = (|| 42)() + /// + /// // Good + /// let a = 42 /// ``` pub REDUNDANT_CLOSURE_CALL, complexity, @@ -112,7 +120,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// let y = 0x1a9BAcD; + /// + /// // Good + /// let y = 0x1A9BACD; /// ``` pub MIXED_CASE_HEX_LITERALS, style, @@ -129,7 +141,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// let y = 123832i32; + /// + /// // Good + /// let y = 123832_i32; /// ``` pub UNSEPARATED_LITERAL_SUFFIX, pedantic, @@ -207,9 +223,16 @@ declare_clippy_lint! { /// ```rust /// # let v = Some("abc"); /// + /// // Bad + /// match v { + /// Some(x) => (), + /// y @ _ => (), + /// } + /// + /// // Good /// match v { /// Some(x) => (), - /// y @ _ => (), // easier written as `y`, + /// y => (), /// } /// ``` pub REDUNDANT_PATTERN, @@ -235,16 +258,13 @@ declare_clippy_lint! { /// # struct TupleStruct(u32, u32, u32); /// # let t = TupleStruct(1, 2, 3); /// + /// // Bad /// match t { /// TupleStruct(0, .., _) => (), /// _ => (), /// } - /// ``` - /// can be written as - /// ```rust - /// # struct TupleStruct(u32, u32, u32); - /// # let t = TupleStruct(1, 2, 3); /// + /// // Good /// match t { /// TupleStruct(0, ..) => (), /// _ => (), diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 2eefb6bbaf4..0fd1e87f9e4 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -187,7 +187,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { hir::ImplItemKind::Const(..) => "an associated constant", hir::ImplItemKind::Fn(..) => "a method", hir::ImplItemKind::TyAlias(_) => "an associated type", - hir::ImplItemKind::OpaqueTy(_) => "an existential type", }; self.check_missing_docs_attrs(cx, &impl_item.attrs, impl_item.span, desc); } diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 3ad3d5aee4d..1802470b184 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -142,7 +142,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline { let desc = match impl_item.kind { hir::ImplItemKind::Fn(..) => "a method", - hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(_) | hir::ImplItemKind::OpaqueTy(_) => return, + hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(_) => return, }; let def_id = cx.tcx.hir().local_def_id(impl_item.hir_id); diff --git a/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs index b6770804e18..6c42014b4c8 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs @@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::DUMMY_SP; -use cargo_metadata::{DependencyKind, MetadataCommand, Node, Package, PackageId}; +use cargo_metadata::{DependencyKind, Node, Package, PackageId}; use if_chain::if_chain; use itertools::Itertools; @@ -42,13 +42,7 @@ impl LateLintPass<'_, '_> for MultipleCrateVersions { return; } - let metadata = if let Ok(metadata) = MetadataCommand::new().exec() { - metadata - } else { - span_lint(cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, "could not read cargo metadata"); - return; - }; - + let metadata = unwrap_cargo_metadata!(cx, MULTIPLE_CRATE_VERSIONS, true); let local_name = cx.tcx.crate_name(LOCAL_CRATE).as_str(); let mut packages = metadata.packages; packages.sort_by(|a, b| a.name.cmp(&b.name)); diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index 67a1ac78a67..7fcf15f8acb 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -16,7 +16,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```ignore + /// // Bad /// my_vec.push(&mut value) + /// + /// // Good + /// my_vec.push(&value) /// ``` pub UNNECESSARY_MUT_PASSED, style, @@ -38,7 +42,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed { ); } }, - ExprKind::MethodCall(ref path, _, ref arguments) => { + ExprKind::MethodCall(ref path, _, ref arguments, _) => { let def_id = cx.tables.type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.tables.node_substs(e.hir_id); let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs); diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs index 4e1a8be4892..78b15afc5a7 100644 --- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs +++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs @@ -22,9 +22,15 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// # let y = true; + /// + /// // Bad /// # use std::sync::Mutex; - /// # let y = 1; /// let x = Mutex::new(&y); + /// + /// // Good + /// # use std::sync::atomic::AtomicBool; + /// let x = AtomicBool::new(y); /// ``` pub MUTEX_ATOMIC, perf, @@ -46,6 +52,10 @@ declare_clippy_lint! { /// ```rust /// # use std::sync::Mutex; /// let x = Mutex::new(0usize); + /// + /// // Good + /// # use std::sync::atomic::AtomicUsize; + /// let x = AtomicUsize::new(0usize); /// ``` pub MUTEX_INTEGER, nursery, diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index efa77db822d..15b129fa098 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -15,8 +15,7 @@ use rustc_span::Span; declare_clippy_lint! { /// **What it does:** Checks for expressions of the form `if c { true } else { - /// false }` - /// (or vice versa) and suggest using the condition directly. + /// false }` (or vice versa) and suggests using the condition directly. /// /// **Why is this bad?** Redundant code. /// diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs index 9ee875d7516..5880d1d6102 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs @@ -18,12 +18,16 @@ declare_clippy_lint! { /// **Why is this bad?** Suggests that the receiver of the expression borrows /// the expression. /// + /// **Known problems:** None. + /// /// **Example:** /// ```rust + /// // Bad /// let x: &i32 = &&&&&&5; - /// ``` /// - /// **Known problems:** None. + /// // Good + /// let x: &i32 = &5; + /// ``` pub NEEDLESS_BORROW, nursery, "taking a reference that is going to be automatically dereferenced" diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index 28183810df4..a971d041ca6 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -424,7 +424,7 @@ fn erode_from_back(s: &str) -> String { } fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> { - block.stmts.iter().next().map(|stmt| stmt.span) + block.stmts.get(0).map(|stmt| stmt.span) } #[cfg(test)] diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs index 4b2586877e5..d866bab2f64 100644 --- a/src/tools/clippy/clippy_lints/src/needless_update.rs +++ b/src/tools/clippy/clippy_lints/src/needless_update.rs @@ -21,6 +21,16 @@ declare_clippy_lint! { /// # z: i32, /// # } /// # let zero_point = Point { x: 0, y: 0, z: 0 }; + /// + /// // Bad + /// Point { + /// x: 1, + /// y: 1, + /// z: 1, + /// ..zero_point + /// }; + /// + /// // Ok /// Point { /// x: 1, /// y: 1, diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index e556e5d59c1..dd236535c18 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -1,13 +1,13 @@ use crate::utils::paths; use crate::utils::sugg::DiagnosticBuilderExt; -use crate::utils::{get_trait_def_id, return_ty, same_tys, span_lint_hir_and_then}; +use crate::utils::{get_trait_def_id, return_ty, span_lint_hir_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::HirIdSet; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{Ty, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { @@ -93,7 +93,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); let self_ty = cx.tcx.type_of(self_def_id); if_chain! { - if same_tys(cx, self_ty, return_ty(cx, id)); + if TyS::same_type(self_ty, return_ty(cx, id)); if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); then { if self.impling_types.is_none() { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index b8bfa676a16..2eacd3c80c4 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -147,7 +147,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option if let ExprKind::Path(ref qpath) = callee.kind { let res = qpath_res(cx, qpath, callee.hir_id); match res { - Res::Def(DefKind::Struct, ..) | Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(..), _) + Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) if !has_drop(cx, cx.tables.expr_ty(expr)) => { Some(args.iter().collect()) diff --git a/src/tools/clippy/clippy_lints/src/open_options.rs b/src/tools/clippy/clippy_lints/src/open_options.rs index 9d3b67988db..2d4629b683f 100644 --- a/src/tools/clippy/clippy_lints/src/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/open_options.rs @@ -29,7 +29,7 @@ declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OpenOptions { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(ref path, _, ref arguments) = e.kind { + if let ExprKind::MethodCall(ref path, _, ref arguments, _) = e.kind { let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&arguments[0])); if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { let mut options = Vec::new(); @@ -57,7 +57,7 @@ enum OpenOption { } fn get_open_options(cx: &LateContext<'_, '_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { - if let ExprKind::MethodCall(ref path, _, ref arguments) = argument.kind { + if let ExprKind::MethodCall(ref path, _, ref arguments, _) = argument.kind { let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&arguments[0])); // Only proceed if this is a call on some object of type std::fs::OpenOptions diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs index 66dfa20edb5..fd653044a1b 100644 --- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs @@ -35,7 +35,7 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]); impl EarlyLintPass for OptionEnvUnwrap { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if_chain! { - if let ExprKind::MethodCall(path_segment, args) = &expr.kind; + if let ExprKind::MethodCall(path_segment, args, _) = &expr.kind; let method_name = path_segment.ident.as_str(); if method_name == "expect" || method_name == "unwrap"; if let ExprKind::Call(caller, _) = &args[0].kind; diff --git a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs index bdbaf2695c8..88ad1e0914f 100644 --- a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs +++ b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs @@ -43,7 +43,7 @@ declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathBufPushOverwrite { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(ref path, _, ref args) = expr.kind; + if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; if path.ident.name == sym!(push); if args.len() == 2; if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(&args[0])), &paths::PATH_BUF); diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index cc783baa687..7dce23dd223 100644 --- a/src/tools/clippy/clippy_lints/src/precedence.rs +++ b/src/tools/clippy/clippy_lints/src/precedence.rs @@ -103,7 +103,7 @@ impl EarlyLintPass for Precedence { } if let ExprKind::Unary(UnOp::Neg, ref rhs) = expr.kind { - if let ExprKind::MethodCall(ref path_segment, ref args) = rhs.kind { + if let ExprKind::MethodCall(ref path_segment, ref args, _) = rhs.kind { let path_segment_str = path_segment.ident.name.as_str(); if let Some(slf) = args.first() { if let ExprKind::Lit(ref lit) = slf.kind { diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 4eac571f966..c77b44e0c99 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -47,7 +47,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```ignore + /// // Bad /// fn foo(&Vec<u32>) { .. } + /// + /// // Good + /// fn foo(&[u32]) { .. } /// ``` pub PTR_ARG, style, @@ -65,9 +69,15 @@ declare_clippy_lint! { /// /// **Example:** /// ```ignore + /// // Bad /// if x == ptr::null { /// .. /// } + /// + /// // Good + /// if x.is_null() { + /// .. + /// } /// ``` pub CMP_NULL, style, @@ -76,19 +86,16 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** This lint checks for functions that take immutable - /// references and return - /// mutable ones. + /// references and return mutable ones. /// /// **Why is this bad?** This is trivially unsound, as one can create two - /// mutable references - /// from the same (immutable!) source. This - /// [error](https://github.com/rust-lang/rust/issues/39465) + /// mutable references from the same (immutable!) source. + /// This [error](https://github.com/rust-lang/rust/issues/39465) /// actually lead to an interim Rust release 1.15.1. /// /// **Known problems:** To be on the conservative side, if there's at least one - /// mutable reference - /// with the output lifetime, this lint will not trigger. In practice, this - /// case is unlikely anyway. + /// mutable reference with the output lifetime, this lint will not trigger. + /// In practice, this case is unlikely anyway. /// /// **Example:** /// ```ignore diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs index ffc59d43750..d23d7e59b73 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs @@ -90,7 +90,7 @@ fn expr_as_ptr_offset_call<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> { - if let ExprKind::MethodCall(ref path_segment, _, ref args) = expr.kind { + if let ExprKind::MethodCall(ref path_segment, _, ref args, _) = expr.kind { if is_expr_ty_raw_ptr(cx, &args[0]) { if path_segment.ident.name == sym!(offset) { return Some((&args[0], &args[1], Method::Offset)); diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index ea654467b86..3591972fe08 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -50,7 +50,7 @@ impl QuestionMark { fn check_is_none_and_early_return_none(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if_chain! { if let Some((if_expr, body, else_)) = higher::if_block(&expr); - if let ExprKind::MethodCall(segment, _, args) = &if_expr.kind; + if let ExprKind::MethodCall(segment, _, args, _) = &if_expr.kind; if segment.ident.name == sym!(is_none); if Self::expression_returns_none(cx, body); if let Some(subject) = args.get(0); @@ -88,7 +88,7 @@ impl QuestionMark { replacement_str, applicability, ) - } + } } } } diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 1eb26d97ed4..fcd02a196e7 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -129,20 +129,20 @@ declare_lint_pass!(Ranges => [ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Ranges { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(ref path, _, ref args) = expr.kind { + if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { let name = path.ident.as_str(); if name == "zip" && args.len() == 2 { let iter = &args[0].kind; let zip_arg = &args[1]; if_chain! { // `.iter()` call - if let ExprKind::MethodCall(ref iter_path, _, ref iter_args ) = *iter; + if let ExprKind::MethodCall(ref iter_path, _, ref iter_args , _) = *iter; if iter_path.ident.name == sym!(iter); // range expression in `.zip()` call: `0..x.len()` if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(cx, zip_arg); if is_integer_const(cx, start, 0); // `.len()` call - if let ExprKind::MethodCall(ref len_path, _, ref len_args) = end.kind; + if let ExprKind::MethodCall(ref len_path, _, ref len_args, _) = end.kind; if len_path.ident.name == sym!(len) && len_args.len() == 1; // `.iter()` and `.len()` called on same `Path` if let ExprKind::Path(QPath::Resolved(_, ref iter_path)) = iter_args[0].kind; @@ -241,14 +241,26 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { } fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { - fn inside_indexing_expr<'a>(cx: &'a LateContext<'_, '_>, expr: &Expr<'_>) -> Option<&'a Expr<'a>> { - match get_parent_expr(cx, expr) { - parent_expr @ Some(Expr { + fn inside_indexing_expr(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { + matches!( + get_parent_expr(cx, expr), + Some(Expr { kind: ExprKind::Index(..), .. - }) => parent_expr, - _ => None, + }) + ) + } + + fn is_for_loop_arg(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { + let mut cur_expr = expr; + while let Some(parent_expr) = get_parent_expr(cx, cur_expr) { + match higher::for_loop(parent_expr) { + Some((_, args, _)) if args.hir_id == expr.hir_id => return true, + _ => cur_expr = parent_expr, + } } + + false } fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool { @@ -267,34 +279,18 @@ fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx); if is_empty_range(limits, ordering); then { - if let Some(parent_expr) = inside_indexing_expr(cx, expr) { - let (reason, outcome) = if ordering == Ordering::Equal { - ("empty", "always yield an empty slice") - } else { - ("reversed", "panic at run-time") - }; - - span_lint_and_then( - cx, - REVERSED_EMPTY_RANGES, - expr.span, - &format!("this range is {} and using it to index a slice will {}", reason, outcome), - |diag| { - if_chain! { - if ordering == Ordering::Equal; - if let ty::Slice(slice_ty) = cx.tables.expr_ty(parent_expr).kind; - then { - diag.span_suggestion( - parent_expr.span, - "if you want an empty slice, use", - format!("[] as &[{}]", slice_ty), - Applicability::MaybeIncorrect - ); - } - } - } - ); - } else { + if inside_indexing_expr(cx, expr) { + // Avoid linting `N..N` as it has proven to be useful, see #5689 and #5628 ... + if ordering != Ordering::Equal { + span_lint( + cx, + REVERSED_EMPTY_RANGES, + expr.span, + "this range is reversed and using it to index a slice will panic at run-time", + ); + } + // ... except in for loop arguments for backwards compatibility with `reverse_range_loop` + } else if ordering != Ordering::Equal || is_for_loop_arg(cx, expr) { span_lint_and_then( cx, REVERSED_EMPTY_RANGES, diff --git a/src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs b/src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs index 7ee298e9833..f16b916441a 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pattern_matching.rs @@ -89,7 +89,7 @@ fn find_sugg_for_if_let<'a, 'tcx>( // check that `while_let_on_iterator` lint does not trigger if_chain! { if keyword == "while"; - if let ExprKind::MethodCall(method_path, _, _) = op.kind; + if let ExprKind::MethodCall(method_path, _, _, _) = op.kind; if method_path.ident.name == sym!(next); if match_trait_method(cx, op, &paths::ITERATOR); then { diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index d5797468e9d..fe457aad50e 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -16,8 +16,13 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust,ignore + /// // Bad /// let a = f(*&mut b); /// let c = *&d; + /// + /// // Good + /// let a = f(b); + /// let c = d; /// ``` pub DEREF_ADDROF, complexity, diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index 30084e3e1ff..a2c35c42673 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -86,11 +86,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Regex { if let Some(span) = is_expn_of(expr.span, "regex"); then { if !self.spans.contains(&span) { - span_lint(cx, - REGEX_MACRO, - span, - "`regex!(_)` found. \ - Please use `Regex::new(_)`, which is faster for now."); + span_lint( + cx, + REGEX_MACRO, + span, + "`regex!(_)` found. \ + Please use `Regex::new(_)`, which is faster for now." + ); self.spans.insert(span); } self.last = Some(block.hir_id); diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 35464f629c3..3c939744173 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; -use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{snippet_opt, span_lint_and_sugg, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for return statements at the end of a block. @@ -37,33 +37,6 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `let`-bindings, which are subsequently - /// returned. - /// - /// **Why is this bad?** It is just extraneous code. Remove it to make your code - /// more rusty. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust - /// fn foo() -> String { - /// let x = String::new(); - /// x - /// } - /// ``` - /// instead, use - /// ``` - /// fn foo() -> String { - /// String::new() - /// } - /// ``` - pub LET_AND_RETURN, - style, - "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block" -} - -declare_clippy_lint! { /// **What it does:** Checks for unit (`()`) expressions that can be removed. /// /// **Why is this bad?** Such expressions add no value, but can make the code @@ -90,7 +63,7 @@ enum RetReplacement { Block, } -declare_lint_pass!(Return => [NEEDLESS_RETURN, LET_AND_RETURN, UNUSED_UNIT]); +declare_lint_pass!(Return => [NEEDLESS_RETURN, UNUSED_UNIT]); impl Return { // Check the final stmt or expr in a block for unnecessary return. @@ -105,7 +78,7 @@ impl Return { } } - // Check a the final expression in a block if it's a return. + // Check the final expression in a block if it's a return. fn check_final_expr( &mut self, cx: &EarlyContext<'_>, @@ -186,54 +159,6 @@ impl Return { }, } } - - // Check for "let x = EXPR; x" - fn check_let_return(cx: &EarlyContext<'_>, block: &ast::Block) { - let mut it = block.stmts.iter(); - - // we need both a let-binding stmt and an expr - if_chain! { - if let Some(retexpr) = it.next_back(); - if let ast::StmtKind::Expr(ref retexpr) = retexpr.kind; - if let Some(stmt) = it.next_back(); - if let ast::StmtKind::Local(ref local) = stmt.kind; - // don't lint in the presence of type inference - if local.ty.is_none(); - if local.attrs.is_empty(); - if let Some(ref initexpr) = local.init; - if let ast::PatKind::Ident(_, ident, _) = local.pat.kind; - if let ast::ExprKind::Path(_, ref path) = retexpr.kind; - if match_path_ast(path, &[&*ident.name.as_str()]); - if !in_external_macro(cx.sess(), initexpr.span); - if !in_external_macro(cx.sess(), retexpr.span); - if !in_external_macro(cx.sess(), local.span); - if !in_macro(local.span); - then { - span_lint_and_then( - cx, - LET_AND_RETURN, - retexpr.span, - "returning the result of a `let` binding from a block", - |err| { - err.span_label(local.span, "unnecessary `let` binding"); - - if let Some(snippet) = snippet_opt(cx, initexpr.span) { - err.multipart_suggestion( - "return the expression directly", - vec![ - (local.span, String::new()), - (retexpr.span, snippet), - ], - Applicability::MachineApplicable, - ); - } else { - err.span_help(initexpr.span, "this expression can be directly returned"); - } - }, - ); - } - } - } } impl EarlyLintPass for Return { @@ -254,7 +179,6 @@ impl EarlyLintPass for Return { } fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { - Self::check_let_return(cx, block); if_chain! { if let Some(ref stmt) = block.stmts.last(); if let ast::StmtKind::Expr(ref expr) = stmt.kind; diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 11360b0ef84..68c36f91891 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -25,7 +25,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let x = 1; + /// + /// // Bad /// let x = &x; + /// + /// // Good + /// let y = &x; // use different variable name /// ``` pub SHADOW_SAME, restriction, @@ -77,7 +82,12 @@ declare_clippy_lint! { /// # let y = 1; /// # let z = 2; /// let x = y; + /// + /// // Bad /// let x = z; // shadows the earlier binding + /// + /// // Good + /// let w = z; // use different variable name /// ``` pub SHADOW_UNRELATED, pedantic, diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index 8d767a7fec8..2e853e8301d 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// /// **Example:** /// - /// ```rust, ignore + /// ```rust,ignore /// use regex; /// /// fn main() { @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Better as - /// ```rust, ignore + /// ```rust,ignore /// fn main() { /// regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); /// } diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index fb3706be1c2..44c9cc19cfb 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -22,11 +22,17 @@ declare_clippy_lint! { /// ```rust /// # use core::iter::repeat; /// # let len = 4; + /// + /// // Bad /// let mut vec1 = Vec::with_capacity(len); /// vec1.resize(len, 0); /// /// let mut vec2 = Vec::with_capacity(len); - /// vec2.extend(repeat(0).take(len)) + /// vec2.extend(repeat(0).take(len)); + /// + /// // Good + /// let mut vec1 = vec![0; len]; + /// let mut vec2 = vec![0; len]; /// ``` pub SLOW_VECTOR_INITIALIZATION, perf, @@ -201,7 +207,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) { if_chain! { if self.initialization_found; - if let ExprKind::MethodCall(ref path, _, ref args) = expr.kind; + if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; if let ExprKind::Path(ref qpath_subj) = args[0].kind; if match_qpath(&qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]); if path.ident.name == sym!(extend); @@ -218,7 +224,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) { if_chain! { if self.initialization_found; - if let ExprKind::MethodCall(ref path, _, ref args) = expr.kind; + if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; if let ExprKind::Path(ref qpath_subj) = args[0].kind; if match_qpath(&qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]); if path.ident.name == sym!(resize); @@ -240,7 +246,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&self, expr: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::MethodCall(ref take_path, _, ref take_args) = expr.kind; + if let ExprKind::MethodCall(ref take_path, _, ref take_args, _) = expr.kind; if take_path.ident.name == sym!(take); // Check that take is applied to `repeat(0)` diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 2c51271e312..d8e4bff3d70 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -24,6 +24,10 @@ declare_clippy_lint! { /// ```rust /// let mut x = "Hello".to_owned(); /// x = x + ", World"; + /// + /// // More readable + /// x += ", World"; + /// x.push_str(", World"); /// ``` pub STRING_ADD_ASSIGN, pedantic, @@ -69,7 +73,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// let bs = "a byte string".as_bytes(); + /// + /// // Good + /// let bs = b"a byte string"; /// ``` pub STRING_LIT_AS_BYTES, style, @@ -156,7 +164,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { use rustc_ast::ast::LitKind; if_chain! { - if let ExprKind::MethodCall(path, _, args) = &e.kind; + if let ExprKind::MethodCall(path, _, args, _) = &e.kind; if path.ident.name == sym!(as_bytes); if let ExprKind::Lit(lit) = &args[0].kind; if let LitKind::Str(lit_content, _) = &lit.node; diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs index f1e223d9a48..a9e6fa329c0 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs @@ -71,8 +71,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for SuspiciousImpl { if let hir::Node::Expr(e) = cx.tcx.hir().get(parent_expr) { match e.kind { hir::ExprKind::Binary(..) - | hir::ExprKind::Unary(hir::UnOp::UnNot, _) - | hir::ExprKind::Unary(hir::UnOp::UnNeg, _) + | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _) | hir::ExprKind::AssignOp(..) => return, _ => {}, } @@ -191,8 +190,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BinaryExprVisitor { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { match expr.kind { hir::ExprKind::Binary(..) - | hir::ExprKind::Unary(hir::UnOp::UnNot, _) - | hir::ExprKind::Unary(hir::UnOp::UnNeg, _) + | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _) | hir::ExprKind::AssignOp(..) => self.in_binary_expr = true, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs index c6302ca03d9..4f132c6db76 100644 --- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs @@ -34,12 +34,12 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ToDigitIsSome { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) { if_chain! { - if let hir::ExprKind::MethodCall(is_some_path, _, is_some_args) = &expr.kind; + if let hir::ExprKind::MethodCall(is_some_path, _, is_some_args, _) = &expr.kind; if is_some_path.ident.name.as_str() == "is_some"; if let [to_digit_expr] = &**is_some_args; then { let match_result = match &to_digit_expr.kind { - hir::ExprKind::MethodCall(to_digits_path, _, to_digit_args) => { + hir::ExprKind::MethodCall(to_digits_path, _, to_digit_args, _) => { if_chain! { if let [char_arg, radix_arg] = &**to_digit_args; if to_digits_path.ident.name.as_str() == "to_digit"; diff --git a/src/tools/clippy/clippy_lints/src/transmute.rs b/src/tools/clippy/clippy_lints/src/transmute.rs index e24d2c4f495..1869638f6ff 100644 --- a/src/tools/clippy/clippy_lints/src/transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute.rs @@ -312,7 +312,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { e.span, &format!("transmute from a type (`{}`) to itself", from_ty), ), - (&ty::Ref(_, rty, rty_mutbl), &ty::RawPtr(ptr_ty)) => span_lint_and_then( + (ty::Ref(_, rty, rty_mutbl), ty::RawPtr(ptr_ty)) => span_lint_and_then( cx, USELESS_TRANSMUTE, e.span, @@ -321,10 +321,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { let rty_and_mut = ty::TypeAndMut { ty: rty, - mutbl: rty_mutbl, + mutbl: *rty_mutbl, }; - let sugg = if ptr_ty == rty_and_mut { + let sugg = if *ptr_ty == rty_and_mut { arg.as_ty(to_ty) } else { arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty) @@ -334,7 +334,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { } }, ), - (&ty::Int(_), &ty::RawPtr(_)) | (&ty::Uint(_), &ty::RawPtr(_)) => span_lint_and_then( + (ty::Int(_) | ty::Uint(_), ty::RawPtr(_)) => span_lint_and_then( cx, USELESS_TRANSMUTE, e.span, @@ -350,16 +350,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { } }, ), - (&ty::Float(_), &ty::Ref(..)) - | (&ty::Float(_), &ty::RawPtr(_)) - | (&ty::Char, &ty::Ref(..)) - | (&ty::Char, &ty::RawPtr(_)) => span_lint( + (ty::Float(_) | ty::Char, ty::Ref(..) | ty::RawPtr(_)) => span_lint( cx, WRONG_TRANSMUTE, e.span, &format!("transmute from a `{}` to a pointer", from_ty), ), - (&ty::RawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint( + (ty::RawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint( cx, CROSSPOINTER_TRANSMUTE, e.span, @@ -368,7 +365,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { from_ty, to_ty ), ), - (_, &ty::RawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint( + (_, ty::RawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint( cx, CROSSPOINTER_TRANSMUTE, e.span, @@ -377,7 +374,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { from_ty, to_ty ), ), - (&ty::RawPtr(from_pty), &ty::Ref(_, to_ref_ty, mutbl)) => span_lint_and_then( + (ty::RawPtr(from_pty), ty::Ref(_, to_ref_ty, mutbl)) => span_lint_and_then( cx, TRANSMUTE_PTR_TO_REF, e.span, @@ -388,13 +385,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { ), |diag| { let arg = sugg::Sugg::hir(cx, &args[0], ".."); - let (deref, cast) = if mutbl == Mutability::Mut { + let (deref, cast) = if *mutbl == Mutability::Mut { ("&mut *", "*mut") } else { ("&*", "*const") }; - let arg = if from_pty.ty == to_ref_ty { + let arg = if from_pty.ty == *to_ref_ty { arg } else { arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_ref_ty))) @@ -408,7 +405,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { ); }, ), - (&ty::Int(ast::IntTy::I32), &ty::Char) | (&ty::Uint(ast::UintTy::U32), &ty::Char) => { + (ty::Int(ast::IntTy::I32) | ty::Uint(ast::UintTy::U32), &ty::Char) => { span_lint_and_then( cx, TRANSMUTE_INT_TO_CHAR, @@ -430,13 +427,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { }, ) }, - (&ty::Ref(_, ty_from, from_mutbl), &ty::Ref(_, ty_to, to_mutbl)) => { + (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) => { if_chain! { if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind, &ty_to.kind); if let ty::Uint(ast::UintTy::U8) = slice_ty.kind; if from_mutbl == to_mutbl; then { - let postfix = if from_mutbl == Mutability::Mut { + let postfix = if *from_mutbl == Mutability::Mut { "_mut" } else { "" @@ -465,13 +462,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { let ty_from_and_mut = ty::TypeAndMut { ty: ty_from, - mutbl: from_mutbl + mutbl: *from_mutbl }; - let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: to_mutbl }; + let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: *to_mutbl }; let sugg_paren = arg .as_ty(cx.tcx.mk_ptr(ty_from_and_mut)) .as_ty(cx.tcx.mk_ptr(ty_to_and_mut)); - let sugg = if to_mutbl == Mutability::Mut { + let sugg = if *to_mutbl == Mutability::Mut { sugg_paren.mut_addr_deref() } else { sugg_paren.addr_deref() @@ -488,19 +485,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { } } }, - (&ty::RawPtr(_), &ty::RawPtr(to_ty)) => span_lint_and_then( + (ty::RawPtr(_), ty::RawPtr(to_ty)) => span_lint_and_then( cx, TRANSMUTE_PTR_TO_PTR, e.span, "transmute from a pointer to a pointer", |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { - let sugg = arg.as_ty(cx.tcx.mk_ptr(to_ty)); + let sugg = arg.as_ty(cx.tcx.mk_ptr(*to_ty)); diag.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified); } }, ), - (&ty::Int(ast::IntTy::I8), &ty::Bool) | (&ty::Uint(ast::UintTy::U8), &ty::Bool) => { + (ty::Int(ast::IntTy::I8) | ty::Uint(ast::UintTy::U8), ty::Bool) => { span_lint_and_then( cx, TRANSMUTE_INT_TO_BOOL, @@ -518,7 +515,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { }, ) }, - (&ty::Int(_), &ty::Float(_)) | (&ty::Uint(_), &ty::Float(_)) => span_lint_and_then( + (ty::Int(_) | ty::Uint(_), ty::Float(_)) => span_lint_and_then( cx, TRANSMUTE_INT_TO_FLOAT, e.span, @@ -541,7 +538,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { ); }, ), - (&ty::Float(float_ty), &ty::Int(_)) | (&ty::Float(float_ty), &ty::Uint(_)) => span_lint_and_then( + (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) => span_lint_and_then( cx, TRANSMUTE_FLOAT_TO_INT, e.span, @@ -585,7 +582,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { ); }, ), - (&ty::Adt(ref from_adt, ref from_substs), &ty::Adt(ref to_adt, ref to_substs)) => { + (ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => { if from_adt.did != to_adt.did || !COLLECTIONS.iter().any(|path| match_def_path(cx, to_adt.did, path)) { return; diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs index 6ed9ff22e46..d59a2f1bae0 100644 --- a/src/tools/clippy/clippy_lints/src/types.rs +++ b/src/tools/clippy/clippy_lints/src/types.rs @@ -10,14 +10,14 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{ - BinOpKind, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, + BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TypeckTables}; +use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeckTables}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::Span; @@ -29,10 +29,10 @@ use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, in_constant, int_bits, is_type_diagnostic_item, + clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item, last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, - qpath_res, same_tys, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, - span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, + qpath_res, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, }; declare_clippy_lint! { @@ -778,25 +778,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { } match expr.kind { - ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args) => { - for arg in args { - if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) { - if let ExprKind::Match(.., match_source) = &arg.kind { - if *match_source == MatchSource::TryDesugar { - continue; + ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => { + let args_to_recover = args + .iter() + .filter(|arg| { + if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) { + if let ExprKind::Match(.., MatchSource::TryDesugar) = &arg.kind { + false + } else { + true } + } else { + false } - - span_lint_and_sugg( - cx, - UNIT_ARG, - arg.span, - "passing a unit value to a function", - "if you intended to pass a unit value, use a unit literal instead", - "()".to_string(), - Applicability::MaybeIncorrect, - ); - } + }) + .collect::<Vec<_>>(); + if !args_to_recover.is_empty() { + lint_unit_args(cx, expr, &args_to_recover); } }, _ => (), @@ -804,6 +802,101 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { } } +fn lint_unit_args(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { + let mut applicability = Applicability::MachineApplicable; + let (singular, plural) = if args_to_recover.len() > 1 { + ("", "s") + } else { + ("a ", "") + }; + span_lint_and_then( + cx, + UNIT_ARG, + expr.span, + &format!("passing {}unit value{} to a function", singular, plural), + |db| { + let mut or = ""; + args_to_recover + .iter() + .filter_map(|arg| { + if_chain! { + if let ExprKind::Block(block, _) = arg.kind; + if block.expr.is_none(); + if let Some(last_stmt) = block.stmts.iter().last(); + if let StmtKind::Semi(last_expr) = last_stmt.kind; + if let Some(snip) = snippet_opt(cx, last_expr.span); + then { + Some(( + last_stmt.span, + snip, + )) + } + else { + None + } + } + }) + .for_each(|(span, sugg)| { + db.span_suggestion( + span, + "remove the semicolon from the last statement in the block", + sugg, + Applicability::MaybeIncorrect, + ); + or = "or "; + }); + let sugg = args_to_recover + .iter() + .filter(|arg| !is_empty_block(arg)) + .enumerate() + .map(|(i, arg)| { + let indent = if i == 0 { + 0 + } else { + indent_of(cx, expr.span).unwrap_or(0) + }; + format!( + "{}{};", + " ".repeat(indent), + snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability) + ) + }) + .collect::<Vec<String>>(); + let mut and = ""; + if !sugg.is_empty() { + let plural = if sugg.len() > 1 { "s" } else { "" }; + db.span_suggestion( + expr.span.with_hi(expr.span.lo()), + &format!("{}move the expression{} in front of the call...", or, plural), + format!("{}\n", sugg.join("\n")), + applicability, + ); + and = "...and " + } + db.multipart_suggestion( + &format!("{}use {}unit literal{} instead", and, singular, plural), + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::<Vec<_>>(), + applicability, + ); + }, + ); +} + +fn is_empty_block(expr: &Expr<'_>) -> bool { + matches!( + expr.kind, + ExprKind::Block( + Block { + stmts: &[], expr: None, .. + }, + _, + ) + ) +} + fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::DesugaringKind; if let ExprKind::Call(ref callee, _) = expr.kind { @@ -974,7 +1067,8 @@ declare_clippy_lint! { /// behavior. /// /// **Known problems:** Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar - /// on the resulting pointer is fine. + /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like + /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. /// /// **Example:** /// ```rust @@ -982,7 +1076,7 @@ declare_clippy_lint! { /// let _ = (&mut 1u8 as *mut u8) as *mut u16; /// ``` pub CAST_PTR_ALIGNMENT, - correctness, + pedantic, "cast from a pointer to a more-strictly-aligned pointer" } @@ -1168,14 +1262,14 @@ fn check_loss_of_sign(cx: &LateContext<'_, '_>, expr: &Expr<'_>, op: &Expr<'_>, } // don't lint for the result of methods that always return non-negative values - if let ExprKind::MethodCall(ref path, _, _) = op.kind { + if let ExprKind::MethodCall(ref path, _, _, _) = op.kind { let mut method_name = path.ident.name.as_str(); let whitelisted_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"]; if_chain! { if method_name == "unwrap"; if let Some(arglist) = method_chain_args(op, &["unwrap"]); - if let ExprKind::MethodCall(ref inner_path, _, _) = &arglist[0][0].kind; + if let ExprKind::MethodCall(ref inner_path, _, _, _) = &arglist[0][0].kind; then { method_name = inner_path.ident.name.as_str(); } @@ -1852,18 +1946,18 @@ fn detect_extreme_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_ let which = match (&ty.kind, cv) { (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum, (&ty::Int(ity), Constant::Int(i)) - if i == unsext(cx.tcx, i128::min_value() >> (128 - int_bits(cx.tcx, ity)), ity) => + if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => { Minimum }, (&ty::Bool, Constant::Bool(true)) => Maximum, (&ty::Int(ity), Constant::Int(i)) - if i == unsext(cx.tcx, i128::max_value() >> (128 - int_bits(cx.tcx, ity)), ity) => + if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => { Maximum }, - (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::max_value(), uty) == i => Maximum, + (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::MAX, uty) == i => Maximum, _ => return None, }; @@ -1945,7 +2039,7 @@ impl FullInt { fn cmp_s_u(s: i128, u: u128) -> Ordering { if s < 0 { Ordering::Less - } else if u > (i128::max_value() as u128) { + } else if u > (i128::MAX as u128) { Ordering::Greater } else { (s as u128).cmp(&u) @@ -1990,48 +2084,48 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'_>) match pre_cast_ty.kind { ty::Int(int_ty) => Some(match int_ty { IntTy::I8 => ( - FullInt::S(i128::from(i8::min_value())), - FullInt::S(i128::from(i8::max_value())), + FullInt::S(i128::from(i8::MIN)), + FullInt::S(i128::from(i8::MAX)), ), IntTy::I16 => ( - FullInt::S(i128::from(i16::min_value())), - FullInt::S(i128::from(i16::max_value())), + FullInt::S(i128::from(i16::MIN)), + FullInt::S(i128::from(i16::MAX)), ), IntTy::I32 => ( - FullInt::S(i128::from(i32::min_value())), - FullInt::S(i128::from(i32::max_value())), + FullInt::S(i128::from(i32::MIN)), + FullInt::S(i128::from(i32::MAX)), ), IntTy::I64 => ( - FullInt::S(i128::from(i64::min_value())), - FullInt::S(i128::from(i64::max_value())), + FullInt::S(i128::from(i64::MIN)), + FullInt::S(i128::from(i64::MAX)), ), - IntTy::I128 => (FullInt::S(i128::min_value()), FullInt::S(i128::max_value())), + IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)), IntTy::Isize => ( - FullInt::S(isize::min_value() as i128), - FullInt::S(isize::max_value() as i128), + FullInt::S(isize::MIN as i128), + FullInt::S(isize::MAX as i128), ), }), ty::Uint(uint_ty) => Some(match uint_ty { UintTy::U8 => ( - FullInt::U(u128::from(u8::min_value())), - FullInt::U(u128::from(u8::max_value())), + FullInt::U(u128::from(u8::MIN)), + FullInt::U(u128::from(u8::MAX)), ), UintTy::U16 => ( - FullInt::U(u128::from(u16::min_value())), - FullInt::U(u128::from(u16::max_value())), + FullInt::U(u128::from(u16::MIN)), + FullInt::U(u128::from(u16::MAX)), ), UintTy::U32 => ( - FullInt::U(u128::from(u32::min_value())), - FullInt::U(u128::from(u32::max_value())), + FullInt::U(u128::from(u32::MIN)), + FullInt::U(u128::from(u32::MAX)), ), UintTy::U64 => ( - FullInt::U(u128::from(u64::min_value())), - FullInt::U(u128::from(u64::max_value())), + FullInt::U(u128::from(u64::MIN)), + FullInt::U(u128::from(u64::MAX)), ), - UintTy::U128 => (FullInt::U(u128::min_value()), FullInt::U(u128::max_value())), + UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)), UintTy::Usize => ( - FullInt::U(usize::min_value() as u128), - FullInt::U(usize::max_value() as u128), + FullInt::U(usize::MIN as u128), + FullInt::U(usize::MAX as u128), ), }), _ => None, @@ -2462,7 +2556,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.kind; if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind; then { - if !same_tys(self.cx, self.target.ty(), self.body.expr_ty(e)) { + if !TyS::same_type(self.target.ty(), self.body.expr_ty(e)) { return; } diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs new file mode 100644 index 00000000000..e94eebb88e4 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs @@ -0,0 +1,267 @@ +use crate::utils; +use crate::utils::paths; +use crate::utils::sugg::Sugg; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::Ident; + +declare_clippy_lint! { + /// **What it does:** + /// Detects when people use `Vec::sort_by` and pass in a function + /// which compares the two arguments, either directly or indirectly. + /// + /// **Why is this bad?** + /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if + /// possible) than to use `Vec::sort_by` and and a more complicated + /// closure. + /// + /// **Known problems:** + /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't + /// imported by a use statement in the current frame, then a `use` + /// statement that imports it will need to be added (which this lint + /// can't do). + /// + /// **Example:** + /// + /// ```rust + /// # struct A; + /// # impl A { fn foo(&self) {} } + /// # let mut vec: Vec<A> = Vec::new(); + /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); + /// ``` + /// Use instead: + /// ```rust + /// # struct A; + /// # impl A { fn foo(&self) {} } + /// # let mut vec: Vec<A> = Vec::new(); + /// vec.sort_by_key(|a| a.foo()); + /// ``` + pub UNNECESSARY_SORT_BY, + complexity, + "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" +} + +declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]); + +enum LintTrigger { + Sort(SortDetection), + SortByKey(SortByKeyDetection), +} + +struct SortDetection { + vec_name: String, + unstable: bool, +} + +struct SortByKeyDetection { + vec_name: String, + closure_arg: String, + closure_body: String, + reverse: bool, + unstable: bool, +} + +/// Detect if the two expressions are mirrored (identical, except one +/// contains a and the other replaces it with b) +fn mirrored_exprs( + cx: &LateContext<'_, '_>, + a_expr: &Expr<'_>, + a_ident: &Ident, + b_expr: &Expr<'_>, + b_ident: &Ident, +) -> bool { + match (&a_expr.kind, &b_expr.kind) { + // Two boxes with mirrored contents + (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => { + mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + }, + // Two arrays with mirrored contents + (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => left_exprs + .iter() + .zip(right_exprs.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + // The two exprs are function calls. + // Check to see that the function itself and its arguments are mirrored + (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => { + mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + && left_args + .iter() + .zip(right_args.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) + }, + // The two exprs are method calls. + // Check to see that the function is the same and the arguments are mirrored + // This is enough because the receiver of the method is listed in the arguments + (ExprKind::MethodCall(left_segment, _, left_args, _), ExprKind::MethodCall(right_segment, _, right_args, _)) => { + left_segment.ident == right_segment.ident + && left_args + .iter() + .zip(right_args.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) + }, + // Two tuples with mirrored contents + (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => left_exprs + .iter() + .zip(right_exprs.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + // Two binary ops, which are the same operation and which have mirrored arguments + (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => { + left_op.node == right_op.node + && mirrored_exprs(cx, left_left, a_ident, right_left, b_ident) + && mirrored_exprs(cx, left_right, a_ident, right_right, b_ident) + }, + // Two unary ops, which are the same operation and which have the same argument + (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => { + left_op == right_op && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + }, + // The two exprs are literals of some kind + (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node, + (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(cx, left, a_ident, right, b_ident), + (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => { + mirrored_exprs(cx, left_block, a_ident, right_block, b_ident) + }, + (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => { + left_ident.name == right_ident.name && mirrored_exprs(cx, left_expr, a_ident, right_expr, right_ident) + }, + // Two paths: either one is a and the other is b, or they're identical to each other + ( + ExprKind::Path(QPath::Resolved( + _, + Path { + segments: left_segments, + .. + }, + )), + ExprKind::Path(QPath::Resolved( + _, + Path { + segments: right_segments, + .. + }, + )), + ) => { + (left_segments + .iter() + .zip(right_segments.iter()) + .all(|(left, right)| left.ident == right.ident) + && left_segments + .iter() + .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident)) + || (left_segments.len() == 1 + && &left_segments[0].ident == a_ident + && right_segments.len() == 1 + && &right_segments[0].ident == b_ident) + }, + // Matching expressions, but one or both is borrowed + ( + ExprKind::AddrOf(left_kind, Mutability::Not, left_expr), + ExprKind::AddrOf(right_kind, Mutability::Not, right_expr), + ) => left_kind == right_kind && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => { + mirrored_exprs(cx, a_expr, a_ident, right_expr, b_ident) + }, + (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(cx, left_expr, a_ident, b_expr, b_ident), + _ => false, + } +} + +fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<LintTrigger> { + if_chain! { + if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind; + if let name = name_ident.ident.name.to_ident_string(); + if name == "sort_by" || name == "sort_unstable_by"; + if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; + if utils::match_type(cx, &cx.tables.expr_ty(vec), &paths::VEC); + if let closure_body = cx.tcx.hir().body(*closure_body_id); + if let &[ + Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, + Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } + ] = &closure_body.params; + if let ExprKind::MethodCall(method_path, _, [ref left_expr, ref right_expr], _) = &closure_body.value.kind; + if method_path.ident.name.to_ident_string() == "cmp"; + then { + let (closure_body, closure_arg, reverse) = if mirrored_exprs( + &cx, + &left_expr, + &left_ident, + &right_expr, + &right_ident + ) { + (Sugg::hir(cx, &left_expr, "..").to_string(), left_ident.name.to_string(), false) + } else if mirrored_exprs(&cx, &left_expr, &right_ident, &right_expr, &left_ident) { + (Sugg::hir(cx, &left_expr, "..").to_string(), right_ident.name.to_string(), true) + } else { + return None; + }; + let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); + let unstable = name == "sort_unstable_by"; + if_chain! { + if let ExprKind::Path(QPath::Resolved(_, Path { + segments: [PathSegment { ident: left_name, .. }], .. + })) = &left_expr.kind; + if left_name == left_ident; + then { + Some(LintTrigger::Sort(SortDetection { vec_name, unstable })) + } + else { + Some(LintTrigger::SortByKey(SortByKeyDetection { + vec_name, + unstable, + closure_arg, + closure_body, + reverse + })) + } + } + } else { + None + } + } +} + +impl LateLintPass<'_, '_> for UnnecessarySortBy { + fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + match detect_lint(cx, expr) { + Some(LintTrigger::SortByKey(trigger)) => utils::span_lint_and_sugg( + cx, + UNNECESSARY_SORT_BY, + expr.span, + "use Vec::sort_by_key here instead", + "try", + format!( + "{}.sort{}_by_key(|&{}| {})", + trigger.vec_name, + if trigger.unstable { "_unstable" } else { "" }, + trigger.closure_arg, + if trigger.reverse { + format!("Reverse({})", trigger.closure_body) + } else { + trigger.closure_body.to_string() + }, + ), + if trigger.reverse { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }, + ), + Some(LintTrigger::Sort(trigger)) => utils::span_lint_and_sugg( + cx, + UNNECESSARY_SORT_BY, + expr.span, + "use Vec::sort here instead", + "try", + format!( + "{}.sort{}()", + trigger.vec_name, + if trigger.unstable { "_unstable" } else { "" }, + ), + Applicability::MachineApplicable, + ), + None => {}, + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs new file mode 100644 index 00000000000..8c281126c32 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -0,0 +1,407 @@ +#![allow(clippy::wildcard_imports, clippy::enum_glob_use)] + +use crate::utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path}; +use crate::utils::{over, span_lint_and_then}; +use rustc_ast::ast::{self, Pat, PatKind, PatKind::*, DUMMY_NODE_ID}; +use rustc_ast::mut_visit::*; +use rustc_ast::ptr::P; +use rustc_ast_pretty::pprust; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::DUMMY_SP; + +use std::cell::Cell; +use std::mem; + +declare_clippy_lint! { + /// **What it does:** + /// + /// Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and + /// suggests replacing the pattern with a nested one, `Some(0 | 2)`. + /// + /// Another way to think of this is that it rewrites patterns in + /// *disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*. + /// + /// **Why is this bad?** + /// + /// In the example above, `Some` is repeated, which unncessarily complicates the pattern. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// fn main() { + /// if let Some(0) | Some(2) = Some(0) {} + /// } + /// ``` + /// Use instead: + /// ```rust + /// #![feature(or_patterns)] + /// + /// fn main() { + /// if let Some(0 | 2) = Some(0) {} + /// } + /// ``` + pub UNNESTED_OR_PATTERNS, + complexity, + "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`" +} + +declare_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]); + +impl EarlyLintPass for UnnestedOrPatterns { + fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) { + lint_unnested_or_patterns(cx, &a.pat); + } + + fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { + if let ast::ExprKind::Let(pat, _) = &e.kind { + lint_unnested_or_patterns(cx, pat); + } + } + + fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) { + lint_unnested_or_patterns(cx, &p.pat); + } + + fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) { + lint_unnested_or_patterns(cx, &l.pat); + } +} + +fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) { + if !cx.sess.opts.unstable_features.is_nightly_build() { + // User cannot do `#![feature(or_patterns)]`, so bail. + return; + } + + if let Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind { + // This is a leaf pattern, so cloning is unprofitable. + return; + } + + let mut pat = P(pat.clone()); + + // Nix all the paren patterns everywhere so that they aren't in our way. + remove_all_parens(&mut pat); + + // Transform all unnested or-patterns into nested ones, and if there were none, quit. + if !unnest_or_patterns(&mut pat) { + return; + } + + span_lint_and_then(cx, UNNESTED_OR_PATTERNS, pat.span, "unnested or-patterns", |db| { + insert_necessary_parens(&mut pat); + db.span_suggestion_verbose( + pat.span, + "nest the patterns", + pprust::pat_to_string(&pat), + Applicability::MachineApplicable, + ); + }); +} + +/// Remove all `(p)` patterns in `pat`. +fn remove_all_parens(pat: &mut P<Pat>) { + struct Visitor; + impl MutVisitor for Visitor { + fn visit_pat(&mut self, pat: &mut P<Pat>) { + noop_visit_pat(pat, self); + let inner = match &mut pat.kind { + Paren(i) => mem::replace(&mut i.kind, Wild), + _ => return, + }; + pat.kind = inner; + } + } + Visitor.visit_pat(pat); +} + +/// Insert parens where necessary according to Rust's precedence rules for patterns. +fn insert_necessary_parens(pat: &mut P<Pat>) { + struct Visitor; + impl MutVisitor for Visitor { + fn visit_pat(&mut self, pat: &mut P<Pat>) { + use ast::{BindingMode::*, Mutability::*}; + noop_visit_pat(pat, self); + let target = match &mut pat.kind { + // `i @ a | b`, `box a | b`, and `& mut? a | b`. + Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p, + Ref(p, Not) if matches!(p.kind, Ident(ByValue(Mut), ..)) => p, // `&(mut x)` + _ => return, + }; + target.kind = Paren(P(take_pat(target))); + } + } + Visitor.visit_pat(pat); +} + +/// Unnest or-patterns `p0 | ... | p1` in the pattern `pat`. +/// For example, this would transform `Some(0) | FOO | Some(2)` into `Some(0 | 2) | FOO`. +fn unnest_or_patterns(pat: &mut P<Pat>) -> bool { + struct Visitor { + changed: bool, + } + impl MutVisitor for Visitor { + fn visit_pat(&mut self, p: &mut P<Pat>) { + // This is a bottom up transformation, so recurse first. + noop_visit_pat(p, self); + + // Don't have an or-pattern? Just quit early on. + let alternatives = match &mut p.kind { + Or(ps) => ps, + _ => return, + }; + + // Collapse or-patterns directly nested in or-patterns. + let mut idx = 0; + let mut this_level_changed = false; + while idx < alternatives.len() { + let inner = if let Or(ps) = &mut alternatives[idx].kind { + mem::take(ps) + } else { + idx += 1; + continue; + }; + this_level_changed = true; + alternatives.splice(idx..=idx, inner); + } + + // Focus on `p_n` and then try to transform all `p_i` where `i > n`. + let mut focus_idx = 0; + while focus_idx < alternatives.len() { + this_level_changed |= transform_with_focus_on_idx(alternatives, focus_idx); + focus_idx += 1; + } + self.changed |= this_level_changed; + + // Deal with `Some(Some(0)) | Some(Some(1))`. + if this_level_changed { + noop_visit_pat(p, self); + } + } + } + + let mut visitor = Visitor { changed: false }; + visitor.visit_pat(pat); + visitor.changed +} + +/// Match `$scrutinee` against `$pat` and extract `$then` from it. +/// Panics if there is no match. +macro_rules! always_pat { + ($scrutinee:expr, $pat:pat => $then:expr) => { + match $scrutinee { + $pat => $then, + _ => unreachable!(), + } + }; +} + +/// Focus on `focus_idx` in `alternatives`, +/// attempting to extend it with elements of the same constructor `C` +/// in `alternatives[focus_idx + 1..]`. +fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize) -> bool { + // Extract the kind; we'll need to make some changes in it. + let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, PatKind::Wild); + // We'll focus on `alternatives[focus_idx]`, + // so we're draining from `alternatives[focus_idx + 1..]`. + let start = focus_idx + 1; + + // We're trying to find whatever kind (~"constructor") we found in `alternatives[start..]`. + let changed = match &mut focus_kind { + // These pattern forms are "leafs" and do not have sub-patterns. + // Therefore they are not some form of constructor `C`, + // with which a pattern `C(p_0)` may be formed, + // which we would want to join with other `C(p_j)`s. + Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) + // Dealt with elsewhere. + | Or(_) | Paren(_) => false, + // Transform `box x | ... | box y` into `box (x | y)`. + // + // The cases below until `Slice(...)` deal with *singleton* products. + // These patterns have the shape `C(p)`, and not e.g., `C(p0, ..., pn)`. + Box(target) => extend_with_matching( + target, start, alternatives, + |k| matches!(k, Box(_)), + |k| always_pat!(k, Box(p) => p), + ), + // Transform `&m x | ... | &m y` into `&m (x | y)`. + Ref(target, m1) => extend_with_matching( + target, start, alternatives, + |k| matches!(k, Ref(_, m2) if m1 == m2), // Mutabilities must match. + |k| always_pat!(k, Ref(p, _) => p), + ), + // Transform `b @ p0 | ... b @ p1` into `b @ (p0 | p1)`. + Ident(b1, i1, Some(target)) => extend_with_matching( + target, start, alternatives, + // Binding names must match. + |k| matches!(k, Ident(b2, i2, Some(_)) if b1 == b2 && eq_id(*i1, *i2)), + |k| always_pat!(k, Ident(_, _, Some(p)) => p), + ), + // Transform `[pre, x, post] | ... | [pre, y, post]` into `[pre, x | y, post]`. + Slice(ps1) => extend_with_matching_product( + ps1, start, alternatives, + |k, ps1, idx| matches!(k, Slice(ps2) if eq_pre_post(ps1, ps2, idx)), + |k| always_pat!(k, Slice(ps) => ps), + ), + // Transform `(pre, x, post) | ... | (pre, y, post)` into `(pre, x | y, post)`. + Tuple(ps1) => extend_with_matching_product( + ps1, start, alternatives, + |k, ps1, idx| matches!(k, Tuple(ps2) if eq_pre_post(ps1, ps2, idx)), + |k| always_pat!(k, Tuple(ps) => ps), + ), + // Transform `S(pre, x, post) | ... | S(pre, y, post)` into `S(pre, x | y, post)`. + TupleStruct(path1, ps1) => extend_with_matching_product( + ps1, start, alternatives, + |k, ps1, idx| matches!( + k, + TupleStruct(path2, ps2) if eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx) + ), + |k| always_pat!(k, TupleStruct(_, ps) => ps), + ), + // Transform a record pattern `S { fp_0, ..., fp_n }`. + Struct(path1, fps1, rest1) => extend_with_struct_pat(path1, fps1, *rest1, start, alternatives), + }; + + alternatives[focus_idx].kind = focus_kind; + changed +} + +/// Here we focusing on a record pattern `S { fp_0, ..., fp_n }`. +/// In particular, for a record pattern, the order in which the field patterns is irrelevant. +/// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern +/// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal. +fn extend_with_struct_pat( + path1: &ast::Path, + fps1: &mut Vec<ast::FieldPat>, + rest1: bool, + start: usize, + alternatives: &mut Vec<P<Pat>>, +) -> bool { + (0..fps1.len()).any(|idx| { + let pos_in_2 = Cell::new(None); // The element `k`. + let tail_or = drain_matching( + start, + alternatives, + |k| { + matches!(k, Struct(path2, fps2, rest2) + if rest1 == *rest2 // If one struct pattern has `..` so must the other. + && eq_path(path1, path2) + && fps1.len() == fps2.len() + && fps1.iter().enumerate().all(|(idx_1, fp1)| { + if idx_1 == idx { + // In the case of `k`, we merely require identical field names + // so that we will transform into `ident_k: p1_k | p2_k`. + let pos = fps2.iter().position(|fp2| eq_id(fp1.ident, fp2.ident)); + pos_in_2.set(pos); + pos.is_some() + } else { + fps2.iter().any(|fp2| eq_field_pat(fp1, fp2)) + } + })) + }, + // Extract `p2_k`. + |k| always_pat!(k, Struct(_, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat), + ); + extend_with_tail_or(&mut fps1[idx].pat, tail_or) + }) +} + +/// Like `extend_with_matching` but for products with > 1 factor, e.g., `C(p_0, ..., p_n)`. +/// Here, the idea is that we fixate on some `p_k` in `C`, +/// allowing it to vary between two `targets` and `ps2` (returned by `extract`), +/// while also requiring `ps1[..n] ~ ps2[..n]` (pre) and `ps1[n + 1..] ~ ps2[n + 1..]` (post), +/// where `~` denotes semantic equality. +fn extend_with_matching_product( + targets: &mut Vec<P<Pat>>, + start: usize, + alternatives: &mut Vec<P<Pat>>, + predicate: impl Fn(&PatKind, &[P<Pat>], usize) -> bool, + extract: impl Fn(PatKind) -> Vec<P<Pat>>, +) -> bool { + (0..targets.len()).any(|idx| { + let tail_or = drain_matching( + start, + alternatives, + |k| predicate(k, targets, idx), + |k| extract(k).swap_remove(idx), + ); + extend_with_tail_or(&mut targets[idx], tail_or) + }) +} + +/// Extract the pattern from the given one and replace it with `Wild`. +/// This is meant for temporarily swapping out the pattern for manipulation. +fn take_pat(from: &mut Pat) -> Pat { + let dummy = Pat { + id: DUMMY_NODE_ID, + kind: Wild, + span: DUMMY_SP, + }; + mem::replace(from, dummy) +} + +/// Extend `target` as an or-pattern with the alternatives +/// in `tail_or` if there are any and return if there were. +fn extend_with_tail_or(target: &mut Pat, tail_or: Vec<P<Pat>>) -> bool { + fn extend(target: &mut Pat, mut tail_or: Vec<P<Pat>>) { + match target { + // On an existing or-pattern in the target, append to it. + Pat { kind: Or(ps), .. } => ps.append(&mut tail_or), + // Otherwise convert the target to an or-pattern. + target => { + let mut init_or = vec![P(take_pat(target))]; + init_or.append(&mut tail_or); + target.kind = Or(init_or); + }, + } + } + + let changed = !tail_or.is_empty(); + if changed { + // Extend the target. + extend(target, tail_or); + } + changed +} + +// Extract all inner patterns in `alternatives` matching our `predicate`. +// Only elements beginning with `start` are considered for extraction. +fn drain_matching( + start: usize, + alternatives: &mut Vec<P<Pat>>, + predicate: impl Fn(&PatKind) -> bool, + extract: impl Fn(PatKind) -> P<Pat>, +) -> Vec<P<Pat>> { + let mut tail_or = vec![]; + let mut idx = 0; + for pat in alternatives.drain_filter(|p| { + // Check if we should extract, but only if `idx >= start`. + idx += 1; + idx > start && predicate(&p.kind) + }) { + tail_or.push(extract(pat.into_inner().kind)); + } + tail_or +} + +fn extend_with_matching( + target: &mut Pat, + start: usize, + alternatives: &mut Vec<P<Pat>>, + predicate: impl Fn(&PatKind) -> bool, + extract: impl Fn(PatKind) -> P<Pat>, +) -> bool { + extend_with_tail_or(target, drain_matching(start, alternatives, predicate, extract)) +} + +/// Are the patterns in `ps1` and `ps2` equal save for `ps1[idx]` compared to `ps2[idx]`? +fn eq_pre_post(ps1: &[P<Pat>], ps2: &[P<Pat>], idx: usize) -> bool { + ps1[idx].is_rest() == ps2[idx].is_rest() // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`. + && ps1.len() == ps2.len() + && over(&ps1[..idx], &ps2[..idx], |l, r| eq_pat(l, r)) + && over(&ps1[idx + 1..], &ps2[idx + 1..], |l, r| eq_pat(l, r)) +} diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index b85134e3d7a..5f4b5fd9dd9 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -52,7 +52,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedIoAmount { } }, - hir::ExprKind::MethodCall(ref path, _, ref args) => match &*path.ident.as_str() { + hir::ExprKind::MethodCall(ref path, _, ref args, _) => match &*path.ident.as_str() { "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { check_method_call(cx, &args[0], expr); }, @@ -65,7 +65,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedIoAmount { } fn check_method_call(cx: &LateContext<'_, '_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { - if let hir::ExprKind::MethodCall(ref path, _, _) = call.kind { + if let hir::ExprKind::MethodCall(ref path, _, _, _) = call.kind { let symbol = &*path.ident.as_str(); let read_trait = match_trait_method(cx, call, &paths::IO_READ); let write_trait = match_trait_method(cx, call, &paths::IO_WRITE); diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 8b971e7064b..a6c7b5d405c 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -101,7 +101,7 @@ fn collect_unwrap_info<'a, 'tcx>( if let ExprKind::Binary(op, left, right) = &expr.kind { match (invert, op.node) { - (false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => { + (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) => { let mut unwrap_info = collect_unwrap_info(cx, left, branch, invert); unwrap_info.append(&mut collect_unwrap_info(cx, right, branch, invert)); return unwrap_info; @@ -112,7 +112,7 @@ fn collect_unwrap_info<'a, 'tcx>( return collect_unwrap_info(cx, expr, branch, !invert); } else { if_chain! { - if let ExprKind::MethodCall(method_name, _, args) = &expr.kind; + if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind; if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind; let ty = cx.tables.expr_ty(&args[0]); let name = method_name.ident.as_str(); @@ -166,7 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { } else { // find `unwrap[_err]()` calls: if_chain! { - if let ExprKind::MethodCall(ref method_name, _, ref args) = expr.kind; + if let ExprKind::MethodCall(ref method_name, _, ref args, _) = expr.kind; if let ExprKind::Path(QPath::Resolved(None, ref path)) = args[0].kind; if [sym!(unwrap), sym!(unwrap_err)].contains(&method_name.ident.name); let call_to_unwrap = method_name.ident.name == sym!(unwrap); diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 7fa97b24699..78d249482d5 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -1,12 +1,12 @@ use crate::utils::{ - is_type_diagnostic_item, match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, + is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet, snippet_with_macro_callsite, span_lint_and_help, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::ty::{self, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { @@ -61,11 +61,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { } }, - ExprKind::MethodCall(ref name, .., ref args) => { + ExprKind::MethodCall(ref name, .., ref args, _) => { if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" { let a = cx.tables.expr_ty(e); let b = cx.tables.expr_ty(&args[0]); - if same_tys(cx, a, b) { + if TyS::same_type(a, b) { let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string(); span_lint_and_sugg( cx, @@ -81,7 +81,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" { let a = cx.tables.expr_ty(e); let b = cx.tables.expr_ty(&args[0]); - if same_tys(cx, a, b) { + if TyS::same_type(a, b) { let sugg = snippet(cx, args[0].span, "<expr>").into_owned(); span_lint_and_sugg( cx, @@ -101,7 +101,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { if is_type_diagnostic_item(cx, a, sym!(result_type)); if let ty::Adt(_, substs) = a.kind; if let Some(a_type) = substs.types().next(); - if same_tys(cx, a_type, b); + if TyS::same_type(a_type, b); then { span_lint_and_help( @@ -131,7 +131,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { if is_type_diagnostic_item(cx, a, sym!(result_type)); if let ty::Adt(_, substs) = a.kind; if let Some(a_type) = substs.types().next(); - if same_tys(cx, a_type, b); + if TyS::same_type(a_type, b); then { let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from")); @@ -148,7 +148,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { if_chain! { if match_def_path(cx, def_id, &paths::FROM_FROM); - if same_tys(cx, a, b); + if TyS::same_type(a, b); then { let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned(); diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs new file mode 100755 index 00000000000..e60e2a81e07 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -0,0 +1,526 @@ +//! Utilities for manipulating and extracting information from `rustc_ast::ast`. +//! +//! - The `eq_foobar` functions test for semantic equality but ignores `NodeId`s and `Span`s. + +#![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)] + +use crate::utils::{both, over}; +use rustc_ast::ast::{self, *}; +use rustc_ast::ptr::P; +use rustc_span::symbol::Ident; +use std::mem; + +/// Checks if each element in the first slice is contained within the latter as per `eq_fn`. +pub fn unordered_over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { + left.len() == right.len() && left.iter().all(|l| right.iter().any(|r| eq_fn(l, r))) +} + +pub fn eq_id(l: Ident, r: Ident) -> bool { + l.name == r.name +} + +pub fn eq_pat(l: &Pat, r: &Pat) -> bool { + use PatKind::*; + match (&l.kind, &r.kind) { + (Paren(l), _) => eq_pat(l, r), + (_, Paren(r)) => eq_pat(l, r), + (Wild, Wild) | (Rest, Rest) => true, + (Lit(l), Lit(r)) => eq_expr(l, r), + (Ident(b1, i1, s1), Ident(b2, i2, s2)) => b1 == b2 && eq_id(*i1, *i2) && both(s1, s2, |l, r| eq_pat(l, r)), + (Range(lf, lt, le), Range(rf, rt, re)) => { + eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt) && eq_range_end(&le.node, &re.node) + }, + (Box(l), Box(r)) + | (Ref(l, Mutability::Not), Ref(r, Mutability::Not)) + | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r), + (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)), + (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), + (TupleStruct(lp, lfs), TupleStruct(rp, rfs)) => eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)), + (Struct(lp, lfs, lr), Struct(rp, rfs, rr)) => { + lr == rr && eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf)) + }, + (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)), + (MacCall(l), MacCall(r)) => eq_mac_call(l, r), + _ => false, + } +} + +pub fn eq_range_end(l: &RangeEnd, r: &RangeEnd) -> bool { + match (l, r) { + (RangeEnd::Excluded, RangeEnd::Excluded) => true, + (RangeEnd::Included(l), RangeEnd::Included(r)) => { + matches!(l, RangeSyntax::DotDotEq) == matches!(r, RangeSyntax::DotDotEq) + }, + _ => false, + } +} + +pub fn eq_field_pat(l: &FieldPat, r: &FieldPat) -> bool { + l.is_placeholder == r.is_placeholder + && eq_id(l.ident, r.ident) + && eq_pat(&l.pat, &r.pat) + && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) +} + +pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool { + l.position == r.position && eq_ty(&l.ty, &r.ty) +} + +pub fn eq_path(l: &Path, r: &Path) -> bool { + over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r)) +} + +pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool { + eq_id(l.ident, r.ident) && both(&l.args, &r.args, |l, r| eq_generic_args(l, r)) +} + +pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool { + match (l, r) { + (GenericArgs::AngleBracketed(l), GenericArgs::AngleBracketed(r)) => { + over(&l.args, &r.args, |l, r| eq_angle_arg(l, r)) + }, + (GenericArgs::Parenthesized(l), GenericArgs::Parenthesized(r)) => { + over(&l.inputs, &r.inputs, |l, r| eq_ty(l, r)) && eq_fn_ret_ty(&l.output, &r.output) + }, + _ => false, + } +} + +pub fn eq_angle_arg(l: &AngleBracketedArg, r: &AngleBracketedArg) -> bool { + match (l, r) { + (AngleBracketedArg::Arg(l), AngleBracketedArg::Arg(r)) => eq_generic_arg(l, r), + (AngleBracketedArg::Constraint(l), AngleBracketedArg::Constraint(r)) => eq_assoc_constraint(l, r), + _ => false, + } +} + +pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool { + match (l, r) { + (GenericArg::Lifetime(l), GenericArg::Lifetime(r)) => eq_id(l.ident, r.ident), + (GenericArg::Type(l), GenericArg::Type(r)) => eq_ty(l, r), + (GenericArg::Const(l), GenericArg::Const(r)) => eq_expr(&l.value, &r.value), + _ => false, + } +} + +pub fn eq_expr_opt(l: &Option<P<Expr>>, r: &Option<P<Expr>>) -> bool { + both(l, r, |l, r| eq_expr(l, r)) +} + +pub fn eq_expr(l: &Expr, r: &Expr) -> bool { + use ExprKind::*; + if !over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) { + return false; + } + match (&l.kind, &r.kind) { + (Paren(l), _) => eq_expr(l, r), + (_, Paren(r)) => eq_expr(l, r), + (Err, Err) => true, + (Box(l), Box(r)) | (Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r), + (Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), + (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value), + (Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)), + (MethodCall(lc, la, _), MethodCall(rc, ra, _)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)), + (Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr), + (Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r), + (Lit(l), Lit(r)) => l.kind == r.kind, + (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt), + (Let(lp, le), Let(rp, re)) => eq_pat(lp, rp) && eq_expr(le, re), + (If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re), + (While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt), + (ForLoop(lp, li, lt, ll), ForLoop(rp, ri, rt, rl)) => { + eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) + }, + (Loop(lt, ll), Loop(rt, rl)) => eq_label(ll, rl) && eq_block(lt, rt), + (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb), + (TryBlock(l), TryBlock(r)) => eq_block(l, r), + (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r), + (Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re), + (Continue(ll), Continue(rl)) => eq_label(ll, rl), + (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2), Index(r1, r2)) => eq_expr(l1, r1) && eq_expr(l2, r2), + (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv), + (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp), + (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, |l, r| eq_arm(l, r)), + (Closure(lc, la, lm, lf, lb, _), Closure(rc, ra, rm, rf, rb, _)) => { + lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(lb, rb) + }, + (Async(lc, _, lb), Async(rc, _, rb)) => lc == rc && eq_block(lb, rb), + (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt), + (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re), + (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), + (MacCall(l), MacCall(r)) => eq_mac_call(l, r), + (Struct(lp, lfs, lb), Struct(rp, rfs, rb)) => { + eq_path(lp, rp) && eq_expr_opt(lb, rb) && unordered_over(lfs, rfs, |l, r| eq_field(l, r)) + }, + _ => false, + } +} + +pub fn eq_field(l: &Field, r: &Field) -> bool { + l.is_placeholder == r.is_placeholder + && eq_id(l.ident, r.ident) + && eq_expr(&l.expr, &r.expr) + && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) +} + +pub fn eq_arm(l: &Arm, r: &Arm) -> bool { + l.is_placeholder == r.is_placeholder + && eq_pat(&l.pat, &r.pat) + && eq_expr(&l.body, &r.body) + && eq_expr_opt(&l.guard, &r.guard) + && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) +} + +pub fn eq_label(l: &Option<Label>, r: &Option<Label>) -> bool { + both(l, r, |l, r| eq_id(l.ident, r.ident)) +} + +pub fn eq_block(l: &Block, r: &Block) -> bool { + l.rules == r.rules && over(&l.stmts, &r.stmts, |l, r| eq_stmt(l, r)) +} + +pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool { + use StmtKind::*; + match (&l.kind, &r.kind) { + (Local(l), Local(r)) => { + eq_pat(&l.pat, &r.pat) + && both(&l.ty, &r.ty, |l, r| eq_ty(l, r)) + && eq_expr_opt(&l.init, &r.init) + && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + }, + (Item(l), Item(r)) => eq_item(l, r, eq_item_kind), + (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r), + (Empty, Empty) => true, + (MacCall(l), MacCall(r)) => l.1 == r.1 && eq_mac_call(&l.0, &r.0) && over(&l.2, &r.2, |l, r| eq_attr(l, r)), + _ => false, + } +} + +pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> bool) -> bool { + eq_id(l.ident, r.ident) + && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + && eq_vis(&l.vis, &r.vis) + && eq_kind(&l.kind, &r.kind) +} + +pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { + use ItemKind::*; + match (l, r) { + (ExternCrate(l), ExternCrate(r)) => l == r, + (Use(l), Use(r)) => eq_use_tree(l, r), + (Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Fn(ld, lf, lg, lb), Fn(rd, rf, rg, rb)) => { + eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r)) + }, + (Mod(l), Mod(r)) => l.inline == r.inline && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_item_kind)), + (ForeignMod(l), ForeignMod(r)) => { + both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r)) + && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind)) + }, + (TyAlias(ld, lg, lb, lt), TyAlias(rd, rg, rb, rt)) => { + eq_defaultness(*ld, *rd) + && eq_generics(lg, rg) + && over(lb, rb, |l, r| eq_generic_bound(l, r)) + && both(lt, rt, |l, r| eq_ty(l, r)) + }, + (Enum(le, lg), Enum(re, rg)) => { + over(&le.variants, &re.variants, |l, r| eq_variant(l, r)) && eq_generics(lg, rg) + }, + (Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => { + eq_variant_data(lv, rv) && eq_generics(lg, rg) + }, + (Trait(la, lu, lg, lb, li), Trait(ra, ru, rg, rb, ri)) => { + la == ra + && matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No) + && eq_generics(lg, rg) + && over(lb, rb, |l, r| eq_generic_bound(l, r)) + && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind)) + }, + (TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, |l, r| eq_generic_bound(l, r)), + ( + Impl { + unsafety: lu, + polarity: lp, + defaultness: ld, + constness: lc, + generics: lg, + of_trait: lot, + self_ty: lst, + items: li, + }, + Impl { + unsafety: ru, + polarity: rp, + defaultness: rd, + constness: rc, + generics: rg, + of_trait: rot, + self_ty: rst, + items: ri, + }, + ) => { + matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No) + && matches!(lp, ImplPolarity::Positive) == matches!(rp, ImplPolarity::Positive) + && eq_defaultness(*ld, *rd) + && matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No) + && eq_generics(lg, rg) + && both(lot, rot, |l, r| eq_path(&l.path, &r.path)) + && eq_ty(lst, rst) + && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind)) + }, + (MacCall(l), MacCall(r)) => eq_mac_call(l, r), + (MacroDef(l), MacroDef(r)) => l.macro_rules == r.macro_rules && eq_mac_args(&l.body, &r.body), + _ => false, + } +} + +pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { + use ForeignItemKind::*; + match (l, r) { + (Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Fn(ld, lf, lg, lb), Fn(rd, rf, rg, rb)) => { + eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r)) + }, + (TyAlias(ld, lg, lb, lt), TyAlias(rd, rg, rb, rt)) => { + eq_defaultness(*ld, *rd) + && eq_generics(lg, rg) + && over(lb, rb, |l, r| eq_generic_bound(l, r)) + && both(lt, rt, |l, r| eq_ty(l, r)) + }, + (MacCall(l), MacCall(r)) => eq_mac_call(l, r), + _ => false, + } +} + +pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { + use AssocItemKind::*; + match (l, r) { + (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re), + (Fn(ld, lf, lg, lb), Fn(rd, rf, rg, rb)) => { + eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r)) + }, + (TyAlias(ld, lg, lb, lt), TyAlias(rd, rg, rb, rt)) => { + eq_defaultness(*ld, *rd) + && eq_generics(lg, rg) + && over(lb, rb, |l, r| eq_generic_bound(l, r)) + && both(lt, rt, |l, r| eq_ty(l, r)) + }, + (MacCall(l), MacCall(r)) => eq_mac_call(l, r), + _ => false, + } +} + +pub fn eq_variant(l: &Variant, r: &Variant) -> bool { + l.is_placeholder == r.is_placeholder + && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + && eq_vis(&l.vis, &r.vis) + && eq_id(l.ident, r.ident) + && eq_variant_data(&l.data, &r.data) + && both(&l.disr_expr, &r.disr_expr, |l, r| eq_expr(&l.value, &r.value)) +} + +pub fn eq_variant_data(l: &VariantData, r: &VariantData) -> bool { + use VariantData::*; + match (l, r) { + (Unit(_), Unit(_)) => true, + (Struct(l, _), Struct(r, _)) | (Tuple(l, _), Tuple(r, _)) => over(l, r, |l, r| eq_struct_field(l, r)), + _ => false, + } +} + +pub fn eq_struct_field(l: &StructField, r: &StructField) -> bool { + l.is_placeholder == r.is_placeholder + && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + && eq_vis(&l.vis, &r.vis) + && both(&l.ident, &r.ident, |l, r| eq_id(*l, *r)) + && eq_ty(&l.ty, &r.ty) +} + +pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool { + eq_fn_decl(&l.decl, &r.decl) && eq_fn_header(&l.header, &r.header) +} + +pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool { + matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No) + && l.asyncness.is_async() == r.asyncness.is_async() + && matches!(l.constness, Const::No) == matches!(r.constness, Const::No) + && eq_ext(&l.ext, &r.ext) +} + +pub fn eq_generics(l: &Generics, r: &Generics) -> bool { + over(&l.params, &r.params, |l, r| eq_generic_param(l, r)) + && over(&l.where_clause.predicates, &r.where_clause.predicates, |l, r| { + eq_where_predicate(l, r) + }) +} + +pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool { + use WherePredicate::*; + match (l, r) { + (BoundPredicate(l), BoundPredicate(r)) => { + over(&l.bound_generic_params, &r.bound_generic_params, |l, r| { + eq_generic_param(l, r) + }) && eq_ty(&l.bounded_ty, &r.bounded_ty) + && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r)) + }, + (RegionPredicate(l), RegionPredicate(r)) => { + eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r)) + }, + (EqPredicate(l), EqPredicate(r)) => eq_ty(&l.lhs_ty, &r.lhs_ty) && eq_ty(&l.rhs_ty, &r.rhs_ty), + _ => false, + } +} + +pub fn eq_use_tree(l: &UseTree, r: &UseTree) -> bool { + eq_path(&l.prefix, &r.prefix) && eq_use_tree_kind(&l.kind, &r.kind) +} + +pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool { + use UseTreeKind::*; + match (l, r) { + (Glob, Glob) => true, + (Simple(l, _, _), Simple(r, _, _)) => both(l, r, |l, r| eq_id(*l, *r)), + (Nested(l), Nested(r)) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)), + _ => false, + } +} + +pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool { + match (l, r) { + (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_)) => true, + _ => false, + } +} + +pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool { + use VisibilityKind::*; + match (&l.node, &r.node) { + (Public, Public) | (Inherited, Inherited) | (Crate(_), Crate(_)) => true, + (Restricted { path: l, .. }, Restricted { path: r, .. }) => eq_path(l, r), + _ => false, + } +} + +pub fn eq_fn_decl(l: &FnDecl, r: &FnDecl) -> bool { + eq_fn_ret_ty(&l.output, &r.output) + && over(&l.inputs, &r.inputs, |l, r| { + l.is_placeholder == r.is_placeholder + && eq_pat(&l.pat, &r.pat) + && eq_ty(&l.ty, &r.ty) + && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) + }) +} + +pub fn eq_fn_ret_ty(l: &FnRetTy, r: &FnRetTy) -> bool { + match (l, r) { + (FnRetTy::Default(_), FnRetTy::Default(_)) => true, + (FnRetTy::Ty(l), FnRetTy::Ty(r)) => eq_ty(l, r), + _ => false, + } +} + +pub fn eq_ty(l: &Ty, r: &Ty) -> bool { + use TyKind::*; + match (&l.kind, &r.kind) { + (Paren(l), _) => eq_ty(l, r), + (_, Paren(r)) => eq_ty(l, r), + (Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err, Err) | (CVarArgs, CVarArgs) => true, + (Slice(l), Slice(r)) => eq_ty(l, r), + (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value), + (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty), + (Rptr(ll, l), Rptr(rl, r)) => { + both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty) + }, + (BareFn(l), BareFn(r)) => { + l.unsafety == r.unsafety + && eq_ext(&l.ext, &r.ext) + && over(&l.generic_params, &r.generic_params, |l, r| eq_generic_param(l, r)) + && eq_fn_decl(&l.decl, &r.decl) + }, + (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), + (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), + (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, |l, r| eq_generic_bound(l, r)), + (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, |l, r| eq_generic_bound(l, r)), + (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), + (MacCall(l), MacCall(r)) => eq_mac_call(l, r), + _ => false, + } +} + +pub fn eq_ext(l: &Extern, r: &Extern) -> bool { + use Extern::*; + match (l, r) { + (None, None) | (Implicit, Implicit) => true, + (Explicit(l), Explicit(r)) => eq_str_lit(l, r), + _ => false, + } +} + +pub fn eq_str_lit(l: &StrLit, r: &StrLit) -> bool { + l.style == r.style && l.symbol == r.symbol && l.suffix == r.suffix +} + +pub fn eq_poly_ref_trait(l: &PolyTraitRef, r: &PolyTraitRef) -> bool { + eq_path(&l.trait_ref.path, &r.trait_ref.path) + && over(&l.bound_generic_params, &r.bound_generic_params, |l, r| { + eq_generic_param(l, r) + }) +} + +pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool { + use GenericParamKind::*; + l.is_placeholder == r.is_placeholder + && eq_id(l.ident, r.ident) + && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r)) + && match (&l.kind, &r.kind) { + (Lifetime, Lifetime) => true, + (Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)), + (Const { ty: l }, Const { ty: r }) => eq_ty(l, r), + _ => false, + } + && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) +} + +pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool { + use GenericBound::*; + match (l, r) { + (Trait(ptr1, tbm1), Trait(ptr2, tbm2)) => tbm1 == tbm2 && eq_poly_ref_trait(ptr1, ptr2), + (Outlives(l), Outlives(r)) => eq_id(l.ident, r.ident), + _ => false, + } +} + +pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool { + use AssocTyConstraintKind::*; + eq_id(l.ident, r.ident) + && match (&l.kind, &r.kind) { + (Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r), + (Bound { bounds: l }, Bound { bounds: r }) => over(l, r, |l, r| eq_generic_bound(l, r)), + _ => false, + } +} + +pub fn eq_mac_call(l: &MacCall, r: &MacCall) -> bool { + eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args) +} + +pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { + use AttrKind::*; + l.style == r.style + && match (&l.kind, &r.kind) { + (DocComment(l), DocComment(r)) => l == r, + (Normal(l), Normal(r)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args), + _ => false, + } +} + +pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool { + use MacArgs::*; + match (l, r) { + (Empty, Empty) => true, + (Delimited(_, ld, lts), Delimited(_, rd, rts)) => ld == rd && lts.eq_unspanned(rts), + (Eq(_, lts), Eq(_, rts)) => lts.eq_unspanned(rts), + _ => false, + } +} diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index bbcf396eef7..8b58bbb5e65 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -250,8 +250,8 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.visit_expr(arg); } }, - ExprKind::MethodCall(ref _method_name, ref _generics, ref _args) => { - println!("MethodCall(ref method_name, ref generics, ref args) = {};", current); + ExprKind::MethodCall(ref _method_name, ref _generics, ref _args, ref _fn_span) => { + println!("MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};", current); println!(" // unimplemented: `ExprKind::MethodCall` is not further destructured at the moment"); }, ExprKind::Tup(ref elements) => { diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs index 92c27e79452..7a84f1c986a 100644 --- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs @@ -132,7 +132,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { && self.eq_pat(&l.pat, &r.pat) }) }, - (&ExprKind::MethodCall(l_path, _, l_args), &ExprKind::MethodCall(r_path, _, r_args)) => { + (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => { !self.ignore_fn && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args) }, (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => { @@ -332,19 +332,13 @@ fn swap_binop<'a>( /// Checks if the two `Option`s are both `None` or some equal values as per /// `eq_fn`. -fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool -where - F: FnMut(&X, &X) -> bool, -{ +pub fn both<X>(l: &Option<X>, r: &Option<X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { l.as_ref() .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) } /// Checks if two slices are equal as per `eq_fn`. -fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool -where - F: FnMut(&X, &X) -> bool, -{ +pub fn over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y)) } @@ -548,7 +542,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { s.hash(&mut self.s); }, - ExprKind::MethodCall(ref path, ref _tys, args) => { + ExprKind::MethodCall(ref path, ref _tys, args, ref _fn_span) => { self.hash_name(path.ident.name); self.hash_exprs(args); }, @@ -716,7 +710,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { segment.ident.name.hash(&mut self.s); }, }, - TyKind::Def(_, arg_list) => { + TyKind::OpaqueDef(_, arg_list) => { for arg in *arg_list { match arg { GenericArg::Lifetime(ref l) => self.hash_lifetime(l), diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 9b672b9ec22..afde971f9df 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -63,7 +63,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DeepCodeInspector { }, hir::ImplItemKind::Fn(..) => println!("method"), hir::ImplItemKind::TyAlias(_) => println!("associated type"), - hir::ImplItemKind::OpaqueTy(_) => println!("existential type"), } } // fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx @@ -167,7 +166,7 @@ fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, indent: usize) { print_expr(cx, arg, indent + 1); } }, - hir::ExprKind::MethodCall(ref path, _, args) => { + hir::ExprKind::MethodCall(ref path, _, args, _) => { println!("{}MethodCall", ind); println!("{}method name: {}", ind, path.ident.name); for arg in args { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index 8e1b047f6f8..89e2bcdd793 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -402,7 +402,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions { } if_chain! { - if let ExprKind::MethodCall(ref path, _, ref args) = expr.kind; + if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; let fn_name = path.ident; if let Some(sugg) = self.map.get(&*fn_name.as_str()); let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0])); @@ -491,7 +491,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CollapsibleCalls { let stmts = &block.stmts; if stmts.len() == 1 && block.expr.is_none(); if let StmtKind::Semi(only_expr) = &stmts[0].kind; - if let ExprKind::MethodCall(ref ps, _, ref span_call_args) = &only_expr.kind; + if let ExprKind::MethodCall(ref ps, _, ref span_call_args, _) = &only_expr.kind; let and_then_snippets = get_and_then_snippets(cx, and_then_args); let mut sle = SpanlessEq::new(cx).ignore_fn(); then { diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 6dd8fef7e82..60ab19e71f5 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -1,6 +1,8 @@ #[macro_use] pub mod sym; +#[allow(clippy::module_name_repetitions)] +pub mod ast_utils; pub mod attrs; pub mod author; pub mod camel_case; @@ -19,7 +21,7 @@ pub mod sugg; pub mod usage; pub use self::attrs::*; pub use self::diagnostics::*; -pub use self::hir_utils::{SpanlessEq, SpanlessHash}; +pub use self::hir_utils::{both, over, SpanlessEq, SpanlessHash}; use std::borrow::Cow; use std::mem; @@ -40,7 +42,7 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Binder, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Ty, TyCtxt, TypeFoldable}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::symbol::{self, kw, Symbol}; @@ -72,7 +74,7 @@ pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool { let parent_id = cx.tcx.hir().get_parent_item(id); match cx.tcx.hir().get(parent_id) { Node::Item(&Item { - kind: ItemKind::Const(..), + kind: ItemKind::Const(..) | ItemKind::Static(..), .. }) | Node::TraitItem(&TraitItem { @@ -83,11 +85,7 @@ pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool { kind: ImplItemKind::Const(..), .. }) - | Node::AnonConst(_) - | Node::Item(&Item { - kind: ItemKind::Static(..), - .. - }) => true, + | Node::AnonConst(_) => true, Node::Item(&Item { kind: ItemKind::Fn(ref sig, ..), .. @@ -165,8 +163,8 @@ pub fn match_trait_method(cx: &LateContext<'_, '_>, expr: &Expr<'_>, path: &[&st /// Checks if an expression references a variable of the given name. pub fn match_var(expr: &Expr<'_>, var: Name) -> bool { if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { - if path.segments.len() == 1 && path.segments[0].ident.name == var { - return true; + if let [p] = path.segments { + return p.ident.name == var; } } false @@ -181,8 +179,7 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> { pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { match *path { - QPath::Resolved(_, ref path) if path.segments.len() == 1 => Some(&path.segments[0]), - QPath::Resolved(..) => None, + QPath::Resolved(_, ref path) => path.segments.get(0), QPath::TypeRelative(_, ref seg) => Some(seg), } } @@ -201,9 +198,12 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { QPath::Resolved(_, ref path) => match_path(path, segments), QPath::TypeRelative(ref ty, ref segment) => match ty.kind { TyKind::Path(ref inner_path) => { - !segments.is_empty() - && match_qpath(inner_path, &segments[..(segments.len() - 1)]) - && segment.ident.name.as_str() == segments[segments.len() - 1] + if let [prefix @ .., end] = segments { + if match_qpath(inner_path, prefix) { + return segment.ident.name.as_str() == *end; + } + } + false }, _ => false, }, @@ -379,7 +379,7 @@ pub fn method_calls<'tcx>( let mut current = expr; for _ in 0..max_depth { - if let ExprKind::MethodCall(path, span, args) = ¤t.kind { + if let ExprKind::MethodCall(path, span, args, _) = ¤t.kind { if args.iter().any(|e| e.span.from_expansion()) { break; } @@ -398,7 +398,7 @@ pub fn method_calls<'tcx>( /// Matches an `Expr` against a chain of methods, and return the matched `Expr`s. /// /// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`, -/// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec` +/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec` /// containing the `Expr`s for /// `.bar()` and `.baz()` pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> { @@ -406,7 +406,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec let mut matched = Vec::with_capacity(methods.len()); for method_name in methods.iter().rev() { // method chains are stored last -> first - if let ExprKind::MethodCall(ref path, _, ref args) = current.kind { + if let ExprKind::MethodCall(ref path, _, ref args, _) = current.kind { if path.ident.name.as_str() == *method_name { if args.iter().any(|e| e.span.from_expansion()) { return None; @@ -882,20 +882,6 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: hir::HirId) -> T cx.tcx.erase_late_bound_regions(&ret_ty) } -/// Checks if two types are the same. -/// -/// This discards any lifetime annotations, too. -// -// FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == -// `for <'b> Foo<'b>`, but not for type parameters). -pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - let a = cx.tcx.erase_late_bound_regions(&Binder::bind(a)); - let b = cx.tcx.erase_late_bound_regions(&Binder::bind(b)); - cx.tcx - .infer_ctxt() - .enter(|infcx| infcx.can_eq(cx.param_env, a, b).is_ok()) -} - /// Returns `true` if the given type is an `unsafe` function. pub fn type_is_unsafe_function<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind { @@ -1338,7 +1324,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool None } }, - ExprKind::MethodCall(_, _, _) => cx.tables.type_dependent_def_id(expr.hir_id), + ExprKind::MethodCall(_, _, _, _) => cx.tables.type_dependent_def_id(expr.hir_id), _ => None, }; @@ -1408,6 +1394,24 @@ pub fn run_lints(cx: &LateContext<'_, '_>, lints: &[&'static Lint], id: HirId) - }) } +#[macro_export] +macro_rules! unwrap_cargo_metadata { + ($cx: ident, $lint: ident, $deps: expr) => {{ + let mut command = cargo_metadata::MetadataCommand::new(); + if !$deps { + command.no_deps(); + } + + match command.exec() { + Ok(metadata) => metadata, + Err(err) => { + span_lint($cx, $lint, DUMMY_SP, &format!("could not read cargo metadata: {}", err)); + return; + }, + } + }}; +} + #[cfg(test)] mod test { use super::{trim_multiline, without_block_comments}; diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs index 779da7e6bf2..3b7e9739211 100644 --- a/src/tools/clippy/clippy_lints/src/utils/paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs @@ -138,5 +138,6 @@ pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"]; pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; +pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; diff --git a/src/tools/clippy/clippy_lints/src/utils/ptr.rs b/src/tools/clippy/clippy_lints/src/utils/ptr.rs index fb6bd5e8158..ee336ecc58d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ptr.rs @@ -58,7 +58,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> { if self.abort { return; } - if let ExprKind::MethodCall(ref seg, _, ref args) = expr.kind { + if let ExprKind::MethodCall(ref seg, _, ref args, _) = expr.kind { if args.len() == 1 && match_var(&args[0], self.name) { if seg.ident.name.as_str() == "capacity" { self.abort = true; diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index 1174f421577..a8d4c7620b1 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -17,8 +17,14 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ```rust,ignore - /// foo(&vec![1, 2]) + /// ```rust + /// # fn foo(my_vec: &[u8]) {} + /// + /// // Bad + /// foo(&vec![1, 2]); + /// + /// // Good + /// foo(&[1, 2]); /// ``` pub USELESS_VEC, perf, diff --git a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs new file mode 100644 index 00000000000..55758efa32e --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs @@ -0,0 +1,59 @@ +use crate::utils::span_lint_and_then; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Spanned; + +use crate::utils::{match_def_path, paths}; +use rustc_ast::ast::LitKind; +use rustc_hir as hir; + +declare_clippy_lint! { + /// **What it does:** Finds occurences of `Vec::resize(0, an_int)` + /// + /// **Why is this bad?** This is probably an argument inversion mistake. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// vec!(1, 2, 3, 4, 5).resize(0, 5) + /// ``` + pub VEC_RESIZE_TO_ZERO, + correctness, + "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake" +} + +declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VecResizeToZero { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { + if let hir::ExprKind::MethodCall(path_segment, _, ref args, _) = expr.kind; + if let Some(method_def_id) = cx.tables.type_dependent_def_id(expr.hir_id); + if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3; + if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind; + if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind; + then { + let method_call_span = expr.span.with_lo(path_segment.ident.span.lo()); + span_lint_and_then( + cx, + VEC_RESIZE_TO_ZERO, + expr.span, + "emptying a vector with `resize`", + |db| { + db.help("the arguments may be inverted..."); + db.span_suggestion( + method_call_span, + "...or you can empty the vector with", + "clear()".to_string(), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs index 4d8d4438d88..6d420d491c5 100644 --- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs +++ b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs @@ -9,6 +9,7 @@ declare_clippy_lint! { /// /// **Why is this bad?** `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) + /// /// **Known problems:** None. /// /// **Example:** @@ -58,7 +59,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VerboseFileReads { fn is_file_read_to_end<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool { if_chain! { - if let ExprKind::MethodCall(method_name, _, exprs) = expr.kind; + if let ExprKind::MethodCall(method_name, _, exprs, _) = expr.kind; if method_name.ident.as_str() == "read_to_end"; if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind; let ty = cx.tables.expr_ty(&exprs[0]); @@ -72,7 +73,7 @@ fn is_file_read_to_end<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'t fn is_file_read_to_string<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool { if_chain! { - if let ExprKind::MethodCall(method_name, _, exprs) = expr.kind; + if let ExprKind::MethodCall(method_name, _, exprs, _) = expr.kind; if method_name.ident.as_str() == "read_to_string"; if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind; let ty = cx.tables.expr_ty(&exprs[0]); diff --git a/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs b/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs index d8d48eb1535..511518082be 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs @@ -34,12 +34,7 @@ impl LateLintPass<'_, '_> for WildcardDependencies { return; } - let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().no_deps().exec() { - metadata - } else { - span_lint(cx, WILDCARD_DEPENDENCIES, DUMMY_SP, "could not read cargo metadata"); - return; - }; + let metadata = unwrap_cargo_metadata!(cx, WILDCARD_DEPENDENCIES, false); for dep in &metadata.packages[0].dependencies { // VersionReq::any() does not work diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 32d9a45c37d..b637253bd02 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -19,8 +19,14 @@ declare_clippy_lint! { /// still around. /// /// **Example:** - /// ```rust + /// ```rust,ignore + /// // Bad /// use std::cmp::Ordering::*; + /// foo(Less); + /// + /// // Good + /// use std::cmp::Ordering; + /// foo(Ordering::Less) /// ``` pub ENUM_GLOB_USE, pedantic, @@ -60,15 +66,15 @@ declare_clippy_lint! { /// /// **Example:** /// - /// Bad: /// ```rust,ignore + /// // Bad /// use crate1::*; /// /// foo(); /// ``` /// - /// Good: /// ```rust,ignore + /// // Good /// use crate1::foo; /// /// foo(); diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs index fb4700d8743..0820385e01b 100644 --- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs +++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs @@ -14,7 +14,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust - /// 0.0f32 / 0.0; + /// // Bad + /// let nan = 0.0f32 / 0.0; + /// + /// // Good + /// let nan = f32::NAN; /// ``` pub ZERO_DIVIDED_BY_ZERO, complexity, diff --git a/src/tools/clippy/doc/changelog_update.md b/src/tools/clippy/doc/changelog_update.md index 0b80cce6d23..49726464957 100644 --- a/src/tools/clippy/doc/changelog_update.md +++ b/src/tools/clippy/doc/changelog_update.md @@ -18,7 +18,7 @@ been very rare that Clippy changes were included in a patch release. ### 1. Finding the relevant Clippy commits -Each Rust release ships with its own version of Clippy. The Clippy submodule can +Each Rust release ships with its own version of Clippy. The Clippy subtree can be found in the `tools` directory of the Rust repository. Depending on the current time and what exactly you want to update, the following @@ -32,8 +32,10 @@ bullet points might be helpful: need to select the Rust release tag from the dropdown and then check the commit of the Clippy directory: -  - +To find the commit hash, issue the following command when in a `rust-lang/rust` checkout: +``` +git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g" +``` ### 2. Fetching the PRs between those commits @@ -74,5 +76,5 @@ relevant commit ranges. [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md [forge]: https://forge.rust-lang.org/ -[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools -[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools +[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy +[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy diff --git a/src/tools/clippy/doc/common_tools_writing_lints.md b/src/tools/clippy/doc/common_tools_writing_lints.md index ed33b37c6bd..dbc43450594 100644 --- a/src/tools/clippy/doc/common_tools_writing_lints.md +++ b/src/tools/clippy/doc/common_tools_writing_lints.md @@ -4,7 +4,9 @@ You may need following tooltips to catch up with common operations. - [Common tools for writing lints](#common-tools-for-writing-lints) - [Retrieving the type of an expression](#retrieving-the-type-of-an-expression) + - [Checking if an expression is calling a specific method](#checking-if-an-expr-is-calling-a-specific-method) - [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait) + - [Checking if a type defines a method](#checking-if-a-type-defines-a-method) - [Dealing with macros](#dealing-with-macros) Useful Rustc dev guide links: @@ -49,6 +51,26 @@ Two noticeable items here: - `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step, it includes useful information such as types of expressions, ways to resolve methods and so on. +# Checking if an expr is calling a specific method + +Starting with an `expr`, you can check whether it is calling a specific method `some_method`: + +```rust +impl LateLintPass<'_, '_> for MyStructLint { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) { + if_chain! { + // Check our expr is calling a method + if let hir::ExprKind::MethodCall(path, _, _args) = &expr.kind; + // Check the name of this method is `some_method` + if path.ident.name == sym!(some_method); + then { + // ... + } + } + } +} +``` + # Checking if a type implements a specific trait There are two ways to do this, depending if the target trait is part of lang items. @@ -83,6 +105,32 @@ A list of defined paths for Clippy can be found in [paths.rs][paths] We access lang items through the type context `tcx`. `tcx` is of type [`TyCtxt`][TyCtxt] and is defined in the `rustc_middle` crate. +# Checking if a type defines a specific method + +To check if our type defines a method called `some_method`: + +```rust +use crate::utils::{is_type_diagnostic_item, return_ty}; + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MyTypeImpl { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx ImplItem<'_>) { + if_chain! { + // Check if item is a method/function + if let ImplItemKind::Fn(ref signature, _) = impl_item.kind; + // Check the method is named `some_method` + if impl_item.ident.name == sym!(some_method); + // We can also check it has a parameter `self` + if signature.decl.implicit_self.has_implicit_self(); + // We can go further and even check if its return type is `String` + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type)); + then { + // ... + } + } + } +} +``` + # Dealing with macros There are several helpers in Clippy's utils to deal with macros: diff --git a/src/tools/clippy/doc/release.md b/src/tools/clippy/doc/release.md index 9d69fa8a7f6..391952ea6b1 100644 --- a/src/tools/clippy/doc/release.md +++ b/src/tools/clippy/doc/release.md @@ -7,11 +7,11 @@ Clippy is released together with stable Rust releases. The dates for these releases can be found at the [Rust Forge]. This document explains the necessary steps to create a Clippy release. -1. [Find the Clippy commit](#find-the-clippy-commit) -2. [Tag the stable commit](#tag-the-stable-commit) -3. [Update `CHANGELOG.md`](#update-changelogmd) -4. [Remerge the `beta` branch](#remerge-the-beta-branch) -5. [Update the `beta` branch](#update-the-beta-branch) +1. [Remerge the `beta` branch](#remerge-the-beta-branch) +2. [Update the `beta` branch](#update-the-beta-branch) +3. [Find the Clippy commit](#find-the-clippy-commit) +4. [Tag the stable commit](#tag-the-stable-commit) +5. [Update `CHANGELOG.md`](#update-changelogmd) _NOTE: This document is for stable Rust releases, not for point releases. For point releases, step 1. and 2. should be enough._ @@ -19,43 +19,6 @@ point releases, step 1. and 2. should be enough._ [Rust Forge]: https://forge.rust-lang.org/ -## Find the Clippy commit - -The first step is to tag the Clippy commit, that is included in the stable Rust -release. This commit can be found in the Rust repository. - -```bash -# Assuming the current directory corresponds to the Rust repository -$ git fetch upstream # `upstream` is the `rust-lang/rust` remote -$ git checkout 1.XX.0 # XX should be exchanged with the corresponding version -$ git submodule update -$ SHA=$(git submodule status src/tools/clippy | awk '{print $1}') -``` - - -## Tag the stable commit - -After finding the Clippy commit, it can be tagged with the release number. - -```bash -# Assuming the current directory corresponds to the Clippy repository -$ git checkout $SHA -$ git tag rust-1.XX.0 # XX should be exchanged with the corresponding version -$ git push upstream master --tags # `upstream` is the `rust-lang/rust-clippy` remote -``` - -After this, the release should be available on the Clippy [release page]. - -[release page]: https://github.com/rust-lang/rust-clippy/releases - - -## Update `CHANGELOG.md` - -For this see the document on [how to update the changelog]. - -[how to update the changelog]: https://github.com/rust-lang/rust-clippy/blob/master/doc/changelog_update.md - - ## Remerge the `beta` branch This step is only necessary, if since the last release something was backported @@ -76,7 +39,7 @@ If this command outputs `master`, this step is **not** necessary. ```bash # Assuming `HEAD` is the current `master` branch of rust-lang/rust-clippy $ git checkout -b backport_remerge -$ git merge beta +$ git merge upstream/beta $ git diff # This diff has to be empty, otherwise something with the remerge failed $ git push origin backport_remerge # This can be pushed to your fork ``` @@ -96,8 +59,7 @@ determined. ```bash # Assuming the current directory corresponds to the Rust repository $ git checkout beta -$ git submodule update -$ BETA_SHA=$(git submodule status src/tools/clippy | awk '{print $1}') +$ BETA_SHA=$(git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g") ``` After finding the Clippy commit, the `beta` branch in the Clippy repository can @@ -109,3 +71,39 @@ $ git checkout beta $ git rebase $BETA_SHA $ git push upstream beta ``` + + +## Find the Clippy commit + +The first step is to tag the Clippy commit, that is included in the stable Rust +release. This commit can be found in the Rust repository. + +```bash +# Assuming the current directory corresponds to the Rust repository +$ git fetch upstream # `upstream` is the `rust-lang/rust` remote +$ git checkout 1.XX.0 # XX should be exchanged with the corresponding version +$ SHA=$(git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g") +``` + + +## Tag the stable commit + +After finding the Clippy commit, it can be tagged with the release number. + +```bash +# Assuming the current directory corresponds to the Clippy repository +$ git checkout $SHA +$ git tag rust-1.XX.0 # XX should be exchanged with the corresponding version +$ git push upstream master --tags # `upstream` is the `rust-lang/rust-clippy` remote +``` + +After this, the release should be available on the Clippy [release page]. + +[release page]: https://github.com/rust-lang/rust-clippy/releases + + +## Update `CHANGELOG.md` + +For this see the document on [how to update the changelog]. + +[how to update the changelog]: https://github.com/rust-lang/rust-clippy/blob/master/doc/changelog_update.md diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs index f63301c7db0..cac3cc6bdb3 100644 --- a/src/tools/clippy/src/lintlist/mod.rs +++ b/src/tools/clippy/src/lintlist/mod.rs @@ -166,7 +166,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ }, Lint { name: "cast_ptr_alignment", - group: "correctness", + group: "pedantic", desc: "cast from a pointer to a more-strictly-aligned pointer", deprecation: None, module: "types", @@ -935,6 +935,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ module: "loops", }, Lint { + name: "iter_next_slice", + group: "style", + desc: "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`", + deprecation: None, + module: "methods", + }, + Lint { name: "iter_nth", group: "perf", desc: "using `.iter().nth()` on a standard library type with O(1) element access", @@ -1016,7 +1023,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ group: "style", desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block", deprecation: None, - module: "returns", + module: "let_and_return", }, Lint { name: "let_underscore_lock", @@ -1735,7 +1742,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ Lint { name: "pub_enum_variant_names", group: "pedantic", - desc: "enums where all variants share a prefix/postfix", + desc: "public enums where all variants share a prefix/postfix", deprecation: None, module: "enum_variants", }, @@ -2293,6 +2300,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ module: "no_effect", }, Lint { + name: "unnecessary_sort_by", + group: "complexity", + desc: "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer", + deprecation: None, + module: "unnecessary_sort_by", + }, + Lint { name: "unnecessary_unwrap", group: "complexity", desc: "checks for calls of `unwrap[_err]()` that cannot fail", @@ -2314,6 +2328,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ module: "misc_early", }, Lint { + name: "unnested_or_patterns", + group: "complexity", + desc: "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`", + deprecation: None, + module: "unnested_or_patterns", + }, + Lint { name: "unreachable", group: "restriction", desc: "`unreachable!` should not be present in production code", @@ -2461,6 +2482,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![ module: "types", }, Lint { + name: "vec_resize_to_zero", + group: "correctness", + desc: "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake", + deprecation: None, + module: "vec_resize_to_zero", + }, + Lint { name: "verbose_bit_mask", group: "style", desc: "expressions where a bit mask is less readable than the corresponding method call", diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 1c4914a470c..f28aedbf0ab 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -184,8 +184,15 @@ fn run_ui_cargo(config: &mut compiletest::Config) { } let src_path = case.path().join("src"); - env::set_current_dir(&src_path)?; + // When switching between branches, if the previous branch had a test + // that the current branch does not have, the directory is not removed + // because an ignored Cargo.lock file exists. + if !src_path.exists() { + continue; + } + + env::set_current_dir(&src_path)?; for file in fs::read_dir(&src_path)? { let file = file?; if file.file_type()?.is_dir() { diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml index c64adcf7c01..ae0a6032996 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml @@ -2,3 +2,5 @@ name = "cargo_common_metadata" version = "0.1.0" publish = false + +[workspace] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml index c8233f328bb..737e84e963c 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml @@ -9,3 +9,5 @@ readme = "README.md" license = "MIT OR Apache-2.0" keywords = ["metadata", "lint", "clippy"] categories = ["development-tools::testing"] + +[workspace] diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml index 72731fbc75d..278bebbbd9e 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml @@ -5,6 +5,8 @@ name = "multiple_crate_versions" version = "0.1.0" publish = false +[workspace] + # One of the versions of winapi is only a dev dependency: allowed [dependencies] ctrlc = "=3.1.0" diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml index 3a94b723f3f..4f97b011334 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml @@ -3,6 +3,8 @@ name = "multiple_crate_versions" version = "0.1.0" publish = false +[workspace] + [dependencies] ctrlc = "=3.1.0" ansi_term = "=0.11.0" diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml index a9b06420b33..b4b49bb369a 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml @@ -3,6 +3,8 @@ name = "cargo_common_metadata" version = "0.1.0" publish = false +[workspace] + [dependencies] regex = "1.3.7" serde = "1.0.110" diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml index fd2a3414856..3e1a02cbb3c 100644 --- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml @@ -3,5 +3,7 @@ name = "wildcard_dependencies" version = "0.1.0" publish = false +[workspace] + [dependencies] regex = "*" diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml index 38cb139146e..f844cab09ba 100644 --- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml @@ -3,5 +3,7 @@ name = "wildcard_dependencies" version = "0.1.0" publish = false +[workspace] + [dependencies] regex = "1" diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index 7e0b211d862..8ee0969b0f0 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -37,11 +37,11 @@ fn main() { 1isize as usize; -1isize as usize; 0i8 as u8; - i8::max_value() as u8; - i16::max_value() as u16; - i32::max_value() as u32; - i64::max_value() as u64; - i128::max_value() as u128; + i8::MAX as u8; + i16::MAX as u16; + i32::MAX as u32; + i64::MAX as u64; + i128::MAX as u128; (-1i8).abs() as u8; (-1i16).abs() as u16; diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed index 7febd6f3761..12290db3dcf 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.fixed +++ b/src/tools/clippy/tests/ui/checked_conversions.fixed @@ -1,106 +1,76 @@ // run-rustfix +#![allow( + clippy::cast_lossless, + // Int::max_value will be deprecated in the future + deprecated, +)] #![warn(clippy::checked_conversions)] -#![allow(clippy::cast_lossless)] -#![allow(dead_code)] + use std::convert::TryFrom; // Positive tests // Signed to unsigned -fn i64_to_u32(value: i64) -> Option<u32> { - if u32::try_from(value).is_ok() { - Some(value as u32) - } else { - None - } +pub fn i64_to_u32(value: i64) { + let _ = u32::try_from(value).is_ok(); + let _ = u32::try_from(value).is_ok(); } -fn i64_to_u16(value: i64) -> Option<u16> { - if u16::try_from(value).is_ok() { - Some(value as u16) - } else { - None - } +pub fn i64_to_u16(value: i64) { + let _ = u16::try_from(value).is_ok(); + let _ = u16::try_from(value).is_ok(); } -fn isize_to_u8(value: isize) -> Option<u8> { - if u8::try_from(value).is_ok() { - Some(value as u8) - } else { - None - } +pub fn isize_to_u8(value: isize) { + let _ = u8::try_from(value).is_ok(); + let _ = u8::try_from(value).is_ok(); } // Signed to signed -fn i64_to_i32(value: i64) -> Option<i32> { - if i32::try_from(value).is_ok() { - Some(value as i32) - } else { - None - } +pub fn i64_to_i32(value: i64) { + let _ = i32::try_from(value).is_ok(); + let _ = i32::try_from(value).is_ok(); } -fn i64_to_i16(value: i64) -> Option<i16> { - if i16::try_from(value).is_ok() { - Some(value as i16) - } else { - None - } +pub fn i64_to_i16(value: i64) { + let _ = i16::try_from(value).is_ok(); + let _ = i16::try_from(value).is_ok(); } // Unsigned to X -fn u32_to_i32(value: u32) -> Option<i32> { - if i32::try_from(value).is_ok() { - Some(value as i32) - } else { - None - } +pub fn u32_to_i32(value: u32) { + let _ = i32::try_from(value).is_ok(); + let _ = i32::try_from(value).is_ok(); } -fn usize_to_isize(value: usize) -> isize { - if isize::try_from(value).is_ok() && value as i32 == 5 { - 5 - } else { - 1 - } +pub fn usize_to_isize(value: usize) { + let _ = isize::try_from(value).is_ok() && value as i32 == 5; + let _ = isize::try_from(value).is_ok() && value as i32 == 5; } -fn u32_to_u16(value: u32) -> isize { - if u16::try_from(value).is_ok() && value as i32 == 5 { - 5 - } else { - 1 - } +pub fn u32_to_u16(value: u32) { + let _ = u16::try_from(value).is_ok() && value as i32 == 5; + let _ = u16::try_from(value).is_ok() && value as i32 == 5; } // Negative tests -fn no_i64_to_i32(value: i64) -> Option<i32> { - if value <= (i32::max_value() as i64) && value >= 0 { - Some(value as i32) - } else { - None - } +pub fn no_i64_to_i32(value: i64) { + let _ = value <= (i32::max_value() as i64) && value >= 0; + let _ = value <= (i32::MAX as i64) && value >= 0; } -fn no_isize_to_u8(value: isize) -> Option<u8> { - if value <= (u8::max_value() as isize) && value >= (u8::min_value() as isize) { - Some(value as u8) - } else { - None - } +pub fn no_isize_to_u8(value: isize) { + let _ = value <= (u8::max_value() as isize) && value >= (u8::min_value() as isize); + let _ = value <= (u8::MAX as isize) && value >= (u8::MIN as isize); } -fn i8_to_u8(value: i8) -> Option<u8> { - if value >= 0 { - Some(value as u8) - } else { - None - } +pub fn i8_to_u8(value: i8) { + let _ = value >= 0; } fn main() {} diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs index a643354e243..895a301e821 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.rs +++ b/src/tools/clippy/tests/ui/checked_conversions.rs @@ -1,106 +1,76 @@ // run-rustfix +#![allow( + clippy::cast_lossless, + // Int::max_value will be deprecated in the future + deprecated, +)] #![warn(clippy::checked_conversions)] -#![allow(clippy::cast_lossless)] -#![allow(dead_code)] + use std::convert::TryFrom; // Positive tests // Signed to unsigned -fn i64_to_u32(value: i64) -> Option<u32> { - if value <= (u32::max_value() as i64) && value >= 0 { - Some(value as u32) - } else { - None - } +pub fn i64_to_u32(value: i64) { + let _ = value <= (u32::max_value() as i64) && value >= 0; + let _ = value <= (u32::MAX as i64) && value >= 0; } -fn i64_to_u16(value: i64) -> Option<u16> { - if value <= i64::from(u16::max_value()) && value >= 0 { - Some(value as u16) - } else { - None - } +pub fn i64_to_u16(value: i64) { + let _ = value <= i64::from(u16::max_value()) && value >= 0; + let _ = value <= i64::from(u16::MAX) && value >= 0; } -fn isize_to_u8(value: isize) -> Option<u8> { - if value <= (u8::max_value() as isize) && value >= 0 { - Some(value as u8) - } else { - None - } +pub fn isize_to_u8(value: isize) { + let _ = value <= (u8::max_value() as isize) && value >= 0; + let _ = value <= (u8::MAX as isize) && value >= 0; } // Signed to signed -fn i64_to_i32(value: i64) -> Option<i32> { - if value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64) { - Some(value as i32) - } else { - None - } +pub fn i64_to_i32(value: i64) { + let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64); + let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64); } -fn i64_to_i16(value: i64) -> Option<i16> { - if value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()) { - Some(value as i16) - } else { - None - } +pub fn i64_to_i16(value: i64) { + let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()); + let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN); } // Unsigned to X -fn u32_to_i32(value: u32) -> Option<i32> { - if value <= i32::max_value() as u32 { - Some(value as i32) - } else { - None - } +pub fn u32_to_i32(value: u32) { + let _ = value <= i32::max_value() as u32; + let _ = value <= i32::MAX as u32; } -fn usize_to_isize(value: usize) -> isize { - if value <= isize::max_value() as usize && value as i32 == 5 { - 5 - } else { - 1 - } +pub fn usize_to_isize(value: usize) { + let _ = value <= isize::max_value() as usize && value as i32 == 5; + let _ = value <= isize::MAX as usize && value as i32 == 5; } -fn u32_to_u16(value: u32) -> isize { - if value <= u16::max_value() as u32 && value as i32 == 5 { - 5 - } else { - 1 - } +pub fn u32_to_u16(value: u32) { + let _ = value <= u16::max_value() as u32 && value as i32 == 5; + let _ = value <= u16::MAX as u32 && value as i32 == 5; } // Negative tests -fn no_i64_to_i32(value: i64) -> Option<i32> { - if value <= (i32::max_value() as i64) && value >= 0 { - Some(value as i32) - } else { - None - } +pub fn no_i64_to_i32(value: i64) { + let _ = value <= (i32::max_value() as i64) && value >= 0; + let _ = value <= (i32::MAX as i64) && value >= 0; } -fn no_isize_to_u8(value: isize) -> Option<u8> { - if value <= (u8::max_value() as isize) && value >= (u8::min_value() as isize) { - Some(value as u8) - } else { - None - } +pub fn no_isize_to_u8(value: isize) { + let _ = value <= (u8::max_value() as isize) && value >= (u8::min_value() as isize); + let _ = value <= (u8::MAX as isize) && value >= (u8::MIN as isize); } -fn i8_to_u8(value: i8) -> Option<u8> { - if value >= 0 { - Some(value as u8) - } else { - None - } +pub fn i8_to_u8(value: i8) { + let _ = value >= 0; } fn main() {} diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr index f678f009621..648ba3ccd01 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.stderr +++ b/src/tools/clippy/tests/ui/checked_conversions.stderr @@ -1,52 +1,100 @@ error: Checked cast can be simplified. - --> $DIR/checked_conversions.rs:13:8 + --> $DIR/checked_conversions.rs:17:13 | -LL | if value <= (u32::max_value() as i64) && value >= 0 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` +LL | let _ = value <= (u32::max_value() as i64) && value >= 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` | = note: `-D clippy::checked-conversions` implied by `-D warnings` error: Checked cast can be simplified. - --> $DIR/checked_conversions.rs:21:8 + --> $DIR/checked_conversions.rs:18:13 | -LL | if value <= i64::from(u16::max_value()) && value >= 0 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` +LL | let _ = value <= (u32::MAX as i64) && value >= 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` error: Checked cast can be simplified. - --> $DIR/checked_conversions.rs:29:8 + --> $DIR/checked_conversions.rs:22:13 | -LL | if value <= (u8::max_value() as isize) && value >= 0 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` +LL | let _ = value <= i64::from(u16::max_value()) && value >= 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: Checked cast can be simplified. - --> $DIR/checked_conversions.rs:39:8 + --> $DIR/checked_conversions.rs:23:13 | -LL | if value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` +LL | let _ = value <= i64::from(u16::MAX) && value >= 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: Checked cast can be simplified. - --> $DIR/checked_conversions.rs:47:8 + --> $DIR/checked_conversions.rs:27:13 | -LL | if value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` +LL | let _ = value <= (u8::max_value() as isize) && value >= 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: Checked cast can be simplified. - --> $DIR/checked_conversions.rs:57:8 + --> $DIR/checked_conversions.rs:28:13 | -LL | if value <= i32::max_value() as u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` +LL | let _ = value <= (u8::MAX as isize) && value >= 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: Checked cast can be simplified. - --> $DIR/checked_conversions.rs:65:8 + --> $DIR/checked_conversions.rs:34:13 | -LL | if value <= isize::max_value() as usize && value as i32 == 5 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` +LL | let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: Checked cast can be simplified. - --> $DIR/checked_conversions.rs:73:8 + --> $DIR/checked_conversions.rs:35:13 | -LL | if value <= u16::max_value() as u32 && value as i32 == 5 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` +LL | let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` -error: aborting due to 8 previous errors +error: Checked cast can be simplified. + --> $DIR/checked_conversions.rs:39:13 + | +LL | let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` + +error: Checked cast can be simplified. + --> $DIR/checked_conversions.rs:40:13 + | +LL | let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` + +error: Checked cast can be simplified. + --> $DIR/checked_conversions.rs:46:13 + | +LL | let _ = value <= i32::max_value() as u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` + +error: Checked cast can be simplified. + --> $DIR/checked_conversions.rs:47:13 + | +LL | let _ = value <= i32::MAX as u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` + +error: Checked cast can be simplified. + --> $DIR/checked_conversions.rs:51:13 + | +LL | let _ = value <= isize::max_value() as usize && value as i32 == 5; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` + +error: Checked cast can be simplified. + --> $DIR/checked_conversions.rs:52:13 + | +LL | let _ = value <= isize::MAX as usize && value as i32 == 5; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` + +error: Checked cast can be simplified. + --> $DIR/checked_conversions.rs:56:13 + | +LL | let _ = value <= u16::max_value() as u32 && value as i32 == 5; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` + +error: Checked cast can be simplified. + --> $DIR/checked_conversions.rs:57:13 + | +LL | let _ = value <= u16::MAX as u32 && value as i32 == 5; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` + +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/checked_conversions.stdout b/src/tools/clippy/tests/ui/checked_conversions.stdout deleted file mode 100644 index e69de29bb2d..00000000000 --- a/src/tools/clippy/tests/ui/checked_conversions.stdout +++ /dev/null diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.rs b/src/tools/clippy/tests/ui/crashes/ice-3969.rs new file mode 100644 index 00000000000..4feab7910b7 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-3969.rs @@ -0,0 +1,51 @@ +// https://github.com/rust-lang/rust-clippy/issues/3969 +// used to crash: error: internal compiler error: +// src/librustc_traits/normalize_erasing_regions.rs:43: could not fully normalize `<i32 as +// std::iter::Iterator>::Item test from rustc ./ui/trivial-bounds/trivial-bounds-inconsistent.rs + +// Check that tautalogically false bounds are accepted, and are used +// in type inference. +#![feature(trivial_bounds)] +#![allow(unused)] + +trait A {} + +impl A for i32 {} + +struct Dst<X: ?Sized> { + x: X, +} + +struct TwoStrs(str, str) +where + str: Sized; + +fn unsized_local() +where + for<'a> Dst<A + 'a>: Sized, +{ + let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>); +} + +fn return_str() -> str +where + str: Sized, +{ + *"Sized".to_string().into_boxed_str() +} + +fn use_op(s: String) -> String +where + String: ::std::ops::Neg<Output = String>, +{ + -s +} + +fn use_for() +where + i32: Iterator, +{ + for _ in 2i32 {} +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.stderr b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr new file mode 100644 index 00000000000..923db0664a7 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr @@ -0,0 +1,22 @@ +error: trait objects without an explicit `dyn` are deprecated + --> $DIR/ice-3969.rs:25:17 + | +LL | for<'a> Dst<A + 'a>: Sized, + | ^^^^^^ help: use `dyn`: `dyn A + 'a` + | + = note: `-D bare-trait-objects` implied by `-D warnings` + +error: trait objects without an explicit `dyn` are deprecated + --> $DIR/ice-3969.rs:27:16 + | +LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>); + | ^ help: use `dyn`: `dyn A` + +error: trait objects without an explicit `dyn` are deprecated + --> $DIR/ice-3969.rs:27:57 + | +LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>); + | ^ help: use `dyn`: `dyn A` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/crashes/regressions.rs b/src/tools/clippy/tests/ui/crashes/regressions.rs index 623ae51f9f0..3d5063d1a3a 100644 --- a/src/tools/clippy/tests/ui/crashes/regressions.rs +++ b/src/tools/clippy/tests/ui/crashes/regressions.rs @@ -6,4 +6,8 @@ pub fn foo(bar: *const u8) { println!("{:#p}", bar); } +// Regression test for https://github.com/rust-lang/rust-clippy/issues/4917 +/// <foo +struct A {} + fn main() {} diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs index 24cb216e79b..2f32a7b1578 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs +++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs @@ -110,7 +110,7 @@ fn main() { } // Lint - if i_8 > i8::min_value() { + if i_8 > i8::MIN { i_8 -= 1; } @@ -120,7 +120,7 @@ fn main() { } // Lint - if i_8 != i8::min_value() { + if i_8 != i8::MIN { i_8 -= 1; } @@ -135,7 +135,7 @@ fn main() { } // Lint - if i_16 > i16::min_value() { + if i_16 > i16::MIN { i_16 -= 1; } @@ -145,7 +145,7 @@ fn main() { } // Lint - if i_16 != i16::min_value() { + if i_16 != i16::MIN { i_16 -= 1; } @@ -160,7 +160,7 @@ fn main() { } // Lint - if i_32 > i32::min_value() { + if i_32 > i32::MIN { i_32 -= 1; } @@ -170,7 +170,7 @@ fn main() { } // Lint - if i_32 != i32::min_value() { + if i_32 != i32::MIN { i_32 -= 1; } @@ -180,7 +180,7 @@ fn main() { let mut i_64: i64 = endi_64 - starti_64; // Lint - if i64::min_value() < i_64 { + if i64::MIN < i_64 { i_64 -= 1; } diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr index a8ba870b1dd..2eb2023b3b9 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr +++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr @@ -75,7 +75,7 @@ LL | | } error: Implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:113:5 | -LL | / if i_8 > i8::min_value() { +LL | / if i_8 > i8::MIN { LL | | i_8 -= 1; LL | | } | |_____^ help: try: `i_8 = i_8.saturating_sub(1);` @@ -91,7 +91,7 @@ LL | | } error: Implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:123:5 | -LL | / if i_8 != i8::min_value() { +LL | / if i_8 != i8::MIN { LL | | i_8 -= 1; LL | | } | |_____^ help: try: `i_8 = i_8.saturating_sub(1);` @@ -107,7 +107,7 @@ LL | | } error: Implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:138:5 | -LL | / if i_16 > i16::min_value() { +LL | / if i_16 > i16::MIN { LL | | i_16 -= 1; LL | | } | |_____^ help: try: `i_16 = i_16.saturating_sub(1);` @@ -123,7 +123,7 @@ LL | | } error: Implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:148:5 | -LL | / if i_16 != i16::min_value() { +LL | / if i_16 != i16::MIN { LL | | i_16 -= 1; LL | | } | |_____^ help: try: `i_16 = i_16.saturating_sub(1);` @@ -139,7 +139,7 @@ LL | | } error: Implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:163:5 | -LL | / if i_32 > i32::min_value() { +LL | / if i_32 > i32::MIN { LL | | i_32 -= 1; LL | | } | |_____^ help: try: `i_32 = i_32.saturating_sub(1);` @@ -155,7 +155,7 @@ LL | | } error: Implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:173:5 | -LL | / if i_32 != i32::min_value() { +LL | / if i_32 != i32::MIN { LL | | i_32 -= 1; LL | | } | |_____^ help: try: `i_32 = i_32.saturating_sub(1);` @@ -163,7 +163,7 @@ LL | | } error: Implicitly performing saturating subtraction --> $DIR/implicit_saturating_sub.rs:183:5 | -LL | / if i64::min_value() < i_64 { +LL | / if i64::MIN < i_64 { LL | | i_64 -= 1; LL | | } | |_____^ help: try: `i_64 = i_64.saturating_sub(1);` diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed index c30d23de3f8..7f92d0dbdc9 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed @@ -40,4 +40,6 @@ fn main() { let _ = (&HashSet::<i32>::new()).iter(); //~ WARN equivalent to .iter() let _ = std::path::Path::new("12/34").iter(); //~ WARN equivalent to .iter() let _ = std::path::PathBuf::from("12/34").iter(); //~ ERROR equivalent to .iter() + + let _ = (&[1, 2, 3]).iter().next(); //~ WARN equivalent to .iter() } diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.rs b/src/tools/clippy/tests/ui/into_iter_on_ref.rs index 94bc1689619..416056d3fdb 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.rs +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.rs @@ -40,4 +40,6 @@ fn main() { let _ = (&HashSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter() let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter() let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() + + let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() } diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr index 80e2d104f82..1cd6400b019 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr @@ -156,5 +156,11 @@ error: this `.into_iter()` call is equivalent to `.iter()` and will not move the LL | let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: aborting due to 26 previous errors +error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array` + --> $DIR/into_iter_on_ref.rs:44:26 + | +LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() + | ^^^^^^^^^ help: call directly: `iter` + +error: aborting due to 27 previous errors diff --git a/src/tools/clippy/tests/ui/iter_next_slice.fixed b/src/tools/clippy/tests/ui/iter_next_slice.fixed new file mode 100644 index 00000000000..79c1db87ac3 --- /dev/null +++ b/src/tools/clippy/tests/ui/iter_next_slice.fixed @@ -0,0 +1,24 @@ +// run-rustfix +#![warn(clippy::iter_next_slice)] + +fn main() { + // test code goes here + let s = [1, 2, 3]; + let v = vec![1, 2, 3]; + + s.get(0); + // Should be replaced by s.get(0) + + s.get(2); + // Should be replaced by s.get(2) + + v.get(5); + // Should be replaced by v.get(5) + + v.get(0); + // Should be replaced by v.get(0) + + let o = Some(5); + o.iter().next(); + // Shouldn't be linted since this is not a Slice or an Array +} diff --git a/src/tools/clippy/tests/ui/iter_next_slice.rs b/src/tools/clippy/tests/ui/iter_next_slice.rs new file mode 100644 index 00000000000..ef9a55f3d99 --- /dev/null +++ b/src/tools/clippy/tests/ui/iter_next_slice.rs @@ -0,0 +1,24 @@ +// run-rustfix +#![warn(clippy::iter_next_slice)] + +fn main() { + // test code goes here + let s = [1, 2, 3]; + let v = vec![1, 2, 3]; + + s.iter().next(); + // Should be replaced by s.get(0) + + s[2..].iter().next(); + // Should be replaced by s.get(2) + + v[5..].iter().next(); + // Should be replaced by v.get(5) + + v.iter().next(); + // Should be replaced by v.get(0) + + let o = Some(5); + o.iter().next(); + // Shouldn't be linted since this is not a Slice or an Array +} diff --git a/src/tools/clippy/tests/ui/iter_next_slice.stderr b/src/tools/clippy/tests/ui/iter_next_slice.stderr new file mode 100644 index 00000000000..bbf61df0cda --- /dev/null +++ b/src/tools/clippy/tests/ui/iter_next_slice.stderr @@ -0,0 +1,28 @@ +error: Using `.iter().next()` on an array + --> $DIR/iter_next_slice.rs:9:5 + | +LL | s.iter().next(); + | ^^^^^^^^^^^^^^^ help: try calling: `s.get(0)` + | + = note: `-D clippy::iter-next-slice` implied by `-D warnings` + +error: Using `.iter().next()` on a Slice without end index. + --> $DIR/iter_next_slice.rs:12:5 + | +LL | s[2..].iter().next(); + | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `s.get(2)` + +error: Using `.iter().next()` on a Slice without end index. + --> $DIR/iter_next_slice.rs:15:5 + | +LL | v[5..].iter().next(); + | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `v.get(5)` + +error: Using `.iter().next()` on an array + --> $DIR/iter_next_slice.rs:18:5 + | +LL | v.iter().next(); + | ^^^^^^^^^^^^^^^ help: try calling: `v.get(0)` + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed index 624e5ef8fcf..a29b832eb60 100644 --- a/src/tools/clippy/tests/ui/len_zero.fixed +++ b/src/tools/clippy/tests/ui/len_zero.fixed @@ -141,3 +141,11 @@ fn main() { fn test_slice(b: &[u8]) { if !b.is_empty() {} } + +mod issue_3807 { + // Avoid suggesting changes to ranges if the user did not enable `range_is_empty`. + // See https://github.com/rust-lang/rust/issues/48111#issuecomment-445132965 + fn no_suggestion() { + let _ = (0..42).len() == 0; + } +} diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs index 7fba971cfd8..8fd0093f4fd 100644 --- a/src/tools/clippy/tests/ui/len_zero.rs +++ b/src/tools/clippy/tests/ui/len_zero.rs @@ -141,3 +141,11 @@ fn main() { fn test_slice(b: &[u8]) { if b.len() != 0 {} } + +mod issue_3807 { + // Avoid suggesting changes to ranges if the user did not enable `range_is_empty`. + // See https://github.com/rust-lang/rust/issues/48111#issuecomment-445132965 + fn no_suggestion() { + let _ = (0..42).len() == 0; + } +} diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.fixed b/src/tools/clippy/tests/ui/len_zero_ranges.fixed new file mode 100644 index 00000000000..7da26f8ff4d --- /dev/null +++ b/src/tools/clippy/tests/ui/len_zero_ranges.fixed @@ -0,0 +1,14 @@ +// run-rustfix + +#![feature(range_is_empty)] +#![warn(clippy::len_zero)] +#![allow(unused)] + +mod issue_3807 { + // With the feature enabled, `is_empty` should be suggested + fn suggestion_is_fine() { + let _ = (0..42).is_empty(); + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.rs b/src/tools/clippy/tests/ui/len_zero_ranges.rs new file mode 100644 index 00000000000..be7b4244bc0 --- /dev/null +++ b/src/tools/clippy/tests/ui/len_zero_ranges.rs @@ -0,0 +1,14 @@ +// run-rustfix + +#![feature(range_is_empty)] +#![warn(clippy::len_zero)] +#![allow(unused)] + +mod issue_3807 { + // With the feature enabled, `is_empty` should be suggested + fn suggestion_is_fine() { + let _ = (0..42).len() == 0; + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.stderr b/src/tools/clippy/tests/ui/len_zero_ranges.stderr new file mode 100644 index 00000000000..6e5fa41fb08 --- /dev/null +++ b/src/tools/clippy/tests/ui/len_zero_ranges.stderr @@ -0,0 +1,10 @@ +error: length comparison to zero + --> $DIR/len_zero_ranges.rs:10:17 + | +LL | let _ = (0..42).len() == 0; + | ^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(0..42).is_empty()` + | + = note: `-D clippy::len-zero` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/let_and_return.rs b/src/tools/clippy/tests/ui/let_and_return.rs new file mode 100644 index 00000000000..09614b8c1ad --- /dev/null +++ b/src/tools/clippy/tests/ui/let_and_return.rs @@ -0,0 +1,138 @@ +#![allow(unused)] +#![warn(clippy::let_and_return)] + +fn test() -> i32 { + let _y = 0; // no warning + let x = 5; + x +} + +fn test_inner() -> i32 { + if true { + let x = 5; + x + } else { + 0 + } +} + +fn test_nowarn_1() -> i32 { + let mut x = 5; + x += 1; + x +} + +fn test_nowarn_2() -> i32 { + let x = 5; + x + 1 +} + +fn test_nowarn_3() -> (i32, i32) { + // this should technically warn, but we do not compare complex patterns + let (x, y) = (5, 9); + (x, y) +} + +fn test_nowarn_4() -> i32 { + // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type + let x: i32 = 5; + x +} + +fn test_nowarn_5(x: i16) -> u16 { + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let x = x as u16; + x +} + +// False positive example +trait Decode { + fn decode<D: std::io::Read>(d: D) -> Result<Self, ()> + where + Self: Sized; +} + +macro_rules! tuple_encode { + ($($x:ident),*) => ( + impl<$($x: Decode),*> Decode for ($($x),*) { + #[inline] + #[allow(non_snake_case)] + fn decode<D: std::io::Read>(mut d: D) -> Result<Self, ()> { + // Shouldn't trigger lint + Ok(($({let $x = Decode::decode(&mut d)?; $x }),*)) + } + } + ); +} + +tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); + +mod no_lint_if_stmt_borrows { + mod issue_3792 { + use std::io::{self, BufRead, Stdin}; + + fn read_line() -> String { + let stdin = io::stdin(); + let line = stdin.lock().lines().next().unwrap().unwrap(); + line + } + } + + mod issue_3324 { + use std::cell::RefCell; + use std::rc::{Rc, Weak}; + + fn test(value: Weak<RefCell<Bar>>) -> u32 { + let value = value.upgrade().unwrap(); + let ret = value.borrow().baz(); + ret + } + + struct Bar {} + + impl Bar { + fn new() -> Self { + Bar {} + } + fn baz(&self) -> u32 { + 0 + } + } + + fn main() { + let a = Rc::new(RefCell::new(Bar::new())); + let b = Rc::downgrade(&a); + test(b); + } + } + + mod free_function { + struct Inner; + + struct Foo<'a> { + inner: &'a Inner, + } + + impl Drop for Foo<'_> { + fn drop(&mut self) {} + } + + impl Foo<'_> { + fn value(&self) -> i32 { + 42 + } + } + + fn some_foo(inner: &Inner) -> Foo<'_> { + Foo { inner } + } + + fn test() -> i32 { + let x = Inner {}; + let value = some_foo(&x).value(); + value + } + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/let_return.stderr b/src/tools/clippy/tests/ui/let_and_return.stderr index 128a22c86e3..eacf948b392 100644 --- a/src/tools/clippy/tests/ui/let_return.stderr +++ b/src/tools/clippy/tests/ui/let_and_return.stderr @@ -1,5 +1,5 @@ error: returning the result of a `let` binding from a block - --> $DIR/let_return.rs:7:5 + --> $DIR/let_and_return.rs:7:5 | LL | let x = 5; | ---------- unnecessary `let` binding @@ -14,7 +14,7 @@ LL | 5 | error: returning the result of a `let` binding from a block - --> $DIR/let_return.rs:13:9 + --> $DIR/let_and_return.rs:13:9 | LL | let x = 5; | ---------- unnecessary `let` binding diff --git a/src/tools/clippy/tests/ui/let_return.rs b/src/tools/clippy/tests/ui/let_return.rs deleted file mode 100644 index 23645d48fe7..00000000000 --- a/src/tools/clippy/tests/ui/let_return.rs +++ /dev/null @@ -1,70 +0,0 @@ -#![allow(unused)] -#![warn(clippy::let_and_return)] - -fn test() -> i32 { - let _y = 0; // no warning - let x = 5; - x -} - -fn test_inner() -> i32 { - if true { - let x = 5; - x - } else { - 0 - } -} - -fn test_nowarn_1() -> i32 { - let mut x = 5; - x += 1; - x -} - -fn test_nowarn_2() -> i32 { - let x = 5; - x + 1 -} - -fn test_nowarn_3() -> (i32, i32) { - // this should technically warn, but we do not compare complex patterns - let (x, y) = (5, 9); - (x, y) -} - -fn test_nowarn_4() -> i32 { - // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type - let x: i32 = 5; - x -} - -fn test_nowarn_5(x: i16) -> u16 { - #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] - let x = x as u16; - x -} - -// False positive example -trait Decode { - fn decode<D: std::io::Read>(d: D) -> Result<Self, ()> - where - Self: Sized; -} - -macro_rules! tuple_encode { - ($($x:ident),*) => ( - impl<$($x: Decode),*> Decode for ($($x),*) { - #[inline] - #[allow(non_snake_case)] - fn decode<D: std::io::Read>(mut d: D) -> Result<Self, ()> { - // Shouldn't trigger lint - Ok(($({let $x = Decode::decode(&mut d)?; $x }),*)) - } - } - ); -} - -tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); - -fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed index b4227eaf2f8..be37dc16b9a 100644 --- a/src/tools/clippy/tests/ui/needless_collect.fixed +++ b/src/tools/clippy/tests/ui/needless_collect.fixed @@ -9,7 +9,7 @@ use std::collections::{BTreeSet, HashMap, HashSet}; fn main() { let sample = [1; 5]; let len = sample.iter().count(); - if sample.iter().next().is_none() { + if sample.get(0).is_none() { // Empty } sample.iter().cloned().any(|x| x == 1); diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr index 8884c8e1612..9113aad90dd 100644 --- a/src/tools/clippy/tests/ui/needless_collect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect.stderr @@ -1,28 +1,28 @@ error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:11:28 + --> $DIR/needless_collect.rs:11:29 | LL | let len = sample.iter().collect::<Vec<_>>().len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` | = note: `-D clippy::needless-collect` implied by `-D warnings` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:12:21 + --> $DIR/needless_collect.rs:12:15 | LL | if sample.iter().collect::<Vec<_>>().is_empty() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.next().is_none()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get(0).is_none()` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:15:27 + --> $DIR/needless_collect.rs:15:28 | LL | sample.iter().cloned().collect::<Vec<_>>().contains(&1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.any(|x| x == 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:16:34 + --> $DIR/needless_collect.rs:16:35 | LL | sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs index 856a430ba2b..ca70e3b7148 100644 --- a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs +++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs @@ -4,6 +4,7 @@ use std::cmp::Ordering; +#[allow(clippy::unnested_or_patterns)] #[warn(clippy::neg_cmp_op_on_partial_ord)] fn main() { let a_value = 1.0; diff --git a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr index d05fd34ce33..8c5d548222e 100644 --- a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr +++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr @@ -1,5 +1,5 @@ error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:15:21 + --> $DIR/neg_cmp_op_on_partial_ord.rs:16:21 | LL | let _not_less = !(a_value < another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,19 +7,19 @@ LL | let _not_less = !(a_value < another_value); = note: `-D clippy::neg-cmp-op-on-partial-ord` implied by `-D warnings` error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:18:30 + --> $DIR/neg_cmp_op_on_partial_ord.rs:19:30 | LL | let _not_less_or_equal = !(a_value <= another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:21:24 + --> $DIR/neg_cmp_op_on_partial_ord.rs:22:24 | LL | let _not_greater = !(a_value > another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable. - --> $DIR/neg_cmp_op_on_partial_ord.rs:24:33 + --> $DIR/neg_cmp_op_on_partial_ord.rs:25:33 | LL | let _not_greater_or_equal = !(a_value >= another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed index 7bb08797ef3..2045ffdb5f0 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.fixed +++ b/src/tools/clippy/tests/ui/or_fun_call.fixed @@ -29,7 +29,7 @@ fn or_fun_call() { with_enum.unwrap_or(Enum::A(5)); let with_const_fn = Some(Duration::from_secs(1)); - with_const_fn.unwrap_or(Duration::from_secs(5)); + with_const_fn.unwrap_or_else(|| Duration::from_secs(5)); let with_constructor = Some(vec![1]); with_constructor.unwrap_or_else(make); @@ -94,7 +94,7 @@ fn test_or_with_ctors() { let b = "b".to_string(); let _ = Some(Bar("a".to_string(), Duration::from_secs(1))) - .or(Some(Bar(b, Duration::from_secs(2)))); + .or_else(|| Some(Bar(b, Duration::from_secs(2)))); let vec = vec!["foo"]; let _ = opt.ok_or(vec.len()); diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr index 96d55771e6c..bc5978b538f 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.stderr +++ b/src/tools/clippy/tests/ui/or_fun_call.stderr @@ -1,10 +1,16 @@ error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:32:19 + | +LL | with_const_fn.unwrap_or(Duration::from_secs(5)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))` + | + = note: `-D clippy::or-fun-call` implied by `-D warnings` + +error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:35:22 | LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` - | - = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:38:5 @@ -78,5 +84,11 @@ error: use of `or` followed by a function call LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` -error: aborting due to 13 previous errors +error: use of `or` followed by a function call + --> $DIR/or_fun_call.rs:97:10 + | +LL | .or(Some(Bar(b, Duration::from_secs(2)))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` + +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed index 332c0427ef6..79e482eec30 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed @@ -4,8 +4,6 @@ const ANSWER: i32 = 42; fn main() { - let arr = [1, 2, 3, 4, 5]; - // These should be linted: (21..=42).rev().for_each(|x| println!("{}", x)); @@ -14,16 +12,18 @@ fn main() { for _ in (-42..=-21).rev() {} for _ in (21u32..42u32).rev() {} - let _ = &[] as &[i32]; - // These should be ignored as they are not empty ranges: (21..=42).for_each(|x| println!("{}", x)); (21..42).for_each(|x| println!("{}", x)); + let arr = [1, 2, 3, 4, 5]; let _ = &arr[1..=3]; let _ = &arr[1..3]; for _ in 21..=42 {} for _ in 21..42 {} + + // This range is empty but should be ignored, see issue #5689 + let _ = &arr[0..0]; } diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs index 901ec8bcc09..b2e8bf33771 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs @@ -4,8 +4,6 @@ const ANSWER: i32 = 42; fn main() { - let arr = [1, 2, 3, 4, 5]; - // These should be linted: (42..=21).for_each(|x| println!("{}", x)); @@ -14,16 +12,18 @@ fn main() { for _ in -21..=-42 {} for _ in 42u32..21u32 {} - let _ = &arr[3..3]; - // These should be ignored as they are not empty ranges: (21..=42).for_each(|x| println!("{}", x)); (21..42).for_each(|x| println!("{}", x)); + let arr = [1, 2, 3, 4, 5]; let _ = &arr[1..=3]; let _ = &arr[1..3]; for _ in 21..=42 {} for _ in 21..42 {} + + // This range is empty but should be ignored, see issue #5689 + let _ = &arr[0..0]; } diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr index 9a646fd9939..de83c4f3d63 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr @@ -1,5 +1,5 @@ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:11:5 + --> $DIR/reversed_empty_ranges_fixable.rs:9:5 | LL | (42..=21).for_each(|x| println!("{}", x)); | ^^^^^^^^^ @@ -11,7 +11,7 @@ LL | (21..=42).rev().for_each(|x| println!("{}", x)); | ^^^^^^^^^^^^^^^ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:12:13 + --> $DIR/reversed_empty_ranges_fixable.rs:10:13 | LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>(); | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::<Ve | ^^^^^^^^^^^^^^^^^^ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:14:14 + --> $DIR/reversed_empty_ranges_fixable.rs:12:14 | LL | for _ in -21..=-42 {} | ^^^^^^^^^ @@ -33,7 +33,7 @@ LL | for _ in (-42..=-21).rev() {} | ^^^^^^^^^^^^^^^^^ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:15:14 + --> $DIR/reversed_empty_ranges_fixable.rs:13:14 | LL | for _ in 42u32..21u32 {} | ^^^^^^^^^^^^ @@ -43,11 +43,5 @@ help: consider using the following if you are attempting to iterate over this ra LL | for _ in (21u32..42u32).rev() {} | ^^^^^^^^^^^^^^^^^^^^ -error: this range is empty and using it to index a slice will always yield an empty slice - --> $DIR/reversed_empty_ranges_fixable.rs:17:18 - | -LL | let _ = &arr[3..3]; - | ----^^^^- help: if you want an empty slice, use: `[] as &[i32]` - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs index 561a35625f0..264d3d1e95a 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs @@ -4,11 +4,12 @@ const ANSWER: i32 = 42; const SOME_NUM: usize = 3; fn main() { - let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21); - let arr = [1, 2, 3, 4, 5]; let _ = &arr[3usize..=1usize]; let _ = &arr[SOME_NUM..1]; for _ in ANSWER..ANSWER {} + + // Should not be linted, see issue #5689 + let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21); } diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr index 240188cbb46..f23d4eb0f9c 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr @@ -1,28 +1,22 @@ -error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_unfixable.rs:7:13 - | -LL | let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21); - | ^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` - error: this range is reversed and using it to index a slice will panic at run-time - --> $DIR/reversed_empty_ranges_unfixable.rs:10:18 + --> $DIR/reversed_empty_ranges_unfixable.rs:8:18 | LL | let _ = &arr[3usize..=1usize]; | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` error: this range is reversed and using it to index a slice will panic at run-time - --> $DIR/reversed_empty_ranges_unfixable.rs:11:18 + --> $DIR/reversed_empty_ranges_unfixable.rs:9:18 | LL | let _ = &arr[SOME_NUM..1]; | ^^^^^^^^^^^ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_unfixable.rs:13:14 + --> $DIR/reversed_empty_ranges_unfixable.rs:11:14 | LL | for _ in ANSWER..ANSWER {} | ^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed index 7ad272ade5f..ccf8f61c4a9 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed @@ -14,6 +14,8 @@ fn str_lit_as_bytes() { let strify = stringify!(foobar).as_bytes(); + let current_version = env!("CARGO_PKG_VERSION").as_bytes(); + let includestr = include_bytes!("entry_unfixable.rs"); let _ = b"string with newline\t\n"; diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs index 1bf4538b7c9..178df08e249 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs @@ -14,6 +14,8 @@ fn str_lit_as_bytes() { let strify = stringify!(foobar).as_bytes(); + let current_version = env!("CARGO_PKG_VERSION").as_bytes(); + let includestr = include_str!("entry_unfixable.rs").as_bytes(); let _ = "string with newline\t\n".as_bytes(); diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr index ff6e3346dfc..99c512354d5 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr @@ -13,13 +13,13 @@ LL | let bs = r###"raw string with 3# plus " ""###.as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###` error: calling `as_bytes()` on `include_str!(..)` - --> $DIR/string_lit_as_bytes.rs:17:22 + --> $DIR/string_lit_as_bytes.rs:19:22 | LL | let includestr = include_str!("entry_unfixable.rs").as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("entry_unfixable.rs")` error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:19:13 + --> $DIR/string_lit_as_bytes.rs:21:13 | LL | let _ = "string with newline/t/n".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"` diff --git a/src/tools/clippy/tests/ui/unit_arg.fixed b/src/tools/clippy/tests/ui/unit_arg.fixed deleted file mode 100644 index a739cf7ad81..00000000000 --- a/src/tools/clippy/tests/ui/unit_arg.fixed +++ /dev/null @@ -1,64 +0,0 @@ -// run-rustfix -#![warn(clippy::unit_arg)] -#![allow(unused_braces, clippy::no_effect, unused_must_use)] - -use std::fmt::Debug; - -fn foo<T: Debug>(t: T) { - println!("{:?}", t); -} - -fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) { - println!("{:?}, {:?}, {:?}", t1, t2, t3); -} - -struct Bar; - -impl Bar { - fn bar<T: Debug>(&self, t: T) { - println!("{:?}", t); - } -} - -fn bad() { - foo(()); - foo(()); - foo(()); - foo(()); - foo3((), 2, 2); - let b = Bar; - b.bar(()); -} - -fn ok() { - foo(()); - foo(1); - foo({ 1 }); - foo3("a", 3, vec![3]); - let b = Bar; - b.bar({ 1 }); - b.bar(()); - question_mark(); -} - -fn question_mark() -> Result<(), ()> { - Ok(Ok(())?)?; - Ok(Ok(()))??; - Ok(()) -} - -#[allow(dead_code)] -mod issue_2945 { - fn unit_fn() -> Result<(), i32> { - Ok(()) - } - - fn fallible() -> Result<(), i32> { - Ok(unit_fn()?) - } -} - -fn main() { - bad(); - ok(); -} diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs index d90c49f79de..2992abae775 100644 --- a/src/tools/clippy/tests/ui/unit_arg.rs +++ b/src/tools/clippy/tests/ui/unit_arg.rs @@ -1,6 +1,5 @@ -// run-rustfix #![warn(clippy::unit_arg)] -#![allow(unused_braces, clippy::no_effect, unused_must_use)] +#![allow(clippy::no_effect, unused_must_use, unused_variables)] use std::fmt::Debug; @@ -21,7 +20,6 @@ impl Bar { } fn bad() { - foo({}); foo({ 1; }); @@ -30,11 +28,25 @@ fn bad() { foo(1); foo(2); }); - foo3({}, 2, 2); let b = Bar; b.bar({ 1; }); + taking_multiple_units(foo(0), foo(1)); + taking_multiple_units(foo(0), { + foo(1); + foo(2); + }); + taking_multiple_units( + { + foo(0); + foo(1); + }, + { + foo(2); + foo(3); + }, + ); } fn ok() { @@ -65,6 +77,13 @@ mod issue_2945 { } } +#[allow(dead_code)] +fn returning_expr() -> Option<()> { + Some(foo(1)) +} + +fn taking_multiple_units(a: (), b: ()) {} + fn main() { bad(); ok(); diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index 21ccc684ea9..56f6a855dfa 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr @@ -1,79 +1,181 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:24:9 + --> $DIR/unit_arg.rs:23:5 | -LL | foo({}); - | ^^ +LL | / foo({ +LL | | 1; +LL | | }); + | |______^ | = note: `-D clippy::unit-arg` implied by `-D warnings` -help: if you intended to pass a unit value, use a unit literal instead +help: remove the semicolon from the last statement in the block | -LL | foo(()); - | ^^ - -error: passing a unit value to a function - --> $DIR/unit_arg.rs:25:9 +LL | 1 | -LL | foo({ - | _________^ -LL | | 1; -LL | | }); - | |_____^ +help: or move the expression in front of the call... | -help: if you intended to pass a unit value, use a unit literal instead +LL | { +LL | 1; +LL | }; + | +help: ...and use a unit literal instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:28:9 + --> $DIR/unit_arg.rs:26:5 | LL | foo(foo(1)); - | ^^^^^^ + | ^^^^^^^^^^^ + | +help: move the expression in front of the call... | -help: if you intended to pass a unit value, use a unit literal instead +LL | foo(1); + | +help: ...and use a unit literal instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:29:9 + --> $DIR/unit_arg.rs:27:5 | -LL | foo({ - | _________^ +LL | / foo({ LL | | foo(1); LL | | foo(2); LL | | }); - | |_____^ + | |______^ + | +help: remove the semicolon from the last statement in the block + | +LL | foo(2) | -help: if you intended to pass a unit value, use a unit literal instead +help: or move the expression in front of the call... + | +LL | { +LL | foo(1); +LL | foo(2); +LL | }; + | +help: ...and use a unit literal instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:33:10 + --> $DIR/unit_arg.rs:32:5 | -LL | foo3({}, 2, 2); - | ^^ +LL | / b.bar({ +LL | | 1; +LL | | }); + | |______^ | -help: if you intended to pass a unit value, use a unit literal instead +help: remove the semicolon from the last statement in the block | -LL | foo3((), 2, 2); - | ^^ +LL | 1 + | +help: or move the expression in front of the call... + | +LL | { +LL | 1; +LL | }; + | +help: ...and use a unit literal instead + | +LL | b.bar(()); + | ^^ -error: passing a unit value to a function - --> $DIR/unit_arg.rs:35:11 +error: passing unit values to a function + --> $DIR/unit_arg.rs:35:5 | -LL | b.bar({ - | ___________^ -LL | | 1; +LL | taking_multiple_units(foo(0), foo(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expressions in front of the call... + | +LL | foo(0); +LL | foo(1); + | +help: ...and use unit literals instead + | +LL | taking_multiple_units((), ()); + | ^^ ^^ + +error: passing unit values to a function + --> $DIR/unit_arg.rs:36:5 + | +LL | / taking_multiple_units(foo(0), { +LL | | foo(1); +LL | | foo(2); LL | | }); + | |______^ + | +help: remove the semicolon from the last statement in the block + | +LL | foo(2) + | +help: or move the expressions in front of the call... + | +LL | foo(0); +LL | { +LL | foo(1); +LL | foo(2); +LL | }; + | +help: ...and use unit literals instead + | +LL | taking_multiple_units((), ()); + | ^^ ^^ + +error: passing unit values to a function + --> $DIR/unit_arg.rs:40:5 + | +LL | / taking_multiple_units( +LL | | { +LL | | foo(0); +LL | | foo(1); +... | +LL | | }, +LL | | ); | |_____^ | -help: if you intended to pass a unit value, use a unit literal instead +help: remove the semicolon from the last statement in the block | -LL | b.bar(()); - | ^^ +LL | foo(1) + | +help: remove the semicolon from the last statement in the block + | +LL | foo(3) + | +help: or move the expressions in front of the call... + | +LL | { +LL | foo(0); +LL | foo(1); +LL | }; +LL | { +LL | foo(2); + ... +help: ...and use unit literals instead + | +LL | (), +LL | (), + | + +error: passing a unit value to a function + --> $DIR/unit_arg.rs:82:5 + | +LL | Some(foo(1)) + | ^^^^^^^^^^^^ + | +help: move the expression in front of the call... + | +LL | foo(1); + | +help: ...and use a unit literal instead + | +LL | Some(()) + | ^^ -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs new file mode 100644 index 00000000000..18a31eb3dee --- /dev/null +++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs @@ -0,0 +1,26 @@ +#![warn(clippy::unit_arg)] +#![allow(clippy::no_effect, unused_must_use, unused_variables)] + +use std::fmt::Debug; + +fn foo<T: Debug>(t: T) { + println!("{:?}", t); +} + +fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) { + println!("{:?}, {:?}, {:?}", t1, t2, t3); +} + +fn bad() { + foo({}); + foo3({}, 2, 2); + taking_two_units({}, foo(0)); + taking_three_units({}, foo(0), foo(1)); +} + +fn taking_two_units(a: (), b: ()) {} +fn taking_three_units(a: (), b: (), c: ()) {} + +fn main() { + bad(); +} diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr new file mode 100644 index 00000000000..bb58483584b --- /dev/null +++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr @@ -0,0 +1,51 @@ +error: passing a unit value to a function + --> $DIR/unit_arg_empty_blocks.rs:15:5 + | +LL | foo({}); + | ^^^^--^ + | | + | help: use a unit literal instead: `()` + | + = note: `-D clippy::unit-arg` implied by `-D warnings` + +error: passing a unit value to a function + --> $DIR/unit_arg_empty_blocks.rs:16:5 + | +LL | foo3({}, 2, 2); + | ^^^^^--^^^^^^^ + | | + | help: use a unit literal instead: `()` + +error: passing unit values to a function + --> $DIR/unit_arg_empty_blocks.rs:17:5 + | +LL | taking_two_units({}, foo(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call... + | +LL | foo(0); + | +help: ...and use unit literals instead + | +LL | taking_two_units((), ()); + | ^^ ^^ + +error: passing unit values to a function + --> $DIR/unit_arg_empty_blocks.rs:18:5 + | +LL | taking_three_units({}, foo(0), foo(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expressions in front of the call... + | +LL | foo(0); +LL | foo(1); + | +help: ...and use unit literals instead + | +LL | taking_three_units((), (), ()); + | ^^ ^^ ^^ + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed new file mode 100644 index 00000000000..779fd57707a --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed @@ -0,0 +1,26 @@ +// run-rustfix + +use std::cmp::Reverse; + +fn id(x: isize) -> isize { + x +} + +fn main() { + let mut vec: Vec<isize> = vec![3, 6, 1, 2, 5]; + // Forward examples + vec.sort(); + vec.sort_unstable(); + vec.sort_by_key(|&a| (a + 5).abs()); + vec.sort_unstable_by_key(|&a| id(-a)); + // Reverse examples + vec.sort_by_key(|&b| Reverse(b)); + vec.sort_by_key(|&b| Reverse((b + 5).abs())); + vec.sort_unstable_by_key(|&b| Reverse(id(-b))); + // Negative examples (shouldn't be changed) + let c = &7; + vec.sort_by(|a, b| (b - a).cmp(&(a - b))); + vec.sort_by(|_, b| b.cmp(&5)); + vec.sort_by(|_, b| b.cmp(c)); + vec.sort_unstable_by(|a, _| a.cmp(c)); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs new file mode 100644 index 00000000000..0485a5630af --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs @@ -0,0 +1,26 @@ +// run-rustfix + +use std::cmp::Reverse; + +fn id(x: isize) -> isize { + x +} + +fn main() { + let mut vec: Vec<isize> = vec![3, 6, 1, 2, 5]; + // Forward examples + vec.sort_by(|a, b| a.cmp(b)); + vec.sort_unstable_by(|a, b| a.cmp(b)); + vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); + vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); + // Reverse examples + vec.sort_by(|a, b| b.cmp(a)); + vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); + vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); + // Negative examples (shouldn't be changed) + let c = &7; + vec.sort_by(|a, b| (b - a).cmp(&(a - b))); + vec.sort_by(|_, b| b.cmp(&5)); + vec.sort_by(|_, b| b.cmp(c)); + vec.sort_unstable_by(|a, _| a.cmp(c)); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr new file mode 100644 index 00000000000..903b6e5099c --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr @@ -0,0 +1,46 @@ +error: use Vec::sort here instead + --> $DIR/unnecessary_sort_by.rs:12:5 + | +LL | vec.sort_by(|a, b| a.cmp(b)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()` + | + = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` + +error: use Vec::sort here instead + --> $DIR/unnecessary_sort_by.rs:13:5 + | +LL | vec.sort_unstable_by(|a, b| a.cmp(b)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:14:5 + | +LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| (a + 5).abs())` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:15:5 + | +LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&a| id(-a))` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:17:5 + | +LL | vec.sort_by(|a, b| b.cmp(a)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:18:5 + | +LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:19:5 + | +LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&b| Reverse(id(-b)))` + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed new file mode 100644 index 00000000000..b39e891094f --- /dev/null +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed @@ -0,0 +1,33 @@ +// run-rustfix + +#![feature(or_patterns)] +#![feature(box_patterns)] +#![warn(clippy::unnested_or_patterns)] +#![allow(clippy::cognitive_complexity, clippy::match_ref_pats)] +#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)] + +fn main() { + if let box (0 | 2) = Box::new(0) {} + if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} + const C0: &u8 = &1; + if let &(0 | 2) | C0 = &0 {} + if let &mut (0 | 2) = &mut 0 {} + if let x @ (0 | 2) = 0 {} + if let (0, 1 | 2 | 3) = (0, 0) {} + if let (1 | 2 | 3, 0) = (0, 0) {} + if let (x, ..) | (x, 1 | 2) = (0, 1) {} + if let [0 | 1] = [0] {} + if let [x, 0 | 1] = [0, 1] {} + if let [x, 0 | 1 | 2] = [0, 1] {} + if let [x, ..] | [x, 1 | 2] = [0, 1] {} + struct TS(u8, u8); + if let TS(0 | 1, x) = TS(0, 0) {} + if let TS(1 | 2 | 3, 0) = TS(0, 0) {} + if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {} + struct S { + x: u8, + y: u8, + } + if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {} + if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} +} diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.rs b/src/tools/clippy/tests/ui/unnested_or_patterns.rs new file mode 100644 index 00000000000..096f5a71150 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.rs @@ -0,0 +1,33 @@ +// run-rustfix + +#![feature(or_patterns)] +#![feature(box_patterns)] +#![warn(clippy::unnested_or_patterns)] +#![allow(clippy::cognitive_complexity, clippy::match_ref_pats)] +#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)] + +fn main() { + if let box 0 | box 2 = Box::new(0) {} + if let box ((0 | 1)) | box (2 | 3) | box 4 = Box::new(0) {} + const C0: &u8 = &1; + if let &0 | C0 | &2 = &0 {} + if let &mut 0 | &mut 2 = &mut 0 {} + if let x @ 0 | x @ 2 = 0 {} + if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {} + if let (1, 0) | (2, 0) | (3, 0) = (0, 0) {} + if let (x, ..) | (x, 1) | (x, 2) = (0, 1) {} + if let [0] | [1] = [0] {} + if let [x, 0] | [x, 1] = [0, 1] {} + if let [x, 0] | [x, 1] | [x, 2] = [0, 1] {} + if let [x, ..] | [x, 1] | [x, 2] = [0, 1] {} + struct TS(u8, u8); + if let TS(0, x) | TS(1, x) = TS(0, 0) {} + if let TS(1, 0) | TS(2, 0) | TS(3, 0) = TS(0, 0) {} + if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {} + struct S { + x: u8, + y: u8, + } + if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} + if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} +} diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr new file mode 100644 index 00000000000..1899dc657df --- /dev/null +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr @@ -0,0 +1,179 @@ +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:10:12 + | +LL | if let box 0 | box 2 = Box::new(0) {} + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::unnested-or-patterns` implied by `-D warnings` +help: nest the patterns + | +LL | if let box (0 | 2) = Box::new(0) {} + | ^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:11:12 + | +LL | if let box ((0 | 1)) | box (2 | 3) | box 4 = Box::new(0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:13:12 + | +LL | if let &0 | C0 | &2 = &0 {} + | ^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let &(0 | 2) | C0 = &0 {} + | ^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:14:12 + | +LL | if let &mut 0 | &mut 2 = &mut 0 {} + | ^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let &mut (0 | 2) = &mut 0 {} + | ^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:15:12 + | +LL | if let x @ 0 | x @ 2 = 0 {} + | ^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let x @ (0 | 2) = 0 {} + | ^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:16:12 + | +LL | if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let (0, 1 | 2 | 3) = (0, 0) {} + | ^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:17:12 + | +LL | if let (1, 0) | (2, 0) | (3, 0) = (0, 0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let (1 | 2 | 3, 0) = (0, 0) {} + | ^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:18:12 + | +LL | if let (x, ..) | (x, 1) | (x, 2) = (0, 1) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let (x, ..) | (x, 1 | 2) = (0, 1) {} + | ^^^^^^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:19:12 + | +LL | if let [0] | [1] = [0] {} + | ^^^^^^^^^ + | +help: nest the patterns + | +LL | if let [0 | 1] = [0] {} + | ^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:20:12 + | +LL | if let [x, 0] | [x, 1] = [0, 1] {} + | ^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let [x, 0 | 1] = [0, 1] {} + | ^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:21:12 + | +LL | if let [x, 0] | [x, 1] | [x, 2] = [0, 1] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let [x, 0 | 1 | 2] = [0, 1] {} + | ^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:22:12 + | +LL | if let [x, ..] | [x, 1] | [x, 2] = [0, 1] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let [x, ..] | [x, 1 | 2] = [0, 1] {} + | ^^^^^^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:24:12 + | +LL | if let TS(0, x) | TS(1, x) = TS(0, 0) {} + | ^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let TS(0 | 1, x) = TS(0, 0) {} + | ^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:25:12 + | +LL | if let TS(1, 0) | TS(2, 0) | TS(3, 0) = TS(0, 0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let TS(1 | 2 | 3, 0) = TS(0, 0) {} + | ^^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:26:12 + | +LL | if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns.rs:31:12 + | +LL | if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {} + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 16 previous errors + diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed new file mode 100644 index 00000000000..02a129c55a3 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed @@ -0,0 +1,18 @@ +// run-rustfix + +#![feature(or_patterns)] +#![feature(box_patterns)] +#![warn(clippy::unnested_or_patterns)] +#![allow(clippy::cognitive_complexity, clippy::match_ref_pats)] +#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)] + +fn main() { + if let Some(Some(0 | 1)) = None {} + if let Some(Some(0 | 1 | 2)) = None {} + if let Some(Some(0 | 1 | 2 | 3 | 4)) = None {} + if let Some(Some(0 | 1 | 2)) = None {} + if let ((0 | 1 | 2,),) = ((0,),) {} + if let 0 | 1 | 2 = 0 {} + if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} + if let box box (0 | 2 | 4) = Box::new(Box::new(0)) {} +} diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.rs b/src/tools/clippy/tests/ui/unnested_or_patterns2.rs new file mode 100644 index 00000000000..acf3158989d --- /dev/null +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.rs @@ -0,0 +1,18 @@ +// run-rustfix + +#![feature(or_patterns)] +#![feature(box_patterns)] +#![warn(clippy::unnested_or_patterns)] +#![allow(clippy::cognitive_complexity, clippy::match_ref_pats)] +#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)] + +fn main() { + if let Some(Some(0)) | Some(Some(1)) = None {} + if let Some(Some(0)) | Some(Some(1) | Some(2)) = None {} + if let Some(Some(0 | 1) | Some(2)) | Some(Some(3) | Some(4)) = None {} + if let Some(Some(0) | Some(1 | 2)) = None {} + if let ((0,),) | ((1,) | (2,),) = ((0,),) {} + if let 0 | (1 | 2) = 0 {} + if let box (0 | 1) | (box 2 | box (3 | 4)) = Box::new(0) {} + if let box box 0 | box (box 2 | box 4) = Box::new(Box::new(0)) {} +} diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr new file mode 100644 index 00000000000..1847fd8e098 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr @@ -0,0 +1,91 @@ +error: unnested or-patterns + --> $DIR/unnested_or_patterns2.rs:10:12 + | +LL | if let Some(Some(0)) | Some(Some(1)) = None {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unnested-or-patterns` implied by `-D warnings` +help: nest the patterns + | +LL | if let Some(Some(0 | 1)) = None {} + | ^^^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns2.rs:11:12 + | +LL | if let Some(Some(0)) | Some(Some(1) | Some(2)) = None {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let Some(Some(0 | 1 | 2)) = None {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns2.rs:12:12 + | +LL | if let Some(Some(0 | 1) | Some(2)) | Some(Some(3) | Some(4)) = None {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let Some(Some(0 | 1 | 2 | 3 | 4)) = None {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns2.rs:13:12 + | +LL | if let Some(Some(0) | Some(1 | 2)) = None {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let Some(Some(0 | 1 | 2)) = None {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns2.rs:14:12 + | +LL | if let ((0,),) | ((1,) | (2,),) = ((0,),) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let ((0 | 1 | 2,),) = ((0,),) {} + | ^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns2.rs:15:12 + | +LL | if let 0 | (1 | 2) = 0 {} + | ^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let 0 | 1 | 2 = 0 {} + | ^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns2.rs:16:12 + | +LL | if let box (0 | 1) | (box 2 | box (3 | 4)) = Box::new(0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: unnested or-patterns + --> $DIR/unnested_or_patterns2.rs:17:12 + | +LL | if let box box 0 | box (box 2 | box 4) = Box::new(Box::new(0)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: nest the patterns + | +LL | if let box box (0 | 2 | 4) = Box::new(Box::new(0)) {} + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/src/tools/clippy/tests/ui/vec_resize_to_zero.rs b/src/tools/clippy/tests/ui/vec_resize_to_zero.rs new file mode 100644 index 00000000000..0263e2f5f20 --- /dev/null +++ b/src/tools/clippy/tests/ui/vec_resize_to_zero.rs @@ -0,0 +1,15 @@ +#![warn(clippy::vec_resize_to_zero)] + +fn main() { + // applicable here + vec![1, 2, 3, 4, 5].resize(0, 5); + + // not applicable + vec![1, 2, 3, 4, 5].resize(2, 5); + + // applicable here, but only implemented for integer litterals for now + vec!["foo", "bar", "baz"].resize(0, "bar"); + + // not applicable + vec!["foo", "bar", "baz"].resize(2, "bar") +} diff --git a/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr b/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr new file mode 100644 index 00000000000..feb846298c6 --- /dev/null +++ b/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr @@ -0,0 +1,13 @@ +error: emptying a vector with `resize` + --> $DIR/vec_resize_to_zero.rs:5:5 + | +LL | vec![1, 2, 3, 4, 5].resize(0, 5); + | ^^^^^^^^^^^^^^^^^^^^------------ + | | + | help: ...or you can empty the vector with: `clear()` + | + = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings` + = help: the arguments may be inverted... + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed index 2aa24ea1156..4f8754a9301 100644 --- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed +++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed @@ -6,7 +6,8 @@ unused_variables, dead_code, clippy::single_match, - clippy::wildcard_in_or_patterns + clippy::wildcard_in_or_patterns, + clippy::unnested_or_patterns )] use std::io::ErrorKind; diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs index 07c93feaf28..5e66644ceca 100644 --- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs +++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs @@ -6,7 +6,8 @@ unused_variables, dead_code, clippy::single_match, - clippy::wildcard_in_or_patterns + clippy::wildcard_in_or_patterns, + clippy::unnested_or_patterns )] use std::io::ErrorKind; diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr index 7151a5c5770..e03b3be43ed 100644 --- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr +++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr @@ -1,5 +1,5 @@ error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:37:9 + --> $DIR/wildcard_enum_match_arm.rs:38:9 | LL | _ => eprintln!("Not red"), | ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` @@ -11,25 +11,25 @@ LL | #![deny(clippy::wildcard_enum_match_arm)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:41:9 + --> $DIR/wildcard_enum_match_arm.rs:42:9 | LL | _not_red => eprintln!("Not red"), | ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:45:9 + --> $DIR/wildcard_enum_match_arm.rs:46:9 | LL | not_red => format!("{:?}", not_red), | ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` error: wildcard match will miss any future added variants - --> $DIR/wildcard_enum_match_arm.rs:61:9 + --> $DIR/wildcard_enum_match_arm.rs:62:9 | LL | _ => "No red", | ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` error: match on non-exhaustive enum doesn't explicitly match all known variants - --> $DIR/wildcard_enum_match_arm.rs:78:9 + --> $DIR/wildcard_enum_match_arm.rs:79:9 | LL | _ => {}, | ^ help: try this: `std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _` diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 31d991e0c2f..f7355433463 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -27,6 +27,12 @@ fn test_parse_normalization_string() { let first = parse_normalization_string(&mut s); assert_eq!(first, Some("something (32 bits)".to_owned())); assert_eq!(s, " -> \"something ($WORD bits)."); + + // Nothing to normalize (No quotes, 16-bit) + let mut s = "normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)."; + let first = parse_normalization_string(&mut s); + assert_eq!(first, None); + assert_eq!(s, r#"normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)."#); } fn config() -> Config { diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index c61bee0f8d9..ca36a15ffc7 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -47,6 +47,7 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ ("armv7", "arm"), ("armv7s", "arm"), ("asmjs", "asmjs"), + ("avr", "avr"), ("hexagon", "hexagon"), ("i386", "x86"), ("i586", "x86"), @@ -114,6 +115,8 @@ pub fn matches_env(triple: &str, name: &str) -> bool { pub fn get_pointer_width(triple: &str) -> &'static str { if (triple.contains("64") && !triple.ends_with("gnux32")) || triple.starts_with("s390x") { "64bit" + } else if triple.starts_with("avr") { + "16bit" } else { "32bit" } diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index 95b63aca154..63cc29b670f 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -43,7 +43,7 @@ impl RawEmitter { words.push(0); let unique_words = words.iter().cloned().collect::<BTreeSet<_>>().into_iter().collect::<Vec<_>>(); - if unique_words.len() > u8::max_value() as usize { + if unique_words.len() > u8::MAX as usize { panic!("cannot pack {} into 8 bits", unique_words.len()); } // needed for the chunk mapping to work diff --git a/triagebot.toml b/triagebot.toml index e43cff55386..fc2dbb8d440 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -20,7 +20,7 @@ Hey LLVM ICE-breakers! This bug has been identified as a good [instructions] for tackling these sorts of bugs. Maybe take a look? Thanks! <3 -[instructions]: https://rustc-dev-guide.rust-lang.org/ice-breaker/llvm.html +[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/llvm.html """ label = "ICEBreaker-LLVM" @@ -32,16 +32,88 @@ Hey Cleanup Crew ICE-breakers! This bug has been identified as a good [instructions] for tackling these sorts of bugs. Maybe take a look? Thanks! <3 -[instructions]: https://rustc-dev-guide.rust-lang.org/ice-breaker/cleanup-crew.html +[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/cleanup-crew.html """ label = "ICEBreaker-Cleanup-Crew" +[ping.windows] +message = """\ +Hey Windows Group! This bug has been identified as a good "Windows candidate". +In case it's useful, here are some [instructions] for tackling these sorts of +bugs. Maybe take a look? +Thanks! <3 + +[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/windows.html +""" +label = "O-windows" + +[ping.arm] +message = """\ +Hey ARM Group! This bug has been identified as a good "ARM candidate". +In case it's useful, here are some [instructions] for tackling these sorts of +bugs. Maybe take a look? +Thanks! <3 + +[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/arm.html +""" +label = "O-ARM" + [prioritize] label = "I-prioritize" -prioritize_on = ["regression-from-stable-to-stable", "regression-from-stable-to-beta", "regression-from-stable-to-nightly"] + +[autolabel."I-prioritize"] +trigger_labels = [ + "regression-from-stable-to-stable", + "regression-from-stable-to-beta", + "regression-from-stable-to-nightly", + "I-unsound 💥", +] exclude_labels = [ "P-*", "T-infra", "T-release", + "requires-nightly", ] -zulip_stream = 227806 + +[notify-zulip."I-prioritize"] +zulip_stream = 227806 # #t-compiler/wg-prioritization +topic = "I-prioritize #{number} {title}" +message_on_add = "@*WG-prioritization* issue #{number} has been requested for prioritization." +message_on_remove = "Issue #{number}'s prioritization request has been removed." + +[notify-zulip."I-nominated"] +required_labels = ["T-compiler"] +zulip_stream = 227806 # #t-compiler/wg-prioritization +topic = "I-prioritize #{number} {title}" +message_on_add = "@*WG-prioritization* #{number} has been nominated for discussion in `T-compiler` meeting." +message_on_remove = "#{number}'s nomination has been removed." + +[notify-zulip."beta-nominated"] +zulip_stream = 227806 # #t-compiler/wg-prioritization +topic = "Backport #{number} {title}" +message_on_add = "@*WG-prioritization* PR #{number} has been requested for beta backport." +message_on_remove = "PR #{number}'s beta backport request has been removed." + +[notify-zulip."stable-nominated"] +zulip_stream = 227806 # #t-compiler/wg-prioritization +topic = "Backport #{number} {title}" +message_on_add = "@*WG-prioritization* PR #{number} has been requested for stable backport." +message_on_remove = "PR #{number}'s stable backport request has been removed." + +[notify-zulip."S-waiting-on-team"] +required_labels = ["T-compiler"] +zulip_stream = 227806 # #t-compiler/wg-prioritization +topic = "S-waiting-on-team #{number} {title}" +message_on_add = "@*WG-prioritization* PR #{number} is waiting on `T-compiler`." +message_on_remove = "PR #{number}'s is no longer waiting on `T-compiler`." + +[notify-zulip."P-critical"] +zulip_stream = 227806 # #t-compiler/wg-prioritization +topic = "P-critical #{number} {title}" +message_on_add = "@*WG-prioritization* issue #{number} has been assigned `P-critical`." + +[notify-zulip."P-high"] +required_labels = ["regression-from-stable-to-*"] +zulip_stream = 227806 # #t-compiler/wg-prioritization +topic = "P-high regression #{number} {title}" +message_on_add = "@*WG-prioritization* issue #{number} has been assigned `P-high` and is a regression." |
