From: kennytm Date: Wed, 9 May 2018 09:25:53 +0000 (+0800) Subject: Rollup merge of #50460 - F001:const_string, r=kennytm X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=1f4718a5c1ae842d119b2a0399ce07a4ee78c28c;hp=160063aad2206a35e6312bfaa159f0f4475af0ae;p=rust.git Rollup merge of #50460 - F001:const_string, r=kennytm Make `String::new()` const Following the steps of https://github.com/rust-lang/rust/pull/50233 , make `String::new()` a `const fn`. --- diff --git a/.mailmap b/.mailmap index 3ff9e94ee54..8f4287a4385 100644 --- a/.mailmap +++ b/.mailmap @@ -51,6 +51,7 @@ Carol Willing Chris C Cerami Chris C Cerami Chris Pressey Chris Thorn Chris Thorn +Chris Vittal Christopher Vittal Clark Gaebel Clinton Ryan Corey Richardson Elaine "See More" Nemo diff --git a/config.toml.example b/config.toml.example index effe0084381..34fcc755b3a 100644 --- a/config.toml.example +++ b/config.toml.example @@ -346,6 +346,9 @@ # Whether to deny warnings in crates #deny-warnings = true +# Print backtrace on internal compiler errors during bootstrap +#backtrace-on-ice = false + # ============================================================================= # Options for specific targets # diff --git a/src/Cargo.lock b/src/Cargo.lock index 0f08eaf596a..21c35458398 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -305,11 +305,11 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.195" +version = "0.0.197" dependencies = [ "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", - "clippy_lints 0.0.195", + "clippy_lints 0.0.197", "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -325,8 +325,9 @@ version = "0.2.0" [[package]] name = "clippy_lints" -version = "0.0.195" +version = "0.0.197" dependencies = [ + "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -390,6 +391,7 @@ dependencies = [ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1629,7 +1631,7 @@ version = "0.127.0" dependencies = [ "cargo 0.28.0", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy_lints 0.0.195", + "clippy_lints 0.0.197", "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1640,7 +1642,7 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1655,7 +1657,7 @@ dependencies = [ [[package]] name = "rls-analysis" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3143,7 +3145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb" "checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rls-analysis 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b339561571efd8d2d4ae1b16eb27f760cad46907d49e9726242844dbbde14e79" +"checksum rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a41488cf5dc99d6ce383319d2978756567b70d4ed0539eb0d9ce07763e732e46" "checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2" "checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510" "checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 9ff681ac680..98c353eb6ec 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -64,6 +64,10 @@ The script accepts commands, flags, and arguments to determine what to do: # execute tests in the standard library in stage0 ./x.py test --stage 0 src/libstd + # execute tests in the core and standard library in stage0, + # without running doc tests (thus avoid depending on building the compiler) + ./x.py test --stage 0 --no-doc src/libcore src/libstd + # execute all doc tests ./x.py test src/doc ``` diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index b6ae824c376..3f97accaa4d 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -107,6 +107,13 @@ fn main() { env::join_paths(&dylib_path).unwrap()); let mut maybe_crate = None; + // Print backtrace in case of ICE + if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() { + cmd.env("RUST_BACKTRACE", "1"); + } + + cmd.env("RUSTC_BREAK_ON_ICE", "1"); + if let Some(target) = target { // The stage0 compiler has a special sysroot distinct from what we // actually downloaded, so we just always pass the `--sysroot` option. diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 08bb8ab4815..9c35cb7f506 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -25,7 +25,7 @@ use install; use dist; use util::{exe, libdir, add_lib_path}; -use {Build, Mode}; +use {Build, Mode, DocTests}; use cache::{INTERNER, Interned, Cache}; use check; use test; @@ -591,6 +591,8 @@ pub fn cargo(&self, format!("{} {}", env::var("RUSTFLAGS").unwrap_or_default(), extra_args)); } + let want_rustdoc = self.doc_tests != DocTests::No; + // Customize the compiler we're running. Specify the compiler to cargo // as our shim and then pass it some various options used to configure // how the actual compiler itself is called. @@ -607,7 +609,7 @@ pub fn cargo(&self, .env("RUSTC_LIBDIR", self.rustc_libdir(compiler)) .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) - .env("RUSTDOC_REAL", if cmd == "doc" || cmd == "test" { + .env("RUSTDOC_REAL", if cmd == "doc" || (cmd == "test" && want_rustdoc) { self.rustdoc(compiler.host) } else { PathBuf::from("/path/to/nowhere/rustdoc/not/required") @@ -624,7 +626,7 @@ pub fn cargo(&self, if let Some(ref error_format) = self.config.rustc_error_format { cargo.env("RUSTC_ERROR_FORMAT", error_format); } - if cmd != "build" && cmd != "check" { + if cmd != "build" && cmd != "check" && want_rustdoc { cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.config.build))); } @@ -706,6 +708,10 @@ pub fn cargo(&self, cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1"); } + if self.config.backtrace_on_ice { + cargo.env("RUSTC_BACKTRACE_ON_ICE", "1"); + } + cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); // in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful. @@ -1403,4 +1409,39 @@ fn build_with_target_flag() { }, ]); } + + #[test] + fn test_with_no_doc_stage0() { + let mut config = configure(&[], &[]); + config.stage = Some(0); + config.cmd = Subcommand::Test { + paths: vec!["src/libstd".into()], + test_args: vec![], + rustc_args: vec![], + fail_fast: true, + doc_tests: DocTests::No, + }; + + let build = Build::new(config); + let mut builder = Builder::new(&build); + + let host = INTERNER.intern_str("A"); + + builder.run_step_descriptions( + &[StepDescription::from::()], + &["src/libstd".into()], + ); + + // Ensure we don't build any compiler artifacts. + assert!(builder.cache.all::().is_empty()); + assert_eq!(first(builder.cache.all::()), &[ + test::Crate { + compiler: Compiler { host, stage: 0 }, + target: host, + mode: Mode::Libstd, + test_kind: test::TestKind::Test, + krate: INTERNER.intern_str("std"), + }, + ]); + } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 7175f6a6764..6dd6291be23 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -72,6 +72,7 @@ pub struct Config { pub dry_run: bool, pub deny_warnings: bool, + pub backtrace_on_ice: bool, // llvm codegen options pub llvm_enabled: bool, @@ -306,6 +307,7 @@ struct Rust { wasm_syscall: Option, lld: Option, deny_warnings: Option, + backtrace_on_ice: Option, } /// TOML representation of how each build target is configured. @@ -531,6 +533,7 @@ pub fn parse(args: &[String]) -> Config { config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings)); + set(&mut config.backtrace_on_ice, rust.backtrace_on_ice); if let Some(ref backends) = rust.codegen_backends { config.rust_codegen_backends = backends.iter() diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index a0123da6d8f..3574b7d210a 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -120,6 +120,8 @@ v("musl-root-arm", "target.arm-unknown-linux-musleabi.musl-root", "arm-unknown-linux-musleabi install directory") v("musl-root-armhf", "target.arm-unknown-linux-musleabihf.musl-root", "arm-unknown-linux-musleabihf install directory") +v("musl-root-armv5te", "target.armv5te-unknown-linux-musleabi.musl-root", + "armv5te-unknown-linux-musleabi install directory") v("musl-root-armv7", "target.armv7-unknown-linux-musleabihf.musl-root", "armv7-unknown-linux-musleabihf install directory") v("musl-root-aarch64", "target.aarch64-unknown-linux-musl.musl-root", diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 3eb9dca2aa8..5315a3028ff 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -19,7 +19,7 @@ use getopts::Options; -use Build; +use {Build, DocTests}; use config::Config; use metadata; use builder::Builder; @@ -62,7 +62,7 @@ pub enum Subcommand { test_args: Vec, rustc_args: Vec, fail_fast: bool, - doc_tests: bool, + doc_tests: DocTests, }, Bench { paths: Vec, @@ -171,7 +171,8 @@ pub fn parse(args: &[String]) -> Flags { "extra options to pass the compiler when running tests", "ARGS", ); - opts.optflag("", "doc", "run doc tests"); + opts.optflag("", "no-doc", "do not run doc tests"); + opts.optflag("", "doc", "only run doc tests"); }, "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, "clean" => { opts.optflag("", "all", "clean all build artifacts"); }, @@ -324,7 +325,13 @@ pub fn parse(args: &[String]) -> Flags { test_args: matches.opt_strs("test-args"), rustc_args: matches.opt_strs("rustc-args"), fail_fast: !matches.opt_present("no-fail-fast"), - doc_tests: matches.opt_present("doc"), + doc_tests: if matches.opt_present("doc") { + DocTests::Only + } else if matches.opt_present("no-doc") { + DocTests::No + } else { + DocTests::Yes + } } } "bench" => { @@ -411,10 +418,10 @@ pub fn fail_fast(&self) -> bool { } } - pub fn doc_tests(&self) -> bool { + pub fn doc_tests(&self) -> DocTests { match *self { Subcommand::Test { doc_tests, .. } => doc_tests, - _ => false, + _ => DocTests::Yes, } } } diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs index fa3ba02482f..6445ce8da33 100644 --- a/src/bootstrap/job.rs +++ b/src/bootstrap/job.rs @@ -122,12 +122,10 @@ struct JOBOBJECT_BASIC_LIMIT_INFORMATION { } pub unsafe fn setup(build: &mut Build) { - // Tell Windows to not show any UI on errors (such as not finding a required dll - // during startup or terminating abnormally). This is important for running tests, - // since some of them use abnormal termination by design. - // This mode is inherited by all child processes. - let mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags - SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + // Enable the Windows Error Reporting dialog which msys disables, + // so we can JIT debug rustc + let mode = SetErrorMode(0); + SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX); // Create a new job object for us to use let job = CreateJobObjectW(0 as *mut _, 0 as *const _); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 0a7f0e5ff4e..e53fef06786 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -210,6 +210,16 @@ pub struct Compiler { host: Interned, } +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum DocTests { + // Default, run normal tests and doc tests. + Yes, + // Do not run any doc tests. + No, + // Only run doc tests. + Only, +} + /// Global configuration for the build system. /// /// This structure transitively contains all configuration for the build system. @@ -233,7 +243,7 @@ pub struct Build { rustfmt_info: channel::GitInfo, local_rebuild: bool, fail_fast: bool, - doc_tests: bool, + doc_tests: DocTests, verbosity: usize, // Targets for which to build. @@ -294,7 +304,7 @@ fn local_path(&self, build: &Build) -> PathBuf { /// /// These entries currently correspond to the various output directories of the /// build system, with each mod generating output in a different directory. -#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum Mode { /// Build the standard library, placing output in the "stageN-std" directory. Libstd, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e8c40dfdb0a..650e09feb0e 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -32,13 +32,13 @@ use native; use tool::{self, Tool}; use util::{self, dylib_path, dylib_path_var}; -use Mode; +use {Mode, DocTests}; use toolstate::ToolState; const ADB_TEST_DIR: &str = "/data/tmp/work"; /// The two modes of the test runner; tests or benchmarks. -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)] pub enum TestKind { /// Run `cargo test` Test, @@ -313,6 +313,9 @@ fn run(self, builder: &Builder) { // Don't build tests dynamically, just a pain to work with cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + let dir = testdir(builder, compiler.host); + t!(fs::create_dir_all(&dir)); + cargo.env("RUSTFMT_TEST_DIR", dir); builder.add_rustc_lib_path(compiler, &mut cargo); @@ -832,7 +835,7 @@ fn run(self, builder: &Builder) { host: true }); -default_test!(RunMake { +host_test!(RunMake { path: "src/test/run-make", mode: "run-make", suite: "run-make" @@ -1019,7 +1022,7 @@ fn run(self, builder: &Builder) { // Only pass correct values for these flags for the `run-make` suite as it // requires that a C++ compiler was configured which isn't always the case. - if !builder.config.dry_run && suite == "run-make-fulldeps" { + if !builder.config.dry_run && mode == "run-make" { let llvm_components = output(Command::new(&llvm_config).arg("--components")); let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); cmd.arg("--cc").arg(builder.cc(target)) @@ -1032,13 +1035,13 @@ fn run(self, builder: &Builder) { } } } - if suite == "run-make-fulldeps" && !builder.config.llvm_enabled { + if mode == "run-make" && !builder.config.llvm_enabled { builder.info( &format!("Ignoring run-make test suite as they generally don't work without LLVM")); return; } - if suite != "run-make-fulldeps" { + if mode != "run-make" { cmd.arg("--cc").arg("") .arg("--cxx").arg("") .arg("--cflags").arg("") @@ -1407,13 +1410,13 @@ fn run(self, builder: &Builder) { } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Crate { - compiler: Compiler, - target: Interned, - mode: Mode, - test_kind: TestKind, - krate: Interned, + pub compiler: Compiler, + pub target: Interned, + pub mode: Mode, + pub test_kind: TestKind, + pub krate: Interned, } impl Step for Crate { @@ -1519,8 +1522,14 @@ fn run(self, builder: &Builder) { if test_kind.subcommand() == "test" && !builder.fail_fast { cargo.arg("--no-fail-fast"); } - if builder.doc_tests { - cargo.arg("--doc"); + match builder.doc_tests { + DocTests::Only => { + cargo.arg("--doc"); + } + DocTests::No => { + cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]); + } + DocTests::Yes => {} } cargo.arg("-p").arg(krate); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 6c29bd84fe4..220af6bd6e4 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -10,6 +10,7 @@ use std::fs; use std::env; +use std::iter; use std::path::PathBuf; use std::process::{Command, exit}; @@ -593,7 +594,7 @@ pub fn tool_cmd(&self, tool: Tool) -> Command { /// right location to run `compiler`. fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) { let host = &compiler.host; - let mut paths: Vec = vec![ + let mut lib_paths: Vec = vec![ PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)), self.cargo_out(compiler, Mode::Tool, *host).join("deps"), ]; @@ -610,11 +611,46 @@ fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) { } for path in env::split_paths(v) { if !curpaths.contains(&path) { - paths.push(path); + lib_paths.push(path); } } } } - add_lib_path(paths, cmd); + + // Add the llvm/bin directory to PATH since it contains lots of + // useful, platform-independent tools + if let Some(llvm_bin_path) = self.llvm_bin_path() { + if host.contains("windows") { + // On Windows, PATH and the dynamic library path are the same, + // so we just add the LLVM bin path to lib_path + lib_paths.push(llvm_bin_path); + } else { + let old_path = env::var_os("PATH").unwrap_or_default(); + let new_path = env::join_paths(iter::once(llvm_bin_path) + .chain(env::split_paths(&old_path))) + .expect("Could not add LLVM bin path to PATH"); + cmd.env("PATH", new_path); + } + } + + add_lib_path(lib_paths, cmd); + } + + fn llvm_bin_path(&self) -> Option { + if self.config.llvm_enabled && !self.config.dry_run { + let llvm_config = self.ensure(native::Llvm { + target: self.config.build, + emscripten: false, + }); + + // Add the llvm/bin directory to PATH since it contains lots of + // useful, platform-independent tools + let llvm_bin_path = llvm_config.parent() + .expect("Expected llvm-config to be contained in directory"); + assert!(llvm_bin_path.is_dir()); + Some(llvm_bin_path.to_path_buf()) + } else { + None + } } } diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index 00366301aa1..b195decfcf5 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -43,6 +43,10 @@ ENV STAGING_DIR=/tmp COPY scripts/musl.sh /build RUN env \ + CC=arm-linux-gnueabi-gcc CFLAGS="-march=armv5te -marm -mfloat-abi=soft" \ + CXX=arm-linux-gnueabi-g++ CXXFLAGS="-march=armv5te -marm -mfloat-abi=soft" \ + bash musl.sh armv5te && \ + env \ CC=arm-linux-gnueabi-gcc CFLAGS="-march=armv6 -marm" \ CXX=arm-linux-gnueabi-g++ CXXFLAGS="-march=armv6 -marm" \ bash musl.sh arm && \ @@ -84,6 +88,7 @@ ENV TARGETS=$TARGETS,mipsel-unknown-linux-musl ENV TARGETS=$TARGETS,arm-unknown-linux-musleabi ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf ENV TARGETS=$TARGETS,armv5te-unknown-linux-gnueabi +ENV TARGETS=$TARGETS,armv5te-unknown-linux-musleabi ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu @@ -100,9 +105,12 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \ CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc \ CC_armv5te_unknown_linux_gnueabi=arm-linux-gnueabi-gcc \ - CFLAGS_armv5te_unknown_linux_gnueabi="-march=armv5te -marm -mfloat-abi=soft" + CFLAGS_armv5te_unknown_linux_gnueabi="-march=armv5te -marm -mfloat-abi=soft" \ + CC_armv5te_unknown_linux_musleabi=arm-linux-gnueabi-gcc \ + CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" ENV RUST_CONFIGURE_ARGS \ + --musl-root-armv5te=/musl-armv5te \ --musl-root-arm=/musl-arm \ --musl-root-armhf=/musl-armhf \ --musl-root-armv7=/musl-armv7 \ diff --git a/src/ci/docker/mingw-check/Dockerfile b/src/ci/docker/mingw-check/Dockerfile index ae4641009cf..aab339f399c 100644 --- a/src/ci/docker/mingw-check/Dockerfile +++ b/src/ci/docker/mingw-check/Dockerfile @@ -19,4 +19,5 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 ENV SCRIPT python2.7 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index ff6ab1013b4..bdde7ad7fe8 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV PARALLEL_CHECK 1 +ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-debug \ diff --git a/src/ci/run.sh b/src/ci/run.sh index 119b239d6b2..456f8cc7317 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -78,9 +78,9 @@ fi # sccache server at the start of the build, but no need to worry if this fails. SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true -if [ "$PARALLEL_CHECK" != "" ]; then +if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then $SRC/configure --enable-experimental-parallel-queries - python2.7 ../x.py check + CARGO_INCREMENTAL=0 python2.7 ../x.py check rm -f config.toml rm -rf build fi diff --git a/src/doc/book b/src/doc/book index 6237a75790c..f51127530d4 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 6237a75790cd2e0ca22961b55f64a83319e73464 +Subproject commit f51127530d46b9acbf4747c859da185e771cfcf3 diff --git a/src/doc/nomicon b/src/doc/nomicon index 3c56329d1bd..748a5e6742d 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 3c56329d1bd9038e5341f1962bcd8d043312a712 +Subproject commit 748a5e6742db4a21c4c630a58087f818828e8a0a diff --git a/src/doc/reference b/src/doc/reference index 76296346e97..134f419ee62 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 76296346e97c3702974d3398fdb94af9e10111a2 +Subproject commit 134f419ee62714590b04712fe6072253bc2a7822 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index d5ec87eabe5..eebda16e4b4 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit d5ec87eabe5733cc2348c7dada89fc67c086f391 +Subproject commit eebda16e4b45f2eed4310cf7b9872cc752278163 diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md index e7ec6af8be1..ef76295f04d 100644 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ b/src/doc/rustc/src/lints/listing/deny-by-default.md @@ -239,3 +239,44 @@ error: invalid `crate_type` value | ^^^^^^^^^^^^^^^^^^^^ | ``` + +## incoherent-fundamental-impls + +This lint detects potentially-conflicting impls that were erroneously allowed. Some +example code that triggers this lint: + +```rust,ignore +pub trait Trait1 { + type Output; +} + +pub trait Trait2 {} + +pub struct A; + +impl Trait1 for T where T: Trait2 { + type Output = (); +} + +impl Trait1> for A { + type Output = i32; +} +``` + +This will produce: + +```text +error: conflicting implementations of trait `Trait1>` for type `A`: (E0119) + --> src/main.rs:13:1 + | +9 | impl Trait1 for T where T: Trait2 { + | --------------------------------------------- first implementation here +... +13 | impl Trait1> for A { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A` + | + = note: #[deny(incoherent_fundamental_impls)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46205 + = note: downstream crates may implement trait `Trait2>` for type `A` +``` 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 1171f75caa1..b49708ff6ad 100644 --- a/src/doc/rustc/src/lints/listing/warn-by-default.md +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -117,47 +117,6 @@ warning: found struct without foreign-function-safe representation annotation in | ``` -## incoherent-fundamental-impls - -This lint detects potentially-conflicting impls that were erroneously allowed. Some -example code that triggers this lint: - -```rust -pub trait Trait1 { - type Output; -} - -pub trait Trait2 {} - -pub struct A; - -impl Trait1 for T where T: Trait2 { - type Output = (); -} - -impl Trait1> for A { - type Output = i32; -} -``` - -This will produce: - -```text -warning: conflicting implementations of trait `Trait1>` for type `A`: (E0119) - --> src/main.rs:13:1 - | -9 | impl Trait1 for T where T: Trait2 { - | --------------------------------------------- first implementation here -... -13 | impl Trait1> for A { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A` - | - = note: #[warn(incoherent_fundamental_impls)] on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46205 - = note: downstream crates may implement trait `Trait2>` for type `A` -``` - ## late-bound-lifetime-arguments This lint detects detects generic lifetime arguments in path segments with diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index 668b61c51d8..fcadcb544c4 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -157,7 +157,7 @@ use core::ops::{Deref, DerefMut}; use core::iter::{FromIterator, FusedIterator}; -use core::mem::{swap, size_of}; +use core::mem::{swap, size_of, ManuallyDrop}; use core::ptr; use core::fmt; @@ -864,8 +864,7 @@ fn better_to_rebuild(len1: usize, len2: usize) -> bool { /// position with the value that was originally removed. struct Hole<'a, T: 'a> { data: &'a mut [T], - /// `elt` is always `Some` from new until drop. - elt: Option, + elt: ManuallyDrop, pos: usize, } @@ -879,7 +878,7 @@ unsafe fn new(data: &'a mut [T], pos: usize) -> Self { let elt = ptr::read(&data[pos]); Hole { data, - elt: Some(elt), + elt: ManuallyDrop::new(elt), pos, } } @@ -892,7 +891,7 @@ fn pos(&self) -> usize { /// Returns a reference to the element removed. #[inline] fn element(&self) -> &T { - self.elt.as_ref().unwrap() + &self.elt } /// Returns a reference to the element at `index`. @@ -925,7 +924,7 @@ fn drop(&mut self) { // fill the hole again unsafe { let pos = self.pos; - ptr::write(self.data.get_unchecked_mut(pos), self.elt.take().unwrap()); + ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1); } } } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 1b4f86dcfac..a1567344235 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -62,7 +62,7 @@ use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; -use core::mem::{self, Pin}; +use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; use core::convert::From; @@ -771,8 +771,8 @@ pub fn new(data: T) -> PinBox { #[unstable(feature = "pin", issue = "49150")] impl PinBox { /// Get a pinned reference to the data in this PinBox. - pub fn as_pin<'a>(&'a mut self) -> Pin<'a, T> { - unsafe { Pin::new_unchecked(&mut *self.inner) } + pub fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> { + unsafe { PinMut::new_unchecked(&mut *self.inner) } } /// Get a mutable reference to the data inside this PinBox. diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 99e3012c9bf..5820fe58932 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -542,10 +542,10 @@ fn fmt(&self, fmt: &mut Formatter) -> Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( - on(crate_local, label="`{Self}` cannot be formatted using `:?`; \ - add `#[derive(Debug)]` or manually implement `{Debug}`"), + on(crate_local, label="`{Self}` cannot be formatted using `{{:?}}`", + note="add `#[derive(Debug)]` or manually implement `{Debug}`"), message="`{Self}` doesn't implement `{Debug}`", - label="`{Self}` cannot be formatted using `:?` because it doesn't implement `{Debug}`", + label="`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`", )] #[doc(alias = "{:?}")] #[lang = "debug_trait"] @@ -610,8 +610,9 @@ pub trait Debug { /// ``` #[rustc_on_unimplemented( message="`{Self}` doesn't implement `{Display}`", - label="`{Self}` cannot be formatted with the default formatter; \ - try using `:?` instead if you are using a format string", + label="`{Self}` cannot be formatted with the default formatter", + note="in format strings you may be able to use `{{:?}}` \ + (or {{:#?}} for pretty-print) instead", )] #[doc(alias = "{}")] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 04dd42583d4..54f35d17974 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -50,6 +50,15 @@ // Since libcore defines many fundamental lang items, all tests live in a // separate crate, libcoretest, to avoid bizarre issues. +// +// Here we explicitly #[cfg]-out this whole crate when testing. If we don't do +// this, both the generated test artifact and the linked libtest (which +// transitively includes libcore) will both define the same set of lang items, +// and this will cause the E0152 "duplicate lang item found" error. See +// discussion in #50466 for details. +// +// This cfg won't affect doc tests. +#![cfg(not(test))] #![stable(feature = "core", since = "1.6.0")] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index c074adfd570..db5f50a99ca 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -595,15 +595,15 @@ unsafe impl Freeze for *mut T {} unsafe impl<'a, T: ?Sized> Freeze for &'a T {} unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} -/// Types which can be moved out of a `Pin`. +/// Types which can be moved out of a `PinMut`. /// -/// The `Unpin` trait is used to control the behavior of the [`Pin`] type. If a +/// The `Unpin` trait is used to control the behavior of the [`PinMut`] type. If a /// type implements `Unpin`, it is safe to move a value of that type out of the -/// `Pin` pointer. +/// `PinMut` pointer. /// /// This trait is automatically implemented for almost every type. /// -/// [`Pin`]: ../mem/struct.Pin.html +/// [`PinMut`]: ../mem/struct.PinMut.html #[unstable(feature = "pin", issue = "49150")] pub unsafe auto trait Unpin {} diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 10efab82ddf..20445def634 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -959,8 +959,9 @@ impl ManuallyDrop { /// ManuallyDrop::new(Box::new(())); /// ``` #[stable(feature = "manually_drop", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_manually_drop_new")] #[inline] - pub fn new(value: T) -> ManuallyDrop { + pub const fn new(value: T) -> ManuallyDrop { ManuallyDrop { value: value } } @@ -1101,53 +1102,56 @@ fn hash(&self, state: &mut H) { /// value implements the `Unpin` trait. #[unstable(feature = "pin", issue = "49150")] #[fundamental] -pub struct Pin<'a, T: ?Sized + 'a> { +pub struct PinMut<'a, T: ?Sized + 'a> { inner: &'a mut T, } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unpin> Pin<'a, T> { - /// Construct a new `Pin` around a reference to some data of a type that +impl<'a, T: ?Sized + Unpin> PinMut<'a, T> { + /// Construct a new `PinMut` around a reference to some data of a type that /// implements `Unpin`. #[unstable(feature = "pin", issue = "49150")] - pub fn new(reference: &'a mut T) -> Pin<'a, T> { - Pin { inner: reference } + pub fn new(reference: &'a mut T) -> PinMut<'a, T> { + PinMut { inner: reference } } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> Pin<'a, T> { - /// Construct a new `Pin` around a reference to some data of a type that +impl<'a, T: ?Sized> PinMut<'a, T> { + /// Construct a new `PinMut` around a reference to some data of a type that /// may or may not implement `Unpin`. /// /// This constructor is unsafe because we do not know what will happen with /// that data after the reference ends. If you cannot guarantee that the /// data will never move again, calling this constructor is invalid. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn new_unchecked(reference: &'a mut T) -> Pin<'a, T> { - Pin { inner: reference } + pub unsafe fn new_unchecked(reference: &'a mut T) -> PinMut<'a, T> { + PinMut { inner: reference } } - /// Borrow a Pin for a shorter lifetime than it already has. + /// Reborrow a `PinMut` for a shorter lifetime. + /// + /// For example, `PinMut::get_mut(x.reborrow())` (unsafely) returns a + /// short-lived mutable reference reborrowing from `x`. #[unstable(feature = "pin", issue = "49150")] - pub fn borrow<'b>(this: &'b mut Pin<'a, T>) -> Pin<'b, T> { - Pin { inner: this.inner } + pub fn reborrow<'b>(&'b mut self) -> PinMut<'b, T> { + PinMut { inner: self.inner } } - /// Get a mutable reference to the data inside of this `Pin`. + /// Get a mutable reference to the data inside of this `PinMut`. /// /// This function is unsafe. You must guarantee that you will never move /// the data out of the mutable reference you receive when you call this /// function. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T { + pub unsafe fn get_mut(this: PinMut<'a, T>) -> &'a mut T { this.inner } /// Construct a new pin by mapping the interior value. /// - /// For example, if you wanted to get a `Pin` of a field of something, you + /// For example, if you wanted to get a `PinMut` of a field of something, you /// could use this to get access to that field in one line of code. /// /// This function is unsafe. You must guarantee that the data you return @@ -1155,15 +1159,15 @@ pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T { /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn map<'b, U, F>(this: &'b mut Pin<'a, T>, f: F) -> Pin<'b, U> where + pub unsafe fn map(this: PinMut<'a, T>, f: F) -> PinMut<'a, U> where F: FnOnce(&mut T) -> &mut U { - Pin { inner: f(this.inner) } + PinMut { inner: f(this.inner) } } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> Deref for Pin<'a, T> { +impl<'a, T: ?Sized> Deref for PinMut<'a, T> { type Target = T; fn deref(&self) -> &T { @@ -1172,35 +1176,35 @@ fn deref(&self) -> &T { } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unpin> DerefMut for Pin<'a, T> { +impl<'a, T: ?Sized + Unpin> DerefMut for PinMut<'a, T> { fn deref_mut(&mut self) -> &mut T { self.inner } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for Pin<'a, T> { +impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for PinMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: fmt::Display + ?Sized> fmt::Display for Pin<'a, T> { +impl<'a, T: fmt::Display + ?Sized> fmt::Display for PinMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> fmt::Pointer for Pin<'a, T> { +impl<'a, T: ?Sized> fmt::Pointer for PinMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&(&*self.inner as *const T), f) } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for Pin<'a, T> {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for PinMut<'a, T> {} #[unstable(feature = "pin", issue = "49150")] -unsafe impl<'a, T: ?Sized> Unpin for Pin<'a, T> {} +unsafe impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {} diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 8d5f6f601da..672119eba7f 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -128,10 +128,18 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const LOG2_E: f32 = 1.44269504088896340735992468100189214_f32; + /// log2(10) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG2_10: f32 = 3.32192809488736234787031942948939018_f32; + /// log10(e) #[stable(feature = "rust1", since = "1.0.0")] pub const LOG10_E: f32 = 0.434294481903251827651128918916605082_f32; + /// log10(2) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG10_2: f32 = 0.301029995663981195213738894724493027_f32; + /// ln(2) #[stable(feature = "rust1", since = "1.0.0")] pub const LN_2: f32 = 0.693147180559945309417232121458176568_f32; diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 08b869734d4..220b23a1e6a 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -124,10 +124,18 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const E: f64 = 2.71828182845904523536028747135266250_f64; + /// log2(10) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG2_10: f64 = 3.32192809488736234787031942948939018_f64; + /// log2(e) #[stable(feature = "rust1", since = "1.0.0")] pub const LOG2_E: f64 = 1.44269504088896340735992468100189214_f64; + /// log10(2) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG10_2: f64 = 0.301029995663981195213738894724493027_f64; + /// log10(e) #[stable(feature = "rust1", since = "1.0.0")] pub const LOG10_E: f64 = 0.434294481903251827651128918916605082_f64; diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index 469404f7f6b..7b62e7b0620 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -135,85 +135,3 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option { // find the byte before the point the body loop stopped text[..offset].iter().rposition(|elt| *elt == x) } - -// test fallback implementations on all platforms -#[test] -fn matches_one() { - assert_eq!(Some(0), memchr(b'a', b"a")); -} - -#[test] -fn matches_begin() { - assert_eq!(Some(0), memchr(b'a', b"aaaa")); -} - -#[test] -fn matches_end() { - assert_eq!(Some(4), memchr(b'z', b"aaaaz")); -} - -#[test] -fn matches_nul() { - assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); -} - -#[test] -fn matches_past_nul() { - assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); -} - -#[test] -fn no_match_empty() { - assert_eq!(None, memchr(b'a', b"")); -} - -#[test] -fn no_match() { - assert_eq!(None, memchr(b'a', b"xyz")); -} - -#[test] -fn matches_one_reversed() { - assert_eq!(Some(0), memrchr(b'a', b"a")); -} - -#[test] -fn matches_begin_reversed() { - assert_eq!(Some(3), memrchr(b'a', b"aaaa")); -} - -#[test] -fn matches_end_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); -} - -#[test] -fn matches_nul_reversed() { - assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); -} - -#[test] -fn matches_past_nul_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); -} - -#[test] -fn no_match_empty_reversed() { - assert_eq!(None, memrchr(b'a', b"")); -} - -#[test] -fn no_match_reversed() { - assert_eq!(None, memrchr(b'a', b"xyz")); -} - -#[test] -fn each_alignment_reversed() { - let mut data = [1u8; 64]; - let needle = 2; - let pos = 40; - data[pos] = needle; - for start in 0..16 { - assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); - } -} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index f6750c590b3..5e98e40e0d5 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -46,6 +46,7 @@ #![feature(reverse_bits)] #![feature(inclusive_range_methods)] #![feature(iterator_find_map)] +#![feature(slice_internals)] extern crate core; extern crate test; @@ -74,4 +75,5 @@ mod slice; mod str; mod str_lossy; +mod time; mod tuple; diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index ca6906f7310..257f6ea20d4 100644 --- a/src/libcore/tests/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs @@ -98,6 +98,7 @@ fn test_swap_bytes() { } #[test] + #[cfg(not(stage0))] fn test_reverse_bits() { assert_eq!(A.reverse_bits().reverse_bits(), A); assert_eq!(B.reverse_bits().reverse_bits(), B); diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 53fdfa06827..c81e5e97cbb 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -550,3 +550,89 @@ fn sort_unstable() { v.sort_unstable(); assert!(v == [0xDEADBEEF]); } + +pub mod memchr { + use core::slice::memchr::{memchr, memrchr}; + + // test fallback implementations on all platforms + #[test] + fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); + } + + #[test] + fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); + } + + #[test] + fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); + } + + #[test] + fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); + } + + #[test] + fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); + } + + #[test] + fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); + } + + #[test] + fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); + } + + #[test] + fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); + } + + #[test] + fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); + } + + #[test] + fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); + } + + #[test] + fn each_alignment_reversed() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); + } + } +} diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs new file mode 100644 index 00000000000..042c523f25f --- /dev/null +++ b/src/libcore/tests/time.rs @@ -0,0 +1,124 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::time::Duration; + +#[test] +fn creation() { + assert!(Duration::from_secs(1) != Duration::from_secs(0)); + assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), + Duration::from_secs(3)); + assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), + Duration::new(4, 10 * 1_000_000)); + assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); +} + +#[test] +fn secs() { + assert_eq!(Duration::new(0, 0).as_secs(), 0); + assert_eq!(Duration::from_secs(1).as_secs(), 1); + assert_eq!(Duration::from_millis(999).as_secs(), 0); + assert_eq!(Duration::from_millis(1001).as_secs(), 1); +} + +#[test] +fn nanos() { + assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); + assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); + assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); + assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); + assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); + assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); +} + +#[test] +fn add() { + assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), + Duration::new(1, 1)); +} + +#[test] +fn checked_add() { + assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), + Some(Duration::new(0, 1))); + assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), + Some(Duration::new(1, 1))); + assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::core::u64::MAX, 0)), None); +} + +#[test] +fn sub() { + assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), + Duration::new(0, 1)); + assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), + Duration::new(0, 999_999_999)); +} + +#[test] +fn checked_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); + assert_eq!(one_sec.checked_sub(one_nano), + Some(Duration::new(0, 999_999_999))); + assert_eq!(zero.checked_sub(one_nano), None); + assert_eq!(zero.checked_sub(one_sec), None); +} + +#[test] +#[should_panic] +fn sub_bad1() { + let _ = Duration::new(0, 0) - Duration::new(0, 1); +} + +#[test] +#[should_panic] +fn sub_bad2() { + let _ = Duration::new(0, 0) - Duration::new(1, 0); +} + +#[test] +fn mul() { + assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001) * 4000, + Duration::new(2000, 4000)); +} + +#[test] +fn checked_mul() { + assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); + assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), + Some(Duration::new(2000, 4000))); + assert_eq!(Duration::new(::core::u64::MAX - 1, 0).checked_mul(2), None); +} + +#[test] +fn div() { + assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); + assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); + assert_eq!(Duration::new(99, 999_999_000) / 100, + Duration::new(0, 999_999_990)); +} + +#[test] +fn checked_div() { + assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + assert_eq!(Duration::new(2, 0).checked_div(0), None); +} diff --git a/src/libcore/time.rs b/src/libcore/time.rs index e22fe450bb1..8e8b1691c65 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -481,119 +481,3 @@ fn sum>(iter: I) -> Duration { iter.fold(Duration::new(0, 0), |a, b| a + *b) } } - -#[cfg(test)] -mod tests { - use super::Duration; - - #[test] - fn creation() { - assert!(Duration::from_secs(1) != Duration::from_secs(0)); - assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), - Duration::from_secs(3)); - assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), - Duration::new(4, 10 * 1_000_000)); - assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); - } - - #[test] - fn secs() { - assert_eq!(Duration::new(0, 0).as_secs(), 0); - assert_eq!(Duration::from_secs(1).as_secs(), 1); - assert_eq!(Duration::from_millis(999).as_secs(), 0); - assert_eq!(Duration::from_millis(1001).as_secs(), 1); - } - - #[test] - fn nanos() { - assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); - assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); - assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); - assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); - assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); - assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); - } - - #[test] - fn add() { - assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), - Duration::new(1, 1)); - } - - #[test] - fn checked_add() { - assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), - Some(Duration::new(0, 1))); - assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), - Some(Duration::new(1, 1))); - assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); - } - - #[test] - fn sub() { - assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), - Duration::new(0, 1)); - assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), - Duration::new(0, 999_999_999)); - } - - #[test] - fn checked_sub() { - let zero = Duration::new(0, 0); - let one_nano = Duration::new(0, 1); - let one_sec = Duration::new(1, 0); - assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); - assert_eq!(one_sec.checked_sub(one_nano), - Some(Duration::new(0, 999_999_999))); - assert_eq!(zero.checked_sub(one_nano), None); - assert_eq!(zero.checked_sub(one_sec), None); - } - - #[test] #[should_panic] - fn sub_bad1() { - Duration::new(0, 0) - Duration::new(0, 1); - } - - #[test] #[should_panic] - fn sub_bad2() { - Duration::new(0, 0) - Duration::new(1, 0); - } - - #[test] - fn mul() { - assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); - assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); - assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); - assert_eq!(Duration::new(0, 500_000_001) * 4000, - Duration::new(2000, 4000)); - } - - #[test] - fn checked_mul() { - assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); - assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), - Some(Duration::new(2000, 4000))); - assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); - } - - #[test] - fn div() { - assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); - assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); - assert_eq!(Duration::new(99, 999_999_000) / 100, - Duration::new(0, 999_999_990)); - } - - #[test] - fn checked_div() { - assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); - assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); - assert_eq!(Duration::new(2, 0).checked_div(0), None); - } -} diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index f51dbc3772f..8451e5987e9 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -74,6 +74,11 @@ #[derive(Clone)] pub struct TokenStream(tokenstream::TokenStream); +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for TokenStream {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for TokenStream {} + /// Error returned from `TokenStream::from_str`. #[stable(feature = "proc_macro_lib", since = "1.15.0")] #[derive(Debug)] @@ -81,6 +86,11 @@ pub struct LexError { _inner: (), } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for LexError {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for LexError {} + impl TokenStream { /// Returns an empty `TokenStream`. #[unstable(feature = "proc_macro", issue = "38356")] @@ -231,6 +241,11 @@ pub fn quote_span(span: Span) -> TokenStream { #[derive(Copy, Clone)] pub struct Span(syntax_pos::Span); +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for Span {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for Span {} + macro_rules! diagnostic_method { ($name:ident, $level:expr) => ( /// Create a new `Diagnostic` with the given `message` at the span @@ -363,6 +378,11 @@ pub struct LineColumn { pub column: usize } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for LineColumn {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for LineColumn {} + /// The source file of a given `Span`. #[unstable(feature = "proc_macro", issue = "38356")] #[derive(Clone)] @@ -393,7 +413,7 @@ pub fn path(&self) -> &FileName { /// Returns `true` if this source file is a real source file, and not generated by an external /// macro's expansion. - # [unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro", issue = "38356")] pub fn is_real(&self) -> bool { // This is a hack until intercrate spans are implemented and we can have real source files // for spans generated in external macros. @@ -450,6 +470,11 @@ pub enum TokenTree { Literal(Literal), } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for TokenTree {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for TokenTree {} + impl TokenTree { /// Returns the span of this token, accessing the `span` method of each of /// the internal tokens. @@ -546,6 +571,11 @@ pub struct Group { span: Span, } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for Group {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for Group {} + /// Describes how a sequence of token trees is delimited. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[unstable(feature = "proc_macro", issue = "38356")] @@ -628,6 +658,11 @@ pub struct Op { span: Span, } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for Op {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for Op {} + /// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[unstable(feature = "proc_macro", issue = "38356")] @@ -694,6 +729,11 @@ pub struct Term { span: Span, } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for Term {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for Term {} + impl Term { /// Creates a new `Term` with the given `string` as well as the specified /// `span`. @@ -752,6 +792,11 @@ pub struct Literal { span: Span, } +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Send for Literal {} +#[unstable(feature = "proc_macro", issue = "38356")] +impl !Sync for Literal {} + macro_rules! suffixed_int_literals { ($($name:ident => $kind:ident,)*) => ($( /// Creates a new suffixed integer literal with the specified value. diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 109edffcde3..398d7d5704c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -14,7 +14,7 @@ //! compiler code, rather than using their own custom pass. Those //! lints are all available in `rustc_lint::builtin`. -use errors::DiagnosticBuilder; +use errors::{Applicability, DiagnosticBuilder}; use lint::{LintPass, LateLintPass, LintArray}; use session::Session; use syntax::codemap::Span; @@ -208,7 +208,7 @@ declare_lint! { pub INCOHERENT_FUNDAMENTAL_IMPLS, - Warn, + Deny, "potentially-conflicting impls were erroneously allowed" } @@ -341,15 +341,16 @@ pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) { match self { BuiltinLintDiagnostics::Normal => (), BuiltinLintDiagnostics::BareTraitObject(span, is_global) => { - let sugg = match sess.codemap().span_to_snippet(span) { - Ok(ref s) if is_global => format!("dyn ({})", s), - Ok(s) => format!("dyn {}", s), - Err(_) => format!("dyn ") + let (sugg, app) = match sess.codemap().span_to_snippet(span) { + Ok(ref s) if is_global => (format!("dyn ({})", s), + Applicability::MachineApplicable), + Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable), + Err(_) => (format!("dyn "), Applicability::HasPlaceholders) }; - db.span_suggestion(span, "use `dyn`", sugg); + db.span_suggestion_with_applicability(span, "use `dyn`", sugg, app); } BuiltinLintDiagnostics::AbsPathWithModule(span) => { - let sugg = match sess.codemap().span_to_snippet(span) { + let (sugg, app) = match sess.codemap().span_to_snippet(span) { Ok(ref s) => { // FIXME(Manishearth) ideally the emitting code // can tell us whether or not this is global @@ -359,11 +360,11 @@ pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) { "::" }; - format!("crate{}{}", opt_colon, s) + (format!("crate{}{}", opt_colon, s), Applicability::MachineApplicable) } - Err(_) => format!("crate::") + Err(_) => (format!("crate::"), Applicability::HasPlaceholders) }; - db.span_suggestion(span, "use `crate`", sugg); + db.span_suggestion_with_applicability(span, "use `crate`", sugg, app); } } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 2cc5a4a8fe6..725fcf1e646 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -28,6 +28,7 @@ use hir::{self, PatKind}; use rustc_data_structures::sync::Lrc; +use std::rc::Rc; use syntax::ast; use syntax::ptr::P; use syntax_pos::Span; @@ -44,7 +45,7 @@ pub trait Delegate<'tcx> { fn consume(&mut self, consume_id: ast::NodeId, consume_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: ConsumeMode); // The value found at `cmt` has been determined to match the @@ -61,14 +62,14 @@ fn consume(&mut self, // called on a subpart of an input passed to `matched_pat). fn matched_pat(&mut self, matched_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: MatchMode); // The value found at `cmt` is either copied or moved via the // pattern binding `consume_pat`, depending on mode. fn consume_pat(&mut self, consume_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: ConsumeMode); // The value found at `borrow` is being borrowed at the point @@ -76,7 +77,7 @@ fn consume_pat(&mut self, fn borrow(&mut self, borrow_id: ast::NodeId, borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: LoanCause); @@ -90,7 +91,7 @@ fn decl_without_init(&mut self, fn mutate(&mut self, assignment_id: ast::NodeId, assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>, + assignee_cmt: &mc::cmt_<'tcx>, mode: MutateMode); } @@ -316,11 +317,11 @@ pub fn consume_body(&mut self, body: &hir::Body) { let fn_body_scope_r = self.tcx().mk_region(ty::ReScope(region::Scope::Node(body.value.hir_id.local_id))); - let arg_cmt = self.mc.cat_rvalue( + let arg_cmt = Rc::new(self.mc.cat_rvalue( arg.id, arg.pat.span, fn_body_scope_r, // Args live only as long as the fn body. - arg_ty); + arg_ty)); self.walk_irrefutable_pat(arg_cmt, &arg.pat); } @@ -335,11 +336,11 @@ fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { fn delegate_consume(&mut self, consume_id: ast::NodeId, consume_span: Span, - cmt: mc::cmt<'tcx>) { + cmt: &mc::cmt_<'tcx>) { debug!("delegate_consume(consume_id={}, cmt={:?})", consume_id, cmt); - let mode = copy_or_move(&self.mc, self.param_env, &cmt, DirectRefMove); + let mode = copy_or_move(&self.mc, self.param_env, cmt, DirectRefMove); self.delegate.consume(consume_id, consume_span, cmt, mode); } @@ -353,7 +354,7 @@ pub fn consume_expr(&mut self, expr: &hir::Expr) { debug!("consume_expr(expr={:?})", expr); let cmt = return_if_err!(self.mc.cat_expr(expr)); - self.delegate_consume(expr.id, expr.span, cmt); + self.delegate_consume(expr.id, expr.span, &cmt); self.walk_expr(expr); } @@ -362,7 +363,7 @@ fn mutate_expr(&mut self, expr: &hir::Expr, mode: MutateMode) { let cmt = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.mutate(assignment_expr.id, assignment_expr.span, cmt, mode); + self.delegate.mutate(assignment_expr.id, assignment_expr.span, &cmt, mode); self.walk_expr(expr); } @@ -375,7 +376,7 @@ fn borrow_expr(&mut self, expr, r, bk); let cmt = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause); + self.delegate.borrow(expr.id, expr.span, &cmt, r, bk, cause); self.walk_expr(expr) } @@ -435,7 +436,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) { } hir::ExprMatch(ref discr, ref arms, _) => { - let discr_cmt = return_if_err!(self.mc.cat_expr(&discr)); + let discr_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&discr))); let r = self.tcx().types.re_empty; self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant); @@ -619,7 +620,7 @@ fn walk_local(&mut self, local: &hir::Local) { // "assigns", which is handled by // `walk_pat`: self.walk_expr(&expr); - let init_cmt = return_if_err!(self.mc.cat_expr(&expr)); + let init_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&expr))); self.walk_irrefutable_pat(init_cmt, &local.pat); } } @@ -652,7 +653,7 @@ fn walk_struct_expr(&mut self, None => { return; } }; - let with_cmt = return_if_err!(self.mc.cat_expr(&with_expr)); + let with_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&with_expr))); // Select just those fields of the `with` // expression that will actually be used @@ -671,7 +672,7 @@ fn walk_struct_expr(&mut self, with_field.name, with_field.ty(self.tcx(), substs) ); - self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + self.delegate_consume(with_expr.id, with_expr.span, &cmt_field); } } } @@ -710,7 +711,7 @@ fn walk_adjustment(&mut self, expr: &hir::Expr) { adjustment::Adjust::Unsize => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. - self.delegate_consume(expr.id, expr.span, cmt.clone()); + self.delegate_consume(expr.id, expr.span, &cmt); } adjustment::Adjust::Deref(None) => {} @@ -722,12 +723,11 @@ fn walk_adjustment(&mut self, expr: &hir::Expr) { // this is an autoref of `x`. adjustment::Adjust::Deref(Some(ref deref)) => { let bk = ty::BorrowKind::from_mutbl(deref.mutbl); - self.delegate.borrow(expr.id, expr.span, cmt.clone(), - deref.region, bk, AutoRef); + self.delegate.borrow(expr.id, expr.span, &cmt, deref.region, bk, AutoRef); } adjustment::Adjust::Borrow(ref autoref) => { - self.walk_autoref(expr, cmt.clone(), autoref); + self.walk_autoref(expr, &cmt, autoref); } } cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment)); @@ -739,7 +739,7 @@ fn walk_adjustment(&mut self, expr: &hir::Expr) { /// after all relevant autoderefs have occurred. fn walk_autoref(&mut self, expr: &hir::Expr, - cmt_base: mc::cmt<'tcx>, + cmt_base: &mc::cmt_<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>) { debug!("walk_autoref(expr.id={} cmt_base={:?} autoref={:?})", expr.id, @@ -852,7 +852,7 @@ fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: Mat // Each match binding is effectively an assignment to the // binding being produced. let def = Def::Local(canonical_id); - if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty, def) { + if let Ok(ref binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty, def) { delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init); } @@ -861,13 +861,13 @@ fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: Mat ty::BindByReference(m) => { if let ty::TyRef(r, _) = pat_ty.sty { let bk = ty::BorrowKind::from_mutbl(m); - delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding); + delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding); } } ty::BindByValue(..) => { let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove); debug!("walk_pat binding consuming pat"); - delegate.consume_pat(pat, cmt_pat, mode); + delegate.consume_pat(pat, &cmt_pat, mode); } } } @@ -891,12 +891,12 @@ fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: Mat let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did); debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat); - delegate.matched_pat(pat, downcast_cmt, match_mode); + delegate.matched_pat(pat, &downcast_cmt, match_mode); } Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => { debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat); - delegate.matched_pat(pat, cmt_pat, match_mode); + delegate.matched_pat(pat, &cmt_pat, match_mode); } _ => {} } @@ -924,12 +924,12 @@ fn walk_captures(&mut self, closure_expr: &hir::Expr, fn_decl_span: Span) { self.param_env, &cmt_var, CaptureMove); - self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode); + self.delegate.consume(closure_expr.id, freevar.span, &cmt_var, mode); } ty::UpvarCapture::ByRef(upvar_borrow) => { self.delegate.borrow(closure_expr.id, fn_decl_span, - cmt_var, + &cmt_var, upvar_borrow.region, upvar_borrow.kind, ClosureCapture(freevar.span)); @@ -943,7 +943,7 @@ fn cat_captured_var(&mut self, closure_id: ast::NodeId, closure_span: Span, upvar: &hir::Freevar) - -> mc::McResult> { + -> mc::McResult> { // Create the cmt for the variable being borrowed, from the // caller's perspective let var_hir_id = self.tcx().hir.node_to_hir_id(upvar.var_id()); @@ -954,7 +954,7 @@ fn cat_captured_var(&mut self, fn copy_or_move<'a, 'gcx, 'tcx>(mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - cmt: &mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, move_reason: MoveReason) -> ConsumeMode { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 6f41f07dce8..f40a41cd299 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -572,13 +572,13 @@ fn pat_ty_unadjusted(&self, pat: &hir::Pat) -> McResult> { Ok(ret_ty) } - pub fn cat_expr(&self, expr: &hir::Expr) -> McResult> { + pub fn cat_expr(&self, expr: &hir::Expr) -> McResult> { // This recursion helper avoids going through *too many* // adjustments, since *only* non-overloaded deref recurses. fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>, expr: &hir::Expr, adjustments: &[adjustment::Adjustment<'tcx>]) - -> McResult> { + -> McResult> { match adjustments.split_last() { None => mc.cat_expr_unadjusted(expr), Some((adjustment, previous)) => { @@ -591,24 +591,24 @@ fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>, } pub fn cat_expr_adjusted(&self, expr: &hir::Expr, - previous: cmt<'tcx>, + previous: cmt_<'tcx>, adjustment: &adjustment::Adjustment<'tcx>) - -> McResult> { + -> McResult> { self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment) } fn cat_expr_adjusted_with(&self, expr: &hir::Expr, previous: F, adjustment: &adjustment::Adjustment<'tcx>) - -> McResult> - where F: FnOnce() -> McResult> + -> McResult> + where F: FnOnce() -> McResult> { debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr); let target = self.resolve_type_vars_if_possible(&adjustment.target); match adjustment.kind { adjustment::Adjust::Deref(overloaded) => { // Equivalent to *expr or something similar. - let base = if let Some(deref) = overloaded { + let base = Rc::new(if let Some(deref) = overloaded { let ref_ty = self.tcx.mk_ref(deref.region, ty::TypeAndMut { ty: target, mutbl: deref.mutbl, @@ -616,7 +616,7 @@ fn cat_expr_adjusted_with(&self, expr: &hir::Expr, self.cat_rvalue_node(expr.id, expr.span, ref_ty) } else { previous()? - }; + }); self.cat_deref(expr, base, false) } @@ -633,7 +633,7 @@ fn cat_expr_adjusted_with(&self, expr: &hir::Expr, } } - pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult> { + pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult> { debug!("cat_expr: id={} expr={:?}", expr.id, expr); let expr_ty = self.expr_ty(expr)?; @@ -642,13 +642,13 @@ pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult> { if self.tables.is_method_call(expr) { self.cat_overloaded_place(expr, e_base, false) } else { - let base_cmt = self.cat_expr(&e_base)?; + let base_cmt = Rc::new(self.cat_expr(&e_base)?); self.cat_deref(expr, base_cmt, false) } } hir::ExprField(ref base, f_name) => { - let base_cmt = self.cat_expr(&base)?; + let base_cmt = Rc::new(self.cat_expr(&base)?); debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.id, expr, @@ -666,7 +666,7 @@ pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult> { // dereferencing. self.cat_overloaded_place(expr, base, true) } else { - let base_cmt = self.cat_expr(&base)?; + let base_cmt = Rc::new(self.cat_expr(&base)?); self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index) } } @@ -701,7 +701,7 @@ pub fn cat_def(&self, span: Span, expr_ty: Ty<'tcx>, def: Def) - -> McResult> { + -> McResult> { debug!("cat_def: id={} expr={:?} def={:?}", id, expr_ty, def); @@ -718,14 +718,14 @@ pub fn cat_def(&self, return Ok(self.cat_rvalue_node(id, span, expr_ty)); } } - Ok(Rc::new(cmt_ { + Ok(cmt_ { id:id, span:span, cat:Categorization::StaticItem, mutbl: if mutbl { McDeclared } else { McImmutable}, ty:expr_ty, note: NoteNone - })) + }) } Def::Upvar(var_id, _, fn_node_id) => { @@ -733,14 +733,14 @@ pub fn cat_def(&self, } Def::Local(vid) => { - Ok(Rc::new(cmt_ { + Ok(cmt_ { id, span, cat: Categorization::Local(vid), mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vid), ty: expr_ty, note: NoteNone - })) + }) } def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def) @@ -754,7 +754,7 @@ fn cat_upvar(&self, span: Span, var_id: ast::NodeId, fn_node_id: ast::NodeId) - -> McResult> + -> McResult> { let fn_hir_id = self.tcx.hir.node_to_hir_id(fn_node_id); @@ -861,7 +861,7 @@ fn cat_upvar(&self, } }; - let ret = Rc::new(cmt_result); + let ret = cmt_result; debug!("cat_upvar ret={:?}", ret); Ok(ret) } @@ -938,7 +938,7 @@ pub fn cat_rvalue_node(&self, id: ast::NodeId, span: Span, expr_ty: Ty<'tcx>) - -> cmt<'tcx> { + -> cmt_<'tcx> { let hir_id = self.tcx.hir.node_to_hir_id(id); let promotable = self.rvalue_promotable_map.as_ref().map(|m| m.contains(&hir_id.local_id)) .unwrap_or(false); @@ -966,15 +966,15 @@ pub fn cat_rvalue(&self, cmt_id: ast::NodeId, span: Span, temp_scope: ty::Region<'tcx>, - expr_ty: Ty<'tcx>) -> cmt<'tcx> { - let ret = Rc::new(cmt_ { + expr_ty: Ty<'tcx>) -> cmt_<'tcx> { + let ret = cmt_ { id:cmt_id, span:span, cat:Categorization::Rvalue(temp_scope), mutbl:McDeclared, ty:expr_ty, note: NoteNone - }); + }; debug!("cat_rvalue ret {:?}", ret); ret } @@ -985,15 +985,15 @@ pub fn cat_field(&self, f_index: usize, f_name: Name, f_ty: Ty<'tcx>) - -> cmt<'tcx> { - let ret = Rc::new(cmt_ { + -> cmt_<'tcx> { + let ret = cmt_ { id: node.id(), span: node.span(), mutbl: base_cmt.mutbl.inherit(), cat: Categorization::Interior(base_cmt, InteriorField(FieldIndex(f_index, f_name))), ty: f_ty, note: NoteNone - }); + }; debug!("cat_field ret {:?}", ret); ret } @@ -1002,7 +1002,7 @@ fn cat_overloaded_place(&self, expr: &hir::Expr, base: &hir::Expr, implicit: bool) - -> McResult> { + -> McResult> { debug!("cat_overloaded_place: implicit={}", implicit); // Reconstruct the output assuming it's a reference with the @@ -1022,7 +1022,7 @@ fn cat_overloaded_place(&self, mutbl, }); - let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty); + let base_cmt = Rc::new(self.cat_rvalue_node(expr.id, expr.span, ref_ty)); self.cat_deref(expr, base_cmt, implicit) } @@ -1030,7 +1030,7 @@ pub fn cat_deref(&self, node: &N, base_cmt: cmt<'tcx>, implicit: bool) - -> McResult> { + -> McResult> { debug!("cat_deref: base_cmt={:?}", base_cmt); let base_cmt_ty = base_cmt.ty; @@ -1052,7 +1052,7 @@ pub fn cat_deref(&self, } ref ty => bug!("unexpected type in cat_deref: {:?}", ty) }; - let ret = Rc::new(cmt_ { + let ret = cmt_ { id: node.id(), span: node.span(), // For unique ptrs, we inherit mutability from the owning reference. @@ -1060,7 +1060,7 @@ pub fn cat_deref(&self, cat: Categorization::Deref(base_cmt, ptr), ty: deref_ty, note: NoteNone - }); + }; debug!("cat_deref ret {:?}", ret); Ok(ret) } @@ -1070,7 +1070,7 @@ fn cat_index(&self, base_cmt: cmt<'tcx>, element_ty: Ty<'tcx>, context: InteriorOffsetKind) - -> McResult> { + -> McResult> { //! Creates a cmt for an indexing operation (`[]`). //! //! One subtle aspect of indexing that may not be @@ -1089,8 +1089,7 @@ fn cat_index(&self, //! - `base_cmt`: the cmt of `elt` let interior_elem = InteriorElement(context); - let ret = - self.cat_imm_interior(elt, base_cmt, element_ty, interior_elem); + let ret = self.cat_imm_interior(elt, base_cmt, element_ty, interior_elem); debug!("cat_index ret {:?}", ret); return Ok(ret); } @@ -1100,15 +1099,15 @@ pub fn cat_imm_interior(&self, base_cmt: cmt<'tcx>, interior_ty: Ty<'tcx>, interior: InteriorKind) - -> cmt<'tcx> { - let ret = Rc::new(cmt_ { + -> cmt_<'tcx> { + let ret = cmt_ { id: node.id(), span: node.span(), mutbl: base_cmt.mutbl.inherit(), cat: Categorization::Interior(base_cmt, interior), ty: interior_ty, note: NoteNone - }); + }; debug!("cat_imm_interior ret={:?}", ret); ret } @@ -1232,7 +1231,7 @@ fn cat_pattern_(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McR .get(pat.hir_id) .map(|v| v.len()) .unwrap_or(0) { - cmt = self.cat_deref(pat, cmt, true /* implicit */)?; + cmt = Rc::new(self.cat_deref(pat, cmt, true /* implicit */)?); } let cmt = cmt; // lose mutability @@ -1279,7 +1278,7 @@ fn cat_pattern_(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McR for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string()))); - let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior); + let subcmt = Rc::new(self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior)); self.cat_pattern_(subcmt, &subpat, op)?; } } @@ -1302,7 +1301,8 @@ fn cat_pattern_(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McR for fp in field_pats { let field_ty = self.pat_ty(&fp.node.pat)?; // see (*2) let f_index = self.tcx.field_index(fp.node.id, self.tables); - let cmt_field = self.cat_field(pat, cmt.clone(), f_index, fp.node.name, field_ty); + let cmt_field = + Rc::new(self.cat_field(pat, cmt.clone(), f_index, fp.node.name, field_ty)); self.cat_pattern_(cmt_field, &fp.node.pat, op)?; } } @@ -1320,7 +1320,7 @@ fn cat_pattern_(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McR for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string()))); - let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior); + let subcmt = Rc::new(self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior)); self.cat_pattern_(subcmt, &subpat, op)?; } } @@ -1329,7 +1329,7 @@ fn cat_pattern_(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McR // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subcmt = self.cat_deref(pat, cmt, false)?; + let subcmt = Rc::new(self.cat_deref(pat, cmt, false)?); self.cat_pattern_(subcmt, &subpat, op)?; } @@ -1342,7 +1342,7 @@ fn cat_pattern_(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McR } }; let context = InteriorOffsetKind::Pattern; - let elt_cmt = self.cat_index(pat, cmt, element_ty, context)?; + let elt_cmt = Rc::new(self.cat_index(pat, cmt, element_ty, context)?); for before_pat in before { self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?; } @@ -1379,7 +1379,7 @@ pub enum AliasableReason { } impl<'tcx> cmt_<'tcx> { - pub fn guarantor(&self) -> cmt<'tcx> { + pub fn guarantor(&self) -> cmt_<'tcx> { //! Returns `self` after stripping away any derefs or //! interior content. The return value is basically the `cmt` which //! determines how long the value in `self` remains live. @@ -1392,7 +1392,7 @@ pub fn guarantor(&self) -> cmt<'tcx> { Categorization::Deref(_, BorrowedPtr(..)) | Categorization::Deref(_, Implicit(..)) | Categorization::Upvar(..) => { - Rc::new((*self).clone()) + (*self).clone() } Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) | @@ -1442,16 +1442,17 @@ pub fn freely_aliasable(&self) -> Aliasability { } } - // Digs down through one or two layers of deref and grabs the cmt - // for the upvar if a note indicates there is one. - pub fn upvar(&self) -> Option> { + // Digs down through one or two layers of deref and grabs the + // Categorization of the cmt for the upvar if a note indicates there is + // one. + pub fn upvar_cat(&self) -> Option<&Categorization<'tcx>> { match self.note { NoteClosureEnv(..) | NoteUpvarRef(..) => { Some(match self.cat { Categorization::Deref(ref inner, _) => { match inner.cat { - Categorization::Deref(ref inner, _) => inner.clone(), - Categorization::Upvar(..) => inner.clone(), + Categorization::Deref(ref inner, _) => &inner.cat, + Categorization::Upvar(..) => &inner.cat, _ => bug!() } } @@ -1462,7 +1463,6 @@ pub fn upvar(&self) -> Option> { } } - pub fn descriptive_string(&self, tcx: TyCtxt) -> String { match self.cat { Categorization::StaticItem => { @@ -1479,8 +1479,7 @@ pub fn descriptive_string(&self, tcx: TyCtxt) -> String { } } Categorization::Deref(_, pk) => { - let upvar = self.upvar(); - match upvar.as_ref().map(|i| &i.cat) { + match self.upvar_cat() { Some(&Categorization::Upvar(ref var)) => { var.to_string() } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 55bfbed0b39..37f6d47ff84 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1978,6 +1978,11 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { } impl Location { + pub const START: Location = Location { + block: START_BLOCK, + statement_index: 0, + }; + /// Returns the location immediately after this one within the enclosing block. /// /// Note that if this location represents a terminator, then the diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index dc97c941567..83dac033f94 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1250,6 +1250,8 @@ fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool { "choose which RELRO level to use"), nll_subminimal_causes: bool = (false, parse_bool, [UNTRACKED], "when tracking region error causes, accept subminimal results for faster execution."), + nll_facts: bool = (false, parse_bool, [UNTRACKED], + "dump facts from NLL analysis into side files"), disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED], "disable user provided type assertion in NLL"), trans_time_graph: bool = (false, parse_bool, [UNTRACKED], @@ -1293,6 +1295,8 @@ fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool { "make the current crate share its generic instantiations"), chalk: bool = (false, parse_bool, [TRACKED], "enable the experimental Chalk-based trait solving engine"), + cross_lang_lto: bool = (false, parse_bool, [TRACKED], + "generate build artifacts that are compatible with linker-based LTO."), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index a319b341ebb..02c4b73efa1 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1057,7 +1057,7 @@ enum StructKind { } tcx.intern_layout(LayoutDetails { variants: Variants::Tagged { - discr: tag, + tag, variants: layout_variants, }, fields: FieldPlacement::Arbitrary { @@ -1218,7 +1218,7 @@ fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) { }) .collect(); record(adt_kind.into(), adt_packed, match layout.variants { - Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)), + Variants::Tagged { ref tag, .. } => Some(tag.value.size(self)), _ => None }, variant_infos); } @@ -1622,7 +1622,7 @@ fn field(this: TyLayout<'tcx>, cx: C, i: usize) -> C::TyLayout { } // Discriminant field for enums (where applicable). - Variants::Tagged { ref discr, .. } | + Variants::Tagged { tag: ref discr, .. } | Variants::NicheFilling { niche: ref discr, .. } => { assert_eq!(i, 0); let layout = LayoutDetails::scalar(tcx, discr.clone()); @@ -1736,10 +1736,10 @@ fn hash_stable(&self, index.hash_stable(hcx, hasher); } Tagged { - ref discr, + ref tag, ref variants, } => { - discr.hash_stable(hcx, hasher); + tag.hash_stable(hcx, hasher); variants.hash_stable(hcx, hasher); } NicheFilling { diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index c74e42263ef..85533caffce 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -58,6 +58,17 @@ fn panic_hook(info: &panic::PanicInfo) { if backtrace { TyCtxt::try_print_query_stack(); } + + #[cfg(windows)] + unsafe { + if env::var("RUSTC_BREAK_ON_ICE").is_ok() { + extern "system" { + fn DebugBreak(); + } + // Trigger a debugger if we crashed during bootstrap + DebugBreak(); + } + } } } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index a01b3cbf47b..79baf0ec151 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { fn consume(&mut self, consume_id: ast::NodeId, consume_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) { debug!("consume(consume_id={}, cmt={:?}, mode={:?})", consume_id, cmt, mode); @@ -110,12 +110,12 @@ fn consume(&mut self, fn matched_pat(&mut self, _matched_pat: &hir::Pat, - _cmt: mc::cmt, + _cmt: &mc::cmt_, _mode: euv::MatchMode) { } fn consume_pat(&mut self, consume_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) { debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})", consume_pat, @@ -128,7 +128,7 @@ fn consume_pat(&mut self, fn borrow(&mut self, borrow_id: ast::NodeId, borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: euv::LoanCause) @@ -139,7 +139,7 @@ fn borrow(&mut self, bk, loan_cause); let hir_id = self.tcx().hir.node_to_hir_id(borrow_id); - if let Some(lp) = opt_loan_path(&cmt) { + if let Some(lp) = opt_loan_path(cmt) { let moved_value_use_kind = match loan_cause { euv::ClosureCapture(_) => MovedInCapture, _ => MovedInUse, @@ -155,13 +155,13 @@ fn borrow(&mut self, fn mutate(&mut self, assignment_id: ast::NodeId, assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>, + assignee_cmt: &mc::cmt_<'tcx>, mode: euv::MutateMode) { debug!("mutate(assignment_id={}, assignee_cmt={:?})", assignment_id, assignee_cmt); - if let Some(lp) = opt_loan_path(&assignee_cmt) { + if let Some(lp) = opt_loan_path(assignee_cmt) { match mode { MutateMode::Init | MutateMode::JustWrite => { // In a case like `path = 1`, then path does not @@ -363,10 +363,10 @@ pub fn loans_generated_by(&self, node: hir::ItemLocalId) -> Vec { } pub fn check_for_loans_across_yields(&self, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>, borrow_span: Span) { - pub fn borrow_of_local_data<'tcx>(cmt: &mc::cmt<'tcx>) -> bool { + pub fn borrow_of_local_data<'tcx>(cmt: &mc::cmt_<'tcx>) -> bool { match cmt.cat { // Borrows of static items is allowed Categorization::StaticItem => false, @@ -401,7 +401,7 @@ pub fn borrow_of_local_data<'tcx>(cmt: &mc::cmt<'tcx>) -> bool { return; } - if !borrow_of_local_data(&cmt) { + if !borrow_of_local_data(cmt) { return; } @@ -649,9 +649,9 @@ pub fn report_error_if_loan_conflicts_with_restriction(&self, fn consume_common(&self, id: hir::ItemLocalId, span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) { - if let Some(lp) = opt_loan_path(&cmt) { + if let Some(lp) = opt_loan_path(cmt) { let moved_value_use_kind = match mode { euv::Copy => { self.check_for_copy_of_frozen_path(id, span, &lp); @@ -876,11 +876,11 @@ fn check_if_assigned_path_is_moved(&self, fn check_assignment(&self, assignment_id: hir::ItemLocalId, assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>) { + assignee_cmt: &mc::cmt_<'tcx>) { debug!("check_assignment(assignee_cmt={:?})", assignee_cmt); // Check that we don't invalidate any outstanding loans - if let Some(loan_path) = opt_loan_path(&assignee_cmt) { + if let Some(loan_path) = opt_loan_path(assignee_cmt) { let scope = region::Scope::Node(assignment_id); self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| { self.report_illegal_mutation(assignment_span, &loan_path, loan); @@ -892,7 +892,7 @@ fn check_assignment(&self, // needs to be done here instead of in check_loans because we // depend on move data. if let Categorization::Local(local_id) = assignee_cmt.cat { - let lp = opt_loan_path(&assignee_cmt).unwrap(); + let lp = opt_loan_path(assignee_cmt).unwrap(); self.move_data.each_assignment_of(assignment_id, &lp, |assign| { if assignee_cmt.mutbl.is_mutable() { let hir_id = self.bccx.tcx.hir.node_to_hir_id(local_id); diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 465457f5ab3..ac905d6de5d 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -26,10 +26,10 @@ use rustc::hir::*; use rustc::hir::map::Node::*; -struct GatherMoveInfo<'tcx> { +struct GatherMoveInfo<'c, 'tcx: 'c> { id: hir::ItemLocalId, kind: MoveKind, - cmt: mc::cmt<'tcx>, + cmt: &'c mc::cmt_<'tcx>, span_path_opt: Option> } @@ -87,7 +87,7 @@ pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, move_data: &MoveData<'tcx>, move_error_collector: &mut MoveErrorCollector<'tcx>, move_expr_id: hir::ItemLocalId, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, move_reason: euv::MoveReason) { let kind = match move_reason { euv::DirectRefMove | euv::PatBindingMove => MoveExpr, @@ -102,11 +102,11 @@ pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, gather_move(bccx, move_data, move_error_collector, move_info); } -pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - move_data: &MoveData<'tcx>, - move_error_collector: &mut MoveErrorCollector<'tcx>, - move_pat: &hir::Pat, - cmt: mc::cmt<'tcx>) { +pub fn gather_move_from_pat<'a, 'c, 'tcx: 'c>(bccx: &BorrowckCtxt<'a, 'tcx>, + move_data: &MoveData<'tcx>, + move_error_collector: &mut MoveErrorCollector<'tcx>, + move_pat: &hir::Pat, + cmt: &'c mc::cmt_<'tcx>) { let source = get_pattern_source(bccx.tcx,move_pat); let pat_span_path_opt = match move_pat.node { PatKind::Binding(_, _, ref path1, _) => { @@ -132,18 +132,17 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, gather_move(bccx, move_data, move_error_collector, move_info); } -fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, +fn gather_move<'a, 'c, 'tcx: 'c>(bccx: &BorrowckCtxt<'a, 'tcx>, move_data: &MoveData<'tcx>, move_error_collector: &mut MoveErrorCollector<'tcx>, - move_info: GatherMoveInfo<'tcx>) { + move_info: GatherMoveInfo<'c, 'tcx>) { debug!("gather_move(move_id={:?}, cmt={:?})", move_info.id, move_info.cmt); - let potentially_illegal_move = - check_and_get_illegal_move_origin(bccx, &move_info.cmt); + let potentially_illegal_move = check_and_get_illegal_move_origin(bccx, move_info.cmt); if let Some(illegal_move_origin) = potentially_illegal_move { debug!("illegal_move_origin={:?}", illegal_move_origin); - let error = MoveError::with_move_info(illegal_move_origin, + let error = MoveError::with_move_info(Rc::new(illegal_move_origin), move_info.span_path_opt); move_error_collector.add_error(error); return; @@ -177,8 +176,8 @@ pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, // (keep in sync with move_error::report_cannot_move_out_of ) fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - cmt: &mc::cmt<'tcx>) - -> Option> { + cmt: &mc::cmt_<'tcx>) + -> Option> { match cmt.cat { Categorization::Deref(_, mc::BorrowedPtr(..)) | Categorization::Deref(_, mc::Implicit(..)) | diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 97fa94b5e5c..6d73500d318 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -27,7 +27,7 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, item_scope: region::Scope, span: Span, cause: euv::LoanCause, - cmt: mc::cmt<'tcx>, + cmt: &'a mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>, _: ty::BorrowKind) -> Result<(),()> { @@ -41,8 +41,8 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, span, cause, loan_region, - cmt_original: cmt.clone()}; - ctxt.check(&cmt, None) + cmt_original: cmt}; + ctxt.check(cmt, None) } /////////////////////////////////////////////////////////////////////////// @@ -57,12 +57,11 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { span: Span, cause: euv::LoanCause, loan_region: ty::Region<'tcx>, - cmt_original: mc::cmt<'tcx> + cmt_original: &'a mc::cmt_<'tcx> } impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { - - fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option) -> R { + fn check(&self, cmt: &mc::cmt_<'tcx>, discr_scope: Option) -> R { //! Main routine. Walks down `cmt` until we find the //! "guarantor". Reports an error if `self.loan_region` is //! larger than scope of `cmt`. @@ -102,7 +101,7 @@ fn check_scope(&self, max_scope: ty::Region<'tcx>) -> R { } } - fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> { + fn scope(&self, cmt: &mc::cmt_<'tcx>) -> ty::Region<'tcx> { //! Returns the maximal region scope for the which the //! place `cmt` is guaranteed to be valid without any //! rooting etc, and presuming `cmt` is not mutated. @@ -136,7 +135,7 @@ fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> { } fn report_error(&self, code: bckerr_code<'tcx>) { - self.bccx.report(BckError { cmt: self.cmt_original.clone(), + self.bccx.report(BckError { cmt: self.cmt_original, span: self.span, cause: BorrowViolation(self.cause), code: code }); diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 49234f4ed7f..a74eba39955 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -76,7 +76,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { fn consume(&mut self, consume_id: ast::NodeId, _consume_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) { debug!("consume(consume_id={}, cmt={:?}, mode={:?})", consume_id, cmt, mode); @@ -93,7 +93,7 @@ fn consume(&mut self, fn matched_pat(&mut self, matched_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::MatchMode) { debug!("matched_pat(matched_pat={:?}, cmt={:?}, mode={:?})", matched_pat, @@ -103,7 +103,7 @@ fn matched_pat(&mut self, fn consume_pat(&mut self, consume_pat: &hir::Pat, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) { debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})", consume_pat, @@ -123,7 +123,7 @@ fn consume_pat(&mut self, fn borrow(&mut self, borrow_id: ast::NodeId, borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: euv::LoanCause) @@ -144,7 +144,7 @@ fn borrow(&mut self, fn mutate(&mut self, assignment_id: ast::NodeId, assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>, + assignee_cmt: &mc::cmt_<'tcx>, mode: euv::MutateMode) { self.guarantee_assignment_valid(assignment_id, @@ -165,7 +165,7 @@ fn decl_without_init(&mut self, id: ast::NodeId, _span: Span) { fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, borrow_span: Span, loan_cause: AliasableViolationKind, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, req_kind: ty::BorrowKind) -> Result<(),()> { @@ -206,7 +206,7 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, borrow_span: Span, cause: AliasableViolationKind, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, req_kind: ty::BorrowKind) -> Result<(),()> { debug!("check_mutability(cause={:?} cmt={:?} req_kind={:?}", @@ -246,10 +246,10 @@ pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.bccx.tcx } fn guarantee_assignment_valid(&mut self, assignment_id: ast::NodeId, assignment_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::MutateMode) { - let opt_lp = opt_loan_path(&cmt); + let opt_lp = opt_loan_path(cmt); debug!("guarantee_assignment_valid(assignment_id={}, cmt={:?}) opt_lp={:?}", assignment_id, cmt, opt_lp); @@ -259,14 +259,14 @@ fn guarantee_assignment_valid(&mut self, } else { // Check that we don't allow assignments to non-mutable data. if check_mutability(self.bccx, assignment_span, MutabilityViolation, - cmt.clone(), ty::MutBorrow).is_err() { + cmt, ty::MutBorrow).is_err() { return; // reported an error, no sense in reporting more. } } // Check that we don't allow assignments to aliasable data if check_aliasability(self.bccx, assignment_span, MutabilityViolation, - cmt.clone(), ty::MutBorrow).is_err() { + cmt, ty::MutBorrow).is_err() { return; // reported an error, no sense in reporting more. } @@ -300,7 +300,7 @@ fn guarantee_assignment_valid(&mut self, fn guarantee_valid(&mut self, borrow_id: hir::ItemLocalId, borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, req_kind: ty::BorrowKind, loan_region: ty::Region<'tcx>, cause: euv::LoanCause) { @@ -320,28 +320,26 @@ fn guarantee_valid(&mut self, // Check that the lifetime of the borrow does not exceed // the lifetime of the data being borrowed. if lifetime::guarantee_lifetime(self.bccx, self.item_ub, - borrow_span, cause, cmt.clone(), loan_region, - req_kind).is_err() { + borrow_span, cause, cmt, loan_region, req_kind).is_err() { return; // reported an error, no sense in reporting more. } // Check that we don't allow mutable borrows of non-mutable data. if check_mutability(self.bccx, borrow_span, BorrowViolation(cause), - cmt.clone(), req_kind).is_err() { + cmt, req_kind).is_err() { return; // reported an error, no sense in reporting more. } // Check that we don't allow mutable borrows of aliasable data. if check_aliasability(self.bccx, borrow_span, BorrowViolation(cause), - cmt.clone(), req_kind).is_err() { + cmt, req_kind).is_err() { return; // reported an error, no sense in reporting more. } // Compute the restrictions that are required to enforce the // loan is safe. let restr = restrictions::compute_restrictions( - self.bccx, borrow_span, cause, - cmt.clone(), loan_region); + self.bccx, borrow_span, cause, &cmt, loan_region); debug!("guarantee_valid(): restrictions={:?}", restr); diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index e3adb51433b..0b90127cc7e 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -30,7 +30,7 @@ pub enum RestrictionResult<'tcx> { pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, span: Span, cause: euv::LoanCause, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, loan_region: ty::Region<'tcx>) -> RestrictionResult<'tcx> { let ctxt = RestrictionsContext { @@ -55,7 +55,7 @@ struct RestrictionsContext<'a, 'tcx: 'a> { impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { fn restrict(&self, - cmt: mc::cmt<'tcx>) -> RestrictionResult<'tcx> { + cmt: &mc::cmt_<'tcx>) -> RestrictionResult<'tcx> { debug!("restrict(cmt={:?})", cmt); let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty)); @@ -86,7 +86,7 @@ fn restrict(&self, // When we borrow the interior of an enum, we have to // ensure the enum itself is not mutated, because that // could cause the type of the memory to change. - self.restrict(cmt_base) + self.restrict(&cmt_base) } Categorization::Interior(cmt_base, interior) => { @@ -101,7 +101,7 @@ fn restrict(&self, }; let interior = interior.cleaned(); let base_ty = cmt_base.ty; - let result = self.restrict(cmt_base); + let result = self.restrict(&cmt_base); // Borrowing one union field automatically borrows all its fields. match base_ty.sty { ty::TyAdt(adt_def, _) if adt_def.is_union() => match result { @@ -145,7 +145,7 @@ fn restrict(&self, // // Eventually we should make these non-special and // just rely on Deref implementation. - let result = self.restrict(cmt_base); + let result = self.restrict(&cmt_base); self.extend(result, &cmt, LpDeref(pk)) } mc::Implicit(bk, lt) | mc::BorrowedPtr(bk, lt) => { @@ -155,7 +155,7 @@ fn restrict(&self, BckError { span: self.span, cause: BorrowViolation(self.cause), - cmt: cmt_base, + cmt: &cmt_base, code: err_borrowed_pointer_too_short( self.loan_region, lt)}); return RestrictionResult::Safe; @@ -169,7 +169,7 @@ fn restrict(&self, // The referent can be aliased after the // references lifetime ends (by a newly-unfrozen // borrow). - let result = self.restrict(cmt_base); + let result = self.restrict(&cmt_base); self.extend(result, &cmt, LpDeref(pk)) } } @@ -183,7 +183,7 @@ fn restrict(&self, fn extend(&self, result: RestrictionResult<'tcx>, - cmt: &mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, elem: LoanPathElem<'tcx>) -> RestrictionResult<'tcx> { match result { RestrictionResult::Safe => RestrictionResult::Safe, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 519dd574e5a..9d0d8c2f909 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -500,7 +500,7 @@ fn common(&self, other: &LoanPath<'tcx>) -> Option> { // Avoid "cannot borrow immutable field `self.x` as mutable" as that implies that a field *can* be // mutable independently of the struct it belongs to. (#35937) -pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt<'tcx>) -> (Option>>, bool) { +pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt_<'tcx>) -> (Option>>, bool) { let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty)); match cmt.cat { @@ -548,7 +548,7 @@ pub fn opt_loan_path_is_field<'tcx>(cmt: &mc::cmt<'tcx>) -> (Option(cmt: &mc::cmt<'tcx>) -> Option>> { +pub fn opt_loan_path<'tcx>(cmt: &mc::cmt_<'tcx>) -> Option>> { opt_loan_path_is_field(cmt).0 } @@ -567,10 +567,10 @@ pub enum bckerr_code<'tcx> { // Combination of an error code and the categorization of the expression // that caused it #[derive(Debug, PartialEq)] -pub struct BckError<'tcx> { +pub struct BckError<'c, 'tcx: 'c> { span: Span, cause: AliasableViolationKind, - cmt: mc::cmt<'tcx>, + cmt: &'c mc::cmt_<'tcx>, code: bckerr_code<'tcx> } @@ -602,7 +602,7 @@ pub fn is_subregion_of(&self, region_rels.is_subregion_of(r_sub, r_sup) } - pub fn report(&self, err: BckError<'tcx>) { + pub fn report(&self, err: BckError<'a, 'tcx>) { // Catch and handle some particular cases. match (&err.code, &err.cause) { (&err_out_of_scope(&ty::ReScope(_), &ty::ReStatic, _), @@ -803,7 +803,7 @@ pub fn span_err_with_code>( self.tcx.sess.span_err_with_code(s, msg, code); } - fn report_bckerr(&self, err: &BckError<'tcx>) { + fn report_bckerr(&self, err: &BckError<'a, 'tcx>) { let error_span = err.span.clone(); match err.code { @@ -1014,7 +1014,7 @@ fn report_bckerr(&self, err: &BckError<'tcx>) { db.emit(); } err_borrowed_pointer_too_short(loan_scope, ptr_scope) => { - let descr = self.cmt_to_path_or_string(&err.cmt); + let descr = self.cmt_to_path_or_string(err.cmt); let mut db = self.lifetime_too_short_for_reborrow(error_span, &descr, Origin::Ast); let descr = match opt_loan_path(&err.cmt) { Some(lp) => { @@ -1045,7 +1045,7 @@ pub fn report_aliasability_violation(&self, span: Span, kind: AliasableViolationKind, cause: mc::AliasableReason, - cmt: mc::cmt<'tcx>) { + cmt: &mc::cmt_<'tcx>) { let mut is_closure = false; let prefix = match kind { MutabilityViolation => { @@ -1243,7 +1243,7 @@ fn note_immutability_blame(&self, } fn report_out_of_scope_escaping_closure_capture(&self, - err: &BckError<'tcx>, + err: &BckError<'a, 'tcx>, capture_span: Span) { let cmt_path_or_string = self.cmt_to_path_or_string(&err.cmt); @@ -1277,18 +1277,18 @@ fn region_end_span(&self, region: ty::Region<'tcx>) -> Option { } } - fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'tcx>, + fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'a, 'tcx>, error_span: &Span) { match err.cmt.note { mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => { // If this is an `Fn` closure, it simply can't mutate upvars. // If it's an `FnMut` closure, the original variable was declared immutable. // We need to determine which is the case here. - let kind = match err.cmt.upvar().unwrap().cat { + let kind = match err.cmt.upvar_cat().unwrap() { Categorization::Upvar(mc::Upvar { kind, .. }) => kind, _ => bug!() }; - if kind == ty::ClosureKind::Fn { + if *kind == ty::ClosureKind::Fn { let closure_node_id = self.tcx.hir.local_def_id_to_node_id(upvar_id.closure_expr_id); db.span_help(self.tcx.hir.span(closure_node_id), @@ -1392,7 +1392,7 @@ pub fn cmt_to_string(&self, cmt: &mc::cmt_<'tcx>) -> String { cmt.descriptive_string(self.tcx) } - pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt<'tcx>) -> String { + pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt_<'tcx>) -> String { match opt_loan_path(cmt) { Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)), None => self.cmt_to_string(cmt), diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f06062fa4ac..7ae13c803dd 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -46,7 +46,7 @@ use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes}; use syntax_pos::{BytePos, Span, SyntaxContext}; use syntax::symbol::keywords; -use syntax::errors::DiagnosticBuilder; +use syntax::errors::{Applicability, DiagnosticBuilder}; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::FnKind; @@ -1300,7 +1300,19 @@ fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId, } else { "pub(crate)" }.to_owned(); - err.span_suggestion(pub_span, "consider restricting its visibility", replacement); + let app = if span.ctxt().outer().expn_info().is_none() { + // even if macros aren't involved the suggestion + // may be incorrect -- the user may have mistakenly + // hidden it behind a private module and this lint is + // a helpful way to catch that. However, we're trying + // not to change the nature of the code with this lint + // so it's marked as machine applicable. + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + err.span_suggestion_with_applicability(pub_span, "consider restricting its visibility", + replacement, app); if exportable { err.help("or consider exporting it for use by other crates"); } @@ -1508,3 +1520,66 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { } } } + +declare_lint! { + pub UNNECESSARY_EXTERN_CRATE, + Allow, + "suggest removing `extern crate` for the 2018 edition" +} + +pub struct ExternCrate(/* depth */ u32); + +impl ExternCrate { + pub fn new() -> Self { + ExternCrate(0) + } +} + +impl LintPass for ExternCrate { + fn get_lints(&self) -> LintArray { + lint_array!(UNNECESSARY_EXTERN_CRATE) + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + if let hir::ItemExternCrate(ref orig) = it.node { + if it.attrs.iter().any(|a| a.check_name("macro_use")) { + return + } + let mut err = cx.struct_span_lint(UNNECESSARY_EXTERN_CRATE, + it.span, "`extern crate` is unnecessary in the new edition"); + if it.vis == hir::Visibility::Public || self.0 > 1 || orig.is_some() { + let pub_ = if it.vis == hir::Visibility::Public { + "pub " + } else { + "" + }; + + let help = format!("use `{}use`", pub_); + + if let Some(orig) = orig { + err.span_suggestion(it.span, &help, + format!("{}use {} as {}", pub_, orig, it.name)); + } else { + err.span_suggestion(it.span, &help, + format!("{}use {}", pub_, it.name)); + } + } else { + err.span_suggestion(it.span, "remove it", "".into()); + } + + err.emit(); + } + } + + fn check_mod(&mut self, _: &LateContext, _: &hir::Mod, + _: Span, _: ast::NodeId) { + self.0 += 1; + } + + fn check_mod_post(&mut self, _: &LateContext, _: &hir::Mod, + _: Span, _: ast::NodeId) { + self.0 += 1; + } +} diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 4f6d23dce6d..4403e1e3358 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -143,6 +143,7 @@ macro_rules! add_lint_group { TypeLimits, MissingDoc, MissingDebugImplementations, + ExternCrate, ); add_lint_group!(sess, @@ -178,9 +179,10 @@ macro_rules! add_lint_group { UNUSED_PARENS); add_lint_group!(sess, - "rust_2018_idioms", + "rust_2018_migration", BARE_TRAIT_OBJECT, - UNREACHABLE_PUB); + UNREACHABLE_PUB, + UNNECESSARY_EXTERN_CRATE); // Guidelines for creating a future incompatibility lint: // diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 904a3e4c427..9e0dc4d80c8 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -820,8 +820,8 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { bug!("failed to get layout for `{}`: {}", t, e) }); - if let layout::Variants::Tagged { ref variants, ref discr, .. } = layout.variants { - let discr_size = discr.value.size(cx.tcx).bytes(); + if let layout::Variants::Tagged { ref variants, ref tag, .. } = layout.variants { + let discr_size = tag.value.size(cx.tcx).bytes(); debug!("enum `{}` is {} bytes large with layout:\n{:#?}", t, layout.size.bytes(), layout); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 8df40b62ddd..845c964b986 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -135,12 +135,12 @@ fn check_must_use(cx: &LateContext, def_id: DefId, sp: Span, describe_path: &str if attr.check_name("must_use") { let mut msg = format!("unused {}`{}` which must be used", describe_path, cx.tcx.item_path_str(def_id)); - // check for #[must_use="..."] - if let Some(s) = attr.value_str() { - msg.push_str(": "); - msg.push_str(&s.as_str()); + let mut err = cx.struct_span_lint(UNUSED_MUST_USE, sp, &msg); + // check for #[must_use = "..."] + if let Some(note) = attr.value_str() { + err.note(¬e.as_str()); } - cx.span_lint(UNUSED_MUST_USE, sp, &msg); + err.emit(); return true; } } diff --git a/src/librustc_mir/borrow_check/location.rs b/src/librustc_mir/borrow_check/location.rs new file mode 100644 index 00000000000..28da1b2d733 --- /dev/null +++ b/src/librustc_mir/borrow_check/location.rs @@ -0,0 +1,123 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::mir::{BasicBlock, Location, Mir}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; + +/// Maps between a MIR Location, which identifies the a particular +/// statement within a basic block, to a "rich location", which +/// identifies at a finer granularity. In particular, we distinguish +/// the *start* of a statement and the *mid-point*. The mid-point is +/// the point *just* before the statement takes effect; in particular, +/// for an assignment `A = B`, it is the point where B is about to be +/// written into A. This mid-point is a kind of hack to work around +/// our inability to track the position information at sufficient +/// granularity through outlives relations; however, the rich location +/// table serves another purpose: it compresses locations from +/// multiple words into a single u32. +crate struct LocationTable { + num_points: usize, + statements_before_block: IndexVec, +} + +newtype_index!(LocationIndex { DEBUG_FORMAT = "LocationIndex({})" }); + +#[derive(Copy, Clone, Debug)] +crate enum RichLocation { + Start(Location), + Mid(Location), +} + +impl LocationTable { + crate fn new(mir: &Mir<'_>) -> Self { + let mut num_points = 0; + let statements_before_block = mir.basic_blocks() + .iter() + .map(|block_data| { + let v = num_points; + num_points += (block_data.statements.len() + 1) * 2; + v + }) + .collect(); + + debug!( + "LocationTable(statements_before_block={:#?})", + statements_before_block + ); + debug!("LocationTable: num_points={:#?}", num_points); + + Self { + num_points, + statements_before_block, + } + } + + crate fn all_points(&self) -> impl Iterator { + (0..self.num_points).map(LocationIndex::new) + } + + crate fn start_index(&self, location: Location) -> LocationIndex { + let Location { + block, + statement_index, + } = location; + let start_index = self.statements_before_block[block]; + LocationIndex::new(start_index + statement_index * 2) + } + + crate fn mid_index(&self, location: Location) -> LocationIndex { + let Location { + block, + statement_index, + } = location; + let start_index = self.statements_before_block[block]; + LocationIndex::new(start_index + statement_index * 2 + 1) + } + + crate fn to_location(&self, index: LocationIndex) -> RichLocation { + let point_index = index.index(); + + // Find the basic block. We have a vector with the + // starting index of the statement in each block. Imagine + // we have statement #22, and we have a vector like: + // + // [0, 10, 20] + // + // In that case, this represents point_index 2 of + // basic block BB2. We know this because BB0 accounts for + // 0..10, BB1 accounts for 11..20, and BB2 accounts for + // 20... + // + // To compute this, we could do a binary search, but + // because I am lazy we instead iterate through to find + // the last point where the "first index" (0, 10, or 20) + // was less than the statement index (22). In our case, this will + // be (BB2, 20). + let (block, &first_index) = self.statements_before_block + .iter_enumerated() + .filter(|(_, first_index)| **first_index <= point_index) + .last() + .unwrap(); + + let statement_index = (point_index - first_index) / 2; + if index.is_start() { + RichLocation::Start(Location { block, statement_index }) + } else { + RichLocation::Mid(Location { block, statement_index }) + } + } +} + +impl LocationIndex { + fn is_start(&self) -> bool { + // even indices are start points; odd indices are mid points + (self.index() % 2) == 0 + } +} diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c619f350f58..3e3f510e308 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -50,12 +50,14 @@ use self::borrow_set::{BorrowSet, BorrowData}; use self::flows::Flows; +use self::location::LocationTable; use self::prefixes::PrefixSet; use self::MutateMode::{JustWrite, WriteAndRead}; crate mod borrow_set; mod error_reporting; mod flows; +mod location; crate mod place_ext; mod prefixes; @@ -110,6 +112,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( let mut mir: Mir<'tcx> = input_mir.clone(); let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut mir); let mir = &mir; // no further changes + let location_table = &LocationTable::new(mir); let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) { Ok(move_data) => move_data, @@ -199,6 +202,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( def_id, free_regions, mir, + location_table, param_env, &mut flow_inits, &mdpe.move_data, diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index afaedecdf0a..d34e9434fbf 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -8,28 +8,37 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use borrow_check::borrow_set::BorrowSet; +use borrow_check::location::LocationTable; +use borrow_check::nll::facts::AllFacts; use rustc::hir; -use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue}; +use rustc::infer::InferCtxt; +use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; use rustc::mir::Place::Projection; -use rustc::mir::{Local, PlaceProjection, ProjectionElem}; -use rustc::mir::visit::TyContext; -use rustc::infer::InferCtxt; -use rustc::ty::{self, CanonicalTy, ClosureSubsts}; -use rustc::ty::subst::Substs; +use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue}; +use rustc::mir::{Local, PlaceProjection, ProjectionElem, Statement, Terminator}; use rustc::ty::fold::TypeFoldable; +use rustc::ty::subst::Substs; +use rustc::ty::{self, CanonicalTy, ClosureSubsts}; +use super::region_infer::{Cause, RegionInferenceContext}; use super::ToRegionVid; -use super::region_infer::{RegionInferenceContext, Cause}; pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( infcx: &InferCtxt<'cx, 'gcx, 'tcx>, regioncx: &mut RegionInferenceContext<'tcx>, + all_facts: &mut Option, + location_table: &LocationTable, mir: &Mir<'tcx>, + borrow_set: &BorrowSet<'tcx>, ) { let mut cg = ConstraintGeneration { + borrow_set, infcx, regioncx, + location_table, + all_facts, mir, }; @@ -41,8 +50,11 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( /// 'cg = the duration of the constraint generation process itself. struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> { infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>, + all_facts: &'cg mut Option, + location_table: &'cg LocationTable, regioncx: &'cg mut RegionInferenceContext<'tcx>, mir: &'cg Mir<'tcx>, + borrow_set: &'cg BorrowSet<'tcx>, } impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> { @@ -68,12 +80,14 @@ fn visit_region(&mut self, region: &ty::Region<'tcx>, location: Location) { /// call. Make them live at the location where they appear. fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) { match ty_context { - TyContext::ReturnTy(source_info) | - TyContext::YieldTy(source_info) | - TyContext::LocalDecl { source_info, .. } => { - span_bug!(source_info.span, - "should not be visiting outside of the CFG: {:?}", - ty_context); + TyContext::ReturnTy(source_info) + | TyContext::YieldTy(source_info) + | TyContext::LocalDecl { source_info, .. } => { + span_bug!( + source_info.span, + "should not be visiting outside of the CFG: {:?}", + ty_context + ); } TyContext::Location(location) => { self.add_regular_live_constraint(*ty, location, Cause::LiveOther(location)); @@ -90,25 +104,117 @@ fn visit_closure_substs(&mut self, substs: &ClosureSubsts<'tcx>, location: Locat self.super_closure_substs(substs); } + fn visit_statement( + &mut self, + block: BasicBlock, + statement: &Statement<'tcx>, + location: Location, + ) { + if let Some(all_facts) = self.all_facts { + all_facts.cfg_edge.push(( + self.location_table.start_index(location), + self.location_table.mid_index(location), + )); + + all_facts.cfg_edge.push(( + self.location_table.mid_index(location), + self.location_table + .start_index(location.successor_within_block()), + )); + } + + self.super_statement(block, statement, location); + } + + fn visit_assign( + &mut self, + block: BasicBlock, + place: &Place<'tcx>, + rvalue: &Rvalue<'tcx>, + location: Location, + ) { + // When we see `X = ...`, then kill borrows of + // `(*X).foo` and so forth. + if let Some(all_facts) = self.all_facts { + if let Place::Local(temp) = place { + if let Some(borrow_indices) = self.borrow_set.local_map.get(temp) { + for &borrow_index in borrow_indices { + let location_index = self.location_table.mid_index(location); + all_facts.killed.push((borrow_index, location_index)); + } + } + } + } + + self.super_assign(block, place, rvalue, location); + } + + fn visit_terminator( + &mut self, + block: BasicBlock, + terminator: &Terminator<'tcx>, + location: Location, + ) { + if let Some(all_facts) = self.all_facts { + all_facts.cfg_edge.push(( + self.location_table.start_index(location), + self.location_table.mid_index(location), + )); + + for successor_block in terminator.successors() { + all_facts.cfg_edge.push(( + self.location_table.mid_index(location), + self.location_table + .start_index(successor_block.start_location()), + )); + } + } + + self.super_terminator(block, terminator, location); + } + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { debug!("visit_rvalue(rvalue={:?}, location={:?})", rvalue, location); - // Look for an rvalue like: - // - // & L - // - // where L is the path that is borrowed. In that case, we have - // to add the reborrow constraints (which don't fall out - // naturally from the type-checker). - if let Rvalue::Ref(region, _bk, ref borrowed_lv) = *rvalue { - self.add_reborrow_constraint(location, region, borrowed_lv); + match rvalue { + Rvalue::Ref(region, _borrow_kind, borrowed_place) => { + // In some cases, e.g. when borrowing from an unsafe + // place, we don't bother to create a loan, since + // there are no conditions to validate. + if let Some(all_facts) = self.all_facts { + if let Some(borrow_index) = self.borrow_set.location_map.get(&location) { + let region_vid = region.to_region_vid(); + all_facts.borrow_region.push(( + region_vid, + *borrow_index, + self.location_table.mid_index(location), + )); + } + } + + // Look for an rvalue like: + // + // & L + // + // where L is the path that is borrowed. In that case, we have + // to add the reborrow constraints (which don't fall out + // naturally from the type-checker). + self.add_reborrow_constraint(location, region, borrowed_place); + } + + _ => { } } self.super_rvalue(rvalue, location); } - fn visit_user_assert_ty(&mut self, _c_ty: &CanonicalTy<'tcx>, - _local: &Local, _location: Location) { } + fn visit_user_assert_ty( + &mut self, + _c_ty: &CanonicalTy<'tcx>, + _local: &Local, + _location: Location, + ) { + } } impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> { @@ -122,8 +228,7 @@ fn add_regular_live_constraint(&mut self, live_ty: T, location: Location, cau { debug!( "add_regular_live_constraint(live_ty={:?}, location={:?})", - live_ty, - location + live_ty, location ); self.infcx @@ -144,8 +249,10 @@ fn add_reborrow_constraint( ) { let mut borrowed_place = borrowed_place; - debug!("add_reborrow_constraint({:?}, {:?}, {:?})", - location, borrow_region, borrowed_place); + debug!( + "add_reborrow_constraint({:?}, {:?}, {:?})", + location, borrow_region, borrowed_place + ); while let Projection(box PlaceProjection { base, elem }) = borrowed_place { debug!("add_reborrow_constraint - iteration {:?}", borrowed_place); @@ -165,12 +272,20 @@ fn add_reborrow_constraint( location.successor_within_block(), ); + if let Some(all_facts) = self.all_facts { + all_facts.outlives.push(( + ref_region.to_region_vid(), + borrow_region.to_region_vid(), + self.location_table.mid_index(location), + )); + } + match mutbl { hir::Mutability::MutImmutable => { // Immutable reference. We don't need the base // to be valid for the entire lifetime of // the borrow. - break + break; } hir::Mutability::MutMutable => { // Mutable reference. We *do* need the base @@ -199,19 +314,19 @@ fn add_reborrow_constraint( } ty::TyRawPtr(..) => { // deref of raw pointer, guaranteed to be valid - break + break; } ty::TyAdt(def, _) if def.is_box() => { // deref of `Box`, need the base to be valid - propagate } - _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place) + _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place), } } - ProjectionElem::Field(..) | - ProjectionElem::Downcast(..) | - ProjectionElem::Index(..) | - ProjectionElem::ConstantIndex { .. } | - ProjectionElem::Subslice { .. } => { + ProjectionElem::Field(..) + | ProjectionElem::Downcast(..) + | ProjectionElem::Index(..) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } => { // other field access } } diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/nll/facts.rs new file mode 100644 index 00000000000..2802aa0dff4 --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/facts.rs @@ -0,0 +1,194 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use borrow_check::location::{LocationIndex, LocationTable}; +use dataflow::indexes::BorrowIndex; +use rustc::ty::RegionVid; +use std::error::Error; +use std::fmt::Debug; +use std::fs::{self, File}; +use std::io::Write; +use std::path::Path; + +/// The "facts" which are the basis of the NLL borrow analysis. +#[derive(Default)] +crate struct AllFacts { + // `borrow_region(R, B, P)` -- the region R may refer to data from borrow B + // starting at the point P (this is usually the point *after* a borrow rvalue) + crate borrow_region: Vec<(RegionVid, BorrowIndex, LocationIndex)>, + + // universal_region(R) -- this is a "free region" within fn body + crate universal_region: Vec, + + // `cfg_edge(P,Q)` for each edge P -> Q in the control flow + crate cfg_edge: Vec<(LocationIndex, LocationIndex)>, + + // `killed(B,P)` when some prefix of the path borrowed at B is assigned at point P + crate killed: Vec<(BorrowIndex, LocationIndex)>, + + // `outlives(R1, R2, P)` when we require `R1@P: R2@P` + crate outlives: Vec<(RegionVid, RegionVid, LocationIndex)>, + + // `region_live_at(R, P)` when the region R appears in a live variable at P + crate region_live_at: Vec<(RegionVid, LocationIndex)>, +} + +impl AllFacts { + crate fn write_to_dir( + &self, + dir: impl AsRef, + location_table: &LocationTable, + ) -> Result<(), Box> { + let dir: &Path = dir.as_ref(); + fs::create_dir_all(dir)?; + let wr = FactWriter { location_table, dir }; + macro_rules! write_facts_to_path { + ($wr:ident . write_facts_to_path($this:ident . [ + $($field:ident,)* + ])) => { + $( + $wr.write_facts_to_path( + &$this.$field, + &format!("{}.facts", stringify!($field)) + )?; + )* + } + } + write_facts_to_path! { + wr.write_facts_to_path(self.[ + borrow_region, + universal_region, + cfg_edge, + killed, + outlives, + region_live_at, + ]) + } + Ok(()) + } +} + +struct FactWriter<'w> { + location_table: &'w LocationTable, + dir: &'w Path, +} + +impl<'w> FactWriter<'w> { + fn write_facts_to_path( + &self, + rows: &Vec, + file_name: &str, + ) -> Result<(), Box> + where + T: FactRow, + { + let file = &self.dir.join(file_name); + let mut file = File::create(file)?; + for row in rows { + row.write(&mut file, self.location_table)?; + } + Ok(()) + } +} + +trait FactRow { + fn write( + &self, + out: &mut File, + location_table: &LocationTable, + ) -> Result<(), Box>; +} + +impl FactRow for RegionVid { + fn write( + &self, + out: &mut File, + location_table: &LocationTable, + ) -> Result<(), Box> { + write_row(out, location_table, &[self]) + } +} + +impl FactRow for (A, B) +where + A: FactCell, + B: FactCell, +{ + fn write( + &self, + out: &mut File, + location_table: &LocationTable, + ) -> Result<(), Box> { + write_row(out, location_table, &[&self.0, &self.1]) + } +} + +impl FactRow for (A, B, C) +where + A: FactCell, + B: FactCell, + C: FactCell, +{ + fn write( + &self, + out: &mut File, + location_table: &LocationTable, + ) -> Result<(), Box> { + write_row(out, location_table, &[&self.0, &self.1, &self.2]) + } +} + +impl FactRow for (A, B, C, D) +where + A: FactCell, + B: FactCell, + C: FactCell, + D: FactCell, +{ + fn write( + &self, + out: &mut File, + location_table: &LocationTable, + ) -> Result<(), Box> { + write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3]) + } +} + +fn write_row( + out: &mut dyn Write, + location_table: &LocationTable, + columns: &[&dyn FactCell], +) -> Result<(), Box> { + for (index, c) in columns.iter().enumerate() { + let tail = if index == columns.len() - 1 { + "\n" + } else { + "\t" + }; + write!(out, "{:?}{}", c.to_string(location_table), tail)?; + } + Ok(()) +} + +trait FactCell { + fn to_string(&self, location_table: &LocationTable) -> String; +} + +impl FactCell for A { + default fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{:?}", self) + } +} + +impl FactCell for LocationIndex { + fn to_string(&self, location_table: &LocationTable) -> String { + format!("{:?}", location_table.to_location(*self)) + } +} diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 3ca1bd23e86..0b1729294d8 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -9,36 +9,39 @@ // except according to those terms. use borrow_check::borrow_set::BorrowSet; +use borrow_check::location::LocationTable; +use dataflow::move_paths::MoveData; +use dataflow::FlowAtLocation; +use dataflow::MaybeInitializedPlaces; use rustc::hir::def_id::DefId; -use rustc::mir::{ClosureRegionRequirements, ClosureOutlivesSubject, Mir}; use rustc::infer::InferCtxt; +use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir}; use rustc::ty::{self, RegionKind, RegionVid}; use rustc::util::nodemap::FxHashMap; use std::collections::BTreeSet; use std::fmt::Debug; use std::io; +use std::path::PathBuf; use transform::MirSource; use util::liveness::{LivenessResults, LocalSet}; -use dataflow::FlowAtLocation; -use dataflow::MaybeInitializedPlaces; -use dataflow::move_paths::MoveData; +use self::mir_util::PassWhere; use util as mir_util; use util::pretty::{self, ALIGN}; -use self::mir_util::PassWhere; mod constraint_generation; pub mod explain_borrow; -pub(crate) mod region_infer; +mod facts; +crate mod region_infer; mod renumber; mod subtype_constraint_generation; -pub(crate) mod type_check; +crate mod type_check; mod universal_regions; +use self::facts::AllFacts; use self::region_infer::RegionInferenceContext; use self::universal_regions::UniversalRegions; - /// Rewrites the regions in the MIR to use NLL variables, also /// scraping out the set of universal regions (e.g., region parameters) /// declared on the function. That set will need to be given to @@ -71,10 +74,11 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( def_id: DefId, universal_regions: UniversalRegions<'tcx>, mir: &Mir<'tcx>, + location_table: &LocationTable, param_env: ty::ParamEnv<'gcx>, flow_inits: &mut FlowAtLocation>, move_data: &MoveData<'tcx>, - _borrow_set: &BorrowSet<'tcx>, + borrow_set: &BorrowSet<'tcx>, ) -> ( RegionInferenceContext<'tcx>, Option>, @@ -92,15 +96,47 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( move_data, ); + let mut all_facts = if infcx.tcx.sess.opts.debugging_opts.nll_facts { + Some(AllFacts::default()) + } else { + None + }; + + if let Some(all_facts) = &mut all_facts { + all_facts + .universal_region + .extend(universal_regions.universal_regions()); + } + // Create the region inference context, taking ownership of the region inference // data that was contained in `infcx`. let var_origins = infcx.take_region_var_origins(); - let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir); - subtype_constraint_generation::generate(&mut regioncx, mir, constraint_sets); - + let mut regioncx = + RegionInferenceContext::new(var_origins, universal_regions, mir); + + // Generate various constraints. + subtype_constraint_generation::generate( + &mut regioncx, + &mut all_facts, + location_table, + mir, + constraint_sets, + ); + constraint_generation::generate_constraints( + infcx, + &mut regioncx, + &mut all_facts, + location_table, + &mir, + borrow_set, + ); - // Generate non-subtyping constraints. - constraint_generation::generate_constraints(infcx, &mut regioncx, &mir); + // Dump facts if requested. + if let Some(all_facts) = all_facts { + let def_path = infcx.tcx.hir.def_path(def_id); + let dir_path = PathBuf::from("nll-facts").join(def_path.to_filename_friendly_no_crate()); + all_facts.write_to_dir(dir_path, location_table).unwrap(); + } // Solve the region constraints. let closure_region_requirements = regioncx.solve(infcx, &mir, def_id); diff --git a/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs b/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs index 32728145b29..9db19085a39 100644 --- a/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs @@ -8,14 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::mir::Mir; +use borrow_check::location::LocationTable; +use borrow_check::nll::facts::AllFacts; use rustc::infer::region_constraints::Constraint; use rustc::infer::region_constraints::RegionConstraintData; use rustc::infer::region_constraints::{Verify, VerifyBound}; +use rustc::mir::{Location, Mir}; use rustc::ty; +use std::iter; use syntax::codemap::Span; -use super::region_infer::{TypeTest, RegionInferenceContext, RegionTest}; +use super::region_infer::{RegionInferenceContext, RegionTest, TypeTest}; use super::type_check::Locations; use super::type_check::MirTypeckRegionConstraints; use super::type_check::OutlivesSet; @@ -27,19 +30,30 @@ /// them into the NLL `RegionInferenceContext`. pub(super) fn generate<'tcx>( regioncx: &mut RegionInferenceContext<'tcx>, + all_facts: &mut Option, + location_table: &LocationTable, mir: &Mir<'tcx>, constraints: &MirTypeckRegionConstraints<'tcx>, ) { - SubtypeConstraintGenerator { regioncx, mir }.generate(constraints); + SubtypeConstraintGenerator { + regioncx, + location_table, + mir, + }.generate(constraints, all_facts); } struct SubtypeConstraintGenerator<'cx, 'tcx: 'cx> { regioncx: &'cx mut RegionInferenceContext<'tcx>, + location_table: &'cx LocationTable, mir: &'cx Mir<'tcx>, } impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> { - fn generate(&mut self, constraints: &MirTypeckRegionConstraints<'tcx>) { + fn generate( + &mut self, + constraints: &MirTypeckRegionConstraints<'tcx>, + all_facts: &mut Option, + ) { let MirTypeckRegionConstraints { liveness_set, outlives_sets, @@ -57,6 +71,17 @@ fn generate(&mut self, constraints: &MirTypeckRegionConstraints<'tcx>) { self.regioncx.add_live_point(region_vid, *location, &cause); } + if let Some(all_facts) = all_facts { + all_facts + .region_live_at + .extend(liveness_set.into_iter().flat_map(|(region, location, _)| { + let r = self.to_region_vid(region); + let p1 = self.location_table.start_index(*location); + let p2 = self.location_table.mid_index(*location); + iter::once((r, p1)).chain(iter::once((r, p2))) + })); + } + for OutlivesSet { locations, data } in outlives_sets { debug!("generate: constraints at: {:#?}", locations); let RegionConstraintData { @@ -65,7 +90,11 @@ fn generate(&mut self, constraints: &MirTypeckRegionConstraints<'tcx>) { givens, } = data; - let span = self.mir.source_info(locations.from_location).span; + let span = self.mir + .source_info(locations.from_location().unwrap_or(Location::START)) + .span; + + let at_location = locations.at_location().unwrap_or(Location::START); for constraint in constraints.keys() { debug!("generate: constraint: {:?}", constraint); @@ -83,8 +112,24 @@ fn generate(&mut self, constraints: &MirTypeckRegionConstraints<'tcx>) { // reverse direction, because `regioncx` talks about // "outlives" (`>=`) whereas the region constraints // talk about `<=`. - self.regioncx - .add_outlives(span, b_vid, a_vid, locations.at_location); + self.regioncx.add_outlives(span, b_vid, a_vid, at_location); + + // In the new analysis, all outlives relations etc + // "take effect" at the mid point of the statement + // that requires them, so ignore the `at_location`. + if let Some(all_facts) = all_facts { + if let Some(from_location) = locations.from_location() { + all_facts.outlives.push(( + b_vid, + a_vid, + self.location_table.mid_index(from_location), + )); + } else { + for location in self.location_table.all_points() { + all_facts.outlives.push((b_vid, a_vid, location)); + } + } + } } for verify in verifys { @@ -109,7 +154,7 @@ fn verify_to_type_test( let lower_bound = self.to_region_vid(verify.region); - let point = locations.at_location; + let point = locations.at_location().unwrap_or(Location::START); let test = self.verify_bound_to_region_test(&verify.bound); @@ -149,14 +194,6 @@ fn verify_bound_to_region_test(&self, verify_bound: &VerifyBound<'tcx>) -> Regio } fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid { - // Every region that we see in the constraints came from the - // MIR or from the parameter environment. If the former, it - // will be a region variable. If the latter, it will be in - // the set of universal regions *somewhere*. - if let ty::ReVar(vid) = r { - *vid - } else { - self.regioncx.to_region_vid(r) - } + self.regioncx.to_region_vid(r) } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index b1aeae0b76b..2b1878c33e9 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -29,7 +29,7 @@ use rustc_data_structures::indexed_vec::Idx; -use super::{AtLocation, TypeChecker}; +use super::{Locations, TypeChecker}; impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { pub(super) fn equate_inputs_and_outputs( @@ -47,26 +47,21 @@ pub(super) fn equate_inputs_and_outputs( } = universal_regions; let infcx = self.infcx; - let start_position = Location { - block: START_BLOCK, - statement_index: 0, - }; - // Equate expected input tys with those in the MIR. let argument_locals = (1..).map(Local::new); for (&unnormalized_input_ty, local) in unnormalized_input_tys.iter().zip(argument_locals) { - let input_ty = self.normalize(&unnormalized_input_ty, start_position); + let input_ty = self.normalize(&unnormalized_input_ty, Locations::All); let mir_input_ty = mir.local_decls[local].ty; - self.equate_normalized_input_or_output(start_position, input_ty, mir_input_ty); + self.equate_normalized_input_or_output(input_ty, mir_input_ty); } assert!( mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() || mir.yield_ty.is_none() && universal_regions.yield_ty.is_none() - ); + ); if let Some(mir_yield_ty) = mir.yield_ty { let ur_yield_ty = universal_regions.yield_ty.unwrap(); - self.equate_normalized_input_or_output(start_position, ur_yield_ty, mir_yield_ty); + self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty); } // Return types are a bit more complex. They may contain existential `impl Trait` @@ -75,13 +70,13 @@ pub(super) fn equate_inputs_and_outputs( "equate_inputs_and_outputs: unnormalized_output_ty={:?}", unnormalized_output_ty ); - let output_ty = self.normalize(&unnormalized_output_ty, start_position); + let output_ty = self.normalize(&unnormalized_output_ty, Locations::All); debug!( "equate_inputs_and_outputs: normalized output_ty={:?}", output_ty ); let mir_output_ty = mir.local_decls[RETURN_PLACE].ty; - let anon_type_map = self.fully_perform_op(start_position.at_self(), |cx| { + let anon_type_map = self.fully_perform_op(Locations::All, |cx| { let mut obligations = ObligationAccumulator::default(); let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types( @@ -112,7 +107,7 @@ pub(super) fn equate_inputs_and_outputs( let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs); let anon_defn_ty = renumber::renumber_regions( cx.infcx, - TyContext::Location(start_position), + TyContext::Location(Location::START), &anon_defn_ty, ); debug!( @@ -134,7 +129,7 @@ pub(super) fn equate_inputs_and_outputs( }).unwrap_or_else(|terr| { span_mirbug!( self, - start_position, + Location::START, "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", output_ty, mir_output_ty, @@ -148,7 +143,7 @@ pub(super) fn equate_inputs_and_outputs( // prove that `T: Iterator` where `T` is the type we // instantiated it with). if let Some(anon_type_map) = anon_type_map { - self.fully_perform_op(start_position.at_self(), |_cx| { + self.fully_perform_op(Locations::All, |_cx| { infcx.constrain_anon_types(&anon_type_map, universal_regions); Ok(InferOk { value: (), @@ -158,13 +153,13 @@ pub(super) fn equate_inputs_and_outputs( } } - fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) { + fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b); - if let Err(terr) = self.eq_types(a, b, location.at_self()) { + if let Err(terr) = self.eq_types(a, b, Locations::All) { span_mirbug!( self, - location, + Location::START, "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`", a, b, diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index a21b9196bad..42a1745addf 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -618,17 +618,72 @@ pub struct OutlivesSet<'tcx> { pub data: RegionConstraintData<'tcx>, } +/// The `Locations` type summarizes *where* region constraints are +/// required to hold. Normally, this is at a particular point which +/// created the obligation, but for constraints that the user gave, we +/// want the constraint to hold at all points. #[derive(Copy, Clone, Debug)] -pub struct Locations { - /// The location in the MIR that generated these constraints. - /// This is intended for error reporting and diagnosis; the - /// constraints may *take effect* at a distinct spot. - pub from_location: Location, - - /// The constraints must be met at this location. In terms of the - /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field - /// is the `P` value. - pub at_location: Location, +pub enum Locations { + /// Indicates that a type constraint should always be true. This + /// is particularly important in the new borrowck analysis for + /// things like the type of the return slot. Consider this + /// example: + /// + /// ``` + /// fn foo<'a>(x: &'a u32) -> &'a u32 { + /// let y = 22; + /// return &y; // error + /// } + /// ``` + /// + /// Here, we wind up with the signature from the return type being + /// something like `&'1 u32` where `'1` is a universal region. But + /// the type of the return slot `_0` is something like `&'2 u32` + /// where `'2` is an existential region variable. The type checker + /// requires that `&'2 u32 = &'1 u32` -- but at what point? In the + /// older NLL analysis, we required this only at the entry point + /// to the function. By the nature of the constraints, this wound + /// up propagating to all points reachable from start (because + /// `'1` -- as a universal region -- is live everywhere). In the + /// newer analysis, though, this doesn't work: `_0` is considered + /// dead at the start (it has no usable value) and hence this type + /// equality is basically a no-op. Then, later on, when we do `_0 + /// = &'3 y`, that region `'3` never winds up related to the + /// universal region `'1` and hence no error occurs. Therefore, we + /// use Locations::All instead, which ensures that the `'1` and + /// `'2` are equal everything. We also use this for other + /// user-given type annotations; e.g., if the user wrote `let mut + /// x: &'static u32 = ...`, we would ensure that all values + /// assigned to `x` are of `'static` lifetime. + All, + + Pair { + /// The location in the MIR that generated these constraints. + /// This is intended for error reporting and diagnosis; the + /// constraints may *take effect* at a distinct spot. + from_location: Location, + + /// The constraints must be met at this location. In terms of the + /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field + /// is the `P` value. + at_location: Location, + } +} + +impl Locations { + pub fn from_location(&self) -> Option { + match self { + Locations::All => None, + Locations::Pair { from_location, .. } => Some(*from_location), + } + } + + pub fn at_location(&self) -> Option { + match self { + Locations::All => None, + Locations::Pair { at_location, .. } => Some(*at_location), + } + } } impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { @@ -770,7 +825,7 @@ fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Loca "check_stmt: user_assert_ty ty={:?} local_ty={:?}", ty, local_ty ); - if let Err(terr) = self.eq_types(ty, local_ty, location.at_self()) { + if let Err(terr) = self.eq_types(ty, local_ty, Locations::All) { span_mirbug!( self, stmt, @@ -820,7 +875,7 @@ fn check_terminator( let place_ty = location.ty(mir, tcx).to_ty(tcx); let rv_ty = value.ty(mir, tcx); - let locations = Locations { + let locations = Locations::Pair { from_location: term_location, at_location: target.start_location(), }; @@ -839,7 +894,7 @@ fn check_terminator( // *both* blocks, so we need to ensure that it holds // at both locations. if let Some(unwind) = unwind { - let locations = Locations { + let locations = Locations::Pair { from_location: term_location, at_location: unwind.start_location(), }; @@ -971,7 +1026,7 @@ fn check_call_dest( match *destination { Some((ref dest, target_block)) => { let dest_ty = dest.ty(mir, tcx).to_ty(tcx); - let locations = Locations { + let locations = Locations::Pair { from_location: term_location, at_location: target_block.start_location(), }; @@ -1375,7 +1430,7 @@ fn check_aggregate_rvalue( }; let operand_ty = operand.ty(mir, tcx); if let Err(terr) = - self.sub_types(operand_ty, field_ty, location.at_successor_within_block()) + self.sub_types(operand_ty, field_ty, location.at_self()) { span_mirbug!( self, @@ -1514,12 +1569,12 @@ fn typeck_mir(&mut self, mir: &Mir<'tcx>) { } } - fn normalize(&mut self, value: &T, location: Location) -> T + fn normalize(&mut self, value: &T, location: impl ToLocations) -> T where T: fmt::Debug + TypeFoldable<'tcx>, { debug!("normalize(value={:?}, location={:?})", value, location); - self.fully_perform_op(location.at_self(), |this| { + self.fully_perform_op(location.to_locations(), |this| { let Normalized { value, obligations } = this.infcx .at(&this.misc(this.last_span), this.param_env) .normalize(value) @@ -1585,16 +1640,32 @@ trait AtLocation { impl AtLocation for Location { fn at_self(self) -> Locations { - Locations { + Locations::Pair { from_location: self, at_location: self, } } fn at_successor_within_block(self) -> Locations { - Locations { + Locations::Pair { from_location: self, at_location: self.successor_within_block(), } } } + +trait ToLocations: fmt::Debug + Copy { + fn to_locations(self) -> Locations; +} + +impl ToLocations for Locations { + fn to_locations(self) -> Locations { + self + } +} + +impl ToLocations for Location { + fn to_locations(self) -> Locations { + self.at_self() + } +} diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index d924baaf005..77bcd88cecb 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -17,7 +17,7 @@ use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; use rustc::middle::expr_use_visitor as euv; -use rustc::middle::mem_categorization::{cmt}; +use rustc::middle::mem_categorization::cmt_; use rustc::middle::region; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; @@ -573,13 +573,13 @@ struct MutationChecker<'a, 'tcx: 'a> { } impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> { - fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {} - fn consume(&mut self, _: ast::NodeId, _: Span, _: cmt, _: ConsumeMode) {} - fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {} + fn matched_pat(&mut self, _: &Pat, _: &cmt_, _: euv::MatchMode) {} + fn consume(&mut self, _: ast::NodeId, _: Span, _: &cmt_, _: ConsumeMode) {} + fn consume_pat(&mut self, _: &Pat, _: &cmt_, _: ConsumeMode) {} fn borrow(&mut self, _: ast::NodeId, span: Span, - _: cmt, + _: &cmt_, _: ty::Region<'tcx>, kind:ty:: BorrowKind, _: LoanCause) { @@ -594,7 +594,7 @@ fn borrow(&mut self, } } fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {} - fn mutate(&mut self, _: ast::NodeId, span: Span, _: cmt, mode: MutateMode) { + fn mutate(&mut self, _: ast::NodeId, span: Span, _: &cmt_, mode: MutateMode) { match mode { MutateMode::JustWrite | MutateMode::WriteAndRead => { struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard") diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index bea29b6926a..d8f13242065 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -654,6 +654,9 @@ pub(super) fn eval_rvalue_into_place( if self.type_is_fat_ptr(src.ty) { match (src.value, self.type_is_fat_ptr(dest_ty)) { (Value::ByRef { .. }, _) | + // pointers to extern types + (Value::ByVal(_),_) | + // slices and trait objects to other slices/trait objects (Value::ByValPair(..), true) => { let valty = ValTy { value: src.value, @@ -661,6 +664,7 @@ pub(super) fn eval_rvalue_into_place( }; self.write_value(valty, dest)?; } + // slices and trait objects to thin pointers (dropping the metadata) (Value::ByValPair(data, _), false) => { let valty = ValTy { value: Value::ByVal(data), @@ -668,7 +672,6 @@ pub(super) fn eval_rvalue_into_place( }; self.write_value(valty, dest)?; } - (Value::ByVal(_), _) => bug!("expected fat ptr"), } } else { let src_layout = self.layout_of(src.ty)?; @@ -960,7 +963,7 @@ pub fn write_discriminant_value( layout::Abi::Uninhabited); } } - layout::Variants::Tagged { ref discr, .. } => { + layout::Variants::Tagged { ref tag, .. } => { let discr_val = dest_ty.ty_adt_def().unwrap() .discriminant_for_variant(*self.tcx, variant_index) .val; @@ -968,12 +971,12 @@ pub fn write_discriminant_value( // raw discriminants for enums are isize or bigger during // their computation, but the in-memory tag is the smallest possible // representation - let size = discr.value.size(self.tcx.tcx).bits(); + let size = tag.value.size(self.tcx.tcx).bits(); let amt = 128 - size; let discr_val = (discr_val << amt) >> amt; - let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?; - self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; + let (discr_dest, tag) = self.place_field(dest, mir::Field::new(0), layout)?; + self.write_primval(discr_dest, PrimVal::Bytes(discr_val), tag.ty)?; } layout::Variants::NicheFilling { dataful_variant, diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 95cf3b8ddc6..2545ba3a94a 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -34,6 +34,7 @@ #![feature(inclusive_range_methods)] #![feature(crate_visibility_modifier)] #![feature(never_type)] +#![feature(specialization)] #![cfg_attr(stage0, feature(try_trait))] extern crate arena; diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 8b771fcf493..5397d18cdd7 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -550,7 +550,7 @@ fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagSta } fn drop_flags_on_init(&mut self) { - let loc = Location { block: START_BLOCK, statement_index: 0 }; + let loc = Location::START; let span = self.patch.source_info_for_location(self.mir, loc).span; let false_ = self.constant_bool(span, false); for flag in self.drop_flags.values() { @@ -576,7 +576,7 @@ fn drop_flags_for_fn_rets(&mut self) { } fn drop_flags_for_args(&mut self) { - let loc = Location { block: START_BLOCK, statement_index: 0 }; + let loc = Location::START; dataflow::drop_flag_effects_for_function_entry( self.tcx, self.mir, self.env, |path, ds| { self.set_drop_flag(loc, path, ds); diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index c5d2f0041a0..3a577341f7e 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -468,13 +468,13 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { fn consume(&mut self, _consume_id: ast::NodeId, _consume_span: Span, - _cmt: mc::cmt, + _cmt: &mc::cmt_, _mode: euv::ConsumeMode) {} fn borrow(&mut self, borrow_id: ast::NodeId, _borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, _loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: euv::LoanCause) { @@ -489,7 +489,7 @@ fn borrow(&mut self, _ => {} } - let mut cur = &cmt; + let mut cur = cmt; loop { match cur.cat { Categorization::Rvalue(..) => { @@ -521,11 +521,11 @@ fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) {} fn mutate(&mut self, _assignment_id: ast::NodeId, _assignment_span: Span, - _assignee_cmt: mc::cmt, + _assignee_cmt: &mc::cmt_, _mode: euv::MutateMode) { } - fn matched_pat(&mut self, _: &hir::Pat, _: mc::cmt, _: euv::MatchMode) {} + fn matched_pat(&mut self, _: &hir::Pat, _: &mc::cmt_, _: euv::MatchMode) {} - fn consume_pat(&mut self, _consume_pat: &hir::Pat, _cmt: mc::cmt, _mode: euv::ConsumeMode) {} + fn consume_pat(&mut self, _consume_pat: &hir::Pat, _cmt: &mc::cmt_, _mode: euv::ConsumeMode) {} } diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index 622d8e51a6c..348aa6a7cef 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -65,7 +65,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(rustc_diagnostic_macros)] -#![feature(staged_api)] #[macro_use] extern crate syntax; diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index ebfd8785a0a..7e3c411c1d2 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -128,8 +128,6 @@ pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxEx /// This can be used in place of `register_syntax_extension` to register legacy custom derives /// (i.e. attribute syntax extensions whose name begins with `derive_`). Legacy custom /// derives defined by this function do not trigger deprecation warnings when used. - #[unstable(feature = "rustc_private", issue = "27812")] - #[rustc_deprecated(since = "1.15.0", reason = "replaced by macros 1.1 (RFC 1861)")] pub fn register_custom_derive(&mut self, name: ast::Name, extension: SyntaxExtension) { assert!(name.as_str().starts_with("derive_")); self.whitelisted_custom_derives.push(name); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d4b212a15d8..0f931d4374e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3277,9 +3277,8 @@ fn resolve_path(&mut self, let prev_name = path[0].name; if prev_name == keywords::Extern.name() || prev_name == keywords::CrateRoot.name() && - // Note: When this feature stabilizes, this should - // be gated on sess.rust_2018() - self.session.features_untracked().extern_absolute_paths { + self.session.features_untracked().extern_absolute_paths && + self.session.rust_2018() { // `::extern_crate::a::b` let crate_id = self.crate_loader.process_path_extern(name, ident.span); let crate_root = diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 17aa510b565..6a5a31a885f 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -646,7 +646,8 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa if module_path.len() == 1 && (module_path[0].name == keywords::CrateRoot.name() || module_path[0].name == keywords::Extern.name()) { let is_extern = module_path[0].name == keywords::Extern.name() || - self.session.features_untracked().extern_absolute_paths; + (self.session.features_untracked().extern_absolute_paths && + self.session.rust_2018()); match directive.subclass { GlobImport { .. } if is_extern => { return Some((directive.span, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 401a280412a..cf12302d989 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -40,7 +40,7 @@ use rustc::hir; use rustc::hir::def::Def as HirDef; -use rustc::hir::map::{Node, NodeItem}; +use rustc::hir::map::{Node, NodeTraitItem, NodeImplItem}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::middle::cstore::ExternCrate; use rustc::session::config::CrateType::CrateTypeExecutable; @@ -418,34 +418,30 @@ pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> O Some(impl_id) => match self.tcx.hir.get_if_local(impl_id) { Some(Node::NodeItem(item)) => match item.node { hir::ItemImpl(.., ref ty, _) => { - let mut result = String::from("<"); - result.push_str(&self.tcx.hir.node_to_pretty_string(ty.id)); + let mut qualname = String::from("<"); + qualname.push_str(&self.tcx.hir.node_to_pretty_string(ty.id)); let mut trait_id = self.tcx.trait_id_of_impl(impl_id); let mut decl_id = None; + let mut docs = String::new(); + let mut attrs = vec![]; + if let Some(NodeImplItem(item)) = self.tcx.hir.find(id) { + docs = self.docs_for_attrs(&item.attrs); + attrs = item.attrs.to_vec(); + } + if let Some(def_id) = trait_id { - result.push_str(" as "); - result.push_str(&self.tcx.item_path_str(def_id)); + // A method in a trait impl. + qualname.push_str(" as "); + qualname.push_str(&self.tcx.item_path_str(def_id)); self.tcx .associated_items(def_id) .find(|item| item.name == name) .map(|item| decl_id = Some(item.def_id)); - } else { - if let Some(NodeItem(item)) = self.tcx.hir.find(id) { - if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node { - trait_id = self.lookup_ref_id(ty.id); - } - } } - result.push_str(">"); - - ( - result, - trait_id, - decl_id, - self.docs_for_attrs(&item.attrs), - item.attrs.to_vec(), - ) + qualname.push_str(">"); + + (qualname, trait_id, decl_id, docs, attrs) } _ => { span_bug!( @@ -467,25 +463,23 @@ pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> O } }, None => match self.tcx.trait_of_item(self.tcx.hir.local_def_id(id)) { - Some(def_id) => match self.tcx.hir.get_if_local(def_id) { - Some(Node::NodeItem(item)) => ( + Some(def_id) => { + let mut docs = String::new(); + let mut attrs = vec![]; + + if let Some(NodeTraitItem(item)) = self.tcx.hir.find(id) { + docs = self.docs_for_attrs(&item.attrs); + attrs = item.attrs.to_vec(); + } + + ( format!("::{}", self.tcx.item_path_str(def_id)), Some(def_id), None, - self.docs_for_attrs(&item.attrs), - item.attrs.to_vec(), - ), - r => { - span_bug!( - span, - "Could not find container {:?} for \ - method {}, got {:?}", - def_id, - id, - r - ); - } - }, + docs, + attrs, + ) + } None => { debug!("Could not find container for method {} at {:?}", id, span); // This is not necessarily a bug, if there was a compilation error, diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index fd1f779f9ec..7ae4d990c8a 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -716,10 +716,10 @@ pub enum Variants { }, /// General-case enums: for each case there is a struct, and they all have - /// all space reserved for the discriminant, and their first field starts - /// at a non-0 offset, after where the discriminant would go. + /// all space reserved for the tag, and their first field starts + /// at a non-0 offset, after where the tag would go. Tagged { - discr: Scalar, + tag: Scalar, variants: Vec, }, diff --git a/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs b/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs new file mode 100644 index 00000000000..2d4e95ab01d --- /dev/null +++ b/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs @@ -0,0 +1,38 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + let base = super::linux_musl_base::opts(); + Ok(Target { + // It's important we use "gnueabihf" and not "musleabihf" here. LLVM + // uses it to determine the calling convention and float ABI, and LLVM + // doesn't support the "musleabihf" value. + llvm_target: "armv5te-unknown-linux-gnueabi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "linux".to_string(), + target_env: "musl".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + + options: TargetOptions { + features: "+soft-float,+strict-align".to_string(), + // Atomic operations provided by compiler-builtins + max_atomic_width: Some(32), + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + } + }) +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 1e94f037885..48e771e0aaf 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -283,6 +283,7 @@ fn $module() { ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf), ("armv4t-unknown-linux-gnueabi", armv4t_unknown_linux_gnueabi), ("armv5te-unknown-linux-gnueabi", armv5te_unknown_linux_gnueabi), + ("armv5te-unknown-linux-musleabi", armv5te_unknown_linux_musleabi), ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 148e3d0025c..b6fae3eaff2 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -293,7 +293,8 @@ fn set_flags(&mut self, sess: &Session, no_builtins: bool) { self.inline_threshold = sess.opts.cg.inline_threshold; self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; let embed_bitcode = sess.target.target.options.embed_bitcode || - sess.opts.debugging_opts.embed_bitcode; + sess.opts.debugging_opts.embed_bitcode || + sess.opts.debugging_opts.cross_lang_lto; if embed_bitcode { match sess.opts.optimize { config::OptLevel::No | @@ -841,13 +842,18 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext, "rustc.embedded.module\0".as_ptr() as *const _, ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = if cgcx.opts.target_triple.triple().contains("-ios") { + + let is_apple = cgcx.opts.target_triple.triple().contains("-ios") || + cgcx.opts.target_triple.triple().contains("-darwin"); + + let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" }; llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); let llconst = C_bytes_in_context(llcx, &[]); let llglobal = llvm::LLVMAddGlobal( @@ -856,7 +862,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext, "rustc.embedded.cmdline\0".as_ptr() as *const _, ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = if cgcx.opts.target_triple.triple().contains("-ios") { + let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" @@ -1350,6 +1356,10 @@ fn execute_work_item(cgcx: &CodegenContext, // settings. let needs_lto = needs_lto && mtrans.kind != ModuleKind::Metadata; + // Don't run LTO passes when cross-lang LTO is enabled. The linker + // will do that for us in this case. + let needs_lto = needs_lto && !cgcx.opts.debugging_opts.cross_lang_lto; + if needs_lto { Ok(WorkItemResult::NeedsLTO(mtrans)) } else { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 2fc6c9d4433..f16fef5ec1e 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1429,8 +1429,8 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let discriminant_type_metadata = match layout.variants { layout::Variants::Single { .. } | layout::Variants::NicheFilling { .. } => None, - layout::Variants::Tagged { ref discr, .. } => { - Some(discriminant_type_metadata(discr.value)) + layout::Variants::Tagged { ref tag, .. } => { + Some(discriminant_type_metadata(tag.value)) } }; diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs index 79859aee64d..d4abd5fa88d 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_trans/mir/place.rs @@ -273,8 +273,8 @@ pub fn trans_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> Value let lldiscr = discr.load(bx).immediate(); match self.layout.variants { layout::Variants::Single { .. } => bug!(), - layout::Variants::Tagged { ref discr, .. } => { - let signed = match discr.value { + layout::Variants::Tagged { ref tag, .. } => { + let signed = match tag.value { layout::Int(_, signed) => signed, _ => false }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b5e862fac95..e7e70a19e49 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -96,6 +96,7 @@ use std::mem; use std::ops::Deref; +use std::rc::Rc; use rustc_data_structures::sync::Lrc; use syntax::ast; use syntax_pos::Span; @@ -513,7 +514,7 @@ fn visit_expr(&mut self, expr: &'gcx hir::Expr) { // the adjusted form if there is an adjustment. match cmt_result { Ok(head_cmt) => { - self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span); + self.check_safety_of_rvalue_destructor_if_necessary(&head_cmt, expr.span); } Err(..) => { self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd"); @@ -799,7 +800,7 @@ fn with_mc(&self, f: F) -> R /// Invoked on any adjustments that occur. Checks that if this is a region pointer being /// dereferenced, the lifetime of the pointer includes the deref expr. - fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult> { + fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult> { debug!("constrain_adjustments(expr={:?})", expr); let mut cmt = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; @@ -814,7 +815,7 @@ fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult mc::McResult mc::McResult, + cmt: &mc::cmt_<'tcx>, span: Span) { match cmt.cat { Categorization::Rvalue(region) => { @@ -980,7 +981,7 @@ fn link_addr_of(&mut self, expr: &hir::Expr, debug!("link_addr_of: cmt={:?}", cmt); - self.link_region_from_node_type(expr.span, expr.hir_id, mutability, cmt); + self.link_region_from_node_type(expr.span, expr.hir_id, mutability, &cmt); } /// Computes the guarantors for any ref bindings in a `let` and @@ -992,7 +993,7 @@ fn link_local(&self, local: &hir::Local) { None => { return; } Some(ref expr) => &**expr, }; - let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr))); + let discr_cmt = Rc::new(ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr)))); self.link_pattern(discr_cmt, &local.pat); } @@ -1001,7 +1002,7 @@ fn link_local(&self, local: &hir::Local) { /// linked to the lifetime of its guarantor (if any). fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) { debug!("regionck::for_match()"); - let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr))); + let discr_cmt = Rc::new(ignore_err!(self.with_mc(|mc| mc.cat_expr(discr)))); debug!("discr_cmt={:?}", discr_cmt); for arm in arms { for root_pat in &arm.pats { @@ -1019,7 +1020,7 @@ fn link_fn_args(&self, body_scope: region::Scope, args: &[hir::Arg]) { let arg_ty = self.node_ty(arg.hir_id); let re_scope = self.tcx.mk_region(ty::ReScope(body_scope)); let arg_cmt = self.with_mc(|mc| { - mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty) + Rc::new(mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty)) }); debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", arg_ty, @@ -1044,7 +1045,7 @@ fn link_pattern(&self, discr_cmt: mc::cmt<'tcx>, root_pat: &hir::Pat) { .expect("missing binding mode"); if let ty::BindByReference(mutbl) = bm { self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id, - mutbl, sub_cmt); + mutbl, &sub_cmt); } } _ => {} @@ -1057,15 +1058,14 @@ fn link_pattern(&self, discr_cmt: mc::cmt<'tcx>, root_pat: &hir::Pat) { /// autoref'd. fn link_autoref(&self, expr: &hir::Expr, - expr_cmt: mc::cmt<'tcx>, + expr_cmt: &mc::cmt_<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>) { debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt); match *autoref { adjustment::AutoBorrow::Ref(r, m) => { - self.link_region(expr.span, r, - ty::BorrowKind::from_mutbl(m.into()), expr_cmt); + self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m.into()), expr_cmt); } adjustment::AutoBorrow::RawPtr(m) => { @@ -1081,15 +1081,14 @@ fn link_region_from_node_type(&self, span: Span, id: hir::HirId, mutbl: hir::Mutability, - cmt_borrowed: mc::cmt<'tcx>) { + cmt_borrowed: &mc::cmt_<'tcx>) { debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})", id, mutbl, cmt_borrowed); let rptr_ty = self.resolve_node_type(id); if let ty::TyRef(r, _) = rptr_ty.sty { debug!("rptr_ty={}", rptr_ty); - self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl), - cmt_borrowed); + self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); } } @@ -1101,19 +1100,19 @@ fn link_region(&self, span: Span, borrow_region: ty::Region<'tcx>, borrow_kind: ty::BorrowKind, - borrow_cmt: mc::cmt<'tcx>) { - let mut borrow_cmt = borrow_cmt; - let mut borrow_kind = borrow_kind; - + borrow_cmt: &mc::cmt_<'tcx>) { let origin = infer::DataBorrowed(borrow_cmt.ty, span); self.type_must_outlive(origin, borrow_cmt.ty, borrow_region); + let mut borrow_kind = borrow_kind; + let mut borrow_cmt_cat = borrow_cmt.cat.clone(); + loop { debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})", borrow_region, borrow_kind, borrow_cmt); - match borrow_cmt.cat.clone() { + match borrow_cmt_cat { Categorization::Deref(ref_cmt, mc::Implicit(ref_kind, ref_region)) | Categorization::Deref(ref_cmt, mc::BorrowedPtr(ref_kind, ref_region)) => { match self.link_reborrowed_region(span, @@ -1121,7 +1120,7 @@ fn link_region(&self, ref_cmt, ref_region, ref_kind, borrow_cmt.note) { Some((c, k)) => { - borrow_cmt = c; + borrow_cmt_cat = c.cat.clone(); borrow_kind = k; } None => { @@ -1135,7 +1134,7 @@ fn link_region(&self, Categorization::Interior(cmt_base, _) => { // Borrowing interior or owned data requires the base // to be valid and borrowable in the same fashion. - borrow_cmt = cmt_base; + borrow_cmt_cat = cmt_base.cat.clone(); borrow_kind = borrow_kind; } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 4fc3344dab2..58dc5839578 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -298,7 +298,8 @@ struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { - fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) { + fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: &mc::cmt_<'tcx>, + mode: euv::ConsumeMode) { debug!( "adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})", cmt, @@ -377,7 +378,7 @@ fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: mc::cmt<'tcx>, mode: euv /// Indicates that `cmt` is being directly mutated (e.g., assigned /// to). If cmt contains any by-ref upvars, this implies that /// those upvars must be borrowed using an `&mut` borrow. - fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) { + fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: &mc::cmt_<'tcx>) { debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", cmt); match cmt.cat.clone() { @@ -386,7 +387,7 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) { Categorization::Downcast(base, _) => { // Interior or owned data is mutable if base is // mutable, so iterate to the base. - self.adjust_upvar_borrow_kind_for_mut(base); + self.adjust_upvar_borrow_kind_for_mut(&base); } Categorization::Deref(base, mc::BorrowedPtr(..)) | @@ -396,7 +397,7 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) { // borrowed pointer implies that the // pointer itself must be unique, but not // necessarily *mutable* - self.adjust_upvar_borrow_kind_for_unique(base); + self.adjust_upvar_borrow_kind_for_unique(&base); } } @@ -410,7 +411,7 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) { } } - fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { + fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: &mc::cmt_<'tcx>) { debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt); match cmt.cat.clone() { @@ -419,7 +420,7 @@ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { Categorization::Downcast(base, _) => { // Interior or owned data is unique if base is // unique. - self.adjust_upvar_borrow_kind_for_unique(base); + self.adjust_upvar_borrow_kind_for_unique(&base); } Categorization::Deref(base, mc::BorrowedPtr(..)) | @@ -427,7 +428,7 @@ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) { // for a borrowed pointer to be unique, its // base must be unique - self.adjust_upvar_borrow_kind_for_unique(base); + self.adjust_upvar_borrow_kind_for_unique(&base); } } @@ -439,7 +440,9 @@ fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { } } - fn try_adjust_upvar_deref(&mut self, cmt: mc::cmt<'tcx>, borrow_kind: ty::BorrowKind) -> bool { + fn try_adjust_upvar_deref(&mut self, cmt: &mc::cmt_<'tcx>, borrow_kind: ty::BorrowKind) + -> bool + { assert!(match borrow_kind { ty::MutBorrow => true, ty::UniqueImmBorrow => true, @@ -581,17 +584,19 @@ fn consume( &mut self, _consume_id: ast::NodeId, _consume_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode, ) { debug!("consume(cmt={:?},mode={:?})", cmt, mode); self.adjust_upvar_borrow_kind_for_consume(cmt, mode); } - fn matched_pat(&mut self, _matched_pat: &hir::Pat, _cmt: mc::cmt<'tcx>, _mode: euv::MatchMode) { + fn matched_pat(&mut self, _matched_pat: &hir::Pat, _cmt: &mc::cmt_<'tcx>, + _mode: euv::MatchMode) { } - fn consume_pat(&mut self, _consume_pat: &hir::Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) { + fn consume_pat(&mut self, _consume_pat: &hir::Pat, cmt: &mc::cmt_<'tcx>, + mode: euv::ConsumeMode) { debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode); self.adjust_upvar_borrow_kind_for_consume(cmt, mode); } @@ -600,7 +605,7 @@ fn borrow( &mut self, borrow_id: ast::NodeId, _borrow_span: Span, - cmt: mc::cmt<'tcx>, + cmt: &mc::cmt_<'tcx>, _loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, _loan_cause: euv::LoanCause, @@ -629,7 +634,7 @@ fn mutate( &mut self, _assignment_id: ast::NodeId, _assignment_span: Span, - assignee_cmt: mc::cmt<'tcx>, + assignee_cmt: &mc::cmt_<'tcx>, _mode: euv::MutateMode, ) { debug!("mutate(assignee_cmt={:?})", assignee_cmt); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 23e0c2625ee..a8f4848bf89 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -38,7 +38,7 @@ /// /// The returned value is `None` if the definition could not be inlined, /// and `Some` of a vector of items if it was successfully expanded. -pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name) +pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHashSet) -> Option> { if def == Def::Err { return None } let did = def.def_id(); @@ -87,7 +87,7 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name) Def::StructCtor(..) => return Some(Vec::new()), Def::Mod(did) => { record_extern_fqn(cx, did, clean::TypeKind::Module); - clean::ModuleItem(build_module(cx, did)) + clean::ModuleItem(build_module(cx, did, visited)) } Def::Static(did, mtbl) => { record_extern_fqn(cx, did, clean::TypeKind::Static); @@ -385,24 +385,24 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { }); } -fn build_module(cx: &DocContext, did: DefId) -> clean::Module { +fn build_module(cx: &DocContext, did: DefId, visited: &mut FxHashSet) -> clean::Module { let mut items = Vec::new(); - fill_in(cx, did, &mut items); + fill_in(cx, did, &mut items, visited); return clean::Module { items, is_crate: false, }; - fn fill_in(cx: &DocContext, did: DefId, items: &mut Vec) { + fn fill_in(cx: &DocContext, did: DefId, items: &mut Vec, + visited: &mut FxHashSet) { // If we're re-exporting a re-export it may actually re-export something in // two namespaces, so the target may be listed twice. Make sure we only // visit each node at most once. - let mut visited = FxHashSet(); for &item in cx.tcx.item_children(did).iter() { let def_id = item.def.def_id(); if item.vis == ty::Visibility::Public { - if !visited.insert(def_id) { continue } - if let Some(i) = try_inline(cx, item.def, item.ident.name) { + if did == def_id || !visited.insert(def_id) { continue } + if let Some(i) = try_inline(cx, item.def, item.ident.name, visited) { items.extend(i) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d124a17b421..fb0bd0e42c5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1755,8 +1755,18 @@ pub struct Generics { impl Clean for hir::Generics { fn clean(&self, cx: &DocContext) -> Generics { + let mut params = Vec::with_capacity(self.params.len()); + for p in &self.params { + let p = p.clean(cx); + if let GenericParam::Type(ref tp) = p { + if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { + cx.impl_trait_bounds.borrow_mut().insert(tp.did, tp.bounds.clone()); + } + } + params.push(p); + } let mut g = Generics { - params: self.params.clean(cx), + params, where_predicates: self.where_clause.predicates.clean(cx) }; @@ -1869,9 +1879,11 @@ pub struct Method { impl<'a> Clean for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) { fn clean(&self, cx: &DocContext) -> Method { - let generics = self.1.clean(cx); + let (generics, decl) = enter_impl_trait(cx, || { + (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)) + }); Method { - decl: enter_impl_trait(cx, &generics.params, || (&*self.0.decl, self.2).clean(cx)), + decl, generics, unsafety: self.0.unsafety, constness: self.0.constness, @@ -1899,8 +1911,9 @@ pub struct Function { impl Clean for doctree::Function { fn clean(&self, cx: &DocContext) -> Item { - let generics = self.generics.clean(cx); - let decl = enter_impl_trait(cx, &generics.params, || (&self.decl, self.body).clean(cx)); + let (generics, decl) = enter_impl_trait(cx, || { + (self.generics.clean(cx), (&self.decl, self.body).clean(cx)) + }); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -2139,12 +2152,12 @@ fn clean(&self, cx: &DocContext) -> Item { MethodItem((sig, &self.generics, body).clean(cx)) } hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => { - let generics = self.generics.clean(cx); + let (generics, decl) = enter_impl_trait(cx, || { + (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx)) + }); TyMethodItem(TyMethod { unsafety: sig.unsafety.clone(), - decl: enter_impl_trait(cx, &generics.params, || { - (&*sig.decl, &names[..]).clean(cx) - }), + decl, generics, abi: sig.abi }) @@ -3415,12 +3428,12 @@ pub struct BareFunctionDecl { impl Clean for hir::BareFnTy { fn clean(&self, cx: &DocContext) -> BareFunctionDecl { - let generic_params = self.generic_params.clean(cx); + let (generic_params, decl) = enter_impl_trait(cx, || { + (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx)) + }); BareFunctionDecl { unsafety: self.unsafety, - decl: enter_impl_trait(cx, &generic_params, || { - (&*self.decl, &self.arg_names[..]).clean(cx) - }), + decl, generic_params, abi: self.abi, } @@ -3673,7 +3686,8 @@ fn clean(&self, cx: &DocContext) -> Vec { } else { let name = self.name; if !denied { - if let Some(items) = inline::try_inline(cx, path.def, name) { + let mut visited = FxHashSet(); + if let Some(items) = inline::try_inline(cx, path.def, name, &mut visited) { return items; } } @@ -3722,11 +3736,11 @@ impl Clean for hir::ForeignItem { fn clean(&self, cx: &DocContext) -> Item { let inner = match self.node { hir::ForeignItemFn(ref decl, ref names, ref generics) => { - let generics = generics.clean(cx); + let (generics, decl) = enter_impl_trait(cx, || { + (generics.clean(cx), (&**decl, &names[..]).clean(cx)) + }); ForeignFunctionItem(Function { - decl: enter_impl_trait(cx, &generics.params, || { - (&**decl, &names[..]).clean(cx) - }), + decl, generics, unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, @@ -4030,23 +4044,11 @@ pub fn def_id_to_path(cx: &DocContext, did: DefId, name: Option) -> Vec< once(crate_name).chain(relative).collect() } -pub fn enter_impl_trait(cx: &DocContext, gps: &[GenericParam], f: F) -> R +pub fn enter_impl_trait(cx: &DocContext, f: F) -> R where F: FnOnce() -> R, { - let bounds = gps.iter() - .filter_map(|p| { - if let GenericParam::Type(ref tp) = *p { - if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { - return Some((tp.did, tp.bounds.clone())); - } - } - - None - }) - .collect::>>(); - - let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), bounds); + let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), Default::default()); let r = f(); assert!(cx.impl_trait_bounds.borrow().is_empty()); *cx.impl_trait_bounds.borrow_mut() = old_bounds; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fc05833e285..d41739ab02c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -330,10 +330,10 @@ // with a rustc without jemalloc. // FIXME(#44236) shouldn't need MSVC logic #![cfg_attr(all(not(target_env = "msvc"), - any(stage0, feature = "force_alloc_system")), + any(all(stage0, not(test)), feature = "force_alloc_system")), feature(global_allocator))] #[cfg(all(not(target_env = "msvc"), - any(stage0, feature = "force_alloc_system")))] + any(all(stage0, not(test)), feature = "force_alloc_system")))] #[global_allocator] static ALLOC: alloc_system::System = alloc_system::System; diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 919d9648297..437d7d74cae 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -116,6 +116,8 @@ mod prim_bool { } /// /// # `!` and generics /// +/// ## Infallible errors +/// /// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`] /// trait: /// @@ -144,9 +146,60 @@ mod prim_bool { } /// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain /// enum variants from generic types like `Result`. /// +/// ## Infinite loops +/// +/// While [`Result`] is very useful for removing errors, `!` can also be used to remove +/// successes as well. If we think of [`Result`] as "if this function returns, it has not +/// errored," we get a very intuitive idea of [`Result`] as well: if the function returns, it +/// *has* errored. +/// +/// For example, consider the case of a simple web server, which can be simplified to: +/// +/// ```ignore (hypothetical-example) +/// loop { +/// let (client, request) = get_request().expect("disconnected"); +/// let response = request.process(); +/// response.send(client); +/// } +/// ``` +/// +/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection. +/// Instead, we'd like to keep track of this error, like this: +/// +/// ```ignore (hypothetical-example) +/// loop { +/// match get_request() { +/// Err(err) => break err, +/// Ok((client, request)) => { +/// let response = request.process(); +/// response.send(client); +/// }, +/// } +/// } +/// ``` +/// +/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it +/// might be intuitive to simply return the error, we might want to wrap it in a [`Result`] +/// instead: +/// +/// ```ignore (hypothetical-example) +/// fn server_loop() -> Result { +/// loop { +/// let (client, request) = get_request()?; +/// let response = request.process(); +/// response.send(client); +/// } +/// } +/// ``` +/// +/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop +/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok` +/// because `!` coerces to `Result` automatically. +/// /// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str /// [`Result`]: result/enum.Result.html /// [`Result`]: result/enum.Result.html +/// [`Result`]: result/enum.Result.html /// [`Ok`]: result/enum.Result.html#variant.Ok /// [`String`]: string/struct.String.html /// [`Err`]: result/enum.Result.html#variant.Err diff --git a/src/libsyntax/edition.rs b/src/libsyntax/edition.rs index 3fc1c279f5a..7341941c242 100644 --- a/src/libsyntax/edition.rs +++ b/src/libsyntax/edition.rs @@ -50,8 +50,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { impl Edition { pub fn lint_name(&self) -> &'static str { match *self { - Edition::Edition2015 => "edition_2015", - Edition::Edition2018 => "edition_2018", + Edition::Edition2015 => "rust_2015_breakage", + Edition::Edition2018 => "rust_2018_breakage", } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d8db76a95ff..5155408ba63 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -300,7 +300,7 @@ pub fn walk_feature_fields(&self, mut f: F) (active, abi_unadjusted, "1.16.0", None, None), // Procedural macros 2.0. - (active, proc_macro, "1.16.0", Some(38356), None), + (active, proc_macro, "1.16.0", Some(38356), Some(Edition::Edition2018)), // Declarative macros 2.0 (`macro`). (active, decl_macro, "1.17.0", Some(39412), None), @@ -324,7 +324,7 @@ pub fn walk_feature_fields(&self, mut f: F) // Allows the `catch {...}` expression - (active, catch_expr, "1.17.0", Some(31436), None), + (active, catch_expr, "1.17.0", Some(31436), Some(Edition::Edition2018)), // Used to preserve symbols (see llvm.used) (active, used, "1.18.0", Some(40289), None), @@ -1848,6 +1848,14 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { let mut feature_checker = FeatureChecker::default(); + for &(.., f_edition, set) in ACTIVE_FEATURES.iter() { + if let Some(f_edition) = f_edition { + if f_edition <= crate_edition { + set(&mut features, DUMMY_SP); + } + } + } + for attr in krate_attrs { if !attr.check_name("feature") { continue diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index f252020bc31..f26a6a53074 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -419,13 +419,24 @@ pub fn lit_token(lit: token::Lit, suf: Option, diag: Option<(Span, &Hand token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)), token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)), - token::Str_(s) => { - let s = Symbol::intern(&str_lit(&s.as_str(), diag)); - (true, Some(LitKind::Str(s, ast::StrStyle::Cooked))) + token::Str_(mut sym) => { + // If there are no characters requiring special treatment we can + // reuse the symbol from the Token. Otherwise, we must generate a + // new symbol because the string in the LitKind is different to the + // string in the Token. + let s = &sym.as_str(); + if s.as_bytes().iter().any(|&c| c == b'\\' || c == b'\r') { + sym = Symbol::intern(&str_lit(s, diag)); + } + (true, Some(LitKind::Str(sym, ast::StrStyle::Cooked))) } - token::StrRaw(s, n) => { - let s = Symbol::intern(&raw_str_lit(&s.as_str())); - (true, Some(LitKind::Str(s, ast::StrStyle::Raw(n)))) + token::StrRaw(mut sym, n) => { + // Ditto. + let s = &sym.as_str(); + if s.contains('\r') { + sym = Symbol::intern(&raw_str_lit(s)); + } + (true, Some(LitKind::Str(sym, ast::StrStyle::Raw(n)))) } token::ByteStr(i) => { (true, Some(LitKind::ByteStr(byte_str_lit(&i.as_str())))) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d8228e2b28b..b8ddb063d98 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -656,7 +656,7 @@ fn print_string(&mut self, st: &str, style: ast::StrStyle) -> io::Result<()> { let st = match style { ast::StrStyle::Cooked => { - (format!("\"{}\"", st.escape_default())) + (format!("\"{}\"", st.escape_debug())) } ast::StrStyle::Raw(n) => { (format!("r{delim}\"{string}\"{delim}", diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index 7352c494a42..754f04a26e7 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -42,16 +42,13 @@ pub fn expand_assert<'cx>( tts: if let Some(ts) = custom_msg_args { ts.into() } else { - // `expr_to_string` escapes the string literals with `.escape_default()` - // which escapes all non-ASCII characters with `\u`. - let escaped_expr = escape_format_string(&unescape_printable_unicode( - &pprust::expr_to_string(&cond_expr), - )); - TokenStream::from(TokenTree::Token( DUMMY_SP, token::Literal( - token::Lit::Str_(Name::intern(&format!("assertion failed: {}", escaped_expr))), + token::Lit::Str_(Name::intern(&format!( + "assertion failed: {}", + pprust::expr_to_string(&cond_expr).escape_debug() + ))), None, ), )).into() @@ -71,53 +68,3 @@ pub fn expand_assert<'cx>( ); MacEager::expr(if_expr) } - -/// Escapes a string for use as a formatting string. -fn escape_format_string(s: &str) -> String { - let mut res = String::with_capacity(s.len()); - for c in s.chars() { - res.extend(c.escape_debug()); - match c { - '{' | '}' => res.push(c), - _ => {} - } - } - res -} - -#[test] -fn test_escape_format_string() { - assert!(escape_format_string(r"foo{}\") == r"foo{{}}\\"); -} - -/// Unescapes the escaped unicodes (`\u{...}`) that are printable. -fn unescape_printable_unicode(mut s: &str) -> String { - use std::{char, u32}; - - let mut res = String::with_capacity(s.len()); - - loop { - if let Some(start) = s.find(r"\u{") { - res.push_str(&s[0..start]); - s = &s[start..]; - s.find('}') - .and_then(|end| { - let v = u32::from_str_radix(&s[3..end], 16).ok()?; - let c = char::from_u32(v)?; - // Escape unprintable characters. - res.extend(c.escape_debug()); - s = &s[end + 1..]; - Some(()) - }) - .expect("lexer should have rejected invalid escape sequences"); - } else { - res.push_str(s); - return res; - } - } -} - -#[test] -fn test_unescape_printable_unicode() { - assert!(unescape_printable_unicode(r"\u{2603}\n\u{0}") == r"☃\n\u{0}"); -} diff --git a/src/stdsimd b/src/stdsimd index 1ea18a5cb43..2f86c75a247 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit 1ea18a5cb431e24aa838b652ac305acc5e394d6b +Subproject commit 2f86c75a2479cf051b92fc98273daaf7f151e7a1 diff --git a/src/test/compile-fail/issue-43355.rs b/src/test/compile-fail/issue-43355.rs index 4db5c84df9a..d793a78799a 100644 --- a/src/test/compile-fail/issue-43355.rs +++ b/src/test/compile-fail/issue-43355.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(incoherent_fundamental_impls)] - pub trait Trait1 { type Output; } diff --git a/src/test/compile-fail/issue-50471.rs b/src/test/compile-fail/issue-50471.rs new file mode 100644 index 00000000000..ce2947144af --- /dev/null +++ b/src/test/compile-fail/issue-50471.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +fn main() { + assert!({false}); + + assert!(r"\u{41}" == "A"); + + assert!(r"\u{".is_empty()); +} diff --git a/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-1.rs b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-1.rs index 14d5d9caa31..fcf4714ba96 100644 --- a/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-1.rs +++ b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-1.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --edition=2018 -Zunstable-options + #![feature(extern_absolute_paths)] use xcrate::S; //~ ERROR can't find crate for `xcrate` diff --git a/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-2.rs b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-2.rs index defd103f9e4..c256c5592c2 100644 --- a/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-2.rs +++ b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-2.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --edition=2018 -Zunstable-options + #![feature(extern_absolute_paths)] fn main() { diff --git a/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-3.rs b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-3.rs index be1708e2b57..837dc617b3a 100644 --- a/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-3.rs +++ b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-3.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --edition=2018 -Zunstable-options + #![feature(extern_absolute_paths)] use ycrate; //~ ERROR can't find crate for `ycrate` diff --git a/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs b/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs index e44465750d1..9b7baa00163 100644 --- a/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs +++ b/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs @@ -9,6 +9,7 @@ // except according to those terms. // aux-build:xcrate.rs +// compile-flags: --edition=2018 -Zunstable-options #![feature(crate_in_paths)] #![feature(extern_absolute_paths)] diff --git a/src/test/compile-fail/unused-result.rs b/src/test/compile-fail/unused-result.rs index 0c6c7fc5a0d..363ab6220bd 100644 --- a/src/test/compile-fail/unused-result.rs +++ b/src/test/compile-fail/unused-result.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(unused_results, unused_must_use)] #![allow(dead_code)] +#![deny(unused_results, unused_must_use)] +//~^ NOTE: lint level defined here +//~| NOTE: lint level defined here #[must_use] enum MustUse { Test } @@ -27,7 +29,8 @@ fn foo() -> T { panic!() } fn test() { foo::(); foo::(); //~ ERROR: unused `MustUse` which must be used - foo::(); //~ ERROR: unused `MustUseMsg` which must be used: some message + foo::(); //~ ERROR: unused `MustUseMsg` which must be used + //~^ NOTE: some message } #[allow(unused_results, unused_must_use)] @@ -40,7 +43,8 @@ fn test2() { fn main() { foo::(); //~ ERROR: unused result foo::(); //~ ERROR: unused `MustUse` which must be used - foo::(); //~ ERROR: unused `MustUseMsg` which must be used: some message + foo::(); //~ ERROR: unused `MustUseMsg` which must be used + //~^ NOTE: some message let _ = foo::(); let _ = foo::(); diff --git a/src/test/run-make-fulldeps/libtest-json/Makefile b/src/test/run-make-fulldeps/libtest-json/Makefile index ec91ddfb9f9..a0bc8cf6688 100644 --- a/src/test/run-make-fulldeps/libtest-json/Makefile +++ b/src/test/run-make-fulldeps/libtest-json/Makefile @@ -6,7 +6,7 @@ OUTPUT_FILE := $(TMPDIR)/libtest-json-output.json all: $(RUSTC) --test f.rs - $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE) || true + RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE) || true cat $(OUTPUT_FILE) | "$(PYTHON)" validate_json.py diff --git a/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile b/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile index a132668ec7c..6a67b5862a8 100644 --- a/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile +++ b/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile @@ -1,9 +1,9 @@ -include ../tools.mk all: extern_absolute_paths.rs extern_in_paths.rs krate2 - $(RUSTC) extern_absolute_paths.rs -Zsave-analysis + $(RUSTC) extern_absolute_paths.rs -Zsave-analysis --edition=2018 cat $(TMPDIR)/save-analysis/extern_absolute_paths.json | "$(PYTHON)" validate_json.py - $(RUSTC) extern_in_paths.rs -Zsave-analysis + $(RUSTC) extern_in_paths.rs -Zsave-analysis --edition=2018 cat $(TMPDIR)/save-analysis/extern_in_paths.json | "$(PYTHON)" validate_json.py krate2: krate2.rs diff --git a/src/test/run-make/cross-lang-lto/Makefile b/src/test/run-make/cross-lang-lto/Makefile new file mode 100644 index 00000000000..98b509cd81f --- /dev/null +++ b/src/test/run-make/cross-lang-lto/Makefile @@ -0,0 +1,53 @@ + +# min-llvm-version 4.0 +# ignore-mingw + +-include ../../run-make-fulldeps/tools.mk + +# This test makes sure that the expected .llvmbc sections for use by +# linker-based LTO are available in object files when compiling with +# -Z cross-lang-lto + +LLVMBC_SECTION_NAME=\\.llvmbc + +ifeq ($(UNAME),Darwin) + LLVMBC_SECTION_NAME=__bitcode +endif + + +OBJDUMP=llvm-objdump +SECTION_HEADERS=$(OBJDUMP) -section-headers + +BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1 + +BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1 --emit=obj + +all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib + +staticlib: lib.rs + $(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib.a + [ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib.a | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ] + +staticlib-fat-lto: lib.rs + $(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib-fat-lto.a -Clto=fat + [ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib-fat-lto.a | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ] + +staticlib-thin-lto: lib.rs + $(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib-thin-lto.a -Clto=thin + [ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib-thin-lto.a | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ] + +rlib: lib.rs + $(BUILD_LIB) --crate-type=rlib -o $(TMPDIR)/liblib.rlib + [ "$$($(SECTION_HEADERS) $(TMPDIR)/liblib.rlib | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ] + +cdylib: lib.rs + $(BUILD_LIB) --crate-type=cdylib --emit=obj -o $(TMPDIR)/cdylib.o + [ "$$($(SECTION_HEADERS) $(TMPDIR)/cdylib.o | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ] + +rdylib: lib.rs + $(BUILD_LIB) --crate-type=dylib --emit=obj -o $(TMPDIR)/rdylib.o + [ "$$($(SECTION_HEADERS) $(TMPDIR)/rdylib.o | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ] + +exe: lib.rs + $(BUILD_EXE) -o $(TMPDIR)/exe.o + [ "$$($(SECTION_HEADERS) $(TMPDIR)/exe.o | grep -c $(LLVMBC_SECTION_NAME))" -ne "0" ] diff --git a/src/test/run-make/cross-lang-lto/lib.rs b/src/test/run-make/cross-lang-lto/lib.rs new file mode 100644 index 00000000000..b2a5b946160 --- /dev/null +++ b/src/test/run-make/cross-lang-lto/lib.rs @@ -0,0 +1,14 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[no_mangle] +pub extern "C" fn foo() { + println!("abc"); +} diff --git a/src/test/run-make/cross-lang-lto/main.rs b/src/test/run-make/cross-lang-lto/main.rs new file mode 100644 index 00000000000..ccd34c9e4db --- /dev/null +++ b/src/test/run-make/cross-lang-lto/main.rs @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + println!("Hello World"); +} diff --git a/src/test/run-pass/issue-43355.rs b/src/test/run-pass/issue-43355.rs deleted file mode 100644 index 19431a6a429..00000000000 --- a/src/test/run-pass/issue-43355.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Check that the code for issue #43355 can run without an ICE, please remove -// this test when it becomes an hard error. - -pub trait Trait1 { - type Output; -} -pub trait Trait2 {} - -impl Trait1 for T where T: Trait2 { - type Output = (); -} -impl Trait1> for A { - type Output = i32; -} - -pub struct A; - -fn f>>() { - println!("k: {}", ::std::mem::size_of::<>>::Output>()); -} - -pub fn g>>() { - f::(); -} - -fn main() {} diff --git a/src/test/run-pass/rfc-2126-extern-absolute-paths/basic.rs b/src/test/run-pass/rfc-2126-extern-absolute-paths/basic.rs index 0fa125a3e50..bbe066481a8 100644 --- a/src/test/run-pass/rfc-2126-extern-absolute-paths/basic.rs +++ b/src/test/run-pass/rfc-2126-extern-absolute-paths/basic.rs @@ -9,6 +9,7 @@ // except according to those terms. // aux-build:xcrate.rs +// compile-flags: --edition=2018 -Zunstable-options #![feature(extern_absolute_paths)] diff --git a/src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs b/src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs index 796f652d6b5..ead462cf0d2 100644 --- a/src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs +++ b/src/test/run-pass/rfc-2126-extern-absolute-paths/test.rs @@ -12,7 +12,7 @@ // // Regression test for #47075. -// compile-flags: --test +// compile-flags: --test --edition=2018 -Zunstable-options #![feature(extern_absolute_paths)] diff --git a/src/test/rustdoc/auxiliary/mod-stackoverflow.rs b/src/test/rustdoc/auxiliary/mod-stackoverflow.rs new file mode 100644 index 00000000000..f03593dbee6 --- /dev/null +++ b/src/test/rustdoc/auxiliary/mod-stackoverflow.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Cmetadata=aux + +pub mod tree { + pub use tree; +} + +pub mod tree2 { + pub mod prelude { + pub use tree2; + } +} diff --git a/src/test/rustdoc/mod-stackoverflow.rs b/src/test/rustdoc/mod-stackoverflow.rs new file mode 100644 index 00000000000..1e2f6dbe780 --- /dev/null +++ b/src/test/rustdoc/mod-stackoverflow.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:mod-stackoverflow.rs +// ignore-cross-compile + +extern crate mod_stackoverflow; +pub use mod_stackoverflow::tree; +pub use mod_stackoverflow::tree2; diff --git a/src/test/rustdoc/universal-impl-trait.rs b/src/test/rustdoc/universal-impl-trait.rs index 4cf99562c52..af51ff3d941 100644 --- a/src/test/rustdoc/universal-impl-trait.rs +++ b/src/test/rustdoc/universal-impl-trait.rs @@ -11,6 +11,8 @@ #![feature(universal_impl_trait)] #![crate_name = "foo"] +use std::io::Read; + // @has foo/fn.foo.html // @has - //pre 'foo(' // @matches - '_x: impl ) { } + + // @has - 'qux(' + // @matches - 'trait\.Read\.html' + pub fn qux(_qux: impl IntoIterator>) { + } } // @has - 'method(' diff --git a/src/test/ui-fulldeps/unnecessary-extern-crate.rs b/src/test/ui-fulldeps/unnecessary-extern-crate.rs new file mode 100644 index 00000000000..9d678d91578 --- /dev/null +++ b/src/test/ui-fulldeps/unnecessary-extern-crate.rs @@ -0,0 +1,55 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(unnecessary_extern_crate)] +#![feature(alloc, test, libc)] + +extern crate alloc; +//~^ ERROR `extern crate` is unnecessary in the new edition +//~| HELP remove +extern crate alloc as x; +//~^ ERROR `extern crate` is unnecessary in the new edition +//~| HELP use `use` + +#[macro_use] +extern crate test; +pub extern crate test as y; +//~^ ERROR `extern crate` is unnecessary in the new edition +//~| HELP use `pub use` +pub extern crate libc; +//~^ ERROR `extern crate` is unnecessary in the new edition +//~| HELP use `pub use` + + +mod foo { + extern crate alloc; + //~^ ERROR `extern crate` is unnecessary in the new edition + //~| HELP use `use` + extern crate alloc as x; + //~^ ERROR `extern crate` is unnecessary in the new edition + //~| HELP use `use` + pub extern crate test; + //~^ ERROR `extern crate` is unnecessary in the new edition + //~| HELP use `pub use` + pub extern crate test as y; + //~^ ERROR `extern crate` is unnecessary in the new edition + //~| HELP use `pub use` + mod bar { + extern crate alloc; + //~^ ERROR `extern crate` is unnecessary in the new edition + //~| HELP use `use` + extern crate alloc as x; + //~^ ERROR `extern crate` is unnecessary in the new edition + //~| HELP use `use` + } +} + + +fn main() {} diff --git a/src/test/ui-fulldeps/unnecessary-extern-crate.stderr b/src/test/ui-fulldeps/unnecessary-extern-crate.stderr new file mode 100644 index 00000000000..7718808be58 --- /dev/null +++ b/src/test/ui-fulldeps/unnecessary-extern-crate.stderr @@ -0,0 +1,68 @@ +error: `extern crate` is unnecessary in the new edition + --> $DIR/unnecessary-extern-crate.rs:14:1 + | +LL | extern crate alloc; + | ^^^^^^^^^^^^^^^^^^^ help: remove it + | +note: lint level defined here + --> $DIR/unnecessary-extern-crate.rs:11:9 + | +LL | #![deny(unnecessary_extern_crate)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `extern crate` is unnecessary in the new edition + --> $DIR/unnecessary-extern-crate.rs:17:1 + | +LL | extern crate alloc as x; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x` + +error: `extern crate` is unnecessary in the new edition + --> $DIR/unnecessary-extern-crate.rs:23:1 + | +LL | pub extern crate test as y; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y` + +error: `extern crate` is unnecessary in the new edition + --> $DIR/unnecessary-extern-crate.rs:26:1 + | +LL | pub extern crate libc; + | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc` + +error: `extern crate` is unnecessary in the new edition + --> $DIR/unnecessary-extern-crate.rs:32:5 + | +LL | extern crate alloc; + | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc` + +error: `extern crate` is unnecessary in the new edition + --> $DIR/unnecessary-extern-crate.rs:35:5 + | +LL | extern crate alloc as x; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x` + +error: `extern crate` is unnecessary in the new edition + --> $DIR/unnecessary-extern-crate.rs:38:5 + | +LL | pub extern crate test; + | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test` + +error: `extern crate` is unnecessary in the new edition + --> $DIR/unnecessary-extern-crate.rs:41:5 + | +LL | pub extern crate test as y; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y` + +error: `extern crate` is unnecessary in the new edition + --> $DIR/unnecessary-extern-crate.rs:45:9 + | +LL | extern crate alloc; + | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc` + +error: `extern crate` is unnecessary in the new edition + --> $DIR/unnecessary-extern-crate.rs:48:9 + | +LL | extern crate alloc as x; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x` + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/const-eval/extern_fat_pointer.rs b/src/test/ui/const-eval/extern_fat_pointer.rs new file mode 100644 index 00000000000..071311430a8 --- /dev/null +++ b/src/test/ui/const-eval/extern_fat_pointer.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![feature(extern_types)] + +extern { + type Opaque; +} + +const FOO: *const u8 = &42 as *const _ as *const Opaque as *const u8; + +fn main() { + let _foo = FOO; +} diff --git a/src/test/ui/fn_must_use.stderr b/src/test/ui/fn_must_use.stderr index 5026dac0a94..b5bad22f3dc 100644 --- a/src/test/ui/fn_must_use.stderr +++ b/src/test/ui/fn_must_use.stderr @@ -1,4 +1,4 @@ -warning: unused return value of `need_to_use_this_value` which must be used: it's important +warning: unused return value of `need_to_use_this_value` which must be used --> $DIR/fn_must_use.rs:60:5 | LL | need_to_use_this_value(); //~ WARN unused return value @@ -9,6 +9,7 @@ note: lint level defined here | LL | #![warn(unused_must_use)] | ^^^^^^^^^^^^^^^ + = note: it's important warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used --> $DIR/fn_must_use.rs:65:5 @@ -16,11 +17,13 @@ warning: unused return value of `MyStruct::need_to_use_this_method_value` which LL | m.need_to_use_this_method_value(); //~ WARN unused return value | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: unused return value of `EvenNature::is_even` which must be used: no side effects +warning: unused return value of `EvenNature::is_even` which must be used --> $DIR/fn_must_use.rs:66:5 | LL | m.is_even(); // trait method! | ^^^^^^^^^^^^ + | + = note: no side effects warning: unused return value of `std::cmp::PartialEq::eq` which must be used --> $DIR/fn_must_use.rs:72:5 diff --git a/src/test/ui/on-unimplemented/no-debug.stderr b/src/test/ui/on-unimplemented/no-debug.stderr index 5d8f80e57b0..275cd91a435 100644 --- a/src/test/ui/on-unimplemented/no-debug.stderr +++ b/src/test/ui/on-unimplemented/no-debug.stderr @@ -2,16 +2,17 @@ error[E0277]: `Foo` doesn't implement `std::fmt::Debug` --> $DIR/no-debug.rs:20:27 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `Foo` cannot be formatted using `:?`; add `#[derive(Debug)]` or manually implement `std::fmt::Debug` + | ^^^ `Foo` cannot be formatted using `{:?}` | = help: the trait `std::fmt::Debug` is not implemented for `Foo` + = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` = note: required by `std::fmt::Debug::fmt` error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Debug` --> $DIR/no-debug.rs:20:32 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `no_debug::Bar` cannot be formatted using `:?` because it doesn't implement `std::fmt::Debug` + | ^^^ `no_debug::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `no_debug::Bar` = note: required by `std::fmt::Debug::fmt` @@ -20,18 +21,20 @@ error[E0277]: `Foo` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:21:23 | LL | println!("{} {}", Foo, Bar); - | ^^^ `Foo` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string + | ^^^ `Foo` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `Foo` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: required by `std::fmt::Display::fmt` error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:21:28 | LL | println!("{} {}", Foo, Bar); - | ^^^ `no_debug::Bar` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string + | ^^^ `no_debug::Bar` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for `no_debug::Bar` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: required by `std::fmt::Display::fmt` error: aborting due to 4 previous errors diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 9f238929215..6b548742fb3 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -57,6 +57,7 @@ "arm-unknown-linux-musleabi", "arm-unknown-linux-musleabihf", "armv5te-unknown-linux-gnueabi", + "armv5te-unknown-linux-musleabi", "armv7-apple-ios", "armv7-linux-androideabi", "armv7-unknown-cloudabi-eabihf", diff --git a/src/tools/cargo b/src/tools/cargo index af3f1cd29bc..9e53ac6e652 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit af3f1cd29bc872b932a13083e531255aab233a7e +Subproject commit 9e53ac6e6525da914cb05a85e5e8eff7b5dca81f diff --git a/src/tools/clippy b/src/tools/clippy index 1742229ebb7..e456241f182 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 1742229ebb7843a65c05ee495d8de5366fcc5567 +Subproject commit e456241f18227c7eb8d78a45daa66c756a9b65e7 diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 77554f244c8..45cb147fbbc 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -19,5 +19,6 @@ rustfix = "0.2" libc = "0.2" [target.'cfg(windows)'.dependencies] +lazy_static = "1.0" miow = "0.3" winapi = { version = "0.3", features = ["winerror"] } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 7ac3f5b5b25..32980a513f6 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -425,6 +425,15 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) { if testfile.is_dir() { return; } + + let comment = if testfile.to_string_lossy().ends_with(".rs") { + "//" + } else { + "#" + }; + + let comment_with_brace = comment.to_string() + "["; + let rdr = BufReader::new(File::open(testfile).unwrap()); for ln in rdr.lines() { // Assume that any directives will be found before the first @@ -434,10 +443,11 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) { let ln = ln.trim(); if ln.starts_with("fn") || ln.starts_with("mod") { return; - } else if ln.starts_with("//[") { + } else if ln.starts_with(&comment_with_brace) { // A comment like `//[foo]` is specific to revision `foo` if let Some(close_brace) = ln.find(']') { - let lncfg = &ln[3..close_brace]; + let open_brace = ln.find('[').unwrap(); + let lncfg = &ln[open_brace + 1 .. close_brace]; let matches = match cfg { Some(s) => s == &lncfg[..], None => false, @@ -446,11 +456,11 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) { it(ln[(close_brace + 1) ..].trim_left()); } } else { - panic!("malformed condition directive: expected `//[foo]`, found `{}`", - ln) + panic!("malformed condition directive: expected `{}foo]`, found `{}`", + comment_with_brace, ln) } - } else if ln.starts_with("//") { - it(ln[2..].trim_left()); + } else if ln.starts_with(comment) { + it(ln[comment.len() ..].trim_left()); } } return; diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index a7849d53c3d..e8b140978b5 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -23,6 +23,9 @@ extern crate log; extern crate regex; #[macro_use] +#[cfg(windows)] +extern crate lazy_static; +#[macro_use] extern crate serde_derive; extern crate serde_json; extern crate test; @@ -611,7 +614,12 @@ pub fn is_test(file_name: &OsString) -> bool { } pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn { - let early_props = EarlyProps::from_file(config, &testpaths.file); + + let early_props = if config.mode == Mode::RunMake { + EarlyProps::from_file(config, &testpaths.file.join("Makefile")) + } else { + EarlyProps::from_file(config, &testpaths.file) + }; // The `should-fail` annotation doesn't apply to pretty tests, // since we run the pretty printer across all tests by default. diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index fae75c352da..1bac9ef66bb 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -38,6 +38,39 @@ use extract_gdb_version; +#[cfg(windows)] +fn disable_error_reporting R, R>(f: F) -> R { + use std::sync::Mutex; + const SEM_NOGPFAULTERRORBOX: u32 = 0x0002; + extern "system" { + fn SetErrorMode(mode: u32) -> u32; + } + + lazy_static! { + static ref LOCK: Mutex<()> = { + Mutex::new(()) + }; + } + // Error mode is a global variable, so lock it so only one thread will change it + let _lock = LOCK.lock().unwrap(); + + // Tell Windows to not show any UI on errors (such as terminating abnormally). + // This is important for running tests, since some of them use abnormal + // termination by design. This mode is inherited by all child processes. + unsafe { + let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX); // read inherited flags + SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX); + let r = f(); + SetErrorMode(old_mode); + r + } +} + +#[cfg(not(windows))] +fn disable_error_reporting R, R>(f: F) -> R { + f() +} + /// The name of the environment variable that holds dynamic library locations. pub fn dylib_env_var() -> &'static str { if cfg!(windows) { @@ -1578,8 +1611,7 @@ fn compose_and_run( let newpath = env::join_paths(&path).unwrap(); command.env(dylib_env_var(), newpath); - let mut child = command - .spawn() + let mut child = disable_error_reporting(|| command.spawn()) .expect(&format!("failed to exec `{:?}`", &command)); if let Some(input) = input { child diff --git a/src/tools/miri b/src/tools/miri index f48fed70d44..e0e1bd7ff77 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit f48fed70d4447445b586a35c4ae88683542ffc72 +Subproject commit e0e1bd7ff778e5913b566c9e03224faecc0eb486 diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 8e23519f57e..1539c2e2578 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -86,7 +86,7 @@ def update_latest( .format(tool, os, old, new) elif new < old: changed = True - message += '💔 {} on {}: {} → {} (cc {}).\n' \ + message += '💔 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \ .format(tool, os, old, new, MAINTAINERS.get(tool)) if changed: diff --git a/src/tools/rls b/src/tools/rls index d2f44357fef..d2ade31a52a 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit d2f44357fef6d61f316abc403e0a5d917f2771c6 +Subproject commit d2ade31a52a417257742de72c5936a8a342a34b5 diff --git a/src/tools/rustfmt b/src/tools/rustfmt index b6cd17f28ae..0f8029f251b 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit b6cd17f28ae314f2484ff05d3ce57652d51c5e85 +Subproject commit 0f8029f251b569a010cb5cfc5a8bff8bf3c949ac diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 8caf39fc27b..9a87fcb00d5 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -73,6 +73,7 @@ Crate("flate2"), Crate("fuchsia-zircon"), Crate("fuchsia-zircon-sys"), + Crate("getopts"), Crate("humantime"), Crate("jobserver"), Crate("kernel32-sys"), diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index fa227436640..022ef57503a 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -51,6 +51,7 @@ macro_rules! tidy_error { pub mod deps; pub mod ui_tests; pub mod unstable_book; +pub mod libcoretest; fn filter_dirs(path: &Path) -> bool { let skip = [ diff --git a/src/tools/tidy/src/libcoretest.rs b/src/tools/tidy/src/libcoretest.rs new file mode 100644 index 00000000000..ef8b55186b1 --- /dev/null +++ b/src/tools/tidy/src/libcoretest.rs @@ -0,0 +1,34 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Tidy check to ensure `#[test]` is not used directly inside `libcore`. +//! +//! `#![no_core]` libraries cannot be tested directly due to duplicating lang +//! item. All tests must be written externally in `libcore/tests`. + +use std::path::Path; +use std::fs::read_to_string; + +pub fn check(path: &Path, bad: &mut bool) { + let libcore_path = path.join("libcore"); + super::walk( + &libcore_path, + &mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"), + &mut |subpath| { + if t!(read_to_string(subpath)).contains("#[test]") { + tidy_error!( + bad, + "{} contains #[test]; libcore tests must be placed inside `src/libcore/tests/`", + subpath.display() + ); + } + }, + ); +} diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 24974192795..7b86650823a 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -41,6 +41,7 @@ fn main() { features::check(&path, &mut bad, quiet); pal::check(&path, &mut bad); unstable_book::check(&path, &mut bad); + libcoretest::check(&path, &mut bad); if !args.iter().any(|s| *s == "--no-vendor") { deps::check(&path, &mut bad); }