diff options
392 files changed, 6606 insertions, 4757 deletions
diff --git a/.gitignore b/.gitignore index 81a472451d7..487867c375d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ -# This file should only ignore things that are generated during a build, -# generated by common IDEs, and optional files controlled by the user -# that affect the build (such as config.toml). +# This file should only ignore things that are generated during a `x.py` build, +# generated by common IDEs, and optional files controlled by the user that +# affect the build (such as config.toml). +# In particular, things like `mir_dump` should not be listed here; they are only +# created during manual debugging and many people like to clean up instead of +# having git ignore such leftovers. You can use `.git/info/exclude` to +# configure your local ignore list. # FIXME: This needs cleanup. *~ .#* @@ -52,3 +56,4 @@ config.stamp Session.vim .cargo no_llvm_build +# Before adding new lines, see the comment at the top. diff --git a/.gitmodules b/.gitmodules index 3ff5af78097..1dcf9ed319f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,9 +28,6 @@ [submodule "src/doc/rust-by-example"] path = src/doc/rust-by-example url = https://github.com/rust-lang/rust-by-example.git -[submodule "src/llvm-emscripten"] - path = src/llvm-emscripten - url = https://github.com/rust-lang/llvm.git [submodule "src/stdarch"] path = src/stdarch url = https://github.com/rust-lang/stdarch.git diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c3a9a68963e..37a217d2a04 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -128,6 +128,14 @@ the master branch to your feature branch. Also, please make sure that fixup commits are squashed into other related commits with meaningful commit messages. +GitHub allows [closing issues using keywords][closing-keywords]. This feature +should be used to keep the issue tracker tidy. However, it is generally preferred +to put the "closes #123" text in the PR description rather than the issue commit; +particularly during rebasing, citing the issue number in the commit can "spam" +the issue in question. + +[closing-keywords]: https://help.github.com/en/articles/closing-issues-using-keywords + Please make sure your pull request is in compliance with Rust's style guidelines by running diff --git a/Cargo.lock b/Cargo.lock index a5a7521abde..efcbd7b6794 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -556,9 +556,9 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "676a74b493d50ac33cacd83fd536597e6b52c0b46b9856f7b9c809d82fef4ac0" +checksum = "f75b10a18fb53549fdd090846eb01c7f8593914494d1faabc4d3005c436e417a" dependencies = [ "diff", "filetime", @@ -1713,9 +1713,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" [[package]] name = "libc" -version = "0.2.62" +version = "0.2.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +checksum = "74dfca3d9957906e8d1e6a0b641dc9a59848e793f1da2165889fd4f62d10d79c" dependencies = [ "rustc-std-workspace-core", ] @@ -3483,6 +3483,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_interface", + "rustc_lint", "rustc_metadata", "rustc_mir", "rustc_plugin", @@ -3556,6 +3557,7 @@ dependencies = [ "rustc_plugin_impl", "rustc_privacy", "rustc_resolve", + "rustc_target", "rustc_traits", "rustc_typeck", "serialize", diff --git a/config.toml.example b/config.toml.example index 2e3b714f922..be977024426 100644 --- a/config.toml.example +++ b/config.toml.example @@ -374,10 +374,7 @@ # This is an array of the codegen backends that will be compiled for the rustc # that's being compiled. The default is to only build the LLVM codegen backend, -# but you can also optionally enable the "emscripten" backend for asm.js or -# make this an empty array (but that probably won't get too far in the -# bootstrap) -# FIXME: remove the obsolete emscripten backend option. +# and currently the only standard option supported is `"llvm"` #codegen-backends = ["llvm"] # This is the name of the directory in which codegen backends will get installed diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 65129eeeec5..4caf36a6f2a 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -734,10 +734,6 @@ class RustBuild(object): if module.endswith("llvm-project"): if self.get_toml('llvm-config') and self.get_toml('lld') != 'true': continue - if module.endswith("llvm-emscripten"): - backends = self.get_toml('codegen-backends') - if backends is None or not 'emscripten' in backends: - continue check = self.check_submodule(module, slow_submodules) filtered_submodules.append((module, check)) submodules_names.append(module) diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index 53071df8552..4310f2c6fa1 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -161,7 +161,7 @@ impl Ord for Interned<String> { } } -struct TyIntern<T: Hash + Clone + Eq> { +struct TyIntern<T: Clone + Eq> { items: Vec<T>, set: HashMap<T, Interned<T>>, } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 6ea32edfb20..5074b035789 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -210,7 +210,6 @@ pub fn std_cargo(builder: &Builder<'_>, // config.toml equivalent) is used let llvm_config = builder.ensure(native::Llvm { target: builder.config.build, - emscripten: false, }); cargo.env("LLVM_CONFIG", llvm_config); cargo.env("RUSTC_BUILD_SANITIZERS", "1"); @@ -615,36 +614,27 @@ pub fn build_codegen_backend(builder: &Builder<'_>, compiler: &Compiler, target: Interned<String>, backend: Interned<String>) -> String { - let mut features = String::new(); - match &*backend { - "llvm" | "emscripten" => { + "llvm" => { // Build LLVM for our target. This will implicitly build the // host LLVM if necessary. let llvm_config = builder.ensure(native::Llvm { target, - emscripten: backend == "emscripten", }); - if backend == "emscripten" { - features.push_str(" emscripten"); - } - builder.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})", compiler.stage, &compiler.host, target, backend)); // Pass down configuration from the LLVM build into the build of // librustc_llvm and librustc_codegen_llvm. - if builder.is_rust_llvm(target) && backend != "emscripten" { + if builder.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); } cargo.env("LLVM_CONFIG", &llvm_config); - if backend != "emscripten" { - let target_config = builder.config.target_config.get(&target); - if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - cargo.env("CFG_LLVM_ROOT", s); - } + let target_config = builder.config.target_config.get(&target); + if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { + cargo.env("CFG_LLVM_ROOT", s); } // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm. if let Some(ref s) = builder.config.llvm_ldflags { @@ -662,9 +652,7 @@ pub fn build_codegen_backend(builder: &Builder<'_>, "libstdc++.a"); cargo.env("LLVM_STATIC_STDCPP", file); } - if builder.config.llvm_link_shared || - (builder.config.llvm_thin_lto && backend != "emscripten") - { + if builder.config.llvm_link_shared || builder.config.llvm_thin_lto { cargo.env("LLVM_LINK_SHARED", "1"); } if builder.config.llvm_use_libcxx { @@ -676,8 +664,7 @@ pub fn build_codegen_backend(builder: &Builder<'_>, } _ => panic!("unknown backend: {}", backend), } - - features + String::new() } /// Creates the `codegen-backends` folder for a compiler that's about to be diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 52b5cd888df..441bb8d68fa 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -668,7 +668,6 @@ impl Config { pub fn llvm_enabled(&self) -> bool { self.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) - || self.rust_codegen_backends.contains(&INTERNER.intern_str("emscripten")) } } diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 346f0cb2039..76509134f7c 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -55,7 +55,6 @@ o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, m o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball") o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo") o("profiler", "build.profiler", "build the profiler runtime") -o("emscripten", None, "compile the emscripten backend as well as LLVM") o("full-tools", None, "enable all tools") o("lld", "rust.lld", "build lld") o("lldb", "rust.lldb", "build lldb") @@ -335,10 +334,8 @@ for key in known_args: set('build.host', value.split(',')) elif option.name == 'target': set('build.target', value.split(',')) - elif option.name == 'emscripten': - set('rust.codegen-backends', ['llvm', 'emscripten']) elif option.name == 'full-tools': - set('rust.codegen-backends', ['llvm', 'emscripten']) + set('rust.codegen-backends', ['llvm']) set('rust.lld', True) set('rust.llvm-tools', True) set('build.extended', True) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index d9dff77a30e..514ad114449 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -826,7 +826,6 @@ fn copy_src_dirs(builder: &Builder<'_>, src_dirs: &[&str], exclude_dirs: &[&str] const LLVM_TEST: &[&str] = &[ "llvm-project/llvm/test", "llvm-project\\llvm\\test", - "llvm-emscripten/test", "llvm-emscripten\\test", ]; if LLVM_TEST.iter().any(|path| spath.contains(path)) && (spath.ends_with(".ll") || @@ -834,9 +833,6 @@ fn copy_src_dirs(builder: &Builder<'_>, src_dirs: &[&str], exclude_dirs: &[&str] spath.ends_with(".s")) { return false } - if spath.contains("test/emscripten") || spath.contains("test\\emscripten") { - return false - } let full_path = Path::new(dir).join(path); if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 6fc72fa0b2a..a182405f3b2 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -232,7 +232,6 @@ pub struct Build { miri_info: channel::GitInfo, rustfmt_info: channel::GitInfo, in_tree_llvm_info: channel::GitInfo, - emscripten_llvm_info: channel::GitInfo, local_rebuild: bool, fail_fast: bool, doc_tests: DocTests, @@ -351,7 +350,6 @@ impl Build { // we always try to use git for LLVM builds let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project")); - let emscripten_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-emscripten")); let mut build = Build { initial_rustc: config.initial_rustc.clone(), @@ -376,7 +374,6 @@ impl Build { miri_info, rustfmt_info, in_tree_llvm_info, - emscripten_llvm_info, cc: HashMap::new(), cxx: HashMap::new(), ar: HashMap::new(), @@ -553,10 +550,6 @@ impl Build { self.out.join(&*target).join("llvm") } - fn emscripten_llvm_out(&self, target: Interned<String>) -> PathBuf { - self.out.join(&*target).join("llvm-emscripten") - } - fn lld_out(&self, target: Interned<String>) -> PathBuf { self.out.join(&*target).join("lld") } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index fb308bc35eb..97cdd256801 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -28,7 +28,6 @@ use crate::GitRepo; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Llvm { pub target: Interned<String>, - pub emscripten: bool, } impl Step for Llvm { @@ -40,46 +39,35 @@ impl Step for Llvm { run.path("src/llvm-project") .path("src/llvm-project/llvm") .path("src/llvm") - .path("src/llvm-emscripten") } fn make_run(run: RunConfig<'_>) { - let emscripten = run.path.ends_with("llvm-emscripten"); run.builder.ensure(Llvm { target: run.target, - emscripten, }); } /// Compile LLVM for `target`. fn run(self, builder: &Builder<'_>) -> PathBuf { let target = self.target; - let emscripten = self.emscripten; // If we're using a custom LLVM bail out here, but we can only use a // custom LLVM for the build triple. - if !self.emscripten { - if let Some(config) = builder.config.target_config.get(&target) { - if let Some(ref s) = config.llvm_config { - check_llvm_version(builder, s); - return s.to_path_buf() - } + if let Some(config) = builder.config.target_config.get(&target) { + if let Some(ref s) = config.llvm_config { + check_llvm_version(builder, s); + return s.to_path_buf() } } - let (llvm_info, root, out_dir, llvm_config_ret_dir) = if emscripten { - let info = &builder.emscripten_llvm_info; - let dir = builder.emscripten_llvm_out(target); - let config_dir = dir.join("bin"); - (info, "src/llvm-emscripten", dir, config_dir) - } else { - let info = &builder.in_tree_llvm_info; - let mut dir = builder.llvm_out(builder.config.build); - if !builder.config.build.contains("msvc") || builder.config.ninja { - dir.push("build"); - } - (info, "src/llvm-project/llvm", builder.llvm_out(target), dir.join("bin")) - }; + let llvm_info = &builder.in_tree_llvm_info; + let root = "src/llvm-project/llvm"; + let out_dir = builder.llvm_out(target); + let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build); + if !builder.config.build.contains("msvc") || builder.config.ninja { + llvm_config_ret_dir.push("build"); + } + llvm_config_ret_dir.push("bin"); let build_llvm_config = llvm_config_ret_dir .join(exe("llvm-config", &*builder.config.build)); @@ -107,8 +95,7 @@ impl Step for Llvm { } } - let descriptor = if emscripten { "Emscripten " } else { "" }; - builder.info(&format!("Building {}LLVM for {}", descriptor, target)); + builder.info(&format!("Building LLVM for {}", target)); let _time = util::timeit(&builder); t!(fs::create_dir_all(&out_dir)); @@ -123,23 +110,15 @@ impl Step for Llvm { // NOTE: remember to also update `config.toml.example` when changing the // defaults! - let llvm_targets = if self.emscripten { - "JSBackend" - } else { - match builder.config.llvm_targets { - Some(ref s) => s, - None => "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\ - Sparc;SystemZ;WebAssembly;X86", - } + let llvm_targets = match &builder.config.llvm_targets { + Some(s) => s, + None => "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\ + Sparc;SystemZ;WebAssembly;X86", }; - let llvm_exp_targets = if self.emscripten { - "" - } else { - match builder.config.llvm_experimental_targets { - Some(ref s) => s, - None => "", - } + let llvm_exp_targets = match builder.config.llvm_experimental_targets { + Some(ref s) => s, + None => "", }; let assertions = if builder.config.llvm_assertions {"ON"} else {"OFF"}; @@ -163,25 +142,23 @@ impl Step for Llvm { .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); - if builder.config.llvm_thin_lto && !emscripten { + if builder.config.llvm_thin_lto { cfg.define("LLVM_ENABLE_LTO", "Thin"); if !target.contains("apple") { cfg.define("LLVM_ENABLE_LLD", "ON"); } } - let want_lldb = builder.config.lldb_enabled && !self.emscripten; - // This setting makes the LLVM tools link to the dynamic LLVM library, // which saves both memory during parallel links and overall disk space // for the tools. We don't do this on every platform as it doesn't work // equally well everywhere. - if builder.llvm_link_tools_dynamically(target) && !emscripten { + if builder.llvm_link_tools_dynamically(target) { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } // For distribution we want the LLVM tools to be *statically* linked to libstdc++ - if builder.config.llvm_tools_enabled || want_lldb { + if builder.config.llvm_tools_enabled || builder.config.lldb_enabled { if !target.contains("windows") { if target.contains("apple") { cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++"); @@ -209,7 +186,7 @@ impl Step for Llvm { enabled_llvm_projects.push("compiler-rt"); } - if want_lldb { + if builder.config.lldb_enabled { enabled_llvm_projects.push("clang"); enabled_llvm_projects.push("lldb"); // For the time being, disable code signing. @@ -234,10 +211,9 @@ impl Step for Llvm { } // http://llvm.org/docs/HowToCrossCompileLLVM.html - if target != builder.config.build && !emscripten { + if target != builder.config.build { builder.ensure(Llvm { target: builder.config.build, - emscripten: false, }); // FIXME: if the llvm root for the build triple is overridden then we // should use llvm-tblgen from there, also should verify that it @@ -481,7 +457,6 @@ impl Step for Lld { let llvm_config = builder.ensure(Llvm { target: self.target, - emscripten: false, }); let out_dir = builder.lld_out(target); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e09e25de64a..7ed67c6c7c5 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -427,7 +427,7 @@ impl Step for Miri { // (We do this separately from the above so that when the setup actually // happens we get some output.) // We re-use the `cargo` from above. - cargo.arg("--env"); + cargo.arg("--print-sysroot"); // FIXME: Is there a way in which we can re-use the usual `run` helpers? let miri_sysroot = if builder.config.dry_run { @@ -437,13 +437,11 @@ impl Step for Miri { let out = cargo.output() .expect("We already ran `cargo miri setup` before and that worked"); assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code"); - // Output is "MIRI_SYSROOT=<str>\n". + // Output is "<sysroot>\n". let stdout = String::from_utf8(out.stdout) .expect("`cargo miri setup` stdout is not valid UTF-8"); - let stdout = stdout.trim(); - builder.verbose(&format!("`cargo miri setup --env` returned: {:?}", stdout)); - let sysroot = stdout.splitn(2, '=') - .nth(1).expect("`cargo miri setup` stdout did not contain '='"); + let sysroot = stdout.trim_end(); + builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot)); sysroot.to_owned() }; @@ -1165,7 +1163,7 @@ impl Step for Compiletest { }).to_string() }) }; - let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") { + let lldb_exe = if builder.config.lldb_enabled { // Test against the lldb that was just built. builder.llvm_out(target).join("bin").join("lldb") } else { @@ -1234,7 +1232,6 @@ impl Step for Compiletest { if builder.config.llvm_enabled() { let llvm_config = builder.ensure(native::Llvm { target: builder.config.build, - emscripten: false, }); if !builder.config.dry_run { let llvm_version = output(Command::new(&llvm_config).arg("--version")); diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 367e4384992..a2d83eca24b 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -165,8 +165,7 @@ For targets: `arm-unknown-linux-gnueabihf` For targets: `armv7-unknown-linux-gnueabihf` - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} -- Path and misc options > Patches origin = Bundled, then local -- Path and misc options > Local patch directory = /tmp/patches +- Path and misc options > Patches origin = Bundled only - Target options > Target Architecture = arm - Target options > Suffix to the arch-part = v7 - Target options > Architecture level = armv7-a -- (+) @@ -174,9 +173,9 @@ For targets: `armv7-unknown-linux-gnueabihf` - Target options > Floating point = hardware (FPU) -- (\*) - Target options > Default instruction set mode = thumb -- (\*) - Operating System > Target OS = linux -- Operating System > Linux kernel version = 3.2.72 -- Precise kernel -- C-library > glibc version = 2.16.0 -- C compiler > gcc version = 5.2.0 +- Operating System > Linux kernel version = 3.2.101 +- C-library > glibc version = 2.17.0 +- C compiler > gcc version = 8.3.0 - C compiler > C++ = ENABLE -- to cross compile LLVM (\*) These options have been selected to match the configuration of the arm diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile index 170b8134d3e..417171a861d 100644 --- a/src/ci/docker/dist-armv7-linux/Dockerfile +++ b/src/ci/docker/dist-armv7-linux/Dockerfile @@ -3,12 +3,7 @@ FROM ubuntu:16.04 COPY scripts/cross-apt-packages.sh /scripts/ RUN sh /scripts/cross-apt-packages.sh -# Ubuntu 16.04 (this container) ships with make 4, but something in the -# toolchains we build below chokes on that, so go back to make 3 -COPY scripts/make3.sh /scripts/ -RUN sh /scripts/make3.sh - -COPY scripts/crosstool-ng.sh /scripts/ +COPY dist-armv7-linux/crosstool-ng.sh /scripts/ RUN sh /scripts/crosstool-ng.sh COPY scripts/rustbuild-setup.sh /scripts/ @@ -16,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh USER rustbuild WORKDIR /tmp -COPY dist-armv7-linux/patches/ /tmp/patches/ COPY dist-armv7-linux/build-toolchains.sh dist-armv7-linux/armv7-linux-gnueabihf.config /tmp/ RUN ./build-toolchains.sh diff --git a/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config index 5cccfd8444d..81b3d7477ec 100644 --- a/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config +++ b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config @@ -1,9 +1,32 @@ # # Automatically generated file; DO NOT EDIT. -# Crosstool-NG Configuration -# -CT_CONFIGURE_has_make381=y -CT_CONFIGURE_has_xz=y +# crosstool-NG Configuration +# +CT_CONFIGURE_has_static_link=y +CT_CONFIGURE_has_cxx11=y +CT_CONFIGURE_has_wget=y +CT_CONFIGURE_has_curl=y +CT_CONFIGURE_has_make_3_81_or_newer=y +CT_CONFIGURE_has_make_4_0_or_newer=y +CT_CONFIGURE_has_libtool_2_4_or_newer=y +CT_CONFIGURE_has_libtoolize_2_4_or_newer=y +CT_CONFIGURE_has_autoconf_2_65_or_newer=y +CT_CONFIGURE_has_autoreconf_2_65_or_newer=y +CT_CONFIGURE_has_automake_1_15_or_newer=y +CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y +CT_CONFIGURE_has_python_3_4_or_newer=y +CT_CONFIGURE_has_bison_2_7_or_newer=y +CT_CONFIGURE_has_python=y +CT_CONFIGURE_has_dtc=y +CT_CONFIGURE_has_svn=y +CT_CONFIGURE_has_git=y +CT_CONFIGURE_has_md5sum=y +CT_CONFIGURE_has_sha1sum=y +CT_CONFIGURE_has_sha256sum=y +CT_CONFIGURE_has_sha512sum=y +CT_CONFIGURE_has_install_with_strip_program=y +CT_CONFIG_VERSION_CURRENT="3" +CT_CONFIG_VERSION="3" CT_MODULES=y # @@ -21,40 +44,46 @@ CT_MODULES=y # Paths # CT_LOCAL_TARBALLS_DIR="" +# CT_TARBALLS_BUILDROOT_LAYOUT is not set CT_WORK_DIR="${CT_TOP_DIR}/.build" +CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}" CT_PREFIX_DIR="/x-tools/${CT_TARGET}" -CT_INSTALL_DIR="${CT_PREFIX_DIR}" CT_RM_RF_PREFIX_DIR=y CT_REMOVE_DOCS=y -CT_INSTALL_DIR_RO=y +CT_INSTALL_LICENSES=y +CT_PREFIX_DIR_RO=y CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y # CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set # # Downloading # +CT_DOWNLOAD_AGENT_WGET=y +# CT_DOWNLOAD_AGENT_CURL is not set +# CT_DOWNLOAD_AGENT_NONE is not set # CT_FORBID_DOWNLOAD is not set # CT_FORCE_DOWNLOAD is not set CT_CONNECT_TIMEOUT=10 +CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary" # CT_ONLY_DOWNLOAD is not set # CT_USE_MIRROR is not set +CT_VERIFY_DOWNLOAD_DIGEST=y +CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y +# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set +# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set +# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set +CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512" +# CT_VERIFY_DOWNLOAD_SIGNATURE is not set # # Extracting # # CT_FORCE_EXTRACT is not set -CT_OVERIDE_CONFIG_GUESS_SUB=y +CT_OVERRIDE_CONFIG_GUESS_SUB=y # CT_ONLY_EXTRACT is not set -# CT_PATCH_BUNDLED is not set -# CT_PATCH_LOCAL is not set -CT_PATCH_BUNDLED_LOCAL=y -# CT_PATCH_LOCAL_BUNDLED is not set -# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set -# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set -# CT_PATCH_NONE is not set -CT_PATCH_ORDER="bundled,local" -CT_PATCH_USE_LOCAL=y -CT_LOCAL_PATCH_DIR="/tmp/patches" +CT_PATCH_BUNDLED=y +# CT_PATCH_BUNDLED_LOCAL is not set +CT_PATCH_ORDER="bundled" # # Build behavior @@ -90,87 +119,82 @@ CT_LOG_FILE_COMPRESS=y # # Target options # +# CT_ARCH_ALPHA is not set +# CT_ARCH_ARC is not set +CT_ARCH_ARM=y +# CT_ARCH_AVR is not set +# CT_ARCH_M68K is not set +# CT_ARCH_MIPS is not set +# CT_ARCH_NIOS2 is not set +# CT_ARCH_POWERPC is not set +# CT_ARCH_S390 is not set +# CT_ARCH_SH is not set +# CT_ARCH_SPARC is not set +# CT_ARCH_X86 is not set +# CT_ARCH_XTENSA is not set CT_ARCH="arm" -CT_ARCH_SUPPORTS_BOTH_MMU=y -CT_ARCH_SUPPORTS_BOTH_ENDIAN=y -CT_ARCH_SUPPORTS_32=y -CT_ARCH_SUPPORTS_64=y -CT_ARCH_SUPPORTS_WITH_ARCH=y -CT_ARCH_SUPPORTS_WITH_CPU=y -CT_ARCH_SUPPORTS_WITH_TUNE=y -CT_ARCH_SUPPORTS_WITH_FLOAT=y -CT_ARCH_SUPPORTS_WITH_FPU=y -CT_ARCH_SUPPORTS_SOFTFP=y -CT_ARCH_DEFAULT_HAS_MMU=y -CT_ARCH_DEFAULT_LE=y -CT_ARCH_DEFAULT_32=y -CT_ARCH_ARCH="armv7-a" +CT_ARCH_CHOICE_KSYM="ARM" CT_ARCH_CPU="" CT_ARCH_TUNE="" -CT_ARCH_FPU="vfpv3-d16" -# CT_ARCH_BE is not set -CT_ARCH_LE=y -CT_ARCH_32=y -# CT_ARCH_64 is not set -CT_ARCH_BITNESS=32 -CT_ARCH_FLOAT_HW=y -# CT_ARCH_FLOAT_SW is not set -CT_TARGET_CFLAGS="" -CT_TARGET_LDFLAGS="" -# CT_ARCH_alpha is not set -CT_ARCH_arm=y -# CT_ARCH_avr is not set -# CT_ARCH_m68k is not set -# CT_ARCH_mips is not set -# CT_ARCH_nios2 is not set -# CT_ARCH_powerpc is not set -# CT_ARCH_s390 is not set -# CT_ARCH_sh is not set -# CT_ARCH_sparc is not set -# CT_ARCH_x86 is not set -# CT_ARCH_xtensa is not set -CT_ARCH_alpha_AVAILABLE=y -CT_ARCH_arm_AVAILABLE=y -CT_ARCH_avr_AVAILABLE=y -CT_ARCH_m68k_AVAILABLE=y -CT_ARCH_microblaze_AVAILABLE=y -CT_ARCH_mips_AVAILABLE=y -CT_ARCH_nios2_AVAILABLE=y -CT_ARCH_powerpc_AVAILABLE=y -CT_ARCH_s390_AVAILABLE=y -CT_ARCH_sh_AVAILABLE=y -CT_ARCH_sparc_AVAILABLE=y -CT_ARCH_x86_AVAILABLE=y -CT_ARCH_xtensa_AVAILABLE=y +CT_ARCH_ARM_SHOW=y + +# +# Options for arm +# +CT_ARCH_ARM_PKG_KSYM="" +CT_ARCH_ARM_MODE="thumb" +# CT_ARCH_ARM_MODE_ARM is not set +CT_ARCH_ARM_MODE_THUMB=y +# CT_ARCH_ARM_INTERWORKING is not set +CT_ARCH_ARM_EABI_FORCE=y +CT_ARCH_ARM_EABI=y +CT_ARCH_ARM_TUPLE_USE_EABIHF=y +CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA" CT_ARCH_SUFFIX="v7" +# CT_OMIT_TARGET_VENDOR is not set # # Generic target options # # CT_MULTILIB is not set +CT_DEMULTILIB=y +CT_ARCH_SUPPORTS_BOTH_MMU=y +CT_ARCH_DEFAULT_HAS_MMU=y CT_ARCH_USE_MMU=y +CT_ARCH_SUPPORTS_FLAT_FORMAT=y +CT_ARCH_SUPPORTS_EITHER_ENDIAN=y +CT_ARCH_DEFAULT_LE=y +# CT_ARCH_BE is not set +CT_ARCH_LE=y CT_ARCH_ENDIAN="little" +CT_ARCH_SUPPORTS_32=y +CT_ARCH_SUPPORTS_64=y +CT_ARCH_DEFAULT_32=y +CT_ARCH_BITNESS=32 +CT_ARCH_32=y +# CT_ARCH_64 is not set # # Target optimisations # +CT_ARCH_SUPPORTS_WITH_ARCH=y +CT_ARCH_SUPPORTS_WITH_CPU=y +CT_ARCH_SUPPORTS_WITH_TUNE=y +CT_ARCH_SUPPORTS_WITH_FLOAT=y +CT_ARCH_SUPPORTS_WITH_FPU=y +CT_ARCH_SUPPORTS_SOFTFP=y CT_ARCH_EXCLUSIVE_WITH_CPU=y +CT_ARCH_ARCH="armv7-a" +CT_ARCH_FPU="vfpv3-d16" # CT_ARCH_FLOAT_AUTO is not set +CT_ARCH_FLOAT_HW=y # CT_ARCH_FLOAT_SOFTFP is not set +# CT_ARCH_FLOAT_SW is not set +CT_TARGET_CFLAGS="" +CT_TARGET_LDFLAGS="" CT_ARCH_FLOAT="hard" # -# arm other options -# -CT_ARCH_ARM_MODE="thumb" -# CT_ARCH_ARM_MODE_ARM is not set -CT_ARCH_ARM_MODE_THUMB=y -# CT_ARCH_ARM_INTERWORKING is not set -CT_ARCH_ARM_EABI_FORCE=y -CT_ARCH_ARM_EABI=y -CT_ARCH_ARM_TUPLE_USE_EABIHF=y - -# # Toolchain options # @@ -182,7 +206,9 @@ CT_USE_SYSROOT=y CT_SYSROOT_NAME="sysroot" CT_SYSROOT_DIR_PREFIX="" CT_WANTS_STATIC_LINK=y +CT_WANTS_STATIC_LINK_CXX=y # CT_STATIC_TOOLCHAIN is not set +CT_SHOW_CT_VERSION=y CT_TOOLCHAIN_PKGVERSION="" CT_TOOLCHAIN_BUGURL="" @@ -216,126 +242,207 @@ CT_BUILD_SUFFIX="" # Operating System # CT_KERNEL_SUPPORTS_SHARED_LIBS=y +# CT_KERNEL_BARE_METAL is not set +CT_KERNEL_LINUX=y CT_KERNEL="linux" -CT_KERNEL_VERSION="3.2.72" -# CT_KERNEL_bare_metal is not set -CT_KERNEL_linux=y -CT_KERNEL_bare_metal_AVAILABLE=y -CT_KERNEL_linux_AVAILABLE=y -# CT_KERNEL_V_4_3 is not set -# CT_KERNEL_V_4_2 is not set -# CT_KERNEL_V_4_1 is not set -# CT_KERNEL_V_3_18 is not set -# CT_KERNEL_V_3_14 is not set -# CT_KERNEL_V_3_12 is not set -# CT_KERNEL_V_3_10 is not set -# CT_KERNEL_V_3_4 is not set -CT_KERNEL_V_3_2=y -# CT_KERNEL_V_2_6_32 is not set -# CT_KERNEL_LINUX_CUSTOM is not set -CT_KERNEL_windows_AVAILABLE=y - -# -# Common kernel options -# -CT_SHARED_LIBS=y - -# -# linux other options -# +CT_KERNEL_CHOICE_KSYM="LINUX" +CT_KERNEL_LINUX_SHOW=y + +# +# Options for linux +# +CT_KERNEL_LINUX_PKG_KSYM="LINUX" +CT_LINUX_DIR_NAME="linux" +CT_LINUX_PKG_NAME="linux" +CT_LINUX_SRC_RELEASE=y +CT_LINUX_PATCH_ORDER="global" +# CT_LINUX_V_4_20 is not set +# CT_LINUX_V_4_19 is not set +# CT_LINUX_V_4_18 is not set +# CT_LINUX_V_4_17 is not set +# CT_LINUX_V_4_16 is not set +# CT_LINUX_V_4_15 is not set +# CT_LINUX_V_4_14 is not set +# CT_LINUX_V_4_13 is not set +# CT_LINUX_V_4_12 is not set +# CT_LINUX_V_4_11 is not set +# CT_LINUX_V_4_10 is not set +# CT_LINUX_V_4_9 is not set +# CT_LINUX_V_4_4 is not set +# CT_LINUX_V_4_1 is not set +# CT_LINUX_V_3_16 is not set +# CT_LINUX_V_3_13 is not set +# CT_LINUX_V_3_12 is not set +# CT_LINUX_V_3_10 is not set +# CT_LINUX_V_3_4 is not set +CT_LINUX_V_3_2=y +# CT_LINUX_V_2_6_32 is not set +# CT_LINUX_NO_VERSIONS is not set +CT_LINUX_VERSION="3.2.101" +CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})" +CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz" +CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign" +CT_LINUX_4_8_or_older=y +CT_LINUX_older_than_4_8=y +CT_LINUX_3_7_or_older=y +CT_LINUX_older_than_3_7=y +CT_LINUX_later_than_3_2=y +CT_LINUX_3_2_or_later=y CT_KERNEL_LINUX_VERBOSITY_0=y # CT_KERNEL_LINUX_VERBOSITY_1 is not set # CT_KERNEL_LINUX_VERBOSITY_2 is not set CT_KERNEL_LINUX_VERBOSE_LEVEL=0 CT_KERNEL_LINUX_INSTALL_CHECK=y +CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS" + +# +# Common kernel options +# +CT_SHARED_LIBS=y # # Binary utilities # CT_ARCH_BINFMT_ELF=y +CT_BINUTILS_BINUTILS=y CT_BINUTILS="binutils" -CT_BINUTILS_binutils=y +CT_BINUTILS_CHOICE_KSYM="BINUTILS" +CT_BINUTILS_BINUTILS_SHOW=y + +# +# Options for binutils +# +CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS" +CT_BINUTILS_DIR_NAME="binutils" +CT_BINUTILS_USE_GNU=y +CT_BINUTILS_USE="BINUTILS" +CT_BINUTILS_PKG_NAME="binutils" +CT_BINUTILS_SRC_RELEASE=y +CT_BINUTILS_PATCH_ORDER="global" +CT_BINUTILS_V_2_32=y +# CT_BINUTILS_V_2_31 is not set +# CT_BINUTILS_V_2_30 is not set +# CT_BINUTILS_V_2_29 is not set +# CT_BINUTILS_V_2_28 is not set +# CT_BINUTILS_V_2_27 is not set +# CT_BINUTILS_V_2_26 is not set +# CT_BINUTILS_NO_VERSIONS is not set +CT_BINUTILS_VERSION="2.32" +CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)" +CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" +CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig" +CT_BINUTILS_later_than_2_30=y +CT_BINUTILS_2_30_or_later=y +CT_BINUTILS_later_than_2_27=y +CT_BINUTILS_2_27_or_later=y +CT_BINUTILS_later_than_2_25=y +CT_BINUTILS_2_25_or_later=y +CT_BINUTILS_later_than_2_23=y +CT_BINUTILS_2_23_or_later=y # # GNU binutils # -# CT_CC_BINUTILS_SHOW_LINARO is not set -CT_BINUTILS_V_2_25_1=y -# CT_BINUTILS_V_2_25 is not set -# CT_BINUTILS_V_2_24 is not set -# CT_BINUTILS_V_2_23_2 is not set -# CT_BINUTILS_V_2_23_1 is not set -# CT_BINUTILS_V_2_22 is not set -# CT_BINUTILS_V_2_21_53 is not set -# CT_BINUTILS_V_2_21_1a is not set -# CT_BINUTILS_V_2_20_1a is not set -# CT_BINUTILS_V_2_19_1a is not set -# CT_BINUTILS_V_2_18a is not set -CT_BINUTILS_VERSION="2.25.1" -CT_BINUTILS_2_25_1_or_later=y -CT_BINUTILS_2_25_or_later=y -CT_BINUTILS_2_24_or_later=y -CT_BINUTILS_2_23_or_later=y -CT_BINUTILS_2_22_or_later=y -CT_BINUTILS_2_21_or_later=y -CT_BINUTILS_2_20_or_later=y -CT_BINUTILS_2_19_or_later=y -CT_BINUTILS_2_18_or_later=y CT_BINUTILS_HAS_HASH_STYLE=y CT_BINUTILS_HAS_GOLD=y -CT_BINUTILS_GOLD_SUPPORTS_ARCH=y -CT_BINUTILS_GOLD_SUPPORT=y CT_BINUTILS_HAS_PLUGINS=y CT_BINUTILS_HAS_PKGVERSION_BUGURL=y -CT_BINUTILS_FORCE_LD_BFD=y +CT_BINUTILS_GOLD_SUPPORTS_ARCH=y +CT_BINUTILS_GOLD_SUPPORT=y +CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y CT_BINUTILS_LINKER_LD=y # CT_BINUTILS_LINKER_LD_GOLD is not set -# CT_BINUTILS_LINKER_GOLD_LD is not set CT_BINUTILS_LINKERS_LIST="ld" CT_BINUTILS_LINKER_DEFAULT="bfd" # CT_BINUTILS_PLUGINS is not set +CT_BINUTILS_RELRO=m CT_BINUTILS_EXTRA_CONFIG_ARRAY="" # CT_BINUTILS_FOR_TARGET is not set - -# -# binutils other options -# +CT_ALL_BINUTILS_CHOICES="BINUTILS" # # C-library # +CT_LIBC_GLIBC=y +# CT_LIBC_UCLIBC is not set CT_LIBC="glibc" -CT_LIBC_VERSION="2.16.0" -CT_LIBC_glibc=y -# CT_LIBC_musl is not set -# CT_LIBC_uClibc is not set -CT_LIBC_avr_libc_AVAILABLE=y -CT_LIBC_glibc_AVAILABLE=y +CT_LIBC_CHOICE_KSYM="GLIBC" CT_THREADS="nptl" -# CT_CC_GLIBC_SHOW_LINARO is not set -# CT_LIBC_GLIBC_V_2_22 is not set -# CT_LIBC_GLIBC_V_2_21 is not set -# CT_LIBC_GLIBC_V_2_20 is not set -# CT_LIBC_GLIBC_V_2_19 is not set -# CT_LIBC_GLIBC_V_2_18 is not set -# CT_LIBC_GLIBC_V_2_17 is not set -CT_LIBC_GLIBC_V_2_16_0=y -# CT_LIBC_GLIBC_V_2_15 is not set -# CT_LIBC_GLIBC_V_2_14_1 is not set -# CT_LIBC_GLIBC_V_2_14 is not set -# CT_LIBC_GLIBC_V_2_13 is not set -# CT_LIBC_GLIBC_V_2_12_2 is not set -# CT_LIBC_GLIBC_V_2_12_1 is not set -# CT_LIBC_GLIBC_V_2_11_1 is not set -# CT_LIBC_GLIBC_V_2_11 is not set -# CT_LIBC_GLIBC_V_2_10_1 is not set -# CT_LIBC_GLIBC_V_2_9 is not set -# CT_LIBC_GLIBC_V_2_8 is not set -CT_LIBC_mingw_AVAILABLE=y -CT_LIBC_musl_AVAILABLE=y -CT_LIBC_newlib_AVAILABLE=y -CT_LIBC_none_AVAILABLE=y -CT_LIBC_uClibc_AVAILABLE=y +CT_LIBC_GLIBC_SHOW=y + +# +# Options for glibc +# +CT_LIBC_GLIBC_PKG_KSYM="GLIBC" +CT_GLIBC_DIR_NAME="glibc" +CT_GLIBC_USE_GNU=y +CT_GLIBC_USE="GLIBC" +CT_GLIBC_PKG_NAME="glibc" +CT_GLIBC_SRC_RELEASE=y +CT_GLIBC_PATCH_ORDER="global" +# CT_GLIBC_V_2_29 is not set +# CT_GLIBC_V_2_28 is not set +# CT_GLIBC_V_2_27 is not set +# CT_GLIBC_V_2_26 is not set +# CT_GLIBC_V_2_25 is not set +# CT_GLIBC_V_2_24 is not set +# CT_GLIBC_V_2_23 is not set +# CT_GLIBC_V_2_19 is not set +CT_GLIBC_V_2_17=y +# CT_GLIBC_V_2_12_1 is not set +# CT_GLIBC_NO_VERSIONS is not set +CT_GLIBC_VERSION="2.17" +CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)" +CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" +CT_GLIBC_SIGNATURE_FORMAT="packed/.sig" +CT_GLIBC_2_29_or_older=y +CT_GLIBC_older_than_2_29=y +CT_GLIBC_2_27_or_older=y +CT_GLIBC_older_than_2_27=y +CT_GLIBC_2_26_or_older=y +CT_GLIBC_older_than_2_26=y +CT_GLIBC_2_25_or_older=y +CT_GLIBC_older_than_2_25=y +CT_GLIBC_2_24_or_older=y +CT_GLIBC_older_than_2_24=y +CT_GLIBC_2_23_or_older=y +CT_GLIBC_older_than_2_23=y +CT_GLIBC_2_20_or_older=y +CT_GLIBC_older_than_2_20=y +CT_GLIBC_2_17_or_later=y +CT_GLIBC_2_17_or_older=y +CT_GLIBC_later_than_2_14=y +CT_GLIBC_2_14_or_later=y +CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y +CT_GLIBC_DEP_BINUTILS=y +CT_GLIBC_DEP_GCC=y +CT_GLIBC_DEP_PYTHON=y +CT_GLIBC_HAS_NPTL_ADDON=y +CT_GLIBC_HAS_PORTS_ADDON=y +CT_GLIBC_HAS_LIBIDN_ADDON=y +CT_GLIBC_USE_PORTS_ADDON=y +CT_GLIBC_USE_NPTL_ADDON=y +# CT_GLIBC_USE_LIBIDN_ADDON is not set +CT_GLIBC_HAS_OBSOLETE_RPC=y +CT_GLIBC_EXTRA_CONFIG_ARRAY="" +CT_GLIBC_CONFIGPARMS="" +CT_GLIBC_EXTRA_CFLAGS="" +CT_GLIBC_ENABLE_OBSOLETE_RPC=y +# CT_GLIBC_DISABLE_VERSIONING is not set +CT_GLIBC_OLDEST_ABI="" +CT_GLIBC_FORCE_UNWIND=y +# CT_GLIBC_LOCALES is not set +# CT_GLIBC_KERNEL_VERSION_NONE is not set +CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y +# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set +CT_GLIBC_MIN_KERNEL="3.2.101" +CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC" CT_LIBC_SUPPORT_THREADS_ANY=y CT_LIBC_SUPPORT_THREADS_NATIVE=y @@ -343,100 +450,71 @@ CT_LIBC_SUPPORT_THREADS_NATIVE=y # Common C library options # CT_THREADS_NATIVE=y +# CT_CREATE_LDSO_CONF is not set CT_LIBC_XLDD=y # -# glibc other options -# -CT_LIBC_GLIBC_PORTS_EXTERNAL=y -CT_LIBC_GLIBC_MAY_FORCE_PORTS=y -CT_LIBC_glibc_familly=y -CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY="" -CT_LIBC_GLIBC_CONFIGPARMS="" -CT_LIBC_GLIBC_EXTRA_CFLAGS="" -CT_LIBC_EXTRA_CC_ARGS="" -# CT_LIBC_DISABLE_VERSIONING is not set -CT_LIBC_OLDEST_ABI="" -CT_LIBC_GLIBC_FORCE_UNWIND=y -CT_LIBC_GLIBC_USE_PORTS=y -CT_LIBC_ADDONS_LIST="" - -# -# WARNING !!! -# - -# -# For glibc >= 2.8, it can happen that the tarballs -# - -# -# for the addons are not available for download. -# - -# -# If that happens, bad luck... Try a previous version -# - -# -# or try again later... :-( -# -# CT_LIBC_LOCALES is not set -# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set -CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y -# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set -CT_LIBC_GLIBC_MIN_KERNEL="3.2.72" - -# # C compiler # -CT_CC="gcc" CT_CC_CORE_PASSES_NEEDED=y CT_CC_CORE_PASS_1_NEEDED=y CT_CC_CORE_PASS_2_NEEDED=y -CT_CC_gcc=y -# CT_CC_GCC_SHOW_LINARO is not set -CT_CC_GCC_V_5_2_0=y -# CT_CC_GCC_V_4_9_3 is not set -# CT_CC_GCC_V_4_8_5 is not set -# CT_CC_GCC_V_4_7_4 is not set -# CT_CC_GCC_V_4_6_4 is not set -# CT_CC_GCC_V_4_5_4 is not set -# CT_CC_GCC_V_4_4_7 is not set -# CT_CC_GCC_V_4_3_6 is not set -# CT_CC_GCC_V_4_2_4 is not set -CT_CC_GCC_4_2_or_later=y -CT_CC_GCC_4_3_or_later=y -CT_CC_GCC_4_4_or_later=y -CT_CC_GCC_4_5_or_later=y -CT_CC_GCC_4_6_or_later=y -CT_CC_GCC_4_7_or_later=y -CT_CC_GCC_4_8_or_later=y -CT_CC_GCC_4_9_or_later=y -CT_CC_GCC_5=y -CT_CC_GCC_5_or_later=y -CT_CC_GCC_HAS_GRAPHITE=y -CT_CC_GCC_USE_GRAPHITE=y -CT_CC_GCC_HAS_LTO=y -CT_CC_GCC_USE_LTO=y -CT_CC_GCC_HAS_PKGVERSION_BUGURL=y -CT_CC_GCC_HAS_BUILD_ID=y -CT_CC_GCC_HAS_LNK_HASH_STYLE=y -CT_CC_GCC_USE_GMP_MPFR=y -CT_CC_GCC_USE_MPC=y -CT_CC_GCC_HAS_LIBQUADMATH=y -CT_CC_GCC_HAS_LIBSANITIZER=y -CT_CC_GCC_VERSION="5.2.0" -# CT_CC_LANG_FORTRAN is not set +CT_CC_SUPPORT_CXX=y +CT_CC_SUPPORT_FORTRAN=y +CT_CC_SUPPORT_ADA=y +CT_CC_SUPPORT_OBJC=y +CT_CC_SUPPORT_OBJCXX=y +CT_CC_SUPPORT_GOLANG=y +CT_CC_GCC=y +CT_CC="gcc" +CT_CC_CHOICE_KSYM="GCC" +CT_CC_GCC_SHOW=y + +# +# Options for gcc +# +CT_CC_GCC_PKG_KSYM="GCC" +CT_GCC_DIR_NAME="gcc" +CT_GCC_USE_GNU=y +CT_GCC_USE="GCC" +CT_GCC_PKG_NAME="gcc" +CT_GCC_SRC_RELEASE=y +CT_GCC_PATCH_ORDER="global" +CT_GCC_V_8=y +# CT_GCC_V_7 is not set +# CT_GCC_V_6 is not set +# CT_GCC_V_5 is not set +# CT_GCC_V_4_9 is not set +# CT_GCC_NO_VERSIONS is not set +CT_GCC_VERSION="8.3.0" +CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})" +CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz" +CT_GCC_SIGNATURE_FORMAT="" +CT_GCC_later_than_7=y +CT_GCC_7_or_later=y +CT_GCC_later_than_6=y +CT_GCC_6_or_later=y +CT_GCC_later_than_5=y +CT_GCC_5_or_later=y +CT_GCC_later_than_4_9=y +CT_GCC_4_9_or_later=y +CT_GCC_later_than_4_8=y +CT_GCC_4_8_or_later=y +CT_CC_GCC_HAS_LIBMPX=y CT_CC_GCC_ENABLE_CXX_FLAGS="" CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" CT_CC_GCC_EXTRA_CONFIG_ARRAY="" -CT_CC_GCC_EXTRA_ENV_ARRAY="" CT_CC_GCC_STATIC_LIBSTDCXX=y # CT_CC_GCC_SYSTEM_ZLIB is not set +CT_CC_GCC_CONFIG_TLS=m # # Optimisation features # +CT_CC_GCC_USE_GRAPHITE=y +CT_CC_GCC_USE_LTO=y # # Settings for libraries running on target @@ -465,97 +543,206 @@ CT_CC_GCC_DEC_FLOAT_AUTO=y # CT_CC_GCC_DEC_FLOAT_BID is not set # CT_CC_GCC_DEC_FLOAT_DPD is not set # CT_CC_GCC_DEC_FLOATS_NO is not set -CT_CC_SUPPORT_CXX=y -CT_CC_SUPPORT_FORTRAN=y -CT_CC_SUPPORT_JAVA=y -CT_CC_SUPPORT_ADA=y -CT_CC_SUPPORT_OBJC=y -CT_CC_SUPPORT_OBJCXX=y -CT_CC_SUPPORT_GOLANG=y +CT_ALL_CC_CHOICES="GCC" # # Additional supported languages: # CT_CC_LANG_CXX=y -# CT_CC_LANG_JAVA is not set +# CT_CC_LANG_FORTRAN is not set # # Debug facilities # -# CT_DEBUG_dmalloc is not set -# CT_DEBUG_duma is not set -# CT_DEBUG_gdb is not set -# CT_DEBUG_ltrace is not set -# CT_DEBUG_strace is not set +# CT_DEBUG_DUMA is not set +# CT_DEBUG_GDB is not set +# CT_DEBUG_LTRACE is not set +# CT_DEBUG_STRACE is not set +CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE" # # Companion libraries # -CT_COMPLIBS_NEEDED=y +# CT_COMPLIBS_CHECK is not set +# CT_COMP_LIBS_CLOOG is not set +# CT_COMP_LIBS_EXPAT is not set +CT_COMP_LIBS_GETTEXT=y +CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT" +CT_GETTEXT_DIR_NAME="gettext" +CT_GETTEXT_PKG_NAME="gettext" +CT_GETTEXT_SRC_RELEASE=y +CT_GETTEXT_PATCH_ORDER="global" +CT_GETTEXT_V_0_19_8_1=y +# CT_GETTEXT_NO_VERSIONS is not set +CT_GETTEXT_VERSION="0.19.8.1" +CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)" +CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz" +CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig" +CT_COMP_LIBS_GMP=y +CT_COMP_LIBS_GMP_PKG_KSYM="GMP" +CT_GMP_DIR_NAME="gmp" +CT_GMP_PKG_NAME="gmp" +CT_GMP_SRC_RELEASE=y +CT_GMP_PATCH_ORDER="global" +CT_GMP_V_6_1=y +# CT_GMP_NO_VERSIONS is not set +CT_GMP_VERSION="6.1.2" +CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)" +CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2" +CT_GMP_SIGNATURE_FORMAT="packed/.sig" +CT_GMP_later_than_5_1_0=y +CT_GMP_5_1_0_or_later=y +CT_GMP_later_than_5_0_0=y +CT_GMP_5_0_0_or_later=y +CT_COMP_LIBS_ISL=y +CT_COMP_LIBS_ISL_PKG_KSYM="ISL" +CT_ISL_DIR_NAME="isl" +CT_ISL_PKG_NAME="isl" +CT_ISL_SRC_RELEASE=y +CT_ISL_PATCH_ORDER="global" +CT_ISL_V_0_20=y +# CT_ISL_V_0_19 is not set +# CT_ISL_V_0_18 is not set +# CT_ISL_V_0_17 is not set +# CT_ISL_V_0_16 is not set +# CT_ISL_V_0_15 is not set +# CT_ISL_NO_VERSIONS is not set +CT_ISL_VERSION="0.20" +CT_ISL_MIRRORS="http://isl.gforge.inria.fr" +CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" +CT_ISL_SIGNATURE_FORMAT="" +CT_ISL_later_than_0_18=y +CT_ISL_0_18_or_later=y +CT_ISL_later_than_0_15=y +CT_ISL_0_15_or_later=y +CT_ISL_REQUIRE_0_15_or_later=y +CT_ISL_later_than_0_14=y +CT_ISL_0_14_or_later=y +CT_ISL_REQUIRE_0_14_or_later=y +CT_ISL_later_than_0_13=y +CT_ISL_0_13_or_later=y +CT_ISL_later_than_0_12=y +CT_ISL_0_12_or_later=y +CT_ISL_REQUIRE_0_12_or_later=y +# CT_COMP_LIBS_LIBELF is not set +CT_COMP_LIBS_LIBICONV=y +CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV" +CT_LIBICONV_DIR_NAME="libiconv" +CT_LIBICONV_PKG_NAME="libiconv" +CT_LIBICONV_SRC_RELEASE=y +CT_LIBICONV_PATCH_ORDER="global" +CT_LIBICONV_V_1_15=y +# CT_LIBICONV_NO_VERSIONS is not set +CT_LIBICONV_VERSION="1.15" +CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)" +CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz" +CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig" +CT_COMP_LIBS_MPC=y +CT_COMP_LIBS_MPC_PKG_KSYM="MPC" +CT_MPC_DIR_NAME="mpc" +CT_MPC_PKG_NAME="mpc" +CT_MPC_SRC_RELEASE=y +CT_MPC_PATCH_ORDER="global" +# CT_MPC_V_1_1 is not set +CT_MPC_V_1_0=y +# CT_MPC_NO_VERSIONS is not set +CT_MPC_VERSION="1.0.3" +CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)" +CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_MPC_ARCHIVE_FORMATS=".tar.gz" +CT_MPC_SIGNATURE_FORMAT="packed/.sig" +CT_MPC_1_1_0_or_older=y +CT_MPC_older_than_1_1_0=y +CT_COMP_LIBS_MPFR=y +CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR" +CT_MPFR_DIR_NAME="mpfr" +CT_MPFR_PKG_NAME="mpfr" +CT_MPFR_SRC_RELEASE=y +CT_MPFR_PATCH_ORDER="global" +CT_MPFR_V_3_1=y +# CT_MPFR_NO_VERSIONS is not set +CT_MPFR_VERSION="3.1.6" +CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)" +CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip" +CT_MPFR_SIGNATURE_FORMAT="packed/.asc" +CT_MPFR_4_0_0_or_older=y +CT_MPFR_older_than_4_0_0=y +CT_MPFR_REQUIRE_older_than_4_0_0=y +CT_MPFR_later_than_3_0_0=y +CT_MPFR_3_0_0_or_later=y +CT_COMP_LIBS_NCURSES=y +CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES" +CT_NCURSES_DIR_NAME="ncurses" +CT_NCURSES_PKG_NAME="ncurses" +CT_NCURSES_SRC_RELEASE=y +CT_NCURSES_PATCH_ORDER="global" +CT_NCURSES_V_6_1=y +# CT_NCURSES_V_6_0 is not set +# CT_NCURSES_NO_VERSIONS is not set +CT_NCURSES_VERSION="6.1" +CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)" +CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_NCURSES_ARCHIVE_FORMATS=".tar.gz" +CT_NCURSES_SIGNATURE_FORMAT="packed/.sig" +CT_NCURSES_HOST_CONFIG_ARGS="" +CT_NCURSES_HOST_DISABLE_DB=y +CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100" +CT_NCURSES_TARGET_CONFIG_ARGS="" +# CT_NCURSES_TARGET_DISABLE_DB is not set +CT_NCURSES_TARGET_FALLBACKS="" +CT_COMP_LIBS_ZLIB=y +CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB" +CT_ZLIB_DIR_NAME="zlib" +CT_ZLIB_PKG_NAME="zlib" +CT_ZLIB_SRC_RELEASE=y +CT_ZLIB_PATCH_ORDER="global" +CT_ZLIB_V_1_2_11=y +# CT_ZLIB_NO_VERSIONS is not set +CT_ZLIB_VERSION="1.2.11" +CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}" +CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}" +CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" +CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz" +CT_ZLIB_SIGNATURE_FORMAT="packed/.asc" +CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB" CT_LIBICONV_NEEDED=y CT_GETTEXT_NEEDED=y CT_GMP_NEEDED=y CT_MPFR_NEEDED=y CT_ISL_NEEDED=y CT_MPC_NEEDED=y -CT_COMPLIBS=y +CT_NCURSES_NEEDED=y +CT_ZLIB_NEEDED=y CT_LIBICONV=y CT_GETTEXT=y CT_GMP=y CT_MPFR=y CT_ISL=y CT_MPC=y -CT_LIBICONV_V_1_14=y -CT_LIBICONV_VERSION="1.14" -CT_GETTEXT_V_0_19_6=y -CT_GETTEXT_VERSION="0.19.6" -CT_GMP_V_6_0_0=y -# CT_GMP_V_5_1_3 is not set -# CT_GMP_V_5_1_1 is not set -# CT_GMP_V_5_0_2 is not set -# CT_GMP_V_5_0_1 is not set -# CT_GMP_V_4_3_2 is not set -# CT_GMP_V_4_3_1 is not set -# CT_GMP_V_4_3_0 is not set -CT_GMP_5_0_2_or_later=y -CT_GMP_VERSION="6.0.0a" -CT_MPFR_V_3_1_3=y -# CT_MPFR_V_3_1_2 is not set -# CT_MPFR_V_3_1_0 is not set -# CT_MPFR_V_3_0_1 is not set -# CT_MPFR_V_3_0_0 is not set -# CT_MPFR_V_2_4_2 is not set -# CT_MPFR_V_2_4_1 is not set -# CT_MPFR_V_2_4_0 is not set -CT_MPFR_VERSION="3.1.3" -CT_ISL_V_0_14=y -# CT_ISL_V_0_12_2 is not set -CT_ISL_V_0_14_or_later=y -CT_ISL_V_0_12_or_later=y -CT_ISL_VERSION="0.14" -# CT_CLOOG_V_0_18_4 is not set -# CT_CLOOG_V_0_18_1 is not set -# CT_CLOOG_V_0_18_0 is not set -CT_MPC_V_1_0_3=y -# CT_MPC_V_1_0_2 is not set -# CT_MPC_V_1_0_1 is not set -# CT_MPC_V_1_0 is not set -# CT_MPC_V_0_9 is not set -# CT_MPC_V_0_8_2 is not set -# CT_MPC_V_0_8_1 is not set -# CT_MPC_V_0_7 is not set -CT_MPC_VERSION="1.0.3" - -# -# Companion libraries common options -# -# CT_COMPLIBS_CHECK is not set +CT_NCURSES=y +CT_ZLIB=y # # Companion tools # - -# -# READ HELP before you say 'Y' below !!! -# -# CT_COMP_TOOLS is not set +# CT_COMP_TOOLS_FOR_HOST is not set +# CT_COMP_TOOLS_AUTOCONF is not set +# CT_COMP_TOOLS_AUTOMAKE is not set +# CT_COMP_TOOLS_BISON is not set +# CT_COMP_TOOLS_DTC is not set +# CT_COMP_TOOLS_LIBTOOL is not set +# CT_COMP_TOOLS_M4 is not set +# CT_COMP_TOOLS_MAKE is not set +CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE" diff --git a/src/ci/docker/dist-armv7-linux/crosstool-ng.sh b/src/ci/docker/dist-armv7-linux/crosstool-ng.sh new file mode 100644 index 00000000000..ae737d9677d --- /dev/null +++ b/src/ci/docker/dist-armv7-linux/crosstool-ng.sh @@ -0,0 +1,12 @@ +set -ex + +# Mirrored from https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-1.24.0.tar.gz +url="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/crosstool-ng-1.24.0.tar.gz" +curl -Lf $url | tar xzf - +cd crosstool-ng-crosstool-ng-1.24.0 +./bootstrap +./configure --prefix=/usr/local +make -j$(nproc) +make install +cd .. +rm -rf crosstool-ng-crosstool-ng-1.24.0 diff --git a/src/ci/docker/dist-armv7-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch b/src/ci/docker/dist-armv7-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch deleted file mode 100644 index 871d5225c0f..00000000000 --- a/src/ci/docker/dist-armv7-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch +++ /dev/null @@ -1,48 +0,0 @@ -commit bdb24c2851fd5f0ad9b82d7ea1db911d334b02d2 -Author: Joseph Myers <joseph@codesourcery.com> -Date: Tue May 20 21:27:13 2014 +0000 - - Fix ARM build with GCC trunk. - - sysdeps/unix/sysv/linux/arm/unwind-resume.c and - sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c have static - variables that are written in C code but only read from toplevel asms. - Current GCC trunk now optimizes away such apparently write-only static - variables, so causing a build failure. This patch marks those - variables with __attribute_used__ to avoid that optimization. - - Tested that this fixes the build for ARM. - - * sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c - (libgcc_s_resume): Use __attribute_used__. - * sysdeps/unix/sysv/linux/arm/unwind-resume.c (libgcc_s_resume): - Likewise. - -diff --git a/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c b/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c -index 29e2c2b00b04..e848bfeffdcb 100644 ---- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c -+++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c -@@ -22,7 +22,8 @@ - #include <pthreadP.h> - - static void *libgcc_s_handle; --static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); -+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc) -+ __attribute_used__; - static _Unwind_Reason_Code (*libgcc_s_personality) - (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); - static _Unwind_Reason_Code (*libgcc_s_forcedunwind) -diff --git a/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c b/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c -index 285b99b5ed0d..48d00fc83641 100644 ---- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c -+++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c -@@ -20,7 +20,8 @@ - #include <stdio.h> - #include <unwind.h> - --static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); -+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc) -+ __attribute_used__; - static _Unwind_Reason_Code (*libgcc_s_personality) - (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); - diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index 10579119462..fab3824a20a 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -139,7 +139,6 @@ ENV RUST_CONFIGURE_ARGS \ --musl-root-aarch64=/musl-aarch64 \ --musl-root-mips=/musl-mips \ --musl-root-mipsel=/musl-mipsel \ - --enable-emscripten \ --disable-docs ENV SCRIPT \ diff --git a/src/ci/docker/scripts/cross-apt-packages.sh b/src/ci/docker/scripts/cross-apt-packages.sh index 51945fd72ad..bb72e33def2 100644 --- a/src/ci/docker/scripts/cross-apt-packages.sh +++ b/src/ci/docker/scripts/cross-apt-packages.sh @@ -22,5 +22,6 @@ apt-get update && apt-get install -y --no-install-recommends \ python2.7 \ sudo \ texinfo \ + unzip \ wget \ xz-utils diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index c7c3b0a5fbf..92c6e546a38 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -47,7 +47,7 @@ function fetch_github_commit_archive { rm $cached } -included="src/llvm-project src/llvm-emscripten src/doc/book src/doc/rust-by-example" +included="src/llvm-project src/doc/book src/doc/rust-by-example" modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)" modules=($modules) use_git="" diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index d5564fd798f..b603c7b231e 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -14,6 +14,7 @@ - [Targets](targets/index.md) - [Built-in Targets](targets/built-in.md) - [Custom Targets](targets/custom.md) + - [Known Issues](targets/known-issues.md) - [Profile-guided Optimization](profile-guided-optimization.md) - [Linker-plugin based LTO](linker-plugin-lto.md) - [Contributing to `rustc`](contributing.md) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index e73fd43f19a..f5d5f2089d7 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -61,6 +61,8 @@ enabling or disabling a feature. To see the valid options and an example of use, run `rustc --print target-features`. +Using this flag is unsafe and might result in [undefined runtime behavior](../targets/known-issues.md). + ## passes This flag can be used to add extra LLVM passes to the compilation. diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index b2cc65c11fd..bdb3c519658 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -145,7 +145,7 @@ of print values are: target CPU may be selected with the `-C target-cpu=val` flag. - `target-features` — List of available target features for the current target. Target features may be enabled with the `-C target-feature=val` - flag. + flag. This flag is unsafe. See [known issues](targets/known-issues.md) for more details. - `relocation-models` — List of relocation models. Relocation models may be selected with the `-C relocation-model=val` flag. - `code-models` — List of code models. Code models may be selected with the diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md index e486240fda8..813d7c4bafe 100644 --- a/src/doc/rustc/src/lints/listing/warn-by-default.md +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -596,30 +596,6 @@ warning: function cannot return without recursing | ``` -## unions-with-drop-fields - -This lint detects use of unions that contain fields with possibly non-trivial drop code. Some -example code that triggers this lint: - -```rust -#![feature(untagged_unions)] - -union U { - s: String, -} -``` - -This will produce: - -```text -warning: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union - --> src/main.rs:4:5 - | -4 | s: String, - | ^^^^^^^^^ - | -``` - ## unknown-lints This lint detects unrecognized lint attribute. Some diff --git a/src/doc/rustc/src/targets/index.md b/src/doc/rustc/src/targets/index.md index 3d63d072bef..5859df83f64 100644 --- a/src/doc/rustc/src/targets/index.md +++ b/src/doc/rustc/src/targets/index.md @@ -11,3 +11,9 @@ To compile to a particular target, use the `--target` flag: ```bash $ rustc src/main.rs --target=wasm32-unknown-unknown ``` +## Target Features +`x86`, and `ARMv8` are two popular CPU architectures. Their instruction sets form a common baseline across most CPUs. However, some CPUs extend these with custom instruction sets, e.g. vector (`AVX`), bitwise manipulation (`BMI`) or cryptographic (`AES`). + +Developers, who know on which CPUs their compiled code is going to run can choose to add (or remove) CPU specific instruction sets via the `-C target-feature=val` flag. + +Please note, that this flag is generally considered as unsafe. More details can be found in [this section](known-issues.md). diff --git a/src/doc/rustc/src/targets/known-issues.md b/src/doc/rustc/src/targets/known-issues.md new file mode 100644 index 00000000000..89fd8ea6d32 --- /dev/null +++ b/src/doc/rustc/src/targets/known-issues.md @@ -0,0 +1,13 @@ +# Known Issues +This section informs you about known "gotchas". Keep in mind, that this section is (and always will be) incomplete. For suggestions and amendments, feel free to [contribute](../contributing.md) to this guide. + +## Target Features +Most target-feature problems arise, when mixing code that have the target-feature _enabled_ with code that have it _disabled_. If you want to avoid undefined behavior, it is recommended to build _all code_ (including the standard library and imported crates) with a common set of target-features. + +By default, compiling your code with the `-C target-feature` flag will not recompile the entire standard library and/or imported crates with matching target features. Therefore, target features are generally considered as unsafe. Using `#[target_feature]` on individual functions makes the function unsafe. + +Examples: + +| Target-Feature | Issue | Seen on | Description | Details | +| -------------- | ----- | ------- | ----------- | ------- | +| `+soft-float` <br> and <br> `-sse` | Segfaults and ABI mismatches | `x86` and `x86-64` | The `x86` and `x86_64` architecture uses SSE registers (aka `xmm`) for floating point operations. Using software emulated floats ("soft-floats") disables usage of `xmm` registers, but parts of Rust's core libraries (e.g. `std::f32` or `std::f64`) are compiled without soft-floats and expect parameters to be passed in `xmm` registers. This leads to ABI mismatches. <br><br> Attempting to compile with disabled SSE causes the same error, too. | [#63466](https://github.com/rust-lang/rust/issues/63466) | diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index a9c5bce4c25..d2bdda83fa9 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -207,6 +207,47 @@ impl<B: ?Sized + ToOwned> Clone for Cow<'_, B> { } impl<B: ?Sized + ToOwned> Cow<'_, B> { + /// Returns true if the data is borrowed, i.e. if `to_mut` would require additional work. + /// + /// # Examples + /// + /// ``` + /// #![feature(cow_is_borrowed)] + /// use std::borrow::Cow; + /// + /// let cow = Cow::Borrowed("moo"); + /// assert!(cow.is_borrowed()); + /// + /// let bull: Cow<'_, str> = Cow::Owned("...moo?".to_string()); + /// assert!(!bull.is_borrowed()); + /// ``` + #[unstable(feature = "cow_is_borrowed", issue = "65143")] + pub fn is_borrowed(&self) -> bool { + match *self { + Borrowed(_) => true, + Owned(_) => false, + } + } + + /// Returns true if the data is owned, i.e. if `to_mut` would be a no-op. + /// + /// # Examples + /// + /// ``` + /// #![feature(cow_is_borrowed)] + /// use std::borrow::Cow; + /// + /// let cow: Cow<'_, str> = Cow::Owned("moo".to_string()); + /// assert!(cow.is_owned()); + /// + /// let bull = Cow::Borrowed("...moo?"); + /// assert!(!bull.is_owned()); + /// ``` + #[unstable(feature = "cow_is_borrowed", issue = "65143")] + pub fn is_owned(&self) -> bool { + !self.is_borrowed() + } + /// Acquires a mutable reference to the owned form of the data. /// /// Clones the data if it is not already owned. diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 0bf573f5e25..8f3dfabd888 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1817,7 +1817,7 @@ impl<T> VecDeque<T> { } } - return elem; + elem } /// Splits the `VecDeque` into two at the given index. diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 3684162d8b1..94379afc2bd 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -85,6 +85,7 @@ #![feature(const_generic_impls_guard)] #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] +#![feature(cow_is_borrowed)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] #![feature(container_error_extra)] diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 9231c2d3f1d..83816d8b954 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -456,7 +456,7 @@ impl str { } } } - return s; + s } /// Converts a [`Box<str>`] into a [`String`] without copying or allocating. diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 69f8f71197c..80d6c6e0d43 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -1638,7 +1638,7 @@ impl<T: ?Sized> Clone for Weak<T> { } } - return Weak { ptr: self.ptr }; + Weak { ptr: self.ptr } } } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 8413b2e0ac4..0e83a282b18 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -2025,7 +2025,7 @@ impl<T: ?Sized> Pointer for *const T { if f.alternate() { f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32); - if let None = f.width { + if f.width.is_none() { f.width = Some(((mem::size_of::<usize>() * 8) / 4) + 2); } } diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index 25439136b85..00a86417058 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -167,7 +167,7 @@ pub trait FromIterator<A>: Sized { /// // and we'll implement IntoIterator /// impl IntoIterator for MyCollection { /// type Item = i32; -/// type IntoIter = ::std::vec::IntoIter<Self::Item>; +/// type IntoIter = std::vec::IntoIter<Self::Item>; /// /// fn into_iter(self) -> Self::IntoIter { /// self.0.into_iter() diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 1320e63df06..35558e3abcd 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -238,6 +238,33 @@ macro_rules! debug_assert_ne { ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); }) } +/// Returns whether the given expression matches any of the given patterns. +/// +/// Like in a `match` expression, the pattern can be optionally followed by `if` +/// and a guard expression that has access to names bound by the pattern. +/// +/// # Examples +/// +/// ``` +/// #![feature(matches_macro)] +/// +/// let foo = 'f'; +/// assert!(matches!(foo, 'A'..='Z' | 'a'..='z')); +/// +/// let bar = Some(4); +/// assert!(matches!(bar, Some(x) if x > 2)); +/// ``` +#[macro_export] +#[unstable(feature = "matches_macro", issue = "65721")] +macro_rules! matches { + ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )?) => { + match $expression { + $( $pattern )|+ $( if $guard )? => true, + _ => false + } + } +} + /// Unwraps a result or propagates its error. /// /// The `?` operator was added to replace `try!` and should be used instead. diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index fa3c8075378..ed89852dc48 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -143,13 +143,12 @@ pub fn fast_path<T: RawFloat>(integral: &[u8], fractional: &[u8], e: i64) -> Opt /// > not a bound for the true error, but bounds the difference between the approximation z and /// > the best possible approximation that uses p bits of significand.) pub fn bellerophon<T: RawFloat>(f: &Big, e: i16) -> T { - let slop; - if f <= &Big::from_u64(T::MAX_SIG) { + let slop = if f <= &Big::from_u64(T::MAX_SIG) { // The cases abs(e) < log5(2^N) are in fast_path() - slop = if e >= 0 { 0 } else { 3 }; + if e >= 0 { 0 } else { 3 } } else { - slop = if e >= 0 { 1 } else { 4 }; - } + if e >= 0 { 1 } else { 4 } + }; let z = rawfp::big_to_fp(f).mul(&power_of_ten(e)).normalize(); let exp_p_n = 1 << (P - T::SIG_BITS as u32); let lowbits: i64 = (z.f % exp_p_n) as i64; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 8f4ade377e3..b4ade704144 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3757,8 +3757,8 @@ assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_power_of_two(self) -> bool { - (self.wrapping_sub(1)) & self == 0 && !(self == 0) + pub const fn is_power_of_two(self) -> bool { + self.count_ones() == 1 } } diff --git a/src/libcore/ops/unsize.rs b/src/libcore/ops/unsize.rs index 8e468300846..d29147645f7 100644 --- a/src/libcore/ops/unsize.rs +++ b/src/libcore/ops/unsize.rs @@ -76,7 +76,7 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} /// ``` /// # #![feature(dispatch_from_dyn, unsize)] /// # use std::{ops::DispatchFromDyn, marker::Unsize}; -/// # struct Rc<T: ?Sized>(::std::rc::Rc<T>); +/// # struct Rc<T: ?Sized>(std::rc::Rc<T>); /// impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> /// where /// T: Unsize<U>, diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 47e3a0d2167..89f2d7ab29c 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -64,7 +64,7 @@ //! //! fn check_optional(optional: Option<Box<i32>>) { //! match optional { -//! Some(ref p) => println!("has value {}", p), +//! Some(p) => println!("has value {}", p), //! None => println!("has no value"), //! } //! } @@ -83,7 +83,7 @@ //! let msg = Some("howdy"); //! //! // Take a reference to the contained string -//! if let Some(ref m) = msg { +//! if let Some(m) = &msg { //! println!("{}", *m); //! } //! @@ -395,10 +395,10 @@ impl<T> Option<T> { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn unwrap_or(self, def: T) -> T { + pub fn unwrap_or(self, default: T) -> T { match self { Some(x) => x, - None => def, + None => default, } } @@ -837,9 +837,8 @@ impl<T> Option<T> { #[inline] #[stable(feature = "option_entry", since = "1.20.0")] pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T { - match *self { - None => *self = Some(f()), - _ => (), + if let None = *self { + *self = Some(f()); } match *self { diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 93391918595..3cc0a1cd75e 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -188,7 +188,7 @@ unsafe fn real_drop_in_place<T: ?Sized>(to_drop: &mut T) { /// let p: *const i32 = ptr::null(); /// assert!(p.is_null()); /// ``` -#[inline] +#[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] pub const fn null<T>() -> *const T { 0 as *const T } @@ -203,7 +203,7 @@ pub const fn null<T>() -> *const T { 0 as *const T } /// let p: *mut i32 = ptr::null_mut(); /// assert!(p.is_null()); /// ``` -#[inline] +#[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] pub const fn null_mut<T>() -> *mut T { 0 as *mut T } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 885696e5acf..f67012d8f2f 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -176,7 +176,7 @@ Section: Creating a string /// ``` /// fn from_utf8_lossy<F>(mut input: &[u8], mut push: F) where F: FnMut(&str) { /// loop { -/// match ::std::str::from_utf8(input) { +/// match std::str::from_utf8(input) { /// Ok(valid) => { /// push(valid); /// break @@ -184,7 +184,7 @@ Section: Creating a string /// Err(error) => { /// let (valid, after_valid) = input.split_at(error.valid_up_to()); /// unsafe { -/// push(::std::str::from_utf8_unchecked(valid)) +/// push(std::str::from_utf8_unchecked(valid)) /// } /// push("\u{FFFD}"); /// diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 236ed150505..a35847c85fc 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -156,21 +156,21 @@ unsafe extern "C" fn rust_eh_personality(version: c_int, if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 { match eh_action { EHAction::None | - EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND, - EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND, - EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR, + EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND, + EHAction::Catch(_) => uw::_URC_HANDLER_FOUND, + EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR, } } else { match eh_action { - EHAction::None => return uw::_URC_CONTINUE_UNWIND, + EHAction::None => uw::_URC_CONTINUE_UNWIND, EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => { uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t); uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); uw::_Unwind_SetIP(context, lpad); - return uw::_URC_INSTALL_CONTEXT; + uw::_URC_INSTALL_CONTEXT } - EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR, + EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR, } } } diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 457ffcd34f9..16b699a4437 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -46,7 +46,7 @@ pub fn payload() -> *mut u8 { pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> { let panic_ctx = Box::from_raw(ptr as *mut PanicData); - return panic_ctx.data; + panic_ctx.data } // SEH doesn't support resuming unwinds after calling a landing pad like diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index cf9f36ca37c..93274ef0c92 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -36,5 +36,5 @@ parking_lot = "0.9" byteorder = { version = "1.3" } chalk-engine = { version = "0.9.0", default-features=false } rustc_fs_util = { path = "../librustc_fs_util" } -smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } +smallvec = { version = "0.6.8", features = ["union", "may_dangle"] } measureme = "0.3" diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 337cdddc432..0104507f702 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -35,7 +35,7 @@ impl DepNodeIndex { pub const INVALID: DepNodeIndex = DepNodeIndex::MAX; } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(PartialEq)] pub enum DepNodeColor { Red, Green(DepNodeIndex) diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 3d501cacf6f..122ae4a6cf6 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -2045,8 +2045,8 @@ so that a generator can then be constructed: async fn bar<T>() -> () {} async fn foo() { - bar::<String>().await; - // ^^^^^^^^ specify type explicitly + bar::<String>().await; + // ^^^^^^^^ specify type explicitly } ``` "##, @@ -2126,6 +2126,84 @@ static X: u32 = 42; ``` "##, +E0728: r##" +[`await`] has been used outside [`async`] function or block. + +Erroneous code examples: + +```edition2018,compile_fail,E0728 +# use std::pin::Pin; +# use std::future::Future; +# use std::task::{Context, Poll}; +# +# struct WakeOnceThenComplete(bool); +# +# fn wake_and_yield_once() -> WakeOnceThenComplete { +# WakeOnceThenComplete(false) +# } +# +# impl Future for WakeOnceThenComplete { +# type Output = (); +# fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { +# if self.0 { +# Poll::Ready(()) +# } else { +# cx.waker().wake_by_ref(); +# self.0 = true; +# Poll::Pending +# } +# } +# } +# +fn foo() { + wake_and_yield_once().await // `await` is used outside `async` context +} +``` + +[`await`] is used to suspend the current computation until the given +future is ready to produce a value. So it is legal only within +an [`async`] context, like an `async fn` or an `async` block. + +```edition2018 +# use std::pin::Pin; +# use std::future::Future; +# use std::task::{Context, Poll}; +# +# struct WakeOnceThenComplete(bool); +# +# fn wake_and_yield_once() -> WakeOnceThenComplete { +# WakeOnceThenComplete(false) +# } +# +# impl Future for WakeOnceThenComplete { +# type Output = (); +# fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { +# if self.0 { +# Poll::Ready(()) +# } else { +# cx.waker().wake_by_ref(); +# self.0 = true; +# Poll::Pending +# } +# } +# } +# +async fn foo() { + wake_and_yield_once().await // `await` is used within `async` function +} + +fn bar(x: u8) -> impl Future<Output = u8> { + async move { + wake_and_yield_once().await; // `await` is used within `async` block + x + } +} +``` + +[`async`]: https://doc.rust-lang.org/std/keyword.async.html +[`await`]: https://doc.rust-lang.org/std/keyword.await.html +"##, + E0734: r##" A stability attribute has been used outside of the standard library. @@ -2218,6 +2296,5 @@ See [RFC 2091] for details on this and other limitations. // E0702, // replaced with a generic attribute input check E0726, // non-explicit (not `'_`) elided lifetime in unsupported position E0727, // `async` generators are not yet supported - E0728, // `await` must be in an `async` function or block E0739, // invalid track_caller application/syntax } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 893b295c60a..5993a97c40d 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -599,7 +599,6 @@ macro_rules! define_global_metadata_kind { (pub enum GlobalMetaDataKind { $($variant:ident),* }) => ( - #[derive(Clone, Copy, Debug, Hash, RustcEncodable, RustcDecodable)] pub enum GlobalMetaDataKind { $($variant),* } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index cd111ab9f94..38c84ad3347 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1077,7 +1077,7 @@ impl Mutability { } } -#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Hash, HashStable)] +#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)] pub enum BinOpKind { /// The `+` operator (addition). Add, @@ -1211,7 +1211,7 @@ impl Into<ast::BinOpKind> for BinOpKind { pub type BinOp = Spanned<BinOpKind>; -#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Hash, HashStable)] +#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)] pub enum UnOp { /// The `*` operator (deferencing). UnDeref, @@ -1388,8 +1388,7 @@ impl Body { } /// The type of source expression that caused this generator to be created. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable, - RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable, Debug, Copy)] pub enum GeneratorKind { /// An explicit `async` block or the body of an async function. Async(AsyncGeneratorKind), @@ -1412,8 +1411,7 @@ impl fmt::Display for GeneratorKind { /// /// This helps error messages but is also used to drive coercions in /// type-checking (see #60424). -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable, - RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable, Debug, Copy)] pub enum AsyncGeneratorKind { /// An explicit `async` block written by the user. Block, diff --git a/src/librustc/hir/ptr.rs b/src/librustc/hir/ptr.rs index 8cdcf5202fc..7ee461a859b 100644 --- a/src/librustc/hir/ptr.rs +++ b/src/librustc/hir/ptr.rs @@ -11,7 +11,7 @@ use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; /// An owned smart pointer. -#[derive(Hash, PartialEq, Eq)] +#[derive(PartialEq, Eq)] pub struct P<T: ?Sized> { ptr: Box<T> } diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index b9474f869ee..49a2c90bdbf 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -468,7 +468,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { ConstValue::Infer(InferConst::Fresh(_)) => { bug!("encountered a fresh const during canonicalization") } - ConstValue::Infer(InferConst::Canonical(debruijn, _)) => { + ConstValue::Bound(debruijn, _) => { if debruijn >= self.binder_index { bug!("escaping bound type during canonicalization") } else { @@ -700,8 +700,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { let var = self.canonical_var(info, const_var.into()); self.tcx().mk_const( ty::Const { - val: ConstValue::Infer(InferConst::Canonical(self.binder_index, var.into())), - ty: const_var.ty, + val: ConstValue::Bound(self.binder_index, var.into()), + ty: self.fold_ty(const_var.ty), } ) } diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 562a463ded8..d833feeeb09 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -33,7 +33,7 @@ use std::ops::Index; use syntax::source_map::Span; use crate::ty::fold::TypeFoldable; use crate::ty::subst::GenericArg; -use crate::ty::{self, BoundVar, InferConst, Lift, List, Region, TyCtxt}; +use crate::ty::{self, BoundVar, Lift, List, Region, TyCtxt}; mod canonicalizer; @@ -73,7 +73,7 @@ pub struct CanonicalVarValues<'tcx> { /// various parts of it with canonical variables. This struct stores /// those replaced bits to remember for when we process the query /// result. -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] +#[derive(Clone, Debug)] pub struct OriginalQueryValues<'tcx> { /// Map from the universes that appear in the query to the /// universes in the caller context. For the time being, we only @@ -510,9 +510,7 @@ impl<'tcx> CanonicalVarValues<'tcx> { GenericArgKind::Const(ct) => { tcx.mk_const(ty::Const { ty: ct.ty, - val: ConstValue::Infer( - InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from_u32(i)) - ), + val: ConstValue::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)), }).into() } }) diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 95b6a8bc843..7ad6006012f 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -26,7 +26,7 @@ use crate::traits::TraitEngine; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use crate::ty::fold::TypeFoldable; use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::{self, BoundVar, InferConst, Ty, TyCtxt}; +use crate::ty::{self, BoundVar, Ty, TyCtxt}; use crate::util::captures::Captures; impl<'tcx> InferCtxtBuilder<'tcx> { @@ -493,10 +493,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { } } GenericArgKind::Const(result_value) => { - if let ty::Const { - val: ConstValue::Infer(InferConst::Canonical(debrujin, b)), - .. - } = result_value { + if let ty::Const { val: ConstValue::Bound(debrujin, b), .. } = result_value { // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. // We only allow a `ty::INNERMOST` index in substitutions. diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 6f73275d455..f06dbc72cd9 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -53,7 +53,7 @@ pub struct CombineFields<'infcx, 'tcx> { pub obligations: PredicateObligations<'tcx>, } -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[derive(Copy, Clone, Debug)] pub enum RelationDir { SubtypeOf, SupertypeOf, EqTo } diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 7e1dcdfe18f..a50cc86862e 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1146,10 +1146,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let span = cause.span(self.tcx); - diag.span_label(span, terr.to_string()); - if let Some((sp, msg)) = secondary_span { - diag.span_label(sp, msg); - } + // Ignore msg for object safe coercion + // since E0038 message will be printed + match terr { + TypeError::ObjectUnsafeCoercion(_) => {} + _ => { + diag.span_label(span, terr.to_string()); + if let Some((sp, msg)) = secondary_span { + diag.span_label(sp, msg); + } + } + }; if let Some((expected, found)) = expected_found { match (terr, is_simple_error, expected == found) { @@ -1169,6 +1176,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &sort_string(values.found), ); } + (TypeError::ObjectUnsafeCoercion(_), ..) => { + diag.note_unsuccessfull_coercion(found, expected); + } (_, false, _) => { if let Some(exp_found) = exp_found { self.suggest_as_ref_where_appropriate(span, &exp_found, diag); @@ -1267,6 +1277,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let span = trace.cause.span(self.tcx); let failure_code = trace.cause.as_failure_code(terr); let mut diag = match failure_code { + FailureCode::Error0038(did) => { + let violations = self.tcx.object_safety_violations(did); + self.tcx.report_object_safety_error(span, did, violations) + } FailureCode::Error0317(failure_str) => { struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) } @@ -1628,6 +1642,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } enum FailureCode { + Error0038(DefId), Error0317(&'static str), Error0580(&'static str), Error0308(&'static str), @@ -1666,6 +1681,7 @@ impl<'tcx> ObligationCause<'tcx> { TypeError::IntrinsicCast => { Error0308("cannot coerce intrinsics to function pointers") } + TypeError::ObjectUnsafeCoercion(did) => Error0038(did.clone()), _ => Error0308("mismatched types"), }, } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 9e9220cc3d8..1841bd9ea64 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -252,7 +252,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { return ct; } - ConstValue::Infer(ty::InferConst::Canonical(..)) | + ConstValue::Bound(..) | ConstValue::Placeholder(_) => { bug!("unexpected const {:?}", ct) } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 61e49d32fcd..e385d576b8c 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -407,7 +407,7 @@ pub enum RegionVariableOrigin { NLL(NLLRegionVariableOrigin), } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug)] pub enum NLLRegionVariableOrigin { /// During NLL region processing, we create variables for free /// regions that we encounter in the function signature and diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index 4649f3f9567..64ef0421808 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -27,12 +27,12 @@ use crate::ty::error::TypeError; use crate::ty::fold::{TypeFoldable, TypeVisitor}; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; use crate::ty::subst::GenericArg; -use crate::ty::{self, Ty, TyCtxt, InferConst}; +use crate::ty::{self, Ty, TyCtxt}; use crate::mir::interpret::ConstValue; use rustc_data_structures::fx::FxHashMap; use std::fmt::Debug; -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(PartialEq)] pub enum NormalizationStrategy { Lazy, Eager, @@ -618,7 +618,7 @@ where a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(_, _)), .. } = a { + if let ty::Const { val: ConstValue::Bound(..), .. } = a { // FIXME(const_generics): I'm unsure how this branch should actually be handled, // so this is probably not correct. self.infcx.super_combine_consts(self, a, b) @@ -993,7 +993,7 @@ where ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { debug!("TypeGeneralizer::consts(a={:?})", a); - if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(_, _)), .. } = a { + if let ty::Const { val: ConstValue::Bound(..), .. } = a { bug!( "unexpected inference variable encountered in NLL generalization: {:?}", a diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index b4b4d1fe3e1..8c6a7c9a376 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -116,7 +116,7 @@ pub struct RegionConstraintData<'tcx> { } /// Represents a constraint that influences the inference process. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)] pub enum Constraint<'tcx> { /// A region variable is a subregion of another. VarSubVar(RegionVid, RegionVid), diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 2db18674e2f..7c3a338366c 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -1,7 +1,7 @@ use super::{InferCtxt, FixupError, FixupResult, Span}; use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::mir::interpret::ConstValue; -use crate::ty::{self, Ty, Const, TyCtxt, TypeFoldable, InferConst, TypeFlags}; +use crate::ty::{self, Ty, Const, TyCtxt, TypeFoldable, InferConst}; use crate::ty::fold::{TypeFolder, TypeVisitor}; /////////////////////////////////////////////////////////////////////////// @@ -29,7 +29,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.has_infer_types() { + if !t.has_infer_types() && !t.has_infer_consts() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { let t = self.infcx.shallow_resolve(t); @@ -38,7 +38,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> { } fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> { - if !ct.has_type_flags(TypeFlags::HAS_CT_INFER) { + if !ct.has_infer_consts() { ct // micro-optimize -- if there is nothing in this const that this fold affects... } else { let ct = self.infcx.shallow_resolve(ct); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 8943fc342c0..3b0ac9ada8f 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -43,6 +43,7 @@ #![feature(nll)] #![feature(non_exhaustive)] #![feature(optin_builtin_traits)] +#![feature(option_expect_none)] #![feature(range_is_empty)] #![feature(slice_patterns)] #![feature(specialization)] diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 4c28f6372fe..15598b60f5c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -4,11 +4,12 @@ //! compiler code, rather than using their own custom pass. Those //! lints are all available in `rustc_lint::builtin`. -use crate::lint::{LintPass, LateLintPass, LintArray}; +use crate::lint::{LintPass, LateLintPass, LintArray, FutureIncompatibleInfo}; use crate::middle::stability; use crate::session::Session; use errors::{Applicability, DiagnosticBuilder, pluralise}; use syntax::ast; +use syntax::edition::Edition; use syntax::source_map::Span; use syntax::symbol::Symbol; @@ -22,7 +23,7 @@ declare_lint! { pub CONST_ERR, Deny, "constant evaluation detected erroneous expression", - report_in_external_macro: true + report_in_external_macro } declare_lint! { @@ -71,7 +72,7 @@ declare_lint! { pub UNREACHABLE_CODE, Warn, "detects unreachable code paths", - report_in_external_macro: true + report_in_external_macro } declare_lint! { @@ -131,7 +132,11 @@ declare_lint! { declare_lint! { pub PRIVATE_IN_PUBLIC, Warn, - "detect private items in public interfaces not caught by the old implementation" + "detect private items in public interfaces not caught by the old implementation", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>", + edition: None, + }; } declare_lint! { @@ -143,13 +148,21 @@ declare_lint! { declare_lint! { pub PUB_USE_OF_PRIVATE_EXTERN_CRATE, Deny, - "detect public re-exports of private extern crates" + "detect public re-exports of private extern crates", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>", + edition: None, + }; } declare_lint! { pub INVALID_TYPE_PARAM_DEFAULT, Deny, - "type parameter default erroneously allowed in invalid location" + "type parameter default erroneously allowed in invalid location", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>", + edition: None, + }; } declare_lint! { @@ -161,63 +174,99 @@ declare_lint! { declare_lint! { pub SAFE_EXTERN_STATICS, Deny, - "safe access to extern statics was erroneously allowed" + "safe access to extern statics was erroneously allowed", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>", + edition: None, + }; } declare_lint! { pub SAFE_PACKED_BORROWS, Warn, - "safe borrows of fields of packed structs were was erroneously allowed" + "safe borrows of fields of packed structs were was erroneously allowed", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>", + edition: None, + }; } declare_lint! { pub PATTERNS_IN_FNS_WITHOUT_BODY, Warn, - "patterns in functions without body were erroneously allowed" + "patterns in functions without body were erroneously allowed", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>", + edition: None, + }; } declare_lint! { pub LEGACY_DIRECTORY_OWNERSHIP, Deny, "non-inline, non-`#[path]` modules (e.g., `mod foo;`) were erroneously allowed in some files \ - not named `mod.rs`" + not named `mod.rs`", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>", + edition: None, + }; } declare_lint! { pub LEGACY_CONSTRUCTOR_VISIBILITY, Deny, - "detects use of struct constructors that would be invisible with new visibility rules" + "detects use of struct constructors that would be invisible with new visibility rules", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>", + edition: None, + }; } declare_lint! { pub MISSING_FRAGMENT_SPECIFIER, Deny, - "detects missing fragment specifiers in unused `macro_rules!` patterns" + "detects missing fragment specifiers in unused `macro_rules!` patterns", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>", + edition: None, + }; } declare_lint! { pub PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, Deny, - "detects parenthesized generic parameters in type and module names" + "detects parenthesized generic parameters in type and module names", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>", + edition: None, + }; } declare_lint! { pub LATE_BOUND_LIFETIME_ARGUMENTS, Warn, - "detects generic lifetime arguments in path segments with late bound lifetime parameters" + "detects generic lifetime arguments in path segments with late bound lifetime parameters", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>", + edition: None, + }; } declare_lint! { pub ORDER_DEPENDENT_TRAIT_OBJECTS, Deny, - "trait-object types were treated as different depending on marker-trait order" + "trait-object types were treated as different depending on marker-trait order", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>", + edition: None, + }; } declare_lint! { pub DEPRECATED, Warn, "detects use of deprecated items", - report_in_external_macro: true + report_in_external_macro } declare_lint! { @@ -253,7 +302,11 @@ declare_lint! { declare_lint! { pub TYVAR_BEHIND_RAW_POINTER, Warn, - "raw pointer to an inference variable" + "raw pointer to an inference variable", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>", + edition: Some(Edition::Edition2018), + }; } declare_lint! { @@ -272,19 +325,33 @@ declare_lint! { pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, Allow, "fully qualified paths that start with a module name \ - instead of `crate`, `self`, or an extern crate name" + instead of `crate`, `self`, or an extern crate name", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #53130 <https://github.com/rust-lang/rust/issues/53130>", + edition: Some(Edition::Edition2018), + }; } declare_lint! { pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, Warn, - "floating-point literals cannot be used in patterns" + "floating-point literals cannot be used in patterns", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>", + edition: None, + }; } declare_lint! { pub UNSTABLE_NAME_COLLISIONS, Warn, - "detects name collision with an existing but unstable method" + "detects name collision with an existing but unstable method", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #48919 <https://github.com/rust-lang/rust/issues/48919>", + edition: None, + // Note: this item represents future incompatibility of all unstable functions in the + // standard library, and thus should never be removed or changed to an error. + }; } declare_lint! { @@ -302,7 +369,11 @@ declare_lint! { declare_lint! { pub DUPLICATE_MACRO_EXPORTS, Deny, - "detects duplicate macro exports" + "detects duplicate macro exports", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #35896 <https://github.com/rust-lang/rust/issues/35896>", + edition: Some(Edition::Edition2018), + }; } declare_lint! { @@ -326,13 +397,21 @@ declare_lint! { declare_lint! { pub WHERE_CLAUSES_OBJECT_SAFETY, Warn, - "checks the object safety of where clauses" + "checks the object safety of where clauses", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>", + edition: None, + }; } declare_lint! { pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, Warn, - "detects proc macro derives using inaccessible names from parent modules" + "detects proc macro derives using inaccessible names from parent modules", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>", + edition: None, + }; } declare_lint! { @@ -346,7 +425,11 @@ declare_lint! { pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, Deny, "macro-expanded `macro_export` macros from the current crate \ - cannot be referred to by absolute paths" + cannot be referred to by absolute paths", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>", + edition: None, + }; } declare_lint! { @@ -359,7 +442,11 @@ declare_lint! { pub INDIRECT_STRUCTURAL_MATCH, // defaulting to allow until rust-lang/rust#62614 is fixed. Allow, - "pattern with const indirectly referencing non-`#[structural_match]` type" + "pattern with const indirectly referencing non-`#[structural_match]` type", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>", + edition: None, + }; } /// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`. @@ -367,7 +454,11 @@ pub mod parser { declare_lint! { pub ILL_FORMED_ATTRIBUTE_INPUT, Warn, - "ill-formed attribute inputs that were previously accepted and used in practice" + "ill-formed attribute inputs that were previously accepted and used in practice", + @future_incompatible = super::FutureIncompatibleInfo { + reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>", + edition: None, + }; } declare_lint! { @@ -387,31 +478,47 @@ declare_lint! { pub DEPRECATED_IN_FUTURE, Allow, "detects use of items that will be deprecated in a future version", - report_in_external_macro: true + report_in_external_macro } declare_lint! { pub AMBIGUOUS_ASSOCIATED_ITEMS, Deny, - "ambiguous associated items" + "ambiguous associated items", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #57644 <https://github.com/rust-lang/rust/issues/57644>", + edition: None, + }; } declare_lint! { pub NESTED_IMPL_TRAIT, Warn, - "nested occurrence of `impl Trait` type" + "nested occurrence of `impl Trait` type", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #59014 <https://github.com/rust-lang/rust/issues/59014>", + edition: None, + }; } declare_lint! { pub MUTABLE_BORROW_RESERVATION_CONFLICT, Warn, - "reservation of a two-phased borrow conflicts with other shared borrows" + "reservation of a two-phased borrow conflicts with other shared borrows", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #59159 <https://github.com/rust-lang/rust/issues/59159>", + edition: None, + }; } declare_lint! { pub SOFT_UNSTABLE, Deny, - "a feature gate that doesn't break dependent crates" + "a feature gate that doesn't break dependent crates", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #64266 <https://github.com/rust-lang/rust/issues/64266>", + edition: None, + }; } declare_lint_pass! { diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 1b38c908917..1cb53d754dc 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -22,11 +22,11 @@ use crate::hir::intravisit as hir_visit; use crate::hir::intravisit::Visitor; use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData}; use crate::lint::{EarlyLintPass, LateLintPass, EarlyLintPassObject, LateLintPassObject}; -use crate::lint::{LintArray, Level, Lint, LintId, LintPass, LintBuffer}; +use crate::lint::{Level, Lint, LintId, LintPass, LintBuffer, FutureIncompatibleInfo}; use crate::lint::builtin::BuiltinLintDiagnostics; use crate::lint::levels::{LintLevelSets, LintLevelsBuilder}; use crate::middle::privacy::AccessLevels; -use crate::session::{config, early_error, Session}; +use crate::session::Session; use crate::ty::{self, print::Printer, subst::GenericArg, TyCtxt, Ty}; use crate::ty::layout::{LayoutError, LayoutOf, TyLayout}; use crate::util::nodemap::FxHashMap; @@ -35,10 +35,9 @@ use crate::util::common::time; use errors::DiagnosticBuilder; use std::slice; use std::default::Default as StdDefault; -use rustc_data_structures::sync::{ReadGuard, Lock, ParallelIterator, join, par_iter}; +use rustc_data_structures::sync::{self, ParallelIterator, join, par_iter}; use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use syntax::ast; -use syntax::edition; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit as ast_visit; use syntax_pos::{MultiSpan, Span, symbol::Symbol}; @@ -50,24 +49,25 @@ use syntax_pos::{MultiSpan, Span, symbol::Symbol}; pub struct LintStore { /// Registered lints. The bool is true if the lint was /// added by a plugin. - lints: Vec<(&'static Lint, bool)>, + lints: Vec<&'static Lint>, - /// Trait objects for each lint pass. - /// This is only `None` while performing a lint pass. - pre_expansion_passes: Option<Vec<EarlyLintPassObject>>, - early_passes: Option<Vec<EarlyLintPassObject>>, - late_passes: Lock<Option<Vec<LateLintPassObject>>>, - late_module_passes: Vec<LateLintPassObject>, + /// Constructor functions for each variety of lint pass. + /// + /// These should only be called once, but since we want to avoid locks or + /// interior mutability, we don't enforce this (and lints should, in theory, + /// be compatible with being constructed more than once, though not + /// necessarily in a sane manner. This is safe though.) + pre_expansion_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>, + early_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>, + late_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>, + /// This is unique in that we construct them per-module, so not once. + late_module_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>, /// Lints indexed by name. by_name: FxHashMap<String, TargetLint>, /// Map of registered lint groups to what lints they expand to. lint_groups: FxHashMap<&'static str, LintGroup>, - - /// Extra info for future incompatibility lints, describing the - /// issue or RFC that caused the incompatibility. - future_incompatible: FxHashMap<LintId, FutureIncompatibleInfo>, } /// Lints that are buffered up early on in the `Session` before the @@ -81,18 +81,6 @@ pub struct BufferedEarlyLint { pub diagnostic: BuiltinLintDiagnostics, } -/// Extra information for a future incompatibility lint. See the call -/// to `register_future_incompatible` in `librustc_lint/lib.rs` for -/// guidelines. -pub struct FutureIncompatibleInfo { - pub id: LintId, - /// e.g., a URL for an issue/PR/RFC or error code - pub reference: &'static str, - /// If this is an edition fixing lint, the edition in which - /// this lint becomes obsolete - pub edition: Option<edition::Edition>, -} - /// The target of the `by_name` map, which accounts for renaming/deprecation. enum TargetLint { /// A direct lint target @@ -142,17 +130,16 @@ impl LintStore { pub fn new() -> LintStore { LintStore { lints: vec![], - pre_expansion_passes: Some(vec![]), - early_passes: Some(vec![]), - late_passes: Lock::new(Some(vec![])), + pre_expansion_passes: vec![], + early_passes: vec![], + late_passes: vec![], late_module_passes: vec![], by_name: Default::default(), - future_incompatible: Default::default(), lint_groups: Default::default(), } } - pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] { + pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] { &self.lints } @@ -168,99 +155,64 @@ impl LintStore { .collect() } - pub fn register_early_pass(&mut self, - sess: Option<&Session>, - from_plugin: bool, - register_only: bool, - pass: EarlyLintPassObject) { - self.push_pass(sess, from_plugin, &pass); - if !register_only { - self.early_passes.as_mut().unwrap().push(pass); - } + pub fn register_early_pass( + &mut self, + pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync + ) { + self.early_passes.push(Box::new(pass)); } pub fn register_pre_expansion_pass( &mut self, - sess: Option<&Session>, - from_plugin: bool, - register_only: bool, - pass: EarlyLintPassObject, + pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync, ) { - self.push_pass(sess, from_plugin, &pass); - if !register_only { - self.pre_expansion_passes.as_mut().unwrap().push(pass); - } + self.pre_expansion_passes.push(Box::new(pass)); } - pub fn register_late_pass(&mut self, - sess: Option<&Session>, - from_plugin: bool, - register_only: bool, - per_module: bool, - pass: LateLintPassObject) { - self.push_pass(sess, from_plugin, &pass); - if !register_only { - if per_module { - self.late_module_passes.push(pass); - } else { - self.late_passes.lock().as_mut().unwrap().push(pass); - } - } + pub fn register_late_pass( + &mut self, + pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync, + ) { + self.late_passes.push(Box::new(pass)); + } + + pub fn register_late_mod_pass( + &mut self, + pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync, + ) { + self.late_module_passes.push(Box::new(pass)); } // Helper method for register_early/late_pass - fn push_pass<P: LintPass + ?Sized + 'static>(&mut self, - sess: Option<&Session>, - from_plugin: bool, - pass: &Box<P>) { - for lint in pass.get_lints() { - self.lints.push((lint, from_plugin)); + pub fn register_lints(&mut self, lints: &[&'static Lint]) { + for lint in lints { + self.lints.push(lint); let id = LintId::of(lint); if self.by_name.insert(lint.name_lower(), Id(id)).is_some() { - let msg = format!("duplicate specification of lint {}", lint.name_lower()); - match (sess, from_plugin) { - // We load builtin lints first, so a duplicate is a compiler bug. - // Use early_error when handling -W help with no crate. - (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]), - (Some(_), false) => bug!("{}", msg), - - // A duplicate name from a plugin is a user error. - (Some(sess), true) => sess.err(&msg[..]), - } + bug!("duplicate specification of lint {}", lint.name_lower()) } - } - } - pub fn register_future_incompatible(&mut self, - sess: Option<&Session>, - lints: Vec<FutureIncompatibleInfo>) { + if let Some(FutureIncompatibleInfo { edition, .. }) = lint.future_incompatible { + if let Some(edition) = edition { + self.lint_groups.entry(edition.lint_name()) + .or_insert(LintGroup { + lint_ids: vec![], + from_plugin: lint.is_plugin, + depr: None, + }) + .lint_ids.push(id); + } - for edition in edition::ALL_EDITIONS { - let lints = lints.iter().filter(|f| f.edition == Some(*edition)).map(|f| f.id) - .collect::<Vec<_>>(); - if !lints.is_empty() { - self.register_group(sess, false, edition.lint_name(), None, lints) + self.lint_groups.entry("future_incompatible") + .or_insert(LintGroup { + lint_ids: vec![], + from_plugin: lint.is_plugin, + depr: None, + }) + .lint_ids.push(id); } } - - let mut future_incompatible = Vec::with_capacity(lints.len()); - for lint in lints { - future_incompatible.push(lint.id); - self.future_incompatible.insert(lint.id, lint); - } - - self.register_group( - sess, - false, - "future_incompatible", - None, - future_incompatible, - ); - } - - pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> { - self.future_incompatible.get(&id) } pub fn register_group_alias( @@ -277,7 +229,6 @@ impl LintStore { pub fn register_group( &mut self, - sess: Option<&Session>, from_plugin: bool, name: &'static str, deprecated_name: Option<&'static str>, @@ -300,16 +251,7 @@ impl LintStore { } if !new { - let msg = format!("duplicate specification of lint group {}", name); - match (sess, from_plugin) { - // We load builtin lints first, so a duplicate is a compiler bug. - // Use early_error when handling -W help with no crate. - (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]), - (Some(_), false) => bug!("{}", msg), - - // A duplicate name from a plugin is a user error. - (Some(sess), true) => sess.err(&msg[..]), - } + bug!("duplicate specification of lint group {}", name); } } @@ -522,7 +464,7 @@ pub struct LateContext<'a, 'tcx> { pub access_levels: &'a AccessLevels, /// The store of registered lints and the lint levels. - lint_store: ReadGuard<'a, LintStore>, + lint_store: &'tcx LintStore, last_node_with_lint_attrs: hir::HirId, @@ -550,7 +492,7 @@ pub struct EarlyContext<'a> { builder: LintLevelsBuilder<'a>, /// The store of registered lints and the lint levels. - lint_store: ReadGuard<'a, LintStore>, + lint_store: &'a LintStore, buffered: LintBuffer, } @@ -639,14 +581,15 @@ pub trait LintContext: Sized { impl<'a> EarlyContext<'a> { fn new( sess: &'a Session, + lint_store: &'a LintStore, krate: &'a ast::Crate, buffered: LintBuffer, ) -> EarlyContext<'a> { EarlyContext { sess, krate, - lint_store: sess.lint_store.borrow(), - builder: LintLevelSets::builder(sess), + lint_store, + builder: LintLevelSets::builder(sess, lint_store), buffered, } } @@ -681,7 +624,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { f: F) where F: FnOnce(&mut Self) { - let push = self.context.builder.push(attrs); + let push = self.context.builder.push(attrs, &self.context.lint_store); self.check_id(id); self.enter_attrs(attrs); f(self); @@ -1355,10 +1298,6 @@ impl LintPass for LateLintPassObjects<'_> { fn name(&self) -> &'static str { panic!() } - - fn get_lints(&self) -> LintArray { - panic!() - } } macro_rules! expand_late_lint_pass_impl_methods { @@ -1393,7 +1332,7 @@ fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>( tables: &ty::TypeckTables::empty(None), param_env: ty::ParamEnv::empty(), access_levels, - lint_store: tcx.sess.lint_store.borrow(), + lint_store: &tcx.lint_store, last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(), generics: None, only_module: true, @@ -1425,8 +1364,8 @@ pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>( late_lint_mod_pass(tcx, module_def_id, builtin_lints); - let mut passes: Vec<_> = tcx.sess.lint_store.borrow().late_module_passes - .iter().map(|pass| pass.fresh_late_pass()).collect(); + let mut passes: Vec<_> = tcx.lint_store.late_module_passes + .iter().map(|pass| (pass)()).collect(); if !passes.is_empty() { late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] }); @@ -1443,7 +1382,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc tables: &ty::TypeckTables::empty(None), param_env: ty::ParamEnv::empty(), access_levels, - lint_store: tcx.sess.lint_store.borrow(), + lint_store: &tcx.lint_store, last_node_with_lint_attrs: hir::CRATE_HIR_ID, generics: None, only_module: false, @@ -1467,7 +1406,8 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc } fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) { - let mut passes = tcx.sess.lint_store.borrow().late_passes.lock().take().unwrap(); + let mut passes = tcx.lint_store + .late_passes.iter().map(|p| (p)()).collect::<Vec<_>>(); if !tcx.sess.opts.debugging_opts.no_interleave_lints { if !passes.is_empty() { @@ -1482,8 +1422,8 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, b }); } - let mut passes: Vec<_> = tcx.sess.lint_store.borrow().late_module_passes - .iter().map(|pass| pass.fresh_late_pass()).collect(); + let mut passes: Vec<_> = tcx.lint_store.late_module_passes + .iter().map(|pass| (pass)()).collect(); for pass in &mut passes { time(tcx.sess, &format!("running late module lint: {}", pass.name()), || { @@ -1491,9 +1431,6 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, b }); } } - - // Put the passes back in the session. - *tcx.sess.lint_store.borrow().late_passes.lock() = Some(passes); } /// Performs lint checking on a crate. @@ -1525,10 +1462,6 @@ impl LintPass for EarlyLintPassObjects<'_> { fn name(&self) -> &'static str { panic!() } - - fn get_lints(&self) -> LintArray { - panic!() - } } macro_rules! expand_early_lint_pass_impl_methods { @@ -1553,12 +1486,13 @@ early_lint_methods!(early_lint_pass_impl, []); fn early_lint_crate<T: EarlyLintPass>( sess: &Session, + lint_store: &LintStore, krate: &ast::Crate, pass: T, buffered: LintBuffer, ) -> LintBuffer { let mut cx = EarlyContextAndPass { - context: EarlyContext::new(sess, krate, buffered), + context: EarlyContext::new(sess, lint_store, krate, buffered), pass, }; @@ -1577,28 +1511,30 @@ fn early_lint_crate<T: EarlyLintPass>( pub fn check_ast_crate<T: EarlyLintPass>( sess: &Session, + lint_store: &LintStore, krate: &ast::Crate, pre_expansion: bool, builtin_lints: T, ) { - let (mut passes, mut buffered) = if pre_expansion { + let (mut passes, mut buffered): (Vec<_>, _) = if pre_expansion { ( - sess.lint_store.borrow_mut().pre_expansion_passes.take().unwrap(), + lint_store.pre_expansion_passes.iter().map(|p| (p)()).collect(), LintBuffer::default(), ) } else { ( - sess.lint_store.borrow_mut().early_passes.take().unwrap(), + lint_store.early_passes.iter().map(|p| (p)()).collect(), sess.buffered_lints.borrow_mut().take().unwrap(), ) }; if !sess.opts.debugging_opts.no_interleave_lints { - buffered = early_lint_crate(sess, krate, builtin_lints, buffered); + buffered = early_lint_crate(sess, lint_store, krate, builtin_lints, buffered); if !passes.is_empty() { buffered = early_lint_crate( sess, + lint_store, krate, EarlyLintPassObjects { lints: &mut passes[..] }, buffered, @@ -1609,6 +1545,7 @@ pub fn check_ast_crate<T: EarlyLintPass>( buffered = time(sess, &format!("running lint: {}", pass.name()), || { early_lint_crate( sess, + lint_store, krate, EarlyLintPassObjects { lints: slice::from_mut(pass) }, buffered, @@ -1617,13 +1554,6 @@ pub fn check_ast_crate<T: EarlyLintPass>( } } - // Put the lint store levels and passes back in the session. - if pre_expansion { - sess.lint_store.borrow_mut().pre_expansion_passes = Some(passes); - } else { - sess.lint_store.borrow_mut().early_passes = Some(passes); - } - // All of the buffered lints should have been emitted at this point. // If not, that means that we somehow buffered a lint for a node id // that was not lint-checked (perhaps it doesn't exist?). This is a bug. @@ -1653,7 +1583,7 @@ impl Decodable for LintId { fn decode<D: Decoder>(d: &mut D) -> Result<LintId, D::Error> { let s = d.read_str()?; ty::tls::with(|tcx| { - match tcx.sess.lint_store.borrow().find_lints(&s) { + match tcx.lint_store.find_lints(&s) { Ok(ids) => { if ids.len() != 0 { panic!("invalid lint-id `{}`", s); diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 60b1b192d10..4c60492e470 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -3,7 +3,7 @@ use std::cmp; use crate::hir::HirId; use crate::ich::StableHashingContext; use crate::lint::builtin; -use crate::lint::context::CheckLintNameResult; +use crate::lint::context::{LintStore, CheckLintNameResult}; use crate::lint::{self, Lint, LintId, Level, LintSource}; use crate::session::Session; use crate::util::nodemap::FxHashMap; @@ -35,21 +35,20 @@ enum LintSet { } impl LintLevelSets { - pub fn new(sess: &Session) -> LintLevelSets { + pub fn new(sess: &Session, lint_store: &LintStore) -> LintLevelSets { let mut me = LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid, }; - me.process_command_line(sess); + me.process_command_line(sess, lint_store); return me } - pub fn builder(sess: &Session) -> LintLevelsBuilder<'_> { - LintLevelsBuilder::new(sess, LintLevelSets::new(sess)) + pub fn builder<'a>(sess: &'a Session, store: &LintStore) -> LintLevelsBuilder<'a> { + LintLevelsBuilder::new(sess, LintLevelSets::new(sess, store)) } - fn process_command_line(&mut self, sess: &Session) { - let store = sess.lint_store.borrow(); + fn process_command_line(&mut self, sess: &Session, store: &LintStore) { let mut specs = FxHashMap::default(); self.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); @@ -186,9 +185,8 @@ impl<'a> LintLevelsBuilder<'a> { /// #[allow] /// /// Don't forget to call `pop`! - pub fn push(&mut self, attrs: &[ast::Attribute]) -> BuilderPush { + pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush { let mut specs = FxHashMap::default(); - let store = self.sess.lint_store.borrow(); let sess = self.sess; let bad_attr = |span| { struct_span_err!(sess, span, E0452, "malformed lint attribute input") @@ -202,11 +200,7 @@ impl<'a> LintLevelsBuilder<'a> { let meta = unwrap_or!(attr.meta(), continue); attr::mark_used(attr); - let mut metas = if let Some(metas) = meta.meta_item_list() { - metas - } else { - continue; - }; + let mut metas = unwrap_or!(meta.meta_item_list(), continue); if metas.is_empty() { // FIXME (#55112): issue unused-attributes lint for `#[level()]` diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 7443cca822a..3c35bdae66e 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -45,7 +45,7 @@ use syntax_pos::Span; pub use crate::lint::context::{LateContext, EarlyContext, LintContext, LintStore, check_crate, check_ast_crate, late_lint_mod, CheckLintNameResult, - FutureIncompatibleInfo, BufferedEarlyLint,}; + BufferedEarlyLint,}; /// Specification of a single lint. #[derive(Copy, Clone, Debug)] @@ -76,9 +76,35 @@ pub struct Lint { /// `true` if this lint is reported even inside expansions of external macros. pub report_in_external_macro: bool, + + pub future_incompatible: Option<FutureIncompatibleInfo>, + + pub is_plugin: bool, +} + +/// Extra information for a future incompatibility lint. +#[derive(Copy, Clone, Debug)] +pub struct FutureIncompatibleInfo { + /// e.g., a URL for an issue/PR/RFC or error code + pub reference: &'static str, + /// If this is an edition fixing lint, the edition in which + /// this lint becomes obsolete + pub edition: Option<Edition>, } impl Lint { + pub const fn default_fields_for_macro() -> Self { + Lint { + name: "", + default_level: Level::Forbid, + desc: "", + edition_lint_opts: None, + is_plugin: false, + report_in_external_macro: false, + future_incompatible: None, + } + } + /// Returns the `rust::lint::Lint` for a `syntax::early_buffered_lints::BufferedEarlyLintId`. pub fn from_parser_lint_id(lint_id: BufferedEarlyLintId) -> &'static Self { match lint_id { @@ -105,18 +131,21 @@ impl Lint { #[macro_export] macro_rules! declare_lint { ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( - declare_lint!{$vis $NAME, $Level, $desc, false} - ); - ($vis: vis $NAME: ident, $Level: ident, $desc: expr, report_in_external_macro: $rep: expr) => ( - declare_lint!{$vis $NAME, $Level, $desc, $rep} + declare_lint!( + $vis $NAME, $Level, $desc, + ); ); - ($vis: vis $NAME: ident, $Level: ident, $desc: expr, $external: expr) => ( + ($vis: vis $NAME: ident, $Level: ident, $desc: expr, + $(@future_incompatible = $fi:expr;)? $($v:ident),*) => ( $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, desc: $desc, edition_lint_opts: None, - report_in_external_macro: $external, + is_plugin: false, + $($v: true,)* + $(future_incompatible: Some($fi),)* + ..$crate::lint::Lint::default_fields_for_macro() }; ); ($vis: vis $NAME: ident, $Level: ident, $desc: expr, @@ -128,6 +157,7 @@ macro_rules! declare_lint { desc: $desc, edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)), report_in_external_macro: false, + is_plugin: false, }; ); } @@ -156,6 +186,8 @@ macro_rules! declare_tool_lint { desc: $desc, edition_lint_opts: None, report_in_external_macro: $external, + future_incompatible: None, + is_plugin: true, }; ); } @@ -173,14 +205,6 @@ pub type LintArray = Vec<&'static Lint>; pub trait LintPass { fn name(&self) -> &'static str; - - /// Gets descriptions of the lints this `LintPass` object can emit. - /// - /// N.B., there is no enforcement that the object only emits lints it registered. - /// And some `rustc` internal `LintPass`es register lints to be emitted by other - /// parts of the compiler. If you want enforced access restrictions for your - /// `Lint`, make it a private `static` item in its own module. - fn get_lints(&self) -> LintArray; } /// Implements `LintPass for $name` with the given list of `Lint` statics. @@ -189,7 +213,9 @@ macro_rules! impl_lint_pass { ($name:ident => [$($lint:expr),* $(,)?]) => { impl LintPass for $name { fn name(&self) -> &'static str { stringify!($name) } - fn get_lints(&self) -> LintArray { $crate::lint_array!($($lint),*) } + } + impl $name { + pub fn get_lints() -> LintArray { $crate::lint_array!($($lint),*) } } }; } @@ -287,9 +313,6 @@ macro_rules! expand_lint_pass_methods { macro_rules! declare_late_lint_pass { ([], [$hir:tt], [$($methods:tt)*]) => ( pub trait LateLintPass<'a, $hir>: LintPass { - fn fresh_late_pass(&self) -> LateLintPassObject { - panic!() - } expand_lint_pass_methods!(&LateContext<'a, $hir>, [$($methods)*]); } ) @@ -327,6 +350,12 @@ macro_rules! declare_combined_late_lint_pass { $($passes: $constructor,)* } } + + $v fn get_lints() -> LintArray { + let mut lints = Vec::new(); + $(lints.extend_from_slice(&$passes::get_lints());)* + lints + } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $name { @@ -337,12 +366,6 @@ macro_rules! declare_combined_late_lint_pass { fn name(&self) -> &'static str { panic!() } - - fn get_lints(&self) -> LintArray { - let mut lints = Vec::new(); - $(lints.extend_from_slice(&self.$passes.get_lints());)* - lints - } } ) } @@ -454,6 +477,12 @@ macro_rules! declare_combined_early_lint_pass { $($passes: $constructor,)* } } + + $v fn get_lints() -> LintArray { + let mut lints = Vec::new(); + $(lints.extend_from_slice(&$passes::get_lints());)* + lints + } } impl EarlyLintPass for $name { @@ -464,12 +493,6 @@ macro_rules! declare_combined_early_lint_pass { fn name(&self) -> &'static str { panic!() } - - fn get_lints(&self) -> LintArray { - let mut lints = Vec::new(); - $(lints.extend_from_slice(&self.$passes.get_lints());)* - lints - } } ) } @@ -649,9 +672,8 @@ pub fn struct_lint_level<'a>(sess: &'a Session, }; // Check for future incompatibility lints and issue a stronger warning. - let lints = sess.lint_store.borrow(); let lint_id = LintId::of(lint); - let future_incompatible = lints.future_incompatible(lint_id); + let future_incompatible = lint.future_incompatible; // If this code originates in a foreign macro, aka something that this crate // did not itself author, then it's likely that there's nothing this crate @@ -755,13 +777,15 @@ pub fn maybe_lint_level_root(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap { assert_eq!(cnum, LOCAL_CRATE); + let store = &tcx.lint_store; let mut builder = LintLevelMapBuilder { - levels: LintLevelSets::builder(tcx.sess), + levels: LintLevelSets::builder(tcx.sess, &store), tcx: tcx, + store: store, }; let krate = tcx.hir().krate(); - let push = builder.levels.push(&krate.attrs); + let push = builder.levels.push(&krate.attrs, &store); builder.levels.register_id(hir::CRATE_HIR_ID); for macro_def in &krate.exported_macros { builder.levels.register_id(macro_def.hir_id); @@ -772,19 +796,20 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap { tcx.arena.alloc(builder.levels.build_map()) } -struct LintLevelMapBuilder<'tcx> { +struct LintLevelMapBuilder<'a, 'tcx> { levels: levels::LintLevelsBuilder<'tcx>, tcx: TyCtxt<'tcx>, + store: &'a LintStore, } -impl LintLevelMapBuilder<'tcx> { +impl LintLevelMapBuilder<'_, '_> { fn with_lint_attrs<F>(&mut self, id: hir::HirId, attrs: &[ast::Attribute], f: F) where F: FnOnce(&mut Self) { - let push = self.levels.push(attrs); + let push = self.levels.push(attrs, self.store); if push.changed { self.levels.register_id(id); } @@ -793,7 +818,7 @@ impl LintLevelMapBuilder<'tcx> { } } -impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { +impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { intravisit::NestedVisitorMap::All(&self.tcx.hir()) } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 2170a288c92..ec1e32988a6 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -117,7 +117,7 @@ pub struct NativeLibrary { pub wasm_import_module: Option<Symbol>, } -#[derive(Clone, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub struct ForeignModule { pub foreign_items: Vec<DefId>, pub def_id: DefId, diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 8f79b8aa295..cbf336fdbe2 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -102,7 +102,7 @@ pub struct Upvar { } // different kinds of pointers: -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum PointerKind<'tcx> { /// `Box<T>` Unique, @@ -116,7 +116,7 @@ pub enum PointerKind<'tcx> { // We use the term "interior" to mean "something reachable from the // base without a pointer dereference", e.g., a field -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq)] pub enum InteriorKind { InteriorField(FieldIndex), InteriorElement(InteriorOffsetKind), @@ -139,13 +139,13 @@ impl Hash for FieldIndex { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq)] pub enum InteriorOffsetKind { Index, // e.g., `array_expr[index_expr]` Pattern, // e.g., `fn foo([_, a, _, _]: [A; 4]) { ... }` } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Debug)] pub enum MutabilityCategory { McImmutable, // Immutable. McDeclared, // Directly declared as mutable. diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 302c11f309d..e65f17c7949 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -25,7 +25,7 @@ use crate::util::nodemap::{FxHashSet, FxHashMap}; use std::mem::replace; use std::cmp::Ordering; -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Hash)] +#[derive(PartialEq, Clone, Copy, Debug)] pub enum StabilityLevel { Unstable, Stable, @@ -905,11 +905,10 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // Warn if the user has enabled an already-stable lang feature. unnecessary_stable_feature_lint(tcx, span, feature, since); } - if lang_features.contains(&feature) { + if !lang_features.insert(feature) { // Warn if the user enables a lang feature multiple times. duplicate_feature_err(tcx.sess, span, feature); } - lang_features.insert(feature); } let declared_lib_features = &tcx.features().declared_lib_features; diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 15e6cb6bcab..796d293e2c6 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -245,6 +245,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { /// as a slice. /// /// It is the caller's responsibility to check bounds and alignment beforehand. + /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods + /// on `InterpCx` instead. #[inline] pub fn get_bytes( &self, @@ -275,6 +277,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { /// so be sure to actually put data there! /// /// It is the caller's responsibility to check bounds and alignment beforehand. + /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods + /// on `InterpCx` instead. pub fn get_bytes_mut( &mut self, cx: &impl HasDataLayout, @@ -297,6 +301,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { /// Reads bytes until a `0` is encountered. Will error if the end of the allocation is reached /// before a `0` is found. + /// + /// Most likely, you want to call `Memory::read_c_str` instead of this method. pub fn read_c_str( &self, cx: &impl HasDataLayout, @@ -342,33 +348,22 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { /// Writes `src` to the memory starting at `ptr.offset`. /// /// It is the caller's responsibility to check bounds and alignment beforehand. + /// Most likely, you want to call `Memory::write_bytes` instead of this method. pub fn write_bytes( &mut self, cx: &impl HasDataLayout, ptr: Pointer<Tag>, - src: &[u8], + src: impl IntoIterator<Item=u8, IntoIter: iter::ExactSizeIterator>, ) -> InterpResult<'tcx> { + let mut src = src.into_iter(); let bytes = self.get_bytes_mut(cx, ptr, Size::from_bytes(src.len() as u64))?; - bytes.clone_from_slice(src); - Ok(()) - } - - /// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - pub fn write_repeat( - &mut self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - val: u8, - count: Size - ) -> InterpResult<'tcx> - { - let bytes = self.get_bytes_mut(cx, ptr, count)?; - for b in bytes { - *b = val; + // `zip` would stop when the first iterator ends; we want to definitely + // cover all of `bytes`. + for dest in bytes { + *dest = src.next().expect("iterator was shorter than it said it would be"); } + src.next().expect_none("iterator was longer than it said it would be"); Ok(()) } @@ -380,6 +375,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { /// pointers being valid for ZSTs. /// /// It is the caller's responsibility to check bounds and alignment beforehand. + /// Most likely, you want to call `InterpCx::read_scalar` instead of this method. pub fn read_scalar( &self, cx: &impl HasDataLayout, @@ -418,6 +414,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { /// Reads a pointer-sized scalar. /// /// It is the caller's responsibility to check bounds and alignment beforehand. + /// Most likely, you want to call `InterpCx::read_scalar` instead of this method. pub fn read_ptr_sized( &self, cx: &impl HasDataLayout, @@ -435,6 +432,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { /// pointers being valid for ZSTs. /// /// It is the caller's responsibility to check bounds and alignment beforehand. + /// Most likely, you want to call `InterpCx::write_scalar` instead of this method. pub fn write_scalar( &mut self, cx: &impl HasDataLayout, @@ -477,6 +475,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { /// Writes a pointer-sized scalar. /// /// It is the caller's responsibility to check bounds and alignment beforehand. + /// Most likely, you want to call `InterpCx::write_scalar` instead of this method. pub fn write_ptr_sized( &mut self, cx: &impl HasDataLayout, diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index bbf00cc23ae..ac16b8b884c 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -5,11 +5,12 @@ use rustc_apfloat::{Float, ieee::{Double, Single}}; use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}, subst::SubstsRef}; use crate::ty::PlaceholderConst; use crate::hir::def_id::DefId; +use crate::ty::{BoundVar, DebruijnIndex}; use super::{InterpResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate}; /// Represents the result of a raw const operation, pre-validation. -#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash, HashStable)] +#[derive(Clone, HashStable)] pub struct RawConst<'tcx> { // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` // (so you can use `AllocMap::unwrap_memory`). @@ -28,6 +29,9 @@ pub enum ConstValue<'tcx> { /// Infer the value of the const. Infer(InferConst<'tcx>), + /// Bound const variable, used only when preparing a trait query. + Bound(DebruijnIndex, BoundVar), + /// A placeholder const - universally quantified higher-ranked const. Placeholder(PlaceholderConst), @@ -66,8 +70,9 @@ impl<'tcx> ConstValue<'tcx> { match *self { ConstValue::Param(_) | ConstValue::Infer(_) | + ConstValue::Bound(..) | ConstValue::Placeholder(_) | - ConstValue::ByRef{ .. } | + ConstValue::ByRef { .. } | ConstValue::Unevaluated(..) | ConstValue::Slice { .. } => None, ConstValue::Scalar(val) => Some(val), @@ -487,7 +492,7 @@ impl<Tag> From<Pointer<Tag>> for Scalar<Tag> { } } -#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, Eq, PartialEq, RustcEncodable, RustcDecodable)] pub enum ScalarMaybeUndef<Tag = (), Id = AllocId> { Scalar(Scalar<Tag, Id>), Undef, diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index b0830fb72eb..08e7001681c 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -468,7 +468,7 @@ impl<T: Decodable> rustc_serialize::UseSpecializedDecodable for ClearCrossCrate< /// Grouped information about the source code origin of a MIR entity. /// Intended to be inspected by diagnostics and debuginfo. /// Most passes can work with it as a whole, within a single function. -#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, HashStable)] +#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable)] pub struct SourceInfo { /// The source span for the AST pertaining to this MIR entity. pub span: Span, @@ -608,7 +608,7 @@ pub enum LocalKind { ReturnPointer, } -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct VarBindingForm<'tcx> { /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? pub binding_mode: ty::BindingMode, @@ -630,7 +630,7 @@ pub struct VarBindingForm<'tcx> { pub pat_span: Span, } -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum BindingForm<'tcx> { /// This is a binding for a non-`self` binding, or a `self` that has an explicit type. Var(VarBindingForm<'tcx>), @@ -641,7 +641,7 @@ pub enum BindingForm<'tcx> { } /// Represents what type of implicit self a function has, if any. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum ImplicitSelfKind { /// Represents a `fn x(self);`. Imm, @@ -2392,7 +2392,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// this does not necessarily mean that they are "==" in Rust -- in /// particular one must be wary of `NaN`! -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] pub struct Constant<'tcx> { pub span: Span, @@ -2438,7 +2438,7 @@ pub struct Constant<'tcx> { /// The first will lead to the constraint `w: &'1 str` (for some /// inferred region `'1`). The second will lead to the constraint `w: /// &'static str`. -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct UserTypeProjections { pub(crate) contents: Vec<(UserTypeProjection, Span)>, } @@ -2515,7 +2515,7 @@ impl<'tcx> UserTypeProjections { /// * `let (x, _): T = ...` -- here, the `projs` vector would contain /// `field[0]` (aka `.0`), indicating that the type of `s` is /// determined by finding the type of the `.0` field from `T`. -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, pub projs: Vec<ProjectionKind>, @@ -2724,7 +2724,7 @@ impl Location { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] pub enum UnsafetyViolationKind { General, /// Permitted both in `const fn`s and regular `fn`s. @@ -2733,7 +2733,7 @@ pub enum UnsafetyViolationKind { BorrowPacked(hir::HirId), } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] pub struct UnsafetyViolation { pub source_info: SourceInfo, pub description: Symbol, @@ -2741,7 +2741,7 @@ pub struct UnsafetyViolation { pub kind: UnsafetyViolationKind, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub struct UnsafetyCheckResult { /// Violations that are propagated *upwards* from this function. pub violations: Lrc<[UnsafetyViolation]>, diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 9be741a1656..58f99667cb3 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -15,7 +15,7 @@ use std::fmt; use std::hash::Hash; /// Describes how a monomorphization will be instantiated in object files. -#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +#[derive(PartialEq)] pub enum InstantiationMode { /// There will be exactly one instance of the given MonoItem. It will have /// external linkage so that it can be linked to from other codegen units. @@ -251,7 +251,7 @@ pub struct CodegenUnit<'tcx> { size_estimate: Option<usize>, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum Linkage { External, AvailableExternally, @@ -280,7 +280,7 @@ impl_stable_hash_for!(enum self::Linkage { Common }); -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum Visibility { Default, Hidden, diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index fef406e8987..427540d7275 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -947,7 +947,7 @@ impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> { /// Extra information passed to `visit_ty` and friends to give context /// about where the type etc appears. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Debug)] pub enum TyContext { LocalDecl { /// The index of the local variable we are visiting. diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 675e3bbd002..33b9ddaa622 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -7,24 +7,19 @@ use crate::session::{early_error, early_warn, Session}; use crate::session::search_paths::SearchPath; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::Lrc; use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel}; use rustc_target::spec::{Target, TargetTriple}; use syntax; -use syntax::ast::{self, IntTy, UintTy, MetaItemKind}; +use syntax::ast::{self, IntTy, UintTy}; use syntax::source_map::{FileName, FilePathMapping}; use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION}; -use syntax::parse::new_parser_from_source_str; -use syntax::parse::token; -use syntax::sess::ParseSess; use syntax::symbol::{sym, Symbol}; use syntax::feature_gate::UnstableFeatures; -use syntax::source_map::SourceMap; use errors::emitter::HumanReadableErrorType; -use errors::{ColorConfig, FatalError, Handler, SourceMapperDyn}; +use errors::{ColorConfig, FatalError, Handler}; use getopts; @@ -67,7 +62,7 @@ impl_stable_hash_via_hash!(OptLevel); /// This is what the `LtoCli` values get mapped to after resolving defaults and /// and taking other command line options into account. -#[derive(Clone, Copy, PartialEq, Hash, Debug)] +#[derive(Clone, PartialEq)] pub enum Lto { /// Don't do any LTO whatsoever No, @@ -301,10 +296,10 @@ impl OutputTypes { /// Use tree-based collections to cheaply get a deterministic `Hash` implementation. /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That /// would break dependency tracking for command-line arguments. -#[derive(Clone, Hash)] +#[derive(Clone)] pub struct Externs(BTreeMap<String, ExternEntry>); -#[derive(Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct ExternEntry { pub locations: BTreeSet<Option<String>>, pub is_private_dep: bool @@ -464,7 +459,7 @@ pub enum PrintRequest { NativeStaticLibs, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone)] pub enum BorrowckMode { Mir, Migrate, @@ -1154,7 +1149,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, target_cpu: Option<String> = (None, parse_opt_string, [TRACKED], "select target processor (`rustc --print target-cpus` for details)"), target_feature: String = (String::new(), parse_string, [TRACKED], - "target specific attributes (`rustc --print target-features` for details)"), + "target specific attributes. (`rustc --print target-features` for details). \ + This feature is unsafe."), passes: Vec<String> = (Vec::new(), parse_list, [TRACKED], "a list of extra LLVM passes to run (space separated)"), llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED], @@ -1854,59 +1850,6 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> { opts } -struct NullEmitter; - -impl errors::emitter::Emitter for NullEmitter { - fn emit_diagnostic(&mut self, _: &errors::Diagnostic) {} - fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> { None } -} - -// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. -pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> { - syntax::with_default_globals(move || { - let cfg = cfgspecs.into_iter().map(|s| { - - let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let handler = Handler::with_emitter(false, None, Box::new(NullEmitter)); - let sess = ParseSess::with_span_handler(handler, cm); - let filename = FileName::cfg_spec_source_code(&s); - let mut parser = new_parser_from_source_str(&sess, filename, s.to_string()); - - macro_rules! error {($reason: expr) => { - early_error(ErrorOutputType::default(), - &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s)); - }} - - match &mut parser.parse_meta_item() { - Ok(meta_item) if parser.token == token::Eof => { - if meta_item.path.segments.len() != 1 { - error!("argument key must be an identifier"); - } - match &meta_item.kind { - MetaItemKind::List(..) => { - error!(r#"expected `key` or `key="value"`"#); - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - error!("argument value must be a string"); - } - MetaItemKind::NameValue(..) | MetaItemKind::Word => { - let ident = meta_item.ident().expect("multi-segment cfg key"); - return (ident.name, meta_item.value_str()); - } - } - } - Ok(..) => {} - Err(err) => err.cancel(), - } - - error!(r#"expected `key` or `key="value"`"#); - }).collect::<ast::CrateConfig>(); - cfg.into_iter().map(|(a, b)| { - (a.to_string(), b.map(|b| b.to_string())) - }).collect() - }) -} - pub fn get_cmd_lint_options(matches: &getopts::Matches, error_format: ErrorOutputType) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) { @@ -2877,6 +2820,3 @@ mod dep_tracking { } } } - -#[cfg(test)] -mod tests; diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index b65bf2230b3..bd2460cfab1 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -14,7 +14,7 @@ use crate::util::common::{duration_to_secs_str, ErrorReported}; use rustc_data_structures::base_n; use rustc_data_structures::sync::{ - self, Lrc, Lock, OneThread, Once, RwLock, AtomicU64, AtomicUsize, Ordering, + self, Lrc, Lock, OneThread, Once, AtomicU64, AtomicUsize, Ordering, Ordering::SeqCst, }; @@ -77,9 +77,11 @@ pub struct Session { /// if the value stored here has been affected by path remapping. pub working_dir: (PathBuf, bool), - // FIXME: `lint_store` and `buffered_lints` are not thread-safe, - // but are only used in a single thread. - pub lint_store: RwLock<lint::LintStore>, + /// This is intended to be used from a single thread. + /// + /// FIXME: there was a previous comment about this not being thread safe, + /// but it's not clear how or why that's the case. The LintBuffer itself is certainly thread + /// safe at least from a "Rust safety" standpoint. pub buffered_lints: Lock<Option<lint::LintBuffer>>, /// Set of `(DiagnosticId, Option<Span>, message)` tuples tracking @@ -1213,7 +1215,6 @@ fn build_session_( sysroot, local_crate_source_file, working_dir, - lint_store: RwLock::new(lint::LintStore::new()), buffered_lints: Lock::new(Some(Default::default())), one_time_diagnostics: Default::default(), plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())), diff --git a/src/librustc/session/search_paths.rs b/src/librustc/session/search_paths.rs index 3695f0a82f4..949dad751a1 100644 --- a/src/librustc/session/search_paths.rs +++ b/src/librustc/session/search_paths.rs @@ -1,5 +1,4 @@ use std::path::{Path, PathBuf}; -use rustc_macros::HashStable; use crate::session::{early_error, config}; use crate::session::filesearch::make_target_lib_path; @@ -10,7 +9,7 @@ pub struct SearchPath { pub files: Vec<PathBuf>, } -#[derive(Eq, PartialEq, Clone, Copy, Debug, PartialOrd, Ord, Hash, HashStable)] +#[derive(PartialEq, Clone, Copy, Debug, HashStable)] pub enum PathKind { Native, Crate, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ae604b9eb13..e684cdc0a38 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -793,15 +793,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::Predicate::ObjectSafe(trait_def_id) => { let violations = self.tcx.object_safety_violations(trait_def_id); - if let Some(err) = self.tcx.report_object_safety_error( + self.tcx.report_object_safety_error( span, trait_def_id, violations, - ) { - err - } else { - return; - } + ) } ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { @@ -937,11 +933,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { TraitNotObjectSafe(did) => { let violations = self.tcx.object_safety_violations(did); - if let Some(err) = self.tcx.report_object_safety_error(span, did, violations) { - err - } else { - return; - } + self.tcx.report_object_safety_error(span, did, violations) } // already reported in the query @@ -1665,11 +1657,7 @@ impl<'tcx> TyCtxt<'tcx> { span: Span, trait_def_id: DefId, violations: Vec<ObjectSafetyViolation>, - ) -> Option<DiagnosticBuilder<'tcx>> { - if self.sess.trait_methods_not_found.borrow().contains(&span) { - // Avoid emitting error caused by non-existing method (#58734) - return None; - } + ) -> DiagnosticBuilder<'tcx> { let trait_str = self.def_path_str(trait_def_id); let span = self.sess.source_map().def_span(span); let mut err = struct_span_err!( @@ -1687,7 +1675,13 @@ impl<'tcx> TyCtxt<'tcx> { }; } } - Some(err) + + if self.sess.trait_methods_not_found.borrow().contains(&span) { + // Avoid emitting error caused by non-existing method (#58734) + err.cancel(); + } + + err } } @@ -2098,6 +2092,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.note(&format!("required for the cast to the object type `{}`", self.ty_to_string(object_ty))); } + ObligationCauseCode::Coercion { source: _, target } => { + err.note(&format!("required by cast to type `{}`", + self.ty_to_string(target))); + } ObligationCauseCode::RepeatVec => { err.note("the `Copy` trait is required because the \ repeated element will be copied"); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index d96330bf0a9..eb4b114eb30 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -188,6 +188,9 @@ pub enum ObligationCauseCode<'tcx> { /// Obligation incurred due to an object cast. ObjectCastObligation(/* Object type */ Ty<'tcx>), + /// Obligation incurred due to a coercion. + Coercion { source: Ty<'tcx>, target: Ty<'tcx> }, + // Various cases where expressions must be sized/copy/etc: /// L = X implies that L is Sized AssignmentLhsSized, diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 112a1d0e09c..f6ea77dc5cc 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -40,7 +40,7 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::normalize::Normalize<T>>>; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug)] pub struct NoSolution; pub type Fallible<T> = Result<T, NoSolution>; diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs index 12a834fbda6..7aa98703411 100644 --- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs +++ b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs @@ -3,7 +3,7 @@ use crate::traits::query::outlives_bounds::OutlivesBound; use crate::traits::query::Fallible; use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct ImpliedOutlivesBounds<'tcx> { pub ty: Ty<'tcx>, } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 44d611ace77..d8a27f1e040 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2246,7 +2246,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if let Some(principal) = data.principal() { - principal.with_self_ty(self.tcx(), self_ty) + if !self.infcx.tcx.features().object_safe_for_dispatch { + principal.with_self_ty(self.tcx(), self_ty) + } else if self.tcx().is_object_safe(principal.def_id()) { + principal.with_self_ty(self.tcx(), self_ty) + } else { + return; + } } else { // Only auto-trait bounds exist. return; diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 2a53dcab8a9..18db3c8d10b 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -481,6 +481,10 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { .and_then(|r| Some(super::ObjectTypeBound(ty, r))) ), super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation), + super::Coercion { source, target } => Some(super::Coercion { + source: tcx.lift(&source)?, + target: tcx.lift(&target)?, + }), super::AssignmentLhsSized => Some(super::AssignmentLhsSized), super::TupleInitializerSized => Some(super::TupleInitializerSized), super::StructInitializerSized => Some(super::StructInitializerSized), diff --git a/src/librustc/ty/binding.rs b/src/librustc/ty/binding.rs index 1290141b0a6..5570144489c 100644 --- a/src/librustc/ty/binding.rs +++ b/src/librustc/ty/binding.rs @@ -2,7 +2,7 @@ use crate::hir::BindingAnnotation::*; use crate::hir::BindingAnnotation; use crate::hir::Mutability; -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] pub enum BindingMode { BindByReference(Mutability), BindByValue(Mutability), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index d34e8d68720..d5a93e02905 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -827,7 +827,7 @@ rustc_index::newtype_index! { pub type CanonicalUserTypeAnnotations<'tcx> = IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>; -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct CanonicalUserTypeAnnotation<'tcx> { pub user_ty: CanonicalUserType<'tcx>, pub span: Span, @@ -882,7 +882,7 @@ impl CanonicalUserType<'tcx> { }, GenericArgKind::Const(ct) => match ct.val { - ConstValue::Infer(InferConst::Canonical(debruijn, b)) => { + ConstValue::Bound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in substitutions. assert_eq!(debruijn, ty::INNERMOST); cvar == b @@ -899,7 +899,7 @@ impl CanonicalUserType<'tcx> { /// A user-given type annotation attached to a constant. These arise /// from constants that are named via paths, like `Foo::<A>::new` and /// so forth. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable)] pub enum UserType<'tcx> { Ty(Ty<'tcx>), @@ -1031,6 +1031,8 @@ pub struct GlobalCtxt<'tcx> { pub sess: &'tcx Session, + pub lint_store: Lrc<lint::LintStore>, + pub dep_graph: DepGraph, pub prof: SelfProfilerRef, @@ -1192,6 +1194,7 @@ impl<'tcx> TyCtxt<'tcx> { /// reference to the context, to allow formatting values that need it. pub fn create_global_ctxt( s: &'tcx Session, + lint_store: Lrc<lint::LintStore>, cstore: &'tcx CrateStoreDyn, local_providers: ty::query::Providers<'tcx>, extern_providers: ty::query::Providers<'tcx>, @@ -1255,6 +1258,7 @@ impl<'tcx> TyCtxt<'tcx> { GlobalCtxt { sess: s, + lint_store, cstore, arena: WorkerLocal::new(|_| Arena::default()), interners, diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 5851a48a8d3..77613b548cf 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -45,13 +45,12 @@ pub enum TypeError<'tcx> { ProjectionMismatched(ExpectedFound<DefId>), ProjectionBoundsLength(ExpectedFound<usize>), ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>), - + ObjectUnsafeCoercion(DefId), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), IntrinsicCast, } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] pub enum UnconstrainedNumeric { UnconstrainedFloat, UnconstrainedInt, @@ -179,6 +178,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { IntrinsicCast => { write!(f, "cannot coerce intrinsics to function pointers") } + ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"), } } } diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 038b54f1f26..27a09b394b8 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -19,7 +19,7 @@ pub type SimplifiedType = SimplifiedTypeGen<DefId>; /// the non-stable but fast to construct DefId-version is the better choice. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, RustcEncodable, RustcDecodable)] pub enum SimplifiedTypeGen<D> - where D: Copy + Debug + Ord + Eq + Hash + where D: Copy + Debug + Ord + Eq { BoolSimplifiedType, CharSimplifiedType, @@ -123,10 +123,10 @@ pub fn simplify_type( } } -impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> { +impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> { pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U> where F: Fn(D) -> U, - U: Copy + Debug + Ord + Eq + Hash, + U: Copy + Debug + Ord + Eq, { match self { BoolSimplifiedType => BoolSimplifiedType, @@ -155,7 +155,7 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> { impl<'a, D> HashStable<StableHashingContext<'a>> for SimplifiedTypeGen<D> where - D: Copy + Debug + Ord + Eq + Hash + HashStable<StableHashingContext<'a>>, + D: Copy + Debug + Ord + Eq + HashStable<StableHashingContext<'a>>, { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index d3a3f51cfa4..cb1fb4f685d 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -240,10 +240,10 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_CT_INFER); match infer { InferConst::Fresh(_) => {} - InferConst::Canonical(debruijn, _) => self.add_binder(debruijn), InferConst::Var(_) => self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX), } } + ConstValue::Bound(debruijn, _) => self.add_binder(debruijn), ConstValue::Param(_) => { self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_PARAMS); } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 5192075c26e..bacf3d42f04 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -88,6 +88,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_infer_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_INFER) } + fn has_infer_consts(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_CT_INFER) + } fn has_local_value(&self) -> bool { self.has_type_flags(TypeFlags::KEEP_IN_LOCAL_TCX) } @@ -518,10 +521,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { } fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { - val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, bound_const)), - ty, - } = *ct { + if let ty::Const { val: ConstValue::Bound(debruijn, bound_const), ty } = *ct { if debruijn == self.current_index { let fld_c = &mut self.fld_c; let ct = fld_c(bound_const, ty); @@ -567,7 +567,10 @@ impl<'tcx> TyCtxt<'tcx> { // identity for bound types and consts let fld_t = |bound_ty| self.mk_ty(ty::Bound(ty::INNERMOST, bound_ty)); let fld_c = |bound_ct, ty| { - self.mk_const_infer(ty::InferConst::Canonical(ty::INNERMOST, bound_ct), ty) + self.mk_const(ty::Const { + val: ConstValue::Bound(ty::INNERMOST, bound_ct), + ty, + }) }; self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) } @@ -718,7 +721,6 @@ impl<'tcx> TyCtxt<'tcx> { // vars. See comment on `shift_vars_through_binders` method in // `subst.rs` for more details. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] enum Direction { In, Out, @@ -799,10 +801,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { } fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { - val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, bound_const)), - ty, - } = *ct { + if let ty::Const { val: ConstValue::Bound(debruijn, bound_ct), ty } = *ct { if self.amount == 0 || debruijn < self.current_index { ct } else { @@ -813,7 +812,10 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { debruijn.shifted_out(self.amount) } }; - self.tcx.mk_const_infer(ty::InferConst::Canonical(debruijn, bound_const), ty) + self.tcx.mk_const(ty::Const { + val: ConstValue::Bound(debruijn, bound_ct), + ty, + }) } } else { ct.super_fold_with(self) @@ -917,8 +919,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { // const, as it has types/regions embedded in a lot of other // places. match ct.val { - ConstValue::Infer(ty::InferConst::Canonical(debruijn, _)) - if debruijn >= self.outer_index => true, + ConstValue::Bound(debruijn, _) if debruijn >= self.outer_index => true, _ => ct.super_visit_with(self), } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f72a221fe39..feede00fea1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -159,7 +159,7 @@ impl AssocItemContainer { /// The "header" of an impl is everything outside the body: a Self type, a trait /// ref (in the case of a trait impl), and a set of predicates (from the /// bounds / where-clauses). -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Debug)] pub struct ImplHeader<'tcx> { pub impl_def_id: DefId, pub self_ty: Ty<'tcx>, @@ -195,7 +195,7 @@ pub struct AssocItem { pub method_has_self_argument: bool, } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Copy, Clone, PartialEq, Debug, HashStable)] pub enum AssocKind { Const, Method, @@ -331,7 +331,7 @@ impl Visibility { } } -#[derive(Copy, Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Hash, HashStable)] +#[derive(Copy, Clone, PartialEq, RustcDecodable, RustcEncodable, HashStable)] pub enum Variance { Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell @@ -752,7 +752,7 @@ pub struct UpvarId { pub closure_expr_id: LocalDefId, } -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy, HashStable)] +#[derive(Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, HashStable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. ImmBorrow, diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index 0c48ae97178..0a217e9ae66 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -8,14 +8,12 @@ use crate::ty::subst::SubstsRef; use crate::ty::fast_reject::SimplifiedType; use crate::mir; -use std::fmt::Debug; -use std::hash::Hash; use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::symbol::Symbol; /// The `Key` trait controls what types can legally be used as the key /// for a query. -pub(super) trait Key: Clone + Hash + Eq + Debug { +pub(super) trait Key { /// Given an instance of this key, what crate is it referring to? /// This is used to find the provider. fn query_crate(&self) -> CrateNum; @@ -201,10 +199,7 @@ impl Key for Symbol { /// Canonical query goals correspond to abstract trait operations that /// are not tied to any crate in particular. -impl<'tcx, T> Key for Canonical<'tcx, T> -where - T: Debug + Hash + Clone + Eq, -{ +impl<'tcx, T> Key for Canonical<'tcx, T> { fn query_crate(&self) -> CrateNum { LOCAL_CRATE } diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 7f05e553bc9..41b4883793b 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -801,7 +801,7 @@ macro_rules! define_queries_inner { } #[allow(nonstandard_style)] - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + #[derive(Clone, Copy)] pub enum QueryName { $($name),* } @@ -819,7 +819,7 @@ macro_rules! define_queries_inner { } #[allow(nonstandard_style)] - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] + #[derive(Clone, Debug)] pub enum Query<$tcx> { $($(#[$attr])* $name($K)),* } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 83ec98f9ddd..5d78d563e9a 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -749,6 +749,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch), IntrinsicCast => IntrinsicCast, + ObjectUnsafeCoercion(ref x) => return tcx.lift(x).map(ObjectUnsafeCoercion), }) } } @@ -1350,6 +1351,7 @@ EnumTypeFoldableImpl! { (ty::error::TypeError::ExistentialMismatch)(x), (ty::error::TypeError::ConstMismatch)(x), (ty::error::TypeError::IntrinsicCast), + (ty::error::TypeError::ObjectUnsafeCoercion)(x), } } @@ -1379,27 +1381,23 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self { match *self { - ConstValue::ByRef { alloc, offset } => - ConstValue::ByRef { alloc, offset }, ConstValue::Infer(ic) => ConstValue::Infer(ic.fold_with(folder)), ConstValue::Param(p) => ConstValue::Param(p.fold_with(folder)), - ConstValue::Placeholder(p) => ConstValue::Placeholder(p), - ConstValue::Scalar(a) => ConstValue::Scalar(a), - ConstValue::Slice { data, start, end } => ConstValue::Slice { data, start, end }, ConstValue::Unevaluated(did, substs) => ConstValue::Unevaluated(did, substs.fold_with(folder)), + ConstValue::ByRef { .. } | ConstValue::Bound(..) | ConstValue::Placeholder(..) + | ConstValue::Scalar(..) | ConstValue::Slice { .. } => *self, + } } fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { match *self { - ConstValue::ByRef { .. } => false, ConstValue::Infer(ic) => ic.visit_with(visitor), ConstValue::Param(p) => p.visit_with(visitor), - ConstValue::Placeholder(_) => false, - ConstValue::Scalar(_) => false, - ConstValue::Slice { .. } => false, ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor), + ConstValue::ByRef { .. } | ConstValue::Bound(..) | ConstValue::Placeholder(_) + | ConstValue::Scalar(_) | ConstValue::Slice { .. } => false, } } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index f4de0cd7b6b..3a9994ac64c 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -304,8 +304,7 @@ static_assert_size!(TyKind<'_>, 24); /// type parameters is similar, but the role of CK and CS are /// different. CK represents the "yield type" and CS represents the /// "return type" of the generator. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, - RustcEncodable, RustcDecodable, HashStable)] +#[derive(Copy, Clone, Debug)] pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function, /// concatenated with the types of the upvars. @@ -392,8 +391,7 @@ impl<'tcx> ClosureSubsts<'tcx> { } /// Similar to `ClosureSubsts`; see the above documentation for more. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, - RustcEncodable, RustcDecodable, HashStable)] +#[derive(Copy, Clone, Debug)] pub struct GeneratorSubsts<'tcx> { pub substs: SubstsRef<'tcx>, } @@ -1035,7 +1033,7 @@ impl<'tcx> ProjectionTy<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, Debug)] pub struct GenSig<'tcx> { pub yield_ty: Ty<'tcx>, pub return_ty: Ty<'tcx>, @@ -2373,6 +2371,4 @@ pub enum InferConst<'tcx> { Var(ConstVid<'tcx>), /// A fresh const variable. See `infer::freshen` for more details. Fresh(u32), - /// Canonicalized const variable, used only when preparing a trait query. - Canonical(DebruijnIndex, BoundVar), } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 4081c02a33c..29721979099 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -2,7 +2,7 @@ use crate::hir::def_id::DefId; use crate::infer::canonical::Canonical; -use crate::ty::{self, Lift, List, Ty, TyCtxt, InferConst, ParamConst}; +use crate::ty::{self, Lift, List, Ty, TyCtxt, ParamConst}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::mir::interpret::ConstValue; use crate::ty::sty::{ClosureSubsts, GeneratorSubsts}; @@ -234,9 +234,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { ty::GenericParamDefKind::Const => { tcx.mk_const(ty::Const { - val: ConstValue::Infer( - InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from(param.index)) - ), + val: ConstValue::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)), ty: tcx.type_of(def_id), }).into() } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index e1eab2c6579..5555dace45b 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -818,6 +818,8 @@ impl<'tcx> ty::TyS<'tcx> { /// /// (Note that this implies that if `ty` has a destructor attached, /// then `needs_drop` will definitely return `true` for `ty`.) + /// + /// Note that this method is used to check eligible types in unions. #[inline] pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { tcx.needs_drop_raw(param_env.and(self)).0 diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index ecb075e30b1..b50e819c956 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -380,16 +380,21 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // obligations that don't refer to Self and // checking those - let cause = self.cause(traits::MiscObligation); - let component_traits = - data.auto_traits().chain(data.principal_def_id()); - self.out.extend( - component_traits.map(|did| traits::Obligation::new( - cause.clone(), - param_env, - ty::Predicate::ObjectSafe(did) - )) - ); + let defer_to_coercion = + self.infcx.tcx.features().object_safe_for_dispatch; + + if !defer_to_coercion { + let cause = self.cause(traits::MiscObligation); + let component_traits = + data.auto_traits().chain(data.principal_def_id()); + self.out.extend( + component_traits.map(|did| traits::Obligation::new( + cause.clone(), + param_env, + ty::Predicate::ObjectSafe(did) + )) + ); + } } // Inference variables are the complicated case, since we don't diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml index 98efa6a5804..867bbd22cfb 100644 --- a/src/librustc_codegen_llvm/Cargo.toml +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -12,9 +12,3 @@ test = false [dependencies] rustc_llvm = { path = "../librustc_llvm" } - -[features] -# This is used to convince Cargo to separately cache builds of `rustc_codegen_llvm` -# when this option is enabled or not. That way we can build two, cache two -# artifacts, and have nice speedy rebuilds. -emscripten = ["rustc_llvm/emscripten"] diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 7437b1e3c8a..b3be3d09f17 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -53,9 +53,7 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>, let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| { if level.is_below_threshold(export_threshold) { - let mut bytes = Vec::with_capacity(name.len() + 1); - bytes.extend(name.bytes()); - Some(CString::new(bytes).unwrap()) + Some(CString::new(name.as_str()).unwrap()) } else { None } diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index d0bfbe05148..f0148a21ae6 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -2069,11 +2069,9 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, 'tcx>, { let mut composite_types_completed = debug_context(cx).composite_types_completed.borrow_mut(); - if composite_types_completed.contains(&composite_type_metadata) { + if !composite_types_completed.insert(&composite_type_metadata) { bug!("debuginfo::set_members_of_composite_type() - \ Already completed forward declaration re-encountered."); - } else { - composite_types_completed.insert(composite_type_metadata); } } diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index a2313b933a6..c69942ef3f2 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -50,7 +50,7 @@ pub enum CallConv { } /// LLVMRustLinkage -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(PartialEq)] #[repr(C)] pub enum Linkage { ExternalLinkage = 0, @@ -67,7 +67,6 @@ pub enum Linkage { } // LLVMRustVisibility -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[repr(C)] pub enum Visibility { Default = 0, diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 8bc815f2c62..762b50f1659 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -259,7 +259,7 @@ fn generate_lto_work<B: ExtraBackendMethods>( needs_thin_lto: Vec<(String, B::ThinBuffer)>, import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)> ) -> Vec<(WorkItem<B>, u64)> { - let _prof_timer = cgcx.prof.generic_activity("codegen_run_lto"); + let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work"); let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); @@ -674,11 +674,11 @@ impl<B: WriteBackendMethods> WorkItem<B> { } } - pub fn name(&self) -> String { + fn profiling_event_id(&self) -> &'static str { match *self { - WorkItem::Optimize(ref m) => format!("optimize: {}", m.name), - WorkItem::CopyPostLtoArtifacts(ref m) => format!("copy post LTO artifacts: {}", m.name), - WorkItem::LTO(ref m) => format!("lto: {}", m.name()), + WorkItem::Optimize(_) => "codegen_module_optimize", + WorkItem::CopyPostLtoArtifacts(_) => "codegen_copy_artifacts_from_incr_cache", + WorkItem::LTO(_) => "codegen_module_perform_lto", } } } @@ -1587,7 +1587,7 @@ fn spawn_work<B: ExtraBackendMethods>( // as a diagnostic was already sent off to the main thread - just // surface that there was an error in this worker. bomb.result = { - let _prof_timer = cgcx.prof.generic_activity(&work.name()); + let _prof_timer = cgcx.prof.generic_activity(work.profiling_event_id()); execute_work_item(&cgcx, work).ok() }; }); diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 516fd5049f2..bf687f84635 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -406,6 +406,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &' rust_main_def_id: DefId, use_start_lang_item: bool, ) { + // The entry function is either `int main(void)` or `int main(int argc, char **argv)`, + // depending on whether the target needs `argc` and `argv` to be passed in. let llfty = if cx.sess().target.target.options.main_needs_argc_argv { cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int()) } else { @@ -440,19 +442,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &' bx.insert_reference_to_gdb_debug_scripts_section_global(); - let (arg_argc, arg_argv) = if cx.sess().target.target.options.main_needs_argc_argv { - // Params from native main() used as args for rust start function - let param_argc = bx.get_param(0); - let param_argv = bx.get_param(1); - let arg_argc = bx.intcast(param_argc, cx.type_isize(), true); - let arg_argv = param_argv; - (arg_argc, arg_argv) - } else { - // The Rust start function doesn't need argc and argv, so just pass zeros. - let arg_argc = bx.const_int(cx.type_int(), 0); - let arg_argv = bx.const_null(cx.type_ptr_to(cx.type_i8p())); - (arg_argc, arg_argv) - }; + let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx); let (start_fn, args) = if use_start_lang_item { let start_def_id = cx.tcx().require_lang_item(StartFnLangItem, None); @@ -477,6 +467,27 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &' } } +/// Obtain the `argc` and `argv` values to pass to the rust start function. +fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + cx: &'a Bx::CodegenCx, + bx: &mut Bx +) -> (Bx::Value, Bx::Value) +{ + if cx.sess().target.target.options.main_needs_argc_argv { + // Params from native `main()` used as args for rust start function + let param_argc = bx.get_param(0); + let param_argv = bx.get_param(1); + let arg_argc = bx.intcast(param_argc, cx.type_isize(), true); + let arg_argv = param_argv; + (arg_argc, arg_argv) + } else { + // The Rust start function doesn't need `argc` and `argv`, so just pass zeros. + let arg_argc = bx.const_int(cx.type_int(), 0); + let arg_argv = bx.const_null(cx.type_ptr_to(cx.type_i8p())); + (arg_argc, arg_argv) + } +} + pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX; pub fn codegen_crate<B: ExtraBackendMethods>( diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index daa25b2ea05..ba5e47aeede 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -79,6 +79,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { ConstValue::Unevaluated(..) => bug!("unevaluated constant in `OperandRef::from_const`"), ConstValue::Param(_) => bug!("encountered a ConstValue::Param in codegen"), ConstValue::Infer(_) => bug!("encountered a ConstValue::Infer in codegen"), + ConstValue::Bound(..) => bug!("encountered a ConstValue::Bound in codegen"), ConstValue::Placeholder(_) => bug!("encountered a ConstValue::Placeholder in codegen"), ConstValue::Scalar(x) => { let scalar = match layout.abi { diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 27442bb6bff..7e662ea37db 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -556,7 +556,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Bx::Value { let is_float = input_ty.is_floating_point(); let is_signed = input_ty.is_signed(); - let is_unit = input_ty.is_unit(); match op { mir::BinOp::Add => if is_float { bx.fadd(lhs, rhs) @@ -594,13 +593,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::BinOp::Shl => common::build_unchecked_lshift(bx, lhs, rhs), mir::BinOp::Shr => common::build_unchecked_rshift(bx, input_ty, lhs, rhs), mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt | - mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_unit { - bx.cx().const_bool(match op { - mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt => false, - mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => true, - _ => unreachable!() - }) - } else if is_float { + mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_float { bx.fcmp( base::bin_op_to_fcmp_predicate(op.to_hir_binop()), lhs, rhs diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs index 29a8a98d229..444463c08e5 100644 --- a/src/librustc_data_structures/graph/dominators/mod.rs +++ b/src/librustc_data_structures/graph/dominators/mod.rs @@ -17,7 +17,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> { dominators_given_rpo(graph, &rpo) } -pub fn dominators_given_rpo<G: ControlFlowGraph>( +fn dominators_given_rpo<G: ControlFlowGraph>( graph: &G, rpo: &[G::Node], ) -> Dominators<G::Node> { @@ -43,14 +43,12 @@ pub fn dominators_given_rpo<G: ControlFlowGraph>( let mut new_idom = None; for pred in graph.predecessors(node) { if immediate_dominators[pred].is_some() { - // (*) // (*) dominators for `pred` have been calculated - new_idom = intersect_opt( - &post_order_rank, - &immediate_dominators, - new_idom, - Some(pred), - ); + new_idom = Some(if let Some(new_idom) = new_idom { + intersect(&post_order_rank, &immediate_dominators, new_idom, pred) + } else { + pred + }); } } @@ -67,19 +65,6 @@ pub fn dominators_given_rpo<G: ControlFlowGraph>( } } -fn intersect_opt<Node: Idx>( - post_order_rank: &IndexVec<Node, usize>, - immediate_dominators: &IndexVec<Node, Option<Node>>, - node1: Option<Node>, - node2: Option<Node>, -) -> Option<Node> { - match (node1, node2) { - (None, None) => None, - (Some(n), None) | (None, Some(n)) => Some(n), - (Some(n1), Some(n2)) => Some(intersect(post_order_rank, immediate_dominators, n1, n2)), - } -} - fn intersect<Node: Idx>( post_order_rank: &IndexVec<Node, usize>, immediate_dominators: &IndexVec<Node, Option<Node>>, diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/src/librustc_data_structures/graph/implementation/mod.rs index c438a8558a7..9fdcea6df88 100644 --- a/src/librustc_data_structures/graph/implementation/mod.rs +++ b/src/librustc_data_structures/graph/implementation/mod.rs @@ -60,10 +60,10 @@ impl<N> SnapshotVecDelegate for Edge<N> { fn reverse(_: &mut Vec<Edge<N>>, _: ()) {} } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Debug)] pub struct NodeIndex(pub usize); -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Debug)] pub struct EdgeIndex(pub usize); pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX); diff --git a/src/librustc_data_structures/sharded.rs b/src/librustc_data_structures/sharded.rs index d0ff6108d6e..2f972eeccdc 100644 --- a/src/librustc_data_structures/sharded.rs +++ b/src/librustc_data_structures/sharded.rs @@ -90,7 +90,7 @@ impl<T> Sharded<T> { pub type ShardedHashMap<K, V> = Sharded<FxHashMap<K, V>>; -impl<K: Eq + Hash, V> ShardedHashMap<K, V> { +impl<K: Eq, V> ShardedHashMap<K, V> { pub fn len(&self) -> usize { self.lock_shards().iter().map(|shard| shard.len()).sum() } diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index ce0aa07cc28..bdd3dc96656 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -7,7 +7,7 @@ use std::mem; mod tests; pub struct SnapshotMap<K, V> - where K: Hash + Clone + Eq + where K: Clone + Eq { map: FxHashMap<K, V>, undo_log: Vec<UndoLog<K, V>>, diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index ee4f6a5e785..092208cfe1d 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -169,7 +169,7 @@ pub trait HashStable<CTX> { /// example, for DefId that can be converted to a DefPathHash. This is used for /// bringing maps into a predictable order before hashing them. pub trait ToStableHashKey<HCX> { - type KeyType: Ord + Clone + Sized + HashStable<HCX>; + type KeyType: Ord + Sized + HashStable<HCX>; fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType; } @@ -460,7 +460,7 @@ impl_stable_hash_via_hash!(::std::path::Path); impl_stable_hash_via_hash!(::std::path::PathBuf); impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R> - where K: ToStableHashKey<HCX> + Eq + Hash, + where K: ToStableHashKey<HCX> + Eq, V: HashStable<HCX>, R: BuildHasher, { @@ -471,7 +471,7 @@ impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R> } impl<K, R, HCX> HashStable<HCX> for ::std::collections::HashSet<K, R> - where K: ToStableHashKey<HCX> + Eq + Hash, + where K: ToStableHashKey<HCX> + Eq, R: BuildHasher, { fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { @@ -513,10 +513,10 @@ pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>( hasher: &mut StableHasher, map: &::std::collections::HashMap<K, V, R>, to_stable_hash_key: F) - where K: Eq + Hash, + where K: Eq, V: HashStable<HCX>, R: BuildHasher, - SK: HashStable<HCX> + Ord + Clone, + SK: HashStable<HCX> + Ord, F: Fn(&K, &HCX) -> SK, { let mut entries: Vec<_> = map.iter() diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 9622c290039..f09474ff4d3 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -738,7 +738,7 @@ impl<T: Clone> Clone for RwLock<T> { /// A type which only allows its inner value to be used in one thread. /// It will panic if it is used on multiple threads. -#[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)] +#[derive(Debug)] pub struct OneThread<T> { #[cfg(parallel_compiler)] thread: thread::ThreadId, diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs index 93a8b7f525f..d97da489db8 100644 --- a/src/librustc_data_structures/thin_vec.rs +++ b/src/librustc_data_structures/thin_vec.rs @@ -3,7 +3,7 @@ use crate::stable_hasher::{StableHasher, HashStable}; /// A vector type optimized for cases where this size is usually 0 (cf. `SmallVector`). /// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`, /// which uses only a single (null) pointer. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct ThinVec<T>(Option<Box<Vec<T>>>); impl<T> ThinVec<T> { diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs index ea771d9f20f..371f0f6fa0b 100644 --- a/src/librustc_data_structures/tiny_list.rs +++ b/src/librustc_data_structures/tiny_list.rs @@ -14,7 +14,7 @@ #[cfg(test)] mod tests; -#[derive(Clone, Hash, Debug, PartialEq)] +#[derive(Clone)] pub struct TinyList<T: PartialEq> { head: Option<Element<T>> } @@ -80,7 +80,7 @@ impl<T: PartialEq> TinyList<T> { } } -#[derive(Clone, Hash, Debug, PartialEq)] +#[derive(Clone)] struct Element<T: PartialEq> { data: T, next: Option<Box<Element<T>>>, diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index f0a9c3afc68..a3926c15551 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -11,7 +11,7 @@ use std::mem; mod tests; #[derive(Clone, Debug)] -pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash> { +pub struct TransitiveRelation<T: Eq + Hash> { // List of elements. This is used to map from a T to a usize. elements: Vec<T>, @@ -35,7 +35,7 @@ pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash> { } // HACK(eddyb) manual impl avoids `Default` bound on `T`. -impl<T: Clone + Debug + Eq + Hash> Default for TransitiveRelation<T> { +impl<T: Eq + Hash> Default for TransitiveRelation<T> { fn default() -> Self { TransitiveRelation { elements: Default::default(), @@ -46,7 +46,7 @@ impl<T: Clone + Debug + Eq + Hash> Default for TransitiveRelation<T> { } } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, RustcEncodable, RustcDecodable, Debug)] struct Index(usize); #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index aa74966d0ab..a9e4e6db1c7 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -16,6 +16,7 @@ log = "0.4" env_logger = { version = "0.7", default-features = false } rustc = { path = "../librustc" } rustc_target = { path = "../librustc_target" } +rustc_lint = { path = "../librustc_lint" } rustc_data_structures = { path = "../librustc_data_structures" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_metadata = { path = "../librustc_metadata" } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f33cb4e215d..5d9dec14c6c 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -106,6 +106,8 @@ pub fn abort_on_err<T>(result: Result<T, ErrorReported>, sess: &Session) -> T { pub trait Callbacks { /// Called before creating the compiler instance fn config(&mut self, _config: &mut interface::Config) {} + /// Called early during compilation to allow other drivers to easily register lints. + fn extra_lints(&mut self, _ls: &mut lint::LintStore) {} /// Called after parsing. Return value instructs the compiler whether to /// continue the compilation afterwards (defaults to `Compilation::Continue`) fn after_parsing(&mut self, _compiler: &interface::Compiler) -> Compilation { @@ -167,7 +169,7 @@ pub fn run_compiler( }; let sopts = config::build_session_options(&matches); - let cfg = config::parse_cfgspecs(matches.opt_strs("cfg")); + let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg")); let mut dummy_config = |sopts, cfg, diagnostic_output| { let mut config = interface::Config { @@ -182,6 +184,7 @@ pub fn run_compiler( stderr: None, crate_name: None, lint_caps: Default::default(), + register_lints: None, }; callbacks.config(&mut config); config @@ -202,9 +205,13 @@ pub fn run_compiler( interface::run_compiler(config, |compiler| { let sopts = &compiler.session().opts; if sopts.describe_lints { + let lint_store = rustc_lint::new_lint_store( + sopts.debugging_opts.no_interleave_lints, + compiler.session().unstable_options(), + ); describe_lints( compiler.session(), - &*compiler.session().lint_store.borrow(), + &lint_store, false ); return; @@ -255,6 +262,7 @@ pub fn run_compiler( stderr: None, crate_name: None, lint_caps: Default::default(), + register_lints: None, }; callbacks.config(&mut config); @@ -321,12 +329,14 @@ pub fn run_compiler( return sess.compile_status(); } - compiler.register_plugins()?; + { + let (_, _, lint_store) = &*compiler.register_plugins()?.peek(); - // Lint plugins are registered; now we can process command line flags. - if sess.opts.describe_lints { - describe_lints(&sess, &sess.lint_store.borrow(), true); - return sess.compile_status(); + // Lint plugins are registered; now we can process command line flags. + if sess.opts.describe_lints { + describe_lints(&sess, &lint_store, true); + return sess.compile_status(); + } } compiler.expansion()?; @@ -835,8 +845,7 @@ Available lint options: "); - fn sort_lints(sess: &Session, lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> { - let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect(); + fn sort_lints(sess: &Session, mut lints: Vec<&'static Lint>) -> Vec<&'static Lint> { // The sort doesn't case-fold but it's doubtful we care. lints.sort_by_cached_key(|x: &&Lint| (x.default_level(sess), x.name)); lints @@ -852,7 +861,7 @@ Available lint options: let (plugin, builtin): (Vec<_>, _) = lint_store.get_lints() .iter() .cloned() - .partition(|&(_, p)| p); + .partition(|&lint| lint.is_plugin); let plugin = sort_lints(sess, plugin); let builtin = sort_lints(sess, builtin); diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index fd74d8673da..1781f2e1650 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -152,6 +152,32 @@ impl Diagnostic { self.note_expected_found_extra(label, expected, found, &"", &"") } + pub fn note_unsuccessfull_coercion(&mut self, + expected: DiagnosticStyledString, + found: DiagnosticStyledString) + -> &mut Self + { + let mut msg: Vec<_> = + vec![(format!("required when trying to coerce from type `"), + Style::NoStyle)]; + msg.extend(expected.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("` to type '"), Style::NoStyle)); + msg.extend(found.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("`"), Style::NoStyle)); + + // For now, just attach these as notes + self.highlighted_note(msg); + self + } + pub fn note_expected_found_extra(&mut self, label: &dyn fmt::Display, expected: DiagnosticStyledString, diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index cc60bf89c7e..40642dd14b8 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -209,6 +209,11 @@ impl<'a> DiagnosticBuilder<'a> { found_extra: &dyn fmt::Display, ) -> &mut Self); + forward!(pub fn note_unsuccessfull_coercion(&mut self, + expected: DiagnosticStyledString, + found: DiagnosticStyledString, + ) -> &mut Self); + forward!(pub fn note(&mut self, msg: &str) -> &mut Self); forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self, sp: S, diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 1e486786f68..e3b55a14133 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -12,7 +12,7 @@ use Destination::*; use syntax_pos::{SourceFile, Span, MultiSpan}; use crate::{ - Level, CodeSuggestion, Diagnostic, SubDiagnostic, + Level, CodeSuggestion, Diagnostic, SubDiagnostic, pluralise, SuggestionStyle, SourceMapper, SourceMapperDyn, DiagnosticId, }; use crate::Level::Error; @@ -1572,7 +1572,8 @@ impl EmitterWriter { } } if suggestions.len() > MAX_SUGGESTIONS { - let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS); + let others = suggestions.len() - MAX_SUGGESTIONS; + let msg = format!("and {} other candidate{}", others, pluralise!(others)); buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); } else if notice_capitalization { let msg = "notice the capitalization difference"; diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index 7a0d931ca73..0d8d765a572 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -27,6 +27,7 @@ rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } rustc_passes = { path = "../librustc_passes" } +rustc_target = { path = "../librustc_target" } rustc_typeck = { path = "../librustc_typeck" } rustc_lint = { path = "../librustc_lint" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index b26bd75c974..24ea0fc8bf6 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -3,7 +3,8 @@ use crate::util; pub use crate::passes::BoxedResolver; use rustc::lint; -use rustc::session::config::{self, Input}; +use rustc::session::early_error; +use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::session::{DiagnosticOutput, Session}; use rustc::util::common::ErrorReported; use rustc_codegen_utils::codegen_backend::CodegenBackend; @@ -14,9 +15,13 @@ use rustc_metadata::cstore::CStore; use std::path::PathBuf; use std::result; use std::sync::{Arc, Mutex}; -use syntax; -use syntax::source_map::{FileLoader, SourceMap}; +use syntax::{self, parse}; +use syntax::ast::{self, MetaItemKind}; +use syntax::parse::token; +use syntax::source_map::{FileName, FilePathMapping, FileLoader, SourceMap}; +use syntax::sess::ParseSess; use syntax_pos::edition; +use rustc_errors::{Diagnostic, emitter::Emitter, Handler, SourceMapperDyn}; pub type Result<T> = result::Result<T, ErrorReported>; @@ -34,6 +39,7 @@ pub struct Compiler { pub(crate) queries: Queries, pub(crate) cstore: Lrc<CStore>, pub(crate) crate_name: Option<String>, + pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>, } impl Compiler { @@ -60,6 +66,58 @@ impl Compiler { } } +/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. +pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> { + struct NullEmitter; + impl Emitter for NullEmitter { + fn emit_diagnostic(&mut self, _: &Diagnostic) {} + fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> { None } + } + + syntax::with_default_globals(move || { + let cfg = cfgspecs.into_iter().map(|s| { + + let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let handler = Handler::with_emitter(false, None, Box::new(NullEmitter)); + let sess = ParseSess::with_span_handler(handler, cm); + let filename = FileName::cfg_spec_source_code(&s); + let mut parser = parse::new_parser_from_source_str(&sess, filename, s.to_string()); + + macro_rules! error {($reason: expr) => { + early_error(ErrorOutputType::default(), + &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s)); + }} + + match &mut parser.parse_meta_item() { + Ok(meta_item) if parser.token == token::Eof => { + if meta_item.path.segments.len() != 1 { + error!("argument key must be an identifier"); + } + match &meta_item.kind { + MetaItemKind::List(..) => { + error!(r#"expected `key` or `key="value"`"#); + } + MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { + error!("argument value must be a string"); + } + MetaItemKind::NameValue(..) | MetaItemKind::Word => { + let ident = meta_item.ident().expect("multi-segment cfg key"); + return (ident.name, meta_item.value_str()); + } + } + } + Ok(..) => {} + Err(err) => err.cancel(), + } + + error!(r#"expected `key` or `key="value"`"#); + }).collect::<ast::CrateConfig>(); + cfg.into_iter().map(|(a, b)| { + (a.to_string(), b.map(|b| b.to_string())) + }).collect() + }) +} + /// The compiler configuration pub struct Config { /// Command line options @@ -80,6 +138,13 @@ pub struct Config { pub crate_name: Option<String>, pub lint_caps: FxHashMap<lint::LintId, lint::Level>, + + /// This is a callback from the driver that is called when we're registering lints; + /// it is called during plugin registration when we have the LintStore in a non-shared state. + /// + /// Note that if you find a Some here you probably want to call that function in the new + /// function being registered. + pub register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>, } pub fn run_compiler_in_existing_thread_pool<F, R>(config: Config, f: F) -> R @@ -108,6 +173,7 @@ where output_file: config.output_file, queries: Default::default(), crate_name: config.crate_name, + register_lints: config.register_lints, }; let _sess_abort_error = OnDrop(|| { diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs index 6be36e9b900..53baf6556fb 100644 --- a/src/librustc_interface/lib.rs +++ b/src/librustc_interface/lib.rs @@ -18,3 +18,6 @@ pub mod util; mod proc_macro_decls; pub use interface::{run_compiler, Config}; + +#[cfg(test)] +mod tests; diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 89de5714695..2044b73db8a 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -117,6 +117,7 @@ declare_box_region_type!( /// Returns `None` if we're aborting after handling -W help. pub fn configure_and_expand( sess: Lrc<Session>, + lint_store: Lrc<lint::LintStore>, cstore: Lrc<CStore>, krate: ast::Crate, crate_name: &str, @@ -134,6 +135,7 @@ pub fn configure_and_expand( let resolver_arenas = Resolver::arenas(); let res = configure_and_expand_inner( sess, + &lint_store, &*cstore, krate, &crate_name, @@ -225,9 +227,10 @@ pub struct PluginInfo { pub fn register_plugins<'a>( sess: &'a Session, cstore: &'a CStore, + register_lints: impl Fn(&Session, &mut lint::LintStore), mut krate: ast::Crate, crate_name: &str, -) -> Result<(ast::Crate, PluginInfo)> { +) -> Result<(ast::Crate, PluginInfo, Lrc<lint::LintStore>)> { krate = time(sess, "attributes injection", || { syntax_ext::cmdline_attrs::inject( krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr @@ -278,7 +281,14 @@ pub fn register_plugins<'a>( ) }); - let mut registry = Registry::new(sess, krate.span); + let mut lint_store = rustc_lint::new_lint_store( + sess.opts.debugging_opts.no_interleave_lints, + sess.unstable_options(), + ); + + (register_lints)(&sess, &mut lint_store); + + let mut registry = Registry::new(sess, &mut lint_store, krate.span); time(sess, "plugin registration", || { for registrar in registrars { @@ -289,34 +299,20 @@ pub fn register_plugins<'a>( let Registry { syntax_exts, - early_lint_passes, - late_lint_passes, - lint_groups, llvm_passes, attributes, .. } = registry; - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, false, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, false, false, pass); - } - - for (name, (to, deprecated_name)) in lint_groups { - ls.register_group(Some(sess), true, name, deprecated_name, to); - } - *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; *sess.plugin_attributes.borrow_mut() = attributes; - Ok((krate, PluginInfo { syntax_exts })) + Ok((krate, PluginInfo { syntax_exts }, Lrc::new(lint_store))) } fn configure_and_expand_inner<'a>( sess: &'a Session, + lint_store: &'a lint::LintStore, cstore: &'a CStore, mut krate: ast::Crate, crate_name: &str, @@ -327,6 +323,7 @@ fn configure_and_expand_inner<'a>( time(sess, "pre-AST-expansion lint checks", || { lint::check_ast_crate( sess, + lint_store, &krate, true, rustc_lint::BuiltinCombinedPreExpansionLintPass::new()); @@ -536,6 +533,7 @@ fn configure_and_expand_inner<'a>( pub fn lower_to_hir( sess: &Session, + lint_store: &lint::LintStore, cstore: &CStore, resolver: &mut Resolver<'_>, dep_graph: &DepGraph, @@ -554,7 +552,13 @@ pub fn lower_to_hir( }); time(sess, "early lint checks", || { - lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new()) + lint::check_ast_crate( + sess, + lint_store, + &krate, + false, + rustc_lint::BuiltinCombinedEarlyLintPass::new(), + ) }); // Discard hygiene data, which isn't required after lowering to HIR. @@ -817,6 +821,7 @@ impl BoxedGlobalCtxt { pub fn create_global_ctxt( compiler: &Compiler, + lint_store: Lrc<lint::LintStore>, mut hir_forest: hir::map::Forest, defs: hir::map::Definitions, resolutions: Resolutions, @@ -854,6 +859,7 @@ pub fn create_global_ctxt( let gcx = TyCtxt::create_global_ctxt( sess, + lint_store, cstore, local_providers, extern_providers, diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index cd72dc9453c..84648ca8326 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -2,9 +2,13 @@ use crate::interface::{Compiler, Result}; use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo}; use rustc_incremental::DepGraphFuture; +use rustc_data_structures::sync::Lrc; use rustc::session::config::{OutputFilenames, OutputType}; use rustc::util::common::{time, ErrorReported}; use rustc::hir; +use rustc::lint; +use rustc::session::Session; +use rustc::lint::LintStore; use rustc::hir::def_id::LOCAL_CRATE; use rustc::ty::steal::Steal; use rustc::dep_graph::DepGraph; @@ -74,8 +78,8 @@ pub(crate) struct Queries { dep_graph_future: Query<Option<DepGraphFuture>>, parse: Query<ast::Crate>, crate_name: Query<String>, - register_plugins: Query<(ast::Crate, PluginInfo)>, - expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>)>, + register_plugins: Query<(ast::Crate, PluginInfo, Lrc<LintStore>)>, + expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>, dep_graph: Query<DepGraph>, lower_to_hir: Query<(Steal<hir::map::Forest>, ExpansionResult)>, prepare_outputs: Query<OutputFilenames>, @@ -106,14 +110,19 @@ impl Compiler { }) } - pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> { + pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo, Lrc<LintStore>)>> { self.queries.register_plugins.compute(|| { let crate_name = self.crate_name()?.peek().clone(); let krate = self.parse()?.take(); + let empty: &(dyn Fn(&Session, &mut lint::LintStore) + Sync + Send) = &|_, _| {}; let result = passes::register_plugins( self.session(), self.cstore(), + self.register_lints + .as_ref() + .map(|p| &**p) + .unwrap_or_else(|| empty), krate, &crate_name, ); @@ -148,17 +157,20 @@ impl Compiler { pub fn expansion( &self - ) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>)>> { + ) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> { self.queries.expansion.compute(|| { let crate_name = self.crate_name()?.peek().clone(); - let (krate, plugin_info) = self.register_plugins()?.take(); + let (krate, plugin_info, lint_store) = self.register_plugins()?.take(); passes::configure_and_expand( self.sess.clone(), + lint_store.clone(), self.cstore().clone(), krate, &crate_name, plugin_info, - ).map(|(krate, resolver)| (krate, Steal::new(Rc::new(RefCell::new(resolver))))) + ).map(|(krate, resolver)| { + (krate, Steal::new(Rc::new(RefCell::new(resolver))), lint_store) + }) }) } @@ -185,9 +197,11 @@ impl Compiler { let peeked = expansion_result.peek(); let krate = &peeked.0; let resolver = peeked.1.steal(); + let lint_store = &peeked.2; let hir = Steal::new(resolver.borrow_mut().access(|resolver| { passes::lower_to_hir( self.session(), + lint_store, self.cstore(), resolver, &*self.dep_graph()?.peek(), @@ -212,11 +226,13 @@ impl Compiler { self.queries.global_ctxt.compute(|| { let crate_name = self.crate_name()?.peek().clone(); let outputs = self.prepare_outputs()?.peek().clone(); + let lint_store = self.expansion()?.peek().2.clone(); let hir = self.lower_to_hir()?; let hir = hir.peek(); let (ref hir_forest, ref expansion) = *hir; Ok(passes::create_global_ctxt( self, + lint_store, hir_forest.steal(), expansion.defs.steal(), expansion.resolutions.steal(), diff --git a/src/librustc/session/config/tests.rs b/src/librustc_interface/tests.rs index 061bbdc307f..7a57605da58 100644 --- a/src/librustc/session/config/tests.rs +++ b/src/librustc_interface/tests.rs @@ -1,25 +1,24 @@ -use getopts; -use crate::lint; -use crate::middle::cstore; -use crate::session::config::{ - build_configuration, - build_session_options, - to_crate_config, - parse_cfgspecs, -}; -use crate::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry}; -use crate::session::build_session; -use crate::session::search_paths::SearchPath; +extern crate getopts; + +use crate::interface::parse_cfgspecs; + +use rustc::lint; +use rustc::middle::cstore; +use rustc::session::config::{build_configuration, build_session_options, to_crate_config}; +use rustc::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry}; +use rustc::session::config::{Externs, OutputType, OutputTypes, SymbolManglingVersion}; +use rustc::session::config::{rustc_optgroups, Options, ErrorOutputType, Passes}; +use rustc::session::build_session; +use rustc::session::search_paths::SearchPath; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; use std::path::PathBuf; -use super::{Externs, OutputType, OutputTypes, SymbolManglingVersion}; use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel}; use syntax::symbol::sym; use syntax::edition::{Edition, DEFAULT_EDITION}; use syntax; -use super::Options; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{ColorConfig, emitter::HumanReadableErrorType, registry}; pub fn build_session_options_and_crate_config( matches: &getopts::Matches, @@ -30,22 +29,23 @@ pub fn build_session_options_and_crate_config( ) } -impl ExternEntry { - fn new_public<S: Into<String>, - I: IntoIterator<Item = Option<S>>>(locations: I) -> ExternEntry { - let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into())) - .collect(); - - ExternEntry { - locations, - is_private_dep: false - } +fn new_public_extern_entry<S, I>(locations: I) -> ExternEntry +where + S: Into<String>, + I: IntoIterator<Item = Option<S>>, +{ + let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into())) + .collect(); + + ExternEntry { + locations, + is_private_dep: false } } fn optgroups() -> getopts::Options { let mut opts = getopts::Options::new(); - for group in super::rustc_optgroups() { + for group in rustc_optgroups() { (group.apply)(&mut opts); } return opts; @@ -63,7 +63,7 @@ fn test_switch_implies_cfg_test() { Ok(m) => m, Err(f) => panic!("test_switch_implies_cfg_test: {}", f), }; - let registry = errors::registry::Registry::new(&[]); + let registry = registry::Registry::new(&[]); let (sessopts, cfg) = build_session_options_and_crate_config(matches); let sess = build_session(sessopts, None, registry); let cfg = build_configuration(&sess, to_crate_config(cfg)); @@ -81,7 +81,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() { Ok(m) => m, Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f), }; - let registry = errors::registry::Registry::new(&[]); + let registry = registry::Registry::new(&[]); let (sessopts, cfg) = build_session_options_and_crate_config(matches); let sess = build_session(sessopts, None, registry); let cfg = build_configuration(&sess, to_crate_config(cfg)); @@ -95,7 +95,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() { fn test_can_print_warnings() { syntax::with_default_globals(|| { let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap(); - let registry = errors::registry::Registry::new(&[]); + let registry = registry::Registry::new(&[]); let (sessopts, _) = build_session_options_and_crate_config(&matches); let sess = build_session(sessopts, None, registry); assert!(!sess.diagnostic().can_emit_warnings()); @@ -105,7 +105,7 @@ fn test_can_print_warnings() { let matches = optgroups() .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]) .unwrap(); - let registry = errors::registry::Registry::new(&[]); + let registry = registry::Registry::new(&[]); let (sessopts, _) = build_session_options_and_crate_config(&matches); let sess = build_session(sessopts, None, registry); assert!(sess.diagnostic().can_emit_warnings()); @@ -113,7 +113,7 @@ fn test_can_print_warnings() { syntax::with_default_globals(|| { let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap(); - let registry = errors::registry::Registry::new(&[]); + let registry = registry::Registry::new(&[]); let (sessopts, _) = build_session_options_and_crate_config(&matches); let sess = build_session(sessopts, None, registry); assert!(sess.diagnostic().can_emit_warnings()); @@ -172,33 +172,33 @@ fn test_externs_tracking_hash_different_construction_order() { v1.externs = Externs::new(mk_map(vec![ ( String::from("a"), - ExternEntry::new_public(vec![Some("b"), Some("c")]) + new_public_extern_entry(vec![Some("b"), Some("c")]) ), ( String::from("d"), - ExternEntry::new_public(vec![Some("e"), Some("f")]) + new_public_extern_entry(vec![Some("e"), Some("f")]) ), ])); v2.externs = Externs::new(mk_map(vec![ ( String::from("d"), - ExternEntry::new_public(vec![Some("e"), Some("f")]) + new_public_extern_entry(vec![Some("e"), Some("f")]) ), ( String::from("a"), - ExternEntry::new_public(vec![Some("b"), Some("c")]) + new_public_extern_entry(vec![Some("b"), Some("c")]) ), ])); v3.externs = Externs::new(mk_map(vec![ ( String::from("a"), - ExternEntry::new_public(vec![Some("b"), Some("c")]) + new_public_extern_entry(vec![Some("b"), Some("c")]) ), ( String::from("d"), - ExternEntry::new_public(vec![Some("f"), Some("e")]) + new_public_extern_entry(vec![Some("f"), Some("e")]) ), ])); @@ -282,9 +282,9 @@ fn test_search_paths_tracking_hash_different_order() { let mut v3 = Options::default(); let mut v4 = Options::default(); - const JSON: super::ErrorOutputType = super::ErrorOutputType::Json { + const JSON: ErrorOutputType = ErrorOutputType::Json { pretty: false, - json_rendered: super::HumanReadableErrorType::Default(super::ColorConfig::Never), + json_rendered: HumanReadableErrorType::Default(ColorConfig::Never), }; // Reference @@ -455,7 +455,7 @@ fn test_codegen_options_tracking_hash() { opts.cg.codegen_units = Some(42); assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.cg.remark = super::Passes::Some(vec![String::from("pass1"), String::from("pass2")]); + opts.cg.remark = Passes::Some(vec![String::from("pass1"), String::from("pass2")]); assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.cg.save_temps = true; diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 0c272f0c456..8f11dc93727 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -13,7 +13,6 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_errors::registry::Registry; -use rustc_lint; use rustc_metadata::dynamic_lib::DynamicLibrary; use rustc_mir; use rustc_passes; @@ -108,11 +107,6 @@ pub fn create_session( let codegen_backend = get_codegen_backend(&sess); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - if sess.unstable_options() { - rustc_lint::register_internals(&mut sess.lint_store.borrow_mut(), Some(&sess)); - } - let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); add_configuration(&mut cfg, &sess, &*codegen_backend); sess.parse_sess.config = cfg; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 08f6f43ab0c..ad674911e6f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -27,6 +27,7 @@ use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::ty::{self, Ty, TyCtxt, layout::VariantIdx}; use rustc::{lint, util}; +use rustc::lint::FutureIncompatibleInfo; use hir::Node; use util::nodemap::HirIdSet; use lint::{LateContext, LintContext, LintArray}; @@ -280,7 +281,7 @@ declare_lint! { pub MISSING_DOCS, Allow, "detects missing documentation for public members", - report_in_external_macro: true + report_in_external_macro } pub struct MissingDoc { @@ -601,7 +602,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { declare_lint! { pub ANONYMOUS_PARAMETERS, Allow, - "detects anonymous parameters" + "detects anonymous parameters", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>", + edition: Some(Edition::Edition2018), + }; } declare_lint_pass!( @@ -981,35 +986,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures { } declare_lint! { - UNIONS_WITH_DROP_FIELDS, - Warn, - "use of unions that contain fields with possibly non-trivial drop code" -} - -declare_lint_pass!( - /// Lint for unions that contain fields with possibly non-trivial destructors. - UnionsWithDropFields => [UNIONS_WITH_DROP_FIELDS] -); - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { - fn check_item(&mut self, ctx: &LateContext<'_, '_>, item: &hir::Item) { - if let hir::ItemKind::Union(ref vdata, _) = item.kind { - for field in vdata.fields() { - let field_ty = ctx.tcx.type_of( - ctx.tcx.hir().local_def_id(field.hir_id)); - if field_ty.needs_drop(ctx.tcx, ctx.param_env) { - ctx.span_lint(UNIONS_WITH_DROP_FIELDS, - field.span, - "union contains a field with possibly non-trivial drop code, \ - drop code of union fields is ignored when dropping the union"); - return; - } - } - } - } -} - -declare_lint! { pub UNREACHABLE_PUB, Allow, "`pub` items not reachable from crate root" @@ -1288,7 +1264,6 @@ declare_lint_pass!( NO_MANGLE_GENERIC_ITEMS, MUTABLE_TRANSMUTES, UNSTABLE_FEATURES, - UNIONS_WITH_DROP_FIELDS, UNREACHABLE_PUB, TYPE_ALIAS_BOUNDS, TRIVIAL_BOUNDS @@ -1374,7 +1349,7 @@ declare_lint! { UNNAMEABLE_TEST_ITEMS, Warn, "detects an item that cannot be named being marked as `#[test_case]`", - report_in_external_macro: true + report_in_external_macro } pub struct UnnameableTestItems { @@ -1423,7 +1398,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems { declare_lint! { pub KEYWORD_IDENTS, Allow, - "detects edition keywords being used as an identifier" + "detects edition keywords being used as an identifier", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>", + edition: Some(Edition::Edition2018), + }; } declare_lint_pass!( diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index e3860e229d6..b1beef04c59 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -33,27 +33,21 @@ use rustc::lint; use rustc::lint::{EarlyContext, LateContext, LateLintPass, EarlyLintPass, LintPass, LintArray}; use rustc::lint::builtin::{ BARE_TRAIT_OBJECTS, - ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS, INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, - parser::ILL_FORMED_ATTRIBUTE_INPUT, }; -use rustc::session; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; use syntax::ast; -use syntax::edition::Edition; use syntax_pos::Span; -use session::Session; use lint::LintId; -use lint::FutureIncompatibleInfo; use redundant_semicolon::*; use nonstandard_style::*; @@ -164,9 +158,6 @@ macro_rules! late_lint_mod_passes { // Depends on referenced function signatures in expressions MutableTransmutes: MutableTransmutes, - // Depends on types of fields, checks if they implement Drop - UnionsWithDropFields: UnionsWithDropFields, - TypeAliasBounds: TypeAliasBounds, TrivialConstraints: TrivialConstraints, @@ -195,59 +186,60 @@ late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass]) late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]); +pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::LintStore { + let mut lint_store = lint::LintStore::new(); + + register_builtins(&mut lint_store, no_interleave_lints); + if internal_lints { + register_internals(&mut lint_store); + } + + lint_store +} + /// Tell the `LintStore` about all the built-in lints (the ones /// defined in this crate and the ones defined in /// `rustc::lint::builtin`). -pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { +fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) { macro_rules! add_lint_group { - ($sess:ident, $name:expr, $($lint:ident),*) => ( - store.register_group($sess, false, $name, None, vec![$(LintId::of($lint)),*]); + ($name:expr, $($lint:ident),*) => ( + store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]); ) } macro_rules! register_pass { - ($method:ident, $constructor:expr, [$($args:expr),*]) => ( - store.$method(sess, false, false, $($args,)* box $constructor); + ($method:ident, $ty:ident, $constructor:expr) => ( + store.register_lints(&$ty::get_lints()); + store.$method(|| box $constructor); ) } macro_rules! register_passes { - ([$method:ident, $args:tt], [$($passes:ident: $constructor:expr,)*]) => ( + ($method:ident, [$($passes:ident: $constructor:expr,)*]) => ( $( - register_pass!($method, $constructor, $args); + register_pass!($method, $passes, $constructor); )* ) } - if sess.map(|sess| sess.opts.debugging_opts.no_interleave_lints).unwrap_or(false) { - pre_expansion_lint_passes!(register_passes, [register_pre_expansion_pass, []]); - early_lint_passes!(register_passes, [register_early_pass, []]); - late_lint_passes!(register_passes, [register_late_pass, [false]]); - late_lint_mod_passes!(register_passes, [register_late_pass, [true]]); + if no_interleave_lints { + pre_expansion_lint_passes!(register_passes, register_pre_expansion_pass); + early_lint_passes!(register_passes, register_early_pass); + late_lint_passes!(register_passes, register_late_pass); + late_lint_mod_passes!(register_passes, register_late_mod_pass); } else { - store.register_pre_expansion_pass( - sess, - false, - true, - box BuiltinCombinedPreExpansionLintPass::new() - ); - store.register_early_pass(sess, false, true, box BuiltinCombinedEarlyLintPass::new()); - store.register_late_pass( - sess, false, true, true, box BuiltinCombinedModuleLateLintPass::new() - ); - store.register_late_pass( - sess, false, true, false, box BuiltinCombinedLateLintPass::new() - ); + store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints()); + store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); + store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints()); + store.register_lints(&BuiltinCombinedLateLintPass::get_lints()); } - add_lint_group!(sess, - "nonstandard_style", + add_lint_group!("nonstandard_style", NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS); - add_lint_group!(sess, - "unused", + add_lint_group!("unused", UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, @@ -268,8 +260,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UNUSED_LABELS, UNUSED_PARENS); - add_lint_group!(sess, - "rust_2018_idioms", + add_lint_group!("rust_2018_idioms", BARE_TRAIT_OBJECTS, UNUSED_EXTERN_CRATES, ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, @@ -285,165 +276,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { // MACRO_USE_EXTERN_CRATE, ); - add_lint_group!(sess, - "rustdoc", + add_lint_group!("rustdoc", INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS); - // Guidelines for creating a future incompatibility lint: - // - // - Create a lint defaulting to warn as normal, with ideally the same error - // message you would normally give - // - Add a suitable reference, typically an RFC or tracking issue. Go ahead - // and include the full URL, sort items in ascending order of issue numbers. - // - Later, change lint to error - // - Eventually, remove lint - store.register_future_incompatible(sess, vec![ - FutureIncompatibleInfo { - id: LintId::of(PRIVATE_IN_PUBLIC), - reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(PUB_USE_OF_PRIVATE_EXTERN_CRATE), - reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY), - reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(DUPLICATE_MACRO_EXPORTS), - reference: "issue #35896 <https://github.com/rust-lang/rust/issues/35896>", - edition: Some(Edition::Edition2018), - }, - FutureIncompatibleInfo { - id: LintId::of(KEYWORD_IDENTS), - reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>", - edition: Some(Edition::Edition2018), - }, - FutureIncompatibleInfo { - id: LintId::of(SAFE_EXTERN_STATICS), - reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(INVALID_TYPE_PARAM_DEFAULT), - reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP), - reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY), - reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(MISSING_FRAGMENT_SPECIFIER), - reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN), - reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(ANONYMOUS_PARAMETERS), - reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>", - edition: Some(Edition::Edition2018), - }, - FutureIncompatibleInfo { - id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES), - reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS), - reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(SAFE_PACKED_BORROWS), - reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(ORDER_DEPENDENT_TRAIT_OBJECTS), - reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(TYVAR_BEHIND_RAW_POINTER), - reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>", - edition: Some(Edition::Edition2018), - }, - FutureIncompatibleInfo { - id: LintId::of(UNSTABLE_NAME_COLLISIONS), - reference: "issue #48919 <https://github.com/rust-lang/rust/issues/48919>", - edition: None, - // Note: this item represents future incompatibility of all unstable functions in the - // standard library, and thus should never be removed or changed to an error. - }, - FutureIncompatibleInfo { - id: LintId::of(ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE), - reference: "issue #53130 <https://github.com/rust-lang/rust/issues/53130>", - edition: Some(Edition::Edition2018), - }, - FutureIncompatibleInfo { - id: LintId::of(WHERE_CLAUSES_OBJECT_SAFETY), - reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(PROC_MACRO_DERIVE_RESOLUTION_FALLBACK), - reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS), - reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(ILL_FORMED_ATTRIBUTE_INPUT), - reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(AMBIGUOUS_ASSOCIATED_ITEMS), - reference: "issue #57644 <https://github.com/rust-lang/rust/issues/57644>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(NESTED_IMPL_TRAIT), - reference: "issue #59014 <https://github.com/rust-lang/rust/issues/59014>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(MUTABLE_BORROW_RESERVATION_CONFLICT), - reference: "issue #59159 <https://github.com/rust-lang/rust/issues/59159>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(INDIRECT_STRUCTURAL_MATCH), - reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>", - edition: None, - }, - FutureIncompatibleInfo { - id: LintId::of(SOFT_UNSTABLE), - reference: "issue #64266 <https://github.com/rust-lang/rust/issues/64266>", - edition: None, - }, - ]); - // Register renamed and removed lints. store.register_renamed("single_use_lifetime", "single_use_lifetimes"); store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths"); @@ -499,12 +336,14 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { "converted into hard error, see https://github.com/rust-lang/rust/issues/46205"); } -pub fn register_internals(store: &mut lint::LintStore, sess: Option<&Session>) { - store.register_early_pass(sess, false, false, box DefaultHashTypes::new()); - store.register_early_pass(sess, false, false, box LintPassImpl); - store.register_late_pass(sess, false, false, false, box TyTyKind); +fn register_internals(store: &mut lint::LintStore) { + store.register_lints(&DefaultHashTypes::get_lints()); + store.register_early_pass(|| box DefaultHashTypes::new()); + store.register_lints(&LintPassImpl::get_lints()); + store.register_early_pass(|| box LintPassImpl); + store.register_lints(&TyTyKind::get_lints()); + store.register_late_pass(|| box TyTyKind); store.register_group( - sess, false, "rustc::internal", None, diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index a93946df68f..61b8cbe369a 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -25,7 +25,7 @@ declare_lint! { pub UNUSED_MUST_USE, Warn, "unused result of a type flagged as `#[must_use]`", - report_in_external_macro: true + report_in_external_macro } declare_lint! { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 6a2da5d4988..7412e8a2cb9 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -738,10 +738,10 @@ impl<'a> CrateLoader<'a> { if !self.sess.crate_types.borrow().iter().all(|ct| { match *ct { // Link the runtime - config::CrateType::Staticlib | config::CrateType::Executable => true, // This crate will be compiled with the required // instrumentation pass + config::CrateType::Staticlib | config::CrateType::Rlib | config::CrateType::Dylib | config::CrateType::Cdylib => diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index c9851694d44..8c52168b418 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -448,7 +448,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Mod(_) => DefKind::Mod, EntryKind::Variant(_) => DefKind::Variant, EntryKind::Trait(_) => DefKind::Trait, - EntryKind::TraitAlias(_) => DefKind::TraitAlias, + EntryKind::TraitAlias => DefKind::TraitAlias, EntryKind::Enum(..) => DefKind::Enum, EntryKind::MacroDef(_) => DefKind::Macro(MacroKind::Bang), EntryKind::ForeignType => DefKind::ForeignTy, @@ -458,7 +458,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Impl(_) | EntryKind::Field | EntryKind::Generator(_) | - EntryKind::Closure(_) => return None, + EntryKind::Closure => return None, }) } } @@ -574,7 +574,7 @@ impl<'a, 'tcx> CrateMetadata { data.is_marker, self.def_path_table.def_path_hash(item_id)) }, - EntryKind::TraitAlias(_) => { + EntryKind::TraitAlias => { ty::TraitDef::new(self.local_def_id(item_id), hir::Unsafety::Normal, false, @@ -679,13 +679,7 @@ impl<'a, 'tcx> CrateMetadata { item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> ty::GenericPredicates<'tcx> { - let super_predicates = match self.kind(item_id) { - EntryKind::Trait(data) => data.decode(self).super_predicates, - EntryKind::TraitAlias(data) => data.decode(self).super_predicates, - _ => bug!("def-index does not refer to trait or trait alias"), - }; - - super_predicates.decode((self, tcx)) + self.root.per_def.super_predicates.get(self, item_id).unwrap().decode((self, tcx)) } crate fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics { @@ -716,7 +710,7 @@ impl<'a, 'tcx> CrateMetadata { } } - fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> { + fn get_impl_data(&self, id: DefIndex) -> ImplData { match self.kind(id) { EntryKind::Impl(data) => data.decode(self), _ => bug!(), @@ -743,7 +737,7 @@ impl<'a, 'tcx> CrateMetadata { } crate fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> { - self.get_impl_data(id).trait_ref.map(|tr| tr.decode((self, tcx))) + self.root.per_def.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx))) } /// Iterates over all the stability attributes in the given crate. @@ -1117,7 +1111,7 @@ impl<'a, 'tcx> CrateMetadata { def_key.parent.and_then(|parent_index| { match self.kind(parent_index) { EntryKind::Trait(_) | - EntryKind::TraitAlias(_) => Some(self.local_def_id(parent_index)), + EntryKind::TraitAlias => Some(self.local_def_id(parent_index)), _ => None, } }) @@ -1244,16 +1238,7 @@ impl<'a, 'tcx> CrateMetadata { } crate fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { - let sig = match self.kind(id) { - EntryKind::Fn(data) | - EntryKind::ForeignFn(data) => data.decode(self).sig, - EntryKind::Method(data) => data.decode(self).fn_data.sig, - EntryKind::Variant(data) | - EntryKind::Struct(data, _) => data.decode(self).ctor_sig.unwrap(), - EntryKind::Closure(data) => data.decode(self).sig, - _ => bug!(), - }; - sig.decode((self, tcx)) + self.root.per_def.fn_sig.get(self, id).unwrap().decode((self, tcx)) } #[inline] diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 6ae8c2fc6c6..0dc9f91ae00 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -71,11 +71,14 @@ struct PerDefTables<'tcx> { deprecation: PerDefTable<Lazy<attr::Deprecation>>, ty: PerDefTable<Lazy<Ty<'tcx>>>, + fn_sig: PerDefTable<Lazy<ty::PolyFnSig<'tcx>>>, + impl_trait_ref: PerDefTable<Lazy<ty::TraitRef<'tcx>>>, inherent_impls: PerDefTable<Lazy<[DefIndex]>>, variances: PerDefTable<Lazy<[ty::Variance]>>, generics: PerDefTable<Lazy<ty::Generics>>, predicates: PerDefTable<Lazy<ty::GenericPredicates<'tcx>>>, predicates_defined_on: PerDefTable<Lazy<ty::GenericPredicates<'tcx>>>, + super_predicates: PerDefTable<Lazy<ty::GenericPredicates<'tcx>>>, mir: PerDefTable<Lazy<mir::Body<'tcx>>>, promoted_mir: PerDefTable<Lazy<IndexVec<mir::Promoted, mir::Body<'tcx>>>>, @@ -508,11 +511,14 @@ impl<'tcx> EncodeContext<'tcx> { deprecation: self.per_def.deprecation.encode(&mut self.opaque), ty: self.per_def.ty.encode(&mut self.opaque), + fn_sig: self.per_def.fn_sig.encode(&mut self.opaque), + impl_trait_ref: self.per_def.impl_trait_ref.encode(&mut self.opaque), inherent_impls: self.per_def.inherent_impls.encode(&mut self.opaque), variances: self.per_def.variances.encode(&mut self.opaque), generics: self.per_def.generics.encode(&mut self.opaque), predicates: self.per_def.predicates.encode(&mut self.opaque), predicates_defined_on: self.per_def.predicates_defined_on.encode(&mut self.opaque), + super_predicates: self.per_def.super_predicates.encode(&mut self.opaque), mir: self.per_def.mir.encode(&mut self.opaque), promoted_mir: self.per_def.promoted_mir.encode(&mut self.opaque), @@ -635,13 +641,7 @@ impl EncodeContext<'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - // FIXME(eddyb) deduplicate these with `encode_enum_variant_ctor`. ctor: variant.ctor_def_id.map(|did| did.index), - ctor_sig: if variant.ctor_kind == CtorKind::Fn { - variant.ctor_def_id.map(|ctor_def_id| self.lazy(&tcx.fn_sig(ctor_def_id))) - } else { - None - }, }; let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap(); @@ -660,6 +660,11 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { + // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`. + if let Some(ctor_def_id) = variant.ctor_def_id { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(ctor_def_id)); + } + // FIXME(eddyb) is this ever used? self.encode_variances_of(def_id); } self.encode_generics(def_id); @@ -679,15 +684,11 @@ impl EncodeContext<'tcx> { let def_id = variant.ctor_def_id.unwrap(); debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id); + // FIXME(eddyb) encode only the `CtorKind` for constructors. let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor: Some(def_id.index), - ctor_sig: if variant.ctor_kind == CtorKind::Fn { - Some(self.lazy(tcx.fn_sig(def_id))) - } else { - None - } }; // Variant constructors have the same visibility as the parent enums, unless marked as @@ -706,6 +707,7 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); } self.encode_generics(def_id); @@ -780,11 +782,6 @@ impl EncodeContext<'tcx> { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor: Some(def_id.index), - ctor_sig: if variant.ctor_kind == CtorKind::Fn { - Some(self.lazy(tcx.fn_sig(def_id))) - } else { - None - } }; let struct_id = tcx.hir().as_local_hir_id(adt_def_id).unwrap(); @@ -811,6 +808,7 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); } self.encode_generics(def_id); @@ -835,6 +833,11 @@ impl EncodeContext<'tcx> { self.tcx.predicates_defined_on(def_id)) } + fn encode_super_predicates(&mut self, def_id: DefId) { + debug!("EncodeContext::encode_super_predicates({:?})", def_id); + record!(self.per_def.super_predicates[def_id] <- self.tcx.super_predicates_of(def_id)); + } + fn encode_info_for_trait_item(&mut self, def_id: DefId) { debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id); let tcx = self.tcx; @@ -874,7 +877,6 @@ impl EncodeContext<'tcx> { asyncness: m_sig.header.asyncness, constness: hir::Constness::NotConst, param_names, - sig: self.lazy(tcx.fn_sig(def_id)), } } else { bug!() @@ -906,6 +908,7 @@ impl EncodeContext<'tcx> { ty::AssocKind::OpaqueTy => unreachable!(), } if trait_item.kind == ty::AssocKind::Method { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); } self.encode_generics(def_id); @@ -952,7 +955,6 @@ impl EncodeContext<'tcx> { asyncness: sig.header.asyncness, constness: sig.header.constness, param_names: self.encode_fn_param_names_for_body(body), - sig: self.lazy(tcx.fn_sig(def_id)), } } else { bug!() @@ -973,6 +975,7 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); self.encode_item_type(def_id); if impl_item.kind == ty::AssocKind::Method { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); } self.encode_generics(def_id); @@ -1081,7 +1084,6 @@ impl EncodeContext<'tcx> { asyncness: header.asyncness, constness: header.constness, param_names: self.encode_fn_param_names_for_body(body), - sig: self.lazy(tcx.fn_sig(def_id)), }; EntryKind::Fn(self.lazy(data)) @@ -1109,7 +1111,6 @@ impl EncodeContext<'tcx> { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor, - ctor_sig: None, }), adt_def.repr) } hir::ItemKind::Union(..) => { @@ -1120,7 +1121,6 @@ impl EncodeContext<'tcx> { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor: None, - ctor_sig: None, }), adt_def.repr) } hir::ItemKind::Impl(_, _, defaultness, ..) => { @@ -1154,7 +1154,6 @@ impl EncodeContext<'tcx> { defaultness, parent_impl: parent, coerce_unsized_info, - trait_ref: trait_ref.map(|trait_ref| self.lazy(trait_ref)), }; EntryKind::Impl(self.lazy(data)) @@ -1166,18 +1165,11 @@ impl EncodeContext<'tcx> { paren_sugar: trait_def.paren_sugar, has_auto_impl: self.tcx.trait_is_auto(def_id), is_marker: trait_def.is_marker, - super_predicates: self.lazy(tcx.super_predicates_of(def_id)), }; EntryKind::Trait(self.lazy(data)) } - hir::ItemKind::TraitAlias(..) => { - let data = TraitAliasData { - super_predicates: self.lazy(tcx.super_predicates_of(def_id)), - }; - - EntryKind::TraitAlias(self.lazy(data)) - } + hir::ItemKind::TraitAlias(..) => EntryKind::TraitAlias, hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item), }); @@ -1232,6 +1224,14 @@ impl EncodeContext<'tcx> { hir::ItemKind::Impl(..) => self.encode_item_type(def_id), _ => {} } + if let hir::ItemKind::Fn(..) = item.kind { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); + } + if let hir::ItemKind::Impl(..) = item.kind { + if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { + record!(self.per_def.impl_trait_ref[def_id] <- trait_ref); + } + } self.encode_inherent_implementations(def_id); match item.kind { hir::ItemKind::Enum(..) | @@ -1269,6 +1269,13 @@ impl EncodeContext<'tcx> { } _ => {} // not *wrong* for other kinds of items, but not needed } + match item.kind { + hir::ItemKind::Trait(..) | + hir::ItemKind::TraitAlias(..) => { + self.encode_super_predicates(def_id); + } + _ => {} + } let mir = match item.kind { hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true, @@ -1321,10 +1328,12 @@ impl EncodeContext<'tcx> { fn encode_info_for_closure(&mut self, def_id: DefId) { debug!("EncodeContext::encode_info_for_closure({:?})", def_id); - let tables = self.tcx.typeck_tables_of(def_id); + // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic, + // including on the signature, which is inferred in `typeck_tables_of. let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap(); + let ty = self.tcx.typeck_tables_of(def_id).node_type(hir_id); - record!(self.per_def.kind[def_id] <- match tables.node_type(hir_id).kind { + record!(self.per_def.kind[def_id] <- match ty.kind { ty::Generator(def_id, ..) => { let layout = self.tcx.generator_layout(def_id); let data = GeneratorData { @@ -1333,11 +1342,7 @@ impl EncodeContext<'tcx> { EntryKind::Generator(self.lazy(data)) } - ty::Closure(def_id, substs) => { - let sig = substs.as_closure().sig(def_id, self.tcx); - let data = ClosureData { sig: self.lazy(sig) }; - EntryKind::Closure(self.lazy(data)) - } + ty::Closure(..) => EntryKind::Closure, _ => bug!("closure that is neither generator nor closure"), }); @@ -1345,6 +1350,9 @@ impl EncodeContext<'tcx> { record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id)); record!(self.per_def.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]); self.encode_item_type(def_id); + if let ty::Closure(def_id, substs) = ty.kind { + record!(self.per_def.fn_sig[def_id] <- substs.as_closure().sig(def_id, self.tcx)); + } self.encode_generics(def_id); self.encode_optimized_mir(def_id); self.encode_promoted_mir(def_id); @@ -1553,7 +1561,6 @@ impl EncodeContext<'tcx> { asyncness: hir::IsAsync::NotAsync, constness: hir::Constness::NotConst, param_names: self.encode_fn_param_names(names), - sig: self.lazy(tcx.fn_sig(def_id)), }; EntryKind::ForeignFn(self.lazy(data)) } @@ -1569,6 +1576,7 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); self.encode_item_type(def_id); if let hir::ForeignItemKind::Fn(..) = nitem.kind { + record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); } self.encode_generics(def_id); diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index 9e4c2685f11..a58db6a903b 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -198,12 +198,10 @@ impl Collector<'tcx> { self.tcx.sess.err(&format!("renaming of the library `{}` was specified, \ however this crate contains no `#[link(...)]` \ attributes referencing this library.", name)); - } else if renames.contains(name) { + } else if !renames.insert(name) { self.tcx.sess.err(&format!("multiple renamings were \ specified for library `{}` .", name)); - } else { - renames.insert(name); } } } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 96f35783278..ad39aa34fd5 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -238,11 +238,14 @@ crate struct LazyPerDefTables<'tcx> { pub deprecation: Lazy!(PerDefTable<Lazy<attr::Deprecation>>), pub ty: Lazy!(PerDefTable<Lazy!(Ty<'tcx>)>), + pub fn_sig: Lazy!(PerDefTable<Lazy!(ty::PolyFnSig<'tcx>)>), + pub impl_trait_ref: Lazy!(PerDefTable<Lazy!(ty::TraitRef<'tcx>)>), pub inherent_impls: Lazy!(PerDefTable<Lazy<[DefIndex]>>), pub variances: Lazy!(PerDefTable<Lazy<[ty::Variance]>>), pub generics: Lazy!(PerDefTable<Lazy<ty::Generics>>), pub predicates: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>), pub predicates_defined_on: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>), + pub super_predicates: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>), pub mir: Lazy!(PerDefTable<Lazy!(mir::Body<'tcx>)>), pub promoted_mir: Lazy!(PerDefTable<Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>), @@ -264,22 +267,22 @@ crate enum EntryKind<'tcx> { OpaqueTy, Enum(ReprOptions), Field, - Variant(Lazy!(VariantData<'tcx>)), - Struct(Lazy!(VariantData<'tcx>), ReprOptions), - Union(Lazy!(VariantData<'tcx>), ReprOptions), - Fn(Lazy!(FnData<'tcx>)), - ForeignFn(Lazy!(FnData<'tcx>)), + Variant(Lazy<VariantData>), + Struct(Lazy<VariantData>, ReprOptions), + Union(Lazy<VariantData>, ReprOptions), + Fn(Lazy<FnData>), + ForeignFn(Lazy<FnData>), Mod(Lazy<ModData>), MacroDef(Lazy<MacroDef>), - Closure(Lazy!(ClosureData<'tcx>)), + Closure, Generator(Lazy!(GeneratorData<'tcx>)), - Trait(Lazy!(TraitData<'tcx>)), - Impl(Lazy!(ImplData<'tcx>)), - Method(Lazy!(MethodData<'tcx>)), + Trait(Lazy<TraitData>), + Impl(Lazy<ImplData>), + Method(Lazy<MethodData>), AssocType(AssocContainer), AssocOpaqueTy(AssocContainer), AssocConst(AssocContainer, ConstQualif, Lazy<RenderedConst>), - TraitAlias(Lazy!(TraitAliasData<'tcx>)), + TraitAlias, } /// Additional data for EntryKind::Const and EntryKind::AssocConst @@ -305,47 +308,37 @@ crate struct MacroDef { } #[derive(RustcEncodable, RustcDecodable)] -crate struct FnData<'tcx> { +crate struct FnData { pub asyncness: hir::IsAsync, pub constness: hir::Constness, pub param_names: Lazy<[ast::Name]>, - pub sig: Lazy!(ty::PolyFnSig<'tcx>), } #[derive(RustcEncodable, RustcDecodable)] -crate struct VariantData<'tcx> { +crate struct VariantData { pub ctor_kind: CtorKind, pub discr: ty::VariantDiscr, /// If this is unit or tuple-variant/struct, then this is the index of the ctor id. pub ctor: Option<DefIndex>, - /// If this is a tuple struct or variant - /// ctor, this is its "function" signature. - pub ctor_sig: Option<Lazy!(ty::PolyFnSig<'tcx>)>, } #[derive(RustcEncodable, RustcDecodable)] -crate struct TraitData<'tcx> { +crate struct TraitData { pub unsafety: hir::Unsafety, pub paren_sugar: bool, pub has_auto_impl: bool, pub is_marker: bool, - pub super_predicates: Lazy!(ty::GenericPredicates<'tcx>), } #[derive(RustcEncodable, RustcDecodable)] -crate struct TraitAliasData<'tcx> { - pub super_predicates: Lazy!(ty::GenericPredicates<'tcx>), -} - -#[derive(RustcEncodable, RustcDecodable)] -crate struct ImplData<'tcx> { +crate struct ImplData { pub polarity: ty::ImplPolarity, pub defaultness: hir::Defaultness, pub parent_impl: Option<DefId>, /// This is `Some` only for impls of `CoerceUnsized`. + // FIXME(eddyb) perhaps compute this on the fly if cheap enough? pub coerce_unsized_info: Option<ty::adjustment::CoerceUnsizedInfo>, - pub trait_ref: Option<Lazy!(ty::TraitRef<'tcx>)>, } @@ -388,18 +381,13 @@ impl AssocContainer { } #[derive(RustcEncodable, RustcDecodable)] -crate struct MethodData<'tcx> { - pub fn_data: FnData<'tcx>, +crate struct MethodData { + pub fn_data: FnData, pub container: AssocContainer, pub has_self: bool, } #[derive(RustcEncodable, RustcDecodable)] -crate struct ClosureData<'tcx> { - pub sig: Lazy!(ty::PolyFnSig<'tcx>), -} - -#[derive(RustcEncodable, RustcDecodable)] crate struct GeneratorData<'tcx> { pub layout: mir::GeneratorLayout<'tcx>, } diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 098258994f4..4c469a82ac3 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -78,7 +78,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .last() .unwrap(); - if self.uninitialized_error_reported.contains(&root_place) { + if !self.uninitialized_error_reported.insert(root_place) { debug!( "report_use_of_moved_or_uninitialized place: error about {:?} suppressed", root_place @@ -86,8 +86,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return; } - self.uninitialized_error_reported.insert(root_place); - let item_msg = match self.describe_place_with_options(used_place, IncludingDowncast(true)) { Some(name) => format!("`{}`", name), diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs index 93113753c63..8a242b7ee25 100644 --- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs +++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs @@ -71,7 +71,7 @@ impl Index<OutlivesConstraintIndex> for OutlivesConstraintSet { } } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct OutlivesConstraint { // NB. The ordering here is not significant for correctness, but // it is for convenience. Before we dump the constraints in the diff --git a/src/librustc_mir/borrow_check/nll/member_constraints.rs b/src/librustc_mir/borrow_check/nll/member_constraints.rs index fd195873a55..75213d30982 100644 --- a/src/librustc_mir/borrow_check/nll/member_constraints.rs +++ b/src/librustc_mir/borrow_check/nll/member_constraints.rs @@ -11,7 +11,7 @@ use syntax_pos::Span; /// indexed by the region `R0`. crate struct MemberConstraintSet<'tcx, R> where - R: Copy + Hash + Eq, + R: Copy + Eq, { /// Stores the first "member" constraint for a given `R0`. This is an /// index into the `constraints` vector below. @@ -191,7 +191,7 @@ where impl<'tcx, R> Index<NllMemberConstraintIndex> for MemberConstraintSet<'tcx, R> where - R: Copy + Hash + Eq, + R: Copy + Eq, { type Output = NllMemberConstraint<'tcx>; diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 6acbff76bdc..7a86536573d 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -129,7 +129,7 @@ rustc_index::newtype_index! { /// An individual element in a region value -- the value of a /// particular region variable consists of a set of these elements. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Debug)] crate enum RegionElement { /// A point in the control-flow graph. Location(Location), diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index b39aa483a6a..b876fd83ec9 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -146,7 +146,7 @@ struct UniversalRegionIndices<'tcx> { indices: FxHashMap<ty::Region<'tcx>, RegionVid>, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Debug, PartialEq)] pub enum RegionClassification { /// A **global** region is one that can be named from /// anywhere. There is only one, `'static`. diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 1d83b104177..dc6d4b27886 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -189,8 +189,8 @@ use std::ops::RangeInclusive; use std::u128; use std::convert::TryInto; -pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> &'a Pat<'tcx> { - cx.pattern_arena.alloc(LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat)) +pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> { + LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat) } struct LiteralExpander<'tcx> { diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 7bc4bf291ee..77f3768172f 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -154,7 +154,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { self.tables ); patcx.include_lint_checks(); - let pattern = expand_pattern(cx, patcx.lower_pattern(&pat)); + let pattern = + cx.pattern_arena.alloc(expand_pattern(cx, patcx.lower_pattern(&pat))) as &_; if !patcx.errors.is_empty() { patcx.report_inlining_errors(pat.span); have_errors = true; @@ -253,8 +254,9 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { patcx.include_lint_checks(); let pattern = patcx.lower_pattern(pat); let pattern_ty = pattern.ty; + let pattern = expand_pattern(cx, pattern); let pats: Matrix<'_, '_> = vec![smallvec![ - expand_pattern(cx, pattern) + &pattern ]].into_iter().collect(); let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) { diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 7e17162dfb3..58480912929 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -1214,7 +1214,7 @@ fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>, // tracks ADT's previously encountered during search, so that // we will not recur on them again. - seen: FxHashSet<&'tcx AdtDef>, + seen: FxHashSet<hir::def_id::DefId>, } impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { @@ -1254,14 +1254,12 @@ fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>, return true // Halt visiting! } - if self.seen.contains(adt_def) { + if !self.seen.insert(adt_def.did) { debug!("Search already seen adt_def: {:?}", adt_def); // let caller continue its search return false; } - self.seen.insert(adt_def); - // `#[structural_match]` does not care about the // instantiation of the generics in an ADT (it // instead looks directly at its fields outside diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 06fdd407951..d929e958f05 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -91,7 +91,7 @@ pub struct Frame<'mir, 'tcx, Tag=(), Extra=()> { pub extra: Extra, } -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Eq, PartialEq, Debug)] // Miri debug-prints these pub enum StackPopCleanup { /// Jump to the next block in the caller, or cause UB if None (that's a function /// that may never return). Also store layout of return place so @@ -113,7 +113,7 @@ pub struct LocalState<'tcx, Tag=(), Id=AllocId> { } /// Current value of a local variable -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] // Miri debug-prints these pub enum LocalValue<Tag=(), Id=AllocId> { /// This local is not currently alive, and cannot be used at all. Dead, diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 924474c5317..eef1868ec65 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -7,7 +7,7 @@ //! short-circuiting the empty case! use std::collections::VecDeque; -use std::ptr; +use std::{ptr, iter}; use std::borrow::Cow; use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt}; @@ -22,7 +22,7 @@ use super::{ Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg, }; -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +#[derive(Debug, PartialEq, Copy, Clone)] pub enum MemoryKind<T> { /// Error if deallocated except during a stack pop Stack, @@ -785,6 +785,25 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { self.get(ptr.alloc_id)?.read_c_str(self, ptr) } + /// Writes the given stream of bytes into memory. + /// + /// Performs appropriate bounds checks. + pub fn write_bytes( + &mut self, + ptr: Scalar<M::PointerTag>, + src: impl IntoIterator<Item=u8, IntoIter: iter::ExactSizeIterator>, + ) -> InterpResult<'tcx> + { + let src = src.into_iter(); + let size = Size::from_bytes(src.len() as u64); + let ptr = match self.check_ptr_access(ptr, size, Align::from_bytes(1).unwrap())? { + Some(ptr) => ptr, + None => return Ok(()), // zero-sized access + }; + let tcx = self.tcx.tcx; + self.get_mut(ptr.alloc_id)?.write_bytes(&tcx, ptr, src) + } + /// Expects the caller to have checked bounds and alignment. pub fn copy( &mut self, diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 4d9be55945e..4fd5e6a5435 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -26,7 +26,7 @@ pub use rustc::mir::interpret::ScalarMaybeUndef; /// operations and fat pointers. This idea was taken from rustc's codegen. /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely /// defined on `Immediate`, and do not have to work with a `Place`. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Immediate<Tag=(), Id=AllocId> { Scalar(ScalarMaybeUndef<Tag, Id>), ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>), @@ -123,7 +123,7 @@ impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> { /// An `Operand` is the result of computing a `mir::Operand`. It can be immediate, /// or still in memory. The latter is an optimization, to delay reading that chunk of /// memory and to avoid having to store arbitrary-sized data here. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Operand<Tag=(), Id=AllocId> { Immediate(Immediate<Tag, Id>), Indirect(MemPlace<Tag, Id>), @@ -153,7 +153,7 @@ impl<Tag> Operand<Tag> { } } -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub struct OpTy<'tcx, Tag=()> { op: Operand<Tag>, // Keep this private, it helps enforce invariants pub layout: TyLayout<'tcx>, @@ -589,8 +589,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let ptr = self.tag_static_base_pointer(Pointer::new(id, offset)); Operand::Indirect(MemPlace::from_ptr(ptr, layout.align.abi)) }, - ConstValue::Scalar(x) => - Operand::Immediate(tag_scalar(x).into()), + ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x).into()), ConstValue::Slice { data, start, end } => { // We rely on mutability being set correctly in `data` to prevent writes // where none should happen. @@ -606,6 +605,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } ConstValue::Param(..) | ConstValue::Infer(..) | + ConstValue::Bound(..) | ConstValue::Placeholder(..) | ConstValue::Unevaluated(..) => bug!("eval_const_to_op: Unexpected ConstValue {:?}", val), diff --git a/src/librustc_mir/lints.rs b/src/librustc_mir/lints.rs index da3fead1f9d..158b730b9bd 100644 --- a/src/librustc_mir/lints.rs +++ b/src/librustc_mir/lints.rs @@ -72,13 +72,11 @@ fn check_fn_for_unconditional_recursion( let caller_substs = &InternalSubsts::identity_for_item(tcx, def_id)[..trait_substs_count]; while let Some(bb) = reachable_without_self_call_queue.pop() { - if visited.contains(bb) { + if !visited.insert(bb) { //already done continue; } - visited.insert(bb); - let block = &basic_blocks[bb]; if let Some(ref terminator) = block.terminator { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index ee7452d3e8b..5e31b80bec6 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -199,7 +199,7 @@ use rustc_data_structures::sync::{MTRef, MTLock, ParallelIterator, par_iter}; use std::iter; -#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] +#[derive(PartialEq)] pub enum MonoItemCollectionMode { Eager, Lazy diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index f0c0e573443..108c6c9786b 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -431,7 +431,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { place_layout: TyLayout<'tcx>, source_info: SourceInfo, place: &Place<'tcx>, - ) -> Option<Const<'tcx>> { + ) -> Option<()> { let span = source_info.span; let overflow_check = self.tcx.sess.overflow_checks(); @@ -518,39 +518,35 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - // Work around: avoid ICE in miri. - // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref - // from a function argument that hasn't been assigned to in this function. The main - // issue is if an arg is a fat-pointer, miri `expects()` to be able to read the value - // of that pointer to get size info. However, since this is `ConstProp`, that argument - // doesn't actually have a backing value and so this causes an ICE. + // Work around: avoid ICE in miri. FIXME(wesleywiser) + // The Miri engine ICEs when taking a reference to an uninitialized unsized + // local. There's nothing it can do here: taking a reference needs an allocation + // which needs to know the size. Normally that's okay as during execution + // (e.g. for CTFE) it can never happen. But here in const_prop + // unknown data is uninitialized, so if e.g. a function argument is unsized + // and has a reference taken, we get an ICE. Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => { trace!("checking Ref({:?})", place); let alive = if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value { true - } else { false }; + } else { + false + }; - if local.as_usize() <= self.ecx.frame().body.arg_count && !alive { - trace!("skipping Ref({:?})", place); + if !alive { + trace!("skipping Ref({:?}) to uninitialized local", place); return None; } } - // Work around: avoid extra unnecessary locals. - // FIXME(wesleywiser): const eval will turn this into a `const Scalar(<ZST>)` that - // `SimplifyLocals` doesn't know it can remove. - Rvalue::Aggregate(_, operands) if operands.len() == 0 => { - return None; - } - _ => { } } self.use_ecx(source_info, |this| { trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place); this.ecx.eval_rvalue_into_place(rvalue, place)?; - this.ecx.eval_place_to_op(place, Some(place_layout)) + Ok(()) }) } @@ -714,16 +710,15 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { base: PlaceBase::Local(local), projection: box [], } = *place { - if let Some(value) = self.const_prop(rval, - place_layout, - statement.source_info, - place) { - trace!("checking whether {:?} can be stored to {:?}", value, local); + let source = statement.source_info; + if let Some(()) = self.const_prop(rval, place_layout, source, place) { if self.can_const_prop[local] { - trace!("stored {:?} to {:?}", value, local); - assert_eq!(self.get_const(local), Some(value)); + trace!("propagated into {:?}", local); if self.should_const_prop() { + let value = + self.get_const(local).expect("local was dead/uninitialized"); + trace!("replacing {:?} with {:?}", rval, value); self.replace_with_const( rval, value, @@ -731,7 +726,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { ); } } else { - trace!("can't propagate {:?} to {:?}", value, local); + trace!("can't propagate into {:?}", local); self.remove_const(local); } } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 606c1a3a1cc..e41b4678dbd 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -31,7 +31,7 @@ use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc::ty::TyCtxt; use rustc::mir::*; -use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext}; +use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext}; use rustc::session::config::DebugInfo; use std::borrow::Cow; use crate::transform::{MirPass, MirSource}; @@ -293,23 +293,31 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { pub struct SimplifyLocals; impl<'tcx> MirPass<'tcx> for SimplifyLocals { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { - let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()) }; - marker.visit_body(body); - // Return pointer and arguments are always live - marker.locals.insert(RETURN_PLACE); - for arg in body.args_iter() { - marker.locals.insert(arg); - } + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + trace!("running SimplifyLocals on {:?}", source); + let locals = { + let mut marker = DeclMarker { + locals: BitSet::new_empty(body.local_decls.len()), + body, + }; + marker.visit_body(body); + // Return pointer and arguments are always live + marker.locals.insert(RETURN_PLACE); + for arg in body.args_iter() { + marker.locals.insert(arg); + } - // We may need to keep dead user variables live for debuginfo. - if tcx.sess.opts.debuginfo == DebugInfo::Full { - for local in body.vars_iter() { - marker.locals.insert(local); + // We may need to keep dead user variables live for debuginfo. + if tcx.sess.opts.debuginfo == DebugInfo::Full { + for local in body.vars_iter() { + marker.locals.insert(local); + } } - } - let map = make_local_map(&mut body.local_decls, marker.locals); + marker.locals + }; + + let map = make_local_map(&mut body.local_decls, locals); // Update references to all vars and tmps now LocalUpdater { map }.visit_body(body); body.local_decls.shrink_to_fit(); @@ -334,18 +342,35 @@ fn make_local_map<V>( map } -struct DeclMarker { +struct DeclMarker<'a, 'tcx> { pub locals: BitSet<Local>, + pub body: &'a Body<'tcx>, } -impl<'tcx> Visitor<'tcx> for DeclMarker { - fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) { +impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { + fn visit_local(&mut self, local: &Local, ctx: PlaceContext, location: Location) { // Ignore storage markers altogether, they get removed along with their otherwise unused // decls. // FIXME: Extend this to all non-uses. - if !ctx.is_storage_marker() { - self.locals.insert(*local); + if ctx.is_storage_marker() { + return; } + + // Ignore stores of constants because `ConstProp` and `CopyProp` can remove uses of many + // of these locals. However, if the local is still needed, then it will be referenced in + // another place and we'll mark it as being used there. + if ctx == PlaceContext::MutatingUse(MutatingUseContext::Store) { + let stmt = + &self.body.basic_blocks()[location.block].statements[location.statement_index]; + if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(c)))) = &stmt.kind { + if p.as_local().is_some() { + trace!("skipping store of const value {:?} to {:?}", c, local); + return; + } + } + } + + self.locals.insert(*local); } } @@ -357,9 +382,16 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater { fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { // Remove unnecessary StorageLive and StorageDead annotations. data.statements.retain(|stmt| { - match stmt.kind { + match &stmt.kind { StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { - self.map[l].is_some() + self.map[*l].is_some() + } + StatementKind::Assign(box (place, _)) => { + if let Some(local) = place.as_local() { + self.map[local].is_some() + } else { + true + } } _ => true } diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index b826dd91198..2e23b8c870c 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -1,8 +1,7 @@ //! Used by plugin crates to tell `rustc` about the plugins they provide. -use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; +use rustc::lint::LintStore; use rustc::session::Session; -use rustc::util::nodemap::FxHashMap; use syntax_expand::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension}; use syntax_expand::base::MacroExpanderFn; @@ -26,6 +25,9 @@ pub struct Registry<'a> { /// from the plugin registrar. pub sess: &'a Session, + /// The `LintStore` allows plugins to register new lints. + pub lint_store: &'a mut LintStore, + #[doc(hidden)] pub args_hidden: Option<Vec<ast::NestedMetaItem>>, @@ -36,15 +38,6 @@ pub struct Registry<'a> { pub syntax_exts: Vec<NamedSyntaxExtension>, #[doc(hidden)] - pub early_lint_passes: Vec<EarlyLintPassObject>, - - #[doc(hidden)] - pub late_lint_passes: Vec<LateLintPassObject>, - - #[doc(hidden)] - pub lint_groups: FxHashMap<&'static str, (Vec<LintId>, Option<&'static str>)>, - - #[doc(hidden)] pub llvm_passes: Vec<String>, #[doc(hidden)] @@ -53,15 +46,13 @@ pub struct Registry<'a> { impl<'a> Registry<'a> { #[doc(hidden)] - pub fn new(sess: &'a Session, krate_span: Span) -> Registry<'a> { + pub fn new(sess: &'a Session, lint_store: &'a mut LintStore, krate_span: Span) -> Registry<'a> { Registry { sess, + lint_store, args_hidden: None, krate_span, syntax_exts: vec![], - early_lint_passes: vec![], - late_lint_passes: vec![], - lint_groups: FxHashMap::default(), llvm_passes: vec![], attributes: vec![], } @@ -99,27 +90,6 @@ impl<'a> Registry<'a> { self.register_syntax_extension(Symbol::intern(name), ext); } - /// Register a compiler lint pass. - pub fn register_early_lint_pass(&mut self, lint_pass: EarlyLintPassObject) { - self.early_lint_passes.push(lint_pass); - } - - /// Register a compiler lint pass. - pub fn register_late_lint_pass(&mut self, lint_pass: LateLintPassObject) { - self.late_lint_passes.push(lint_pass); - } - /// Register a lint group. - pub fn register_lint_group( - &mut self, - name: &'static str, - deprecated_name: Option<&'static str>, - to: Vec<&'static Lint> - ) { - self.lint_groups.insert(name, - (to.into_iter().map(|x| LintId::of(x)).collect(), - deprecated_name)); - } - /// Register an LLVM pass. /// /// Registration with LLVM itself is handled through static C++ objects with diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs index cd6189c681d..b82cba8c83d 100644 --- a/src/librustc_resolve/error_codes.rs +++ b/src/librustc_resolve/error_codes.rs @@ -1682,7 +1682,7 @@ enum Wizard { } trait Isengard { - fn wizard(w: Wizard) { // error! + fn wizard(w: Wizard) { // ok! match w { Wizard::Saruman => { // do something diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 424bf31a785..34edd5eaf4f 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -673,13 +673,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> { self.throw_unresolved_import_error(errors, None); errors = vec![]; } - if !seen_spans.contains(&err.span) { + if seen_spans.insert(err.span) { let path = import_path_to_string( &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(), &import.subclass, err.span, ); - seen_spans.insert(err.span); errors.push((path, err)); prev_root_id = import.root_id; } diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index c5277c4f90e..d91588db183 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -71,8 +71,7 @@ mod riscv_base; mod wasm32_base; mod vxworks_base; -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, - RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum LinkerFlavor { Em, Gcc, @@ -82,8 +81,7 @@ pub enum LinkerFlavor { PtxLinker, } -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, - RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum LldFlavor { Wasm, Ld64, diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs index 54d580ec05d..8d136a1b65c 100644 --- a/src/librustc_traits/chalk_context/mod.rs +++ b/src/librustc_traits/chalk_context/mod.rs @@ -33,7 +33,7 @@ use rustc::traits::{ InEnvironment, ChalkCanonicalGoal, }; -use rustc::ty::{self, TyCtxt, InferConst}; +use rustc::ty::{self, TyCtxt}; use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc::ty::query::Providers; use rustc::ty::subst::{GenericArg, GenericArgKind}; @@ -286,7 +286,7 @@ impl context::ContextOps<ChalkArenas<'tcx>> for ChalkContext<'tcx> { _ => false, }, GenericArgKind::Const(ct) => match ct.val { - ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)) => { + ConstValue::Bound(debruijn, bound_ct) => { debug_assert_eq!(debruijn, ty::INNERMOST); cvar == bound_ct } diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs index 8facec1e9e3..49d76681196 100644 --- a/src/librustc_traits/chalk_context/resolvent_ops.rs +++ b/src/librustc_traits/chalk_context/resolvent_ops.rs @@ -16,7 +16,7 @@ use rustc::traits::{ Environment, InEnvironment, }; -use rustc::ty::{self, Ty, TyCtxt, InferConst}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::GenericArg; use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc::mir::interpret::ConstValue; @@ -287,10 +287,7 @@ impl TypeRelation<'tcx> for AnswerSubstitutor<'cx, 'tcx> { a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - if let ty::Const { - val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)), - .. - } = a { + if let ty::Const { val: ConstValue::Bound(debruijn, bound_ct), .. } = a { if *debruijn == self.binder_index { self.unify_free_answer_var(*bound_ct, b.into())?; return Ok(b); @@ -299,14 +296,8 @@ impl TypeRelation<'tcx> for AnswerSubstitutor<'cx, 'tcx> { match (a, b) { ( - ty::Const { - val: ConstValue::Infer(InferConst::Canonical(a_debruijn, a_bound)), - .. - }, - ty::Const { - val: ConstValue::Infer(InferConst::Canonical(b_debruijn, b_bound)), - .. - }, + ty::Const { val: ConstValue::Bound(a_debruijn, a_bound), .. }, + ty::Const { val: ConstValue::Bound(b_debruijn, b_bound), .. }, ) => { assert_eq!(a_debruijn, b_debruijn); assert_eq!(a_bound, b_bound); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f2502ab3648..79dc4f7e136 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -232,8 +232,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.sess, span, E0632, - "cannot provide explicit type parameters when `impl Trait` is \ - used in argument position." + "cannot provide explicit generic arguments when `impl Trait` is \ + used in argument position" }; err.emit(); @@ -1274,8 +1274,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, item.trait_ref().def_id(), object_safety_violations - ) - .map(|mut err| err.emit()); + ).emit(); return tcx.types.err; } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index dfeb5fb958c..9cbde276ae9 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -428,21 +428,36 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.report_cast_to_unsized_type(fcx); } else if self.expr_ty.references_error() || self.cast_ty.references_error() { // No sense in giving duplicate error messages - } else if self.try_coercion_cast(fcx) { - self.trivial_cast_lint(fcx); - debug!(" -> CoercionCast"); - fcx.tables.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id); - } else { - match self.do_check(fcx) { - Ok(k) => { - debug!(" -> {:?}", k); + match self.try_coercion_cast(fcx) { + Ok(()) => { + self.trivial_cast_lint(fcx); + debug!(" -> CoercionCast"); + fcx.tables.borrow_mut() + .set_coercion_cast(self.expr.hir_id.local_id); + } + Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => { + self.report_object_unsafe_cast(&fcx, did); + } + Err(_) => { + match self.do_check(fcx) { + Ok(k) => { + debug!(" -> {:?}", k); + } + Err(e) => self.report_cast_error(fcx, e), + }; } - Err(e) => self.report_cast_error(fcx, e), }; } } + fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) { + let violations = fcx.tcx.object_safety_violations(did); + let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations); + err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty))); + err.emit(); + } + /// Checks a cast, and report an error if one exists. In some cases, this /// can return Ok and create type errors in the fcx rather than returning /// directly. coercion-cast is handled in check instead of here. @@ -646,8 +661,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { } } - fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool { - fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok() + fn try_coercion_cast( + &self, + fcx: &FnCtxt<'a, 'tcx>, + ) -> Result<(), ty::error::TypeError<'_>> { + match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) { + Ok(_) => Ok(()), + Err(err) => Err(err), + } } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 3a89cddda23..f79351dc903 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -61,10 +61,11 @@ use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{ Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast }; -use rustc::ty::{self, TypeAndMut, Ty, subst::SubstsRef}; +use rustc::ty::{self, TypeAndMut, Ty}; use rustc::ty::fold::TypeFoldable; use rustc::ty::error::TypeError; use rustc::ty::relate::RelateResult; +use rustc::ty::subst::SubstsRef; use smallvec::{smallvec, SmallVec}; use std::ops::Deref; use syntax::feature_gate; @@ -196,9 +197,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // a "spurious" type variable, and we don't want to have that // type variable in memory if the coercion fails. let unsize = self.commit_if_ok(|_| self.coerce_unsized(a, b)); - if unsize.is_ok() { - debug!("coerce: unsize successful"); - return unsize; + match unsize { + Ok(_) => { + debug!("coerce: unsize successful"); + return unsize; + } + Err(TypeError::ObjectUnsafeCoercion(did)) => { + debug!("coerce: unsize not object safe"); + return Err(TypeError::ObjectUnsafeCoercion(did)); + } + Err(_) => {} } debug!("coerce: unsize failed"); @@ -539,7 +547,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut selcx = traits::SelectionContext::new(self); // Create an obligation for `Source: CoerceUnsized<Target>`. - let cause = ObligationCause::misc(self.cause.span, self.body_id); + let cause = ObligationCause::new( + self.cause.span, + self.body_id, + ObligationCauseCode::Coercion { source, target }, + ); // Use a FIFO queue for this custom fulfillment procedure. // @@ -566,14 +578,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let obligation = queue.remove(0); debug!("coerce_unsized resolve step: {:?}", obligation); let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref t) if traits.contains(&t.def_id()) => { - if unsize_did == t.def_id() { - if let ty::Tuple(..) = &t.skip_binder().input_types().nth(1).unwrap().kind { + ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { + if unsize_did == tr.def_id() { + let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind; + if let ty::Tuple(..) = sty { debug!("coerce_unsized: found unsized tuple coercion"); has_unsized_tuple_coercion = true; } } - t.clone() + tr.clone() } _ => { coercion.obligations.push(obligation); @@ -811,7 +824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { target: Ty<'tcx>, allow_two_phase: AllowTwoPhase, ) -> RelateResult<'tcx, Ty<'tcx>> { - let source = self.resolve_type_vars_with_obligations(expr_ty); + let source = self.resolve_vars_with_obligations(expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); @@ -829,7 +842,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Same as `try_coerce()`, but without side-effects. pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool { - let source = self.resolve_type_vars_with_obligations(expr_ty); + let source = self.resolve_vars_with_obligations(expr_ty); debug!("coercion::can({:?} -> {:?})", source, target); let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable); @@ -853,8 +866,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { -> RelateResult<'tcx, Ty<'tcx>> where E: AsCoercionSite { - let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); - let new_ty = self.resolve_type_vars_with_obligations(new_ty); + let prev_ty = self.resolve_vars_with_obligations(prev_ty); + let new_ty = self.resolve_vars_with_obligations(new_ty); debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty); // Special-case that coercion alone cannot handle: @@ -1333,7 +1346,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { err.span_label(return_sp, "expected because this return type..."); err.span_label( *sp, format!( "...is found to be `{}` here", - fcx.resolve_type_vars_with_obligations(expected), + fcx.resolve_vars_with_obligations(expected), )); } err diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 677e2ea3566..3509d6566ec 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -108,7 +108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, allow_two_phase: AllowTwoPhase) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) { - let expected = self.resolve_type_vars_with_obligations(expected); + let expected = self.resolve_vars_with_obligations(expected); let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase) { Ok(ty) => return (ty, None), @@ -117,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr = expr.peel_drop_temps(); let cause = self.misc(expr.span); - let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); + let expr_ty = self.resolve_vars_with_obligations(checked_ty); let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); if self.is_assign_to_bool(expr, expected) { diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index ad46a443b8f..8668dd99a8c 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -566,7 +566,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the `enclosing_loops` field and let's coerce the // type of `expr_opt` into what is expected. let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(target_id); + let ctxt = match enclosing_breakables.opt_find_breakable(target_id) { + Some(ctxt) => ctxt, + None => { // Avoid ICE when `break` is inside a closure (#65383). + self.tcx.sess.delay_span_bug( + expr.span, + "break was outside loop, but no error was emitted", + ); + return tcx.types.err; + } + }; + if let Some(ref mut coerce) = ctxt.coerce { if let Some(ref e) = expr_opt { coerce.coerce(self, &cause, e, e_ty); @@ -592,7 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } else { // If `ctxt.coerce` is `None`, we can just ignore - // the type of the expresison. This is because + // the type of the expression. This is because // either this was a break *without* a value, in // which case it is always a legal type (`()`), or // else an error would have been flagged by the @@ -1010,7 +1020,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr, ) -> Ty<'tcx> { let flds = expected.only_has_type(self).and_then(|ty| { - let ty = self.resolve_type_vars_with_obligations(ty); + let ty = self.resolve_vars_with_obligations(ty); match ty.kind { ty::Tuple(ref flds) => Some(&flds[..]), _ => None diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f2d001eaded..d90ed2a790b 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -919,7 +919,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This occurs for UFCS desugaring of `T::method`, where there is no // receiver expression for the method call, and thus no autoderef. if let SelfSource::QPath(_) = source { - return is_local(self.resolve_type_vars_with_obligations(rcvr_ty)); + return is_local(self.resolve_vars_with_obligations(rcvr_ty)); } self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty)) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 152edf8dd0e..d1a8a6f6026 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -536,10 +536,16 @@ pub struct EnclosingBreakables<'tcx> { impl<'tcx> EnclosingBreakables<'tcx> { fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> { - let ix = *self.by_id.get(&target_id).unwrap_or_else(|| { + self.opt_find_breakable(target_id).unwrap_or_else(|| { bug!("could not find enclosing breakable with id {}", target_id); - }); - &mut self.stack[ix] + }) + } + + fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> { + match self.by_id.get(&target_id) { + Some(ix) => Some(&mut self.stack[*ix]), + None => None, + } } } @@ -1387,9 +1393,37 @@ fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); check_transparent(tcx, span, def_id); + check_union_fields(tcx, span, def_id); check_packed(tcx, span, def_id); } +/// When the `#![feature(untagged_unions)]` gate is active, +/// check that the fields of the `union` does not contain fields that need dropping. +fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: DefId) -> bool { + let item_type = tcx.type_of(item_def_id); + if let ty::Adt(def, substs) = item_type.kind { + assert!(def.is_union()); + let fields = &def.non_enum_variant().fields; + for field in fields { + let field_ty = field.ty(tcx, substs); + // We are currently checking the type this field came from, so it must be local. + let field_span = tcx.hir().span_if_local(field.did).unwrap(); + let param_env = tcx.param_env(field.did); + if field_ty.needs_drop(tcx, param_env) { + struct_span_err!(tcx.sess, field_span, E0740, + "unions may not contain fields that need dropping") + .span_note(field_span, + "`std::mem::ManuallyDrop` can be used to wrap the type") + .emit(); + return false; + } + } + } else { + span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind); + } + return true; +} + /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` /// projections that would result in "inheriting lifetimes". fn check_opaque<'tcx>( @@ -2440,23 +2474,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.cause(span, ObligationCauseCode::MiscObligation) } - /// Resolves type variables in `ty` if possible. Unlike the infcx + /// Resolves type and const variables in `ty` if possible. Unlike the infcx /// version (resolve_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort /// to get more type information. - fn resolve_type_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - debug!("resolve_type_vars_with_obligations(ty={:?})", ty); + fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + debug!("resolve_vars_with_obligations(ty={:?})", ty); // No Infer()? Nothing needs doing. - if !ty.has_infer_types() { - debug!("resolve_type_vars_with_obligations: ty={:?}", ty); + if !ty.has_infer_types() && !ty.has_infer_consts() { + debug!("resolve_vars_with_obligations: ty={:?}", ty); return ty; } // If `ty` is a type variable, see whether we already know what it is. ty = self.resolve_vars_if_possible(&ty); - if !ty.has_infer_types() { - debug!("resolve_type_vars_with_obligations: ty={:?}", ty); + if !ty.has_infer_types() && !ty.has_infer_consts() { + debug!("resolve_vars_with_obligations: ty={:?}", ty); return ty; } @@ -2467,7 +2501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.select_obligations_where_possible(false, |_| {}); ty = self.resolve_vars_if_possible(&ty); - debug!("resolve_type_vars_with_obligations: ty={:?}", ty); + debug!("resolve_vars_with_obligations: ty={:?}", ty); ty } @@ -3668,7 +3702,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { formal_ret: Ty<'tcx>, formal_args: &[Ty<'tcx>]) -> Vec<Ty<'tcx>> { - let formal_ret = self.resolve_type_vars_with_obligations(formal_ret); + let formal_ret = self.resolve_vars_with_obligations(formal_ret); let ret_ty = match expected_ret.only_has_type(self) { Some(ret) => ret, None => return Vec::new() @@ -4517,7 +4551,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion( span, "try adding a return type", - format!("-> {} ", self.resolve_type_vars_with_obligations(found)), + format!("-> {} ", self.resolve_vars_with_obligations(found)), Applicability::MachineApplicable); true } @@ -4993,7 +5027,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If no resolution is possible, then an error is reported. // Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.resolve_type_vars_with_obligations(ty); + let ty = self.resolve_vars_with_obligations(ty); if !ty.is_ty_var() { ty } else { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index f9df2d1d848..819c347d3ae 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -179,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_with_needs(lhs_expr, Needs::MutPlace) } }; - let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty); + let lhs_ty = self.resolve_vars_with_obligations(lhs_ty); // N.B., as we have not yet type-checked the RHS, we don't have the // type at hand. Make a variable to represent it. The whole reason @@ -196,7 +196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // see `NB` above let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); - let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty); + let rhs_ty = self.resolve_vars_with_obligations(rhs_ty); let return_ty = match result { Ok(method) => { diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 53ee0777c7c..97c30f208f5 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -251,7 +251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, mut def_bm: BindingMode, ) -> (Ty<'tcx>, BindingMode) { - let mut expected = self.resolve_type_vars_with_obligations(&expected); + let mut expected = self.resolve_vars_with_obligations(&expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index a44c475e0f8..8adf4bb94a8 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -183,8 +183,11 @@ fn check_impl_overlap<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId) { for component_def_id in component_def_ids { if !tcx.is_object_safe(component_def_id) { - // This is an error, but it will be reported by wfcheck. Ignore it here. + // Without the 'object_safe_for_dispatch' feature this is an error + // which will be reported by wfcheck. Ignore it here. // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. + // With the feature enabled, the trait is not implemented automatically, + // so this is valid. } else { let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id); diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index ef08e8d4f0b..3d41c6e09c6 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -194,7 +194,7 @@ a guard. ```compile_fail,E0029 let string = "salutations !"; -// The ordering relation for strings can't be evaluated at compile time, +// The ordering relation for strings cannot be evaluated at compile time, // so this doesn't work: match string { "hello" ..= "world" => {} @@ -348,7 +348,7 @@ fn main() { "##, E0044: r##" -You can't use type or const parameters on foreign items. +You cannot use type or const parameters on foreign items. Example of erroneous code: ```compile_fail,E0044 @@ -788,7 +788,7 @@ fn some_other_func() {} fn some_function() { SOME_CONST = 14; // error : a constant value cannot be changed! 1 = 3; // error : 1 isn't a valid place! - some_other_func() = 4; // error : we can't assign value to a function! + some_other_func() = 4; // error : we cannot assign value to a function! SomeStruct.x = 12; // error : SomeStruct a structure name but it is used // like a variable! } @@ -3891,6 +3891,33 @@ details. [issue #33685]: https://github.com/rust-lang/rust/issues/33685 "##, +E0588: r##" +A type with `packed` representation hint has a field with `align` +representation hint. + +Erroneous code example: + +```compile_fail,E0588 +#[repr(align(16))] +struct Aligned(i32); + +#[repr(packed)] // error! +struct Packed(Aligned); +``` + +Just like you cannot have both `align` and `packed` representation hints on a +same type, a `packed` type cannot contain another type with the `align` +representation hint. However, you can do the opposite: + +``` +#[repr(packed)] +struct Packed(i32); + +#[repr(align(16))] // ok! +struct Aligned(Packed); +``` +"##, + E0592: r##" This error occurs when you defined methods or associated functions with same name. @@ -4299,7 +4326,7 @@ extern { unsafe { printf(::std::ptr::null(), 0f32); - // error: can't pass an `f32` to variadic function, cast to `c_double` + // error: cannot pass an `f32` to variadic function, cast to `c_double` } ``` @@ -4863,6 +4890,10 @@ assert_eq!(1, discriminant(&Enum::Struct{a: 7, b: 11})); ``` "##, +E0740: r##" +A `union` cannot have fields with destructors. +"##, + E0733: r##" Recursion in an `async fn` requires boxing. For example, this will not compile: @@ -4996,7 +5027,7 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC. // E0174, // E0182, // merged into E0229 E0183, -// E0187, // can't infer the kind of the closure +// E0187, // cannot infer the kind of the closure // E0188, // can not cast an immutable reference to a mutable pointer // E0189, // deprecated: can only cast a boxed pointer to a boxed object // E0190, // deprecated: can only cast a &-pointer to an &-object @@ -5043,13 +5074,12 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC. // E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` E0587, // type has conflicting packed and align representation hints - E0588, // packed type cannot transitively contain a `[repr(align)]` type // E0611, // merged into E0616 // E0612, // merged into E0609 // E0613, // Removed (merged with E0609) E0627, // yield statement outside of generator literal - E0632, // cannot provide explicit type parameters when `impl Trait` is used - // in argument position. + E0632, // cannot provide explicit generic arguments when `impl Trait` is + // used in argument position E0634, // type has conflicting packed representaton hints E0640, // infer outlives requirements E0641, // cannot cast to/from a pointer with an unknown kind diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b84540d899e..abc8b831449 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1306,7 +1306,7 @@ impl Clean<Option<Lifetime>> for ty::RegionKind { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Debug)] pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec<GenericBound> }, RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> }, @@ -1588,7 +1588,7 @@ impl Clean<GenericParamDef> for hir::GenericParam { } // maybe use a Generic enum and use Vec<Generic>? -#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] +#[derive(Clone, Debug, Default)] pub struct Generics { pub params: Vec<GenericParamDef>, pub where_predicates: Vec<WherePredicate>, @@ -3839,7 +3839,7 @@ impl Clean<Mutability> for hir::Mutability { } } -#[derive(Clone, PartialEq, Eq, Copy, Debug, Hash)] +#[derive(Clone, PartialEq, Debug)] pub enum ImplPolarity { Positive, Negative, @@ -4498,7 +4498,6 @@ struct RegionDeps<'tcx> { smaller: FxHashSet<RegionTarget<'tcx>> } -#[derive(Eq, PartialEq, Hash, Debug)] enum SimpleBound { TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier), Outlives(Lifetime), diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 1c0d1b32737..0b8d4d6c302 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -53,6 +53,8 @@ pub struct Options { pub codegen_options_strs: Vec<String>, /// Debugging (`-Z`) options to pass to the compiler. pub debugging_options: DebuggingOptions, + /// Debugging (`-Z`) options strings to pass to the compiler. + pub debugging_options_strs: Vec<String>, /// The target used to compile the crate against. pub target: TargetTriple, /// Edition used when reading the crate. Defaults to "2015". Also used by default when @@ -478,6 +480,7 @@ impl Options { let generate_redirect_pages = matches.opt_present("generate-redirect-pages"); let test_builder = matches.opt_str("test-builder").map(PathBuf::from); let codegen_options_strs = matches.opt_strs("C"); + let debugging_options_strs = matches.opt_strs("Z"); let lib_strs = matches.opt_strs("L"); let extern_strs = matches.opt_strs("extern"); let runtool = matches.opt_str("runtool"); @@ -499,6 +502,7 @@ impl Options { codegen_options, codegen_options_strs, debugging_options, + debugging_options_strs, target, edition, maybe_sysroot, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 00265caa965..39ab30e8ecf 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -5,7 +5,7 @@ use rustc::hir::HirId; use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; use rustc::ty::{Ty, TyCtxt}; -use rustc::lint::{self, LintPass}; +use rustc::lint; use rustc::session::config::ErrorOutputType; use rustc::session::DiagnosticOutput; use rustc::util::nodemap::{FxHashMap, FxHashSet}; @@ -273,10 +273,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); let lints = || { - lint::builtin::HardwiredLints - .get_lints() + lint::builtin::HardwiredLints::get_lints() .into_iter() - .chain(rustc_lint::SoftLints.get_lints().into_iter()) + .chain(rustc_lint::SoftLints::get_lints().into_iter()) }; let lint_opts = lints().filter_map(|lint| { @@ -329,7 +328,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let config = interface::Config { opts: sessopts, - crate_cfg: config::parse_cfgspecs(cfgs), + crate_cfg: interface::parse_cfgspecs(cfgs), input, input_path: cpath, output_file: None, @@ -339,6 +338,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt stderr: None, crate_name, lint_caps, + register_lints: None, }; interface::run_compiler_in_existing_thread_pool(config, |compiler| { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 0dc094ae329..bbc00147ee1 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -59,7 +59,7 @@ impl Module<'hir> { fns : Vec::new(), mods : Vec::new(), typedefs : Vec::new(), - opaque_tys : Vec::new(), + opaque_tys : Vec::new(), statics : Vec::new(), constants : Vec::new(), traits : Vec::new(), diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 72a72e89281..414c3137376 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1241,6 +1241,7 @@ fn settings(root_path: &str, suffix: &str) -> String { ("go-to-only-result", "Directly go to item in search if there is only one result", false), ("line-numbers", "Show line numbers on code examples", false), + ("disable-shortcuts", "Disable keyboard shortcuts", false), ]; format!( "<h1 class='fqn'>\ diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 17a940cc4c9..f0104c9156d 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -79,6 +79,7 @@ function getSearchElement() { "derive", "traitalias"]; + var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") !== "true"; var search_input = getSearchInput(); // On the search screen, so you remain on the last tab you opened. @@ -294,7 +295,7 @@ function getSearchElement() { function handleShortcut(ev) { // Don't interfere with browser shortcuts - if (ev.ctrlKey || ev.altKey || ev.metaKey) { + if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts === true) { return; } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 0be6340df96..07dc1e4e915 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -67,7 +67,7 @@ pub fn run(options: Options) -> i32 { cfgs.push("doctest".to_owned()); let config = interface::Config { opts: sessopts, - crate_cfg: config::parse_cfgspecs(cfgs), + crate_cfg: interface::parse_cfgspecs(cfgs), input, input_path: None, output_file: None, @@ -77,6 +77,7 @@ pub fn run(options: Options) -> i32 { stderr: None, crate_name: options.crate_name.clone(), lint_caps: Default::default(), + register_lints: None, }; let mut test_args = options.test_args.clone(); @@ -280,6 +281,9 @@ fn run_test( for codegen_options_str in &options.codegen_options_strs { compiler.arg("-C").arg(&codegen_options_str); } + for debugging_option_str in &options.debugging_options_strs { + compiler.arg("-Z").arg(&debugging_option_str); + } if no_run { compiler.arg("--emit=metadata"); } diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index d981740780e..f2e9be14c8d 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -143,7 +143,7 @@ impl<T> Decodable for BTreeSet<T> } impl<K, V, S> Encodable for HashMap<K, V, S> - where K: Encodable + Hash + Eq, + where K: Encodable + Eq, V: Encodable, S: BuildHasher, { @@ -180,7 +180,7 @@ impl<K, V, S> Decodable for HashMap<K, V, S> } impl<T, S> Encodable for HashSet<T, S> - where T: Encodable + Hash + Eq, + where T: Encodable + Eq, S: BuildHasher, { fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> { diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 483f2ba52ec..6dcda986310 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -327,7 +327,31 @@ impl CString { /// [`NulError`]: struct.NulError.html #[stable(feature = "rust1", since = "1.0.0")] pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> { - Self::_new(t.into()) + trait SpecIntoVec { + fn into_vec(self) -> Vec<u8>; + } + impl<T: Into<Vec<u8>>> SpecIntoVec for T { + default fn into_vec(self) -> Vec<u8> { + self.into() + } + } + // Specialization for avoiding reallocation. + impl SpecIntoVec for &'_ [u8] { + fn into_vec(self) -> Vec<u8> { + let mut v = Vec::with_capacity(self.len() + 1); + v.extend(self); + v + } + } + impl SpecIntoVec for &'_ str { + fn into_vec(self) -> Vec<u8> { + let mut v = Vec::with_capacity(self.len() + 1); + v.extend(self.as_bytes()); + v + } + } + + Self::_new(SpecIntoVec::into_vec(t)) } fn _new(bytes: Vec<u8>) -> Result<CString, NulError> { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index fc26dcb3211..6595f54162f 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1090,13 +1090,14 @@ impl Metadata { /// Returns the creation time listed in this metadata. /// - /// The returned value corresponds to the `birthtime` field of `stat` on - /// Unix platforms and the `ftCreationTime` field on Windows platforms. + /// The returned value corresponds to the `btime` field of `statx` on + /// Linux kernel starting from to 4.11, the `birthtime` field of `stat` on other + /// Unix platforms, and the `ftCreationTime` field on Windows platforms. /// /// # Errors /// /// This field may not be available on all platforms, and will return an - /// `Err` on platforms where it is not available. + /// `Err` on platforms or filesystems where it is not available. /// /// # Examples /// @@ -1109,7 +1110,7 @@ impl Metadata { /// if let Ok(time) = metadata.created() { /// println!("{:?}", time); /// } else { - /// println!("Not supported on this platform"); + /// println!("Not supported on this platform or filesystem"); /// } /// Ok(()) /// } @@ -3443,5 +3444,18 @@ mod tests { check!(a.created()); check!(b.created()); } + + if cfg!(target_os = "linux") { + // Not always available + match (a.created(), b.created()) { + (Ok(t1), Ok(t2)) => assert!(t1 <= t2), + (Err(e1), Err(e2)) if e1.kind() == ErrorKind::Other && + e2.kind() == ErrorKind::Other => {} + (a, b) => panic!( + "creation time must be always supported or not supported: {:?} {:?}", + a, b, + ), + } + } } } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index c798ee0e220..6574ef13db9 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -762,7 +762,7 @@ pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + /// otherwise. `label` identifies the stream in a panic message. /// /// This function is used to print error messages, so it takes extra -/// care to avoid causing a panic when `local_stream` is unusable. +/// care to avoid causing a panic when `local_s` is unusable. /// For instance, if the TLS key for the local stream is /// already destroyed, or if the local stream is locked by another /// thread, it will just fall back to the global stream. diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index a8dfe924fdf..ab8a55660cb 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -33,9 +33,72 @@ mod as_keyword { } // /// Exit early from a loop. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// When `break` is encountered, execution of the associated loop body is +/// immediately terminated. +/// +/// ```rust +/// let mut last = 0; +/// +/// for x in 1..100 { +/// if x > 12 { +/// break; +/// } +/// last = x; +/// } +/// +/// assert_eq!(last, 12); +/// println!("{}", last); +/// ``` +/// +/// A break expression is normally associated with the innermost loop enclosing the +/// `break` but a label can be used to specify which enclosing loop is affected. +/// +///```rust +/// 'outer: for i in 1..=5 { +/// println!("outer iteration (i): {}", i); +/// +/// 'inner: for j in 1..=200 { +/// println!(" inner iteration (j): {}", j); +/// if j >= 3 { +/// // breaks from inner loop, let's outer loop continue. +/// break; +/// } +/// if i >= 2 { +/// // breaks from outer loop, and directly to "Bye". +/// break 'outer; +/// } +/// } +/// } +/// println!("Bye."); +///``` +/// +/// When associated with `loop`, a break expression may be used to return a value from that loop. +/// This is only valid with `loop` and not with any other type of loop. +/// If no value is specified, `break;` returns `()`. +/// Every `break` within a loop must return the same type. +/// +/// ```rust +/// let (mut a, mut b) = (1, 1); +/// let result = loop { +/// if b > 10 { +/// break b; +/// } +/// let c = a + b; +/// a = b; +/// b = c; +/// }; +/// // first number in Fibonacci sequence over 10: +/// assert_eq!(result, 13); +/// println!("{}", result); +/// ``` +/// +/// For more details consult the [Reference on "break expression"] and the [Reference on "break and +/// loop values"]. +/// +/// [Reference on "break expression"]: ../reference/expressions/loop-expr.html#break-expressions +/// [Reference on "break and loop values"]: +/// ../reference/expressions/loop-expr.html#break-and-loop-values /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 mod break_keyword { } #[doc(keyword = "const")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index af6cb656444..d0cb0104f6c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -275,6 +275,8 @@ #![feature(link_args)] #![feature(linkage)] #![feature(log_syntax)] +#![feature(manually_drop_take)] +#![feature(matches_macro)] #![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] #![feature(needs_panic_runtime)] @@ -297,6 +299,7 @@ #![feature(slice_concat_ext)] #![feature(slice_internals)] #![feature(slice_patterns)] +#![feature(specialization)] #![feature(staged_api)] #![feature(std_internals)] #![feature(stdsimd)] @@ -525,6 +528,7 @@ pub use core::{ writeln, // Unstable todo, + matches, }; // Re-export built-in macros defined through libcore. diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 46bbd8855de..a9e4457f423 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -202,7 +202,7 @@ impl UdpSocket { /// /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); /// assert_eq!(socket.peer_addr().unwrap_err().kind(), - /// ::std::io::ErrorKind::NotConnected); + /// std::io::ErrorKind::NotConnected); /// ``` #[stable(feature = "udp_peer_addr", since = "1.40.0")] pub fn peer_addr(&self) -> io::Result<SocketAddr> { diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 24c693790e8..577673b7e40 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -264,7 +264,7 @@ impl RefUnwindSafe for atomic::AtomicI128 {} #[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicUsize {} -#[cfg(target_hastarget_has_atomic_load_store_atomic = "8")] +#[cfg(target_has_atomic_load_store = "8")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicU8 {} #[cfg(target_has_atomic_load_store = "16")] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 638ce1679b8..619b1820190 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -12,8 +12,7 @@ use core::panic::{BoxMeUp, PanicInfo, Location}; use crate::any::Any; use crate::fmt; use crate::intrinsics; -use crate::mem; -use crate::ptr; +use crate::mem::{self, ManuallyDrop}; use crate::raw; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::stdio::panic_output; @@ -218,7 +217,7 @@ pub fn update_panic_count(amt: isize) -> usize { PANIC_COUNT.with(|c| { let next = (c.get() as isize + amt) as usize; c.set(next); - return next + next }) } @@ -227,10 +226,9 @@ pub use realstd::rt::update_panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> { - #[allow(unions_with_drop_fields)] union Data<F, R> { - f: F, - r: R, + f: ManuallyDrop<F>, + r: ManuallyDrop<R>, } // We do some sketchy operations with ownership here for the sake of @@ -261,7 +259,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> let mut any_data = 0; let mut any_vtable = 0; let mut data = Data { - f, + f: ManuallyDrop::new(f) }; let r = __rust_maybe_catch_panic(do_call::<F, R>, @@ -271,7 +269,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> return if r == 0 { debug_assert!(update_panic_count(0) == 0); - Ok(data.r) + Ok(ManuallyDrop::into_inner(data.r)) } else { update_panic_count(-1); debug_assert!(update_panic_count(0) == 0); @@ -284,8 +282,9 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> fn do_call<F: FnOnce() -> R, R>(data: *mut u8) { unsafe { let data = data as *mut Data<F, R>; - let f = ptr::read(&mut (*data).f); - ptr::write(&mut (*data).r, f()); + let data = &mut (*data); + let f = ManuallyDrop::take(&mut data.f); + data.r = ManuallyDrop::new(f()); } } } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index da136ca6bf6..4b0cf8312f1 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1488,12 +1488,12 @@ impl Child { /// } /// /// fn main() { -/// ::std::process::exit(match run_app() { -/// Ok(_) => 0, -/// Err(err) => { -/// eprintln!("error: {:?}", err); -/// 1 -/// } +/// std::process::exit(match run_app() { +/// Ok(_) => 0, +/// Err(err) => { +/// eprintln!("error: {:?}", err); +/// 1 +/// } /// }); /// } /// ``` diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index ac43526b50f..ba611a6b7e7 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -71,22 +71,7 @@ impl FileDesc { #[cfg(target_os = "android")] use super::android::cvt_pread64; - #[cfg(target_os = "emscripten")] - unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) - -> io::Result<isize> - { - use crate::convert::TryInto; - use libc::pread64; - // pread64 on emscripten actually takes a 32 bit offset - if let Ok(o) = offset.try_into() { - cvt(pread64(fd, buf, count, o)) - } else { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot pread >2GB")) - } - } - - #[cfg(not(any(target_os = "android", target_os = "emscripten")))] + #[cfg(not(target_os = "android"))] unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) -> io::Result<isize> { @@ -128,22 +113,7 @@ impl FileDesc { #[cfg(target_os = "android")] use super::android::cvt_pwrite64; - #[cfg(target_os = "emscripten")] - unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) - -> io::Result<isize> - { - use crate::convert::TryInto; - use libc::pwrite64; - // pwrite64 on emscripten actually takes a 32 bit offset - if let Ok(o) = offset.try_into() { - cvt(pwrite64(fd, buf, count, o)) - } else { - Err(io::Error::new(io::ErrorKind::InvalidInput, - "cannot pwrite >2GB")) - } - } - - #[cfg(not(any(target_os = "android", target_os = "emscripten")))] + #[cfg(not(target_os = "android"))] unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) -> io::Result<isize> { diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 3b1eb86b84f..39cc120594a 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -41,11 +41,138 @@ pub use crate::sys_common::fs::remove_dir_all; pub struct File(FileDesc); -#[derive(Clone)] -pub struct FileAttr { - stat: stat64, +// FIXME: This should be available on Linux with all `target_arch` and `target_env`. +// https://github.com/rust-lang/libc/issues/1545 +macro_rules! cfg_has_statx { + ({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => { + cfg_if::cfg_if! { + if #[cfg(all(target_os = "linux", target_env = "gnu", any( + target_arch = "x86", + target_arch = "arm", + // target_arch = "mips", + target_arch = "powerpc", + target_arch = "x86_64", + // target_arch = "aarch64", + target_arch = "powerpc64", + // target_arch = "mips64", + // target_arch = "s390x", + target_arch = "sparc64", + )))] { + $($then_tt)* + } else { + $($else_tt)* + } + } + }; + ($($block_inner:tt)*) => { + #[cfg(all(target_os = "linux", target_env = "gnu", any( + target_arch = "x86", + target_arch = "arm", + // target_arch = "mips", + target_arch = "powerpc", + target_arch = "x86_64", + // target_arch = "aarch64", + target_arch = "powerpc64", + // target_arch = "mips64", + // target_arch = "s390x", + target_arch = "sparc64", + )))] + { + $($block_inner)* + } + }; } +cfg_has_statx! {{ + #[derive(Clone)] + pub struct FileAttr { + stat: stat64, + statx_extra_fields: Option<StatxExtraFields>, + } + + #[derive(Clone)] + struct StatxExtraFields { + // This is needed to check if btime is supported by the filesystem. + stx_mask: u32, + stx_btime: libc::statx_timestamp, + } + + // We prefer `statx` on Linux if available, which contains file creation time. + // Default `stat64` contains no creation time. + unsafe fn try_statx( + fd: c_int, + path: *const libc::c_char, + flags: i32, + mask: u32, + ) -> Option<io::Result<FileAttr>> { + use crate::sync::atomic::{AtomicBool, Ordering}; + + // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx` + // We store the availability in a global to avoid unnecessary syscalls + static HAS_STATX: AtomicBool = AtomicBool::new(true); + syscall! { + fn statx( + fd: c_int, + pathname: *const libc::c_char, + flags: c_int, + mask: libc::c_uint, + statxbuf: *mut libc::statx + ) -> c_int + } + + if !HAS_STATX.load(Ordering::Relaxed) { + return None; + } + + let mut buf: libc::statx = mem::zeroed(); + let ret = cvt(statx(fd, path, flags, mask, &mut buf)); + match ret { + Err(err) => match err.raw_os_error() { + Some(libc::ENOSYS) => { + HAS_STATX.store(false, Ordering::Relaxed); + return None; + } + _ => return Some(Err(err)), + } + Ok(_) => { + // We cannot fill `stat64` exhaustively because of private padding fields. + let mut stat: stat64 = mem::zeroed(); + // `c_ulong` on gnu-mips, `dev_t` otherwise + stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; + stat.st_ino = buf.stx_ino as libc::ino64_t; + stat.st_nlink = buf.stx_nlink as libc::nlink_t; + stat.st_mode = buf.stx_mode as libc::mode_t; + stat.st_uid = buf.stx_uid as libc::uid_t; + stat.st_gid = buf.stx_gid as libc::gid_t; + stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; + stat.st_size = buf.stx_size as off64_t; + stat.st_blksize = buf.stx_blksize as libc::blksize_t; + stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; + stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; + // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. + stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; + stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; + stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; + stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; + stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; + + let extra = StatxExtraFields { + stx_mask: buf.stx_mask, + stx_btime: buf.stx_btime, + }; + + Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) + } + } + } + +} else { + #[derive(Clone)] + pub struct FileAttr { + stat: stat64, + } +}} + // all DirEntry's will have a reference to this struct struct InnerReadDir { dirp: Dir, @@ -97,6 +224,20 @@ pub struct FileType { mode: mode_t } #[derive(Debug)] pub struct DirBuilder { mode: mode_t } +cfg_has_statx! {{ + impl FileAttr { + fn from_stat64(stat: stat64) -> Self { + Self { stat, statx_extra_fields: None } + } + } +} else { + impl FileAttr { + fn from_stat64(stat: stat64) -> Self { + Self { stat } + } + } +}} + impl FileAttr { pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { @@ -164,6 +305,22 @@ impl FileAttr { target_os = "macos", target_os = "ios")))] pub fn created(&self) -> io::Result<SystemTime> { + cfg_has_statx! { + if let Some(ext) = &self.statx_extra_fields { + return if (ext.stx_mask & libc::STATX_BTIME) != 0 { + Ok(SystemTime::from(libc::timespec { + tv_sec: ext.stx_btime.tv_sec as libc::time_t, + tv_nsec: ext.stx_btime.tv_nsec as _, + })) + } else { + Err(io::Error::new( + io::ErrorKind::Other, + "creation time is not available for the filesystem", + )) + }; + } + } + Err(io::Error::new(io::ErrorKind::Other, "creation time is not available on this platform \ currently")) @@ -306,12 +463,25 @@ impl DirEntry { #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] pub fn metadata(&self) -> io::Result<FileAttr> { - let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; + let fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?; + let name = self.entry.d_name.as_ptr(); + + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + fd, + name, + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW) + fstatat64(fd, name, &mut stat, libc::AT_SYMLINK_NOFOLLOW) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))] @@ -517,11 +687,24 @@ impl File { } pub fn file_attr(&self) -> io::Result<FileAttr> { + let fd = self.0.raw(); + + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + fd, + b"\0" as *const _ as *const libc::c_char, + libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - fstat64(self.0.raw(), &mut stat) + fstat64(fd, &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn fsync(&self) -> io::Result<()> { @@ -602,8 +785,6 @@ impl File { SeekFrom::End(off) => (libc::SEEK_END, off), SeekFrom::Current(off) => (libc::SEEK_CUR, off), }; - #[cfg(target_os = "emscripten")] - let pos = pos as i32; let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?; Ok(n as u64) } @@ -798,20 +979,44 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { pub fn stat(p: &Path) -> io::Result<FileAttr> { let p = cstr(p)?; + + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { stat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn lstat(p: &Path) -> io::Result<FileAttr> { let p = cstr(p)?; + + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { lstat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index c5be1763302..be112f6fc03 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -8,7 +8,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { mem::size_of_val(&v)); imp::fill_bytes(view); } - return v + v } #[cfg(all(unix, diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs index 28a504f1979..6ce41420284 100644 --- a/src/libstd/sys/wasi/thread.rs +++ b/src/libstd/sys/wasi/thread.rs @@ -31,10 +31,10 @@ impl Thread { let nanos = dur.as_nanos(); assert!(nanos <= u64::max_value() as u128); - const CLOCK_ID: wasi::Userdata = 0x0123_45678; + const USERDATA: wasi::Userdata = 0x0123_45678; let clock = wasi::raw::__wasi_subscription_u_clock_t { - identifier: CLOCK_ID, + identifier: 0, clock_id: wasi::CLOCK_MONOTONIC, timeout: nanos as u64, precision: 0, @@ -42,7 +42,7 @@ impl Thread { }; let in_ = [wasi::Subscription { - userdata: 0, + userdata: USERDATA, type_: wasi::EVENTTYPE_CLOCK, u: wasi::raw::__wasi_subscription_u { clock: clock }, }]; @@ -53,7 +53,7 @@ impl Thread { }; match (res, event) { (Ok(1), wasi::Event { - userdata: CLOCK_ID, + userdata: USERDATA, error: 0, type_: wasi::EVENTTYPE_CLOCK, .. diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index 3e5aa693354..3986cda1a50 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -46,7 +46,7 @@ impl Handle { pub fn into_raw(self) -> c::HANDLE { let ret = self.raw(); mem::forget(self); - return ret; + ret } } diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 37cbdcefced..79dec1adf4b 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -144,7 +144,7 @@ fn kind() -> Kind { Some(..) => Kind::SRWLock, }; KIND.store(ret as usize, Ordering::SeqCst); - return ret; + ret } pub struct ReentrantMutex { inner: UnsafeCell<MaybeUninit<c::CRITICAL_SECTION>> } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 8658deb8546..096b7bea8a5 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -257,7 +257,7 @@ impl Stdio { let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS); io.into_raw(); - return ret + ret } Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)), } @@ -472,9 +472,8 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> { cmd.push('"' as u16); } - let mut iter = arg.encode_wide(); let mut backslashes: usize = 0; - while let Some(x) = iter.next() { + for x in arg.encode_wide() { if x == '\\' as u16 { backslashes += 1; } else { diff --git a/src/libstd/sys/windows/rand.rs b/src/libstd/sys/windows/rand.rs index c9bcb5d7415..993831bec18 100644 --- a/src/libstd/sys/windows/rand.rs +++ b/src/libstd/sys/windows/rand.rs @@ -13,7 +13,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); } - return v + v } #[cfg(target_vendor = "uwp")] diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 4c9734fa0aa..728257cdd4b 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -52,7 +52,7 @@ pub unsafe fn create(dtor: Option<Dtor>) -> Key { if let Some(f) = dtor { register_dtor(key, f); } - return key; + key } #[inline] diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index e0f0e3a1a45..bd533c93d43 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -80,7 +80,7 @@ impl SystemTime { unsafe { let mut t: SystemTime = mem::zeroed(); c::GetSystemTimeAsFileTime(&mut t.t); - return t + t } } @@ -228,7 +228,7 @@ mod perf_counter { FREQUENCY = frequency; STATE.store(2, SeqCst); } - return frequency; + frequency } } diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index e92c0d1c58e..cfaab4e22e9 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -509,9 +509,8 @@ pub mod os { pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> { let ptr = self.os.get() as *mut Value<T>; if ptr as usize > 1 { - match (*ptr).inner.get() { - Some(ref value) => return Some(value), - None => {}, + if let Some(ref value) = (*ptr).inner.get() { + return Some(value); } } self.try_initialize(init) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0408d7d1bc2..51a62cd0658 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1305,6 +1305,7 @@ impl MacroDef { } } +// Clippy uses Hash and PartialEq #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq)] pub enum StrStyle { /// A regular string, like `"foo"`. @@ -1327,6 +1328,7 @@ pub struct Lit { pub span: Span, } +// Clippy uses Hash and PartialEq #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq)] pub enum LitIntType { Signed(IntTy), @@ -1337,6 +1339,7 @@ pub enum LitIntType { /// Literal kind. /// /// E.g., `"foo"`, `42`, `12.34`, or `bool`. +// Clippy uses Hash and PartialEq #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq)] pub enum LitKind { /// A string literal (`"foo"`). diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 28b61c5aa77..84c86c9651f 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -84,7 +84,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { } } -#[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] pub enum InlineAttr { None, Hint, @@ -92,7 +92,7 @@ pub enum InlineAttr { Never, } -#[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub enum OptimizeAttr { None, Speed, @@ -624,8 +624,7 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) } } - -#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] +#[derive(RustcEncodable, RustcDecodable, Clone)] pub struct Deprecation { pub since: Option<Symbol>, pub note: Option<Symbol>, @@ -749,7 +748,7 @@ pub enum ReprAttr { ReprAlign(u32), } -#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] +#[derive(Eq, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] pub enum IntType { SignedInt(ast::IntTy), UnsignedInt(ast::UintTy) diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 94f0995566f..1386eac48da 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -528,6 +528,9 @@ declare_features! ( /// Enable accurate caller location reporting during panic (RFC 2091). (active, track_caller, "1.40.0", Some(47809), None), + /// Non-object safe trait objects safe to use but cannot be created in safe rust + (active, object_safe_for_dispatch, "1.40.0", Some(43561), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index a68b7fdf931..3fa13f08d3a 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -67,7 +67,7 @@ pub struct Globals { impl Globals { fn new(edition: Edition) -> Globals { Globals { - // We have no idea how many attributes their will be, so just + // We have no idea how many attributes there will be, so just // initiate the vectors with 0 bits. We'll grow them as necessary. used_attrs: Lock::new(GrowableBitSet::new_empty()), known_attrs: Lock::new(GrowableBitSet::new_empty()), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6bbd8be0cb9..2ce0046ca27 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -86,13 +86,6 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath { } } -fn maybe_append(mut lhs: Vec<Attribute>, mut rhs: Option<Vec<Attribute>>) -> Vec<Attribute> { - if let Some(ref mut rhs) = rhs { - lhs.append(rhs); - } - lhs -} - #[derive(Debug, Clone, Copy, PartialEq)] enum PrevTokenKind { DocComment, diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 0acfd1450d8..73bd80e2a21 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -10,7 +10,6 @@ use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, use crate::ast::{Ty, TyKind, Generics, GenericBounds, TraitRef, EnumDef, VariantData, StructField}; use crate::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, MethodSig, SelfKind, Param}; use crate::parse::token; -use crate::parse::parser::maybe_append; use crate::tokenstream::{TokenTree, TokenStream}; use crate::symbol::{kw, sym}; use crate::source_map::{self, respan, Span}; @@ -416,10 +415,17 @@ impl<'a> Parser<'a> { ) -> PResult<'a, Option<P<Item>>> { let (ident, item, extra_attrs) = info; let span = lo.to(self.prev_span); - let attrs = maybe_append(attrs, extra_attrs); + let attrs = Self::maybe_append(attrs, extra_attrs); Ok(Some(self.mk_item(span, ident, item, vis, attrs))) } + fn maybe_append<T>(mut lhs: Vec<T>, mut rhs: Option<Vec<T>>) -> Vec<T> { + if let Some(ref mut rhs) = rhs { + lhs.append(rhs); + } + lhs + } + /// This is the fall-through for parsing items. fn parse_macro_use_or_failure( &mut self, diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 7300ce24954..d987dc855b6 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -35,7 +35,6 @@ use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; /// An owned smart pointer. -#[derive(Hash, PartialEq, Eq)] pub struct P<T: ?Sized> { ptr: Box<T> } diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index 1501adc5971..a1d147637e2 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -41,7 +41,7 @@ pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { } } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy)] pub struct Spanned<T> { pub node: T, pub span: Span, diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index ac155556cda..0559f224f1f 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -19,7 +19,6 @@ use syntax_pos::{BytePos, Span, DUMMY_SP}; #[cfg(target_arch = "x86_64")] use rustc_data_structures::static_assert_size; use rustc_data_structures::sync::Lrc; -use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use smallvec::{SmallVec, smallvec}; use std::{iter, mem}; @@ -136,7 +135,7 @@ impl TokenTree { /// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s /// instead of a representation of the abstract syntax tree. /// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, RustcEncodable, RustcDecodable)] pub struct TokenStream(pub Lrc<Vec<TreeAndJoint>>); pub type TreeAndJoint = (TokenTree, IsJoint); @@ -145,7 +144,7 @@ pub type TreeAndJoint = (TokenTree, IsJoint); #[cfg(target_arch = "x86_64")] static_assert_size!(TokenStream, 8); -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum IsJoint { Joint, NonJoint @@ -460,18 +459,6 @@ impl Cursor { } } -impl Encodable for TokenStream { - fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), E::Error> { - self.trees().collect::<Vec<_>>().encode(encoder) - } -} - -impl Decodable for TokenStream { - fn decode<D: Decoder>(decoder: &mut D) -> Result<TokenStream, D::Error> { - Vec::<TokenTree>::decode(decoder).map(|vec| vec.into_iter().collect()) - } -} - #[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] pub struct DelimSpan { pub open: Span, diff --git a/src/libsyntax_expand/base.rs b/src/libsyntax_expand/base.rs index c222e7357ac..58edf23a5b1 100644 --- a/src/libsyntax_expand/base.rs +++ b/src/libsyntax_expand/base.rs @@ -1072,7 +1072,11 @@ impl<'a> ExtCtxt<'a> { /// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths. /// /// Returns an absolute path to the file that `path` refers to. - pub fn resolve_path(&self, path: impl Into<PathBuf>, span: Span) -> PathBuf { + pub fn resolve_path( + &self, + path: impl Into<PathBuf>, + span: Span, + ) -> Result<PathBuf, DiagnosticBuilder<'a>> { let path = path.into(); // Relative paths are resolved relative to the file in which they are found @@ -1082,13 +1086,16 @@ impl<'a> ExtCtxt<'a> { let mut result = match self.source_map().span_to_unmapped_path(callsite) { FileName::Real(path) => path, FileName::DocTest(path, _) => path, - other => panic!("cannot resolve relative path in non-file source `{}`", other), + other => return Err(self.struct_span_err( + span, + &format!("cannot resolve relative path in non-file source `{}`", other), + )), }; result.pop(); result.push(path); - result + Ok(result) } else { - path + Ok(path) } } } diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index f03d464eafb..fc521e5edc0 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -1418,7 +1418,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { return noop_visit_attribute(at, self); } - let filename = self.cx.resolve_path(&*file.as_str(), it.span()); + let filename = match self.cx.resolve_path(&*file.as_str(), it.span()) { + Ok(filename) => filename, + Err(mut err) => { + err.emit(); + continue; + } + }; + match self.cx.source_map().load_file(&filename) { Ok(source_file) => { let src = source_file.src.as_ref() diff --git a/src/libsyntax_expand/mbe.rs b/src/libsyntax_expand/mbe.rs index 453fe94f1de..d0f790638ef 100644 --- a/src/libsyntax_expand/mbe.rs +++ b/src/libsyntax_expand/mbe.rs @@ -73,7 +73,7 @@ impl KleeneToken { /// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) /// for token sequences. -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] enum KleeneOp { /// Kleene star (`*`) for zero or more repetitions ZeroOrMore, diff --git a/src/libsyntax_ext/source_util.rs b/src/libsyntax_ext/source_util.rs index 438e199ebdb..f6c58fcdfa1 100644 --- a/src/libsyntax_ext/source_util.rs +++ b/src/libsyntax_ext/source_util.rs @@ -76,7 +76,13 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream) None => return DummyResult::any(sp), }; // The file will be added to the code map by the parser - let file = cx.resolve_path(file, sp); + let file = match cx.resolve_path(file, sp) { + Ok(f) => f, + Err(mut err) => { + err.emit(); + return DummyResult::any(sp); + }, + }; let directory_ownership = DirectoryOwnership::Owned { relative: None }; let p = parse::new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp); @@ -122,7 +128,13 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream) Some(f) => f, None => return DummyResult::any(sp) }; - let file = cx.resolve_path(file, sp); + let file = match cx.resolve_path(file, sp) { + Ok(f) => f, + Err(mut err) => { + err.emit(); + return DummyResult::any(sp); + }, + }; match cx.source_map().load_binary_file(&file) { Ok(bytes) => match std::str::from_utf8(&bytes) { Ok(src) => { @@ -147,7 +159,13 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream) Some(f) => f, None => return DummyResult::any(sp) }; - let file = cx.resolve_path(file, sp); + let file = match cx.resolve_path(file, sp) { + Ok(f) => f, + Err(mut err) => { + err.emit(); + return DummyResult::any(sp); + }, + }; match cx.source_map().load_binary_file(&file) { Ok(bytes) => { base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::new(bytes)))) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 7f7c5cb2e45..7e42b931961 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -1311,7 +1311,7 @@ pub struct BytePos(pub u32); /// A character offset. Because of multibyte UTF-8 characters, a byte offset /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` /// values to `CharPos` values as necessary. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct CharPos(pub usize); // FIXME: lots of boilerplate in these impls, but so far my attempts to fix diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 4b947c5b857..377d2f877b3 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -459,6 +459,7 @@ symbols! { no_std, not, note, + object_safe_for_dispatch, Ok, omit_gdb_pretty_printer_section, on, diff --git a/src/libtest/bench.rs b/src/libtest/bench.rs new file mode 100644 index 00000000000..c86bfd16c21 --- /dev/null +++ b/src/libtest/bench.rs @@ -0,0 +1,258 @@ +//! Benchmarking module. +pub use std::hint::black_box; + +use super::{ + event::CompletedTest, + helpers::sink::Sink, + options::BenchMode, + types::TestDesc, + test_result::TestResult, + Sender, +}; + +use crate::stats; +use std::time::{Duration, Instant}; +use std::cmp; +use std::io; +use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::sync::{Arc, Mutex}; + +/// Manager of the benchmarking runs. +/// +/// This is fed into functions marked with `#[bench]` to allow for +/// set-up & tear-down before running a piece of code repeatedly via a +/// call to `iter`. +#[derive(Clone)] +pub struct Bencher { + mode: BenchMode, + summary: Option<stats::Summary>, + pub bytes: u64, +} + +impl Bencher { + /// Callback for benchmark functions to run in their body. + pub fn iter<T, F>(&mut self, mut inner: F) + where + F: FnMut() -> T, + { + if self.mode == BenchMode::Single { + ns_iter_inner(&mut inner, 1); + return; + } + + self.summary = Some(iter(&mut inner)); + } + + pub fn bench<F>(&mut self, mut f: F) -> Option<stats::Summary> + where + F: FnMut(&mut Bencher), + { + f(self); + self.summary + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct BenchSamples { + pub ns_iter_summ: stats::Summary, + pub mb_s: usize, +} + +pub fn fmt_bench_samples(bs: &BenchSamples) -> String { + use std::fmt::Write; + let mut output = String::new(); + + let median = bs.ns_iter_summ.median as usize; + let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; + + output + .write_fmt(format_args!( + "{:>11} ns/iter (+/- {})", + fmt_thousands_sep(median, ','), + fmt_thousands_sep(deviation, ',') + )) + .unwrap(); + if bs.mb_s != 0 { + output + .write_fmt(format_args!(" = {} MB/s", bs.mb_s)) + .unwrap(); + } + output +} + +// Format a number with thousands separators +fn fmt_thousands_sep(mut n: usize, sep: char) -> String { + use std::fmt::Write; + let mut output = String::new(); + let mut trailing = false; + for &pow in &[9, 6, 3, 0] { + let base = 10_usize.pow(pow); + if pow == 0 || trailing || n / base != 0 { + if !trailing { + output.write_fmt(format_args!("{}", n / base)).unwrap(); + } else { + output.write_fmt(format_args!("{:03}", n / base)).unwrap(); + } + if pow != 0 { + output.push(sep); + } + trailing = true; + } + n %= base; + } + + output +} + +fn ns_from_dur(dur: Duration) -> u64 { + dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64) +} + +fn ns_iter_inner<T, F>(inner: &mut F, k: u64) -> u64 +where + F: FnMut() -> T, +{ + let start = Instant::now(); + for _ in 0..k { + black_box(inner()); + } + ns_from_dur(start.elapsed()) +} + +pub fn iter<T, F>(inner: &mut F) -> stats::Summary +where + F: FnMut() -> T, +{ + // Initial bench run to get ballpark figure. + let ns_single = ns_iter_inner(inner, 1); + + // Try to estimate iter count for 1ms falling back to 1m + // iterations if first run took < 1ns. + let ns_target_total = 1_000_000; // 1ms + let mut n = ns_target_total / cmp::max(1, ns_single); + + // if the first run took more than 1ms we don't want to just + // be left doing 0 iterations on every loop. The unfortunate + // side effect of not being able to do as many runs is + // automatically handled by the statistical analysis below + // (i.e., larger error bars). + n = cmp::max(1, n); + + let mut total_run = Duration::new(0, 0); + let samples: &mut [f64] = &mut [0.0_f64; 50]; + loop { + let loop_start = Instant::now(); + + for p in &mut *samples { + *p = ns_iter_inner(inner, n) as f64 / n as f64; + } + + stats::winsorize(samples, 5.0); + let summ = stats::Summary::new(samples); + + for p in &mut *samples { + let ns = ns_iter_inner(inner, 5 * n); + *p = ns as f64 / (5 * n) as f64; + } + + stats::winsorize(samples, 5.0); + let summ5 = stats::Summary::new(samples); + + let loop_run = loop_start.elapsed(); + + // If we've run for 100ms and seem to have converged to a + // stable median. + if loop_run > Duration::from_millis(100) + && summ.median_abs_dev_pct < 1.0 + && summ.median - summ5.median < summ5.median_abs_dev + { + return summ5; + } + + total_run = total_run + loop_run; + // Longest we ever run for is 3s. + if total_run > Duration::from_secs(3) { + return summ5; + } + + // If we overflow here just return the results so far. We check a + // multiplier of 10 because we're about to multiply by 2 and the + // next iteration of the loop will also multiply by 5 (to calculate + // the summ5 result) + n = match n.checked_mul(10) { + Some(_) => n * 2, + None => { + return summ5; + } + }; + } +} + +pub fn benchmark<F>(desc: TestDesc, monitor_ch: Sender<CompletedTest>, nocapture: bool, f: F) +where + F: FnMut(&mut Bencher), +{ + let mut bs = Bencher { + mode: BenchMode::Auto, + summary: None, + bytes: 0, + }; + + let data = Arc::new(Mutex::new(Vec::new())); + let oldio = if !nocapture { + Some(( + io::set_print(Some(Sink::new_boxed(&data))), + io::set_panic(Some(Sink::new_boxed(&data))), + )) + } else { + None + }; + + let result = catch_unwind(AssertUnwindSafe(|| bs.bench(f))); + + if let Some((printio, panicio)) = oldio { + io::set_print(printio); + io::set_panic(panicio); + } + + let test_result = match result { + //bs.bench(f) { + Ok(Some(ns_iter_summ)) => { + let ns_iter = cmp::max(ns_iter_summ.median as u64, 1); + let mb_s = bs.bytes * 1000 / ns_iter; + + let bs = BenchSamples { + ns_iter_summ, + mb_s: mb_s as usize, + }; + TestResult::TrBench(bs) + } + Ok(None) => { + // iter not called, so no data. + // FIXME: error in this case? + let samples: &mut [f64] = &mut [0.0_f64; 1]; + let bs = BenchSamples { + ns_iter_summ: stats::Summary::new(samples), + mb_s: 0, + }; + TestResult::TrBench(bs) + } + Err(_) => TestResult::TrFailed, + }; + + let stdout = data.lock().unwrap().to_vec(); + let message = CompletedTest::new(desc, test_result, None, stdout); + monitor_ch.send(message).unwrap(); +} + +pub fn run_once<F>(f: F) +where + F: FnMut(&mut Bencher), +{ + let mut bs = Bencher { + mode: BenchMode::Single, + summary: None, + bytes: 0, + }; + bs.bench(f); +} diff --git a/src/libtest/cli.rs b/src/libtest/cli.rs new file mode 100644 index 00000000000..a34426305be --- /dev/null +++ b/src/libtest/cli.rs @@ -0,0 +1,444 @@ +//! Module converting command-line arguments into test configuration. + +use std::env; +use std::path::PathBuf; +use getopts; + +use super::options::{RunIgnored, ColorConfig, OutputFormat, Options}; +use super::time::TestTimeOptions; +use super::helpers::isatty; + +#[derive(Debug)] +pub struct TestOpts { + pub list: bool, + pub filter: Option<String>, + pub filter_exact: bool, + pub exclude_should_panic: bool, + pub run_ignored: RunIgnored, + pub run_tests: bool, + pub bench_benchmarks: bool, + pub logfile: Option<PathBuf>, + pub nocapture: bool, + pub color: ColorConfig, + pub format: OutputFormat, + pub test_threads: Option<usize>, + pub skip: Vec<String>, + pub time_options: Option<TestTimeOptions>, + pub options: Options, +} + +impl TestOpts { + pub fn use_color(&self) -> bool { + match self.color { + ColorConfig::AutoColor => !self.nocapture && isatty::stdout_isatty(), + ColorConfig::AlwaysColor => true, + ColorConfig::NeverColor => false, + } + } +} + +/// Result of parsing the options. +pub type OptRes = Result<TestOpts, String>; +/// Result of parsing the option part. +type OptPartRes<T> = Result<T, String>; + +fn optgroups() -> getopts::Options { + let mut opts = getopts::Options::new(); + opts.optflag("", "include-ignored", "Run ignored and not ignored tests") + .optflag("", "ignored", "Run only ignored tests") + .optflag("", "exclude-should-panic", "Excludes tests marked as should_panic") + .optflag("", "test", "Run tests and not benchmarks") + .optflag("", "bench", "Run benchmarks instead of tests") + .optflag("", "list", "List all tests and benchmarks") + .optflag("h", "help", "Display this message (longer with --help)") + .optopt( + "", + "logfile", + "Write logs to the specified file instead \ + of stdout", + "PATH", + ) + .optflag( + "", + "nocapture", + "don't capture stdout/stderr of each \ + task, allow printing directly", + ) + .optopt( + "", + "test-threads", + "Number of threads used for running tests \ + in parallel", + "n_threads", + ) + .optmulti( + "", + "skip", + "Skip tests whose names contain FILTER (this flag can \ + be used multiple times)", + "FILTER", + ) + .optflag( + "q", + "quiet", + "Display one character per test instead of one line. \ + Alias to --format=terse", + ) + .optflag( + "", + "exact", + "Exactly match filters rather than by substring", + ) + .optopt( + "", + "color", + "Configure coloring of output: + auto = colorize if stdout is a tty and tests are run on serially (default); + always = always colorize output; + never = never colorize output;", + "auto|always|never", + ) + .optopt( + "", + "format", + "Configure formatting of output: + pretty = Print verbose output; + terse = Display one character per test; + json = Output a json document", + "pretty|terse|json", + ) + .optflag( + "", + "show-output", + "Show captured stdout of successful tests" + ) + .optopt( + "Z", + "", + "Enable nightly-only flags: + unstable-options = Allow use of experimental features", + "unstable-options", + ) + .optflagopt( + "", + "report-time", + "Show execution time of each test. Awailable values: + plain = do not colorize the execution time (default); + colored = colorize output according to the `color` parameter value; + + Threshold values for colorized output can be configured via + `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and + `RUST_TEST_TIME_DOCTEST` environment variables. + + Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`. + + Not available for --format=terse", + "plain|colored" + ) + .optflag( + "", + "ensure-time", + "Treat excess of the test execution time limit as error. + + Threshold values for this option can be configured via + `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and + `RUST_TEST_TIME_DOCTEST` environment variables. + + Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`. + + `CRITICAL_TIME` here means the limit that should not be exceeded by test. + " + ); + opts +} + +fn usage(binary: &str, options: &getopts::Options) { + let message = format!("Usage: {} [OPTIONS] [FILTER]", binary); + println!( + r#"{usage} + +The FILTER string is tested against the name of all tests, and only those +tests whose names contain the filter are run. + +By default, all tests are run in parallel. This can be altered with the +--test-threads flag or the RUST_TEST_THREADS environment variable when running +tests (set it to 1). + +All tests have their standard output and standard error captured by default. +This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE +environment variable to a value other than "0". Logging is not captured by default. + +Test Attributes: + + `#[test]` - Indicates a function is a test to be run. This function + takes no arguments. + `#[bench]` - Indicates a function is a benchmark to be run. This + function takes one argument (test::Bencher). + `#[should_panic]` - This function (also labeled with `#[test]`) will only pass if + the code causes a panic (an assertion failure or panic!) + A message may be provided, which the failure string must + contain: #[should_panic(expected = "foo")]. + `#[ignore]` - When applied to a function which is already attributed as a + test, then the test runner will ignore these tests during + normal test runs. Running with --ignored or --include-ignored will run + these tests."#, + usage = options.usage(&message) + ); +} + +/// Parses command line arguments into test options. +/// Returns `None` if help was requested (since we only show help message and don't run tests), +/// returns `Some(Err(..))` if provided arguments are incorrect, +/// otherwise creates a `TestOpts` object and returns it. +pub fn parse_opts(args: &[String]) -> Option<OptRes> { + // Parse matches. + let opts = optgroups(); + let args = args.get(1..).unwrap_or(args); + let matches = match opts.parse(args) { + Ok(m) => m, + Err(f) => return Some(Err(f.to_string())), + }; + + // Check if help was requested. + if matches.opt_present("h") { + // Show help and do nothing more. + usage(&args[0], &opts); + return None; + } + + // Actually parse the opts. + let opts_result = parse_opts_impl(matches); + + Some(opts_result) +} + +// Gets the option value and checks if unstable features are enabled. +macro_rules! unstable_optflag { + ($matches:ident, $allow_unstable:ident, $option_name:literal) => {{ + let opt = $matches.opt_present($option_name); + if !$allow_unstable && opt { + return Err(format!( + "The \"{}\" flag is only accepted on the nightly compiler", + $option_name + )); + } + + opt + }}; +} + +// Implementation of `parse_opts` that doesn't care about help message +// and returns a `Result`. +fn parse_opts_impl(matches: getopts::Matches) -> OptRes { + let allow_unstable = get_allow_unstable(&matches)?; + + // Unstable flags + let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic"); + let include_ignored = unstable_optflag!(matches, allow_unstable, "include-ignored"); + let time_options = get_time_options(&matches, allow_unstable)?; + + let quiet = matches.opt_present("quiet"); + let exact = matches.opt_present("exact"); + let list = matches.opt_present("list"); + let skip = matches.opt_strs("skip"); + + let bench_benchmarks = matches.opt_present("bench"); + let run_tests = !bench_benchmarks || matches.opt_present("test"); + + let logfile = get_log_file(&matches)?; + let run_ignored = get_run_ignored(&matches, include_ignored)?; + let filter = get_filter(&matches)?; + let nocapture = get_nocapture(&matches)?; + let test_threads = get_test_threads(&matches)?; + let color = get_color_config(&matches)?; + let format = get_format(&matches, quiet, allow_unstable)?; + + let options = Options::new().display_output(matches.opt_present("show-output")); + + let test_opts = TestOpts { + list, + filter, + filter_exact: exact, + exclude_should_panic, + run_ignored, + run_tests, + bench_benchmarks, + logfile, + nocapture, + color, + format, + test_threads, + skip, + time_options, + options, + }; + + Ok(test_opts) +} + +// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566 +fn is_nightly() -> bool { + // Whether this is a feature-staged build, i.e., on the beta or stable channel + let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); + // Whether we should enable unstable features for bootstrapping + let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); + + bootstrap || !disable_unstable_features +} + +// Gets the CLI options assotiated with `report-time` feature. +fn get_time_options( + matches: &getopts::Matches, + allow_unstable: bool) +-> OptPartRes<Option<TestTimeOptions>> { + let report_time = unstable_optflag!(matches, allow_unstable, "report-time"); + let colored_opt_str = matches.opt_str("report-time"); + let mut report_time_colored = report_time && colored_opt_str == Some("colored".into()); + let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time"); + + // If `ensure-test-time` option is provided, time output is enforced, + // so user won't be confused if any of tests will silently fail. + let options = if report_time || ensure_test_time { + if ensure_test_time && !report_time { + report_time_colored = true; + } + Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored)) + } else { + None + }; + + Ok(options) +} + +fn get_test_threads(matches: &getopts::Matches) -> OptPartRes<Option<usize>> { + let test_threads = match matches.opt_str("test-threads") { + Some(n_str) => match n_str.parse::<usize>() { + Ok(0) => return Err("argument for --test-threads must not be 0".to_string()), + Ok(n) => Some(n), + Err(e) => { + return Err(format!( + "argument for --test-threads must be a number > 0 \ + (error: {})", + e + )); + } + }, + None => None, + }; + + Ok(test_threads) +} + +fn get_format( + matches: &getopts::Matches, + quiet: bool, + allow_unstable: bool +) -> OptPartRes<OutputFormat> { + let format = match matches.opt_str("format").as_ref().map(|s| &**s) { + None if quiet => OutputFormat::Terse, + Some("pretty") | None => OutputFormat::Pretty, + Some("terse") => OutputFormat::Terse, + Some("json") => { + if !allow_unstable { + return Err( + "The \"json\" format is only accepted on the nightly compiler".into(), + ); + } + OutputFormat::Json + } + + Some(v) => { + return Err(format!( + "argument for --format must be pretty, terse, or json (was \ + {})", + v + )); + } + }; + + Ok(format) +} + +fn get_color_config(matches: &getopts::Matches) -> OptPartRes<ColorConfig> { + let color = match matches.opt_str("color").as_ref().map(|s| &**s) { + Some("auto") | None => ColorConfig::AutoColor, + Some("always") => ColorConfig::AlwaysColor, + Some("never") => ColorConfig::NeverColor, + + Some(v) => { + return Err(format!( + "argument for --color must be auto, always, or never (was \ + {})", + v + )); + } + }; + + Ok(color) +} + +fn get_nocapture(matches: &getopts::Matches) -> OptPartRes<bool> { + let mut nocapture = matches.opt_present("nocapture"); + if !nocapture { + nocapture = match env::var("RUST_TEST_NOCAPTURE") { + Ok(val) => &val != "0", + Err(_) => false, + }; + } + + Ok(nocapture) +} + +fn get_run_ignored(matches: &getopts::Matches, include_ignored: bool) -> OptPartRes<RunIgnored> { + let run_ignored = match (include_ignored, matches.opt_present("ignored")) { + (true, true) => { + return Err( + "the options --include-ignored and --ignored are mutually exclusive".into(), + ); + } + (true, false) => RunIgnored::Yes, + (false, true) => RunIgnored::Only, + (false, false) => RunIgnored::No, + }; + + Ok(run_ignored) +} + +fn get_filter(matches: &getopts::Matches) -> OptPartRes<Option<String>> { + let filter = if !matches.free.is_empty() { + Some(matches.free[0].clone()) + } else { + None + }; + + Ok(filter) +} + +fn get_allow_unstable(matches: &getopts::Matches) -> OptPartRes<bool> { + let mut allow_unstable = false; + + if let Some(opt) = matches.opt_str("Z") { + if !is_nightly() { + return Err( + "the option `Z` is only accepted on the nightly compiler".into(), + ); + } + + match &*opt { + "unstable-options" => { + allow_unstable = true; + } + _ => { + return Err("Unrecognized option to `Z`".into()); + } + } + }; + + Ok(allow_unstable) +} + +fn get_log_file(matches: &getopts::Matches) -> OptPartRes<Option<PathBuf>> { + let logfile = matches.opt_str("logfile").map(|s| PathBuf::from(&s)); + + Ok(logfile) +} diff --git a/src/libtest/console.rs b/src/libtest/console.rs new file mode 100644 index 00000000000..244cbd2cf5f --- /dev/null +++ b/src/libtest/console.rs @@ -0,0 +1,308 @@ +//! Module providing interface for running tests in the console. + +use std::fs::File; +use std::io::prelude::Write; +use std::io; + +use term; + +use super::{ + bench::fmt_bench_samples, + cli::TestOpts, + event::{TestEvent, CompletedTest}, + formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter}, + helpers::{ + concurrency::get_concurrency, + metrics::MetricMap, + }, + types::{TestDesc, TestDescAndFn, NamePadding}, + options::{Options, OutputFormat}, + test_result::TestResult, + time::TestExecTime, + run_tests, + filter_tests, +}; + +/// Generic wrapper over stdout. +pub enum OutputLocation<T> { + Pretty(Box<term::StdoutTerminal>), + Raw(T), +} + +impl<T: Write> Write for OutputLocation<T> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + match *self { + OutputLocation::Pretty(ref mut term) => term.write(buf), + OutputLocation::Raw(ref mut stdout) => stdout.write(buf), + } + } + + fn flush(&mut self) -> io::Result<()> { + match *self { + OutputLocation::Pretty(ref mut term) => term.flush(), + OutputLocation::Raw(ref mut stdout) => stdout.flush(), + } + } +} + +pub struct ConsoleTestState { + pub log_out: Option<File>, + pub total: usize, + pub passed: usize, + pub failed: usize, + pub ignored: usize, + pub allowed_fail: usize, + pub filtered_out: usize, + pub measured: usize, + pub metrics: MetricMap, + pub failures: Vec<(TestDesc, Vec<u8>)>, + pub not_failures: Vec<(TestDesc, Vec<u8>)>, + pub time_failures: Vec<(TestDesc, Vec<u8>)>, + pub options: Options, +} + +impl ConsoleTestState { + pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> { + let log_out = match opts.logfile { + Some(ref path) => Some(File::create(path)?), + None => None, + }; + + Ok(ConsoleTestState { + log_out, + total: 0, + passed: 0, + failed: 0, + ignored: 0, + allowed_fail: 0, + filtered_out: 0, + measured: 0, + metrics: MetricMap::new(), + failures: Vec::new(), + not_failures: Vec::new(), + time_failures: Vec::new(), + options: opts.options, + }) + } + + pub fn write_log<F, S>( + &mut self, + msg: F, + ) -> io::Result<()> + where + S: AsRef<str>, + F: FnOnce() -> S, + { + match self.log_out { + None => Ok(()), + Some(ref mut o) => { + let msg = msg(); + let msg = msg.as_ref(); + o.write_all(msg.as_bytes()) + }, + } + } + + pub fn write_log_result(&mut self,test: &TestDesc, + result: &TestResult, + exec_time: Option<&TestExecTime>, + ) -> io::Result<()> { + self.write_log(|| format!( + "{} {}", + match *result { + TestResult::TrOk => "ok".to_owned(), + TestResult::TrFailed => "failed".to_owned(), + TestResult::TrFailedMsg(ref msg) => format!("failed: {}", msg), + TestResult::TrIgnored => "ignored".to_owned(), + TestResult::TrAllowedFail => "failed (allowed)".to_owned(), + TestResult::TrBench(ref bs) => fmt_bench_samples(bs), + TestResult::TrTimedFail => "failed (time limit exceeded)".to_owned(), + }, + test.name, + ))?; + if let Some(exec_time) = exec_time { + self.write_log(|| format!(" <{}>", exec_time))?; + } + self.write_log(|| "\n") + } + + fn current_test_count(&self) -> usize { + self.passed + self.failed + self.ignored + self.measured + self.allowed_fail + } +} + +// List the tests to console, and optionally to logfile. Filters are honored. +pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> { + let mut output = match term::stdout() { + None => OutputLocation::Raw(io::stdout()), + Some(t) => OutputLocation::Pretty(t), + }; + + let quiet = opts.format == OutputFormat::Terse; + let mut st = ConsoleTestState::new(opts)?; + + let mut ntest = 0; + let mut nbench = 0; + + for test in filter_tests(&opts, tests) { + use crate::TestFn::*; + + let TestDescAndFn { + desc: TestDesc { name, .. }, + testfn, + } = test; + + let fntype = match testfn { + StaticTestFn(..) | DynTestFn(..) => { + ntest += 1; + "test" + } + StaticBenchFn(..) | DynBenchFn(..) => { + nbench += 1; + "benchmark" + } + }; + + writeln!(output, "{}: {}", name, fntype)?; + st.write_log(|| format!("{} {}\n", fntype, name))?; + } + + fn plural(count: u32, s: &str) -> String { + match count { + 1 => format!("{} {}", 1, s), + n => format!("{} {}s", n, s), + } + } + + if !quiet { + if ntest != 0 || nbench != 0 { + writeln!(output, "")?; + } + + writeln!( + output, + "{}, {}", + plural(ntest, "test"), + plural(nbench, "benchmark") + )?; + } + + Ok(()) +} + +// Updates `ConsoleTestState` depending on result of the test execution. +fn handle_test_result(st: &mut ConsoleTestState, completed_test: CompletedTest) { + let test = completed_test.desc; + let stdout = completed_test.stdout; + match completed_test.result { + TestResult::TrOk => { + st.passed += 1; + st.not_failures.push((test, stdout)); + } + TestResult::TrIgnored => st.ignored += 1, + TestResult::TrAllowedFail => st.allowed_fail += 1, + TestResult::TrBench(bs) => { + st.metrics.insert_metric( + test.name.as_slice(), + bs.ns_iter_summ.median, + bs.ns_iter_summ.max - bs.ns_iter_summ.min, + ); + st.measured += 1 + } + TestResult::TrFailed => { + st.failed += 1; + st.failures.push((test, stdout)); + } + TestResult::TrFailedMsg(msg) => { + st.failed += 1; + let mut stdout = stdout; + stdout.extend_from_slice(format!("note: {}", msg).as_bytes()); + st.failures.push((test, stdout)); + } + TestResult::TrTimedFail => { + st.failed += 1; + st.time_failures.push((test, stdout)); + } + } +} + +// Handler for events that occur during test execution. +// It is provided as a callback to the `run_tests` function. +fn on_test_event( + event: &TestEvent, + st: &mut ConsoleTestState, + out: &mut dyn OutputFormatter, +) -> io::Result<()> { + match (*event).clone() { + TestEvent::TeFiltered(ref filtered_tests) => { + st.total = filtered_tests.len(); + out.write_run_start(filtered_tests.len())?; + } + TestEvent::TeFilteredOut(filtered_out) => { + st.filtered_out = filtered_out; + } + TestEvent::TeWait(ref test) => out.write_test_start(test)?, + TestEvent::TeTimeout(ref test) => out.write_timeout(test)?, + TestEvent::TeResult(completed_test) => { + let test = &completed_test.desc; + let result = &completed_test.result; + let exec_time = &completed_test.exec_time; + let stdout = &completed_test.stdout; + + st.write_log_result(test, result, exec_time.as_ref())?; + out.write_result(test, result, exec_time.as_ref(), &*stdout, st)?; + handle_test_result(st, completed_test); + } + } + + Ok(()) +} + +/// A simple console test runner. +/// Runs provided tests reporting process and results to the stdout. +pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> { + let output = match term::stdout() { + None => OutputLocation::Raw(io::stdout()), + Some(t) => OutputLocation::Pretty(t), + }; + + let max_name_len = tests + .iter() + .max_by_key(|t| len_if_padded(*t)) + .map(|t| t.desc.name.as_slice().len()) + .unwrap_or(0); + + let is_multithreaded = opts.test_threads.unwrap_or_else(get_concurrency) > 1; + + let mut out: Box<dyn OutputFormatter> = match opts.format { + OutputFormat::Pretty => Box::new(PrettyFormatter::new( + output, + opts.use_color(), + max_name_len, + is_multithreaded, + opts.time_options, + )), + OutputFormat::Terse => Box::new(TerseFormatter::new( + output, + opts.use_color(), + max_name_len, + is_multithreaded, + )), + OutputFormat::Json => Box::new(JsonFormatter::new(output)), + }; + let mut st = ConsoleTestState::new(opts)?; + + run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?; + + assert!(st.current_test_count() == st.total); + + out.write_run_finish(&st) +} + +// Calculates padding for given test description. +fn len_if_padded(t: &TestDescAndFn) -> usize { + match t.testfn.padding() { + NamePadding::PadNone => 0, + NamePadding::PadOnRight => t.desc.name.as_slice().len(), + } +} diff --git a/src/libtest/event.rs b/src/libtest/event.rs new file mode 100644 index 00000000000..eefbd2d6a81 --- /dev/null +++ b/src/libtest/event.rs @@ -0,0 +1,41 @@ +//! Module containing different events that can occur +//! during tests execution process. + +use super::types::TestDesc; +use super::test_result::TestResult; +use super::time::TestExecTime; + +#[derive(Debug, Clone)] +pub struct CompletedTest { + pub desc: TestDesc, + pub result: TestResult, + pub exec_time: Option<TestExecTime>, + pub stdout: Vec<u8>, +} + +impl CompletedTest { + pub fn new( + desc: TestDesc, + result: TestResult, + exec_time: Option<TestExecTime>, + stdout: Vec<u8> + ) -> Self { + Self { + desc, + result, + exec_time, + stdout, + } + } +} + +unsafe impl Send for CompletedTest {} + +#[derive(Debug, Clone)] +pub enum TestEvent { + TeFiltered(Vec<TestDesc>), + TeWait(TestDesc), + TeResult(CompletedTest), + TeTimeout(TestDesc), + TeFilteredOut(usize), +} diff --git a/src/libtest/formatters/json.rs b/src/libtest/formatters/json.rs index dcd733620bf..b73d7349678 100644 --- a/src/libtest/formatters/json.rs +++ b/src/libtest/formatters/json.rs @@ -1,4 +1,16 @@ -use super::*; +use std::{ + io, + io::prelude::Write, + borrow::Cow, +}; + +use crate::{ + types::TestDesc, + time, + test_result::TestResult, + console::{ConsoleTestState, OutputLocation}, +}; +use super::OutputFormatter; pub(crate) struct JsonFormatter<T> { out: OutputLocation<T>, @@ -27,7 +39,7 @@ impl<T: Write> JsonFormatter<T> { ty: &str, name: &str, evt: &str, - exec_time: Option<&TestExecTime>, + exec_time: Option<&time::TestExecTime>, stdout: Option<Cow<'_, str>>, extra: Option<&str>, ) -> io::Result<()> { @@ -76,25 +88,26 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> { &mut self, desc: &TestDesc, result: &TestResult, - exec_time: Option<&TestExecTime>, + exec_time: Option<&time::TestExecTime>, stdout: &[u8], state: &ConsoleTestState, ) -> io::Result<()> { - let stdout = if (state.options.display_output || *result != TrOk) && stdout.len() > 0 { + let display_stdout = state.options.display_output || *result != TestResult::TrOk; + let stdout = if display_stdout && stdout.len() > 0 { Some(String::from_utf8_lossy(stdout)) } else { None }; match *result { - TrOk => { + TestResult::TrOk => { self.write_event("test", desc.name.as_slice(), "ok", exec_time, stdout, None) } - TrFailed => { + TestResult::TrFailed => { self.write_event("test", desc.name.as_slice(), "failed", exec_time, stdout, None) } - TrTimedFail => self.write_event( + TestResult::TrTimedFail => self.write_event( "test", desc.name.as_slice(), "failed", @@ -103,7 +116,7 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> { Some(r#""reason": "time limit exceeded""#), ), - TrFailedMsg(ref m) => self.write_event( + TestResult::TrFailedMsg(ref m) => self.write_event( "test", desc.name.as_slice(), "failed", @@ -112,11 +125,11 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> { Some(&*format!(r#""message": "{}""#, EscapedString(m))), ), - TrIgnored => { + TestResult::TrIgnored => { self.write_event("test", desc.name.as_slice(), "ignored", exec_time, stdout, None) } - TrAllowedFail => self.write_event( + TestResult::TrAllowedFail => self.write_event( "test", desc.name.as_slice(), "allowed_failure", @@ -125,7 +138,7 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> { None, ), - TrBench(ref bs) => { + TestResult::TrBench(ref bs) => { let median = bs.ns_iter_summ.median as usize; let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; diff --git a/src/libtest/formatters/mod.rs b/src/libtest/formatters/mod.rs index dd202fb3ab6..b6649a3effc 100644 --- a/src/libtest/formatters/mod.rs +++ b/src/libtest/formatters/mod.rs @@ -1,4 +1,14 @@ -use super::*; +use std::{ + io, + io::prelude::Write, +}; + +use crate::{ + types::{TestDesc, TestName}, + time, + test_result::TestResult, + console::{ConsoleTestState}, +}; mod pretty; mod json; @@ -16,7 +26,7 @@ pub(crate) trait OutputFormatter { &mut self, desc: &TestDesc, result: &TestResult, - exec_time: Option<&TestExecTime>, + exec_time: Option<&time::TestExecTime>, stdout: &[u8], state: &ConsoleTestState, ) -> io::Result<()>; diff --git a/src/libtest/formatters/pretty.rs b/src/libtest/formatters/pretty.rs index 2935b4c99ce..2fdbc63d513 100644 --- a/src/libtest/formatters/pretty.rs +++ b/src/libtest/formatters/pretty.rs @@ -1,9 +1,21 @@ -use super::*; +use std::{ + io, + io::prelude::Write, +}; + +use crate::{ + types::TestDesc, + time, + test_result::TestResult, + console::{ConsoleTestState, OutputLocation}, + bench::fmt_bench_samples, +}; +use super::OutputFormatter; pub(crate) struct PrettyFormatter<T> { out: OutputLocation<T>, use_color: bool, - time_options: Option<TestTimeOptions>, + time_options: Option<time::TestTimeOptions>, /// Number of columns to fill when aligning names max_name_len: usize, @@ -17,7 +29,7 @@ impl<T: Write> PrettyFormatter<T> { use_color: bool, max_name_len: usize, is_multithreaded: bool, - time_options: Option<TestTimeOptions>, + time_options: Option<time::TestTimeOptions>, ) -> Self { PrettyFormatter { out, @@ -67,7 +79,7 @@ impl<T: Write> PrettyFormatter<T> { pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> { match self.out { - Pretty(ref mut term) => { + OutputLocation::Pretty(ref mut term) => { if self.use_color { term.fg(color)?; } @@ -77,7 +89,7 @@ impl<T: Write> PrettyFormatter<T> { } term.flush() } - Raw(ref mut stdout) => { + OutputLocation::Raw(ref mut stdout) => { stdout.write_all(word.as_bytes())?; stdout.flush() } @@ -93,7 +105,7 @@ impl<T: Write> PrettyFormatter<T> { fn write_time( &mut self, desc: &TestDesc, - exec_time: Option<&TestExecTime> + exec_time: Option<&time::TestExecTime> ) -> io::Result<()> { if let (Some(opts), Some(time)) = (self.time_options, exec_time) { let time_str = format!(" <{}>", time); @@ -194,7 +206,7 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> { &mut self, desc: &TestDesc, result: &TestResult, - exec_time: Option<&TestExecTime>, + exec_time: Option<&time::TestExecTime>, _: &[u8], _: &ConsoleTestState, ) -> io::Result<()> { @@ -203,15 +215,15 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> { } match *result { - TrOk => self.write_ok()?, - TrFailed | TrFailedMsg(_) => self.write_failed()?, - TrIgnored => self.write_ignored()?, - TrAllowedFail => self.write_allowed_fail()?, - TrBench(ref bs) => { + TestResult::TrOk => self.write_ok()?, + TestResult::TrFailed | TestResult::TrFailedMsg(_) => self.write_failed()?, + TestResult::TrIgnored => self.write_ignored()?, + TestResult::TrAllowedFail => self.write_allowed_fail()?, + TestResult::TrBench(ref bs) => { self.write_bench()?; self.write_plain(&format!(": {}", fmt_bench_samples(bs)))?; } - TrTimedFail => self.write_time_failed()?, + TestResult::TrTimedFail => self.write_time_failed()?, } self.write_time(desc, exec_time)?; @@ -225,7 +237,7 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> { self.write_plain(&format!( "test {} has been running for over {} seconds\n", - desc.name, TEST_WARN_TIMEOUT_S + desc.name, time::TEST_WARN_TIMEOUT_S )) } diff --git a/src/libtest/formatters/terse.rs b/src/libtest/formatters/terse.rs index 8914e7b6b56..fe56157d9c1 100644 --- a/src/libtest/formatters/terse.rs +++ b/src/libtest/formatters/terse.rs @@ -1,4 +1,20 @@ -use super::*; +use std::{ + io, + io::prelude::Write, +}; + +use crate::{ + types::TestDesc, + time, + test_result::TestResult, + types::NamePadding, + console::{ConsoleTestState, OutputLocation}, + bench::fmt_bench_samples, +}; +use super::OutputFormatter; + +// insert a '\n' after 100 tests in quiet mode +const QUIET_MODE_MAX_COLUMN: usize = 100; pub(crate) struct TerseFormatter<T> { out: OutputLocation<T>, @@ -68,7 +84,7 @@ impl<T: Write> TerseFormatter<T> { pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> { match self.out { - Pretty(ref mut term) => { + OutputLocation::Pretty(ref mut term) => { if self.use_color { term.fg(color)?; } @@ -78,7 +94,7 @@ impl<T: Write> TerseFormatter<T> { } term.flush() } - Raw(ref mut stdout) => { + OutputLocation::Raw(ref mut stdout) => { stdout.write_all(word.as_bytes())?; stdout.flush() } @@ -163,7 +179,7 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> { // in order to indicate benchmarks. // When running benchmarks, terse-mode should still print their name as if // it is the Pretty formatter. - if !self.is_multithreaded && desc.name.padding() == PadOnRight { + if !self.is_multithreaded && desc.name.padding() == NamePadding::PadOnRight { self.write_test_name(desc)?; } @@ -174,16 +190,18 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> { &mut self, desc: &TestDesc, result: &TestResult, - _: Option<&TestExecTime>, + _: Option<&time::TestExecTime>, _: &[u8], _: &ConsoleTestState, ) -> io::Result<()> { match *result { - TrOk => self.write_ok(), - TrFailed | TrFailedMsg(_) | TrTimedFail => self.write_failed(), - TrIgnored => self.write_ignored(), - TrAllowedFail => self.write_allowed_fail(), - TrBench(ref bs) => { + TestResult::TrOk => self.write_ok(), + TestResult::TrFailed + | TestResult::TrFailedMsg(_) + | TestResult::TrTimedFail => self.write_failed(), + TestResult::TrIgnored => self.write_ignored(), + TestResult::TrAllowedFail => self.write_allowed_fail(), + TestResult::TrBench(ref bs) => { if self.is_multithreaded { self.write_test_name(desc)?; } @@ -196,7 +214,7 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> { fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> { self.write_plain(&format!( "test {} has been running for over {} seconds\n", - desc.name, TEST_WARN_TIMEOUT_S + desc.name, time::TEST_WARN_TIMEOUT_S )) } diff --git a/src/libtest/helpers/concurrency.rs b/src/libtest/helpers/concurrency.rs new file mode 100644 index 00000000000..61651a927c5 --- /dev/null +++ b/src/libtest/helpers/concurrency.rs @@ -0,0 +1,143 @@ +//! Helper module which helps to determine amount of threads to be used +//! during tests execution. +use std::env; + +#[allow(deprecated)] +pub fn get_concurrency() -> usize { + return match env::var("RUST_TEST_THREADS") { + Ok(s) => { + let opt_n: Option<usize> = s.parse().ok(); + match opt_n { + Some(n) if n > 0 => n, + _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s), + } + } + Err(..) => num_cpus(), + }; + + #[cfg(windows)] + #[allow(nonstandard_style)] + fn num_cpus() -> usize { + #[repr(C)] + struct SYSTEM_INFO { + wProcessorArchitecture: u16, + wReserved: u16, + dwPageSize: u32, + lpMinimumApplicationAddress: *mut u8, + lpMaximumApplicationAddress: *mut u8, + dwActiveProcessorMask: *mut u8, + dwNumberOfProcessors: u32, + dwProcessorType: u32, + dwAllocationGranularity: u32, + wProcessorLevel: u16, + wProcessorRevision: u16, + } + extern "system" { + fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32; + } + unsafe { + let mut sysinfo = std::mem::zeroed(); + GetSystemInfo(&mut sysinfo); + sysinfo.dwNumberOfProcessors as usize + } + } + + #[cfg(target_os = "vxworks")] + fn num_cpus() -> usize { + // FIXME: Implement num_cpus on vxWorks + 1 + } + + #[cfg(target_os = "redox")] + fn num_cpus() -> usize { + // FIXME: Implement num_cpus on Redox + 1 + } + + #[cfg(any( + all(target_arch = "wasm32", not(target_os = "emscripten")), + all(target_vendor = "fortanix", target_env = "sgx") + ))] + fn num_cpus() -> usize { + 1 + } + + #[cfg(any( + target_os = "android", + target_os = "cloudabi", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "solaris", + ))] + fn num_cpus() -> usize { + unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize } + } + + #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] + fn num_cpus() -> usize { + use std::ptr; + + let mut cpus: libc::c_uint = 0; + let mut cpus_size = std::mem::size_of_val(&cpus); + + unsafe { + cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint; + } + if cpus < 1 { + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + unsafe { + libc::sysctl( + mib.as_mut_ptr(), + 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + ptr::null_mut(), + 0, + ); + } + if cpus < 1 { + cpus = 1; + } + } + cpus as usize + } + + #[cfg(target_os = "openbsd")] + fn num_cpus() -> usize { + use std::ptr; + + let mut cpus: libc::c_uint = 0; + let mut cpus_size = std::mem::size_of_val(&cpus); + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + + unsafe { + libc::sysctl( + mib.as_mut_ptr(), + 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + ptr::null_mut(), + 0, + ); + } + if cpus < 1 { + cpus = 1; + } + cpus as usize + } + + #[cfg(target_os = "haiku")] + fn num_cpus() -> usize { + // FIXME: implement + 1 + } + + #[cfg(target_os = "l4re")] + fn num_cpus() -> usize { + // FIXME: implement + 1 + } +} diff --git a/src/libtest/helpers/exit_code.rs b/src/libtest/helpers/exit_code.rs new file mode 100644 index 00000000000..831bef3b118 --- /dev/null +++ b/src/libtest/helpers/exit_code.rs @@ -0,0 +1,20 @@ +//! Helper module to detect subprocess exit code. + +use std::process::ExitStatus; + +#[cfg(not(unix))] +pub fn get_exit_code(status: ExitStatus) -> Result<i32, String> { + status.code().ok_or("received no exit code from child process".into()) +} + +#[cfg(unix)] +pub fn get_exit_code(status: ExitStatus) -> Result<i32, String> { + use std::os::unix::process::ExitStatusExt; + match status.code() { + Some(code) => Ok(code), + None => match status.signal() { + Some(signal) => Err(format!("child process exited with signal {}", signal)), + None => Err("child process exited with unknown signal".into()), + } + } +} diff --git a/src/libtest/helpers/isatty.rs b/src/libtest/helpers/isatty.rs new file mode 100644 index 00000000000..6e4954778e6 --- /dev/null +++ b/src/libtest/helpers/isatty.rs @@ -0,0 +1,33 @@ +//! Helper module which provides a function to test +//! if stdout is a tty. + +#[cfg(any( + target_os = "cloudabi", + all(target_arch = "wasm32", not(target_os = "emscripten")), + all(target_vendor = "fortanix", target_env = "sgx") +))] +pub fn stdout_isatty() -> bool { + // FIXME: Implement isatty on SGX + false +} +#[cfg(unix)] +pub fn stdout_isatty() -> bool { + unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 } +} +#[cfg(windows)] +pub fn stdout_isatty() -> bool { + type DWORD = u32; + type BOOL = i32; + type HANDLE = *mut u8; + type LPDWORD = *mut u32; + const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD; + extern "system" { + fn GetStdHandle(which: DWORD) -> HANDLE; + fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL; + } + unsafe { + let handle = GetStdHandle(STD_OUTPUT_HANDLE); + let mut out = 0; + GetConsoleMode(handle, &mut out) != 0 + } +} diff --git a/src/libtest/helpers/metrics.rs b/src/libtest/helpers/metrics.rs new file mode 100644 index 00000000000..f77a23e6875 --- /dev/null +++ b/src/libtest/helpers/metrics.rs @@ -0,0 +1,50 @@ +//! Benchmark metrics. +use std::collections::BTreeMap; + +#[derive(Clone, PartialEq, Debug, Copy)] +pub struct Metric { + value: f64, + noise: f64, +} + +impl Metric { + pub fn new(value: f64, noise: f64) -> Metric { + Metric { value, noise } + } +} + +#[derive(Clone, PartialEq)] +pub struct MetricMap(BTreeMap<String, Metric>); + +impl MetricMap { + pub fn new() -> MetricMap { + MetricMap(BTreeMap::new()) + } + + /// Insert a named `value` (+/- `noise`) metric into the map. The value + /// must be non-negative. The `noise` indicates the uncertainty of the + /// metric, which doubles as the "noise range" of acceptable + /// pairwise-regressions on this named value, when comparing from one + /// metric to the next using `compare_to_old`. + /// + /// If `noise` is positive, then it means this metric is of a value + /// you want to see grow smaller, so a change larger than `noise` in the + /// positive direction represents a regression. + /// + /// If `noise` is negative, then it means this metric is of a value + /// you want to see grow larger, so a change larger than `noise` in the + /// negative direction represents a regression. + pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) { + let m = Metric { value, noise }; + self.0.insert(name.to_owned(), m); + } + + pub fn fmt_metrics(&self) -> String { + let v = self + .0 + .iter() + .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise)) + .collect::<Vec<_>>(); + v.join(", ") + } +} diff --git a/src/libtest/helpers/mod.rs b/src/libtest/helpers/mod.rs new file mode 100644 index 00000000000..6a2ef6086cb --- /dev/null +++ b/src/libtest/helpers/mod.rs @@ -0,0 +1,8 @@ +//! Module with common helpers not directly related to tests +//! but used in `libtest`. + +pub mod concurrency; +pub mod isatty; +pub mod metrics; +pub mod sink; +pub mod exit_code; diff --git a/src/libtest/helpers/sink.rs b/src/libtest/helpers/sink.rs new file mode 100644 index 00000000000..aa7fe248773 --- /dev/null +++ b/src/libtest/helpers/sink.rs @@ -0,0 +1,24 @@ +//! Module providing a helper structure to capture output in subprocesses. + +use std::{ + io, + io::prelude::Write, + sync::{Arc, Mutex}, +}; + +pub struct Sink(Arc<Mutex<Vec<u8>>>); + +impl Sink { + pub fn new_boxed(data: &Arc<Mutex<Vec<u8>>>) -> Box<Self> { + Box::new(Self(data.clone())) + } +} + +impl Write for Sink { + fn write(&mut self, data: &[u8]) -> io::Result<usize> { + Write::write(&mut *self.0.lock().unwrap(), data) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 4c3cbeb4acc..8c1e9f1722a 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -30,320 +30,81 @@ #![feature(termination_trait_lib)] #![feature(test)] -use getopts; -#[cfg(any(unix, target_os = "cloudabi"))] -extern crate libc; -use term; - +// Public reexports pub use self::ColorConfig::*; -use self::NamePadding::*; -use self::OutputLocation::*; -use self::TestEvent::*; -pub use self::TestFn::*; -pub use self::TestName::*; -pub use self::TestResult::*; - -use std::any::Any; -use std::borrow::Cow; -use std::cmp; -use std::collections::BTreeMap; -use std::env; -use std::fmt; -use std::fs::File; -use std::io; -use std::io::prelude::*; -use std::panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo}; -use std::path::PathBuf; -use std::process; -use std::process::{ExitStatus, Command, Termination}; -use std::str::FromStr; -use std::sync::mpsc::{channel, Sender}; -use std::sync::{Arc, Mutex}; -use std::thread; -use std::time::{Duration, Instant}; - -#[cfg(test)] -mod tests; - -const TEST_WARN_TIMEOUT_S: u64 = 60; -const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode - -const SECONDARY_TEST_INVOKER_VAR: &'static str = "__RUST_TEST_INVOKE"; - -// Return codes for secondary process. -// Start somewhere other than 0 so we know the return code means what we think -// it means. -const TR_OK: i32 = 50; -const TR_FAILED: i32 = 51; - -/// This small module contains constants used by `report-time` option. -/// Those constants values will be used if corresponding environment variables are not set. -/// -/// To override values for unit-tests, use a constant `RUST_TEST_TIME_UNIT`, -/// To override values for integration tests, use a constant `RUST_TEST_TIME_INTEGRATION`, -/// To override values for doctests, use a constant `RUST_TEST_TIME_DOCTEST`. -/// -/// Example of the expected format is `RUST_TEST_TIME_xxx=100,200`, where 100 means -/// warn time, and 200 means critical time. -pub mod time_constants { - use std::time::Duration; - use super::TEST_WARN_TIMEOUT_S; - - /// Environment variable for overriding default threshold for unit-tests. - pub const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT"; - - // Unit tests are supposed to be really quick. - pub const UNIT_WARN: Duration = Duration::from_millis(50); - pub const UNIT_CRITICAL: Duration = Duration::from_millis(100); - - /// Environment variable for overriding default threshold for unit-tests. - pub const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION"; - - // Integration tests may have a lot of work, so they can take longer to execute. - pub const INTEGRATION_WARN: Duration = Duration::from_millis(500); - pub const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000); - - /// Environment variable for overriding default threshold for unit-tests. - pub const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST"; - - // Doctests are similar to integration tests, because they can include a lot of - // initialization code. - pub const DOCTEST_WARN: Duration = INTEGRATION_WARN; - pub const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL; - - // Do not suppose anything about unknown tests, base limits on the - // `TEST_WARN_TIMEOUT_S` constant. - pub const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S); - pub const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2); -} - -// to be used by rustc to compile tests in libtest +pub use self::types::*; +pub use self::types::TestName::*; +pub use self::options::{ColorConfig, Options, OutputFormat, RunIgnored, ShouldPanic}; +pub use self::bench::{Bencher, black_box}; +pub use self::console::run_tests_console; +pub use cli::TestOpts; + +// Module to be used by rustc to compile tests in libtest pub mod test { pub use crate::{ - assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static, - Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, RunStrategy, - ShouldPanic, StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, - TestOpts, TestTimeOptions, TestType, TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk, + bench::Bencher, + cli::{parse_opts, TestOpts}, + helpers::metrics::{Metric, MetricMap}, + options::{ShouldPanic, Options, RunIgnored, RunStrategy}, + test_result::{TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk}, + time::{TestTimeOptions, TestExecTime}, + types::{ + DynTestFn, DynTestName, StaticBenchFn, StaticTestFn, StaticTestName, + TestDesc, TestDescAndFn, TestName, TestType, + }, + assert_test_result, filter_tests, run_test, test_main, test_main_static, }; } -mod formatters; -pub mod stats; - -use crate::formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter}; - -/// Whether to execute tests concurrently or not -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Concurrent { - Yes, - No, -} - -/// Type of the test according to the [rust book](https://doc.rust-lang.org/cargo/guide/tests.html) -/// conventions. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum TestType { - /// Unit-tests are expected to be in the `src` folder of the crate. - UnitTest, - /// Integration-style tests are expected to be in the `tests` folder of the crate. - IntegrationTest, - /// Doctests are created by the `librustdoc` manually, so it's a different type of test. - DocTest, - /// Tests for the sources that don't follow the project layout convention - /// (e.g. tests in raw `main.rs` compiled by calling `rustc --test` directly). - Unknown, -} - -// The name of a test. By convention this follows the rules for rust -// paths; i.e., it should be a series of identifiers separated by double -// colons. This way if some test runner wants to arrange the tests -// hierarchically it may. - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum TestName { - StaticTestName(&'static str), - DynTestName(String), - AlignedTestName(Cow<'static, str>, NamePadding), -} -impl TestName { - fn as_slice(&self) -> &str { - match *self { - StaticTestName(s) => s, - DynTestName(ref s) => s, - AlignedTestName(ref s, _) => &*s, - } - } - - fn padding(&self) -> NamePadding { - match self { - &AlignedTestName(_, p) => p, - _ => PadNone, - } - } - - fn with_padding(&self, padding: NamePadding) -> TestName { - let name = match self { - &TestName::StaticTestName(name) => Cow::Borrowed(name), - &TestName::DynTestName(ref name) => Cow::Owned(name.clone()), - &TestName::AlignedTestName(ref name, _) => name.clone(), - }; - - TestName::AlignedTestName(name, padding) - } -} -impl fmt::Display for TestName { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), f) - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum NamePadding { - PadNone, - PadOnRight, -} - -impl TestDesc { - fn padded_name(&self, column_count: usize, align: NamePadding) -> String { - let mut name = String::from(self.name.as_slice()); - let fill = column_count.saturating_sub(name.len()); - let pad = " ".repeat(fill); - match align { - PadNone => name, - PadOnRight => { - name.push_str(&pad); - name - } - } - } -} - -/// Represents a benchmark function. -pub trait TDynBenchFn: Send { - fn run(&self, harness: &mut Bencher); -} - -// A function that runs a test. If the function returns successfully, -// the test succeeds; if the function panics then the test fails. We -// may need to come up with a more clever definition of test in order -// to support isolation of tests into threads. -pub enum TestFn { - StaticTestFn(fn()), - StaticBenchFn(fn(&mut Bencher)), - DynTestFn(Box<dyn FnOnce() + Send>), - DynBenchFn(Box<dyn TDynBenchFn + 'static>), -} - -impl TestFn { - fn padding(&self) -> NamePadding { - match *self { - StaticTestFn(..) => PadNone, - StaticBenchFn(..) => PadOnRight, - DynTestFn(..) => PadNone, - DynBenchFn(..) => PadOnRight, - } - } -} - -impl fmt::Debug for TestFn { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match *self { - StaticTestFn(..) => "StaticTestFn(..)", - StaticBenchFn(..) => "StaticBenchFn(..)", - DynTestFn(..) => "DynTestFn(..)", - DynBenchFn(..) => "DynBenchFn(..)", - }) - } -} +use std::{ + env, + io, + io::prelude::Write, + panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo}, + process, + process::{Command, Termination}, + sync::mpsc::{channel, Sender}, + sync::{Arc, Mutex}, + thread, + time::{Duration, Instant}, +}; -/// Manager of the benchmarking runs. -/// -/// This is fed into functions marked with `#[bench]` to allow for -/// set-up & tear-down before running a piece of code repeatedly via a -/// call to `iter`. -#[derive(Clone)] -pub struct Bencher { - mode: BenchMode, - summary: Option<stats::Summary>, - pub bytes: u64, -} - -#[derive(Clone, PartialEq, Eq)] -pub enum BenchMode { - Auto, - Single, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum ShouldPanic { - No, - Yes, - YesWithMessage(&'static str), -} - -// The definition of a single test. A test runner will run a list of -// these. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct TestDesc { - pub name: TestName, - pub ignore: bool, - pub should_panic: ShouldPanic, - pub allow_fail: bool, - pub test_type: TestType, -} - -#[derive(Debug)] -pub struct TestDescAndFn { - pub desc: TestDesc, - pub testfn: TestFn, -} - -#[derive(Clone, PartialEq, Debug, Copy)] -pub struct Metric { - value: f64, - noise: f64, -} - -impl Metric { - pub fn new(value: f64, noise: f64) -> Metric { - Metric { value, noise } - } -} +pub mod stats; +pub mod bench; +mod formatters; +mod cli; +mod console; +mod event; +mod helpers; +mod time; +mod types; +mod options; +mod test_result; -/// In case we want to add other options as well, just add them in this struct. -#[derive(Copy, Clone, Debug)] -pub struct Options { - display_output: bool, - panic_abort: bool, -} +#[cfg(test)] +mod tests; -impl Options { - pub fn new() -> Options { - Options { - display_output: false, - panic_abort: false, - } - } +use test_result::*; +use time::TestExecTime; +use options::{RunStrategy, Concurrent}; +use event::{CompletedTest, TestEvent}; +use helpers::sink::Sink; +use helpers::concurrency::get_concurrency; +use helpers::exit_code::get_exit_code; - pub fn display_output(mut self, display_output: bool) -> Options { - self.display_output = display_output; - self - } +// Process exit code to be used to indicate test failures. +const ERROR_EXIT_CODE: i32 = 101; - pub fn panic_abort(mut self, panic_abort: bool) -> Options { - self.panic_abort = panic_abort; - self - } -} +const SECONDARY_TEST_INVOKER_VAR: &'static str = "__RUST_TEST_INVOKE"; // The default console test runner. It accepts the command line // arguments and a vector of test_descs. pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Options>) { - let mut opts = match parse_opts(args) { + let mut opts = match cli::parse_opts(args) { Some(Ok(o)) => o, Some(Err(msg)) => { eprintln!("error: {}", msg); - process::exit(101); + process::exit(ERROR_EXIT_CODE); } None => return, }; @@ -351,17 +112,17 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt opts.options = options; } if opts.list { - if let Err(e) = list_tests_console(&opts, tests) { + if let Err(e) = console::list_tests_console(&opts, tests) { eprintln!("error: io error when listing tests: {:?}", e); - process::exit(101); + process::exit(ERROR_EXIT_CODE); } } else { - match run_tests_console(&opts, tests) { + match console::run_tests_console(&opts, tests) { Ok(true) => {} - Ok(false) => process::exit(101), + Ok(false) => process::exit(ERROR_EXIT_CODE), Err(e) => { eprintln!("error: io error when listing tests: {:?}", e); - process::exit(101); + process::exit(ERROR_EXIT_CODE); } } } @@ -440,938 +201,11 @@ pub fn assert_test_result<T: Termination>(result: T) { ); } -#[derive(Copy, Clone, Debug)] -pub enum ColorConfig { - AutoColor, - AlwaysColor, - NeverColor, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum OutputFormat { - Pretty, - Terse, - Json, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum RunIgnored { - Yes, - No, - Only, -} - -/// Structure denoting time limits for test execution. -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub struct TimeThreshold { - pub warn: Duration, - pub critical: Duration, -} - -impl TimeThreshold { - /// Creates a new `TimeThreshold` instance with provided durations. - pub fn new(warn: Duration, critical: Duration) -> Self { - Self { - warn, - critical, - } - } - - /// Attempts to create a `TimeThreshold` instance with values obtained - /// from the environment variable, and returns `None` if the variable - /// is not set. - /// Environment variable format is expected to match `\d+,\d+`. - /// - /// # Panics - /// - /// Panics if variable with provided name is set but contains inappropriate - /// value. - pub fn from_env_var(env_var_name: &str) -> Option<Self> { - let durations_str = env::var(env_var_name).ok()?; - - // Split string into 2 substrings by comma and try to parse numbers. - let mut durations = durations_str - .splitn(2, ',') - .map(|v| { - u64::from_str(v).unwrap_or_else(|_| { - panic!( - "Duration value in variable {} is expected to be a number, but got {}", - env_var_name, v - ) - }) - }); - - // Callback to be called if the environment variable has unexpected structure. - let panic_on_incorrect_value = || { - panic!( - "Duration variable {} expected to have 2 numbers separated by comma, but got {}", - env_var_name, durations_str - ); - }; - - let (warn, critical) = ( - durations.next().unwrap_or_else(panic_on_incorrect_value), - durations.next().unwrap_or_else(panic_on_incorrect_value) - ); - - if warn > critical { - panic!("Test execution warn time should be less or equal to the critical time"); - } - - Some(Self::new(Duration::from_millis(warn), Duration::from_millis(critical))) - } -} - -/// Structure with parameters for calculating test execution time. -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub struct TestTimeOptions { - /// Denotes if the test critical execution time limit excess should be considered - /// a test failure. - pub error_on_excess: bool, - pub colored: bool, - pub unit_threshold: TimeThreshold, - pub integration_threshold: TimeThreshold, - pub doctest_threshold: TimeThreshold, -} - -impl TestTimeOptions { - pub fn new_from_env(error_on_excess: bool, colored: bool) -> Self { - let unit_threshold = - TimeThreshold::from_env_var(time_constants::UNIT_ENV_NAME) - .unwrap_or_else(Self::default_unit); - - let integration_threshold = - TimeThreshold::from_env_var(time_constants::INTEGRATION_ENV_NAME) - .unwrap_or_else(Self::default_integration); - - let doctest_threshold = - TimeThreshold::from_env_var(time_constants::DOCTEST_ENV_NAME) - .unwrap_or_else(Self::default_doctest); - - Self { - error_on_excess, - colored, - unit_threshold, - integration_threshold, - doctest_threshold, - } - } - - pub fn is_warn(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool { - exec_time.0 >= self.warn_time(test) - } - - pub fn is_critical(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool { - exec_time.0 >= self.critical_time(test) - } - - fn warn_time(&self, test: &TestDesc) -> Duration { - match test.test_type { - TestType::UnitTest => self.unit_threshold.warn, - TestType::IntegrationTest => self.integration_threshold.warn, - TestType::DocTest => self.doctest_threshold.warn, - TestType::Unknown => time_constants::UNKNOWN_WARN, - } - } - - fn critical_time(&self, test: &TestDesc) -> Duration { - match test.test_type { - TestType::UnitTest => self.unit_threshold.critical, - TestType::IntegrationTest => self.integration_threshold.critical, - TestType::DocTest => self.doctest_threshold.critical, - TestType::Unknown => time_constants::UNKNOWN_CRITICAL, - } - } - - fn default_unit() -> TimeThreshold { - TimeThreshold::new(time_constants::UNIT_WARN, time_constants::UNIT_CRITICAL) - } - - fn default_integration() -> TimeThreshold { - TimeThreshold::new(time_constants::INTEGRATION_WARN, time_constants::INTEGRATION_CRITICAL) - } - - fn default_doctest() -> TimeThreshold { - TimeThreshold::new(time_constants::DOCTEST_WARN, time_constants::DOCTEST_CRITICAL) - } -} - -#[derive(Debug)] -pub struct TestOpts { - pub list: bool, - pub filter: Option<String>, - pub filter_exact: bool, - pub exclude_should_panic: bool, - pub run_ignored: RunIgnored, - pub run_tests: bool, - pub bench_benchmarks: bool, - pub logfile: Option<PathBuf>, - pub nocapture: bool, - pub color: ColorConfig, - pub format: OutputFormat, - pub test_threads: Option<usize>, - pub skip: Vec<String>, - pub time_options: Option<TestTimeOptions>, - pub options: Options, -} - -/// Result of parsing the options. -pub type OptRes = Result<TestOpts, String>; -/// Result of parsing the option part. -type OptPartRes<T> = Result<Option<T>, String>; - -fn optgroups() -> getopts::Options { - let mut opts = getopts::Options::new(); - opts.optflag("", "include-ignored", "Run ignored and not ignored tests") - .optflag("", "ignored", "Run only ignored tests") - .optflag("", "exclude-should-panic", "Excludes tests marked as should_panic") - .optflag("", "test", "Run tests and not benchmarks") - .optflag("", "bench", "Run benchmarks instead of tests") - .optflag("", "list", "List all tests and benchmarks") - .optflag("h", "help", "Display this message (longer with --help)") - .optopt( - "", - "logfile", - "Write logs to the specified file instead \ - of stdout", - "PATH", - ) - .optflag( - "", - "nocapture", - "don't capture stdout/stderr of each \ - task, allow printing directly", - ) - .optopt( - "", - "test-threads", - "Number of threads used for running tests \ - in parallel", - "n_threads", - ) - .optmulti( - "", - "skip", - "Skip tests whose names contain FILTER (this flag can \ - be used multiple times)", - "FILTER", - ) - .optflag( - "q", - "quiet", - "Display one character per test instead of one line. \ - Alias to --format=terse", - ) - .optflag( - "", - "exact", - "Exactly match filters rather than by substring", - ) - .optopt( - "", - "color", - "Configure coloring of output: - auto = colorize if stdout is a tty and tests are run on serially (default); - always = always colorize output; - never = never colorize output;", - "auto|always|never", - ) - .optopt( - "", - "format", - "Configure formatting of output: - pretty = Print verbose output; - terse = Display one character per test; - json = Output a json document", - "pretty|terse|json", - ) - .optflag( - "", - "show-output", - "Show captured stdout of successful tests" - ) - .optopt( - "Z", - "", - "Enable nightly-only flags: - unstable-options = Allow use of experimental features", - "unstable-options", - ) - .optflagopt( - "", - "report-time", - "Show execution time of each test. Awailable values: - plain = do not colorize the execution time (default); - colored = colorize output according to the `color` parameter value; - - Threshold values for colorized output can be configured via - `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and - `RUST_TEST_TIME_DOCTEST` environment variables. - - Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`. - - Not available for --format=terse", - "plain|colored" - ) - .optflag( - "", - "ensure-time", - "Treat excess of the test execution time limit as error. - - Threshold values for this option can be configured via - `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and - `RUST_TEST_TIME_DOCTEST` environment variables. - - Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`. - - `CRITICAL_TIME` here means the limit that should not be exceeded by test. - " - ); - return opts; -} - -fn usage(binary: &str, options: &getopts::Options) { - let message = format!("Usage: {} [OPTIONS] [FILTER]", binary); - println!( - r#"{usage} - -The FILTER string is tested against the name of all tests, and only those -tests whose names contain the filter are run. - -By default, all tests are run in parallel. This can be altered with the ---test-threads flag or the RUST_TEST_THREADS environment variable when running -tests (set it to 1). - -All tests have their standard output and standard error captured by default. -This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE -environment variable to a value other than "0". Logging is not captured by default. - -Test Attributes: - - `#[test]` - Indicates a function is a test to be run. This function - takes no arguments. - `#[bench]` - Indicates a function is a benchmark to be run. This - function takes one argument (test::Bencher). - `#[should_panic]` - This function (also labeled with `#[test]`) will only pass if - the code causes a panic (an assertion failure or panic!) - A message may be provided, which the failure string must - contain: #[should_panic(expected = "foo")]. - `#[ignore]` - When applied to a function which is already attributed as a - test, then the test runner will ignore these tests during - normal test runs. Running with --ignored or --include-ignored will run - these tests."#, - usage = options.usage(&message) - ); -} - -// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566 -fn is_nightly() -> bool { - // Whether this is a feature-staged build, i.e., on the beta or stable channel - let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); - // Whether we should enable unstable features for bootstrapping - let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); - - bootstrap || !disable_unstable_features -} - -// Gets the option value and checks if unstable features are enabled. -macro_rules! unstable_optflag { - ($matches:ident, $allow_unstable:ident, $option_name:literal) => {{ - let opt = $matches.opt_present($option_name); - if !$allow_unstable && opt { - return Some(Err(format!( - "The \"{}\" flag is only accepted on the nightly compiler", - $option_name - ))); - } - - opt - }}; -} - -// Gets the CLI options assotiated with `report-time` feature. -fn get_time_options( - matches: &getopts::Matches, - allow_unstable: bool) --> Option<OptPartRes<TestTimeOptions>> { - let report_time = unstable_optflag!(matches, allow_unstable, "report-time"); - let colored_opt_str = matches.opt_str("report-time"); - let mut report_time_colored = report_time && colored_opt_str == Some("colored".into()); - let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time"); - - // If `ensure-test-time` option is provided, time output is enforced, - // so user won't be confused if any of tests will silently fail. - let options = if report_time || ensure_test_time { - if ensure_test_time && !report_time { - report_time_colored = true; - } - Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored)) - } else { - None - }; - - Some(Ok(options)) -} - -// Parses command line arguments into test options -pub fn parse_opts(args: &[String]) -> Option<OptRes> { - let mut allow_unstable = false; - let opts = optgroups(); - let args = args.get(1..).unwrap_or(args); - let matches = match opts.parse(args) { - Ok(m) => m, - Err(f) => return Some(Err(f.to_string())), - }; - - if let Some(opt) = matches.opt_str("Z") { - if !is_nightly() { - return Some(Err( - "the option `Z` is only accepted on the nightly compiler".into(), - )); - } - - match &*opt { - "unstable-options" => { - allow_unstable = true; - } - _ => { - return Some(Err("Unrecognized option to `Z`".into())); - } - } - }; - - if matches.opt_present("h") { - usage(&args[0], &opts); - return None; - } - - let filter = if !matches.free.is_empty() { - Some(matches.free[0].clone()) - } else { - None - }; - - let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic"); - - let include_ignored = unstable_optflag!(matches, allow_unstable, "include-ignored"); - - let run_ignored = match (include_ignored, matches.opt_present("ignored")) { - (true, true) => { - return Some(Err( - "the options --include-ignored and --ignored are mutually exclusive".into(), - )); - } - (true, false) => RunIgnored::Yes, - (false, true) => RunIgnored::Only, - (false, false) => RunIgnored::No, - }; - let quiet = matches.opt_present("quiet"); - let exact = matches.opt_present("exact"); - let list = matches.opt_present("list"); - - let logfile = matches.opt_str("logfile"); - let logfile = logfile.map(|s| PathBuf::from(&s)); - - let bench_benchmarks = matches.opt_present("bench"); - let run_tests = !bench_benchmarks || matches.opt_present("test"); - - let mut nocapture = matches.opt_present("nocapture"); - if !nocapture { - nocapture = match env::var("RUST_TEST_NOCAPTURE") { - Ok(val) => &val != "0", - Err(_) => false, - }; - } - - let time_options = match get_time_options(&matches, allow_unstable) { - Some(Ok(val)) => val, - Some(Err(e)) => return Some(Err(e)), - None => panic!("Unexpected output from `get_time_options`"), - }; - - let test_threads = match matches.opt_str("test-threads") { - Some(n_str) => match n_str.parse::<usize>() { - Ok(0) => return Some(Err("argument for --test-threads must not be 0".to_string())), - Ok(n) => Some(n), - Err(e) => { - return Some(Err(format!( - "argument for --test-threads must be a number > 0 \ - (error: {})", - e - ))); - } - }, - None => None, - }; - - let color = match matches.opt_str("color").as_ref().map(|s| &**s) { - Some("auto") | None => AutoColor, - Some("always") => AlwaysColor, - Some("never") => NeverColor, - - Some(v) => { - return Some(Err(format!( - "argument for --color must be auto, always, or never (was \ - {})", - v - ))); - } - }; - - let format = match matches.opt_str("format").as_ref().map(|s| &**s) { - None if quiet => OutputFormat::Terse, - Some("pretty") | None => OutputFormat::Pretty, - Some("terse") => OutputFormat::Terse, - Some("json") => { - if !allow_unstable { - return Some(Err( - "The \"json\" format is only accepted on the nightly compiler".into(), - )); - } - OutputFormat::Json - } - - Some(v) => { - return Some(Err(format!( - "argument for --format must be pretty, terse, or json (was \ - {})", - v - ))); - } - }; - - let test_opts = TestOpts { - list, - filter, - filter_exact: exact, - exclude_should_panic, - run_ignored, - run_tests, - bench_benchmarks, - logfile, - nocapture, - color, - format, - test_threads, - skip: matches.opt_strs("skip"), - time_options, - options: Options::new().display_output(matches.opt_present("show-output")), - }; - - Some(Ok(test_opts)) -} - -#[derive(Debug, Clone, PartialEq)] -pub struct BenchSamples { - ns_iter_summ: stats::Summary, - mb_s: usize, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum TestResult { - TrOk, - TrFailed, - TrFailedMsg(String), - TrIgnored, - TrAllowedFail, - TrBench(BenchSamples), - TrTimedFail, -} - -unsafe impl Send for TestResult {} - -/// The meassured execution time of a unit test. -#[derive(Clone, PartialEq)] -pub struct TestExecTime(Duration); - -impl fmt::Display for TestExecTime { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:.3}s", self.0.as_secs_f64()) - } -} - -enum OutputLocation<T> { - Pretty(Box<term::StdoutTerminal>), - Raw(T), -} - -impl<T: Write> Write for OutputLocation<T> { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - match *self { - Pretty(ref mut term) => term.write(buf), - Raw(ref mut stdout) => stdout.write(buf), - } - } - - fn flush(&mut self) -> io::Result<()> { - match *self { - Pretty(ref mut term) => term.flush(), - Raw(ref mut stdout) => stdout.flush(), - } - } -} - -struct ConsoleTestState { - log_out: Option<File>, - total: usize, - passed: usize, - failed: usize, - ignored: usize, - allowed_fail: usize, - filtered_out: usize, - measured: usize, - metrics: MetricMap, - failures: Vec<(TestDesc, Vec<u8>)>, - not_failures: Vec<(TestDesc, Vec<u8>)>, - time_failures: Vec<(TestDesc, Vec<u8>)>, - options: Options, -} - -impl ConsoleTestState { - pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> { - let log_out = match opts.logfile { - Some(ref path) => Some(File::create(path)?), - None => None, - }; - - Ok(ConsoleTestState { - log_out, - total: 0, - passed: 0, - failed: 0, - ignored: 0, - allowed_fail: 0, - filtered_out: 0, - measured: 0, - metrics: MetricMap::new(), - failures: Vec::new(), - not_failures: Vec::new(), - time_failures: Vec::new(), - options: opts.options, - }) - } - - pub fn write_log<F, S>( - &mut self, - msg: F, - ) -> io::Result<()> - where - S: AsRef<str>, - F: FnOnce() -> S, - { - match self.log_out { - None => Ok(()), - Some(ref mut o) => { - let msg = msg(); - let msg = msg.as_ref(); - o.write_all(msg.as_bytes()) - }, - } - } - - pub fn write_log_result(&mut self,test: &TestDesc, - result: &TestResult, - exec_time: Option<&TestExecTime>, - ) -> io::Result<()> { - self.write_log(|| format!( - "{} {}", - match *result { - TrOk => "ok".to_owned(), - TrFailed => "failed".to_owned(), - TrFailedMsg(ref msg) => format!("failed: {}", msg), - TrIgnored => "ignored".to_owned(), - TrAllowedFail => "failed (allowed)".to_owned(), - TrBench(ref bs) => fmt_bench_samples(bs), - TrTimedFail => "failed (time limit exceeded)".to_owned(), - }, - test.name, - ))?; - if let Some(exec_time) = exec_time { - self.write_log(|| format!(" <{}>", exec_time))?; - } - self.write_log(|| "\n") - } - - fn current_test_count(&self) -> usize { - self.passed + self.failed + self.ignored + self.measured + self.allowed_fail - } -} - -// Format a number with thousands separators -fn fmt_thousands_sep(mut n: usize, sep: char) -> String { - use std::fmt::Write; - let mut output = String::new(); - let mut trailing = false; - for &pow in &[9, 6, 3, 0] { - let base = 10_usize.pow(pow); - if pow == 0 || trailing || n / base != 0 { - if !trailing { - output.write_fmt(format_args!("{}", n / base)).unwrap(); - } else { - output.write_fmt(format_args!("{:03}", n / base)).unwrap(); - } - if pow != 0 { - output.push(sep); - } - trailing = true; - } - n %= base; - } - - output -} - -pub fn fmt_bench_samples(bs: &BenchSamples) -> String { - use std::fmt::Write; - let mut output = String::new(); - - let median = bs.ns_iter_summ.median as usize; - let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; - - output - .write_fmt(format_args!( - "{:>11} ns/iter (+/- {})", - fmt_thousands_sep(median, ','), - fmt_thousands_sep(deviation, ',') - )) - .unwrap(); - if bs.mb_s != 0 { - output - .write_fmt(format_args!(" = {} MB/s", bs.mb_s)) - .unwrap(); - } - output -} - -// List the tests to console, and optionally to logfile. Filters are honored. -pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> { - let mut output = match term::stdout() { - None => Raw(io::stdout()), - Some(t) => Pretty(t), - }; - - let quiet = opts.format == OutputFormat::Terse; - let mut st = ConsoleTestState::new(opts)?; - - let mut ntest = 0; - let mut nbench = 0; - - for test in filter_tests(&opts, tests) { - use crate::TestFn::*; - - let TestDescAndFn { - desc: TestDesc { name, .. }, - testfn, - } = test; - - let fntype = match testfn { - StaticTestFn(..) | DynTestFn(..) => { - ntest += 1; - "test" - } - StaticBenchFn(..) | DynBenchFn(..) => { - nbench += 1; - "benchmark" - } - }; - - writeln!(output, "{}: {}", name, fntype)?; - st.write_log(|| format!("{} {}\n", fntype, name))?; - } - - fn plural(count: u32, s: &str) -> String { - match count { - 1 => format!("{} {}", 1, s), - n => format!("{} {}s", n, s), - } - } - - if !quiet { - if ntest != 0 || nbench != 0 { - writeln!(output, "")?; - } - - writeln!( - output, - "{}, {}", - plural(ntest, "test"), - plural(nbench, "benchmark") - )?; - } - - Ok(()) -} - -// A simple console test runner -pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> { - fn callback( - event: &TestEvent, - st: &mut ConsoleTestState, - out: &mut dyn OutputFormatter, - ) -> io::Result<()> { - match (*event).clone() { - TeFiltered(ref filtered_tests) => { - st.total = filtered_tests.len(); - out.write_run_start(filtered_tests.len()) - } - TeFilteredOut(filtered_out) => Ok(st.filtered_out = filtered_out), - TeWait(ref test) => out.write_test_start(test), - TeTimeout(ref test) => out.write_timeout(test), - TeResult(test, result, exec_time, stdout) => { - st.write_log_result(&test, &result, exec_time.as_ref())?; - out.write_result(&test, &result, exec_time.as_ref(), &*stdout, &st)?; - match result { - TrOk => { - st.passed += 1; - st.not_failures.push((test, stdout)); - } - TrIgnored => st.ignored += 1, - TrAllowedFail => st.allowed_fail += 1, - TrBench(bs) => { - st.metrics.insert_metric( - test.name.as_slice(), - bs.ns_iter_summ.median, - bs.ns_iter_summ.max - bs.ns_iter_summ.min, - ); - st.measured += 1 - } - TrFailed => { - st.failed += 1; - st.failures.push((test, stdout)); - } - TrFailedMsg(msg) => { - st.failed += 1; - let mut stdout = stdout; - stdout.extend_from_slice(format!("note: {}", msg).as_bytes()); - st.failures.push((test, stdout)); - } - TrTimedFail => { - st.failed += 1; - st.time_failures.push((test, stdout)); - } - } - Ok(()) - } - } - } - - let output = match term::stdout() { - None => Raw(io::stdout()), - Some(t) => Pretty(t), - }; - - let max_name_len = tests - .iter() - .max_by_key(|t| len_if_padded(*t)) - .map(|t| t.desc.name.as_slice().len()) - .unwrap_or(0); - - let is_multithreaded = opts.test_threads.unwrap_or_else(get_concurrency) > 1; - - let mut out: Box<dyn OutputFormatter> = match opts.format { - OutputFormat::Pretty => Box::new(PrettyFormatter::new( - output, - use_color(opts), - max_name_len, - is_multithreaded, - opts.time_options, - )), - OutputFormat::Terse => Box::new(TerseFormatter::new( - output, - use_color(opts), - max_name_len, - is_multithreaded, - )), - OutputFormat::Json => Box::new(JsonFormatter::new(output)), - }; - let mut st = ConsoleTestState::new(opts)?; - fn len_if_padded(t: &TestDescAndFn) -> usize { - match t.testfn.padding() { - PadNone => 0, - PadOnRight => t.desc.name.as_slice().len(), - } - } - - run_tests(opts, tests, |x| callback(&x, &mut st, &mut *out))?; - - assert!(st.current_test_count() == st.total); - - return out.write_run_finish(&st); -} - -fn use_color(opts: &TestOpts) -> bool { - match opts.color { - AutoColor => !opts.nocapture && stdout_isatty(), - AlwaysColor => true, - NeverColor => false, - } -} - -#[cfg(any( - target_os = "cloudabi", - all(target_arch = "wasm32", not(target_os = "emscripten")), - all(target_vendor = "fortanix", target_env = "sgx") -))] -fn stdout_isatty() -> bool { - // FIXME: Implement isatty on SGX - false -} -#[cfg(unix)] -fn stdout_isatty() -> bool { - unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 } -} -#[cfg(windows)] -fn stdout_isatty() -> bool { - type DWORD = u32; - type BOOL = i32; - type HANDLE = *mut u8; - type LPDWORD = *mut u32; - const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD; - extern "system" { - fn GetStdHandle(which: DWORD) -> HANDLE; - fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL; - } - unsafe { - let handle = GetStdHandle(STD_OUTPUT_HANDLE); - let mut out = 0; - GetConsoleMode(handle, &mut out) != 0 - } -} - -#[derive(Clone)] -pub enum TestEvent { - TeFiltered(Vec<TestDesc>), - TeWait(TestDesc), - TeResult(TestDesc, TestResult, Option<TestExecTime>, Vec<u8>), - TeTimeout(TestDesc), - TeFilteredOut(usize), -} - -pub type MonitorMsg = (TestDesc, TestResult, Option<TestExecTime>, Vec<u8>); - -struct Sink(Arc<Mutex<Vec<u8>>>); -impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result<usize> { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[derive(Clone, Copy)] -pub enum RunStrategy { - /// Runs the test in the current process, and sends the result back over the - /// supplied channel. - InProcess, - - /// Spawns a subprocess to run the test, and sends the result back over the - /// supplied channel. Requires `argv[0]` to exist and point to the binary - /// that's currently running. - SpawnPrimary, -} - -pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()> +pub fn run_tests<F>( + opts: &TestOpts, + tests: Vec<TestDescAndFn>, + mut notify_about_test_event: F +) -> io::Result<()> where F: FnMut(TestEvent) -> io::Result<()>, { @@ -1399,11 +233,13 @@ where }; let filtered_out = tests_len - filtered_tests.len(); - callback(TeFilteredOut(filtered_out))?; + let event = TestEvent::TeFilteredOut(filtered_out); + notify_about_test_event(event)?; let filtered_descs = filtered_tests.iter().map(|t| t.desc.clone()).collect(); - callback(TeFiltered(filtered_descs))?; + let event = TestEvent::TeFiltered(filtered_descs); + notify_about_test_event(event)?; let (filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests.into_iter().partition(|e| match e.testfn { @@ -1417,7 +253,7 @@ where remaining.reverse(); let mut pending = 0; - let (tx, rx) = channel::<MonitorMsg>(); + let (tx, rx) = channel::<CompletedTest>(); let run_strategy = if opts.options.panic_abort { RunStrategy::SpawnPrimary } else { @@ -1458,18 +294,23 @@ where if concurrency == 1 { while !remaining.is_empty() { let test = remaining.pop().unwrap(); - callback(TeWait(test.desc.clone()))?; + let event = TestEvent::TeWait(test.desc.clone()); + notify_about_test_event(event)?; run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No); - let (test, result, exec_time, stdout) = rx.recv().unwrap(); - callback(TeResult(test, result, exec_time, stdout))?; + let completed_test = rx.recv().unwrap(); + + let event = TestEvent::TeResult(completed_test); + notify_about_test_event(event)?; } } else { while pending > 0 || !remaining.is_empty() { while pending < concurrency && !remaining.is_empty() { let test = remaining.pop().unwrap(); - let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S); + let timeout = time::get_default_test_timeout(); running_tests.insert(test.desc.clone(), timeout); - callback(TeWait(test.desc.clone()))?; //here no pad + + let event = TestEvent::TeWait(test.desc.clone()); + notify_about_test_event(event)?; //here no pad run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::Yes); pending += 1; } @@ -1479,10 +320,18 @@ where if let Some(timeout) = calc_timeout(&running_tests) { res = rx.recv_timeout(timeout); for test in get_timed_out_tests(&mut running_tests) { - callback(TeTimeout(test))?; + let event = TestEvent::TeTimeout(test); + notify_about_test_event(event)?; } - if res != Err(RecvTimeoutError::Timeout) { - break; + + match res { + Err(RecvTimeoutError::Timeout) => { + // Result is not yet ready, continue waiting. + } + _ => { + // We've got a result, stop the loop. + break; + } } } else { res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected); @@ -1490,10 +339,11 @@ where } } - let (desc, result, exec_time, stdout) = res.unwrap(); - running_tests.remove(&desc); + let completed_test = res.unwrap(); + running_tests.remove(&completed_test.desc); - callback(TeResult(desc, result, exec_time, stdout))?; + let event = TestEvent::TeResult(completed_test); + notify_about_test_event(event)?; pending -= 1; } } @@ -1501,160 +351,16 @@ where if opts.bench_benchmarks { // All benchmarks run at the end, in serial. for b in filtered_benchs { - callback(TeWait(b.desc.clone()))?; + let event = TestEvent::TeWait(b.desc.clone()); + notify_about_test_event(event)?; run_test(opts, false, b, run_strategy, tx.clone(), Concurrent::No); - let (test, result, exec_time, stdout) = rx.recv().unwrap(); - callback(TeResult(test, result, exec_time, stdout))?; - } - } - Ok(()) -} - -#[allow(deprecated)] -fn get_concurrency() -> usize { - return match env::var("RUST_TEST_THREADS") { - Ok(s) => { - let opt_n: Option<usize> = s.parse().ok(); - match opt_n { - Some(n) if n > 0 => n, - _ => panic!( - "RUST_TEST_THREADS is `{}`, should be a positive integer.", - s - ), - } - } - Err(..) => num_cpus(), - }; - - #[cfg(windows)] - #[allow(nonstandard_style)] - fn num_cpus() -> usize { - #[repr(C)] - struct SYSTEM_INFO { - wProcessorArchitecture: u16, - wReserved: u16, - dwPageSize: u32, - lpMinimumApplicationAddress: *mut u8, - lpMaximumApplicationAddress: *mut u8, - dwActiveProcessorMask: *mut u8, - dwNumberOfProcessors: u32, - dwProcessorType: u32, - dwAllocationGranularity: u32, - wProcessorLevel: u16, - wProcessorRevision: u16, - } - extern "system" { - fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32; - } - unsafe { - let mut sysinfo = std::mem::zeroed(); - GetSystemInfo(&mut sysinfo); - sysinfo.dwNumberOfProcessors as usize - } - } - - #[cfg(target_os = "vxworks")] - fn num_cpus() -> usize { - // FIXME: Implement num_cpus on vxWorks - 1 - } - - #[cfg(target_os = "redox")] - fn num_cpus() -> usize { - // FIXME: Implement num_cpus on Redox - 1 - } - - #[cfg(any( - all(target_arch = "wasm32", not(target_os = "emscripten")), - all(target_vendor = "fortanix", target_env = "sgx") - ))] - fn num_cpus() -> usize { - 1 - } - - #[cfg(any( - target_os = "android", - target_os = "cloudabi", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "solaris", - ))] - fn num_cpus() -> usize { - unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize } - } - - #[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "netbsd" - ))] - fn num_cpus() -> usize { - use std::ptr; - - let mut cpus: libc::c_uint = 0; - let mut cpus_size = std::mem::size_of_val(&cpus); - - unsafe { - cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint; - } - if cpus < 1 { - let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; - unsafe { - libc::sysctl( - mib.as_mut_ptr(), - 2, - &mut cpus as *mut _ as *mut _, - &mut cpus_size as *mut _ as *mut _, - ptr::null_mut(), - 0, - ); - } - if cpus < 1 { - cpus = 1; - } - } - cpus as usize - } + let completed_test = rx.recv().unwrap(); - #[cfg(target_os = "openbsd")] - fn num_cpus() -> usize { - use std::ptr; - - let mut cpus: libc::c_uint = 0; - let mut cpus_size = std::mem::size_of_val(&cpus); - let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; - - unsafe { - libc::sysctl( - mib.as_mut_ptr(), - 2, - &mut cpus as *mut _ as *mut _, - &mut cpus_size as *mut _ as *mut _, - ptr::null_mut(), - 0, - ); - } - if cpus < 1 { - cpus = 1; + let event = TestEvent::TeResult(completed_test); + notify_about_test_event(event)?; } - cpus as usize - } - - #[cfg(target_os = "haiku")] - fn num_cpus() -> usize { - // FIXME: implement - 1 - } - - #[cfg(target_os = "l4re")] - fn num_cpus() -> usize { - // FIXME: implement - 1 } + Ok(()) } pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> { @@ -1730,7 +436,7 @@ pub fn run_test( force_ignore: bool, test: TestDescAndFn, strategy: RunStrategy, - monitor_ch: Sender<MonitorMsg>, + monitor_ch: Sender<CompletedTest>, concurrency: Concurrent, ) { let TestDescAndFn { desc, testfn } = test; @@ -1740,7 +446,8 @@ pub fn run_test( && (cfg!(target_arch = "wasm32") || cfg!(target_os = "emscripten")); if force_ignore || desc.ignore || ignore_because_no_process_support { - monitor_ch.send((desc, TrIgnored, None, Vec::new())).unwrap(); + let message = CompletedTest::new(desc, TrIgnored, None, Vec::new()); + monitor_ch.send(message).unwrap(); return; } @@ -1748,12 +455,12 @@ pub fn run_test( pub strategy: RunStrategy, pub nocapture: bool, pub concurrency: Concurrent, - pub time: Option<TestTimeOptions>, + pub time: Option<time::TestTimeOptions>, } fn run_test_inner( desc: TestDesc, - monitor_ch: Sender<MonitorMsg>, + monitor_ch: Sender<CompletedTest>, testfn: Box<dyn FnOnce() + Send>, opts: TestRunOpts, ) { @@ -1835,94 +542,21 @@ fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) { f() } -fn calc_result<'a>( - desc: &TestDesc, - task_result: Result<(), &'a (dyn Any + 'static + Send)>, - time_opts: &Option<TestTimeOptions>, - exec_time: &Option<TestExecTime> -) -> TestResult { - let result = match (&desc.should_panic, task_result) { - (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk, - (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => { - if err - .downcast_ref::<String>() - .map(|e| &**e) - .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e)) - .map(|e| e.contains(msg)) - .unwrap_or(false) - { - TrOk - } else { - if desc.allow_fail { - TrAllowedFail - } else { - TrFailedMsg(format!("panic did not include expected string '{}'", msg)) - } - } - } - (&ShouldPanic::Yes, Ok(())) => TrFailedMsg("test did not panic as expected".to_string()), - _ if desc.allow_fail => TrAllowedFail, - _ => TrFailed, - }; - - // If test is already failed (or allowed to fail), do not change the result. - if result != TrOk { - return result; - } - - // Check if test is failed due to timeout. - if let (Some(opts), Some(time)) = (time_opts, exec_time) { - if opts.error_on_excess && opts.is_critical(desc, time) { - return TrTimedFail; - } - } - - result -} - -fn get_result_from_exit_code( - desc: &TestDesc, - code: i32, - time_opts: &Option<TestTimeOptions>, - exec_time: &Option<TestExecTime>, -) -> TestResult { - let result = match (desc.allow_fail, code) { - (_, TR_OK) => TrOk, - (true, TR_FAILED) => TrAllowedFail, - (false, TR_FAILED) => TrFailed, - (_, _) => TrFailedMsg(format!("got unexpected return code {}", code)), - }; - - // If test is already failed (or allowed to fail), do not change the result. - if result != TrOk { - return result; - } - - // Check if test is failed due to timeout. - if let (Some(opts), Some(time)) = (time_opts, exec_time) { - if opts.error_on_excess && opts.is_critical(desc, time) { - return TrTimedFail; - } - } - - result -} - fn run_test_in_process( desc: TestDesc, nocapture: bool, report_time: bool, testfn: Box<dyn FnOnce() + Send>, - monitor_ch: Sender<MonitorMsg>, - time_opts: Option<TestTimeOptions>, + monitor_ch: Sender<CompletedTest>, + time_opts: Option<time::TestTimeOptions>, ) { // Buffer for capturing standard I/O let data = Arc::new(Mutex::new(Vec::new())); let oldio = if !nocapture { Some(( - io::set_print(Some(Box::new(Sink(data.clone())))), - io::set_panic(Some(Box::new(Sink(data.clone())))), + io::set_print(Some(Sink::new_boxed(&data))), + io::set_panic(Some(Sink::new_boxed(&data))), )) } else { None @@ -1949,14 +583,15 @@ fn run_test_in_process( Err(e) => calc_result(&desc, Err(e.as_ref()), &time_opts, &exec_time), }; let stdout = data.lock().unwrap().to_vec(); - monitor_ch.send((desc.clone(), test_result, exec_time, stdout)).unwrap(); + let message = CompletedTest::new(desc.clone(), test_result, exec_time, stdout); + monitor_ch.send(message).unwrap(); } fn spawn_test_subprocess( desc: TestDesc, report_time: bool, - monitor_ch: Sender<MonitorMsg>, - time_opts: Option<TestTimeOptions>, + monitor_ch: Sender<CompletedTest>, + time_opts: Option<time::TestTimeOptions>, ) { let (result, test_output, exec_time) = (|| { let args = env::args().collect::<Vec<_>>(); @@ -2000,7 +635,8 @@ fn spawn_test_subprocess( (result, test_output, exec_time) })(); - monitor_ch.send((desc.clone(), result, exec_time, test_output)).unwrap(); + let message = CompletedTest::new(desc.clone(), result, exec_time, test_output); + monitor_ch.send(message).unwrap(); } fn run_test_in_spawned_subprocess( @@ -2025,9 +661,9 @@ fn run_test_in_spawned_subprocess( } if let TrOk = test_result { - process::exit(TR_OK); + process::exit(test_result::TR_OK); } else { - process::exit(TR_FAILED); + process::exit(test_result::TR_FAILED); } }); let record_result2 = record_result.clone(); @@ -2036,246 +672,3 @@ fn run_test_in_spawned_subprocess( record_result(None); unreachable!("panic=abort callback should have exited the process") } - -#[cfg(not(unix))] -fn get_exit_code(status: ExitStatus) -> Result<i32, String> { - status.code().ok_or("received no exit code from child process".into()) -} - -#[cfg(unix)] -fn get_exit_code(status: ExitStatus) -> Result<i32, String> { - use std::os::unix::process::ExitStatusExt; - match status.code() { - Some(code) => Ok(code), - None => match status.signal() { - Some(signal) => Err(format!("child process exited with signal {}", signal)), - None => Err("child process exited with unknown signal".into()), - } - } -} - -#[derive(Clone, PartialEq)] -pub struct MetricMap(BTreeMap<String, Metric>); - -impl MetricMap { - pub fn new() -> MetricMap { - MetricMap(BTreeMap::new()) - } - - /// Insert a named `value` (+/- `noise`) metric into the map. The value - /// must be non-negative. The `noise` indicates the uncertainty of the - /// metric, which doubles as the "noise range" of acceptable - /// pairwise-regressions on this named value, when comparing from one - /// metric to the next using `compare_to_old`. - /// - /// If `noise` is positive, then it means this metric is of a value - /// you want to see grow smaller, so a change larger than `noise` in the - /// positive direction represents a regression. - /// - /// If `noise` is negative, then it means this metric is of a value - /// you want to see grow larger, so a change larger than `noise` in the - /// negative direction represents a regression. - pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) { - let m = Metric { value, noise }; - self.0.insert(name.to_owned(), m); - } - - pub fn fmt_metrics(&self) -> String { - let v = self - .0 - .iter() - .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise)) - .collect::<Vec<_>>(); - v.join(", ") - } -} - -// Benchmarking - -pub use std::hint::black_box; - -impl Bencher { - /// Callback for benchmark functions to run in their body. - pub fn iter<T, F>(&mut self, mut inner: F) - where - F: FnMut() -> T, - { - if self.mode == BenchMode::Single { - ns_iter_inner(&mut inner, 1); - return; - } - - self.summary = Some(iter(&mut inner)); - } - - pub fn bench<F>(&mut self, mut f: F) -> Option<stats::Summary> - where - F: FnMut(&mut Bencher), - { - f(self); - return self.summary; - } -} - -fn ns_from_dur(dur: Duration) -> u64 { - dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64) -} - -fn ns_iter_inner<T, F>(inner: &mut F, k: u64) -> u64 -where - F: FnMut() -> T, -{ - let start = Instant::now(); - for _ in 0..k { - black_box(inner()); - } - return ns_from_dur(start.elapsed()); -} - -pub fn iter<T, F>(inner: &mut F) -> stats::Summary -where - F: FnMut() -> T, -{ - // Initial bench run to get ballpark figure. - let ns_single = ns_iter_inner(inner, 1); - - // Try to estimate iter count for 1ms falling back to 1m - // iterations if first run took < 1ns. - let ns_target_total = 1_000_000; // 1ms - let mut n = ns_target_total / cmp::max(1, ns_single); - - // if the first run took more than 1ms we don't want to just - // be left doing 0 iterations on every loop. The unfortunate - // side effect of not being able to do as many runs is - // automatically handled by the statistical analysis below - // (i.e., larger error bars). - n = cmp::max(1, n); - - let mut total_run = Duration::new(0, 0); - let samples: &mut [f64] = &mut [0.0_f64; 50]; - loop { - let loop_start = Instant::now(); - - for p in &mut *samples { - *p = ns_iter_inner(inner, n) as f64 / n as f64; - } - - stats::winsorize(samples, 5.0); - let summ = stats::Summary::new(samples); - - for p in &mut *samples { - let ns = ns_iter_inner(inner, 5 * n); - *p = ns as f64 / (5 * n) as f64; - } - - stats::winsorize(samples, 5.0); - let summ5 = stats::Summary::new(samples); - - let loop_run = loop_start.elapsed(); - - // If we've run for 100ms and seem to have converged to a - // stable median. - if loop_run > Duration::from_millis(100) - && summ.median_abs_dev_pct < 1.0 - && summ.median - summ5.median < summ5.median_abs_dev - { - return summ5; - } - - total_run = total_run + loop_run; - // Longest we ever run for is 3s. - if total_run > Duration::from_secs(3) { - return summ5; - } - - // If we overflow here just return the results so far. We check a - // multiplier of 10 because we're about to multiply by 2 and the - // next iteration of the loop will also multiply by 5 (to calculate - // the summ5 result) - n = match n.checked_mul(10) { - Some(_) => n * 2, - None => { - return summ5; - } - }; - } -} - -pub mod bench { - use super::{ - BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult - }; - use crate::stats; - use std::cmp; - use std::io; - use std::panic::{catch_unwind, AssertUnwindSafe}; - use std::sync::{Arc, Mutex}; - - pub fn benchmark<F>(desc: TestDesc, monitor_ch: Sender<MonitorMsg>, nocapture: bool, f: F) - where - F: FnMut(&mut Bencher), - { - let mut bs = Bencher { - mode: BenchMode::Auto, - summary: None, - bytes: 0, - }; - - let data = Arc::new(Mutex::new(Vec::new())); - let oldio = if !nocapture { - Some(( - io::set_print(Some(Box::new(Sink(data.clone())))), - io::set_panic(Some(Box::new(Sink(data.clone())))), - )) - } else { - None - }; - - let result = catch_unwind(AssertUnwindSafe(|| bs.bench(f))); - - if let Some((printio, panicio)) = oldio { - io::set_print(printio); - io::set_panic(panicio); - } - - let test_result = match result { - //bs.bench(f) { - Ok(Some(ns_iter_summ)) => { - let ns_iter = cmp::max(ns_iter_summ.median as u64, 1); - let mb_s = bs.bytes * 1000 / ns_iter; - - let bs = BenchSamples { - ns_iter_summ, - mb_s: mb_s as usize, - }; - TestResult::TrBench(bs) - } - Ok(None) => { - // iter not called, so no data. - // FIXME: error in this case? - let samples: &mut [f64] = &mut [0.0_f64; 1]; - let bs = BenchSamples { - ns_iter_summ: stats::Summary::new(samples), - mb_s: 0, - }; - TestResult::TrBench(bs) - } - Err(_) => TestResult::TrFailed, - }; - - let stdout = data.lock().unwrap().to_vec(); - monitor_ch.send((desc, test_result, None, stdout)).unwrap(); - } - - pub fn run_once<F>(f: F) - where - F: FnMut(&mut Bencher), - { - let mut bs = Bencher { - mode: BenchMode::Single, - summary: None, - bytes: 0, - }; - bs.bench(f); - } -} diff --git a/src/libtest/options.rs b/src/libtest/options.rs new file mode 100644 index 00000000000..ec87b0fcd46 --- /dev/null +++ b/src/libtest/options.rs @@ -0,0 +1,90 @@ +//! Enums denoting options for test execution. + +/// Whether to execute tests concurrently or not +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Concurrent { + Yes, + No, +} + +/// Number of times to run a benchmarked function +#[derive(Clone, PartialEq, Eq)] +pub enum BenchMode { + Auto, + Single, +} + +/// Whether test is expected to panic or not +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum ShouldPanic { + No, + Yes, + YesWithMessage(&'static str), +} + +/// Whether should console output be colored or not +#[derive(Copy, Clone, Debug)] +pub enum ColorConfig { + AutoColor, + AlwaysColor, + NeverColor, +} + +/// Format of the test results output +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum OutputFormat { + /// Verbose output + Pretty, + /// Quiet output + Terse, + /// JSON output + Json, +} + +/// Whether ignored test should be runned or not +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum RunIgnored { + Yes, + No, + /// Run only ignored tests + Only, +} + +#[derive(Clone, Copy)] +pub enum RunStrategy { + /// Runs the test in the current process, and sends the result back over the + /// supplied channel. + InProcess, + + /// Spawns a subprocess to run the test, and sends the result back over the + /// supplied channel. Requires `argv[0]` to exist and point to the binary + /// that's currently running. + SpawnPrimary, +} + +/// Options for the test run defined by the caller (instead of CLI arguments). +/// In case we want to add other options as well, just add them in this struct. +#[derive(Copy, Clone, Debug)] +pub struct Options { + pub display_output: bool, + pub panic_abort: bool, +} + +impl Options { + pub fn new() -> Options { + Options { + display_output: false, + panic_abort: false, + } + } + + pub fn display_output(mut self, display_output: bool) -> Options { + self.display_output = display_output; + self + } + + pub fn panic_abort(mut self, panic_abort: bool) -> Options { + self.panic_abort = panic_abort; + self + } +} diff --git a/src/libtest/stats/tests.rs b/src/libtest/stats/tests.rs index 7d1d635186f..eaf41bc9e22 100644 --- a/src/libtest/stats/tests.rs +++ b/src/libtest/stats/tests.rs @@ -4,7 +4,7 @@ extern crate test; use std::f64; use std::io::prelude::*; use std::io; -use self::test::Bencher; +use self::test::test::Bencher; // Test vectors generated from R, using the script src/etc/stat-test-vectors.r. diff --git a/src/libtest/test_result.rs b/src/libtest/test_result.rs new file mode 100644 index 00000000000..80ca9dea18f --- /dev/null +++ b/src/libtest/test_result.rs @@ -0,0 +1,107 @@ +use std::any::Any; + +use super::bench::BenchSamples; +use super::time; +use super::types::TestDesc; +use super::options::ShouldPanic; + +pub use self::TestResult::*; + +// Return codes for secondary process. +// Start somewhere other than 0 so we know the return code means what we think +// it means. +pub const TR_OK: i32 = 50; +pub const TR_FAILED: i32 = 51; + +#[derive(Debug, Clone, PartialEq)] +pub enum TestResult { + TrOk, + TrFailed, + TrFailedMsg(String), + TrIgnored, + TrAllowedFail, + TrBench(BenchSamples), + TrTimedFail, +} + +unsafe impl Send for TestResult {} + +/// Creates a `TestResult` depending on the raw result of test execution +/// and assotiated data. +pub fn calc_result<'a>( + desc: &TestDesc, + task_result: Result<(), &'a (dyn Any + 'static + Send)>, + time_opts: &Option<time::TestTimeOptions>, + exec_time: &Option<time::TestExecTime> +) -> TestResult { + let result = match (&desc.should_panic, task_result) { + (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk, + (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => { + if err + .downcast_ref::<String>() + .map(|e| &**e) + .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e)) + .map(|e| e.contains(msg)) + .unwrap_or(false) + { + TestResult::TrOk + } else { + if desc.allow_fail { + TestResult::TrAllowedFail + } else { + TestResult::TrFailedMsg( + format!("panic did not include expected string '{}'", msg) + ) + } + } + } + (&ShouldPanic::Yes, Ok(())) => { + TestResult::TrFailedMsg("test did not panic as expected".to_string()) + } + _ if desc.allow_fail => TestResult::TrAllowedFail, + _ => TestResult::TrFailed, + }; + + // If test is already failed (or allowed to fail), do not change the result. + if result != TestResult::TrOk { + return result; + } + + // Check if test is failed due to timeout. + if let (Some(opts), Some(time)) = (time_opts, exec_time) { + if opts.error_on_excess && opts.is_critical(desc, time) { + return TestResult::TrTimedFail; + } + } + + result +} + +/// Creates a `TestResult` depending on the exit code of test subprocess. +pub fn get_result_from_exit_code( + desc: &TestDesc, + code: i32, + time_opts: &Option<time::TestTimeOptions>, + exec_time: &Option<time::TestExecTime>, +) -> TestResult { + let result = match (desc.allow_fail, code) { + (_, TR_OK) => TestResult::TrOk, + (true, TR_FAILED) => TestResult::TrAllowedFail, + (false, TR_FAILED) => TestResult::TrFailed, + (_, _) => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)), + }; + + // If test is already failed (or allowed to fail), do not change the result. + if result != TestResult::TrOk { + return result; + } + + // Check if test is failed due to timeout. + if let (Some(opts), Some(time)) = (time_opts, exec_time) { + if opts.error_on_excess && opts.is_critical(desc, time) { + return TestResult::TrTimedFail; + } + } + + result +} diff --git a/src/libtest/tests.rs b/src/libtest/tests.rs index 5f7150a8eeb..9de774555e9 100644 --- a/src/libtest/tests.rs +++ b/src/libtest/tests.rs @@ -1,11 +1,19 @@ use super::*; -use crate::test::{ - filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored, RunStrategy, - // ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TestTimeOptions, - // TestType, TrFailedMsg, TrIgnored, TrOk, - ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, - TrIgnored, TrOk, +use crate::{ + bench::Bencher, + console::OutputLocation, + options::OutputFormat, + time::{TimeThreshold, TestTimeOptions}, + formatters::PrettyFormatter, + test::{ + filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, + RunIgnored, RunStrategy, ShouldPanic, StaticTestName, TestDesc, + TestDescAndFn, TestOpts, TrIgnored, TrOk, + // FIXME (introduced by #65251) + // ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TestTimeOptions, + // TestType, TrFailedMsg, TrIgnored, TrOk, + }, }; use std::sync::mpsc::channel; use std::time::Duration; @@ -74,8 +82,8 @@ pub fn do_not_run_ignored_tests() { }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); - let (_, res, _, _) = rx.recv().unwrap(); - assert!(res != TrOk); + let result = rx.recv().unwrap().result; + assert!(result != TrOk); } #[test] @@ -93,11 +101,11 @@ pub fn ignored_tests_result_in_ignored() { }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); - let (_, res, _, _) = rx.recv().unwrap(); - assert!(res == TrIgnored); + let result = rx.recv().unwrap().result; + assert!(result == TrIgnored); } -// FIXME: Re-enable emscripten once it can catch panics again +// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] #[cfg(not(target_os = "emscripten"))] fn test_should_panic() { @@ -116,11 +124,11 @@ fn test_should_panic() { }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); - let (_, res, _, _) = rx.recv().unwrap(); - assert!(res == TrOk); + let result = rx.recv().unwrap().result; + assert!(result == TrOk); } -// FIXME: Re-enable emscripten once it can catch panics again +// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] #[cfg(not(target_os = "emscripten"))] fn test_should_panic_good_message() { @@ -139,11 +147,11 @@ fn test_should_panic_good_message() { }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); - let (_, res, _, _) = rx.recv().unwrap(); - assert!(res == TrOk); + let result = rx.recv().unwrap().result; + assert!(result == TrOk); } -// FIXME: Re-enable emscripten once it can catch panics again +// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] #[cfg(not(target_os = "emscripten"))] fn test_should_panic_bad_message() { @@ -165,11 +173,11 @@ fn test_should_panic_bad_message() { }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); - let (_, res, _, _) = rx.recv().unwrap(); - assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected))); + let result = rx.recv().unwrap().result; + assert!(result == TrFailedMsg(format!("{} '{}'", failed_msg, expected))); } -// FIXME: Re-enable emscripten once it can catch panics again +// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] #[cfg(not(target_os = "emscripten"))] fn test_should_panic_but_succeeds() { @@ -186,8 +194,8 @@ fn test_should_panic_but_succeeds() { }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No); - let (_, res, _, _) = rx.recv().unwrap(); - assert!(res == TrFailedMsg("test did not panic as expected".to_string())); + let result = rx.recv().unwrap().result; + assert!(result == TrFailedMsg("test did not panic as expected".to_string())); } fn report_time_test_template(report_time: bool) -> Option<TestExecTime> { @@ -214,7 +222,7 @@ fn report_time_test_template(report_time: bool) -> Option<TestExecTime> { }; let (tx, rx) = channel(); run_test(&test_opts, false, desc, RunStrategy::InProcess, tx, Concurrent::No); - let (_, _, exec_time, _) = rx.recv().unwrap(); + let exec_time = rx.recv().unwrap().exec_time; exec_time } @@ -252,7 +260,7 @@ fn time_test_failure_template(test_type: TestType) -> TestResult { }; let (tx, rx) = channel(); run_test(&test_opts, false, desc, RunStrategy::InProcess, tx, Concurrent::No); - let (_, result, _, _) = rx.recv().unwrap(); + let result = rx.recv().unwrap().result; result } @@ -658,9 +666,9 @@ fn should_sort_failures_before_printing_them() { test_type: TestType::Unknown, }; - let mut out = PrettyFormatter::new(Raw(Vec::new()), false, 10, false, None); + let mut out = PrettyFormatter::new(OutputLocation::Raw(Vec::new()), false, 10, false, None); - let st = ConsoleTestState { + let st = console::ConsoleTestState { log_out: None, total: 0, passed: 0, @@ -678,8 +686,8 @@ fn should_sort_failures_before_printing_them() { out.write_failures(&st).unwrap(); let s = match out.output_location() { - &Raw(ref m) => String::from_utf8_lossy(&m[..]), - &Pretty(_) => unreachable!(), + &OutputLocation::Raw(ref m) => String::from_utf8_lossy(&m[..]), + &OutputLocation::Pretty(_) => unreachable!(), }; let apos = s.find("a").unwrap(); diff --git a/src/libtest/time.rs b/src/libtest/time.rs new file mode 100644 index 00000000000..f4d4b17b620 --- /dev/null +++ b/src/libtest/time.rs @@ -0,0 +1,206 @@ +//! Module `time` contains everything related to the time measurement of unit tests +//! execution. +//! Two main purposes of this module: +//! - Check whether test is timed out. +//! - Provide helpers for `report-time` and `measure-time` options. + +use std::time::{Duration, Instant}; +use std::str::FromStr; +use std::fmt; +use std::env; + +use super::types::{TestDesc, TestType}; + +pub const TEST_WARN_TIMEOUT_S: u64 = 60; + +/// This small module contains constants used by `report-time` option. +/// Those constants values will be used if corresponding environment variables are not set. +/// +/// To override values for unit-tests, use a constant `RUST_TEST_TIME_UNIT`, +/// To override values for integration tests, use a constant `RUST_TEST_TIME_INTEGRATION`, +/// To override values for doctests, use a constant `RUST_TEST_TIME_DOCTEST`. +/// +/// Example of the expected format is `RUST_TEST_TIME_xxx=100,200`, where 100 means +/// warn time, and 200 means critical time. +pub mod time_constants { + use std::time::Duration; + use super::TEST_WARN_TIMEOUT_S; + + /// Environment variable for overriding default threshold for unit-tests. + pub const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT"; + + // Unit tests are supposed to be really quick. + pub const UNIT_WARN: Duration = Duration::from_millis(50); + pub const UNIT_CRITICAL: Duration = Duration::from_millis(100); + + /// Environment variable for overriding default threshold for unit-tests. + pub const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION"; + + // Integration tests may have a lot of work, so they can take longer to execute. + pub const INTEGRATION_WARN: Duration = Duration::from_millis(500); + pub const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000); + + /// Environment variable for overriding default threshold for unit-tests. + pub const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST"; + + // Doctests are similar to integration tests, because they can include a lot of + // initialization code. + pub const DOCTEST_WARN: Duration = INTEGRATION_WARN; + pub const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL; + + // Do not suppose anything about unknown tests, base limits on the + // `TEST_WARN_TIMEOUT_S` constant. + pub const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S); + pub const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2); +} + +/// Returns an `Instance` object denoting when the test should be considered +/// timed out. +pub fn get_default_test_timeout() -> Instant { + Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S) +} + +/// The meassured execution time of a unit test. +#[derive(Debug, Clone, PartialEq)] +pub struct TestExecTime(pub Duration); + +impl fmt::Display for TestExecTime { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:.3}s", self.0.as_secs_f64()) + } +} + +/// Structure denoting time limits for test execution. +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct TimeThreshold { + pub warn: Duration, + pub critical: Duration, +} + +impl TimeThreshold { + /// Creates a new `TimeThreshold` instance with provided durations. + pub fn new(warn: Duration, critical: Duration) -> Self { + Self { + warn, + critical, + } + } + + /// Attempts to create a `TimeThreshold` instance with values obtained + /// from the environment variable, and returns `None` if the variable + /// is not set. + /// Environment variable format is expected to match `\d+,\d+`. + /// + /// # Panics + /// + /// Panics if variable with provided name is set but contains inappropriate + /// value. + pub fn from_env_var(env_var_name: &str) -> Option<Self> { + let durations_str = env::var(env_var_name).ok()?; + + // Split string into 2 substrings by comma and try to parse numbers. + let mut durations = durations_str + .splitn(2, ',') + .map(|v| { + u64::from_str(v).unwrap_or_else(|_| { + panic!( + "Duration value in variable {} is expected to be a number, but got {}", + env_var_name, v + ) + }) + }); + + // Callback to be called if the environment variable has unexpected structure. + let panic_on_incorrect_value = || { + panic!( + "Duration variable {} expected to have 2 numbers separated by comma, but got {}", + env_var_name, durations_str + ); + }; + + let (warn, critical) = ( + durations.next().unwrap_or_else(panic_on_incorrect_value), + durations.next().unwrap_or_else(panic_on_incorrect_value) + ); + + if warn > critical { + panic!("Test execution warn time should be less or equal to the critical time"); + } + + Some(Self::new(Duration::from_millis(warn), Duration::from_millis(critical))) + } +} + +/// Structure with parameters for calculating test execution time. +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct TestTimeOptions { + /// Denotes if the test critical execution time limit excess should be considered + /// a test failure. + pub error_on_excess: bool, + pub colored: bool, + pub unit_threshold: TimeThreshold, + pub integration_threshold: TimeThreshold, + pub doctest_threshold: TimeThreshold, +} + +impl TestTimeOptions { + pub fn new_from_env(error_on_excess: bool, colored: bool) -> Self { + let unit_threshold = + TimeThreshold::from_env_var(time_constants::UNIT_ENV_NAME) + .unwrap_or_else(Self::default_unit); + + let integration_threshold = + TimeThreshold::from_env_var(time_constants::INTEGRATION_ENV_NAME) + .unwrap_or_else(Self::default_integration); + + let doctest_threshold = + TimeThreshold::from_env_var(time_constants::DOCTEST_ENV_NAME) + .unwrap_or_else(Self::default_doctest); + + Self { + error_on_excess, + colored, + unit_threshold, + integration_threshold, + doctest_threshold, + } + } + + pub fn is_warn(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool { + exec_time.0 >= self.warn_time(test) + } + + pub fn is_critical(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool { + exec_time.0 >= self.critical_time(test) + } + + fn warn_time(&self, test: &TestDesc) -> Duration { + match test.test_type { + TestType::UnitTest => self.unit_threshold.warn, + TestType::IntegrationTest => self.integration_threshold.warn, + TestType::DocTest => self.doctest_threshold.warn, + TestType::Unknown => time_constants::UNKNOWN_WARN, + } + } + + fn critical_time(&self, test: &TestDesc) -> Duration { + match test.test_type { + TestType::UnitTest => self.unit_threshold.critical, + TestType::IntegrationTest => self.integration_threshold.critical, + TestType::DocTest => self.doctest_threshold.critical, + TestType::Unknown => time_constants::UNKNOWN_CRITICAL, + } + } + + fn default_unit() -> TimeThreshold { + TimeThreshold::new(time_constants::UNIT_WARN, time_constants::UNIT_CRITICAL) + } + + fn default_integration() -> TimeThreshold { + TimeThreshold::new(time_constants::INTEGRATION_WARN, time_constants::INTEGRATION_CRITICAL) + } + + fn default_doctest() -> TimeThreshold { + TimeThreshold::new(time_constants::DOCTEST_WARN, time_constants::DOCTEST_CRITICAL) + } +} diff --git a/src/libtest/types.rs b/src/libtest/types.rs new file mode 100644 index 00000000000..89bcf2cf285 --- /dev/null +++ b/src/libtest/types.rs @@ -0,0 +1,145 @@ +//! Common types used by `libtest`. + +use std::fmt; +use std::borrow::Cow; + +use super::options; +use super::bench::Bencher; + +pub use NamePadding::*; +pub use TestName::*; +pub use TestFn::*; + +/// Type of the test according to the [rust book](https://doc.rust-lang.org/cargo/guide/tests.html) +/// conventions. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum TestType { + /// Unit-tests are expected to be in the `src` folder of the crate. + UnitTest, + /// Integration-style tests are expected to be in the `tests` folder of the crate. + IntegrationTest, + /// Doctests are created by the `librustdoc` manually, so it's a different type of test. + DocTest, + /// Tests for the sources that don't follow the project layout convention + /// (e.g. tests in raw `main.rs` compiled by calling `rustc --test` directly). + Unknown, +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum NamePadding { + PadNone, + PadOnRight, +} + +// The name of a test. By convention this follows the rules for rust +// paths; i.e., it should be a series of identifiers separated by double +// colons. This way if some test runner wants to arrange the tests +// hierarchically it may. +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum TestName { + StaticTestName(&'static str), + DynTestName(String), + AlignedTestName(Cow<'static, str>, NamePadding), +} + +impl TestName { + pub fn as_slice(&self) -> &str { + match *self { + StaticTestName(s) => s, + DynTestName(ref s) => s, + AlignedTestName(ref s, _) => &*s, + } + } + + pub fn padding(&self) -> NamePadding { + match self { + &AlignedTestName(_, p) => p, + _ => PadNone, + } + } + + pub fn with_padding(&self, padding: NamePadding) -> TestName { + let name = match self { + &TestName::StaticTestName(name) => Cow::Borrowed(name), + &TestName::DynTestName(ref name) => Cow::Owned(name.clone()), + &TestName::AlignedTestName(ref name, _) => name.clone(), + }; + + TestName::AlignedTestName(name, padding) + } +} +impl fmt::Display for TestName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), f) + } +} + +/// Represents a benchmark function. +pub trait TDynBenchFn: Send { + fn run(&self, harness: &mut Bencher); +} + +// A function that runs a test. If the function returns successfully, +// the test succeeds; if the function panics then the test fails. We +// may need to come up with a more clever definition of test in order +// to support isolation of tests into threads. +pub enum TestFn { + StaticTestFn(fn()), + StaticBenchFn(fn(&mut Bencher)), + DynTestFn(Box<dyn FnOnce() + Send>), + DynBenchFn(Box<dyn TDynBenchFn + 'static>), +} + +impl TestFn { + pub fn padding(&self) -> NamePadding { + match *self { + StaticTestFn(..) => PadNone, + StaticBenchFn(..) => PadOnRight, + DynTestFn(..) => PadNone, + DynBenchFn(..) => PadOnRight, + } + } +} + +impl fmt::Debug for TestFn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match *self { + StaticTestFn(..) => "StaticTestFn(..)", + StaticBenchFn(..) => "StaticBenchFn(..)", + DynTestFn(..) => "DynTestFn(..)", + DynBenchFn(..) => "DynBenchFn(..)", + }) + } +} + +// The definition of a single test. A test runner will run a list of +// these. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct TestDesc { + pub name: TestName, + pub ignore: bool, + pub should_panic: options::ShouldPanic, + pub allow_fail: bool, + pub test_type: TestType, +} + +impl TestDesc { + pub fn padded_name(&self, column_count: usize, align: NamePadding) -> String { + let mut name = String::from(self.name.as_slice()); + let fill = column_count.saturating_sub(name.len()); + let pad = " ".repeat(fill); + match align { + PadNone => name, + PadOnRight => { + name.push_str(&pad); + name + } + } + } +} + +#[derive(Debug)] +pub struct TestDescAndFn { + pub desc: TestDesc, + pub testfn: TestFn, +} diff --git a/src/llvm-emscripten b/src/llvm-emscripten deleted file mode 160000 -Subproject 7f23313edff8beccb3fe44b815714269c5124c1 diff --git a/src/test/incremental/const-generics/issue-61338.rs b/src/test/incremental/const-generics/issue-61338.rs new file mode 100644 index 00000000000..00b3b29698b --- /dev/null +++ b/src/test/incremental/const-generics/issue-61338.rs @@ -0,0 +1,14 @@ +// revisions:rpass1 + +#![feature(const_generics)] + +struct Struct<T>(T); + +impl<T, const N: usize> Struct<[T; N]> { + fn f() {} + fn g() { Self::f(); } +} + +fn main() { + Struct::<[u32; 3]>::g(); +} diff --git a/src/test/incremental/const-generics/issue-61516.rs b/src/test/incremental/const-generics/issue-61516.rs new file mode 100644 index 00000000000..a7465b77267 --- /dev/null +++ b/src/test/incremental/const-generics/issue-61516.rs @@ -0,0 +1,16 @@ +// revisions:rpass1 + +#![feature(const_generics)] + +struct FakeArray<T, const N: usize>(T); + +impl<T, const N: usize> FakeArray<T, { N }> { + fn len(&self) -> usize { + N + } +} + +fn main() { + let fa = FakeArray::<u32, { 32 }>(1); + assert_eq!(fa.len(), 32); +} diff --git a/src/test/incremental/const-generics/issue-62536.rs b/src/test/incremental/const-generics/issue-62536.rs new file mode 100644 index 00000000000..90e279bfc74 --- /dev/null +++ b/src/test/incremental/const-generics/issue-62536.rs @@ -0,0 +1,12 @@ +// revisions:cfail1 +#![feature(const_generics)] +//[cfail1]~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct S<T, const N: usize>([T; N]); + +fn f<T, const N: usize>(x: T) -> S<T, {N}> { panic!() } + +fn main() { + f(0u8); + //[cfail1]~^ ERROR type annotations needed +} diff --git a/src/test/incremental/const-generics/issue-64087.rs b/src/test/incremental/const-generics/issue-64087.rs new file mode 100644 index 00000000000..b3c12fbb6e8 --- /dev/null +++ b/src/test/incremental/const-generics/issue-64087.rs @@ -0,0 +1,11 @@ +// revisions:cfail1 +#![feature(const_generics)] +//[cfail1]~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +fn combinator<T, const S: usize>() -> [T; S] {} +//[cfail1]~^ ERROR mismatched types + +fn main() { + combinator().into_iter(); + //[cfail1]~^ ERROR type annotations needed +} diff --git a/src/test/incremental/const-generics/issue-65623.rs b/src/test/incremental/const-generics/issue-65623.rs new file mode 100644 index 00000000000..353e323e67b --- /dev/null +++ b/src/test/incremental/const-generics/issue-65623.rs @@ -0,0 +1,14 @@ +// revisions:rpass1 +#![feature(const_generics)] + +pub struct Foo<T, const N: usize>([T; 0]); + +impl<T, const N: usize> Foo<T, {N}> { + pub fn new() -> Self { + Foo([]) + } +} + +fn main() { + let _: Foo<u32, 0> = Foo::new(); +} diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs index 70820dfaea4..8e134ad14fc 100644 --- a/src/test/incremental/hashes/for_loops.rs +++ b/src/test/incremental/hashes/for_loops.rs @@ -25,7 +25,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 68545b7daaa..4e8ba5a209d 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -22,7 +22,7 @@ pub fn change_name() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="HirBody,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_name() { let _y = 2u64; @@ -86,7 +86,7 @@ pub fn change_mutability_of_slot() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_slot() { let _x: u64 = 0; @@ -182,7 +182,7 @@ pub fn add_initializer() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn add_initializer() { let _x: i16 = 3i16; @@ -198,7 +198,7 @@ pub fn change_initializer() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="HirBody,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_initializer() { let _x = 5u16; diff --git a/src/test/incremental/hashes/loop_expressions.rs b/src/test/incremental/hashes/loop_expressions.rs index a2222db4c59..ca85ee39e36 100644 --- a/src/test/incremental/hashes/loop_expressions.rs +++ b/src/test/incremental/hashes/loop_expressions.rs @@ -25,7 +25,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; diff --git a/src/test/incremental/hashes/while_let_loops.rs b/src/test/incremental/hashes/while_let_loops.rs index da3c957741f..1e628d01919 100644 --- a/src/test/incremental/hashes/while_let_loops.rs +++ b/src/test/incremental/hashes/while_let_loops.rs @@ -25,7 +25,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; diff --git a/src/test/incremental/hashes/while_loops.rs b/src/test/incremental/hashes/while_loops.rs index 3be42e7a4ee..295c2244879 100644 --- a/src/test/incremental/hashes/while_loops.rs +++ b/src/test/incremental/hashes/while_loops.rs @@ -25,7 +25,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; diff --git a/src/test/mir-opt/simplify-locals-removes-unused-consts.rs b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs new file mode 100644 index 00000000000..6f03438ff72 --- /dev/null +++ b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs @@ -0,0 +1,89 @@ +// compile-flags: -C overflow-checks=no + +fn use_zst(_: ((), ())) { } + +struct Temp { + x: u8 +} + +fn use_u8(_: u8) { } + +fn main() { + let ((), ()) = ((), ()); + use_zst(((), ())); + + use_u8((Temp { x : 40 }).x + 2); +} + +// END RUST SOURCE + +// START rustc.main.SimplifyLocals.before.mir +// let mut _0: (); +// let mut _1: ((), ()); +// let mut _2: (); +// let mut _3: (); +// let _4: (); +// let mut _5: ((), ()); +// let mut _6: (); +// let mut _7: (); +// let _8: (); +// let mut _9: u8; +// let mut _10: u8; +// let mut _11: Temp; +// scope 1 { +// } +// bb0: { +// StorageLive(_1); +// StorageLive(_2); +// _2 = const Scalar(<ZST>) : (); +// StorageLive(_3); +// _3 = const Scalar(<ZST>) : (); +// _1 = const Scalar(<ZST>) : ((), ()); +// StorageDead(_3); +// StorageDead(_2); +// StorageDead(_1); +// StorageLive(_4); +// StorageLive(_6); +// _6 = const Scalar(<ZST>) : (); +// StorageLive(_7); +// _7 = const Scalar(<ZST>) : (); +// StorageDead(_7); +// StorageDead(_6); +// _4 = const use_zst(const Scalar(<ZST>) : ((), ())) -> bb1; +// } +// bb1: { +// StorageDead(_4); +// StorageLive(_8); +// StorageLive(_10); +// StorageLive(_11); +// _11 = const Scalar(0x28) : Temp; +// _10 = const 40u8; +// StorageDead(_10); +// _8 = const use_u8(const 42u8) -> bb2; +// } +// bb2: { +// StorageDead(_11); +// StorageDead(_8); +// return; +// } +// END rustc.main.SimplifyLocals.before.mir +// START rustc.main.SimplifyLocals.after.mir +// let mut _0: (); +// let _1: (); +// let _2: (); +// scope 1 { +// } +// bb0: { +// StorageLive(_1); +// _1 = const use_zst(const Scalar(<ZST>) : ((), ())) -> bb1; +// } +// bb1: { +// StorageDead(_1); +// StorageLive(_2); +// _2 = const use_u8(const 42u8) -> bb2; +// } +// bb2: { +// StorageDead(_2); +// return; +// } +// END rustc.main.SimplifyLocals.after.mir diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs index 754fad51b21..f270dec5fe2 100644 --- a/src/test/mir-opt/slice-drop-shim.rs +++ b/src/test/mir-opt/slice-drop-shim.rs @@ -1,5 +1,7 @@ +// compile-flags: -Zmir-opt-level=0 + fn main() { - std::ptr::drop_in_place::<[String]> as unsafe fn(_); + let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_); } // END RUST SOURCE diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index e290f7fa6b1..9582137eae9 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -59,6 +59,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { stderr: None, crate_name: None, lint_caps: Default::default(), + register_lints: None, }; interface::run_compiler(config, |compiler| { diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile index 200dc1be4de..f56475b441f 100644 --- a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile @@ -4,12 +4,18 @@ -include ../tools.mk -# This test builds a staticlib, then an executable that links to it. -# The staticlib and executable both are compiled with address sanitizer, -# and we assert that a fault in the staticlib is correctly detected. +# This test first builds a staticlib with AddressSanitizer and checks that +# linking it to an executable fails due to the missing sanitizer runtime. +# It then builds an executable linking to the staticlib and checks that +# the fault in the staticlib is detected correctly. + +# Note that checking for the link failure actually checks two things at once: +# 1) That the library has the sanitizer intrumentation +# 2) and that library does not have the sanitizer runtime all: $(RUSTC) -g -Z sanitizer=address --crate-type staticlib --target $(TARGET) library.rs - $(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS) + ! $(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS) + $(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) -L . program.rs LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | $(CGREP) stack-buffer-overflow diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/program.rs b/src/test/run-make-fulldeps/sanitizer-staticlib-link/program.rs new file mode 100644 index 00000000000..21e1ade2cd5 --- /dev/null +++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/program.rs @@ -0,0 +1,10 @@ +#[link(name = "library")] +extern { + fn overflow(); +} + +fn main() { + unsafe { + overflow(); + } +} diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout index d206b721765..a8753d14de2 100644 --- a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout +++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout @@ -6,13 +6,13 @@ failures: ---- $DIR/failed-doctest-missing-codes.rs - Foo (line 8) stdout ---- error[E0308]: mismatched types - --> $DIR/failed-doctest-missing-codes.rs:9:13 - | -3 | let x: () = 5i32; - | ^^^^ expected (), found i32 - | - = note: expected type `()` - found type `i32` + --> $DIR/failed-doctest-missing-codes.rs:9:13 + | +LL | let x: () = 5i32; + | ^^^^ expected (), found i32 + | + = note: expected type `()` + found type `i32` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout index ef1b419f528..9887d07a3eb 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.stdout +++ b/src/test/rustdoc-ui/failed-doctest-output.stdout @@ -7,10 +7,10 @@ failures: ---- $DIR/failed-doctest-output.rs - OtherStruct (line 21) stdout ---- error[E0425]: cannot find value `no` in this scope - --> $DIR/failed-doctest-output.rs:22:1 - | -3 | no - | ^^ not found in this scope + --> $DIR/failed-doctest-output.rs:22:1 + | +LL | no + | ^^ not found in this scope error: aborting due to previous error diff --git a/src/test/rustdoc-ui/unparseable-doc-test.stdout b/src/test/rustdoc-ui/unparseable-doc-test.stdout index 0350c016436..4ea6455d3aa 100644 --- a/src/test/rustdoc-ui/unparseable-doc-test.stdout +++ b/src/test/rustdoc-ui/unparseable-doc-test.stdout @@ -6,10 +6,10 @@ failures: ---- $DIR/unparseable-doc-test.rs - foo (line 6) stdout ---- error: unterminated double quote string - --> $DIR/unparseable-doc-test.rs:8:1 - | -2 | "unterminated - | ^^^^^^^^^^^^^ + --> $DIR/unparseable-doc-test.rs:8:1 + | +LL | "unterminated + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/rustdoc/sanitizer-option.rs b/src/test/rustdoc/sanitizer-option.rs new file mode 100644 index 00000000000..6af9ed3e33f --- /dev/null +++ b/src/test/rustdoc/sanitizer-option.rs @@ -0,0 +1,17 @@ +// needs-sanitizer-support +// compile-flags: --test -Z sanitizer=address +// +// #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern +// function that is provided by the sanitizer runtime, if flag is not passed +// correctly, then linking will fail. + +/// ``` +/// extern { +/// fn __sanitizer_print_stack_trace(); +/// } +/// +/// fn main() { +/// unsafe { __sanitizer_print_stack_trace() }; +/// } +/// ``` +pub fn z_flag_is_passed_to_rustc() {} diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs index bb0ebf693d0..6b914f501ca 100644 --- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs @@ -15,15 +15,14 @@ use syntax::symbol::Symbol; use rustc::hir; use rustc::hir::intravisit; -use rustc::hir::map as hir_map; use hir::Node; use rustc::lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext}; -use rustc::ty; -use syntax::{ast, source_map}; +use syntax::source_map; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box MissingWhitelistedAttrPass); + reg.lint_store.register_lints(&[&MISSING_WHITELISTED_ATTR]); + reg.lint_store.register_late_pass(|| box MissingWhitelistedAttrPass); reg.register_attribute(Symbol::intern("whitelisted_attr"), Whitelisted); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs index 17386d7e1aa..6874c921c1c 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs @@ -7,24 +7,20 @@ extern crate rustc_driver; extern crate syntax; -use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; +use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass}; use rustc_driver::plugin::Registry; use rustc::hir; use syntax::attr; use syntax::symbol::Symbol; macro_rules! fake_lint_pass { - ($struct:ident, $lints:expr, $($attr:expr),*) => { + ($struct:ident, $($attr:expr),*) => { struct $struct; impl LintPass for $struct { fn name(&self) -> &'static str { stringify!($struct) } - - fn get_lints(&self) -> LintArray { - $lints - } } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $struct { @@ -49,25 +45,29 @@ declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]"); fake_lint_pass! { PassOkay, - lint_array!(CRATE_NOT_OKAY), // Single lint Symbol::intern("rustc_crate_okay") } fake_lint_pass! { PassRedBlue, - lint_array!(CRATE_NOT_RED, CRATE_NOT_BLUE), // Multiple lints Symbol::intern("rustc_crate_red"), Symbol::intern("rustc_crate_blue") } fake_lint_pass! { PassGreyGreen, - lint_array!(CRATE_NOT_GREY, CRATE_NOT_GREEN, ), // Trailing comma Symbol::intern("rustc_crate_grey"), Symbol::intern("rustc_crate_green") } #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box PassOkay); - reg.register_late_lint_pass(box PassRedBlue); - reg.register_late_lint_pass(box PassGreyGreen); + reg.lint_store.register_lints(&[ + &CRATE_NOT_OKAY, + &CRATE_NOT_RED, + &CRATE_NOT_BLUE, + &CRATE_NOT_GREY, + &CRATE_NOT_GREEN, + ]); + reg.lint_store.register_late_pass(|| box PassOkay); + reg.lint_store.register_late_pass(|| box PassRedBlue); + reg.lint_store.register_late_pass(|| box PassGreyGreen); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index 000e10392e8..1cd3e7b28db 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -7,7 +7,7 @@ extern crate rustc_driver; extern crate syntax; -use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; +use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray}; use rustc_driver::plugin::Registry; use rustc::hir; use syntax::attr; @@ -32,5 +32,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box Pass); + reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]); + reg.lint_store.register_late_pass(|| box Pass); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs index a377b07bd3d..cb793b43498 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs @@ -9,7 +9,7 @@ extern crate rustc; extern crate rustc_driver; use rustc::hir; -use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray}; +use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId}; use rustc_driver::plugin::Registry; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); @@ -30,6 +30,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_late_lint_pass(box Pass); - reg.register_lint_group("lint_me", None, vec![TEST_LINT, PLEASE_LINT]); + reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]); + reg.lint_store.register_late_pass(|| box Pass); + reg.lint_store.register_group(true, "lint_me", None, + vec![LintId::of(&TEST_LINT), LintId::of(&PLEASE_LINT)]); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs index 02675191f78..40c37eb570e 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs @@ -10,8 +10,7 @@ extern crate syntax; extern crate rustc; extern crate rustc_driver; -use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, - EarlyLintPassObject, LintArray}; +use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray}; use rustc_driver::plugin::Registry; use syntax::ast; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); @@ -28,5 +27,6 @@ impl EarlyLintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_early_lint_pass(box Pass as EarlyLintPassObject); + reg.lint_store.register_lints(&[&TEST_LINT]); + reg.lint_store.register_early_pass(|| box Pass); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs index 40f8d490ac8..67135d595f4 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs @@ -8,7 +8,7 @@ extern crate syntax; extern crate rustc; extern crate rustc_driver; -use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; +use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId}; use rustc_driver::plugin::Registry; use syntax::ast; declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff"); @@ -40,6 +40,8 @@ impl EarlyLintPass for Pass { #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_early_lint_pass(box Pass); - reg.register_lint_group("clippy::group", Some("clippy_group"), vec![TEST_LINT, TEST_GROUP]); + reg.lint_store.register_lints(&[&TEST_RUSTC_TOOL_LINT, &TEST_LINT, &TEST_GROUP]); + reg.lint_store.register_early_pass(|| box Pass); + reg.lint_store.register_group(true, "clippy::group", Some("clippy_group"), + vec![LintId::of(&TEST_LINT), LintId::of(&TEST_GROUP)]); } diff --git a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs index 48dd5b122b5..0bfb32c6dc4 100644 --- a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs +++ b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs @@ -6,7 +6,7 @@ extern crate rustc; use rustc::lint::{LintArray, LintPass}; -use rustc::{declare_lint, declare_lint_pass, impl_lint_pass, lint_array}; +use rustc::{declare_lint, declare_lint_pass, impl_lint_pass}; declare_lint! { pub TEST_LINT, @@ -17,10 +17,6 @@ declare_lint! { struct Foo; impl LintPass for Foo { //~ERROR implementing `LintPass` by hand - fn get_lints(&self) -> LintArray { - lint_array!(TEST_LINT) - } - fn name(&self) -> &'static str { "Foo" } @@ -31,10 +27,6 @@ macro_rules! custom_lint_pass_macro { struct Custom; impl LintPass for Custom { //~ERROR implementing `LintPass` by hand - fn get_lints(&self) -> LintArray { - lint_array!(TEST_LINT) - } - fn name(&self) -> &'static str { "Custom" } diff --git a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr index b439ae2cd14..0dbdf4f5aa9 100644 --- a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr +++ b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr @@ -12,7 +12,7 @@ LL | #![deny(rustc::lint_pass_impl_without_macro)] = help: try using `declare_lint_pass!` or `impl_lint_pass!` instead error: implementing `LintPass` by hand - --> $DIR/lint_pass_impl_without_macro.rs:33:14 + --> $DIR/lint_pass_impl_without_macro.rs:29:14 | LL | impl LintPass for Custom { | ^^^^^^^^ diff --git a/src/test/ui/asm/issue-51431.rs b/src/test/ui/asm/issue-51431.rs new file mode 100644 index 00000000000..d29c31fafc2 --- /dev/null +++ b/src/test/ui/asm/issue-51431.rs @@ -0,0 +1,10 @@ +// ignore-emscripten no asm! support + +#![feature(asm)] + +fn main() { + unsafe { + asm! {"mov $0,$1"::"0"("bx"),"1"(0x00)} + //~^ ERROR: invalid value for constraint in inline assembly + } +} diff --git a/src/test/ui/asm/issue-51431.stderr b/src/test/ui/asm/issue-51431.stderr new file mode 100644 index 00000000000..132eea126d6 --- /dev/null +++ b/src/test/ui/asm/issue-51431.stderr @@ -0,0 +1,8 @@ +error[E0669]: invalid value for constraint in inline assembly + --> $DIR/issue-51431.rs:7:32 + | +LL | asm! {"mov $0,$1"::"0"("bx"),"1"(0x00)} + | ^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/associated-const/issue-63496.rs b/src/test/ui/associated-const/issue-63496.rs new file mode 100644 index 00000000000..311c48b5e48 --- /dev/null +++ b/src/test/ui/associated-const/issue-63496.rs @@ -0,0 +1,9 @@ +trait A { + const C: usize; + + fn f() -> ([u8; A::C], [u8; A::C]); + //~^ ERROR: type annotations needed: cannot resolve + //~| ERROR: type annotations needed: cannot resolve +} + +fn main() {} diff --git a/src/test/ui/associated-const/issue-63496.stderr b/src/test/ui/associated-const/issue-63496.stderr new file mode 100644 index 00000000000..70bb12de1fb --- /dev/null +++ b/src/test/ui/associated-const/issue-63496.stderr @@ -0,0 +1,21 @@ +error[E0283]: type annotations needed: cannot resolve `_: A` + --> $DIR/issue-63496.rs:4:21 + | +LL | const C: usize; + | --------------- required by `A::C` +LL | +LL | fn f() -> ([u8; A::C], [u8; A::C]); + | ^^^^ + +error[E0283]: type annotations needed: cannot resolve `_: A` + --> $DIR/issue-63496.rs:4:33 + | +LL | const C: usize; + | --------------- required by `A::C` +LL | +LL | fn f() -> ([u8; A::C], [u8; A::C]); + | ^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs index ce482fff401..97c5acf1f72 100644 --- a/src/test/ui/associated-type-bounds/union-bounds.rs +++ b/src/test/ui/associated-type-bounds/union-bounds.rs @@ -3,13 +3,13 @@ #![feature(associated_type_bounds)] #![feature(untagged_unions)] -#![allow(unions_with_drop_fields, unused_assignments)] +#![allow(unused_assignments)] -trait Tr1 { type As1; } -trait Tr2 { type As2; } -trait Tr3 { type As3; } -trait Tr4<'a> { type As4; } -trait Tr5 { type As5; } +trait Tr1: Copy { type As1: Copy; } +trait Tr2: Copy { type As2: Copy; } +trait Tr3: Copy { type As3: Copy; } +trait Tr4<'a>: Copy { type As4: Copy; } +trait Tr5: Copy { type As5: Copy; } impl Tr1 for &str { type As1 = bool; } impl Tr2 for bool { type As2 = u8; } @@ -71,7 +71,8 @@ where let _: &'a T = &x.f0; } -union UnSelf<T> where Self: Tr1<As1: Tr2> { +#[derive(Copy, Clone)] +union UnSelf<T> where Self: Tr1<As1: Tr2>, T: Copy { f0: T, f1: <Self as Tr1>::As1, f2: <<Self as Tr1>::As1 as Tr2>::As2, diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 563885133a4..64c9f693115 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"ident":{"name":"core","span":{"lo":0,"hi":0}},"attrs":[],"id":0,"kind":{"variant":"ExternCrate","fields":[null]},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"span":{"lo":0,"hi":0},"tokens":[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]}]}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"ident":{"name":"core","span":{"lo":0,"hi":0}},"attrs":[],"id":0,"kind":{"variant":"ExternCrate","fields":[null]},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"span":{"lo":0,"hi":0},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}} diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 7caa9f26bc2..4b5e2d59e38 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -244,4 +244,5 @@ LL | let _ = await bar()?; error: aborting due to 35 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0728. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issues/issue-51719.stderr b/src/test/ui/async-await/issues/issue-51719.stderr index 6c3c8889da7..5b9adb253d9 100644 --- a/src/test/ui/async-await/issues/issue-51719.stderr +++ b/src/test/ui/async-await/issues/issue-51719.stderr @@ -8,3 +8,4 @@ LL | let _gen = || foo().await; error: aborting due to previous error +For more information about this error, try `rustc --explain E0728`. diff --git a/src/test/ui/async-await/issues/issue-51751.stderr b/src/test/ui/async-await/issues/issue-51751.stderr index e50c78534f8..f120bd119c5 100644 --- a/src/test/ui/async-await/issues/issue-51751.stderr +++ b/src/test/ui/async-await/issues/issue-51751.stderr @@ -9,3 +9,4 @@ LL | let finished = result.await; error: aborting due to previous error +For more information about this error, try `rustc --explain E0728`. diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index f63eaa4c48a..538430290d2 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -40,4 +40,5 @@ LL | F: Future error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0728. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issues/issue-62009-2.stderr b/src/test/ui/async-await/issues/issue-62009-2.stderr index 79b6803263e..47b74b5574f 100644 --- a/src/test/ui/async-await/issues/issue-62009-2.stderr +++ b/src/test/ui/async-await/issues/issue-62009-2.stderr @@ -8,3 +8,4 @@ LL | (async || 2333)().await; error: aborting due to previous error +For more information about this error, try `rustc --explain E0728`. diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr index 49ebf414c55..f826a86f089 100644 --- a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr +++ b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr @@ -9,3 +9,4 @@ LL | let y = do_the_thing().await; error: aborting due to previous error +For more information about this error, try `rustc --explain E0728`. diff --git a/src/test/ui/break-outside-loop.rs b/src/test/ui/break-outside-loop.rs index c424c25c646..a6f9d0423d0 100644 --- a/src/test/ui/break-outside-loop.rs +++ b/src/test/ui/break-outside-loop.rs @@ -22,4 +22,12 @@ fn main() { let rs: Foo = Foo{t: pth}; let unconstrained = break; //~ ERROR: `break` outside of a loop + + // This used to ICE because `target_id` passed to `check_expr_break` would be the closure and + // not the `loop`, which failed in the call to `find_breakable`. (#65383) + 'lab: loop { + || { + break 'lab; //~ ERROR `break` inside of a closure + }; + } } diff --git a/src/test/ui/break-outside-loop.stderr b/src/test/ui/break-outside-loop.stderr index 8b686356055..8e300fd848d 100644 --- a/src/test/ui/break-outside-loop.stderr +++ b/src/test/ui/break-outside-loop.stderr @@ -33,7 +33,15 @@ error[E0268]: `break` outside of a loop LL | let unconstrained = break; | ^^^^^ cannot `break` outside of a loop -error: aborting due to 5 previous errors +error[E0267]: `break` inside of a closure + --> $DIR/break-outside-loop.rs:30:13 + | +LL | || { + | -- enclosing closure +LL | break 'lab; + | ^^^^^^^^^^ cannot `break` inside of a closure + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0267, E0268. For more information about an error, try `rustc --explain E0267`. diff --git a/src/test/ui/closures/issue-41366.rs b/src/test/ui/closures/issue-41366.rs new file mode 100644 index 00000000000..5cae0e76d1a --- /dev/null +++ b/src/test/ui/closures/issue-41366.rs @@ -0,0 +1,13 @@ +trait T<'x> { + type V; +} + +impl<'g> T<'g> for u32 { + type V = u16; +} + +fn main() { + (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V); + //~^ ERROR: type mismatch in closure arguments + //~| ERROR: type mismatch resolving +} diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr new file mode 100644 index 00000000000..91d26efbc4f --- /dev/null +++ b/src/test/ui/closures/issue-41366.stderr @@ -0,0 +1,22 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/issue-41366.rs:10:5 + | +LL | (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V); + | ^^-----^ + | | | + | | found signature of `fn(_) -> _` + | expected signature of `for<'x> fn(<u32 as T<'x>>::V) -> _` + | + = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)` + +error[E0271]: type mismatch resolving `for<'x> <[closure@$DIR/issue-41366.rs:10:7: 10:12] as std::ops::FnOnce<(<u32 as T<'x>>::V,)>>::Output == ()` + --> $DIR/issue-41366.rs:10:5 + | +LL | (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V); + | ^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime + | + = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/closures/issue-52437.rs b/src/test/ui/closures/issue-52437.rs new file mode 100644 index 00000000000..6ac5380a5aa --- /dev/null +++ b/src/test/ui/closures/issue-52437.rs @@ -0,0 +1,5 @@ +fn main() { + [(); &(&'static: loop { |x| {}; }) as *const _ as usize] + //~^ ERROR: invalid label name `'static` + //~| ERROR: type annotations needed +} diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr new file mode 100644 index 00000000000..e76f942e9ba --- /dev/null +++ b/src/test/ui/closures/issue-52437.stderr @@ -0,0 +1,15 @@ +error: invalid label name `'static` + --> $DIR/issue-52437.rs:2:13 + | +LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] + | ^^^^^^^ + +error[E0282]: type annotations needed + --> $DIR/issue-52437.rs:2:30 + | +LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] + | ^ consider giving this closure parameter a type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs new file mode 100644 index 00000000000..9859a226efd --- /dev/null +++ b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs @@ -0,0 +1,18 @@ +// Check that unsafe trait object do not implement themselves +// automatically + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized { + fn call(&self); +} + +fn takes_t<S: Trait>(s: S) { + s.call(); +} + +fn takes_t_obj(t: &dyn Trait) { + takes_t(t); //~ ERROR E0277 +} + +fn main() {} diff --git a/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr new file mode 100644 index 00000000000..b5a86acfb97 --- /dev/null +++ b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `&dyn Trait: Trait` is not satisfied + --> $DIR/coherence-unsafe-trait-object-impl.rs:15:13 + | +LL | fn takes_t<S: Trait>(s: S) { + | ------- ----- required by this bound in `takes_t` +... +LL | takes_t(t); + | ^ the trait `Trait` is not implemented for `&dyn Trait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/coherence/impl-foreign-for-foreign.rs b/src/test/ui/coherence/impl-foreign-for-foreign.rs new file mode 100644 index 00000000000..de0b66a35eb --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign.rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for i32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-foreign.stderr b/src/test/ui/coherence/impl-foreign-for-foreign.stderr new file mode 100644 index 00000000000..b03a75a77c3 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign.stderr @@ -0,0 +1,12 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign.rs:12:1 + | +LL | impl Remote for i32 { + | ^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs new file mode 100644 index 00000000000..5146263d991 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs @@ -0,0 +1,25 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote1<Rc<i32>> for i32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote1<Rc<Local>> for f64 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl<T> Remote1<Rc<T>> for f32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr new file mode 100644 index 00000000000..bfaec790b20 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr @@ -0,0 +1,30 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign[foreign].rs:12:1 + | +LL | impl Remote1<Rc<i32>> for i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign[foreign].rs:16:1 + | +LL | impl Remote1<Rc<Local>> for f64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-foreign[foreign].rs:20:1 + | +LL | impl<T> Remote1<Rc<T>> for f32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[local].rs b/src/test/ui/coherence/impl-foreign-for-foreign[local].rs new file mode 100644 index 00000000000..050769dcf4c --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-foreign[local].rs @@ -0,0 +1,16 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local<T>(Rc<T>); + +impl Remote1<Local<i32>> for i32 {} +impl<T> Remote1<Local<T>> for f32 {} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs new file mode 100644 index 00000000000..03b11edf98b --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs @@ -0,0 +1,21 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for Box<i32> { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl<T> Remote for Box<Rc<T>> { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr new file mode 100644 index 00000000000..2ce4921cf93 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr @@ -0,0 +1,21 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-fundamental[foreign].rs:12:1 + | +LL | impl Remote for Box<i32> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign-for-fundamental[foreign].rs:16:1 + | +LL | impl<T> Remote for Box<Rc<T>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs b/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs new file mode 100644 index 00000000000..ae03ce6a440 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1<T>(Rc<T>); + +impl Remote for Box<Local> {} +impl<T> Remote for Box<Local1<T>> {} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign-for-local.rs b/src/test/ui/coherence/impl-foreign-for-local.rs new file mode 100644 index 00000000000..c9dddeba18d --- /dev/null +++ b/src/test/ui/coherence/impl-foreign-for-local.rs @@ -0,0 +1,15 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl Remote for Local {} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs new file mode 100644 index 00000000000..06efb6c2ad7 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs @@ -0,0 +1,26 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1<T>(Rc<T>); + +impl Remote1<Box<String>> for i32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl Remote1<Box<Rc<i32>>> for f64 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} +impl<T> Remote1<Box<Rc<T>>> for f32 { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr new file mode 100644 index 00000000000..bf2361a1718 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr @@ -0,0 +1,30 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:13:1 + | +LL | impl Remote1<Box<String>> for i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:17:1 + | +LL | impl Remote1<Box<Rc<i32>>> for f64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:21:1 + | +LL | impl<T> Remote1<Box<Rc<T>>> for f32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs new file mode 100644 index 00000000000..d47e0a36a56 --- /dev/null +++ b/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs @@ -0,0 +1,18 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1<T>(Rc<T>); + +impl Remote1<Box<Local>> for i32 {} +impl Remote1<Box<Local1<i32>>> for f64 {} +impl<T> Remote1<Box<Local1<T>>> for f32 {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs new file mode 100644 index 00000000000..db7a2ae8076 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs @@ -0,0 +1,23 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; +use std::sync::Arc; + +struct Local; + +impl Remote for Rc<Local> { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +impl<T> Remote for Arc<T> { + //~^ ERROR only traits defined in the current crate + // | can be implemented for arbitrary types [E0117] +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr new file mode 100644 index 00000000000..d7ffcaf76f9 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr @@ -0,0 +1,21 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl[t]-foreign-for-foreign[t].rs:13:1 + | +LL | impl Remote for Rc<Local> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/impl[t]-foreign-for-foreign[t].rs:18:1 + | +LL | impl<T> Remote for Arc<T> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate + | + = note: the impl does not reference only types defined in this crate + = note: define and implement a trait or new type instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs new file mode 100644 index 00000000000..4cc19e1a526 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; + +impl<T> Remote for Box<T> { + //~^ ERROR type parameter `T` must be used as the type parameter for + // | some local type (e.g., `MyStruct<T>`) +} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr new file mode 100644 index 00000000000..20ce11ef975 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr @@ -0,0 +1,11 @@ +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`) + --> $DIR/impl[t]-foreign-for-fundamental[t].rs:12:1 + | +LL | impl<T> Remote for Box<T> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type + | + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0210`. diff --git a/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs new file mode 100644 index 00000000000..914680f191a --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1<S>(Rc<S>); + +impl<T> Remote1<Box<Local>> for Rc<T> {} +impl<S, T> Remote1<Box<Local1<S>>> for Rc<T> {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs new file mode 100644 index 00000000000..1e84ff40c62 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs @@ -0,0 +1,17 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1<S>(Rc<S>); + +impl<T> Remote1<Local> for Rc<T> {} +impl<T, S> Remote1<Local1<S>> for Rc<T> {} + +fn main() {} diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs new file mode 100644 index 00000000000..ea6aa101d20 --- /dev/null +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs @@ -0,0 +1,19 @@ +#![feature(re_rebalance_coherence)] + +// compile-flags:--crate-name=test +// aux-build:coherence_lib.rs +// check-pass + +extern crate coherence_lib as lib; +use lib::*; +use std::rc::Rc; + +struct Local; +struct Local1<S>(Rc<S>); + +impl<T> Remote1<Local> for Box<Rc<T>> {} +impl<T, S> Remote1<Local1<S>> for Box<Rc<T>> {} +impl<T> Remote1<Box<Local>> for Box<Rc<T>> {} +impl<T, S> Remote1<Box<Local1<S>>> for Box<Rc<T>> {} + +fn main() {} diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr index b7fd29ce706..7090cb880fd 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr @@ -1,20 +1,20 @@ error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:6:41 + --> $DIR/const-argument-cross-crate-mismatch.rs:6:67 | LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `3usize`, found `2usize` + | ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements | - = note: expected type `const_generic_lib::Struct<3usize>` - found type `const_generic_lib::Struct<_: usize>` + = note: expected type `[u8; 3]` + found type `[u8; 2]` error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:8:39 + --> $DIR/const-argument-cross-crate-mismatch.rs:8:65 | LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2usize`, found `3usize` + | ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements | - = note: expected type `const_generic_lib::Struct<2usize>` - found type `const_generic_lib::Struct<_: usize>` + = note: expected type `[u8; 2]` + found type `[u8; 3]` error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/issue-65394.rs b/src/test/ui/consts/const-eval/issue-65394.rs index 978e227bcc8..8cf527f0429 100644 --- a/src/test/ui/consts/const-eval/issue-65394.rs +++ b/src/test/ui/consts/const-eval/issue-65394.rs @@ -1,8 +1,5 @@ // Test for absence of validation mismatch ICE in #65394 -#![feature(rustc_attrs)] - -#[rustc_mir(borrowck_graphviz_postflow="hello.dot")] const _: Vec<i32> = { let mut x = Vec::<i32>::new(); let r = &mut x; //~ ERROR references in constants may only refer to immutable values diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr index f48c551cb50..15df813836e 100644 --- a/src/test/ui/consts/const-eval/issue-65394.stderr +++ b/src/test/ui/consts/const-eval/issue-65394.stderr @@ -1,11 +1,11 @@ error[E0017]: references in constants may only refer to immutable values - --> $DIR/issue-65394.rs:8:13 + --> $DIR/issue-65394.rs:5:13 | LL | let r = &mut x; | ^^^^^^ constants require immutable values -[ERROR rustc_mir::transform::qualify_consts] old validator: [($DIR/issue-65394.rs:8:13: 8:19, "MutBorrow(Mut { allow_two_phase_borrow: false })")] -[ERROR rustc_mir::transform::qualify_consts] new validator: [($DIR/issue-65394.rs:8:13: 8:19, "MutBorrow(Mut { allow_two_phase_borrow: false })"), ($DIR/issue-65394.rs:7:9: 7:14, "LiveDrop")] +[ERROR rustc_mir::transform::qualify_consts] old validator: [($DIR/issue-65394.rs:5:13: 5:19, "MutBorrow(Mut { allow_two_phase_borrow: false })")] +[ERROR rustc_mir::transform::qualify_consts] new validator: [($DIR/issue-65394.rs:5:13: 5:19, "MutBorrow(Mut { allow_two_phase_borrow: false })"), ($DIR/issue-65394.rs:4:9: 4:14, "LiveDrop")] error: aborting due to previous error For more information about this error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/const-int-pow-rpass.rs b/src/test/ui/consts/const-int-pow-rpass.rs new file mode 100644 index 00000000000..8e84a900605 --- /dev/null +++ b/src/test/ui/consts/const-int-pow-rpass.rs @@ -0,0 +1,11 @@ +// run-pass + +const IS_POWER_OF_TWO_A: bool = 0u32.is_power_of_two(); +const IS_POWER_OF_TWO_B: bool = 32u32.is_power_of_two(); +const IS_POWER_OF_TWO_C: bool = 33u32.is_power_of_two(); + +fn main() { + assert!(!IS_POWER_OF_TWO_A); + assert!(IS_POWER_OF_TWO_B); + assert!(!IS_POWER_OF_TWO_C); +} diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.rs b/src/test/ui/consts/miri_unleashed/non_const_fn.rs new file mode 100644 index 00000000000..e1ac4306575 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/non_const_fn.rs @@ -0,0 +1,13 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +#![warn(const_err)] + +// A test demonstrating that we prevent calling non-const fn during CTFE. + +fn foo() {} + +const C: () = foo(); //~ WARN: skipping const checks +//~^ WARN any use of this value will cause an error + +fn main() { + println!("{:?}", C); //~ ERROR: evaluation of constant expression failed +} diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr new file mode 100644 index 00000000000..7a574b34304 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr @@ -0,0 +1,29 @@ +warning: skipping const checks + --> $DIR/non_const_fn.rs:8:15 + | +LL | const C: () = foo(); + | ^^^^^ + +warning: any use of this value will cause an error + --> $DIR/non_const_fn.rs:8:15 + | +LL | const C: () = foo(); + | --------------^^^^^- + | | + | calling non-const function `foo` + | +note: lint level defined here + --> $DIR/non_const_fn.rs:2:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + +error[E0080]: evaluation of constant expression failed + --> $DIR/non_const_fn.rs:12:22 + | +LL | println!("{:?}", C); + | ^ referenced constant has errors + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index 7fd3f420a6d..5a7568fe2cd 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -8,6 +8,7 @@ #![feature(slice_patterns)] use std::cell::{Cell, RefCell}; +use std::mem::ManuallyDrop; use std::ops::Generator; use std::panic; use std::pin::Pin; @@ -152,17 +153,16 @@ fn assignment1(a: &Allocator, c0: bool) { _v = _w; } -#[allow(unions_with_drop_fields)] union Boxy<T> { - a: T, - b: T, + a: ManuallyDrop<T>, + b: ManuallyDrop<T>, } fn union1(a: &Allocator) { unsafe { - let mut u = Boxy { a: a.alloc() }; - u.b = a.alloc(); - drop(u.a); + let mut u = Boxy { a: ManuallyDrop::new(a.alloc()) }; + *u.b = a.alloc(); // drops first alloc + drop(ManuallyDrop::into_inner(u.a)); } } diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs index 3d75251e156..0faa9090f4e 100644 --- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs @@ -1,7 +1,7 @@ #![feature(untagged_unions)] -trait Tr1 { type As1; } -trait Tr2 { type As2; } +trait Tr1 { type As1: Copy; } +trait Tr2 { type As2: Copy; } struct S1; #[derive(Copy, Clone)] @@ -32,7 +32,7 @@ enum _En1<T: Tr1<As1: Tr2>> { union _Un1<T: Tr1<As1: Tr2>> { //~^ ERROR associated type bounds are unstable - outest: T, + outest: std::mem::ManuallyDrop<T>, outer: T::As1, inner: <T::As1 as Tr2>::As2, } diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs new file mode 100644 index 00000000000..8945360b7be --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs @@ -0,0 +1,41 @@ +// Test that the use of the non object-safe trait objects +// are gated by `object_safe_for_dispatch` feature gate. + +trait NonObjectSafe1: Sized {} + +trait NonObjectSafe2 { + fn static_fn() {} +} + +trait NonObjectSafe3 { + fn foo<T>(&self); +} + +trait NonObjectSafe4 { + fn foo(&self, &Self); +} + +fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) { + //~^ ERROR E0038 +} + +fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 { + //~^ ERROR E0038 + loop {} +} + +fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) { + //~^ ERROR E0038 +} + +fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> { + //~^ ERROR E0038 + loop {} +} + +trait Trait {} + +impl Trait for dyn NonObjectSafe1 {} +//~^ ERROR E0038 + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr new file mode 100644 index 00000000000..54e64e2fc1b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr @@ -0,0 +1,46 @@ +error[E0038]: the trait `NonObjectSafe1` cannot be made into an object + --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:1 + | +LL | fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + +error[E0038]: the trait `NonObjectSafe2` cannot be made into an object + --> $DIR/feature-gate-object_safe_for_dispatch.rs:22:1 + | +LL | fn static_fn() {} + | --------- associated function `static_fn` has no `self` parameter +... +LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe2` cannot be made into an object + +error[E0038]: the trait `NonObjectSafe3` cannot be made into an object + --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:1 + | +LL | fn foo<T>(&self); + | --- method `foo` has generic type parameters +... +LL | fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe3` cannot be made into an object + +error[E0038]: the trait `NonObjectSafe4` cannot be made into an object + --> $DIR/feature-gate-object_safe_for_dispatch.rs:31:1 + | +LL | fn foo(&self, &Self); + | --- method `foo` references the `Self` type in its parameters or return type +... +LL | fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe4` cannot be made into an object + +error[E0038]: the trait `NonObjectSafe1` cannot be made into an object + --> $DIR/feature-gate-object_safe_for_dispatch.rs:38:6 + | +LL | impl Trait for dyn NonObjectSafe1 {} + | ^^^^^ the trait `NonObjectSafe1` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs index 3bac3d853e9..9ee0e6f681d 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs @@ -7,11 +7,11 @@ union U2<T: Copy> { // OK } union U3 { //~ ERROR unions with non-`Copy` fields are unstable - a: String, + a: String, //~ ERROR unions may not contain fields that need dropping } union U4<T> { //~ ERROR unions with non-`Copy` fields are unstable - a: T, + a: T, //~ ERROR unions may not contain fields that need dropping } union U5 { //~ ERROR unions with `Drop` implementations are unstable diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index f59a34e2c81..1885518a458 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -31,6 +31,31 @@ LL | | } = note: for more information, see https://github.com/rust-lang/rust/issues/32836 = help: add `#![feature(untagged_unions)]` to the crate attributes to enable -error: aborting due to 3 previous errors +error[E0740]: unions may not contain fields that need dropping + --> $DIR/feature-gate-untagged_unions.rs:10:5 + | +LL | a: String, + | ^^^^^^^^^ + | +note: `std::mem::ManuallyDrop` can be used to wrap the type + --> $DIR/feature-gate-untagged_unions.rs:10:5 + | +LL | a: String, + | ^^^^^^^^^ + +error[E0740]: unions may not contain fields that need dropping + --> $DIR/feature-gate-untagged_unions.rs:14:5 + | +LL | a: T, + | ^^^^ + | +note: `std::mem::ManuallyDrop` can be used to wrap the type + --> $DIR/feature-gate-untagged_unions.rs:14:5 + | +LL | a: T, + | ^^^^ + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0658, E0740. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/impl-trait/issues/universal-issue-48703.rs b/src/test/ui/impl-trait/issues/universal-issue-48703.rs index e434e10bf89..f661c62c9e4 100644 --- a/src/test/ui/impl-trait/issues/universal-issue-48703.rs +++ b/src/test/ui/impl-trait/issues/universal-issue-48703.rs @@ -5,5 +5,5 @@ use std::fmt::Debug; fn foo<T>(x: impl Debug) { } fn main() { - foo::<String>('a'); //~ ERROR cannot provide explicit type parameters + foo::<String>('a'); //~ ERROR cannot provide explicit generic arguments } diff --git a/src/test/ui/impl-trait/issues/universal-issue-48703.stderr b/src/test/ui/impl-trait/issues/universal-issue-48703.stderr index 527bbd5f30f..a51302dce29 100644 --- a/src/test/ui/impl-trait/issues/universal-issue-48703.stderr +++ b/src/test/ui/impl-trait/issues/universal-issue-48703.stderr @@ -1,4 +1,4 @@ -error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. +error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position --> $DIR/universal-issue-48703.rs:8:5 | LL | foo::<String>('a'); diff --git a/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs index d3d561621fc..4ac0a694cb1 100644 --- a/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs +++ b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs @@ -12,6 +12,6 @@ struct TestEvent(i32); fn main() { let mut evt = EventHandler {}; evt.handle_event::<TestEvent, fn(TestEvent)>(|_evt| { - //~^ ERROR cannot provide explicit type parameters + //~^ ERROR cannot provide explicit generic arguments }); } diff --git a/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr index e2e6581fcf9..f09aa166ef5 100644 --- a/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr +++ b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr @@ -1,4 +1,4 @@ -error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. +error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position --> $DIR/universal-turbofish-in-method-issue-50950.rs:14:9 | LL | evt.handle_event::<TestEvent, fn(TestEvent)>(|_evt| { diff --git a/src/test/ui/issues/issue-17546.stderr b/src/test/ui/issues/issue-17546.stderr index 4a0fb186e49..291086d4f69 100644 --- a/src/test/ui/issues/issue-17546.stderr +++ b/src/test/ui/issues/issue-17546.stderr @@ -27,7 +27,7 @@ LL | use std::prelude::v1::Result; | LL | use std::result::Result; | - and 1 other candidates + and 1 other candidate error[E0573]: expected type, found variant `Result` --> $DIR/issue-17546.rs:28:13 @@ -44,7 +44,7 @@ LL | use std::prelude::v1::Result; | LL | use std::result::Result; | - and 1 other candidates + and 1 other candidate error[E0573]: expected type, found variant `NoResult` --> $DIR/issue-17546.rs:33:15 diff --git a/src/test/ui/issues/issue-19538.stderr b/src/test/ui/issues/issue-19538.stderr index 5415a45f7d6..83c03b514dd 100644 --- a/src/test/ui/issues/issue-19538.stderr +++ b/src/test/ui/issues/issue-19538.stderr @@ -17,6 +17,7 @@ LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&mut dyn Bar>` for `&mut Thing` + = note: required by cast to type `&mut dyn Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-20692.stderr b/src/test/ui/issues/issue-20692.stderr index 66309394a42..06c83f65be2 100644 --- a/src/test/ui/issues/issue-20692.stderr +++ b/src/test/ui/issues/issue-20692.stderr @@ -14,6 +14,7 @@ LL | let _ = x | = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Array>` for `&T` + = note: required by cast to type `&dyn Array` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-38604.stderr b/src/test/ui/issues/issue-38604.stderr index 8ef7d346cb3..8b923a2c6b2 100644 --- a/src/test/ui/issues/issue-38604.stderr +++ b/src/test/ui/issues/issue-38604.stderr @@ -14,6 +14,7 @@ LL | Box::new(()); | = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<()>` + = note: required by cast to type `std::boxed::Box<dyn Foo>` error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr index 27901d06927..a93f4686496 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied - --> $DIR/kindck-inherited-copy-bound.rs:18:16 + --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | fn take_param<T:Foo>(foo: &T) { } | ---------- --- required by this bound in `take_param` @@ -10,7 +10,7 @@ LL | take_param(&x); = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/kindck-inherited-copy-bound.rs:24:19 + --> $DIR/kindck-inherited-copy-bound.rs:28:19 | LL | let z = &x as &dyn Foo; | ^^^^^^^^ the trait `Foo` cannot be made into an object @@ -18,13 +18,14 @@ LL | let z = &x as &dyn Foo; = note: the trait cannot require that `Self : Sized` error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/kindck-inherited-copy-bound.rs:24:13 + --> $DIR/kindck-inherited-copy-bound.rs:28:13 | LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<{integer}>` + = note: required by cast to type `&dyn Foo` error: aborting due to 3 previous errors diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr new file mode 100644 index 00000000000..7c67c5f9e95 --- /dev/null +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied + --> $DIR/kindck-inherited-copy-bound.rs:21:16 + | +LL | fn take_param<T:Foo>(foo: &T) { } + | ---------- --- required by this bound in `take_param` +... +LL | take_param(&x); + | ^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` + | + = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/kindck-inherited-copy-bound.rs:28:13 + | +LL | let z = &x as &dyn Foo; + | ^^ the trait `Foo` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<i32>` + = note: required by cast to type `&dyn Foo` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0038, E0277. +For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.rs b/src/test/ui/kindck/kindck-inherited-copy-bound.rs index 61e72908248..aad693e5b19 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.rs +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.rs @@ -1,5 +1,8 @@ // Test that Copy bounds inherited by trait are checked. +// +// revisions: curr object_safe_for_dispatch +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] #![feature(box_syntax)] use std::any::Any; @@ -15,15 +18,17 @@ fn take_param<T:Foo>(foo: &T) { } fn a() { let x: Box<_> = box 3; - take_param(&x); //~ ERROR E0277 + take_param(&x); //[curr]~ ERROR E0277 + //[object_safe_for_dispatch]~^ ERROR E0277 } fn b() { let x: Box<_> = box 3; let y = &x; let z = &x as &dyn Foo; - //~^ ERROR E0038 - //~| ERROR E0038 + //[curr]~^ ERROR E0038 + //[curr]~| ERROR E0038 + //[object_safe_for_dispatch]~^^^ ERROR E0038 } fn main() { } diff --git a/src/test/ui/lint/unused_parens_json_suggestion.fixed b/src/test/ui/lint/unused_parens_json_suggestion.fixed index 42740711910..15ee19755bf 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.fixed +++ b/src/test/ui/lint/unused_parens_json_suggestion.fixed @@ -1,5 +1,4 @@ -// compile-flags: --error-format pretty-json -Zunstable-options -// build-pass (FIXME(62277): could be check-pass?) +// compile-flags: --error-format json -Zunstable-options // run-rustfix // The output for humans should just highlight the whole span without showing @@ -8,13 +7,13 @@ // stripping away any starting or ending parenthesis characters—hence this // test of the JSON error format. -#![warn(unused_parens)] +#![deny(unused_parens)] #![allow(unreachable_code)] fn main() { // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not // the malformed `1 / (2 + 3` - let _a = 1 / (2 + 3); + let _a = 1 / (2 + 3); //~ERROR unnecessary parentheses f(); } diff --git a/src/test/ui/lint/unused_parens_json_suggestion.rs b/src/test/ui/lint/unused_parens_json_suggestion.rs index 87192503986..d72df21e09a 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.rs +++ b/src/test/ui/lint/unused_parens_json_suggestion.rs @@ -1,5 +1,4 @@ -// compile-flags: --error-format pretty-json -Zunstable-options -// build-pass (FIXME(62277): could be check-pass?) +// compile-flags: --error-format json -Zunstable-options // run-rustfix // The output for humans should just highlight the whole span without showing @@ -8,13 +7,13 @@ // stripping away any starting or ending parenthesis characters—hence this // test of the JSON error format. -#![warn(unused_parens)] +#![deny(unused_parens)] #![allow(unreachable_code)] fn main() { // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not // the malformed `1 / (2 + 3` - let _a = (1 / (2 + 3)); + let _a = (1 / (2 + 3)); //~ERROR unnecessary parentheses f(); } diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr index 256c7555c90..c503c100808 100644 --- a/src/test/ui/lint/unused_parens_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr @@ -1,106 +1,16 @@ -{ - "message": "unnecessary parentheses around assigned value", - "code": { - "code": "unused_parens", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "$DIR/unused_parens_json_suggestion.rs", - "byte_start": 654, - "byte_end": 667, - "line_start": 17, - "line_end": 17, - "column_start": 14, - "column_end": 27, - "is_primary": true, - "text": [ - { - "text": " let _a = (1 / (2 + 3));", - "highlight_start": 14, - "highlight_end": 27 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "lint level defined here", - "code": null, - "level": "note", - "spans": [ - { - "file_name": "$DIR/unused_parens_json_suggestion.rs", - "byte_start": 472, - "byte_end": 485, - "line_start": 11, - "line_end": 11, - "column_start": 9, - "column_end": 22, - "is_primary": true, - "text": [ - { - "text": "#![warn(unused_parens)]", - "highlight_start": 9, - "highlight_end": 22 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [], - "rendered": null - }, - { - "message": "remove these parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/unused_parens_json_suggestion.rs", - "byte_start": 654, - "byte_end": 667, - "line_start": 17, - "line_end": 17, - "column_start": 14, - "column_end": 27, - "is_primary": true, - "text": [ - { - "text": " let _a = (1 / (2 + 3));", - "highlight_start": 14, - "highlight_end": 27 - } - ], - "label": null, - "suggested_replacement": "1 / (2 + 3)", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unnecessary parentheses around assigned value - --> $DIR/unused_parens_json_suggestion.rs:17:14 +{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":596,"byte_end":609,"line_start":16,"line_end":16,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3)); + --> $DIR/unused_parens_json_suggestion.rs:16:14 | LL | let _a = (1 / (2 + 3)); | ^^^^^^^^^^^^^ help: remove these parentheses | note: lint level defined here - --> $DIR/unused_parens_json_suggestion.rs:11:9 + --> $DIR/unused_parens_json_suggestion.rs:10:9 | -LL | #![warn(unused_parens)] +LL | #![deny(unused_parens)] | ^^^^^^^^^^^^^ -" -} +"} +{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error + +"} diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed b/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed index 2459eb1ac5c..1d891d328dd 100644 --- a/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed @@ -1,5 +1,4 @@ -// compile-flags: --error-format pretty-json -Zunstable-options -// build-pass +// compile-flags: --error-format json -Zunstable-options // run-rustfix // The output for humans should just highlight the whole span without showing @@ -8,14 +7,14 @@ // stripping away any starting or ending parenthesis characters—hence this // test of the JSON error format. -#![warn(unused_parens)] +#![deny(unused_parens)] #![allow(unreachable_code)] fn main() { let _b = false; - if _b { + if _b { //~ ERROR unnecessary parentheses println!("hello"); } @@ -26,29 +25,29 @@ fn main() { fn f() -> bool { let c = false; - if c { + if c { //~ ERROR unnecessary parentheses println!("next"); } - if c { + if c { //~ ERROR unnecessary parentheses println!("prev"); } while false && true { - if c { + if c { //~ ERROR unnecessary parentheses println!("norm"); } } - while true && false { - for _ in 0 .. 3 { + while true && false { //~ ERROR unnecessary parentheses + for _ in 0 .. 3 { //~ ERROR unnecessary parentheses println!("e~") } } - for _ in 0 .. 3 { - while true && false { + for _ in 0 .. 3 { //~ ERROR unnecessary parentheses + while true && false { //~ ERROR unnecessary parentheses println!("e~") } } diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.rs b/src/test/ui/lint/unused_parens_remove_json_suggestion.rs index 0e9869b67d5..494cd184506 100644 --- a/src/test/ui/lint/unused_parens_remove_json_suggestion.rs +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.rs @@ -1,5 +1,4 @@ -// compile-flags: --error-format pretty-json -Zunstable-options -// build-pass +// compile-flags: --error-format json -Zunstable-options // run-rustfix // The output for humans should just highlight the whole span without showing @@ -8,14 +7,14 @@ // stripping away any starting or ending parenthesis characters—hence this // test of the JSON error format. -#![warn(unused_parens)] +#![deny(unused_parens)] #![allow(unreachable_code)] fn main() { let _b = false; - if (_b) { + if (_b) { //~ ERROR unnecessary parentheses println!("hello"); } @@ -26,29 +25,29 @@ fn main() { fn f() -> bool { let c = false; - if(c) { + if(c) { //~ ERROR unnecessary parentheses println!("next"); } - if (c){ + if (c){ //~ ERROR unnecessary parentheses println!("prev"); } while (false && true){ - if (c) { + if (c) { //~ ERROR unnecessary parentheses println!("norm"); } } - while(true && false) { - for _ in (0 .. 3){ + while(true && false) { //~ ERROR unnecessary parentheses + for _ in (0 .. 3){ //~ ERROR unnecessary parentheses println!("e~") } } - for _ in (0 .. 3) { - while (true && false) { + for _ in (0 .. 3) { //~ ERROR unnecessary parentheses + while (true && false) { //~ ERROR unnecessary parentheses println!("e~") } } diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr b/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr index b4eab200dd0..873f105435e 100644 --- a/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr +++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr @@ -1,666 +1,72 @@ -{ - "message": "unnecessary parentheses around `if` condition", - "code": { - "code": "unused_parens", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 521, - "byte_end": 525, - "line_start": 18, - "line_end": 18, - "column_start": 8, - "column_end": 12, - "is_primary": true, - "text": [ - { - "text": " if (_b) {", - "highlight_start": 8, - "highlight_end": 12 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "lint level defined here", - "code": null, - "level": "note", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 435, - "byte_end": 448, - "line_start": 11, - "line_end": 11, - "column_start": 9, - "column_end": 22, - "is_primary": true, - "text": [ - { - "text": "#![warn(unused_parens)]", - "highlight_start": 9, - "highlight_end": 22 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [], - "rendered": null - }, - { - "message": "remove these parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 521, - "byte_end": 525, - "line_start": 18, - "line_end": 18, - "column_start": 8, - "column_end": 12, - "is_primary": true, - "text": [ - { - "text": " if (_b) {", - "highlight_start": 8, - "highlight_end": 12 - } - ], - "label": null, - "suggested_replacement": "_b", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unnecessary parentheses around `if` condition - --> $DIR/unused_parens_remove_json_suggestion.rs:18:8 +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":500,"byte_end":504,"line_start":17,"line_end":17,"column_start":8,"column_end":12,"is_primary":true,"text":[{"text":" if (_b) { + --> $DIR/unused_parens_remove_json_suggestion.rs:17:8 | LL | if (_b) { | ^^^^ help: remove these parentheses | note: lint level defined here - --> $DIR/unused_parens_remove_json_suggestion.rs:11:9 + --> $DIR/unused_parens_remove_json_suggestion.rs:10:9 | -LL | #![warn(unused_parens)] +LL | #![deny(unused_parens)] | ^^^^^^^^^^^^^ -" -} -{ - "message": "unnecessary parentheses around `if` condition", - "code": { - "code": "unused_parens", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 618, - "byte_end": 621, - "line_start": 29, - "line_end": 29, - "column_start": 7, - "column_end": 10, - "is_primary": true, - "text": [ - { - "text": " if(c) {", - "highlight_start": 7, - "highlight_end": 10 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "remove these parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 618, - "byte_end": 621, - "line_start": 29, - "line_end": 29, - "column_start": 7, - "column_end": 10, - "is_primary": true, - "text": [ - { - "text": " if(c) {", - "highlight_start": 7, - "highlight_end": 10 - } - ], - "label": null, - "suggested_replacement": " c", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unnecessary parentheses around `if` condition - --> $DIR/unused_parens_remove_json_suggestion.rs:29:7 +"} +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":631,"byte_end":634,"line_start":28,"line_end":28,"column_start":7,"column_end":10,"is_primary":true,"text":[{"text":" if(c) { + --> $DIR/unused_parens_remove_json_suggestion.rs:28:7 | LL | if(c) { | ^^^ help: remove these parentheses -" -} -{ - "message": "unnecessary parentheses around `if` condition", - "code": { - "code": "unused_parens", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 664, - "byte_end": 667, - "line_start": 33, - "line_end": 33, - "column_start": 8, - "column_end": 11, - "is_primary": true, - "text": [ - { - "text": " if (c){", - "highlight_start": 8, - "highlight_end": 11 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "remove these parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 664, - "byte_end": 667, - "line_start": 33, - "line_end": 33, - "column_start": 8, - "column_end": 11, - "is_primary": true, - "text": [ - { - "text": " if (c){", - "highlight_start": 8, - "highlight_end": 11 - } - ], - "label": null, - "suggested_replacement": "c ", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unnecessary parentheses around `if` condition - --> $DIR/unused_parens_remove_json_suggestion.rs:33:8 +"} +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":711,"byte_end":714,"line_start":32,"line_end":32,"column_start":8,"column_end":11,"is_primary":true,"text":[{"text":" if (c){ + --> $DIR/unused_parens_remove_json_suggestion.rs:32:8 | LL | if (c){ | ^^^ help: remove these parentheses -" -} -{ - "message": "unnecessary parentheses around `while` condition", - "code": { - "code": "unused_parens", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 712, - "byte_end": 727, - "line_start": 37, - "line_end": 37, - "column_start": 11, - "column_end": 26, - "is_primary": true, - "text": [ - { - "text": " while (false && true){", - "highlight_start": 11, - "highlight_end": 26 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "remove these parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 712, - "byte_end": 727, - "line_start": 37, - "line_end": 37, - "column_start": 11, - "column_end": 26, - "is_primary": true, - "text": [ - { - "text": " while (false && true){", - "highlight_start": 11, - "highlight_end": 26 - } - ], - "label": null, - "suggested_replacement": "false && true ", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unnecessary parentheses around `while` condition - --> $DIR/unused_parens_remove_json_suggestion.rs:37:11 +"} +{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":808,"line_start":36,"line_end":36,"column_start":11,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":808,"line_start":36,"line_end":36,"column_start":11,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":26}],"label":null,"suggested_replacement":"false && true ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition + --> $DIR/unused_parens_remove_json_suggestion.rs:36:11 | LL | while (false && true){ | ^^^^^^^^^^^^^^^ help: remove these parentheses -" -} -{ - "message": "unnecessary parentheses around `if` condition", - "code": { - "code": "unused_parens", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 740, - "byte_end": 743, - "line_start": 38, - "line_end": 38, - "column_start": 12, - "column_end": 15, - "is_primary": true, - "text": [ - { - "text": " if (c) {", - "highlight_start": 12, - "highlight_end": 15 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "remove these parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 740, - "byte_end": 743, - "line_start": 38, - "line_end": 38, - "column_start": 12, - "column_end": 15, - "is_primary": true, - "text": [ - { - "text": " if (c) {", - "highlight_start": 12, - "highlight_end": 15 - } - ], - "label": null, - "suggested_replacement": "c", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unnecessary parentheses around `if` condition - --> $DIR/unused_parens_remove_json_suggestion.rs:38:12 +"} +{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":824,"line_start":37,"line_end":37,"column_start":12,"column_end":15,"is_primary":true,"text":[{"text":" if (c) { + --> $DIR/unused_parens_remove_json_suggestion.rs:37:12 | LL | if (c) { | ^^^ help: remove these parentheses -" -} -{ - "message": "unnecessary parentheses around `while` condition", - "code": { - "code": "unused_parens", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 803, - "byte_end": 818, - "line_start": 44, - "line_end": 44, - "column_start": 10, - "column_end": 25, - "is_primary": true, - "text": [ - { - "text": " while(true && false) {", - "highlight_start": 10, - "highlight_end": 25 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "remove these parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 803, - "byte_end": 818, - "line_start": 44, - "line_end": 44, - "column_start": 10, - "column_end": 25, - "is_primary": true, - "text": [ - { - "text": " while(true && false) {", - "highlight_start": 10, - "highlight_end": 25 - } - ], - "label": null, - "suggested_replacement": " true && false", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unnecessary parentheses around `while` condition - --> $DIR/unused_parens_remove_json_suggestion.rs:44:10 +"} +{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":918,"byte_end":933,"line_start":43,"line_end":43,"column_start":10,"column_end":25,"is_primary":true,"text":[{"text":" while(true && false) { + --> $DIR/unused_parens_remove_json_suggestion.rs:43:10 | LL | while(true && false) { | ^^^^^^^^^^^^^^^ help: remove these parentheses -" -} -{ - "message": "unnecessary parentheses around `for` head expression", - "code": { - "code": "unused_parens", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 838, - "byte_end": 846, - "line_start": 45, - "line_end": 45, - "column_start": 18, - "column_end": 26, - "is_primary": true, - "text": [ - { - "text": " for _ in (0 .. 3){", - "highlight_start": 18, - "highlight_end": 26 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "remove these parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 838, - "byte_end": 846, - "line_start": 45, - "line_end": 45, - "column_start": 18, - "column_end": 26, - "is_primary": true, - "text": [ - { - "text": " for _ in (0 .. 3){", - "highlight_start": 18, - "highlight_end": 26 - } - ], - "label": null, - "suggested_replacement": "0 .. 3 ", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unnecessary parentheses around `for` head expression - --> $DIR/unused_parens_remove_json_suggestion.rs:45:18 +"} +{"message":"unnecessary parentheses around `for` head expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":987,"byte_end":995,"line_start":44,"line_end":44,"column_start":18,"column_end":26,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){ + --> $DIR/unused_parens_remove_json_suggestion.rs:44:18 | LL | for _ in (0 .. 3){ | ^^^^^^^^ help: remove these parentheses -" -} -{ - "message": "unnecessary parentheses around `for` head expression", - "code": { - "code": "unused_parens", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 905, - "byte_end": 913, - "line_start": 50, - "line_end": 50, - "column_start": 14, - "column_end": 22, - "is_primary": true, - "text": [ - { - "text": " for _ in (0 .. 3) {", - "highlight_start": 14, - "highlight_end": 22 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "remove these parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 905, - "byte_end": 913, - "line_start": 50, - "line_end": 50, - "column_start": 14, - "column_end": 22, - "is_primary": true, - "text": [ - { - "text": " for _ in (0 .. 3) {", - "highlight_start": 14, - "highlight_end": 22 - } - ], - "label": null, - "suggested_replacement": "0 .. 3", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unnecessary parentheses around `for` head expression - --> $DIR/unused_parens_remove_json_suggestion.rs:50:14 +"} +{"message":"unnecessary parentheses around `for` head expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1088,"byte_end":1096,"line_start":49,"line_end":49,"column_start":14,"column_end":22,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) { + --> $DIR/unused_parens_remove_json_suggestion.rs:49:14 | LL | for _ in (0 .. 3) { | ^^^^^^^^ help: remove these parentheses -" -} -{ - "message": "unnecessary parentheses around `while` condition", - "code": { - "code": "unused_parens", - "explanation": null - }, - "level": "warning", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 930, - "byte_end": 945, - "line_start": 51, - "line_end": 51, - "column_start": 15, - "column_end": 30, - "is_primary": true, - "text": [ - { - "text": " while (true && false) {", - "highlight_start": 15, - "highlight_end": 30 - } - ], - "label": null, - "suggested_replacement": null, - "suggestion_applicability": null, - "expansion": null - } - ], - "children": [ - { - "message": "remove these parentheses", - "code": null, - "level": "help", - "spans": [ - { - "file_name": "$DIR/unused_parens_remove_json_suggestion.rs", - "byte_start": 930, - "byte_end": 945, - "line_start": 51, - "line_end": 51, - "column_start": 15, - "column_end": 30, - "is_primary": true, - "text": [ - { - "text": " while (true && false) {", - "highlight_start": 15, - "highlight_end": 30 - } - ], - "label": null, - "suggested_replacement": "true && false", - "suggestion_applicability": "MachineApplicable", - "expansion": null - } - ], - "children": [], - "rendered": null - } - ], - "rendered": "warning: unnecessary parentheses around `while` condition - --> $DIR/unused_parens_remove_json_suggestion.rs:51:15 +"} +{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1147,"byte_end":1162,"line_start":50,"line_end":50,"column_start":15,"column_end":30,"is_primary":true,"text":[{"text":" while (true && false) { + --> $DIR/unused_parens_remove_json_suggestion.rs:50:15 | LL | while (true && false) { | ^^^^^^^^^^^^^^^ help: remove these parentheses -" -} +"} +{"message":"aborting due to 9 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 9 previous errors + +"} diff --git a/src/test/ui/object-safety/object-safety-associated-consts.stderr b/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr index 7d5aa00356e..67ef7a62f10 100644 --- a/src/test/ui/object-safety/object-safety-associated-consts.stderr +++ b/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-associated-consts.rs:9:1 + --> $DIR/object-safety-associated-consts.rs:12:1 | LL | const X: usize; | - the trait cannot contain associated consts like `X` diff --git a/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr new file mode 100644 index 00000000000..20993a680ba --- /dev/null +++ b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr @@ -0,0 +1,15 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-associated-consts.rs:14:5 + | +LL | const X: usize; + | - the trait cannot contain associated consts like `X` +... +LL | t + | ^ the trait `Bar` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-associated-consts.rs b/src/test/ui/object-safety/object-safety-associated-consts.rs index 5900019ea91..e1a772e5ab2 100644 --- a/src/test/ui/object-safety/object-safety-associated-consts.rs +++ b/src/test/ui/object-safety/object-safety-associated-consts.rs @@ -1,14 +1,18 @@ // Check that we correctly prevent users from making trait objects // from traits with associated consts. +// +// revisions: curr object_safe_for_dispatch +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] trait Bar { const X: usize; } fn make_bar<T:Bar>(t: &T) -> &dyn Bar { - //~^ ERROR E0038 + //[curr]~^ ERROR E0038 t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn main() { diff --git a/src/test/ui/object-safety/object-safety-generics.stderr b/src/test/ui/object-safety/object-safety-generics.curr.stderr index b25e0052e41..8ae9236a5c3 100644 --- a/src/test/ui/object-safety/object-safety-generics.stderr +++ b/src/test/ui/object-safety/object-safety-generics.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:14:1 + --> $DIR/object-safety-generics.rs:18:1 | LL | fn bar<T>(&self, t: T); | --- method `bar` has generic type parameters @@ -8,7 +8,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:19:1 + --> $DIR/object-safety-generics.rs:24:1 | LL | fn bar<T>(&self, t: T); | --- method `bar` has generic type parameters diff --git a/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr new file mode 100644 index 00000000000..d3d8d368888 --- /dev/null +++ b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr @@ -0,0 +1,27 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-generics.rs:20:5 + | +LL | fn bar<T>(&self, t: T); + | --- method `bar` has generic type parameters +... +LL | t + | ^ the trait `Bar` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-generics.rs:26:5 + | +LL | fn bar<T>(&self, t: T); + | --- method `bar` has generic type parameters +... +LL | t as &dyn Bar + | ^ the trait `Bar` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-generics.rs b/src/test/ui/object-safety/object-safety-generics.rs index d63ea28c8f2..63dcd169925 100644 --- a/src/test/ui/object-safety/object-safety-generics.rs +++ b/src/test/ui/object-safety/object-safety-generics.rs @@ -1,6 +1,10 @@ // Check that we correctly prevent users from making trait objects // from traits with generic methods, unless `where Self : Sized` is // present. +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] + trait Bar { fn bar<T>(&self, t: T); @@ -12,13 +16,15 @@ trait Quux { } fn make_bar<T:Bar>(t: &T) -> &dyn Bar { - //~^ ERROR E0038 + //[curr]~^ ERROR E0038 t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar { - //~^ ERROR E0038 + //[curr]~^ ERROR E0038 t as &dyn Bar + //[object_safe_for_dispatch]~^ ERROR E0038 } fn make_quux<T:Quux>(t: &T) -> &dyn Quux { diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr index 971e79cb021..297cd876187 100644 --- a/src/test/ui/object-safety/object-safety-mentions-Self.stderr +++ b/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-mentions-Self.rs:17:1 + --> $DIR/object-safety-mentions-Self.rs:22:1 | LL | fn bar(&self, x: &Self); | --- method `bar` references the `Self` type in its parameters or return type @@ -8,10 +8,10 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object error[E0038]: the trait `Baz` cannot be made into an object - --> $DIR/object-safety-mentions-Self.rs:22:1 + --> $DIR/object-safety-mentions-Self.rs:28:1 | -LL | fn bar(&self) -> Self; - | --- method `bar` references the `Self` type in its parameters or return type +LL | fn baz(&self) -> Self; + | --- method `baz` references the `Self` type in its parameters or return type ... LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Baz` cannot be made into an object diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr new file mode 100644 index 00000000000..03b2b8da075 --- /dev/null +++ b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr @@ -0,0 +1,27 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-mentions-Self.rs:24:5 + | +LL | fn bar(&self, x: &Self); + | --- method `bar` references the `Self` type in its parameters or return type +... +LL | t + | ^ the trait `Bar` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error[E0038]: the trait `Baz` cannot be made into an object + --> $DIR/object-safety-mentions-Self.rs:30:5 + | +LL | fn baz(&self) -> Self; + | --- method `baz` references the `Self` type in its parameters or return type +... +LL | t + | ^ the trait `Baz` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Baz>` for `&T` + = note: required by cast to type `&dyn Baz` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.rs b/src/test/ui/object-safety/object-safety-mentions-Self.rs index f13ffe53626..412d16ff3c7 100644 --- a/src/test/ui/object-safety/object-safety-mentions-Self.rs +++ b/src/test/ui/object-safety/object-safety-mentions-Self.rs @@ -1,27 +1,34 @@ // Check that we correctly prevent users from making trait objects // form traits that make use of `Self` in an argument or return // position, unless `where Self : Sized` is present.. +// +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] + trait Bar { fn bar(&self, x: &Self); } trait Baz { - fn bar(&self) -> Self; + fn baz(&self) -> Self; } trait Quux { - fn get(&self, s: &Self) -> Self where Self : Sized; + fn quux(&self, s: &Self) -> Self where Self : Sized; } fn make_bar<T:Bar>(t: &T) -> &dyn Bar { - //~^ ERROR E0038 - loop { } + //[curr]~^ ERROR E0038 + t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn make_baz<T:Baz>(t: &T) -> &dyn Baz { - //~^ ERROR E0038 + //[curr]~^ ERROR E0038 t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn make_quux<T:Quux>(t: &T) -> &dyn Quux { @@ -32,5 +39,4 @@ fn make_quux_explicit<T:Quux>(t: &T) -> &dyn Quux { t as &dyn Quux } -fn main() { -} +fn main() {} diff --git a/src/test/ui/object-safety/object-safety-no-static.curr.stderr b/src/test/ui/object-safety/object-safety-no-static.curr.stderr new file mode 100644 index 00000000000..1641ce57771 --- /dev/null +++ b/src/test/ui/object-safety/object-safety-no-static.curr.stderr @@ -0,0 +1,12 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety-no-static.rs:12:1 + | +LL | fn foo() {} + | --- associated function `foo` has no `self` parameter +... +LL | fn diverges() -> Box<dyn Foo> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr new file mode 100644 index 00000000000..91a9285b63c --- /dev/null +++ b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr @@ -0,0 +1,15 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety-no-static.rs:22:27 + | +LL | fn foo() {} + | --- associated function `foo` has no `self` parameter +... +LL | let b: Box<dyn Foo> = Box::new(Bar); + | ^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<Bar>` + = note: required by cast to type `std::boxed::Box<dyn Foo>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-no-static.rs b/src/test/ui/object-safety/object-safety-no-static.rs index 55d31ce8087..03b62217483 100644 --- a/src/test/ui/object-safety/object-safety-no-static.rs +++ b/src/test/ui/object-safety/object-safety-no-static.rs @@ -1,14 +1,24 @@ // Check that we correctly prevent users from making trait objects // from traits with static methods. +// +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] trait Foo { - fn foo(); + fn foo() {} } -fn foo_implicit<T:Foo+'static>(b: Box<T>) -> Box<dyn Foo + 'static> { - //~^ ERROR E0038 +fn diverges() -> Box<dyn Foo> { + //[curr]~^ ERROR E0038 loop { } } +struct Bar; + +impl Foo for Bar {} + fn main() { + let b: Box<dyn Foo> = Box::new(Bar); + //[object_safe_for_dispatch]~^ ERROR E0038 } diff --git a/src/test/ui/object-safety/object-safety-sized-2.stderr b/src/test/ui/object-safety/object-safety-sized-2.curr.stderr index dcaf2ff0bc2..1e1d2bf64c4 100644 --- a/src/test/ui/object-safety/object-safety-sized-2.stderr +++ b/src/test/ui/object-safety/object-safety-sized-2.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-sized-2.rs:10:1 + --> $DIR/object-safety-sized-2.rs:14:1 | LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object diff --git a/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr new file mode 100644 index 00000000000..06ecfd019c8 --- /dev/null +++ b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr @@ -0,0 +1,13 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-sized-2.rs:16:5 + | +LL | t + | ^ the trait `Bar` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-sized-2.rs b/src/test/ui/object-safety/object-safety-sized-2.rs index 7235b22404e..1e79b8cd917 100644 --- a/src/test/ui/object-safety/object-safety-sized-2.rs +++ b/src/test/ui/object-safety/object-safety-sized-2.rs @@ -1,5 +1,9 @@ // Check that we correctly prevent users from making trait objects // from traits where `Self : Sized`. +// +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] trait Bar where Self : Sized @@ -8,8 +12,9 @@ trait Bar } fn make_bar<T:Bar>(t: &T) -> &dyn Bar { - //~^ ERROR E0038 - loop { } + //[curr]~^ ERROR E0038 + t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn main() { diff --git a/src/test/ui/object-safety/object-safety-sized.stderr b/src/test/ui/object-safety/object-safety-sized.curr.stderr index 98bc73e38d4..1a67e79e83d 100644 --- a/src/test/ui/object-safety/object-safety-sized.stderr +++ b/src/test/ui/object-safety/object-safety-sized.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-sized.rs:8:1 + --> $DIR/object-safety-sized.rs:12:1 | LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object diff --git a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr new file mode 100644 index 00000000000..3d88dfc40ed --- /dev/null +++ b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr @@ -0,0 +1,13 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-sized.rs:14:5 + | +LL | t + | ^ the trait `Bar` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-sized.rs b/src/test/ui/object-safety/object-safety-sized.rs index 1312bb34717..b424b892d3b 100644 --- a/src/test/ui/object-safety/object-safety-sized.rs +++ b/src/test/ui/object-safety/object-safety-sized.rs @@ -1,13 +1,18 @@ // Check that we correctly prevent users from making trait objects // from traits where `Self : Sized`. +// +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] trait Bar : Sized { fn bar<T>(&self, t: T); } fn make_bar<T:Bar>(t: &T) -> &dyn Bar { - //~^ ERROR E0038 + //[curr]~^ ERROR E0038 t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn main() { diff --git a/src/test/ui/repr/repr-packed-contains-align.stderr b/src/test/ui/repr/repr-packed-contains-align.stderr index 219516d8abc..df001d6b5f2 100644 --- a/src/test/ui/repr/repr-packed-contains-align.stderr +++ b/src/test/ui/repr/repr-packed-contains-align.stderr @@ -56,3 +56,4 @@ LL | | } error: aborting due to 8 previous errors +For more information about this error, try `rustc --explain E0588`. diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs new file mode 100644 index 00000000000..fa04f4b12d5 --- /dev/null +++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs @@ -0,0 +1,23 @@ +// Check that we if we get ahold of an object unsafe trait +// object with auto traits and lifetimes, we can downcast it +// +// check-pass + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized {} + +fn downcast_auto(t: &(dyn Trait + Send)) -> &dyn Trait { + t +} + +fn downcast_lifetime<'a, 'b, 't>(t: &'a (dyn Trait + 't)) + -> &'b (dyn Trait + 't) +where + 'a: 'b, + 't: 'a + 'b, +{ + t +} + +fn main() {} diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs new file mode 100644 index 00000000000..1dea4012265 --- /dev/null +++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs @@ -0,0 +1,69 @@ +// Check that we can manually implement an object +// unsafe trait for its trait object +// +// run-pass + +#![feature(object_safe_for_dispatch)] + +trait Bad { + fn stat() -> char { + 'A' + } + fn virt(&self) -> char { + 'B' + } + fn indirect(&self) -> char { + Self::stat() + } +} + +trait Good { + fn good_virt(&self) -> char { + panic!() + } + fn good_indirect(&self) -> char { + panic!() + } +} + +impl<'a> Bad for dyn Bad + 'a { + fn stat() -> char { + 'C' + } + fn virt(&self) -> char { + 'D' + } +} + +struct Struct {} + +impl Bad for Struct {} + +impl Good for Struct {} + +fn main() { + let s = Struct {}; + + let mut res = String::new(); + + // Directly call static + res.push(Struct::stat()); // "A" + res.push(<dyn Bad>::stat()); // "AC" + + let good: &dyn Good = &s; + + // These look similar enough... + let bad = unsafe { std::mem::transmute::<&dyn Good, &dyn Bad>(good) }; + + // Call virtual + res.push(s.virt()); // "ACB" + res.push(bad.virt()); // "ACBD" + + // Indirectly call static + res.push(s.indirect()); // "ACBDA" + res.push(bad.indirect()); // "ACBDAC" + + if &res != "ACBDAC" { + panic!(); + } +} diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs new file mode 100644 index 00000000000..df97d2c1327 --- /dev/null +++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs @@ -0,0 +1,37 @@ +// Check that we can statically dispatch methods for object +// unsafe trait objects, directly and indirectly +// +// check-pass + +#![feature(object_safe_for_dispatch)] + +trait Statics { + fn plain() {} + fn generic<T>() {} +} + +trait Trait: Sized {} + +impl<'a> Statics for dyn Trait + 'a {} + +fn static_poly<T: Statics + ?Sized>() { + T::plain(); + T::generic::<usize>(); +} + +fn inferred_poly<T: Statics + ?Sized>(t: &T) { + static_poly::<T>(); + T::plain(); + T::generic::<usize>(); +} + +fn call(t: &dyn Trait) { + static_poly::<dyn Trait>(); + inferred_poly(t); +} + +fn main() { + static_poly::<dyn Trait>(); + <dyn Trait>::plain(); + <dyn Trait>::generic::<usize>() +} diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs index a16fb7670a6..ea8a3c177e9 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs @@ -1,13 +1,12 @@ #![feature(rustc_attrs)] #![feature(untagged_unions)] -#![allow(unions_with_drop_fields)] #[rustc_outlives] -union Foo<'b, U> { //~ ERROR rustc_outlives +union Foo<'b, U: Copy> { //~ ERROR rustc_outlives bar: Bar<'b, U> } -union Bar<'a, T> where T: 'a { +union Bar<'a, T: Copy> where T: 'a { x: &'a (), y: T, } diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr index adf62651cac..8aa246e8bfe 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr @@ -1,7 +1,7 @@ error: rustc_outlives - --> $DIR/explicit-union.rs:6:1 + --> $DIR/explicit-union.rs:5:1 | -LL | / union Foo<'b, U> { +LL | / union Foo<'b, U: Copy> { LL | | bar: Bar<'b, U> LL | | } | |_^ diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.rs b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs index 0ff667fbeba..0da3cc2ba1b 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-union.rs +++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs @@ -1,14 +1,13 @@ #![feature(rustc_attrs)] #![feature(untagged_unions)] -#![allow(unions_with_drop_fields)] #[rustc_outlives] -union Foo<'a, T> { //~ ERROR rustc_outlives +union Foo<'a, T: Copy> { //~ ERROR rustc_outlives field1: Bar<'a, T> } // Type U needs to outlive lifetime 'b -union Bar<'b, U> { +union Bar<'b, U: Copy> { field2: &'b U } diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr index fc4b1a22329..a42285a56d0 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr @@ -1,7 +1,7 @@ error: rustc_outlives - --> $DIR/nested-union.rs:6:1 + --> $DIR/nested-union.rs:5:1 | -LL | / union Foo<'a, T> { +LL | / union Foo<'a, T: Copy> { LL | | field1: Bar<'a, T> LL | | } | |_^ diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr new file mode 100644 index 00000000000..cdffc1d86ed --- /dev/null +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr @@ -0,0 +1,24 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/arbitrary-self-types-not-object-safe.rs:34:32 + | +LL | fn foo(self: &Rc<Self>) -> usize; + | --- method `foo`'s `self` parameter cannot be dispatched on +... +LL | let x = Rc::new(5usize) as Rc<dyn Foo>; + | ^^^^^^^^^^^ the trait `Foo` cannot be made into an object + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/arbitrary-self-types-not-object-safe.rs:34:13 + | +LL | fn foo(self: &Rc<Self>) -> usize; + | --- method `foo`'s `self` parameter cannot be dispatched on +... +LL | let x = Rc::new(5usize) as Rc<dyn Foo>; + | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>` + = note: required by cast to type `std::rc::Rc<dyn Foo>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr new file mode 100644 index 00000000000..725632a1212 --- /dev/null +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr @@ -0,0 +1,15 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/arbitrary-self-types-not-object-safe.rs:34:13 + | +LL | fn foo(self: &Rc<Self>) -> usize; + | --- method `foo`'s `self` parameter cannot be dispatched on +... +LL | let x = Rc::new(5usize) as Rc<dyn Foo>; + | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>` + = note: required by cast to type `std::rc::Rc<dyn Foo>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.rs b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs index 7443d888c9e..2eeabad28db 100644 --- a/src/test/ui/self/arbitrary-self-types-not-object-safe.rs +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs @@ -1,3 +1,6 @@ +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] #![feature(arbitrary_self_types)] use std::rc::Rc; @@ -29,8 +32,9 @@ impl Bar for usize { fn make_foo() { let x = Rc::new(5usize) as Rc<dyn Foo>; - //~^ ERROR E0038 - //~| ERROR E0038 + //[curr]~^ ERROR E0038 + //[curr]~| ERROR E0038 + //[object_safe_for_dispatch]~^^^ ERROR E0038 } fn make_bar() { diff --git a/src/test/ui/self/self-in-typedefs.rs b/src/test/ui/self/self-in-typedefs.rs index 73f23a9cc17..3b1eb9e1dfa 100644 --- a/src/test/ui/self/self-in-typedefs.rs +++ b/src/test/ui/self/self-in-typedefs.rs @@ -3,7 +3,8 @@ #![feature(untagged_unions)] #![allow(dead_code)] -#![allow(unions_with_drop_fields)] + +use std::mem::ManuallyDrop; enum A<'a, T: 'a> where @@ -26,6 +27,14 @@ where Self: Send, T: PartialEq<Self> { foo: &'a Self, + bar: ManuallyDrop<T>, +} + +union D<'a, T: 'a> +where + Self: Send, T: PartialEq<Self> + Copy +{ + foo: &'a Self, bar: T, } diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr index a3d966bb0b0..610937739c1 100644 --- a/src/test/ui/symbol-names/impl1.legacy.stderr +++ b/src/test/ui/symbol-names/impl1.legacy.stderr @@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz) LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h059bf53000885489E) +error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h636bc933fc62ee2fE) --> $DIR/impl1.rs:61:13 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h059bf53000885489) +error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h636bc933fc62ee2f) --> $DIR/impl1.rs:61:13 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/synthetic-param.rs b/src/test/ui/synthetic-param.rs index e53e3ba06e0..e14697f5c3e 100644 --- a/src/test/ui/synthetic-param.rs +++ b/src/test/ui/synthetic-param.rs @@ -17,12 +17,12 @@ impl<S> Bar<S> { } fn main() { - func::<u8>(42); //~ ERROR cannot provide explicit type parameters + func::<u8>(42); //~ ERROR cannot provide explicit generic arguments func(42); // Ok - Foo::func::<u8>(42); //~ ERROR cannot provide explicit type parameters + Foo::func::<u8>(42); //~ ERROR cannot provide explicit generic arguments Foo::func(42); // Ok - Bar::<i8>::func::<u8>(42); //~ ERROR cannot provide explicit type parameters + Bar::<i8>::func::<u8>(42); //~ ERROR cannot provide explicit generic arguments Bar::<i8>::func(42); // Ok } diff --git a/src/test/ui/synthetic-param.stderr b/src/test/ui/synthetic-param.stderr index bfafd8cbd72..f8d14f26f32 100644 --- a/src/test/ui/synthetic-param.stderr +++ b/src/test/ui/synthetic-param.stderr @@ -1,16 +1,16 @@ -error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. +error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position --> $DIR/synthetic-param.rs:20:5 | LL | func::<u8>(42); | ^^^^^^^^^^ -error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. +error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position --> $DIR/synthetic-param.rs:23:5 | LL | Foo::func::<u8>(42); | ^^^^^^^^^^^^^^^ -error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. +error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position --> $DIR/synthetic-param.rs:26:5 | LL | Bar::<i8>::func::<u8>(42); diff --git a/src/test/ui/traits/trait-object-safety.stderr b/src/test/ui/traits/trait-object-safety.stderr index 3ac1e96b30c..028e9eedd64 100644 --- a/src/test/ui/traits/trait-object-safety.stderr +++ b/src/test/ui/traits/trait-object-safety.stderr @@ -8,6 +8,7 @@ LL | let _: &dyn Tr = &St; | ^^^ the trait `Tr` cannot be made into an object | = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Tr>` for `&St` + = note: required by cast to type `&dyn Tr` error[E0038]: the trait `Tr` cannot be made into an object --> $DIR/trait-object-safety.rs:15:12 diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr index 83c2c065274..9b750d382ec 100644 --- a/src/test/ui/traits/trait-test-2.stderr +++ b/src/test/ui/traits/trait-test-2.stderr @@ -33,6 +33,7 @@ LL | (box 10 as Box<dyn bar>).dup(); | ^^^^^^ the trait `bar` cannot be made into an object | = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn bar>>` for `std::boxed::Box<{integer}>` + = note: required by cast to type `std::boxed::Box<dyn bar>` error: aborting due to 4 previous errors diff --git a/src/test/ui/union/issue-41073.rs b/src/test/ui/union/issue-41073.rs new file mode 100644 index 00000000000..91e9a0d0b65 --- /dev/null +++ b/src/test/ui/union/issue-41073.rs @@ -0,0 +1,24 @@ +#![feature(untagged_unions)] + +union Test { + a: A, //~ ERROR unions may not contain fields that need dropping + b: B +} + +#[derive(Debug)] +struct A(i32); +impl Drop for A { + fn drop(&mut self) { println!("A"); } +} + +#[derive(Debug)] +struct B(f32); +impl Drop for B { + fn drop(&mut self) { println!("B"); } +} + +fn main() { + let mut test = Test { a: A(3) }; + println!("{:?}", unsafe { test.b }); + unsafe { test.b = B(0.5); } +} diff --git a/src/test/ui/union/issue-41073.stderr b/src/test/ui/union/issue-41073.stderr new file mode 100644 index 00000000000..2e9598b2271 --- /dev/null +++ b/src/test/ui/union/issue-41073.stderr @@ -0,0 +1,15 @@ +error[E0740]: unions may not contain fields that need dropping + --> $DIR/issue-41073.rs:4:5 + | +LL | a: A, + | ^^^^ + | +note: `std::mem::ManuallyDrop` can be used to wrap the type + --> $DIR/issue-41073.rs:4:5 + | +LL | a: A, + | ^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0740`. diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.rs b/src/test/ui/union/union-borrow-move-parent-sibling.rs index 1b6052f10ba..edf08e6ca67 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.rs +++ b/src/test/ui/union/union-borrow-move-parent-sibling.rs @@ -1,51 +1,90 @@ #![feature(untagged_unions)] #![allow(unused)] -#[allow(unions_with_drop_fields)] +use std::ops::{Deref, DerefMut}; + +#[derive(Default)] +struct MockBox<T> { + value: [T; 1], +} + +impl<T> MockBox<T> { + fn new(value: T) -> Self { MockBox { value: [value] } } +} + +impl<T> Deref for MockBox<T> { + type Target = T; + fn deref(&self) -> &T { &self.value[0] } +} + +impl<T> DerefMut for MockBox<T> { + fn deref_mut(&mut self) -> &mut T { &mut self.value[0] } +} + +#[derive(Default)] +struct MockVec<T> { + value: [T; 0], +} + +impl<T> MockVec<T> { + fn new() -> Self { MockVec { value: [] } } +} + +impl<T> Deref for MockVec<T> { + type Target = [T]; + fn deref(&self) -> &[T] { &self.value } +} + +impl<T> DerefMut for MockVec<T> { + fn deref_mut(&mut self) -> &mut [T] { &mut self.value } +} + + union U { - x: ((Vec<u8>, Vec<u8>), Vec<u8>), - y: Box<Vec<u8>>, + x: ((MockVec<u8>, MockVec<u8>), MockVec<u8>), + y: MockBox<MockVec<u8>>, } fn use_borrow<T>(_: &T) {} unsafe fn parent_sibling_borrow() { - let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + let mut u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; let a = &mut u.x.0; let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`) use_borrow(a); } unsafe fn parent_sibling_move() { - let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; let a = u.x.0; let b = u.y; //~ ERROR use of moved value: `u` } unsafe fn grandparent_sibling_borrow() { - let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + let mut u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; let a = &mut (u.x.0).0; let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`) use_borrow(a); } unsafe fn grandparent_sibling_move() { - let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; + let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; let a = (u.x.0).0; let b = u.y; //~ ERROR use of moved value: `u` } unsafe fn deref_sibling_borrow() { - let mut u = U { y: Box::default() }; + let mut u = U { y: MockBox::default() }; let a = &mut *u.y; let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`) use_borrow(a); } unsafe fn deref_sibling_move() { - let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; - let a = *u.y; - let b = u.x; //~ ERROR use of moved value: `u` + let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; + // No way to test deref-move without Box in union + // let a = *u.y; + // let b = u.x; ERROR use of moved value: `u` } diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.stderr index 2f4c921ea08..8ba155bafb0 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.stderr +++ b/src/test/ui/union/union-borrow-move-parent-sibling.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`) - --> $DIR/union-borrow-move-parent-sibling.rs:15:13 + --> $DIR/union-borrow-move-parent-sibling.rs:53:13 | LL | let a = &mut u.x.0; | ---------- mutable borrow occurs here (via `u.x.0`) @@ -11,9 +11,9 @@ LL | use_borrow(a); = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0` error[E0382]: use of moved value: `u` - --> $DIR/union-borrow-move-parent-sibling.rs:22:13 + --> $DIR/union-borrow-move-parent-sibling.rs:60:13 | -LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; +LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = u.x.0; | ----- value moved here @@ -21,7 +21,7 @@ LL | let b = u.y; | ^^^ value used here after move error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`) - --> $DIR/union-borrow-move-parent-sibling.rs:28:13 + --> $DIR/union-borrow-move-parent-sibling.rs:66:13 | LL | let a = &mut (u.x.0).0; | -------------- mutable borrow occurs here (via `u.x.0.0`) @@ -33,38 +33,28 @@ LL | use_borrow(a); = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0` error[E0382]: use of moved value: `u` - --> $DIR/union-borrow-move-parent-sibling.rs:35:13 + --> $DIR/union-borrow-move-parent-sibling.rs:73:13 | -LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; +LL | let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) }; | - move occurs because `u` has type `U`, which does not implement the `Copy` trait LL | let a = (u.x.0).0; | --------- value moved here LL | let b = u.y; | ^^^ value used here after move -error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `*u.y`) - --> $DIR/union-borrow-move-parent-sibling.rs:41:13 +error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`) + --> $DIR/union-borrow-move-parent-sibling.rs:79:13 | LL | let a = &mut *u.y; - | --------- mutable borrow occurs here (via `*u.y`) + | --- mutable borrow occurs here (via `u.y`) LL | let b = &u.x; - | ^^^^ immutable borrow of `u.x` -- which overlaps with `*u.y` -- occurs here + | ^^^^ immutable borrow of `u.x` -- which overlaps with `u.y` -- occurs here LL | use_borrow(a); | - mutable borrow later used here | - = note: `u.x` is a field of the union `U`, so it overlaps the field `*u.y` + = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y` -error[E0382]: use of moved value: `u` - --> $DIR/union-borrow-move-parent-sibling.rs:48:13 - | -LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) }; - | - move occurs because `u` has type `U`, which does not implement the `Copy` trait -LL | let a = *u.y; - | ---- value moved here -LL | let b = u.x; - | ^^^ value used here after move - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0382, E0502. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/union/union-custom-drop.rs b/src/test/ui/union/union-custom-drop.rs new file mode 100644 index 00000000000..8f816cc1b73 --- /dev/null +++ b/src/test/ui/union/union-custom-drop.rs @@ -0,0 +1,19 @@ +// test for a union with a field that's a union with a manual impl Drop +// Ensures we do not treat all unions as not having any drop glue. + +#![feature(untagged_unions)] + +union Foo { + bar: Bar, //~ ERROR unions may not contain fields that need dropping +} + +union Bar { + a: i32, + b: u32, +} + +impl Drop for Bar { + fn drop(&mut self) {} +} + +fn main() {} diff --git a/src/test/ui/union/union-custom-drop.stderr b/src/test/ui/union/union-custom-drop.stderr new file mode 100644 index 00000000000..ee2333f905f --- /dev/null +++ b/src/test/ui/union/union-custom-drop.stderr @@ -0,0 +1,15 @@ +error[E0740]: unions may not contain fields that need dropping + --> $DIR/union-custom-drop.rs:7:5 + | +LL | bar: Bar, + | ^^^^^^^^ + | +note: `std::mem::ManuallyDrop` can be used to wrap the type + --> $DIR/union-custom-drop.rs:7:5 + | +LL | bar: Bar, + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0740`. diff --git a/src/test/ui/union/union-derive-clone.rs b/src/test/ui/union/union-derive-clone.rs index 64c3caef449..60e280f53f5 100644 --- a/src/test/ui/union/union-derive-clone.rs +++ b/src/test/ui/union/union-derive-clone.rs @@ -1,5 +1,7 @@ #![feature(untagged_unions)] +use std::mem::ManuallyDrop; + #[derive(Clone)] //~ ERROR the trait bound `U1: std::marker::Copy` is not satisfied union U1 { a: u8, @@ -18,14 +20,19 @@ union U3 { } #[derive(Clone, Copy)] -union U4<T> { +union U4<T: Copy> { a: T, // OK } +#[derive(Clone, Copy)] +union U5<T> { + a: ManuallyDrop<T>, // OK +} + #[derive(Clone)] struct CloneNoCopy; fn main() { - let u = U4 { a: CloneNoCopy }; - let w = u.clone(); //~ ERROR no method named `clone` found for type `U4<CloneNoCopy>` + let u = U5 { a: ManuallyDrop::new(CloneNoCopy) }; + let w = u.clone(); //~ ERROR no method named `clone` found for type `U5<CloneNoCopy>` } diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index 4f4c779b12b..6893f9176f2 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -1,22 +1,22 @@ error[E0277]: the trait bound `U1: std::marker::Copy` is not satisfied - --> $DIR/union-derive-clone.rs:3:10 + --> $DIR/union-derive-clone.rs:5:10 | LL | #[derive(Clone)] | ^^^^^ the trait `std::marker::Copy` is not implemented for `U1` | = note: required by `std::clone::AssertParamIsCopy` -error[E0599]: no method named `clone` found for type `U4<CloneNoCopy>` in the current scope - --> $DIR/union-derive-clone.rs:30:15 +error[E0599]: no method named `clone` found for type `U5<CloneNoCopy>` in the current scope + --> $DIR/union-derive-clone.rs:37:15 | -LL | union U4<T> { +LL | union U5<T> { | ----------- method `clone` not found for this ... LL | let w = u.clone(); - | ^^^^^ method not found in `U4<CloneNoCopy>` + | ^^^^^ method not found in `U5<CloneNoCopy>` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `U4<CloneNoCopy> : std::clone::Clone` + `U5<CloneNoCopy> : std::clone::Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone` diff --git a/src/test/ui/union/union-derive-rpass.rs b/src/test/ui/union/union-derive-rpass.rs index d4b82cdb250..b2f7ae679fd 100644 --- a/src/test/ui/union/union-derive-rpass.rs +++ b/src/test/ui/union/union-derive-rpass.rs @@ -1,7 +1,6 @@ // run-pass #![allow(dead_code)] #![allow(unused_variables)] -#![allow(unions_with_drop_fields)] // Some traits can be derived for unions. @@ -24,11 +23,11 @@ impl PartialEq for U { fn eq(&self, rhs: &Self) -> bool { true } } Copy, Eq )] -union W<T> { +union W<T: Copy> { a: T, } -impl<T> PartialEq for W<T> { fn eq(&self, rhs: &Self) -> bool { true } } +impl<T: Copy> PartialEq for W<T> { fn eq(&self, rhs: &Self) -> bool { true } } fn main() { let u = U { b: 0 }; diff --git a/src/test/ui/union/union-drop-assign.rs b/src/test/ui/union/union-drop-assign.rs index c4349c45464..f1511b0a601 100644 --- a/src/test/ui/union/union-drop-assign.rs +++ b/src/test/ui/union/union-drop-assign.rs @@ -1,15 +1,16 @@ // run-pass #![allow(unused_assignments)] -#![allow(unions_with_drop_fields)] // Drop works for union itself. #![feature(untagged_unions)] +use std::mem::ManuallyDrop; + struct S; union U { - a: S + a: ManuallyDrop<S> } impl Drop for S { @@ -28,11 +29,11 @@ static mut CHECK: u8 = 0; fn main() { unsafe { - let mut u = U { a: S }; + let mut u = U { a: ManuallyDrop::new(S) }; assert_eq!(CHECK, 0); - u = U { a: S }; + u = U { a: ManuallyDrop::new(S) }; assert_eq!(CHECK, 1); // union itself is assigned, union is dropped, field is not dropped - u.a = S; + *u.a = S; assert_eq!(CHECK, 11); // union field is assigned, field is dropped } } diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs index 2060950dda9..daa03ce6b6f 100644 --- a/src/test/ui/union/union-drop.rs +++ b/src/test/ui/union/union-drop.rs @@ -1,7 +1,6 @@ // run-pass #![allow(dead_code)] #![allow(unused_variables)] -#![allow(unions_with_drop_fields)] // Drop works for union itself. @@ -21,12 +20,6 @@ union Y { a: S, } -impl Drop for S { - fn drop(&mut self) { - unsafe { CHECK += 10; } - } -} - impl Drop for U { fn drop(&mut self) { unsafe { CHECK += 1; } @@ -51,10 +44,10 @@ fn main() { { let w = W { a: S }; } - assert_eq!(CHECK, 2); // 2, not 11, dtor of S is not called + assert_eq!(CHECK, 2); // 2, dtor of W is called { let y = Y { a: S }; } - assert_eq!(CHECK, 2); // 2, not 12, dtor of S is not called + assert_eq!(CHECK, 2); // 2, dtor of Y is called } } diff --git a/src/test/ui/union/union-generic-rpass.rs b/src/test/ui/union/union-generic-rpass.rs index 6f2caf8dc5b..eb169c516d2 100644 --- a/src/test/ui/union/union-generic-rpass.rs +++ b/src/test/ui/union/union-generic-rpass.rs @@ -1,37 +1,33 @@ // run-pass #![allow(dead_code)] -#![allow(unions_with_drop_fields)] #![feature(untagged_unions)] +use std::mem::ManuallyDrop; + union MaybeItem<T: Iterator> { - elem: T::Item, + elem: ManuallyDrop<T::Item>, none: (), } -union U<A, B> { +union U<A, B> where A: Copy, B: Copy { a: A, b: B, } -unsafe fn union_transmute<A, B>(a: A) -> B { +unsafe fn union_transmute<A, B>(a: A) -> B where A: Copy, B: Copy { U { a: a }.b } fn main() { unsafe { - let u = U::<String, Vec<u8>> { a: String::from("abcd") }; - - assert_eq!(u.b.len(), 4); - assert_eq!(u.b[0], b'a'); - let b = union_transmute::<(u8, u8), u16>((1, 1)); assert_eq!(b, (1 << 8) + 1); let v: Vec<u8> = vec![1, 2, 3]; let mut i = v.iter(); i.next(); - let mi = MaybeItem::<std::slice::Iter<_>> { elem: i.next().unwrap() }; - assert_eq!(*mi.elem, 2); + let mi = MaybeItem::<std::slice::Iter<_>> { elem: ManuallyDrop::new(i.next().unwrap()) }; + assert_eq!(**mi.elem, 2); } } diff --git a/src/test/ui/union/union-manuallydrop-rpass.rs b/src/test/ui/union/union-manuallydrop-rpass.rs new file mode 100644 index 00000000000..a43a5050865 --- /dev/null +++ b/src/test/ui/union/union-manuallydrop-rpass.rs @@ -0,0 +1,42 @@ +#![feature(untagged_unions)] +#![allow(dead_code)] +// run-pass + +use std::mem::needs_drop; +use std::mem::ManuallyDrop; + +struct NeedDrop; + +impl Drop for NeedDrop { + fn drop(&mut self) {} +} + +union UnionOk1<T> { + empty: (), + value: ManuallyDrop<T>, +} + +union UnionOk2 { + value: ManuallyDrop<NeedDrop>, +} + +#[allow(dead_code)] +union UnionOk3<T: Copy> { + empty: (), + value: T, +} + +trait Foo { } + +trait ImpliesCopy : Copy { } + +#[allow(dead_code)] +union UnionOk4<T: ImpliesCopy> { + value: T, +} + +fn main() { + // NeedDrop should not make needs_drop true + assert!(!needs_drop::<UnionOk1<NeedDrop>>()); + assert!(!needs_drop::<UnionOk3<&dyn Foo>>()); +} diff --git a/src/test/ui/union/union-nodrop.rs b/src/test/ui/union/union-nodrop.rs index 4cd64ddb5d6..59282bec59b 100644 --- a/src/test/ui/union/union-nodrop.rs +++ b/src/test/ui/union/union-nodrop.rs @@ -1,12 +1,11 @@ // run-pass -#![feature(core_intrinsics)] #![feature(untagged_unions)] -#![allow(unions_with_drop_fields)] #![allow(dead_code)] -use std::intrinsics::needs_drop; +use std::mem::needs_drop; +use std::mem::ManuallyDrop; struct NeedDrop; @@ -16,10 +15,14 @@ impl Drop for NeedDrop { // Constant expressios allow `NoDrop` to go out of scope, // unlike a value of the interior type implementing `Drop`. -static X: () = (NoDrop { inner: NeedDrop }, ()).1; +static X: () = (NoDrop { inner: ManuallyDrop::new(NeedDrop) }, ()).1; + +const Y: () = (NoDrop { inner: ManuallyDrop::new(NeedDrop) }, ()).1; + +const fn _f() { (NoDrop { inner: ManuallyDrop::new(NeedDrop) }, ()).1 } // A union that scrubs the drop glue from its inner type -union NoDrop<T> {inner: T} +union NoDrop<T> { inner: ManuallyDrop<T> } // Copy currently can't be implemented on drop-containing unions, // this may change later @@ -40,7 +43,7 @@ struct Baz { y: Box<u8>, } -union ActuallyDrop<T> {inner: T} +union ActuallyDrop<T> { inner: ManuallyDrop<T> } impl<T> Drop for ActuallyDrop<T> { fn drop(&mut self) {} diff --git a/src/test/ui/union/union-overwrite.rs b/src/test/ui/union/union-overwrite.rs index 64c60604ba9..8234beb74a8 100644 --- a/src/test/ui/union/union-overwrite.rs +++ b/src/test/ui/union/union-overwrite.rs @@ -1,21 +1,27 @@ // run-pass -#![allow(unions_with_drop_fields)] - #![feature(untagged_unions)] #[repr(C)] +#[derive(Copy, Clone)] struct Pair<T, U>(T, U); #[repr(C)] +#[derive(Copy, Clone)] struct Triple<T>(T, T, T); #[repr(C)] -union U<A, B> { +union U<A, B> +where + A: Copy, B: Copy +{ a: Pair<A, A>, b: B, } #[repr(C)] -union W<A, B> { +union W<A, B> +where + A: Copy, B: Copy +{ a: A, b: B, } diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 6cfde35fe4c..8535cbd019c 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -1,15 +1,16 @@ #![feature(untagged_unions)] +use std::mem::ManuallyDrop; union U1 { a: u8 } union U2 { - a: String + a: ManuallyDrop<String> } union U3<T> { - a: T + a: ManuallyDrop<T> } union U4<T: Copy> { @@ -17,13 +18,16 @@ union U4<T: Copy> { } fn generic_noncopy<T: Default>() { - let mut u3 = U3 { a: T::default() }; - u3.a = T::default(); //~ ERROR assignment to non-`Copy` union field is unsafe + let mut u3 = U3 { a: ManuallyDrop::new(T::default()) }; + u3.a = ManuallyDrop::new(T::default()); //~ ERROR assignment to non-`Copy` union field is unsafe + *u3.a = T::default(); //~ ERROR access to union field is unsafe } fn generic_copy<T: Copy + Default>() { - let mut u3 = U3 { a: T::default() }; - u3.a = T::default(); // OK + let mut u3 = U3 { a: ManuallyDrop::new(T::default()) }; + u3.a = ManuallyDrop::new(T::default()); // OK + *u3.a = T::default(); //~ ERROR access to union field is unsafe + let mut u4 = U4 { a: T::default() }; u4.a = T::default(); // OK } @@ -32,14 +36,20 @@ fn main() { let mut u1 = U1 { a: 10 }; // OK let a = u1.a; //~ ERROR access to union field is unsafe u1.a = 11; // OK + let U1 { a } = u1; //~ ERROR access to union field is unsafe if let U1 { a: 12 } = u1 {} //~ ERROR access to union field is unsafe // let U1 { .. } = u1; // OK - let mut u2 = U2 { a: String::from("old") }; // OK - u2.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field is unsafe - let mut u3 = U3 { a: 0 }; // OK - u3.a = 1; // OK - let mut u3 = U3 { a: String::from("old") }; // OK - u3.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field is unsafe + let mut u2 = U2 { a: ManuallyDrop::new(String::from("old")) }; // OK + u2.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union + *u2.a = String::from("new"); //~ ERROR access to union field is unsafe + + let mut u3 = U3 { a: ManuallyDrop::new(0) }; // OK + u3.a = ManuallyDrop::new(1); // OK + *u3.a = 1; //~ ERROR access to union field is unsafe + + let mut u3 = U3 { a: ManuallyDrop::new(String::from("old")) }; // OK + u3.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union + *u3.a = String::from("new"); //~ ERROR access to union field is unsafe } diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr index ab62508fcf6..e020dab63f8 100644 --- a/src/test/ui/union/union-unsafe.stderr +++ b/src/test/ui/union/union-unsafe.stderr @@ -1,13 +1,29 @@ error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:21:5 + --> $DIR/union-unsafe.rs:22:5 | -LL | u3.a = T::default(); - | ^^^^ assignment to non-`Copy` union field +LL | u3.a = ManuallyDrop::new(T::default()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:33:13 + --> $DIR/union-unsafe.rs:23:6 + | +LL | *u3.a = T::default(); + | ^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:29:6 + | +LL | *u3.a = T::default(); + | ^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:37:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -15,7 +31,7 @@ LL | let a = u1.a; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:35:14 + --> $DIR/union-unsafe.rs:40:14 | LL | let U1 { a } = u1; | ^ access to union field @@ -23,7 +39,7 @@ LL | let U1 { a } = u1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:36:20 + --> $DIR/union-unsafe.rs:41:20 | LL | if let U1 { a: 12 } = u1 {} | ^^ access to union field @@ -31,21 +47,45 @@ LL | if let U1 { a: 12 } = u1 {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:40:5 + --> $DIR/union-unsafe.rs:45:5 | -LL | u2.a = String::from("new"); - | ^^^^ assignment to non-`Copy` union field +LL | u2.a = ManuallyDrop::new(String::from("new")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:46:6 + | +LL | *u2.a = String::from("new"); + | ^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:50:6 + | +LL | *u3.a = 1; + | ^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:44:5 + --> $DIR/union-unsafe.rs:53:5 | -LL | u3.a = String::from("new"); - | ^^^^ assignment to non-`Copy` union field +LL | u3.a = ManuallyDrop::new(String::from("new")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field | = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized -error: aborting due to 6 previous errors +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-unsafe.rs:54:6 + | +LL | *u3.a = String::from("new"); + | ^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/union/union-with-drop-fields-lint-rpass.rs b/src/test/ui/union/union-with-drop-fields-lint-rpass.rs deleted file mode 100644 index 4dbeb7c1e7e..00000000000 --- a/src/test/ui/union/union-with-drop-fields-lint-rpass.rs +++ /dev/null @@ -1,32 +0,0 @@ -// run-pass - -#![feature(untagged_unions)] -#![allow(dead_code)] -#![allow(unions_with_drop_fields)] - -union U { - a: u8, // OK -} - -union W { - a: String, // OK - b: String, // OK -} - -struct S(String); - -// `S` doesn't implement `Drop` trait, but still has non-trivial destructor -union Y { - a: S, // OK -} - -// We don't know if `T` is trivially-destructable or not until trans -union J<T> { - a: T, // OK -} - -union H<T: Copy> { - a: T, // OK -} - -fn main() {} diff --git a/src/test/ui/union/union-with-drop-fields-lint.stderr b/src/test/ui/union/union-with-drop-fields-lint.stderr deleted file mode 100644 index 2f90f240d2e..00000000000 --- a/src/test/ui/union/union-with-drop-fields-lint.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union - --> $DIR/union-with-drop-fields-lint.rs:10:5 - | -LL | a: String, - | ^^^^^^^^^ - | -note: lint level defined here - --> $DIR/union-with-drop-fields-lint.rs:3:9 - | -LL | #![deny(unions_with_drop_fields)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union - --> $DIR/union-with-drop-fields-lint.rs:18:5 - | -LL | a: S, - | ^^^^ - -error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union - --> $DIR/union-with-drop-fields-lint.rs:23:5 - | -LL | a: T, - | ^^^^ - -error: aborting due to 3 previous errors - diff --git a/src/test/ui/union/union-with-drop-fields-lint.rs b/src/test/ui/union/union-with-drop-fields.rs index 8e502aa55f9..e3c63a6d5b5 100644 --- a/src/test/ui/union/union-with-drop-fields-lint.rs +++ b/src/test/ui/union/union-with-drop-fields.rs @@ -1,13 +1,12 @@ #![feature(untagged_unions)] #![allow(dead_code)] -#![deny(unions_with_drop_fields)] union U { a: u8, // OK } union W { - a: String, //~ ERROR union contains a field with possibly non-trivial drop code + a: String, //~ ERROR unions may not contain fields that need dropping b: String, // OK, only one field is reported } @@ -15,12 +14,12 @@ struct S(String); // `S` doesn't implement `Drop` trait, but still has non-trivial destructor union Y { - a: S, //~ ERROR union contains a field with possibly non-trivial drop code + a: S, //~ ERROR unions may not contain fields that need dropping } // We don't know if `T` is trivially-destructable or not until trans union J<T> { - a: T, //~ ERROR union contains a field with possibly non-trivial drop code + a: T, //~ ERROR unions may not contain fields that need dropping } union H<T: Copy> { diff --git a/src/test/ui/union/union-with-drop-fields.stderr b/src/test/ui/union/union-with-drop-fields.stderr new file mode 100644 index 00000000000..0e77279be61 --- /dev/null +++ b/src/test/ui/union/union-with-drop-fields.stderr @@ -0,0 +1,39 @@ +error[E0740]: unions may not contain fields that need dropping + --> $DIR/union-with-drop-fields.rs:9:5 + | +LL | a: String, + | ^^^^^^^^^ + | +note: `std::mem::ManuallyDrop` can be used to wrap the type + --> $DIR/union-with-drop-fields.rs:9:5 + | +LL | a: String, + | ^^^^^^^^^ + +error[E0740]: unions may not contain fields that need dropping + --> $DIR/union-with-drop-fields.rs:17:5 + | +LL | a: S, + | ^^^^ + | +note: `std::mem::ManuallyDrop` can be used to wrap the type + --> $DIR/union-with-drop-fields.rs:17:5 + | +LL | a: S, + | ^^^^ + +error[E0740]: unions may not contain fields that need dropping + --> $DIR/union-with-drop-fields.rs:22:5 + | +LL | a: T, + | ^^^^ + | +note: `std::mem::ManuallyDrop` can be used to wrap the type + --> $DIR/union-with-drop-fields.rs:22:5 + | +LL | a: T, + | ^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0740`. diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs new file mode 100644 index 00000000000..ffdb49a3be5 --- /dev/null +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs @@ -0,0 +1,18 @@ +// Check that we do not allow casts or coercions +// to object unsafe trait objects inside a Box + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized {} + +struct S; + +impl Trait for S {} + +fn takes_box(t: Box<dyn Trait>) {} + +fn main() { + Box::new(S) as Box<dyn Trait>; //~ ERROR E0038 + let t_box: Box<dyn Trait> = Box::new(S); //~ ERROR E0038 + takes_box(Box::new(S)); //~ ERROR E0038 +} diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr new file mode 100644 index 00000000000..0b63aef2bce --- /dev/null +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr @@ -0,0 +1,33 @@ +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj-box.rs:16:33 + | +LL | let t_box: Box<dyn Trait> = Box::new(S); + | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>` + = note: required by cast to type `std::boxed::Box<dyn Trait>` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj-box.rs:17:15 + | +LL | takes_box(Box::new(S)); + | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>` + = note: required by cast to type `std::boxed::Box<(dyn Trait + 'static)>` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj-box.rs:15:5 + | +LL | Box::new(S) as Box<dyn Trait>; + | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>` + = note: required by cast to type `std::boxed::Box<dyn Trait>` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs b/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs new file mode 100644 index 00000000000..143b854ed6b --- /dev/null +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs @@ -0,0 +1,18 @@ +// Check that we do not allow casts or coercions +// to object unsafe trait objects by ref + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized {} + +struct S; + +impl Trait for S {} + +fn takes_trait(t: &dyn Trait) {} + +fn main() { + &S as &dyn Trait; //~ ERROR E0038 + let t: &dyn Trait = &S; //~ ERROR E0038 + takes_trait(&S); //~ ERROR E0038 +} diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr new file mode 100644 index 00000000000..7aeefd731fb --- /dev/null +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr @@ -0,0 +1,33 @@ +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj.rs:16:25 + | +LL | let t: &dyn Trait = &S; + | ^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required by cast to type `&dyn Trait` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj.rs:17:17 + | +LL | takes_trait(&S); + | ^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required by cast to type `&dyn Trait` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj.rs:15:5 + | +LL | &S as &dyn Trait; + | ^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required by cast to type `&dyn Trait` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.rs b/src/test/ui/wf/wf-unsafe-trait-obj-match.rs new file mode 100644 index 00000000000..c8731a8ecaf --- /dev/null +++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.rs @@ -0,0 +1,29 @@ +// Check that we do not allow coercions to object +// unsafe trait objects in match arms + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized {} + +struct S; + +impl Trait for S {} + +struct R; + +impl Trait for R {} + +fn opt() -> Option<()> { + Some(()) +} + +fn main() { + match opt() { + Some(()) => &S, + None => &R, //~ ERROR E0308 + } + let t: &dyn Trait = match opt() { //~ ERROR E0038 + Some(()) => &S, //~ ERROR E0038 + None => &R, + }; +} diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr new file mode 100644 index 00000000000..185b1e6c36b --- /dev/null +++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -0,0 +1,38 @@ +error[E0308]: match arms have incompatible types + --> $DIR/wf-unsafe-trait-obj-match.rs:23:17 + | +LL | / match opt() { +LL | | Some(()) => &S, + | | -- this is found to be of type `&S` +LL | | None => &R, + | | ^^ expected struct `S`, found struct `R` +LL | | } + | |_____- `match` arms have incompatible types + | + = note: expected type `&S` + found type `&R` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-unsafe-trait-obj-match.rs:26:21 + | +LL | Some(()) => &S, + | ^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required by cast to type `&dyn Trait` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-unsafe-trait-obj-match.rs:25:25 + | +LL | let t: &dyn Trait = match opt() { + | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&R` + = note: required by cast to type `&dyn Trait` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0038, E0308. +For more information about an error, try `rustc --explain E0038`. diff --git a/src/tools/clippy b/src/tools/clippy -Subproject cbedd97b3a58023eff365a2fa74700d06115144 +Subproject e8d5a9e95c145a3a9be89c582d8a6f88d4ea703 diff --git a/src/tools/miri b/src/tools/miri -Subproject 2adc39f27b7fd2d06b3d1d470827928766731a1 +Subproject fccb2398248802a268fcda544ff3945247ef211 diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs new file mode 100644 index 00000000000..ee555a3e5bd --- /dev/null +++ b/src/tools/tidy/src/debug_artifacts.rs @@ -0,0 +1,24 @@ +//! Tidy check to prevent creation of unnecessary debug artifacts. + +use std::path::{Path, PathBuf}; + +const GRAPHVIZ_POSTFLOW_MSG: &'static str = + "`borrowck_graphviz_postflow` attribute in test"; + +pub fn check(path: &Path, bad: &mut bool) { + let test_dir: PathBuf = path.join("test"); + + super::walk(&test_dir, &mut super::filter_dirs, &mut |entry, contents| { + let filename = entry.path(); + let is_rust = filename.extension().map_or(false, |ext| ext == "rs"); + if !is_rust { + return; + } + + for (i, line) in contents.lines().enumerate() { + if line.contains("borrowck_graphviz_postflow") { + tidy_error!(bad, "{}:{}: {}", filename.display(), i + 1, GRAPHVIZ_POSTFLOW_MSG); + } + } + }); +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index eb93eb29747..d9db68ff66e 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -31,6 +31,7 @@ macro_rules! tidy_error { pub mod bins; pub mod style; +pub mod debug_artifacts; pub mod errors; pub mod features; pub mod cargo; @@ -45,7 +46,6 @@ pub mod error_codes_check; fn filter_dirs(path: &Path) -> bool { let skip = [ - "src/llvm-emscripten", "src/llvm-project", "src/stdarch", "src/tools/cargo", diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index e08c23c01fe..de6b0c5b28d 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -22,6 +22,7 @@ fn main() { let verbose = args.iter().any(|s| *s == "--verbose"); bins::check(&path, &mut bad); style::check(&path, &mut bad); + debug_artifacts::check(&path, &mut bad); errors::check(&path, &mut bad); cargo::check(&path, &mut bad); edition::check(&path, &mut bad); |
