diff options
179 files changed, 2480 insertions, 981 deletions
diff --git a/config.toml.example b/config.toml.example index 1d60d8c9494..9ca0f563d0a 100644 --- a/config.toml.example +++ b/config.toml.example @@ -312,6 +312,11 @@ # bootstrap) #codegen-backends = ["llvm"] +# Flag indicating whether `libstd` calls an imported function to hande basic IO +# when targetting WebAssembly. Enable this to debug tests for the `wasm32-unknown-unknown` +# target, as without this option the test output will not be captured. +#wasm-syscall = false + # ============================================================================= # Options for specific targets # diff --git a/src/Cargo.lock b/src/Cargo.lock index d26098903ee..fc89cc4ea9e 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1618,7 +1618,7 @@ version = "0.1.0" [[package]] name = "rls" -version = "0.124.0" +version = "0.125.0" dependencies = [ "cargo 0.26.0", "env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1635,7 +1635,7 @@ dependencies = [ "rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 0.3.6", + "rustfmt-nightly 0.3.8", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1723,7 +1723,7 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_cratesio_shim" -version = "12.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1732,57 +1732,57 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_data_structures" -version = "12.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_errors" -version = "12.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-serialize" -version = "12.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-ap-syntax" -version = "12.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-syntax_pos" -version = "12.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2207,7 +2207,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "0.3.6" +version = "0.3.8" dependencies = [ "cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2219,8 +2219,8 @@ dependencies = [ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3068,12 +3068,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "85cfb9dde19e313da3e47738008f8a472e470cc42d910b71595a9238494701f2" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff" -"checksum rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a51c10af5abd5d698b7e3487e869e6d15f6feb04cbedb5c792e2824f9d845e" -"checksum rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1aa227490501072780d57f74b1164d361833ff8e172f817da0da2cdf2e4280cc" -"checksum rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21ff6c6e13ac4fc04b7d4d398828b024c4b6577045cb3175b33d35fea35ff6d0" -"checksum rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b4e7f51e298675c2bf830f7265621a8936fb09e63b825b58144cbaac969e604" -"checksum rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8bf5639869ba2f7fa581939cd217cb71a85506b82ad0ea520614fb0dceb2386c" -"checksum rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c020cdb7379e1c733ae0a311ae47c748337ba584d2dd7b7f53baaae78de6f8b" +"checksum rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ad5e562044ea78a6764dd75ae8afe4b21fde49f4548024b5fdf6345c21fb524" +"checksum rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c0d65325492aba7db72899e3edbab34d39af98c42ab7c7e450c9a288ffe4ad" +"checksum rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87d4ab2e06a671b5b5c5b0359dac346f164c99d059dce6a22feb08f2f56bd182" +"checksum rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e0745fa445ff41c4b6699936cf35ce3ca49502377dd7b3929c829594772c3a7b" +"checksum rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82efedabe30f393161e11214a9130edfa01ad476372d1c6f3fec1f8d30488c9d" +"checksum rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db9de2e927e280c75b8efab9c5f591ad31082d5d2c4c562c68fdba2ee77286b0" "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 1272643edd2..780513dd943 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -377,6 +377,11 @@ impl<'a> Builder<'a> { self.ensure(Libdir { compiler, target }) } + pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf { + self.sysroot_libdir(compiler, compiler.host) + .with_file_name("codegen-backends") + } + /// Returns the compiler's libdir where it stores the dynamic libraries that /// it itself links against. /// diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index fa289bbd76a..1d5e11c5d6d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -724,8 +724,7 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder, // // Here we're looking for the output dylib of the `CodegenBackend` step and // we're copying that into the `codegen-backends` folder. - let libdir = builder.sysroot_libdir(target_compiler, target); - let dst = libdir.join("codegen-backends"); + let dst = builder.sysroot_codegen_backends(target_compiler); t!(fs::create_dir_all(&dst)); for backend in builder.config.rust_codegen_backends.iter() { diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index dbeb27cbfb7..0da04bebac5 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -107,6 +107,7 @@ pub struct Config { pub debug_jemalloc: bool, pub use_jemalloc: bool, pub backtrace: bool, // support for RUST_BACKTRACE + pub wasm_syscall: bool, // misc pub low_priority: bool, @@ -282,6 +283,7 @@ struct Rust { test_miri: Option<bool>, save_toolstates: Option<String>, codegen_backends: Option<Vec<String>>, + wasm_syscall: Option<bool>, } /// TOML representation of how each build target is configured. @@ -463,6 +465,7 @@ impl Config { set(&mut config.rust_dist_src, rust.dist_src); set(&mut config.quiet_tests, rust.quiet_tests); set(&mut config.test_miri, rust.test_miri); + set(&mut config.wasm_syscall, rust.wasm_syscall); config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false); config.rustc_default_linker = rust.default_linker.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 4127239dc49..dbb7d19e432 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -435,11 +435,9 @@ impl Step for Rustc { } // Copy over the codegen backends - let backends_src = builder.sysroot_libdir(compiler, host) - .join("codegen-backends"); - let backends_dst = image.join("lib/rustlib") - .join(&*host) - .join("lib/codegen-backends"); + let backends_src = builder.sysroot_codegen_backends(compiler); + let backends_rel = backends_src.strip_prefix(&src).unwrap(); + let backends_dst = image.join(&backends_rel); t!(fs::create_dir_all(&backends_dst)); cp_r(&backends_src, &backends_dst); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index aae0a4f056f..f2a7ce30c8a 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -423,6 +423,9 @@ impl Build { if self.config.profiler { features.push_str(" profiler"); } + if self.config.wasm_syscall { + features.push_str(" wasm_syscall"); + } features } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index a316b0f7ef9..e4c1cdb79fd 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -610,7 +610,6 @@ static HOST_COMPILETESTS: &[Test] = &[ mode: "incremental", suite: "incremental-fulldeps", }, - Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" }, Test { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" }, Test { path: "src/test/pretty", mode: "pretty", suite: "pretty" }, @@ -619,6 +618,7 @@ static HOST_COMPILETESTS: &[Test] = &[ Test { path: "src/test/run-pass-valgrind/pretty", mode: "pretty", suite: "run-pass-valgrind" }, Test { path: "src/test/run-pass-fulldeps/pretty", mode: "pretty", suite: "run-pass-fulldeps" }, Test { path: "src/test/run-fail-fulldeps/pretty", mode: "pretty", suite: "run-fail-fulldeps" }, + Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" }, ]; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -1286,6 +1286,14 @@ impl Step for Crate { cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), build.config.nodejs.as_ref().expect("nodejs not configured")); } else if target.starts_with("wasm32") { + // Warn about running tests without the `wasm_syscall` feature enabled. + // The javascript shim implements the syscall interface so that test + // output can be correctly reported. + if !build.config.wasm_syscall { + println!("Libstd was built without `wasm_syscall` feature enabled: \ + test output may not be visible."); + } + // On the wasm32-unknown-unknown target we're using LTO which is // incompatible with `-C prefer-dynamic`, so disable that here cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index 0137a052a62..c5167418614 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -37,28 +37,23 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { p } -#[lang = "exchange_free"] -unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { - libc::free(ptr as *mut libc::c_void) -} - #[lang = "box_free"] unsafe fn box_free<T: ?Sized>(ptr: *mut T) { - deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr)); + libc::free(ptr as *mut libc::c_void) } #[start] -fn main(argc: isize, argv: *const *const u8) -> isize { - let x = box 1; +fn main(_argc: isize, _argv: *const *const u8) -> isize { + let _x = box 1; 0 } #[lang = "eh_personality"] extern fn rust_eh_personality() {} #[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } } -# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} -# #[no_mangle] pub extern fn rust_eh_register_frames () {} -# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} +#[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} +#[no_mangle] pub extern fn rust_eh_register_frames () {} +#[no_mangle] pub extern fn rust_eh_unregister_frames () {} ``` Note the use of `abort`: the `exchange_malloc` lang item is assumed to @@ -80,7 +75,7 @@ Other features provided by lang items include: Lang items are loaded lazily by the compiler; e.g. if one never uses `Box` then there is no need to define functions for `exchange_malloc` -and `exchange_free`. `rustc` will emit an error when an item is needed +and `box_free`. `rustc` will emit an error when an item is needed but not found in the current crate or any that it depends on. Most lang items are defined by `libcore`, but if you're trying to build @@ -318,4 +313,4 @@ the source code. - `phantom_data`: `libcore/marker.rs` - `freeze`: `libcore/marker.rs` - `debug_trait`: `libcore/fmt/mod.rs` - - `non_zero`: `libcore/nonzero.rs` \ No newline at end of file + - `non_zero`: `libcore/nonzero.rs` diff --git a/src/doc/unstable-book/src/language-features/match-beginning-vert.md b/src/doc/unstable-book/src/language-features/match-beginning-vert.md deleted file mode 100644 index f0a51af7fd1..00000000000 --- a/src/doc/unstable-book/src/language-features/match-beginning-vert.md +++ /dev/null @@ -1,23 +0,0 @@ -# `match_beginning_vert` - -The tracking issue for this feature is [#44101]. - -With this feature enabled, you are allowed to add a '|' to the beginning of a -match arm: - -```rust -#![feature(match_beginning_vert)] - -enum Foo { A, B, C } - -fn main() { - let x = Foo::A; - match x { - | Foo::A - | Foo::B => println!("AB"), - | Foo::C => println!("C"), - } -} -``` - -[#44101]: https://github.com/rust-lang/rust/issues/44101 \ No newline at end of file diff --git a/src/etc/wasm32-shim.js b/src/etc/wasm32-shim.js index d55083e0f8e..69647f37eec 100644 --- a/src/etc/wasm32-shim.js +++ b/src/etc/wasm32-shim.js @@ -28,14 +28,76 @@ let m = new WebAssembly.Module(buffer); let memory = null; +function viewstruct(data, fields) { + return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields); +} + function copystr(a, b) { - if (memory === null) { - return null - } - let view = new Uint8Array(memory.buffer).slice(a, a + b); + let view = new Uint8Array(memory.buffer).subarray(a, a + b); return String.fromCharCode.apply(null, view); } +function syscall_write([fd, ptr, len]) { + let s = copystr(ptr, len); + switch (fd) { + case 1: process.stdout.write(s); break; + case 2: process.stderr.write(s); break; + } +} + +function syscall_exit([code]) { + process.exit(code); +} + +function syscall_args(params) { + let [ptr, len] = params; + + // Calculate total required buffer size + let totalLen = -1; + for (let i = 2; i < process.argv.length; ++i) { + totalLen += Buffer.byteLength(process.argv[i]) + 1; + } + if (totalLen < 0) { totalLen = 0; } + params[2] = totalLen; + + // If buffer is large enough, copy data + if (len >= totalLen) { + let view = new Uint8Array(memory.buffer); + for (let i = 2; i < process.argv.length; ++i) { + let value = process.argv[i]; + Buffer.from(value).copy(view, ptr); + ptr += Buffer.byteLength(process.argv[i]) + 1; + } + } +} + +function syscall_getenv(params) { + let [keyPtr, keyLen, valuePtr, valueLen] = params; + + let key = copystr(keyPtr, keyLen); + let value = process.env[key]; + + if (value == null) { + params[4] = 0xFFFFFFFF; + } else { + let view = new Uint8Array(memory.buffer); + let totalLen = Buffer.byteLength(value); + params[4] = totalLen; + if (valueLen >= totalLen) { + Buffer.from(value).copy(view, valuePtr); + } + } +} + +function syscall_time(params) { + let t = Date.now(); + let secs = Math.floor(t / 1000); + let millis = t % 1000; + params[1] = Math.floor(secs / 0x100000000); + params[2] = secs % 0x100000000; + params[3] = Math.floor(millis * 1000000); +} + let imports = {}; imports.env = { // These are generated by LLVM itself for various intrinsic calls. Hopefully @@ -48,68 +110,25 @@ imports.env = { log10: Math.log10, log10f: Math.log10, - // These are called in src/libstd/sys/wasm/stdio.rs and are used when - // debugging is enabled. - rust_wasm_write_stdout: function(a, b) { - let s = copystr(a, b); - if (s !== null) { - process.stdout.write(s); - } - }, - rust_wasm_write_stderr: function(a, b) { - let s = copystr(a, b); - if (s !== null) { - process.stderr.write(s); - } - }, - - // These are called in src/libstd/sys/wasm/args.rs and are used when - // debugging is enabled. - rust_wasm_args_count: function() { - if (memory === null) - return 0; - return process.argv.length - 2; - }, - rust_wasm_args_arg_size: function(i) { - return Buffer.byteLength(process.argv[i + 2]); - }, - rust_wasm_args_arg_fill: function(idx, ptr) { - let arg = process.argv[idx + 2]; - let view = new Uint8Array(memory.buffer); - Buffer.from(arg).copy(view, ptr); - }, - - // These are called in src/libstd/sys/wasm/os.rs and are used when - // debugging is enabled. - rust_wasm_getenv_len: function(a, b) { - let key = copystr(a, b); - if (key === null) { - return -1; + rust_wasm_syscall: function(index, data) { + switch (index) { + case 1: syscall_write(viewstruct(data, 3)); return true; + case 2: syscall_exit(viewstruct(data, 1)); return true; + case 3: syscall_args(viewstruct(data, 3)); return true; + case 4: syscall_getenv(viewstruct(data, 5)); return true; + case 6: syscall_time(viewstruct(data, 4)); return true; + default: + console.log("Unsupported syscall: " + index); + return false; } - if (!(key in process.env)) { - return -1; - } - return Buffer.byteLength(process.env[key]); - }, - rust_wasm_getenv_data: function(a, b, ptr) { - let key = copystr(a, b); - let value = process.env[key]; - let view = new Uint8Array(memory.buffer); - Buffer.from(value).copy(view, ptr); - }, -}; - -let module_imports = WebAssembly.Module.imports(m); - -for (var i = 0; i < module_imports.length; i++) { - let imp = module_imports[i]; - if (imp.module != 'env') { - continue } - if (imp.name == 'memory' && imp.kind == 'memory') { - memory = new WebAssembly.Memory({initial: 20}); - imports.env.memory = memory; - } -} +}; let instance = new WebAssembly.Instance(m, imports); +memory = instance.exports.memory; +try { + instance.exports.main(); +} catch (e) { + console.error(e); + process.exit(101); +} diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 65aacb23bd7..6c8a1c3062b 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1586,6 +1586,7 @@ impl Display for ! { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for bool { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { Display::fmt(self, f) } @@ -1748,6 +1749,7 @@ impl<T: Debug> Debug for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for () { + #[inline] fn fmt(&self, f: &mut Formatter) -> Result { f.pad("()") } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index ee989854a37..2992e7cf8db 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -157,6 +157,7 @@ macro_rules! debug { ($T:ident) => { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for $T { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index a611dc02469..a05d67a304f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -992,7 +992,7 @@ extern "rust-intrinsic" { /// ptr::copy_nonoverlapping(y, x, 1); /// ptr::copy_nonoverlapping(&t, y, 1); /// - /// // y and t now point to the same thing, but we need to completely forget `tmp` + /// // y and t now point to the same thing, but we need to completely forget `t` /// // because it's no longer relevant. /// mem::forget(t); /// } diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 06c29b47bf9..7314fac282b 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -307,6 +307,7 @@ use fmt; use iter_private::TrustedRandomAccess; use ops::Try; use usize; +use intrinsics; #[stable(feature = "rust1", since = "1.0.0")] pub use self::iterator::Iterator; @@ -694,6 +695,49 @@ impl<I> Iterator for StepBy<I> where I: Iterator { (f(inner_hint.0), inner_hint.1.map(f)) } } + + #[inline] + fn nth(&mut self, mut n: usize) -> Option<Self::Item> { + if self.first_take { + self.first_take = false; + let first = self.iter.next(); + if n == 0 { + return first; + } + n -= 1; + } + // n and self.step are indices, we need to add 1 to get the amount of elements + // When calling `.nth`, we need to subtract 1 again to convert back to an index + // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1` + let mut step = self.step + 1; + // n + 1 could overflow + // thus, if n is usize::MAX, instead of adding one, we call .nth(step) + if n == usize::MAX { + self.iter.nth(step - 1); + } else { + n += 1; + } + + // overflow handling + loop { + let mul = n.checked_mul(step); + if unsafe { intrinsics::likely(mul.is_some()) } { + return self.iter.nth(mul.unwrap() - 1); + } + let div_n = usize::MAX / n; + let div_step = usize::MAX / step; + let nth_n = div_n * n; + let nth_step = div_step * step; + let nth = if nth_n > nth_step { + step -= div_n; + nth_n + } else { + n -= div_step; + nth_step + }; + self.iter.nth(nth - 1); + } + } } // StepBy can only make the iterator shorter, so the len will still fit. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 7f094e580ab..59a296c2a76 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -169,6 +169,7 @@ pub mod slice; pub mod str; pub mod hash; pub mod fmt; +pub mod time; // note: does not need to be public mod char_private; diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 93f6a0214d7..21a0beccbf6 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -189,6 +189,7 @@ pub fn forget<T>(t: T) { /// Type | size_of::\<Type>() /// ---- | --------------- /// () | 0 +/// bool | 1 /// u8 | 1 /// u16 | 2 /// u32 | 4 diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 207df84d080..3586fa5442f 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -239,7 +239,9 @@ impl Float for f32 { /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f32 { - self * (180.0f32 / consts::PI) + // Use a constant for better precision. + const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; + self * PIS_IN_180 } /// Converts to radians, assuming the number is in degrees. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 9206132e8b4..64c0d508b38 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -237,6 +237,9 @@ impl Float for f64 { /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f64 { + // The division here is correctly rounded with respect to the true + // value of 180/π. (This differs from f32, where a constant must be + // used to ensure a correctly rounded result.) self * (180.0f64 / consts::PI) } diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 8997cf9c6bf..e52e119ff59 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -162,6 +162,68 @@ fn test_iterator_step_by() { } #[test] +fn test_iterator_step_by_nth() { + let mut it = (0..16).step_by(5); + assert_eq!(it.nth(0), Some(0)); + assert_eq!(it.nth(0), Some(5)); + assert_eq!(it.nth(0), Some(10)); + assert_eq!(it.nth(0), Some(15)); + assert_eq!(it.nth(0), None); + + let it = (0..18).step_by(5); + assert_eq!(it.clone().nth(0), Some(0)); + assert_eq!(it.clone().nth(1), Some(5)); + assert_eq!(it.clone().nth(2), Some(10)); + assert_eq!(it.clone().nth(3), Some(15)); + assert_eq!(it.clone().nth(4), None); + assert_eq!(it.clone().nth(42), None); +} + +#[test] +fn test_iterator_step_by_nth_overflow() { + #[cfg(target_pointer_width = "8")] + type Bigger = u16; + #[cfg(target_pointer_width = "16")] + type Bigger = u32; + #[cfg(target_pointer_width = "32")] + type Bigger = u64; + #[cfg(target_pointer_width = "64")] + type Bigger = u128; + + #[derive(Clone)] + struct Test(Bigger); + impl<'a> Iterator for &'a mut Test { + type Item = i32; + fn next(&mut self) -> Option<Self::Item> { Some(21) } + fn nth(&mut self, n: usize) -> Option<Self::Item> { + self.0 += n as Bigger + 1; + Some(42) + } + } + + let mut it = Test(0); + let root = usize::MAX >> (::std::mem::size_of::<usize>() * 8 / 2); + let n = root + 20; + (&mut it).step_by(n).nth(n); + assert_eq!(it.0, n as Bigger * n as Bigger); + + // large step + let mut it = Test(0); + (&mut it).step_by(usize::MAX).nth(5); + assert_eq!(it.0, (usize::MAX as Bigger) * 5); + + // n + 1 overflows + let mut it = Test(0); + (&mut it).step_by(2).nth(usize::MAX); + assert_eq!(it.0, (usize::MAX as Bigger) * 2); + + // n + 1 overflows + let mut it = Test(0); + (&mut it).step_by(1).nth(usize::MAX); + assert_eq!(it.0, (usize::MAX as Bigger) * 1); +} + +#[test] #[should_panic] fn test_iterator_step_by_zero() { let mut it = (0..).step_by(0); diff --git a/src/libstd/time/duration.rs b/src/libcore/time.rs index ee444830be4..1a0208d2f25 100644 --- a/src/libstd/time/duration.rs +++ b/src/libcore/time.rs @@ -7,6 +7,19 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. +#![stable(feature = "duration_core", since = "1.24.0")] + +//! Temporal quantification. +//! +//! Example: +//! +//! ``` +//! use std::time::Duration; +//! +//! let five_seconds = Duration::new(5, 0); +//! // both declarations are equivalent +//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); +//! ``` use iter::Sum; use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; @@ -45,7 +58,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// /// let ten_millis = Duration::from_millis(10); /// ``` -#[stable(feature = "duration", since = "1.3.0")] +#[stable(feature = "duration_core", since = "1.24.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] pub struct Duration { secs: u64, diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index c3bd6a2bc18..5f768ef4399 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -27,10 +27,12 @@ #![feature(libc)] #![feature(panic_runtime)] #![feature(staged_api)] +#![feature(rustc_attrs)] // Rust's "try" function, but if we're aborting on panics we just call the // function as there's nothing else we need to do here. #[no_mangle] +#[rustc_std_internal_symbol] pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, _data_ptr: *mut usize, @@ -50,6 +52,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8), // will kill us with an illegal instruction, which will do a good enough job for // now hopefully. #[no_mangle] +#[rustc_std_internal_symbol] pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { abort(); diff --git a/src/librustc/README.md b/src/librustc/README.md index ddf71a06d60..722456a76ce 100644 --- a/src/librustc/README.md +++ b/src/librustc/README.md @@ -176,6 +176,7 @@ pointers for understanding them better. - `'gcx` -- the lifetime of the global arena (see `librustc/ty`). - generics -- the set of generic type parameters defined on a type or item - ICE -- internal compiler error. When the compiler crashes. +- ICH -- incremental compilation hash. - infcx -- the inference context (see `librustc/infer`) - MIR -- the **Mid-level IR** that is created after type-checking for use by borrowck and trans. Defined in the `src/librustc/mir/` module, but much of the code that manipulates it is diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 1de9091b5df..4034055d041 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -639,6 +639,9 @@ define_dep_nodes!( <'tcx> [] TargetFeaturesEnabled(DefId), [] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> }, + + [] GetSymbolExportLevel(DefId), + ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index b10e7425957..03fc40b2e39 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -175,25 +175,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::ReEarlyBound(_) | ty::ReFree(_) => { let scope = region.free_region_binding_scope(self); - let prefix = match *region { - ty::ReEarlyBound(ref br) => { - format!("the lifetime {} as defined on", br.name) - } - ty::ReFree(ref fr) => { - match fr.bound_region { - ty::BrAnon(idx) => { - format!("the anonymous lifetime #{} defined on", idx + 1) - } - ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(), - _ => { - format!("the lifetime {} as defined on", - fr.bound_region) - } - } - } - _ => bug!() - }; - let node = self.hir.as_local_node_id(scope) .unwrap_or(DUMMY_NODE_ID); let unknown; @@ -218,7 +199,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { &unknown } }; - let (msg, opt_span) = explain_span(self, tag, self.hir.span(node)); + let (prefix, span) = match *region { + ty::ReEarlyBound(ref br) => { + (format!("the lifetime {} as defined on", br.name), + self.sess.codemap().def_span(self.hir.span(node))) + } + ty::ReFree(ref fr) => { + match fr.bound_region { + ty::BrAnon(idx) => { + (format!("the anonymous lifetime #{} defined on", idx + 1), + self.hir.span(node)) + } + ty::BrFresh(_) => ("an anonymous lifetime defined on".to_owned(), + self.hir.span(node)), + _ => (format!("the lifetime {} as defined on", fr.bound_region), + self.sess.codemap().def_span(self.hir.span(node))), + } + } + _ => bug!() + }; + let (msg, opt_span) = explain_span(self, tag, span); (format!("{} {}", prefix, msg), opt_span) } @@ -807,7 +807,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } }; - let span = cause.span; + let span = cause.span(&self.tcx); diag.span_label(span, terr.to_string()); if let Some((sp, msg)) = secondary_span { @@ -842,7 +842,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "did you mean `{}(/* fields */)`?", self.tcx.item_path_str(def_id) ); - diag.span_label(cause.span, message); + diag.span_label(span, message); } } } @@ -870,7 +870,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trace, terr); - let span = trace.cause.span; + let span = trace.cause.span(&self.tcx); let failure_code = trace.cause.as_failure_code(terr); let mut diag = match failure_code { FailureCode::Error0317(failure_str) => { @@ -1076,6 +1076,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { sup_region, "..."); + match (&sup_origin, &sub_origin) { + (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => { + if let (Some((sup_expected, sup_found)), + Some((sub_expected, sub_found))) = (self.values_str(&sup_trace.values), + self.values_str(&sub_trace.values)) { + if sub_expected == sup_expected && sub_found == sup_found { + self.tcx.note_and_explain_region( + region_scope_tree, + &mut err, + "...but the lifetime must also be valid for ", + sub_region, + "...", + ); + err.note(&format!("...so that the {}:\nexpected {}\n found {}", + sup_trace.cause.as_requirement_str(), + sup_expected.content(), + sup_found.content())); + err.emit(); + return; + } + } + } + _ => {} + } + self.note_region_origin(&mut err, &sup_origin); self.tcx.note_and_explain_region(region_scope_tree, &mut err, diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index e46613b3e4d..02ec9fe74c1 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -23,12 +23,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some((expected, found)) = self.values_str(&trace.values) { let expected = expected.content(); let found = found.content(); - // FIXME: do we want a "the" here? - err.span_note(trace.cause.span, - &format!("...so that {} (expected {}, found {})", - trace.cause.as_requirement_str(), - expected, - found)); + err.note(&format!("...so that the {}:\nexpected {}\n found {}", + trace.cause.as_requirement_str(), + expected, + found)); } else { // FIXME: this really should be handled at some earlier stage. Our // handling of region checking when type errors are present is diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d727dfb0c4b..db6863d6dad 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -66,6 +66,7 @@ #![feature(specialization)] #![feature(unboxed_closures)] #![feature(underscore_lifetimes)] +#![feature(universal_impl_trait)] #![feature(trace_macros)] #![feature(catch_expr)] #![feature(test)] diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 143d2c2ea28..0577800f3f4 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -246,6 +246,12 @@ declare_lint! { "raw pointer to an inference variable" } +declare_lint! { + pub ELIDED_LIFETIME_IN_PATH, + Allow, + "hidden lifetime parameters are deprecated, try `Foo<'_>`" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -291,7 +297,9 @@ impl LintPass for HardwiredLints { UNUSED_MUT, COERCE_NEVER, SINGLE_USE_LIFETIME, - TYVAR_BEHIND_RAW_POINTER + TYVAR_BEHIND_RAW_POINTER, + ELIDED_LIFETIME_IN_PATH + ) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 5336c1944e8..929d5e7ec62 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -631,7 +631,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for &'a LateContext<'a, 'tcx> { type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - (self.tcx, self.param_env.reveal_all()).layout_of(ty) + self.tcx.layout_of(self.param_env.and(ty)) } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index dad2d7a7c90..e5619f469e7 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -467,9 +467,13 @@ impl<'tcx> Visitor<'tcx> for ExprLocatorVisitor { } fn visit_pat(&mut self, pat: &'tcx Pat) { + intravisit::walk_pat(self, pat); + self.expr_and_pat_count += 1; - intravisit::walk_pat(self, pat); + if pat.id == self.id { + self.result = Some(self.expr_and_pat_count); + } } fn visit_expr(&mut self, expr: &'tcx Expr) { @@ -814,7 +818,8 @@ impl<'tcx> ScopeTree { /// Checks whether the given scope contains a `yield`. If so, /// returns `Some((span, expr_count))` with the span of a yield we found and - /// the number of expressions appearing before the `yield` in the body. + /// the number of expressions and patterns appearing before the `yield` in the body + 1. + /// If there a are multiple yields in a scope, the one with the highest number is returned. pub fn yield_in_scope(&self, scope: Scope) -> Option<(Span, usize)> { self.yield_in_scope.get(&scope).cloned() } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 944d7705163..59460141166 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -737,7 +737,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { if lifetime_ref.is_elided() { - self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref)); + self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref), false); return; } if lifetime_ref.is_static() { @@ -1444,7 +1444,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } if params.lifetimes.iter().all(|l| l.is_elided()) { - self.resolve_elided_lifetimes(¶ms.lifetimes); + self.resolve_elided_lifetimes(¶ms.lifetimes, true); } else { for l in ¶ms.lifetimes { self.visit_lifetime(l); @@ -1803,14 +1803,24 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime]) { + fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime], deprecated: bool) { if lifetime_refs.is_empty() { return; } let span = lifetime_refs[0].span; + let id = lifetime_refs[0].id; let mut late_depth = 0; let mut scope = self.scope; + if deprecated { + self.tcx + .struct_span_lint_node( + lint::builtin::ELIDED_LIFETIME_IN_PATH, + id, + span, + &format!("hidden lifetime parameters are deprecated, try `Foo<'_>`")) + .emit(); + } let error = loop { match *scope { // Do not assign any resolution, it will be inferred. diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 3b644aa13f3..c0feb8ad020 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1825,7 +1825,7 @@ pub struct Location { /// the location is within this block pub block: BasicBlock, - /// the location is the start of the this statement; or, if `statement_index` + /// the location is the start of the statement; or, if `statement_index` /// == num-statements, then the start of the terminator. pub statement_index: usize, } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index b9546143a05..9543d01597d 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1288,6 +1288,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves"), + approximate_suggestions: bool = (false, parse_bool, [UNTRACKED], + "include machine-applicability of suggestions in JSON output"), unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED], "Present the input source, unstable (and less-pretty) variants; valid types are any of the types for `--pretty`, as well as: diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 2765239d5e6..f4a00a43d8d 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -904,22 +904,27 @@ pub fn build_session_with_codemap(sopts: config::Options, let emitter: Box<Emitter> = match (sopts.error_format, emitter_dest) { (config::ErrorOutputType::HumanReadable(color_config), None) => { - Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), false)) + Box::new(EmitterWriter::stderr(color_config, + Some(codemap.clone()), + false, + sopts.debugging_opts.teach)) } (config::ErrorOutputType::HumanReadable(_), Some(dst)) => { - Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false)) + Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false, false)) } (config::ErrorOutputType::Json(pretty), None) => { - Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), pretty)) + Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), + pretty, sopts.debugging_opts.approximate_suggestions)) } (config::ErrorOutputType::Json(pretty), Some(dst)) => { - Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), pretty)) + Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), + pretty, sopts.debugging_opts.approximate_suggestions)) } (config::ErrorOutputType::Short(color_config), None) => { - Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true)) + Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)) } (config::ErrorOutputType::Short(_), Some(dst)) => { - Box::new(EmitterWriter::new(dst, Some(codemap.clone()), true)) + Box::new(EmitterWriter::new(dst, Some(codemap.clone()), true, false)) } }; @@ -1095,11 +1100,11 @@ pub enum IncrCompSession { pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { let emitter: Box<Emitter> = match output { config::ErrorOutputType::HumanReadable(color_config) => { - Box::new(EmitterWriter::stderr(color_config, None, false)) + Box::new(EmitterWriter::stderr(color_config, None, false, false)) } config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)), config::ErrorOutputType::Short(color_config) => { - Box::new(EmitterWriter::stderr(color_config, None, true)) + Box::new(EmitterWriter::stderr(color_config, None, true, false)) } }; let handler = errors::Handler::with_emitter(true, false, emitter); @@ -1110,11 +1115,11 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { pub fn early_warn(output: config::ErrorOutputType, msg: &str) { let emitter: Box<Emitter> = match output { config::ErrorOutputType::HumanReadable(color_config) => { - Box::new(EmitterWriter::stderr(color_config, None, false)) + Box::new(EmitterWriter::stderr(color_config, None, false, false)) } config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)), config::ErrorOutputType::Short(color_config) => { - Box::new(EmitterWriter::stderr(color_config, None, true)) + Box::new(EmitterWriter::stderr(color_config, None, true, false)) } }; let handler = errors::Handler::with_emitter(true, false, emitter); diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index ae68e3fe8d0..9de18612d81 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -19,7 +19,7 @@ use ty::{self, Ty, TyCtxt}; use ty::fold::TypeFoldable; use ty::subst::Subst; -use infer::{InferCtxt, InferOk}; +use infer::{InferOk}; /// Whether we do the orphan check relative to this crate or /// to some remote crate. @@ -40,13 +40,20 @@ pub struct OverlapResult<'tcx> { pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, } -/// If there are types that satisfy both impls, returns a suitably-freshened -/// `ImplHeader` with those types substituted -pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>, - impl1_def_id: DefId, - impl2_def_id: DefId, - intercrate_mode: IntercrateMode) - -> Option<OverlapResult<'tcx>> +/// If there are types that satisfy both impls, invokes `on_overlap` +/// with a suitably-freshened `ImplHeader` with those types +/// substituted. Otherwise, invokes `no_overlap`. +pub fn overlapping_impls<'gcx, F1, F2, R>( + tcx: TyCtxt<'_, 'gcx, 'gcx>, + impl1_def_id: DefId, + impl2_def_id: DefId, + intercrate_mode: IntercrateMode, + on_overlap: F1, + no_overlap: F2, +) -> R +where + F1: FnOnce(OverlapResult<'_>) -> R, + F2: FnOnce() -> R, { debug!("impl_can_satisfy(\ impl1_def_id={:?}, \ @@ -56,8 +63,23 @@ pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>, impl2_def_id, intercrate_mode); - let selcx = &mut SelectionContext::intercrate(infcx, intercrate_mode); - overlap(selcx, impl1_def_id, impl2_def_id) + let overlaps = tcx.infer_ctxt().enter(|infcx| { + let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode); + overlap(selcx, impl1_def_id, impl2_def_id).is_some() + }); + + if !overlaps { + return no_overlap(); + } + + // In the case where we detect an error, run the check again, but + // this time tracking intercrate ambuiguity causes for better + // diagnostics. (These take time and can lead to false errors.) + tcx.infer_ctxt().enter(|infcx| { + let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode); + selcx.enable_tracking_intercrate_ambiguity_causes(); + on_overlap(overlap(selcx, impl1_def_id, impl2_def_id).unwrap()) + }) } fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, @@ -135,10 +157,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, return None } - Some(OverlapResult { - impl_header: selcx.infcx().resolve_type_vars_if_possible(&a_impl_header), - intercrate_ambiguity_causes: selcx.intercrate_ambiguity_causes().to_vec(), - }) + let impl_header = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header); + let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); + debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); + Some(OverlapResult { impl_header, intercrate_ambiguity_causes }) } pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 42200a3a447..7b86791026b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -831,6 +831,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span, node: hir::ImplItemKind::Method(hir::MethodSig { ref decl, .. }, _), .. + }) | + hir::map::NodeTraitItem(&hir::TraitItem { + span, + node: hir::TraitItemKind::Method(hir::MethodSig { ref decl, .. }, _), + .. }) => { (self.tcx.sess.codemap().def_span(span), decl.inputs.iter() .map(|arg| match arg.clone().into_inner().node { @@ -1261,6 +1266,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.note("the return type of a function must have a \ statically known size"); } + ObligationCauseCode::SizedYieldType => { + err.note("the yield type of a generator must have a \ + statically known size"); + } ObligationCauseCode::AssignmentLhsSized => { err.note("the left-hand-side of an assignment must have a statically known size"); } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index fd47e09aad7..80819a86b7c 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -100,6 +100,19 @@ pub struct ObligationCause<'tcx> { pub code: ObligationCauseCode<'tcx> } +impl<'tcx> ObligationCause<'tcx> { + pub fn span<'a, 'gcx>(&self, tcx: &TyCtxt<'a, 'gcx, 'tcx>) -> Span { + match self.code { + ObligationCauseCode::CompareImplMethodObligation { .. } | + ObligationCauseCode::MainFunctionType | + ObligationCauseCode::StartFunctionType => { + tcx.sess.codemap().def_span(self.span) + } + _ => self.span, + } + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. @@ -138,6 +151,8 @@ pub enum ObligationCauseCode<'tcx> { VariableType(ast::NodeId), /// Return type must be Sized SizedReturnType, + /// Yield type must be Sized + SizedYieldType, /// [T,..n] --> T must be Copy RepeatVec, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 55cbc890e1e..4ed25646d43 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -92,10 +92,10 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { inferred_obligations: SnapshotVec<InferredObligationsSnapshotVecDelegate<'tcx>>, - intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, + intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum IntercrateAmbiguityCause { DownstreamCrate { trait_desc: String, @@ -423,7 +423,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { freshener: infcx.freshener(), intercrate: None, inferred_obligations: SnapshotVec::new(), - intercrate_ambiguity_causes: Vec::new(), + intercrate_ambiguity_causes: None, } } @@ -435,10 +435,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { freshener: infcx.freshener(), intercrate: Some(mode), inferred_obligations: SnapshotVec::new(), - intercrate_ambiguity_causes: Vec::new(), + intercrate_ambiguity_causes: None, } } + /// Enables tracking of intercrate ambiguity causes. These are + /// used in coherence to give improved diagnostics. We don't do + /// this until we detect a coherence error because it can lead to + /// false overflow results (#47139) and because it costs + /// computation time. + pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { + assert!(self.intercrate.is_some()); + assert!(self.intercrate_ambiguity_causes.is_none()); + self.intercrate_ambiguity_causes = Some(vec![]); + debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); + } + + /// Gets the intercrate ambiguity causes collected since tracking + /// was enabled and disables tracking at the same time. If + /// tracking is not enabled, just returns an empty vector. + pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> { + assert!(self.intercrate.is_some()); + self.intercrate_ambiguity_causes.take().unwrap_or(vec![]) + } + pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> { self.infcx } @@ -451,10 +471,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx } - pub fn intercrate_ambiguity_causes(&self) -> &[IntercrateAmbiguityCause] { - &self.intercrate_ambiguity_causes - } - /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection /// context's self. fn in_snapshot<R, F>(&mut self, f: F) -> R @@ -828,19 +844,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", stack.fresh_trait_ref); // Heuristics: show the diagnostics when there are no candidates in crate. - if let Ok(candidate_set) = self.assemble_candidates(stack) { - if !candidate_set.ambiguous && candidate_set.vec.is_empty() { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let cause = IntercrateAmbiguityCause::DownstreamCrate { - trait_desc: trait_ref.to_string(), - self_desc: if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }, - }; - self.intercrate_ambiguity_causes.push(cause); + if self.intercrate_ambiguity_causes.is_some() { + debug!("evaluate_stack: intercrate_ambiguity_causes is some"); + if let Ok(candidate_set) = self.assemble_candidates(stack) { + if !candidate_set.ambiguous && candidate_set.vec.is_empty() { + let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let self_ty = trait_ref.self_ty(); + let cause = IntercrateAmbiguityCause::DownstreamCrate { + trait_desc: trait_ref.to_string(), + self_desc: if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }, + }; + debug!("evaluate_stack: pushing cause = {:?}", cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + } } } return EvaluatedToAmbig; @@ -1092,25 +1112,29 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { None => {} Some(conflict) => { debug!("coherence stage: not knowable"); - // Heuristics: show the diagnostics when there are no candidates in crate. - let candidate_set = self.assemble_candidates(stack)?; - if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| { - !self.evaluate_candidate(stack, &c).may_apply() - }) { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let trait_desc = trait_ref.to_string(); - let self_desc = if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }; - let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } - } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } - }; - self.intercrate_ambiguity_causes.push(cause); + if self.intercrate_ambiguity_causes.is_some() { + debug!("evaluate_stack: intercrate_ambiguity_causes is some"); + // Heuristics: show the diagnostics when there are no candidates in crate. + let candidate_set = self.assemble_candidates(stack)?; + if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| { + !self.evaluate_candidate(stack, &c).may_apply() + }) { + let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let self_ty = trait_ref.self_ty(); + let trait_desc = trait_ref.to_string(); + let self_desc = if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }; + let cause = if let Conflict::Upstream = conflict { + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } + } else { + IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } + }; + debug!("evaluate_stack: pushing cause = {:?}", cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + } } return Ok(None); } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 834389e5d00..a10169e13e6 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -133,12 +133,12 @@ impl<'a, 'gcx, 'tcx> Children { }; let tcx = tcx.global_tcx(); - let (le, ge) = tcx.infer_ctxt().enter(|infcx| { - let overlap = traits::overlapping_impls(&infcx, - possible_sibling, - impl_def_id, - traits::IntercrateMode::Issue43355); - if let Some(overlap) = overlap { + let (le, ge) = traits::overlapping_impls( + tcx, + possible_sibling, + impl_def_id, + traits::IntercrateMode::Issue43355, + |overlap| { if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { return Ok((false, false)); } @@ -151,10 +151,9 @@ impl<'a, 'gcx, 'tcx> Children { } else { Ok((le, ge)) } - } else { - Ok((false, false)) - } - })?; + }, + || Ok((false, false)), + )?; if le && !ge { debug!("descending as child of TraitRef {:?}", @@ -171,16 +170,14 @@ impl<'a, 'gcx, 'tcx> Children { return Ok(Inserted::Replaced(possible_sibling)); } else { if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { - tcx.infer_ctxt().enter(|infcx| { - if let Some(overlap) = traits::overlapping_impls( - &infcx, - possible_sibling, - impl_def_id, - traits::IntercrateMode::Fixed) - { - last_lint = Some(overlap_error(overlap)); - } - }); + traits::overlapping_impls( + tcx, + possible_sibling, + impl_def_id, + traits::IntercrateMode::Fixed, + |overlap| last_lint = Some(overlap_error(overlap)), + || (), + ); } // no overlap (error bailed already via ?) diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index e1e2798ecb5..1eb14a22278 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -209,6 +209,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::VariableType(id) => Some(super::VariableType(id)), super::ReturnType(id) => Some(super::ReturnType(id)), super::SizedReturnType => Some(super::SizedReturnType), + super::SizedYieldType => Some(super::SizedYieldType), super::RepeatVec => Some(super::RepeatVec), super::FieldSized(item) => Some(super::FieldSized(item)), super::ConstSized => Some(super::ConstSized), @@ -526,6 +527,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::VariableType(_) | super::ReturnType(_) | super::SizedReturnType | + super::SizedYieldType | super::ReturnNoExpression | super::RepeatVec | super::FieldSized(_) | @@ -574,6 +576,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::VariableType(_) | super::ReturnType(_) | super::SizedReturnType | + super::SizedYieldType | super::ReturnNoExpression | super::RepeatVec | super::FieldSized(_) | diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 69d07eafdca..63b91ff1101 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -895,7 +895,8 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } tcx.layout_depth.set(depth+1); - let layout = LayoutDetails::compute_uncached(tcx, param_env, ty); + let cx = LayoutCx { tcx, param_env }; + let layout = cx.layout_raw_uncached(ty); tcx.layout_depth.set(depth); layout @@ -908,13 +909,18 @@ pub fn provide(providers: &mut ty::maps::Providers) { }; } -impl<'a, 'tcx> LayoutDetails { - fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>) - -> Result<&'tcx Self, LayoutError<'tcx>> { - let cx = (tcx, param_env); - let dl = cx.data_layout(); +#[derive(Copy, Clone)] +pub struct LayoutCx<'tcx, C> { + pub tcx: C, + pub param_env: ty::ParamEnv<'tcx> +} + +impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { + fn layout_raw_uncached(self, ty: Ty<'tcx>) + -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> { + let tcx = self.tcx; + let param_env = self.param_env; + let dl = self.data_layout(); let scalar_unit = |value: Primitive| { let bits = value.size(dl).bits(); assert!(bits <= 128); @@ -924,7 +930,7 @@ impl<'a, 'tcx> LayoutDetails { } }; let scalar = |value: Primitive| { - tcx.intern_layout(LayoutDetails::scalar(cx, scalar_unit(value))) + tcx.intern_layout(LayoutDetails::scalar(self, scalar_unit(value))) }; let scalar_pair = |a: Scalar, b: Scalar| { let align = a.value.align(dl).max(b.value.align(dl)).max(dl.aggregate_align); @@ -1158,13 +1164,13 @@ impl<'a, 'tcx> LayoutDetails { Ok(match ty.sty { // Basic scalars. ty::TyBool => { - tcx.intern_layout(LayoutDetails::scalar(cx, Scalar { + tcx.intern_layout(LayoutDetails::scalar(self, Scalar { value: Int(I8, false), valid_range: 0..=1 })) } ty::TyChar => { - tcx.intern_layout(LayoutDetails::scalar(cx, Scalar { + tcx.intern_layout(LayoutDetails::scalar(self, Scalar { value: Int(I32, false), valid_range: 0..=0x10FFFF })) @@ -1180,7 +1186,7 @@ impl<'a, 'tcx> LayoutDetails { ty::TyFnPtr(_) => { let mut ptr = scalar_unit(Pointer); ptr.valid_range.start = 1; - tcx.intern_layout(LayoutDetails::scalar(cx, ptr)) + tcx.intern_layout(LayoutDetails::scalar(self, ptr)) } // The never type. @@ -1198,13 +1204,13 @@ impl<'a, 'tcx> LayoutDetails { let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env); if pointee.is_sized(tcx, param_env, DUMMY_SP) { - return Ok(tcx.intern_layout(LayoutDetails::scalar(cx, data_ptr))); + return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr))); } let unsized_part = tcx.struct_tail(pointee); let metadata = match unsized_part.sty { ty::TyForeign(..) => { - return Ok(tcx.intern_layout(LayoutDetails::scalar(cx, data_ptr))); + return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr))); } ty::TySlice(_) | ty::TyStr => { scalar_unit(Int(dl.ptr_sized_integer(), false)) @@ -1230,7 +1236,7 @@ impl<'a, 'tcx> LayoutDetails { } } - let element = cx.layout_of(element)?; + let element = self.layout_of(element)?; let count = count.val.to_const_int().unwrap().to_u64().unwrap(); let size = element.size.checked_mul(count, dl) .ok_or(LayoutError::SizeOverflow(ty))?; @@ -1247,7 +1253,7 @@ impl<'a, 'tcx> LayoutDetails { }) } ty::TySlice(element) => { - let element = cx.layout_of(element)?; + let element = self.layout_of(element)?; tcx.intern_layout(LayoutDetails { variants: Variants::Single { index: 0 }, fields: FieldPlacement::Array { @@ -1289,14 +1295,14 @@ impl<'a, 'tcx> LayoutDetails { // Tuples, generators and closures. ty::TyGenerator(def_id, ref substs, _) => { let tys = substs.field_tys(def_id, tcx); - univariant(&tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?, + univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?, &ReprOptions::default(), StructKind::AlwaysSized)? } ty::TyClosure(def_id, ref substs) => { let tys = substs.upvar_tys(def_id, tcx); - univariant(&tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?, + univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?, &ReprOptions::default(), StructKind::AlwaysSized)? } @@ -1308,13 +1314,13 @@ impl<'a, 'tcx> LayoutDetails { StructKind::MaybeUnsized }; - univariant(&tys.iter().map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?, + univariant(&tys.iter().map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?, &ReprOptions::default(), kind)? } // SIMD vector types. ty::TyAdt(def, ..) if def.repr.simd() => { - let element = cx.layout_of(ty.simd_type(tcx))?; + let element = self.layout_of(ty.simd_type(tcx))?; let count = ty.simd_size(tcx) as u64; assert!(count > 0); let scalar = match element.abi { @@ -1350,7 +1356,7 @@ impl<'a, 'tcx> LayoutDetails { // Cache the field layouts. let variants = def.variants.iter().map(|v| { v.fields.iter().map(|field| { - cx.layout_of(field.ty(tcx, substs)) + self.layout_of(field.ty(tcx, substs)) }).collect::<Result<Vec<_>, _>>() }).collect::<Result<Vec<_>, _>>()?; @@ -1430,7 +1436,7 @@ impl<'a, 'tcx> LayoutDetails { let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?; st.variants = Variants::Single { index: v }; // Exclude 0 from the range of a newtype ABI NonZero<T>. - if Some(def.did) == cx.tcx().lang_items().non_zero() { + if Some(def.did) == self.tcx.lang_items().non_zero() { match st.abi { Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { @@ -1482,7 +1488,7 @@ impl<'a, 'tcx> LayoutDetails { let count = (niche_variants.end - niche_variants.start + 1) as u128; for (field_index, field) in variants[i].iter().enumerate() { let (offset, niche, niche_start) = - match field.find_niche(cx, count)? { + match field.find_niche(self, count)? { Some(niche) => niche, None => continue }; @@ -1687,56 +1693,49 @@ impl<'a, 'tcx> LayoutDetails { /// This is invoked by the `layout_raw` query to record the final /// layout of each type. #[inline] - fn record_layout_for_printing(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - layout: TyLayout<'tcx>) { + fn record_layout_for_printing(self, layout: TyLayout<'tcx>) { // If we are running with `-Zprint-type-sizes`, record layouts for // dumping later. Ignore layouts that are done with non-empty // environments or non-monomorphic layouts, as the user only wants // to see the stuff resulting from the final trans session. if - !tcx.sess.opts.debugging_opts.print_type_sizes || - ty.has_param_types() || - ty.has_self_ty() || - !param_env.caller_bounds.is_empty() + !self.tcx.sess.opts.debugging_opts.print_type_sizes || + layout.ty.has_param_types() || + layout.ty.has_self_ty() || + !self.param_env.caller_bounds.is_empty() { return; } - Self::record_layout_for_printing_outlined(tcx, ty, param_env, layout) + self.record_layout_for_printing_outlined(layout) } - fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - layout: TyLayout<'tcx>) { - let cx = (tcx, param_env); + fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) { // (delay format until we actually need it) let record = |kind, opt_discr_size, variants| { - let type_desc = format!("{:?}", ty); - tcx.sess.code_stats.borrow_mut().record_type_size(kind, - type_desc, - layout.align, - layout.size, - opt_discr_size, - variants); + let type_desc = format!("{:?}", layout.ty); + self.tcx.sess.code_stats.borrow_mut().record_type_size(kind, + type_desc, + layout.align, + layout.size, + opt_discr_size, + variants); }; - let adt_def = match ty.sty { + let adt_def = match layout.ty.sty { ty::TyAdt(ref adt_def, _) => { - debug!("print-type-size t: `{:?}` process adt", ty); + debug!("print-type-size t: `{:?}` process adt", layout.ty); adt_def } ty::TyClosure(..) => { - debug!("print-type-size t: `{:?}` record closure", ty); + debug!("print-type-size t: `{:?}` record closure", layout.ty); record(DataTypeKind::Closure, None, vec![]); return; } _ => { - debug!("print-type-size t: `{:?}` skip non-nominal", ty); + debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty); return; } }; @@ -1748,7 +1747,7 @@ impl<'a, 'tcx> LayoutDetails { layout: TyLayout<'tcx>| { let mut min_size = Size::from_bytes(0); let field_info: Vec<_> = flds.iter().enumerate().map(|(i, &name)| { - match layout.field(cx, i) { + match layout.field(self, i) { Err(err) => { bug!("no layout found for field {}: `{:?}`", name, err); } @@ -1808,18 +1807,18 @@ impl<'a, 'tcx> LayoutDetails { Variants::NicheFilling { .. } | Variants::Tagged { .. } => { debug!("print-type-size `{:#?}` adt general variants def {}", - ty, adt_def.variants.len()); + layout.ty, adt_def.variants.len()); let variant_infos: Vec<_> = adt_def.variants.iter().enumerate().map(|(i, variant_def)| { let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect(); build_variant_info(Some(variant_def.name), &fields, - layout.for_variant(cx, i)) + layout.for_variant(self, i)) }) .collect(); record(adt_kind.into(), match layout.variants { - Variants::Tagged { ref discr, .. } => Some(discr.value.size(tcx)), + Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)), _ => None }, variant_infos); } @@ -1855,7 +1854,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> { assert!(!ty.has_infer_types()); // First try computing a static layout. - let err = match (tcx, param_env).layout_of(ty) { + let err = match tcx.layout_of(param_env.and(ty)) { Ok(layout) => { return Ok(SizeSkeleton::Known(layout.size)); } @@ -2001,15 +2000,15 @@ impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx, T: Copy> HasDataLayout for (TyCtxt<'a, 'gcx, 'tcx>, T) { +impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> { fn data_layout(&self) -> &TargetDataLayout { - self.0.data_layout() + self.tcx.data_layout() } } -impl<'a, 'gcx, 'tcx, T: Copy> HasTyCtxt<'gcx> for (TyCtxt<'a, 'gcx, 'tcx>, T) { +impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { - self.0.tcx() + self.tcx.tcx() } } @@ -2042,17 +2041,15 @@ pub trait LayoutOf<T> { fn layout_of(self, ty: T) -> Self::TyLayout; } -impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx>) { +impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode. - #[inline] fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - let (tcx, param_env) = self; - - let ty = tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all()); - let details = tcx.layout_raw(param_env.reveal_all().and(ty))?; + let param_env = self.param_env.reveal_all(); + let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env); + let details = self.tcx.layout_raw(param_env.and(ty))?; let layout = TyLayout { ty, details @@ -2064,24 +2061,21 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx // completed, to avoid problems around recursive structures // and the like. (Admitedly, I wasn't able to reproduce a problem // here, but it seems like the right thing to do. -nmatsakis) - LayoutDetails::record_layout_for_printing(tcx, ty, param_env, layout); + self.record_layout_for_printing(layout); Ok(layout) } } -impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>, - ty::ParamEnv<'tcx>) { +impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>> { type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode. - #[inline] fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - let (tcx_at, param_env) = self; - - let ty = tcx_at.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all()); - let details = tcx_at.layout_raw(param_env.reveal_all().and(ty))?; + let param_env = self.param_env.reveal_all(); + let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all()); + let details = self.tcx.layout_raw(param_env.reveal_all().and(ty))?; let layout = TyLayout { ty, details @@ -2093,12 +2087,45 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>, // completed, to avoid problems around recursive structures // and the like. (Admitedly, I wasn't able to reproduce a problem // here, but it seems like the right thing to do. -nmatsakis) - LayoutDetails::record_layout_for_printing(tcx_at.tcx, ty, param_env, layout); + let cx = LayoutCx { + tcx: *self.tcx, + param_env: self.param_env + }; + cx.record_layout_for_printing(layout); Ok(layout) } } +// Helper (inherent) `layout_of` methods to avoid pushing `LayoutCx` to users. +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Computes the layout of a type. Note that this implicitly + /// executes in "reveal all" mode. + #[inline] + pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> Result<TyLayout<'tcx>, LayoutError<'tcx>> { + let cx = LayoutCx { + tcx: self, + param_env: param_env_and_ty.param_env + }; + cx.layout_of(param_env_and_ty.value) + } +} + +impl<'a, 'tcx> ty::maps::TyCtxtAt<'a, 'tcx, 'tcx> { + /// Computes the layout of a type. Note that this implicitly + /// executes in "reveal all" mode. + #[inline] + pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> Result<TyLayout<'tcx>, LayoutError<'tcx>> { + let cx = LayoutCx { + tcx: self, + param_env: param_env_and_ty.param_env + }; + cx.layout_of(param_env_and_ty.value) + } +} + impl<'a, 'tcx> TyLayout<'tcx> { pub fn for_variant<C>(&self, cx: C, variant_index: usize) -> Self where C: LayoutOf<Ty<'tcx>> + HasTyCtxt<'tcx>, diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 6c79f6a62fa..85fca68187f 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -343,6 +343,7 @@ define_maps! { <'tcx> -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>), [] fn export_name: ExportName(DefId) -> Option<Symbol>, [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool, + [] fn symbol_export_level: GetSymbolExportLevel(DefId) -> SymbolExportLevel, [] fn is_translated_function: IsTranslatedFunction(DefId) -> bool, [] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>, [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index c9eebc3d2a0..0ab6ee1a54a 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -921,6 +921,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } DepKind::TargetFeaturesEnabled => { force!(target_features_enabled, def_id!()); } + + DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); } } true diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0c1ebd1a2ba..1593b452cdf 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -390,14 +390,21 @@ impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { state.map(move |d| d.ty.subst(tcx, self.substs)) } + /// This is the types of the fields of a generate which + /// is available before the generator transformation. + /// It includes the upvars and the state discriminant which is u32. + pub fn pre_transforms_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> + impl Iterator<Item=Ty<'tcx>> + 'a + { + self.upvar_tys(def_id, tcx).chain(iter::once(tcx.types.u32)) + } + /// This is the types of all the fields stored in a generator. /// It includes the upvars, state types and the state discriminant which is u32. pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator<Item=Ty<'tcx>> + 'a { - let upvars = self.upvar_tys(def_id, tcx); - let state = self.state_tys(def_id, tcx); - upvars.chain(iter::once(tcx.types.u32)).chain(state) + self.pre_transforms_tys(def_id, tcx).chain(self.state_tys(def_id, tcx)) } } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 3c8a676dcc2..2872c59157d 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -468,6 +468,10 @@ pub struct TargetOptions { /// The codegen backend to use for this target, typically "llvm" pub codegen_backend: String, + + /// The default visibility for symbols in this target should be "hidden" + /// rather than "default" + pub default_hidden_visibility: bool, } impl Default for TargetOptions { @@ -538,6 +542,7 @@ impl Default for TargetOptions { no_builtins: false, i128_lowering: false, codegen_backend: "llvm".to_string(), + default_hidden_visibility: false, } } } @@ -785,6 +790,7 @@ impl Target { key!(singlethread, bool); key!(no_builtins, bool); key!(codegen_backend); + key!(default_hidden_visibility, bool); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -982,6 +988,7 @@ impl ToJson for Target { target_option_val!(singlethread); target_option_val!(no_builtins); target_option_val!(codegen_backend); + target_option_val!(default_hidden_visibility); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_back/target/msp430_none_elf.rs b/src/librustc_back/target/msp430_none_elf.rs index 509a7cf5e03..966df897f01 100644 --- a/src/librustc_back/target/msp430_none_elf.rs +++ b/src/librustc_back/target/msp430_none_elf.rs @@ -53,6 +53,12 @@ pub fn target() -> TargetResult { // don't want to invoke that many gcc instances. default_codegen_units: Some(1), + // Since MSP430 doesn't meaningfully support faulting on illegal + // instructions, LLVM generates a call to abort() function instead + // of a trap instruction. Such calls are 4 bytes long, and that is + // too much overhead for such small target. + trap_unreachable: false, + .. Default::default( ) } }) diff --git a/src/librustc_back/target/wasm32_unknown_unknown.rs b/src/librustc_back/target/wasm32_unknown_unknown.rs index 7e1011ab8af..242860e5c6e 100644 --- a/src/librustc_back/target/wasm32_unknown_unknown.rs +++ b/src/librustc_back/target/wasm32_unknown_unknown.rs @@ -83,6 +83,9 @@ pub fn target() -> Result<Target, String> { // performing LTO with compiler-builtins. no_builtins: true, + // no dynamic linking, no need for default visibility! + default_hidden_visibility: true, + .. Default::default() }; Ok(Target { diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs index ddee122d0a6..7bcd8a18545 100644 --- a/src/librustc_borrowck/borrowck/unused.rs +++ b/src/librustc_borrowck/borrowck/unused.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> { continue } - let mut_span = tcx.sess.codemap().span_until_char(ids[0].2, ' '); + let mut_span = tcx.sess.codemap().span_until_non_whitespace(ids[0].2); // Ok, every name wasn't used mutably, so issue a warning that this // didn't need to be mutable. diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index fd171b89924..ae53ed0e114 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -127,13 +127,16 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { } } + impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn report_inlining_errors(&self, pat_span: Span) { for error in &self.errors { match *error { PatternError::StaticInPattern(span) => { - span_err!(self.tcx.sess, span, E0158, - "statics cannot be referenced in patterns"); + self.span_e0158(span, "statics cannot be referenced in patterns") + } + PatternError::AssociatedConstInPattern(span) => { + self.span_e0158(span, "associated consts cannot be referenced in patterns") } PatternError::ConstEval(ref err) => { err.report(self.tcx, pat_span, "pattern"); @@ -141,6 +144,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } } + + fn span_e0158(&self, span: Span, text: &str) { + span_err!(self.tcx.sess, span, E0158, "{}", text) + } } impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 17a9454e9d4..8e4ec93c14b 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -17,7 +17,6 @@ use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::layout::LayoutOf; use rustc::ty::util::IntTypeExt; use rustc::ty::subst::{Substs, Subst}; use rustc::util::common::ErrorReported; @@ -313,7 +312,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic { let layout_of = |ty: Ty<'tcx>| { let ty = tcx.erase_regions(&ty); - (tcx.at(e.span), cx.param_env).layout_of(ty).map_err(|err| { + tcx.at(e.span).layout_of(cx.param_env.and(ty)).map_err(|err| { ConstEvalErr { span: e.span, kind: LayoutError(err) } }) }; diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 3577feaf90c..e0b3929e32a 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -27,6 +27,7 @@ use syntax_pos::Span; #[derive(Clone, Debug)] pub enum PatternError<'tcx> { + AssociatedConstInPattern(Span), StaticInPattern(Span), ConstEval(ConstEvalErr<'tcx>), } @@ -635,6 +636,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { -> Pattern<'tcx> { let ty = self.tables.node_id_to_type(id); let def = self.tables.qpath_def(qpath, id); + let is_associated_const = match def { + Def::AssociatedConst(_) => true, + _ => false, + }; let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); @@ -656,7 +661,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { return pat; } None => { - self.errors.push(PatternError::StaticInPattern(span)); + self.errors.push(if is_associated_const { + PatternError::AssociatedConstInPattern(span) + } else { + PatternError::StaticInPattern(span) + }); PatternKind::Wild } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6118ee94c84..05dcaf73135 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -167,7 +167,8 @@ pub fn run<F>(run_compiler: F) -> isize let emitter = errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None, - true); + true, + false); let handler = errors::Handler::with_emitter(true, false, Box::new(emitter)); handler.emit(&MultiSpan::new(), "aborting due to previous error(s)", @@ -289,7 +290,7 @@ fn get_trans_sysroot(backend_name: &str) -> fn() -> Box<TransCrate> { let sysroot = sysroot_candidates.iter() .map(|sysroot| { let libdir = filesearch::relative_target_lib_path(&sysroot, &target); - sysroot.join(&libdir).join("codegen-backends") + sysroot.join(libdir).with_file_name("codegen-backends") }) .filter(|f| { info!("codegen backend candidate: {}", f.display()); @@ -456,10 +457,13 @@ pub fn run_compiler<'a>(args: &[String], None); let (odir, ofile) = make_output(&matches); - let (input, input_file_path) = match make_input(&matches.free) { - Some((input, input_file_path)) => callbacks.some_input(input, input_file_path), + let (input, input_file_path, input_err) = match make_input(&matches.free) { + Some((input, input_file_path, input_err)) => { + let (input, input_file_path) = callbacks.some_input(input, input_file_path); + (input, input_file_path, input_err) + }, None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) { - Some((input, input_file_path)) => (input, input_file_path), + Some((input, input_file_path)) => (input, input_file_path, None), None => return (Ok(()), None), }, }; @@ -470,6 +474,13 @@ pub fn run_compiler<'a>(args: &[String], sopts, input_file_path.clone(), descriptions, codemap, emitter_dest, ); + if let Some(err) = input_err { + // Immediately stop compilation if there was an issue reading + // the input (for example if the input stream is not UTF-8). + sess.err(&format!("{}", err)); + return (Err(CompileIncomplete::Stopped), Some(sess)); + } + let trans = get_trans(&sess); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); @@ -512,17 +523,22 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) } // Extract input (string or file and optional path) from matches. -fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>)> { +fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option<io::Error>)> { if free_matches.len() == 1 { let ifile = &free_matches[0]; if ifile == "-" { let mut src = String::new(); - io::stdin().read_to_string(&mut src).unwrap(); + let err = if io::stdin().read_to_string(&mut src).is_err() { + Some(io::Error::new(io::ErrorKind::InvalidData, + "couldn't read from stdin, as it did not contain valid UTF-8")) + } else { + None + }; Some((Input::Str { name: FileName::Anon, input: src }, - None)) + None, err)) } else { Some((Input::File(PathBuf::from(ifile)), - Some(PathBuf::from(ifile)))) + Some(PathBuf::from(ifile)), None)) } } else { None @@ -1434,6 +1450,7 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) { let emitter = Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None, + false, false)); let handler = errors::Handler::with_emitter(true, false, emitter); diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 2e654fe9929..40e4efb397d 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -222,6 +222,7 @@ impl Diagnostic { }], msg: msg.to_owned(), show_code_when_inline: false, + approximate: false, }); self } @@ -252,6 +253,7 @@ impl Diagnostic { }], msg: msg.to_owned(), show_code_when_inline: true, + approximate: false, }); self } @@ -267,6 +269,41 @@ impl Diagnostic { }).collect(), msg: msg.to_owned(), show_code_when_inline: true, + approximate: false, + }); + self + } + + /// This is a suggestion that may contain mistakes or fillers and should + /// be read and understood by a human. + pub fn span_approximate_suggestion(&mut self, sp: Span, msg: &str, + suggestion: String) -> &mut Self { + self.suggestions.push(CodeSuggestion { + substitutions: vec![Substitution { + parts: vec![SubstitutionPart { + snippet: suggestion, + span: sp, + }], + }], + msg: msg.to_owned(), + show_code_when_inline: true, + approximate: true, + }); + self + } + + pub fn span_approximate_suggestions(&mut self, sp: Span, msg: &str, + suggestions: Vec<String>) -> &mut Self { + self.suggestions.push(CodeSuggestion { + substitutions: suggestions.into_iter().map(|snippet| Substitution { + parts: vec![SubstitutionPart { + snippet, + span: sp, + }], + }).collect(), + msg: msg.to_owned(), + show_code_when_inline: true, + approximate: true, }); self } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 61674ada6fa..2536fc648c7 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -186,6 +186,16 @@ impl<'a> DiagnosticBuilder<'a> { msg: &str, suggestions: Vec<String>) -> &mut Self); + forward!(pub fn span_approximate_suggestion(&mut self, + sp: Span, + msg: &str, + suggestion: String) + -> &mut Self); + forward!(pub fn span_approximate_suggestions(&mut self, + sp: Span, + msg: &str, + suggestions: Vec<String>) + -> &mut Self); forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index ffb5efd93ed..a49284eb55a 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -106,6 +106,7 @@ pub struct EmitterWriter { dst: Destination, cm: Option<Rc<CodeMapper>>, short_message: bool, + teach: bool, } struct FileWithAnnotatedLines { @@ -117,32 +118,37 @@ struct FileWithAnnotatedLines { impl EmitterWriter { pub fn stderr(color_config: ColorConfig, code_map: Option<Rc<CodeMapper>>, - short_message: bool) + short_message: bool, + teach: bool) -> EmitterWriter { if color_config.use_color() { let dst = Destination::from_stderr(); EmitterWriter { dst, cm: code_map, - short_message: short_message, + short_message, + teach, } } else { EmitterWriter { dst: Raw(Box::new(io::stderr())), cm: code_map, - short_message: short_message, + short_message, + teach, } } } pub fn new(dst: Box<Write + Send>, code_map: Option<Rc<CodeMapper>>, - short_message: bool) + short_message: bool, + teach: bool) -> EmitterWriter { EmitterWriter { dst: Raw(dst), cm: code_map, - short_message: short_message, + short_message, + teach, } } @@ -284,6 +290,10 @@ impl EmitterWriter { line: &Line, width_offset: usize, code_offset: usize) -> Vec<(usize, Style)> { + if line.line_index == 0 { + return Vec::new(); + } + let source_string = match file.get_line(line.line_index - 1) { Some(s) => s, None => return Vec::new(), @@ -551,7 +561,14 @@ impl EmitterWriter { code_offset + annotation.start_col, style); } - _ => (), + _ if self.teach => { + buffer.set_style_range(line_offset, + code_offset + annotation.start_col, + code_offset + annotation.end_col, + style, + annotation.is_primary); + } + _ => {} } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 3d50c95d3f4..236698ed2d4 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -83,6 +83,12 @@ pub struct CodeSuggestion { pub substitutions: Vec<Substitution>, pub msg: String, pub show_code_when_inline: bool, + /// Whether or not the suggestion is approximate + /// + /// Sometimes we may show suggestions with placeholders, + /// which are useful for users but not useful for + /// tools like rustfix + pub approximate: bool, } #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] @@ -297,7 +303,7 @@ impl Handler { cm: Option<Rc<CodeMapper>>, flags: HandlerFlags) -> Handler { - let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false)); + let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false)); Handler::with_emitter_and_flags(emitter, flags) } diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 6035f33c822..7d416f13ffc 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -10,32 +10,8 @@ // Code for annotating snippets. -use syntax_pos::{Span, FileMap}; -use CodeMapper; -use std::rc::Rc; use Level; -#[derive(Clone)] -pub struct SnippetData { - codemap: Rc<CodeMapper>, - files: Vec<FileInfo>, -} - -#[derive(Clone)] -pub struct FileInfo { - file: Rc<FileMap>, - - /// The "primary file", if any, gets a `-->` marker instead of - /// `>>>`, and has a line-number/column printed and not just a - /// filename (other files are not guaranteed to have line numbers - /// or columns). It appears first in the listing. It is known to - /// contain at least one primary span, though primary spans (which - /// are designated with `^^^`) may also occur in other files. - primary_span: Option<Span>, - - lines: Vec<Line>, -} - #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub struct Line { pub line_index: usize, diff --git a/src/librustc_errors/styled_buffer.rs b/src/librustc_errors/styled_buffer.rs index 2c33f805203..2c736ec22c3 100644 --- a/src/librustc_errors/styled_buffer.rs +++ b/src/librustc_errors/styled_buffer.rs @@ -144,4 +144,25 @@ impl StyledBuffer { pub fn num_lines(&self) -> usize { self.text.len() } + + pub fn set_style_range(&mut self, + line: usize, + col_start: usize, + col_end: usize, + style: Style, + overwrite: bool) { + for col in col_start..col_end { + self.set_style(line, col, style, overwrite); + } + } + + pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) { + if let Some(ref mut line) = self.styles.get_mut(line) { + if let Some(s) = line.get_mut(col) { + if *s == Style::NoStyle || *s == Style::Quotation || overwrite { + *s = style; + } + } + } + } } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index e0999db6e3e..e7e4119b999 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -437,8 +437,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // repr(transparent) types are allowed to have arbitrary ZSTs, not just // PhantomData -- skip checking all ZST fields if def.repr.transparent() { - let is_zst = (cx, cx.param_env(field.did)) - .layout_of(field_ty) + let is_zst = cx + .layout_of(cx.param_env(field.did).and(field_ty)) .map(|layout| layout.is_zst()) .unwrap_or(false); if is_zst { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index ef6475f9ee4..56f863ab3aa 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -302,19 +302,38 @@ impl EarlyLintPass for UnusedParens { Assign(_, ref value) => (value, "assigned value", false), AssignOp(.., ref value) => (value, "assigned value", false), InPlace(_, ref value) => (value, "emplacement value", false), - Call(_, ref args) => { - for arg in args { - self.check_unused_parens_core(cx, arg, "function argument", false) + // either function/method call, or something this lint doesn't care about + ref call_or_other => { + let args_to_check; + let call_kind; + match *call_or_other { + Call(_, ref args) => { + call_kind = "function"; + args_to_check = &args[..]; + }, + MethodCall(_, ref args) => { + call_kind = "method"; + // first "argument" is self (which sometimes needs parens) + args_to_check = &args[1..]; + } + // actual catch-all arm + _ => { return; } } - return; - }, - MethodCall(_, ref args) => { - for arg in &args[1..] { // first "argument" is self (which sometimes needs parens) - self.check_unused_parens_core(cx, arg, "method argument", false) + // Don't lint if this is a nested macro expansion: otherwise, the lint could + // trigger in situations that macro authors shouldn't have to care about, e.g., + // when a parenthesized token tree matched in one macro expansion is matched as + // an expression in another and used as a fn/method argument (Issue #47775) + if e.span.ctxt().outer().expn_info() + .map_or(false, |info| info.call_site.ctxt().outer() + .expn_info().is_some()) { + return; + } + let msg = format!("{} argument", call_kind); + for arg in args_to_check { + self.check_unused_parens_core(cx, arg, &msg, false); } return; } - _ => return, }; self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens); } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 7bd3b6e39f0..7fadc4b36e4 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -746,12 +746,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.describe_field_from_ty(&tnm.ty, field) } ty::TyArray(ty, _) | ty::TySlice(ty) => self.describe_field_from_ty(&ty, field), - ty::TyClosure(closure_def_id, _) => { + ty::TyClosure(def_id, _) | ty::TyGenerator(def_id, _, _) => { // Convert the def-id into a node-id. node-ids are only valid for // the local code in the current crate, so this returns an `Option` in case // the closure comes from another crate. But in that case we wouldn't // be borrowck'ing it, so we can just unwrap: - let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap(); + let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); let freevar = self.tcx.with_freevars(node_id, |fv| fv[field.index()]); self.tcx.hir.name(freevar.var_id()).to_string() 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 015eb8a3b66..c0c680a4ddc 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -374,13 +374,20 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } }; if let PlaceContext::Copy = context { - let ty = place_ty.to_ty(self.tcx()); - if self.cx - .infcx - .type_moves_by_default(self.cx.param_env, ty, DUMMY_SP) - { - span_mirbug!(self, place, "attempted copy of non-Copy type ({:?})", ty); - } + let tcx = self.tcx(); + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().copy_trait().unwrap(), + substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]), + }; + + // In order to have a Copy operand, the type T of the value must be Copy. Note that we + // prove that T: Copy, rather than using the type_moves_by_default test. This is + // important because type_moves_by_default ignores the resulting region obligations and + // assumes they pass. This can result in bounds from Copy impls being unsoundly ignored + // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds + // fully apply: in effect, the rule is that if a value of some type could implement + // Copy, then it must. + self.cx.prove_trait_ref(trait_ref, location); } place_ty } @@ -533,15 +540,17 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } ty::TyGenerator(def_id, substs, _) => { - // Try upvars first. `field_tys` requires final optimized MIR. - if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field.index()) { + // Try pre-transform fields first (upvars and current state) + if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field.index()) { return Ok(ty); } + // Then try `field_tys` which contains all the fields, but it + // requires the final optimized MIR. return match substs.field_tys(def_id, tcx).nth(field.index()) { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { - field_count: substs.field_tys(def_id, tcx).count() + 1, + field_count: substs.field_tys(def_id, tcx).count(), }), }; } @@ -1233,13 +1242,16 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } AggregateKind::Generator(def_id, substs, _) => { - if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field_index) { + // Try pre-transform fields first (upvars and current state) + if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field_index) { Ok(ty) } else { + // Then try `field_tys` which contains all the fields, but it + // requires the final optimized MIR. match substs.field_tys(def_id, tcx).nth(field_index) { Some(ty) => Ok(ty), None => Err(FieldAccessError::OutOfRange { - field_count: substs.field_tys(def_id, tcx).count() + 1, + field_count: substs.field_tys(def_id, tcx).count(), }), } } diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs new file mode 100644 index 00000000000..244e8b5ccd7 --- /dev/null +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -0,0 +1,118 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use super::*; + +use rustc::mir::*; +use rustc::mir::visit::Visitor; +use dataflow::BitDenotation; + +/// This calculates if any part of a MIR local could have previously been borrowed. +/// This means that once a local has been borrowed, its bit will always be set +/// from that point and onwards, even if the borrow ends. You could also think of this +/// as computing the lifetimes of infinite borrows. +/// This is used to compute which locals are live during a yield expression for +/// immovable generators. +#[derive(Copy, Clone)] +pub struct HaveBeenBorrowedLocals<'a, 'tcx: 'a> { + mir: &'a Mir<'tcx>, +} + +impl<'a, 'tcx: 'a> HaveBeenBorrowedLocals<'a, 'tcx> { + pub fn new(mir: &'a Mir<'tcx>) + -> Self { + HaveBeenBorrowedLocals { mir: mir } + } + + pub fn mir(&self) -> &Mir<'tcx> { + self.mir + } +} + +impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> { + type Idx = Local; + fn name() -> &'static str { "has_been_borrowed_locals" } + fn bits_per_block(&self) -> usize { + self.mir.local_decls.len() + } + + fn start_block_effect(&self, _sets: &mut IdxSet<Local>) { + // Nothing is borrowed on function entry + } + + fn statement_effect(&self, + sets: &mut BlockSets<Local>, + loc: Location) { + BorrowedLocalsVisitor { + sets, + }.visit_statement(loc.block, &self.mir[loc.block].statements[loc.statement_index], loc); + } + + fn terminator_effect(&self, + sets: &mut BlockSets<Local>, + loc: Location) { + BorrowedLocalsVisitor { + sets, + }.visit_terminator(loc.block, self.mir[loc.block].terminator(), loc); + } + + fn propagate_call_return(&self, + _in_out: &mut IdxSet<Local>, + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + _dest_place: &mir::Place) { + // Nothing to do when a call returns successfully + } +} + +impl<'a, 'tcx> BitwiseOperator for HaveBeenBorrowedLocals<'a, 'tcx> { + #[inline] + fn join(&self, pred1: usize, pred2: usize) -> usize { + pred1 | pred2 // "maybe" means we union effects of both preds + } +} + +impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> { + #[inline] + fn bottom_value() -> bool { + false // bottom = unborrowed + } +} + +struct BorrowedLocalsVisitor<'b, 'c: 'b> { + sets: &'b mut BlockSets<'c, Local>, +} + +fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> { + match *place { + Place::Local(l) => Some(l), + Place::Static(..) => None, + Place::Projection(ref proj) => { + match proj.elem { + ProjectionElem::Deref => None, + _ => find_local(&proj.base) + } + } + } +} + +impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> { + fn visit_rvalue(&mut self, + rvalue: &Rvalue<'tcx>, + location: Location) { + if let Rvalue::Ref(_, _, ref place) = *rvalue { + if let Some(local) = find_local(place) { + self.sets.gen(&local); + } + } + + self.super_rvalue(rvalue, location) + } +} diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 632bb5b3428..80990bcc080 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -396,8 +396,7 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { // Issue #46746: Two-phase borrows handles // stmts of form `Tmp = &mut Borrow` ... match lhs { - Place::Local(..) => {} // okay - Place::Static(..) => unreachable!(), // (filtered by is_unsafe_place) + Place::Local(..) | Place::Static(..) => {} // okay Place::Projection(..) => { // ... can assign into projections, // e.g. `box (&mut _)`. Current diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index e7c15625cbe..c5f5492cd2c 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -33,6 +33,10 @@ mod storage_liveness; pub use self::storage_liveness::*; +mod borrowed_locals; + +pub use self::borrowed_locals::*; + #[allow(dead_code)] pub(super) mod borrows; diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index bd63198ecd0..291c22b5e1e 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -30,6 +30,7 @@ pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; pub use self::impls::{DefinitelyInitializedPlaces, MovingOutStatements}; pub use self::impls::EverInitializedPlaces; pub use self::impls::borrows::{Borrows, BorrowData}; +pub use self::impls::HaveBeenBorrowedLocals; pub(crate) use self::impls::borrows::{ActiveBorrows, Reservations, ReserveOrActivateIndex}; pub use self::at_location::{FlowAtLocation, FlowsAtLocation}; pub(crate) use self::drop_flag_effects::*; diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index baec0fea50f..02fcb69fef5 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -172,7 +172,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'tcx type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - (self.tcx, self.param_env).layout_of(ty) + self.tcx.layout_of(self.param_env.and(ty)) .map_err(|layout| EvalErrorKind::Layout(layout).into()) } } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 806d787c845..e9471cdb4f9 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -107,6 +107,7 @@ use rustc::dep_graph::WorkProductId; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; use rustc::mir::mono::{Linkage, Visibility}; +use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::ty::{self, TyCtxt, InstanceDef}; use rustc::ty::item_path::characteristic_def_id_of_type; use rustc::util::nodemap::{FxHashMap, FxHashSet}; @@ -322,7 +323,16 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .or_insert_with(make_codegen_unit); let mut can_be_internalized = true; - let (linkage, visibility) = match trans_item.explicit_linkage(tcx) { + let default_visibility = |id: DefId| { + if tcx.sess.target.target.options.default_hidden_visibility && + tcx.symbol_export_level(id) != SymbolExportLevel::C + { + Visibility::Hidden + } else { + Visibility::Default + } + }; + let (linkage, mut visibility) = match trans_item.explicit_linkage(tcx) { Some(explicit_linkage) => (explicit_linkage, Visibility::Default), None => { match trans_item { @@ -352,7 +362,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Visibility::Hidden } else if def_id.is_local() { if tcx.is_exported_symbol(def_id) { - Visibility::Default + can_be_internalized = false; + default_visibility(def_id) } else { Visibility::Hidden } @@ -375,7 +386,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, MonoItem::GlobalAsm(node_id) => { let def_id = tcx.hir.local_def_id(node_id); let visibility = if tcx.is_exported_symbol(def_id) { - Visibility::Default + can_be_internalized = false; + default_visibility(def_id) } else { Visibility::Hidden }; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index ebd34f81deb..812665f5fa4 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -78,7 +78,8 @@ use std::mem; use transform::{MirPass, MirSource}; use transform::simplify; use transform::no_landing_pads::no_landing_pads; -use dataflow::{do_dataflow, DebugFormatted, MaybeStorageLive, state_for_location}; +use dataflow::{do_dataflow, DebugFormatted, state_for_location}; +use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals}; pub struct StateTransform; @@ -369,17 +370,33 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, HashMap<BasicBlock, liveness::LocalSet>) { let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); let node_id = tcx.hir.as_local_node_id(source.def_id).unwrap(); - let analysis = MaybeStorageLive::new(mir); + + // Calculate when MIR locals have live storage. This gives us an upper bound of their + // lifetimes. + let storage_live_analysis = MaybeStorageLive::new(mir); let storage_live = - do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis, + do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, storage_live_analysis, |bd, p| DebugFormatted::new(&bd.mir().local_decls[p])); + // Find the MIR locals which do not use StorageLive/StorageDead statements. + // The storage of these locals are always live. let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len())); ignored.visit_mir(mir); - let mut borrowed_locals = BorrowedLocals(IdxSetBuf::new_empty(mir.local_decls.len())); - borrowed_locals.visit_mir(mir); + // Calculate the MIR locals which have been previously + // borrowed (even if they are still active). + // This is only used for immovable generators. + let borrowed_locals = if !movable { + let analysis = HaveBeenBorrowedLocals::new(mir); + let result = + do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis, + |bd, p| DebugFormatted::new(&bd.mir().local_decls[p])); + Some((analysis, result)) + } else { + None + }; + // Calculate the liveness of MIR locals ignoring borrows. let mut set = liveness::LocalSet::new_empty(mir.local_decls.len()); let mut liveness = liveness::liveness_of_locals(mir, LivenessMode { include_regular_use: true, @@ -396,24 +413,41 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, statement_index: data.statements.len(), }; - let storage_liveness = state_for_location(loc, &analysis, &storage_live, mir); + if let Some((ref analysis, ref result)) = borrowed_locals { + let borrowed_locals = state_for_location(loc, + analysis, + result, + mir); + // The `liveness` variable contains the liveness of MIR locals ignoring borrows. + // This is correct for movable generators since borrows cannot live across + // suspension points. However for immovable generators we need to account for + // borrows, so we conseratively assume that all borrowed locals live forever. + // To do this we just union our `liveness` result with `borrowed_locals`, which + // contains all the locals which has been borrowed before this suspension point. + // If a borrow is converted to a raw reference, we must also assume that it lives + // forever. Note that the final liveness is still bounded by the storage liveness + // of the local, which happens using the `intersect` operation below. + liveness.outs[block].union(&borrowed_locals); + } + + let mut storage_liveness = state_for_location(loc, + &storage_live_analysis, + &storage_live, + mir); + // Store the storage liveness for later use so we can restore the state + // after a suspension point storage_liveness_map.insert(block, storage_liveness.clone()); - let mut live_locals = storage_liveness; - // Mark locals without storage statements as always having live storage - live_locals.union(&ignored.0); + storage_liveness.union(&ignored.0); - if !movable { - // For immovable generators we consider borrowed locals to always be live. - // This effectively makes those locals use just the storage liveness. - liveness.outs[block].union(&borrowed_locals.0); - } + // Locals live are live at this point only if they are used across + // suspension points (the `liveness` variable) + // and their storage is live (the `storage_liveness` variable) + storage_liveness.intersect(&liveness.outs[block]); - // Locals live are live at this point only if they are used across suspension points - // and their storage is live - live_locals.intersect(&liveness.outs[block]); + let live_locals = storage_liveness; // Add the locals life at this suspension point to the set of locals which live across // any suspension points diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 43ee75d1e2b..ceea97e3ed3 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -19,7 +19,6 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::*; use rustc::mir::visit::*; use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; -use rustc::ty::layout::LayoutOf; use rustc::ty::subst::{Subst,Substs}; use std::collections::VecDeque; @@ -655,7 +654,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> Option<u64> { - (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes()) + tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes()) } fn subst_and_normalize<'a, 'tcx: 'a>( diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index c23f28fe220..008c71cc9ce 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -119,6 +119,11 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { kind.name()) .span_label(e.span, "can only break with a value inside `loop`") + .span_suggestion(e.span, + &format!("instead, use `break` on its own \ + without a value inside this `{}` loop", + kind.name()), + "break".to_string()) .emit(); } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ecf3c9e42d5..2da4bfedd3a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3998,14 +3998,20 @@ impl<'a> Resolver<'a> { if let (Ok(snippet), false) = (cm.span_to_snippet(binding.span), binding.is_renamed_extern_crate()) { + let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() { + format!("Other{}", name) + } else { + format!("other_{}", name) + }; + err.span_suggestion(binding.span, rename_msg, if snippet.ends_with(';') { - format!("{} as Other{};", + format!("{} as {};", &snippet[..snippet.len()-1], - name) + suggested_name) } else { - format!("{} as Other{}", snippet, name) + format!("{} as {}", snippet, suggested_name) }); } else { err.span_label(binding.span, rename_msg); diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs index fd5aa1364d3..e1c145b122d 100644 --- a/src/librustc_trans/allocator.rs +++ b/src/librustc_trans/allocator.rs @@ -86,6 +86,10 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) name.as_ptr(), ty); + if tcx.sess.target.target.options.default_hidden_visibility { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + let callee = CString::new(kind.fn_name(method.name)).unwrap(); let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr(), diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index c7be0c4e67d..751f8148a2a 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -59,8 +59,9 @@ pub fn trans_inline_asm<'a, 'tcx>( // Default per-arch clobbers // Basically what clang does let arch_clobbers = match &bx.sess().target.target.arch[..] { - "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"], - _ => Vec::new() + "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"], + "mips" | "mips64" => vec!["~{$1}"], + _ => Vec::new() }; let all_constraints = diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 15ff59c7df9..989ef8a9537 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -133,6 +133,8 @@ pub fn provide(providers: &mut Providers) { Arc::new(local_crate) }; + + providers.symbol_export_level = export_level; } pub fn provide_extern(providers: &mut Providers) { @@ -203,6 +205,7 @@ pub fn provide_extern(providers: &mut Providers) { Arc::new(crate_exports) }; + providers.symbol_export_level = export_level; } fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 8afa63a5e97..206c73b0174 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -824,9 +824,7 @@ fn binaryen_assemble(cgcx: &CodegenContext, if cgcx.debuginfo != config::NoDebugInfo { options.debuginfo(true); } - if cgcx.crate_types.contains(&config::CrateTypeExecutable) { - options.start("main"); - } + options.stack(1024 * 1024); options.import_memory(cgcx.wasm_import_memory); let assembled = input.and_then(|input| { @@ -1452,7 +1450,7 @@ fn start_executing_work(tcx: TyCtxt, target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen, debuginfo: tcx.sess.opts.debuginfo, - wasm_import_memory: wasm_import_memory, + wasm_import_memory, assembler_cmd, }; diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 06b8d9ff7b3..a285e5f263a 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -464,8 +464,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for &'a CodegenCx<'a, 'tcx> { type TyLayout = TyLayout<'tcx>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - (self.tcx, ty::ParamEnv::empty(traits::Reveal::All)) - .layout_of(ty) + self.tcx.layout_of(ty::ParamEnv::empty(traits::Reveal::All).and(ty)) .unwrap_or_else(|e| match e { LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()), _ => bug!("failed to get layout for `{}`: {}", ty, e) diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index b1533cfad19..af957500f70 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -57,7 +57,9 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::TyClosure(..) | ty::TyGenerator(..) | ty::TyAdt(..) | - ty::TyDynamic(..) | + // FIXME(eddyb) producing readable type names for trait objects can result + // in problematically distinct types due to HRTB and subtyping (see #47638). + // ty::TyDynamic(..) | ty::TyForeign(..) | ty::TyStr => { let mut name = String::with_capacity(32); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 570eecfc267..4c10f28eb8e 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -40,6 +40,8 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); + let impl_m_span = tcx.sess.codemap().def_span(impl_m_span); + if let Err(ErrorReported) = compare_self_type(tcx, impl_m, impl_m_span, @@ -186,6 +188,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_region_bounds_on_impl_method(tcx, impl_m_span, impl_m, + trait_m, &trait_m_generics, &impl_m_generics, trait_to_skol_substs)?; @@ -310,7 +313,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let mut diag = struct_span_err!(tcx.sess, - cause.span, + cause.span(&tcx), E0053, "method `{}` has an incompatible type for trait", trait_m.name); @@ -346,10 +349,12 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, impl_m: &ty::AssociatedItem, + trait_m: &ty::AssociatedItem, trait_generics: &ty::Generics, impl_generics: &ty::Generics, trait_to_skol_substs: &Substs<'tcx>) -> Result<(), ErrorReported> { + let span = tcx.sess.codemap().def_span(span); let trait_params = &trait_generics.regions[..]; let impl_params = &impl_generics.regions[..]; @@ -371,14 +376,18 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // are zero. Since I don't quite know how to phrase things at // the moment, give a kind of vague error message. if trait_params.len() != impl_params.len() { - struct_span_err!(tcx.sess, - span, - E0195, - "lifetime parameters or bounds on method `{}` do not match the \ - trait declaration", - impl_m.name) - .span_label(span, "lifetimes do not match trait") - .emit(); + let mut err = struct_span_err!(tcx.sess, + span, + E0195, + "lifetime parameters or bounds on method `{}` do not match \ + the trait declaration", + impl_m.name); + err.span_label(span, "lifetimes do not match method in trait"); + if let Some(sp) = tcx.hir.span_if_local(trait_m.def_id) { + err.span_label(tcx.sess.codemap().def_span(sp), + "lifetimes in impl do not match this method in trait"); + } + err.emit(); return Err(ErrorReported); } @@ -424,9 +433,9 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a }).map(|(ref impl_arg, ref trait_arg)| { (impl_arg.span, Some(trait_arg.span)) }) - .unwrap_or_else(|| (cause.span, tcx.hir.span_if_local(trait_m.def_id))) + .unwrap_or_else(|| (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))) } else { - (cause.span, tcx.hir.span_if_local(trait_m.def_id)) + (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)) } } TypeError::Sorts(ExpectedFound { .. }) => { @@ -459,14 +468,14 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a { (impl_m_output.span(), Some(trait_m_output.span())) } else { - (cause.span, tcx.hir.span_if_local(trait_m.def_id)) + (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)) } }) } else { - (cause.span, tcx.hir.span_if_local(trait_m.def_id)) + (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)) } } - _ => (cause.span, tcx.hir.span_if_local(trait_m.def_id)), + _ => (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)), } } diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 781eeaef248..2e45e3b1f35 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -150,15 +150,15 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'gcx, 'tcx> { } fn visit_pat(&mut self, pat: &'tcx Pat) { + intravisit::walk_pat(self, pat); + + self.expr_count += 1; + if let PatKind::Binding(..) = pat.node { let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id); let ty = self.fcx.tables.borrow().pat_ty(pat); self.record(ty, Some(scope), None, pat.span); } - - self.expr_count += 1; - - intravisit::walk_pat(self, pat); } fn visit_expr(&mut self, expr: &'tcx Expr) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 483dd345286..363d4a9dc0c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -100,7 +100,6 @@ use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc::ty::fold::TypeFoldable; use rustc::ty::maps::Providers; use rustc::ty::util::{Representability, IntTypeExt}; -use rustc::ty::layout::LayoutOf; use errors::{DiagnosticBuilder, DiagnosticId}; use require_c_abi_if_variadic; @@ -1015,7 +1014,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let span = body.value.span; if body.is_generator && can_be_generator.is_some() { - fcx.yield_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span))); + let yield_ty = fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)); + fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); + fcx.yield_ty = Some(yield_ty); } GatherLocalsVisitor { fcx: &fcx, }.visit_body(body); @@ -1551,7 +1552,7 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De let field_infos: Vec<_> = adt.non_enum_variant().fields.iter().map(|field| { let ty = field.ty(tcx, Substs::identity_for_item(tcx, field.did)); let param_env = tcx.param_env(field.did); - let layout = (tcx, param_env).layout_of(ty); + let layout = tcx.layout_of(param_env.and(ty)); // We are currently checking the type this field came from, so it must be local let span = tcx.hir.span_if_local(field.did).unwrap(); let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false); diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 07d5f813cbb..88a2dc817ae 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -82,29 +82,37 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for (i, &impl1_def_id) in impls.iter().enumerate() { for &impl2_def_id in &impls[(i + 1)..] { - let used_to_be_allowed = self.tcx.infer_ctxt().enter(|infcx| { - if let Some(overlap) = - traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id, - IntercrateMode::Issue43355) - { + let used_to_be_allowed = traits::overlapping_impls( + self.tcx, + impl1_def_id, + impl2_def_id, + IntercrateMode::Issue43355, + |overlap| { self.check_for_common_items_in_impls( - impl1_def_id, impl2_def_id, overlap, false); + impl1_def_id, + impl2_def_id, + overlap, + false, + ); false - } else { - true - } - }); + }, + || true, + ); if used_to_be_allowed { - self.tcx.infer_ctxt().enter(|infcx| { - if let Some(overlap) = - traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id, - IntercrateMode::Fixed) - { - self.check_for_common_items_in_impls( - impl1_def_id, impl2_def_id, overlap, true); - } - }); + traits::overlapping_impls( + self.tcx, + impl1_def_id, + impl2_def_id, + IntercrateMode::Fixed, + |overlap| self.check_for_common_items_in_impls( + impl1_def_id, + impl2_def_id, + overlap, + true, + ), + || (), + ); } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0929b833c19..7c9a49c82a9 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2447,7 +2447,12 @@ impl Clean<Type> for hir::Ty { let def_id = cx.tcx.hir.body_owner_def_id(n); let param_env = cx.tcx.param_env(def_id); let substs = Substs::identity_for_item(cx.tcx, def_id); - let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap(); + let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap_or_else(|_| { + cx.tcx.mk_const(ty::Const { + val: ConstVal::Unevaluated(def_id, substs), + ty: cx.tcx.types.usize + }) + }); let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { n.to_string() } else if let ConstVal::Unevaluated(def_id, _) = n.val { @@ -2577,7 +2582,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { let mut n = cx.tcx.lift(&n).unwrap(); if let ConstVal::Unevaluated(def_id, substs) = n.val { let param_env = cx.tcx.param_env(def_id); - n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap() + if let Ok(new_n) = cx.tcx.const_eval(param_env.and((def_id, substs))) { + n = new_n; + } }; let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { n.to_string() diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index d2eeb2e15b3..2b1f920bba0 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -181,15 +181,19 @@ nav.sub { overflow: auto; } -.sidebar .current { +.sidebar .block > ul > li { margin-right: -20px; } -.content, nav { max-width: 960px; } +.content, nav { + max-width: 960px; +} /* Everything else */ -.js-only, .hidden { display: none !important; } +.js-only, .hidden { + display: none !important; +} .sidebar img { margin: 20px auto; @@ -218,7 +222,9 @@ nav.sub { border: none; } -.location a:first-child { font-weight: 500; } +.location a:first-child { + font-weight: 500; +} .block { padding: 0; @@ -299,7 +305,9 @@ nav.sub { -ms-user-select: none; user-select: none; } -.line-numbers span { cursor: pointer; } +.line-numbers span { + cursor: pointer; +} .docblock-short p { display: inline; @@ -317,7 +325,9 @@ nav.sub { text-overflow: ellipsis; margin: 0; } -.docblock-short code { white-space: nowrap; } +.docblock-short code { + white-space: nowrap; +} .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { border-bottom: 1px solid; @@ -384,7 +394,9 @@ h4 > code, h3 > code, .invisible > code { display: inline-block; } -#main { position: relative; } +#main { + position: relative; +} #main > .since { top: inherit; font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; @@ -428,7 +440,9 @@ h4 > code, h3 > code, .invisible > code { padding: 0; } -.content .item-list li { margin-bottom: 1em; } +.content .item-list li { + margin-bottom: 1em; +} .content .multi-column { -moz-column-count: 5; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index d61b80c9aa0..087d88419bc 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -238,6 +238,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, )); let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()), Some(codemap.clone()), + false, false); let old = io::set_panic(Some(box Sink(data.clone()))); let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout())); diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 3430ecabcbe..c1fe4a89d6a 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -48,3 +48,4 @@ jemalloc = ["alloc_jemalloc"] force_alloc_system = [] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] +wasm_syscall = [] diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 9810dede618..ecf68f29d6f 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1531,6 +1531,7 @@ mod tests { assert!(nan.to_degrees().is_nan()); assert_eq!(inf.to_degrees(), inf); assert_eq!(neg_inf.to_degrees(), neg_inf); + assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); } #[test] diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index d1f3ccbd2c6..5cea389531f 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -482,20 +482,42 @@ impl File { self.inner.file_attr().map(Metadata) } - /// Creates a new independently owned handle to the underlying file. - /// - /// The returned `File` is a reference to the same state that this object - /// references. Both handles will read and write with the same cursor - /// position. + /// Create a new `File` instance that shares the same underlying file handle + /// as the existing `File` instance. Reads, writes, and seeks will affect + /// both `File` instances simultaneously. /// /// # Examples /// + /// Create two handles for a file named `foo.txt`: + /// /// ```no_run /// use std::fs::File; /// /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let file_copy = f.try_clone()?; + /// let mut file = File::open("foo.txt")?; + /// let file_copy = file.try_clone()?; + /// # Ok(()) + /// # } + /// ``` + /// + /// Assuming there’s a file named `foo.txt` with contents `abcdef\n`, create + /// two handles, seek one of them, and read the remaining bytes from the + /// other handle: + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::SeekFrom; + /// use std::io::prelude::*; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// let mut file_copy = file.try_clone()?; + /// + /// file.seek(SeekFrom::Start(3))?; + /// + /// let mut contents = vec![]; + /// file_copy.read_to_end(&mut contents)?; + /// assert_eq!(contents, b"def\n"); /// # Ok(()) /// # } /// ``` @@ -1001,7 +1023,7 @@ impl Metadata { self.0.accessed().map(FromInner::from_inner) } - /// Returns the creation time listed in the this metadata. + /// Returns the creation time listed in this metadata. /// /// The returned value corresponds to the `birthtime` field of `stat` on /// Unix platforms and the `ftCreationTime` field on Windows platforms. diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index f0b41f30251..bdd675e6e2b 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -292,8 +292,8 @@ impl Error { /// # if cfg!(target_os = "linux") { /// use std::io; /// - /// let error = io::Error::from_raw_os_error(98); - /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse); + /// let error = io::Error::from_raw_os_error(22); + /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput); /// # } /// ``` /// @@ -303,8 +303,8 @@ impl Error { /// # if cfg!(windows) { /// use std::io; /// - /// let error = io::Error::from_raw_os_error(10048); - /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse); + /// let error = io::Error::from_raw_os_error(10022); + /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput); /// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index c980ae75261..78a3b82546e 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -111,10 +111,11 @@ impl Drop for Thread { #[cfg_attr(test, allow(dead_code))] pub mod guard { - pub unsafe fn current() -> Option<usize> { + pub type Guard = !; + pub unsafe fn current() -> Option<Guard> { None } - pub unsafe fn init() -> Option<usize> { + pub unsafe fn init() -> Option<Guard> { None } } diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index c4aad8d86f8..c4719a94c7e 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -88,6 +88,7 @@ impl Thread { } pub mod guard { - pub unsafe fn current() -> Option<usize> { None } - pub unsafe fn init() -> Option<usize> { None } + pub type Guard = !; + pub unsafe fn current() -> Option<Guard> { None } + pub unsafe fn init() -> Option<Guard> { None } } diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 51adbc24ae0..40453f9b8a1 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -57,9 +57,6 @@ mod imp { use sys_common::thread_info; - // This is initialized in init() and only read from after - static mut PAGE_SIZE: usize = 0; - #[cfg(any(target_os = "linux", target_os = "android"))] unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { #[repr(C)] @@ -102,12 +99,12 @@ mod imp { _data: *mut libc::c_void) { use sys_common::util::report_overflow; - let guard = thread_info::stack_guard().unwrap_or(0); + let guard = thread_info::stack_guard().unwrap_or(0..0); let addr = siginfo_si_addr(info); // If the faulting address is within the guard page, then we print a // message saying so and abort. - if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard { + if guard.start <= addr && addr < guard.end { report_overflow(); rtabort!("stack overflow"); } else { @@ -123,8 +120,6 @@ mod imp { static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut(); pub unsafe fn init() { - PAGE_SIZE = ::sys::os::page_size(); - let mut action: sigaction = mem::zeroed(); action.sa_flags = SA_SIGINFO | SA_ONSTACK; action.sa_sigaction = signal_handler as sighandler_t; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 525882c1e1e..72cdb9440b8 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -205,8 +205,10 @@ impl Drop for Thread { not(target_os = "solaris")))] #[cfg_attr(test, allow(dead_code))] pub mod guard { - pub unsafe fn current() -> Option<usize> { None } - pub unsafe fn init() -> Option<usize> { None } + use ops::Range; + pub type Guard = Range<usize>; + pub unsafe fn current() -> Option<Guard> { None } + pub unsafe fn init() -> Option<Guard> { None } } @@ -222,14 +224,43 @@ pub mod guard { use libc; use libc::mmap; use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED}; + use ops::Range; use sys::os; - #[cfg(any(target_os = "macos", - target_os = "bitrig", - target_os = "openbsd", - target_os = "solaris"))] + // This is initialized in init() and only read from after + static mut PAGE_SIZE: usize = 0; + + pub type Guard = Range<usize>; + + #[cfg(target_os = "solaris")] + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + let mut current_stack: libc::stack_t = ::mem::zeroed(); + assert_eq!(libc::stack_getbounds(&mut current_stack), 0); + Some(current_stack.ss_sp) + } + + #[cfg(target_os = "macos")] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { - current().map(|s| s as *mut libc::c_void) + let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - + libc::pthread_get_stacksize_np(libc::pthread_self()); + Some(stackaddr as *mut libc::c_void) + } + + #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + let mut current_stack: libc::stack_t = ::mem::zeroed(); + assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), + &mut current_stack), 0); + + let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE; + let stackaddr = if libc::pthread_main_np() == 1 { + // main thread + current_stack.ss_sp as usize - current_stack.ss_size + extra + } else { + // new thread + current_stack.ss_sp as usize - current_stack.ss_size + }; + Some(stackaddr as *mut libc::c_void) } #[cfg(any(target_os = "android", target_os = "freebsd", @@ -253,8 +284,9 @@ pub mod guard { ret } - pub unsafe fn init() -> Option<usize> { - let psize = os::page_size(); + pub unsafe fn init() -> Option<Guard> { + PAGE_SIZE = os::page_size(); + let mut stackaddr = get_stack_start()?; // Ensure stackaddr is page aligned! A parent process might @@ -263,9 +295,9 @@ pub mod guard { // stackaddr < stackaddr + stacksize, so if stackaddr is not // page-aligned, calculate the fix such that stackaddr < // new_page_aligned_stackaddr < stackaddr + stacksize - let remainder = (stackaddr as usize) % psize; + let remainder = (stackaddr as usize) % PAGE_SIZE; if remainder != 0 { - stackaddr = ((stackaddr as usize) + psize - remainder) + stackaddr = ((stackaddr as usize) + PAGE_SIZE - remainder) as *mut libc::c_void; } @@ -280,60 +312,42 @@ pub mod guard { // Instead, we'll just note where we expect rlimit to start // faulting, so our handler can report "stack overflow", and // trust that the kernel's own stack guard will work. - Some(stackaddr as usize) + let stackaddr = stackaddr as usize; + Some(stackaddr - PAGE_SIZE..stackaddr) } else { // Reallocate the last page of the stack. // This ensures SIGBUS will be raised on // stack overflow. - let result = mmap(stackaddr, psize, PROT_NONE, + let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); if result != stackaddr || result == MAP_FAILED { panic!("failed to allocate a guard page"); } + let guardaddr = stackaddr as usize; let offset = if cfg!(target_os = "freebsd") { 2 } else { 1 }; - Some(stackaddr as usize + offset * psize) + Some(guardaddr..guardaddr + offset * PAGE_SIZE) } } - #[cfg(target_os = "solaris")] - pub unsafe fn current() -> Option<usize> { - let mut current_stack: libc::stack_t = ::mem::zeroed(); - assert_eq!(libc::stack_getbounds(&mut current_stack), 0); - Some(current_stack.ss_sp as usize) - } - - #[cfg(target_os = "macos")] - pub unsafe fn current() -> Option<usize> { - Some(libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - - libc::pthread_get_stacksize_np(libc::pthread_self())) - } - - #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] - pub unsafe fn current() -> Option<usize> { - let mut current_stack: libc::stack_t = ::mem::zeroed(); - assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), - &mut current_stack), 0); - - let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size(); - Some(if libc::pthread_main_np() == 1 { - // main thread - current_stack.ss_sp as usize - current_stack.ss_size + extra - } else { - // new thread - current_stack.ss_sp as usize - current_stack.ss_size - }) + #[cfg(any(target_os = "macos", + target_os = "bitrig", + target_os = "openbsd", + target_os = "solaris"))] + pub unsafe fn current() -> Option<Guard> { + let stackaddr = get_stack_start()? as usize; + Some(stackaddr - PAGE_SIZE..stackaddr) } #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux", target_os = "netbsd", target_os = "l4re"))] - pub unsafe fn current() -> Option<usize> { + pub unsafe fn current() -> Option<Guard> { let mut ret = None; let mut attr: libc::pthread_attr_t = ::mem::zeroed(); assert_eq!(libc::pthread_attr_init(&mut attr), 0); @@ -352,12 +366,23 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); + let stackaddr = stackaddr as usize; ret = if cfg!(target_os = "freebsd") { - Some(stackaddr as usize - guardsize) + // FIXME does freebsd really fault *below* the guard addr? + let guardaddr = stackaddr - guardsize; + Some(guardaddr - PAGE_SIZE..guardaddr) } else if cfg!(target_os = "netbsd") { - Some(stackaddr as usize) + Some(stackaddr - guardsize..stackaddr) + } else if cfg!(all(target_os = "linux", target_env = "gnu")) { + // glibc used to include the guard area within the stack, as noted in the BUGS + // section of `man pthread_attr_getguardsize`. This has been corrected starting + // with glibc 2.27, and in some distro backports, so the guard is now placed at the + // end (below) the stack. There's no easy way for us to know which we have at + // runtime, so we'll just match any fault in the range right above or below the + // stack base to call that fault a stack overflow. + Some(stackaddr - guardsize..stackaddr + guardsize) } else { - Some(stackaddr as usize + guardsize) + Some(stackaddr..stackaddr + guardsize) }; } assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs index d2a4a7b19d5..b3c6b671e80 100644 --- a/src/libstd/sys/wasm/args.rs +++ b/src/libstd/sys/wasm/args.rs @@ -10,8 +10,8 @@ use ffi::OsString; use marker::PhantomData; -use mem; use vec; +use sys::ArgsSysCall; pub unsafe fn init(_argc: isize, _argv: *const *const u8) { // On wasm these should always be null, so there's nothing for us to do here @@ -21,38 +21,10 @@ pub unsafe fn cleanup() { } pub fn args() -> Args { - // When the runtime debugging is enabled we'll link to some extra runtime - // functions to actually implement this. These are for now just implemented - // in a node.js script but they're off by default as they're sort of weird - // in a web-wasm world. - if !super::DEBUG { - return Args { - iter: Vec::new().into_iter(), - _dont_send_or_sync_me: PhantomData, - } - } - - // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These - // are just meant for debugging and should not be relied on. - extern { - fn rust_wasm_args_count() -> usize; - fn rust_wasm_args_arg_size(a: usize) -> usize; - fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8); - } - - unsafe { - let cnt = rust_wasm_args_count(); - let mut v = Vec::with_capacity(cnt); - for i in 0..cnt { - let n = rust_wasm_args_arg_size(i); - let mut data = vec![0; n]; - rust_wasm_args_arg_fill(i, data.as_mut_ptr()); - v.push(mem::transmute::<Vec<u8>, OsString>(data)); - } - Args { - iter: v.into_iter(), - _dont_send_or_sync_me: PhantomData, - } + let v = ArgsSysCall::perform(); + Args { + iter: v.into_iter(), + _dont_send_or_sync_me: PhantomData, } } diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index ba3d6a2813a..c02e5e809c8 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -26,17 +26,11 @@ use io; use os::raw::c_char; - -// Right now the wasm backend doesn't even have the ability to print to the -// console by default. Wasm can't import anything from JS! (you have to -// explicitly provide it). -// -// Sometimes that's a real bummer, though, so this flag can be set to `true` to -// enable calling various shims defined in `src/etc/wasm32-shim.js` which should -// help receive debug output and see what's going on. In general this flag -// currently controls "will we call out to our own defined shims in node.js", -// and this flag should always be `false` for release builds. -const DEBUG: bool = false; +use ptr; +use sys::os_str::Buf; +use sys_common::{AsInner, FromInner}; +use ffi::{OsString, OsStr}; +use time::Duration; pub mod args; #[cfg(feature = "backtrace")] @@ -92,7 +86,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize { } pub unsafe fn abort_internal() -> ! { - ::intrinsics::abort(); + ExitSysCall::perform(1) } // We don't have randomness yet, but I totally used a random number generator to @@ -103,3 +97,218 @@ pub unsafe fn abort_internal() -> ! { pub fn hashmap_random_keys() -> (u64, u64) { (1, 2) } + +// Implement a minimal set of system calls to enable basic IO +pub enum SysCallIndex { + Read = 0, + Write = 1, + Exit = 2, + Args = 3, + GetEnv = 4, + SetEnv = 5, + Time = 6, +} + +#[repr(C)] +pub struct ReadSysCall { + fd: usize, + ptr: *mut u8, + len: usize, + result: usize, +} + +impl ReadSysCall { + pub fn perform(fd: usize, buffer: &mut [u8]) -> usize { + let mut call_record = ReadSysCall { + fd, + len: buffer.len(), + ptr: buffer.as_mut_ptr(), + result: 0 + }; + if unsafe { syscall(SysCallIndex::Read, &mut call_record) } { + call_record.result + } else { + 0 + } + } +} + +#[repr(C)] +pub struct WriteSysCall { + fd: usize, + ptr: *const u8, + len: usize, +} + +impl WriteSysCall { + pub fn perform(fd: usize, buffer: &[u8]) { + let mut call_record = WriteSysCall { + fd, + len: buffer.len(), + ptr: buffer.as_ptr() + }; + unsafe { syscall(SysCallIndex::Write, &mut call_record); } + } +} + +#[repr(C)] +pub struct ExitSysCall { + code: usize, +} + +impl ExitSysCall { + pub fn perform(code: usize) -> ! { + let mut call_record = ExitSysCall { + code + }; + unsafe { + syscall(SysCallIndex::Exit, &mut call_record); + ::intrinsics::abort(); + } + } +} + +fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F) + -> Result<Vec<u8>, E> +{ + let mut buffer = vec![0; estimate]; + loop { + let result = f(&mut buffer)?; + if result <= buffer.len() { + buffer.truncate(result); + break; + } + buffer.resize(result, 0); + } + Ok(buffer) +} + +#[repr(C)] +pub struct ArgsSysCall { + ptr: *mut u8, + len: usize, + result: usize +} + +impl ArgsSysCall { + pub fn perform() -> Vec<OsString> { + receive_buffer(1024, |buffer| -> Result<usize, !> { + let mut call_record = ArgsSysCall { + len: buffer.len(), + ptr: buffer.as_mut_ptr(), + result: 0 + }; + if unsafe { syscall(SysCallIndex::Args, &mut call_record) } { + Ok(call_record.result) + } else { + Ok(0) + } + }) + .unwrap() + .split(|b| *b == 0) + .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() })) + .collect() + } +} + +#[repr(C)] +pub struct GetEnvSysCall { + key_ptr: *const u8, + key_len: usize, + value_ptr: *mut u8, + value_len: usize, + result: usize +} + +impl GetEnvSysCall { + pub fn perform(key: &OsStr) -> Option<OsString> { + let key_buf = &AsInner::as_inner(key).inner; + receive_buffer(64, |buffer| { + let mut call_record = GetEnvSysCall { + key_len: key_buf.len(), + key_ptr: key_buf.as_ptr(), + value_len: buffer.len(), + value_ptr: buffer.as_mut_ptr(), + result: !0usize + }; + if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } { + if call_record.result == !0usize { + Err(()) + } else { + Ok(call_record.result) + } + } else { + Err(()) + } + }).ok().map(|s| { + FromInner::from_inner(Buf { inner: s }) + }) + } +} + +#[repr(C)] +pub struct SetEnvSysCall { + key_ptr: *const u8, + key_len: usize, + value_ptr: *const u8, + value_len: usize +} + +impl SetEnvSysCall { + pub fn perform(key: &OsStr, value: Option<&OsStr>) { + let key_buf = &AsInner::as_inner(key).inner; + let value_buf = value.map(|v| &AsInner::as_inner(v).inner); + let mut call_record = SetEnvSysCall { + key_len: key_buf.len(), + key_ptr: key_buf.as_ptr(), + value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize), + value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null()) + }; + unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); } + } +} + +pub enum TimeClock { + Monotonic = 0, + System = 1, +} + +#[repr(C)] +pub struct TimeSysCall { + clock: usize, + secs_hi: usize, + secs_lo: usize, + nanos: usize +} + +impl TimeSysCall { + pub fn perform(clock: TimeClock) -> Duration { + let mut call_record = TimeSysCall { + clock: clock as usize, + secs_hi: 0, + secs_lo: 0, + nanos: 0 + }; + if unsafe { syscall(SysCallIndex::Time, &mut call_record) } { + Duration::new( + ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64), + call_record.nanos as u32 + ) + } else { + panic!("Time system call is not implemented by WebAssembly host"); + } + } +} + +unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool { + #[cfg(feature = "wasm_syscall")] + extern { + #[no_mangle] + fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize; + } + + #[cfg(not(feature = "wasm_syscall"))] + unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 } + + rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0 +} diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs index c98030f7ebf..23ca1754719 100644 --- a/src/libstd/sys/wasm/os.rs +++ b/src/libstd/sys/wasm/os.rs @@ -8,16 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::intrinsics; - use error::Error as StdError; use ffi::{OsString, OsStr}; use fmt; use io; -use mem; use path::{self, PathBuf}; use str; -use sys::{unsupported, Void}; +use sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall}; pub fn errno() -> i32 { 0 @@ -87,36 +84,15 @@ pub fn env() -> Env { } pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { - // If we're debugging the runtime then we actually probe node.js to ask for - // the value of environment variables to help provide inputs to programs. - // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are - // intended for debugging only, you should not rely on them. - if !super::DEBUG { - return Ok(None) - } - - extern { - fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize; - fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8); - } - unsafe { - let k: &[u8] = mem::transmute(k); - let n = rust_wasm_getenv_len(k.as_ptr(), k.len()); - if n == -1 { - return Ok(None) - } - let mut data = vec![0; n as usize]; - rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr()); - Ok(Some(mem::transmute(data))) - } + Ok(GetEnvSysCall::perform(k)) } -pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> { - unsupported() +pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + Ok(SetEnvSysCall::perform(k, Some(v))) } -pub fn unsetenv(_n: &OsStr) -> io::Result<()> { - unsupported() +pub fn unsetenv(k: &OsStr) -> io::Result<()> { + Ok(SetEnvSysCall::perform(k, None)) } pub fn temp_dir() -> PathBuf { @@ -128,7 +104,7 @@ pub fn home_dir() -> Option<PathBuf> { } pub fn exit(_code: i32) -> ! { - unsafe { intrinsics::abort() } + ExitSysCall::perform(_code as isize as usize) } pub fn getpid() -> u32 { diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs index 0f75f240251..beb19c0ed2c 100644 --- a/src/libstd/sys/wasm/stdio.rs +++ b/src/libstd/sys/wasm/stdio.rs @@ -9,19 +9,19 @@ // except according to those terms. use io; -use sys::{Void, unsupported}; +use sys::{ReadSysCall, WriteSysCall}; -pub struct Stdin(Void); +pub struct Stdin; pub struct Stdout; pub struct Stderr; impl Stdin { pub fn new() -> io::Result<Stdin> { - unsupported() + Ok(Stdin) } - pub fn read(&self, _data: &mut [u8]) -> io::Result<usize> { - match self.0 {} + pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { + Ok(ReadSysCall::perform(0, data)) } } @@ -31,19 +31,7 @@ impl Stdout { } pub fn write(&self, data: &[u8]) -> io::Result<usize> { - // If runtime debugging is enabled at compile time we'll invoke some - // runtime functions that are defined in our src/etc/wasm32-shim.js - // debugging script. Note that this ffi function call is intended - // *purely* for debugging only and should not be relied upon. - if !super::DEBUG { - return unsupported() - } - extern { - fn rust_wasm_write_stdout(data: *const u8, len: usize); - } - unsafe { - rust_wasm_write_stdout(data.as_ptr(), data.len()) - } + WriteSysCall::perform(1, data); Ok(data.len()) } @@ -58,16 +46,7 @@ impl Stderr { } pub fn write(&self, data: &[u8]) -> io::Result<usize> { - // See comments in stdout for what's going on here. - if !super::DEBUG { - return unsupported() - } - extern { - fn rust_wasm_write_stderr(data: *const u8, len: usize); - } - unsafe { - rust_wasm_write_stderr(data.as_ptr(), data.len()) - } + WriteSysCall::perform(2, data); Ok(data.len()) } diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 13980e0cc19..6a066509b49 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -43,6 +43,7 @@ impl Thread { } pub mod guard { - pub unsafe fn current() -> Option<usize> { None } - pub unsafe fn init() -> Option<usize> { None } + pub type Guard = !; + pub unsafe fn current() -> Option<Guard> { None } + pub unsafe fn init() -> Option<Guard> { None } } diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs index c269def98f6..e52435e6339 100644 --- a/src/libstd/sys/wasm/time.rs +++ b/src/libstd/sys/wasm/time.rs @@ -8,56 +8,50 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use fmt; use time::Duration; +use sys::{TimeSysCall, TimeClock}; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant; +pub struct Instant(Duration); -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SystemTime; +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(Duration); -pub const UNIX_EPOCH: SystemTime = SystemTime; +pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); impl Instant { pub fn now() -> Instant { - panic!("not supported on web assembly"); + Instant(TimeSysCall::perform(TimeClock::Monotonic)) } - pub fn sub_instant(&self, _other: &Instant) -> Duration { - panic!("can't sub yet"); + pub fn sub_instant(&self, other: &Instant) -> Duration { + self.0 - other.0 } - pub fn add_duration(&self, _other: &Duration) -> Instant { - panic!("can't add yet"); + pub fn add_duration(&self, other: &Duration) -> Instant { + Instant(self.0 + *other) } - pub fn sub_duration(&self, _other: &Duration) -> Instant { - panic!("can't sub yet"); + pub fn sub_duration(&self, other: &Duration) -> Instant { + Instant(self.0 - *other) } } impl SystemTime { pub fn now() -> SystemTime { - panic!("not supported on web assembly"); + SystemTime(TimeSysCall::perform(TimeClock::System)) } - pub fn sub_time(&self, _other: &SystemTime) + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - panic!() - } - - pub fn add_duration(&self, _other: &Duration) -> SystemTime { - panic!() + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - pub fn sub_duration(&self, _other: &Duration) -> SystemTime { - panic!() + pub fn add_duration(&self, other: &Duration) -> SystemTime { + SystemTime(self.0 + *other) } -} -impl fmt::Debug for SystemTime { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - panic!() + pub fn sub_duration(&self, other: &Duration) -> SystemTime { + SystemTime(self.0 - *other) } } diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 74786d09285..43abfbb1f64 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -93,6 +93,7 @@ impl Thread { #[cfg_attr(test, allow(dead_code))] pub mod guard { - pub unsafe fn current() -> Option<usize> { None } - pub unsafe fn init() -> Option<usize> { None } + pub type Guard = !; + pub unsafe fn current() -> Option<Guard> { None } + pub unsafe fn init() -> Option<Guard> { None } } diff --git a/src/libstd/sys_common/thread_info.rs b/src/libstd/sys_common/thread_info.rs index 7970042b1d6..6a2b6742367 100644 --- a/src/libstd/sys_common/thread_info.rs +++ b/src/libstd/sys_common/thread_info.rs @@ -11,10 +11,11 @@ #![allow(dead_code)] // stack_guard isn't used right now on all platforms use cell::RefCell; +use sys::thread::guard::Guard; use thread::Thread; struct ThreadInfo { - stack_guard: Option<usize>, + stack_guard: Option<Guard>, thread: Thread, } @@ -38,11 +39,11 @@ pub fn current_thread() -> Option<Thread> { ThreadInfo::with(|info| info.thread.clone()) } -pub fn stack_guard() -> Option<usize> { - ThreadInfo::with(|info| info.stack_guard).and_then(|o| o) +pub fn stack_guard() -> Option<Guard> { + ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o) } -pub fn set(stack_guard: Option<usize>, thread: Thread) { +pub fn set(stack_guard: Option<Guard>, thread: Thread) { THREAD_INFO.with(|c| assert!(c.borrow().is_none())); THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ stack_guard, diff --git a/src/libstd/time/mod.rs b/src/libstd/time.rs index 6ce3b3e8a00..12f2a9bb85f 100644 --- a/src/libstd/time/mod.rs +++ b/src/libstd/time.rs @@ -29,9 +29,7 @@ use sys::time; use sys_common::FromInner; #[stable(feature = "time", since = "1.3.0")] -pub use self::duration::Duration; - -mod duration; +pub use core::time::Duration; /// A measurement of a monotonically nondecreasing clock. /// Opaque and useful only with `Duration`. diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 73810b3fe81..c7ab6158256 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -883,7 +883,6 @@ pub struct Arm { pub pats: Vec<P<Pat>>, pub guard: Option<P<Expr>>, pub body: P<Expr>, - pub beginning_vert: Option<Span>, // For RFC 1925 feature gate } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index a6a7f9e20b3..3601b9ba8a8 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -593,8 +593,30 @@ impl CodeMap { } } - /// Given a `Span`, try to get a shorter span ending just after the first - /// occurrence of `char` `c`. + /// Given a `Span`, get a new `Span` covering the first token and all its trailing whitespace or + /// the original `Span`. + /// + /// If `sp` points to `"let mut x"`, then a span pointing at `"let "` will be returned. + pub fn span_until_non_whitespace(&self, sp: Span) -> Span { + if let Ok(snippet) = self.span_to_snippet(sp) { + let mut offset = 0; + // get the bytes width of all the non-whitespace characters + for c in snippet.chars().take_while(|c| !c.is_whitespace()) { + offset += c.len_utf8(); + } + // get the bytes width of all the whitespace characters after that + for c in snippet[offset..].chars().take_while(|c| c.is_whitespace()) { + offset += c.len_utf8(); + } + if offset > 1 { + return sp.with_hi(BytePos(sp.lo().0 + offset as u32)); + } + } + sp + } + + /// Given a `Span`, try to get a shorter span ending just after the first occurrence of `char` + /// `c`. pub fn span_through_char(&self, sp: Span, c: char) -> Span { if let Ok(snippet) = self.span_to_snippet(sp) { if let Some(offset) = snippet.find(c) { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index cf63592c2ec..2e6de96d65a 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -883,7 +883,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { pats, guard: None, body: expr, - beginning_vert: None, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9a2560b0458..3e858c3b923 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -386,9 +386,6 @@ declare_features! ( // allow `#[must_use]` on functions and comparison operators (RFC 1940) (active, fn_must_use, "1.21.0", Some(43302)), - // allow '|' at beginning of match arms (RFC 1925) - (active, match_beginning_vert, "1.21.0", Some(44101)), - // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008) (active, non_exhaustive, "1.22.0", Some(44109)), @@ -545,6 +542,8 @@ declare_features! ( (accepted, abi_sysv64, "1.24.0", Some(36167)), // Allows `repr(align(16))` struct attribute (RFC 1358) (accepted, repr_align, "1.24.0", Some(33626)), + // allow '|' at beginning of match arms (RFC 1925) + (accepted, match_beginning_vert, "1.25.0", Some(44101)), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -788,6 +787,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), + ("rustc_serialize_exclude_null", Normal, Gated(Stability::Unstable, + "rustc_attrs", + "the `#[rustc_serialize_exclude_null]` attribute \ + is an internal-only feature", + cfg_fn!(rustc_attrs))), ("rustc_synthetic", Whitelisted, Gated(Stability::Unstable, "rustc_attrs", "this attribute \ @@ -1678,11 +1682,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_arm(&mut self, arm: &'a ast::Arm) { - if let Some(span) = arm.beginning_vert { - gate_feature_post!(&self, match_beginning_vert, - span, - "Use of a '|' at the beginning of a match arm is experimental") - } visit::walk_arm(self, arm) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 0f8fe57e380..921ed3565a4 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -340,14 +340,13 @@ pub fn fold_thin_attrs<T: Folder>(attrs: ThinVec<Attribute>, fld: &mut T) -> Thi fold_attrs(attrs.into(), fld).into() } -pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body, beginning_vert}: Arm, +pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm, fld: &mut T) -> Arm { Arm { attrs: fold_attrs(attrs, fld), pats: pats.move_map(|x| fld.fold_pat(x)), guard: guard.map(|x| fld.fold_expr(x)), body: fld.fold_expr(body), - beginning_vert, } } diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 54c726d8462..98d5fa8f797 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -38,34 +38,41 @@ pub struct JsonEmitter { registry: Option<Registry>, cm: Rc<CodeMapper + 'static>, pretty: bool, + /// Whether "approximate suggestions" are enabled in the config + approximate_suggestions: bool, } impl JsonEmitter { pub fn stderr(registry: Option<Registry>, code_map: Rc<CodeMap>, - pretty: bool) -> JsonEmitter { + pretty: bool, + approximate_suggestions: bool) -> JsonEmitter { JsonEmitter { dst: Box::new(io::stderr()), registry, cm: code_map, pretty, + approximate_suggestions, } } pub fn basic(pretty: bool) -> JsonEmitter { let file_path_mapping = FilePathMapping::empty(); - JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), pretty) + JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), + pretty, false) } pub fn new(dst: Box<Write + Send>, registry: Option<Registry>, code_map: Rc<CodeMap>, - pretty: bool) -> JsonEmitter { + pretty: bool, + approximate_suggestions: bool) -> JsonEmitter { JsonEmitter { dst, registry, cm: code_map, pretty, + approximate_suggestions, } } } @@ -101,6 +108,7 @@ struct Diagnostic { } #[derive(RustcEncodable)] +#[allow(unused_attributes)] struct DiagnosticSpan { file_name: String, byte_start: u32, @@ -121,6 +129,9 @@ struct DiagnosticSpan { /// If we are suggesting a replacement, this will contain text /// that should be sliced in atop this span. suggested_replacement: Option<String>, + /// If the suggestion is approximate + #[rustc_serialize_exclude_null] + suggestion_approximate: Option<bool>, /// Macro invocations that created the code at this span, if any. expansion: Option<Box<DiagnosticSpanMacroExpansion>>, } @@ -188,7 +199,7 @@ impl Diagnostic { } let buf = BufWriter::default(); let output = buf.clone(); - EmitterWriter::new(Box::new(buf), Some(je.cm.clone()), false).emit(db); + EmitterWriter::new(Box::new(buf), Some(je.cm.clone()), false, false).emit(db); let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = String::from_utf8(output).unwrap(); @@ -220,7 +231,7 @@ impl Diagnostic { impl DiagnosticSpan { fn from_span_label(span: SpanLabel, - suggestion: Option<&String>, + suggestion: Option<(&String, bool)>, je: &JsonEmitter) -> DiagnosticSpan { Self::from_span_etc(span.span, @@ -233,7 +244,7 @@ impl DiagnosticSpan { fn from_span_etc(span: Span, is_primary: bool, label: Option<String>, - suggestion: Option<&String>, + suggestion: Option<(&String, bool)>, je: &JsonEmitter) -> DiagnosticSpan { // obtain the full backtrace from the `macro_backtrace` @@ -253,7 +264,7 @@ impl DiagnosticSpan { fn from_span_full(span: Span, is_primary: bool, label: Option<String>, - suggestion: Option<&String>, + suggestion: Option<(&String, bool)>, mut backtrace: vec::IntoIter<MacroBacktrace>, je: &JsonEmitter) -> DiagnosticSpan { @@ -281,6 +292,13 @@ impl DiagnosticSpan { def_site_span, }) }); + + let suggestion_approximate = if je.approximate_suggestions { + suggestion.map(|x| x.1) + } else { + None + }; + DiagnosticSpan { file_name: start.file.name.to_string(), byte_start: span.lo().0 - start.file.start_pos.0, @@ -291,7 +309,8 @@ impl DiagnosticSpan { column_end: end.col.0 + 1, is_primary, text: DiagnosticSpanLine::from_span(span, je), - suggested_replacement: suggestion.cloned(), + suggested_replacement: suggestion.map(|x| x.0.clone()), + suggestion_approximate, expansion: backtrace_step, label, } @@ -309,14 +328,15 @@ impl DiagnosticSpan { suggestion.substitutions .iter() .flat_map(|substitution| { - substitution.parts.iter().map(move |suggestion| { + substitution.parts.iter().map(move |suggestion_inner| { let span_label = SpanLabel { - span: suggestion.span, + span: suggestion_inner.span, is_primary: true, label: None, }; DiagnosticSpan::from_span_label(span_label, - Some(&suggestion.snippet), + Some((&suggestion_inner.snippet, + suggestion.approximate)), je) }) }) diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 3b4c5da10f2..9181cca215c 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -25,6 +25,7 @@ #![feature(match_default_bindings)] #![feature(i128_type)] #![feature(const_atomic_usize_new)] +#![feature(rustc_attrs)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b95c91548d0..11ab84a5729 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -246,14 +246,27 @@ impl<'a> StringReader<'a> { self.err_span(self.mk_sp(from_pos, to_pos), m) } + /// Pushes a character to a message string for error reporting + fn push_escaped_char_for_msg(m: &mut String, c: char) { + match c { + '\u{20}'...'\u{7e}' => { + // Don't escape \, ' or " for user-facing messages + m.push(c); + } + _ => { + for c in c.escape_default() { + m.push(c); + } + } + } + } + /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an /// escaped character to the error message fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> FatalError { let mut m = m.to_string(); m.push_str(": "); - for c in c.escape_default() { - m.push(c) - } + Self::push_escaped_char_for_msg(&mut m, c); self.fatal_span_(from_pos, to_pos, &m[..]) } fn struct_fatal_span_char(&self, @@ -264,9 +277,7 @@ impl<'a> StringReader<'a> { -> DiagnosticBuilder<'a> { let mut m = m.to_string(); m.push_str(": "); - for c in c.escape_default() { - m.push(c) - } + Self::push_escaped_char_for_msg(&mut m, c); self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..]) } @@ -275,9 +286,7 @@ impl<'a> StringReader<'a> { fn err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) { let mut m = m.to_string(); m.push_str(": "); - for c in c.escape_default() { - m.push(c) - } + Self::push_escaped_char_for_msg(&mut m, c); self.err_span_(from_pos, to_pos, &m[..]); } fn struct_err_span_char(&self, @@ -288,9 +297,7 @@ impl<'a> StringReader<'a> { -> DiagnosticBuilder<'a> { let mut m = m.to_string(); m.push_str(": "); - for c in c.escape_default() { - m.push(c) - } + Self::push_escaped_char_for_msg(&mut m, c); self.sess.span_diagnostic.struct_span_err(self.mk_sp(from_pos, to_pos), &m[..]) } @@ -1745,6 +1752,7 @@ mod tests { fn mk_sess(cm: Rc<CodeMap>) -> ParseSess { let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()), Some(cm.clone()), + false, false); ParseSess { span_diagnostic: errors::Handler::with_emitter(true, false, Box::new(emitter)), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b3c485a85c0..764b3d0a848 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3398,11 +3398,7 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; // Allow a '|' before the pats (RFC 1925) - let beginning_vert = if self.eat(&token::BinOp(token::Or)) { - Some(self.prev_span) - } else { - None - }; + self.eat(&token::BinOp(token::Or)); let pats = self.parse_pats()?; let guard = if self.eat_keyword(keywords::If) { Some(self.parse_expr()?) @@ -3426,7 +3422,6 @@ impl<'a> Parser<'a> { pats, guard, body: expr, - beginning_vert, }) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 2be93c07d5a..7fbe781e9a1 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -112,6 +112,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { keywords::Unsafe.name(), keywords::While.name(), keywords::Yield.name(), + keywords::Static.name(), ].contains(&ident.name) } diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index 5072f2e2793..3b4bba24d77 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -62,6 +62,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: & let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), Some(code_map.clone()), + false, false); let handler = Handler::with_emitter(true, false, Box::new(emitter)); handler.span_err(msp, "foo"); diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 0e6e96438d8..743f22b6b31 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -190,7 +190,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, Struct(_, ref fields) => { let emit_struct_field = cx.ident_of("emit_struct_field"); let mut stmts = Vec::new(); - for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() { + for (i, &FieldInfo { name, ref self_, span, attrs, .. }) in fields.iter().enumerate() { let name = match name { Some(id) => id.name, None => Symbol::intern(&format!("_field{}", i)), @@ -212,7 +212,19 @@ fn encodable_substructure(cx: &mut ExtCtxt, } else { cx.expr(span, ExprKind::Ret(Some(call))) }; - stmts.push(cx.stmt_expr(call)); + + // This exists for https://github.com/rust-lang/rust/pull/47540 + // + // If we decide to stabilize that flag this can be removed + let expr = if attrs.iter().any(|a| a.check_name("rustc_serialize_exclude_null")) { + let is_some = cx.ident_of("is_some"); + let condition = cx.expr_method_call(span, self_.clone(), is_some, vec![]); + cx.expr_if(span, condition, call, None) + } else { + call + }; + let stmt = cx.stmt_expr(expr); + stmts.push(stmt); } // unit structs have no fields and need to return Ok() diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index dd1ec7284f6..294506625bc 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -347,13 +347,24 @@ impl Span { /// Return a `Span` that would enclose both `self` and `end`. pub fn to(self, end: Span) -> Span { - let span = self.data(); - let end = end.data(); + let span_data = self.data(); + let end_data = end.data(); + // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480) + // Return the macro span on its own to avoid weird diagnostic output. It is preferable to + // have an incomplete span than a completely nonsensical one. + if span_data.ctxt != end_data.ctxt { + if span_data.ctxt == SyntaxContext::empty() { + return end; + } else if end_data.ctxt == SyntaxContext::empty() { + return self; + } + // both span fall within a macro + // FIXME(estebank) check if it is the *same* macro + } Span::new( - cmp::min(span.lo, end.lo), - cmp::max(span.hi, end.hi), - // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480) - if span.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt }, + cmp::min(span_data.lo, end_data.lo), + cmp::max(span_data.hi, end_data.hi), + if span_data.ctxt == SyntaxContext::empty() { end_data.ctxt } else { span_data.ctxt }, ) } diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index b2f1229891d..06d1301d700 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -836,6 +836,10 @@ struct LLVMRustThinLTOData { StringMap<FunctionImporter::ImportMapTy> ImportLists; StringMap<FunctionImporter::ExportSetTy> ExportLists; StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries; + +#if LLVM_VERSION_GE(7, 0) + LLVMRustThinLTOData() : Index(/* isPerformingAnalysis = */ false) {} +#endif }; // Just an argument to the `LLVMRustCreateThinLTOData` function below. @@ -918,7 +922,14 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, // // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp` #if LLVM_VERSION_GE(5, 0) +#if LLVM_VERSION_GE(7, 0) + auto deadIsPrevailing = [&](GlobalValue::GUID G) { + return PrevailingType::Unknown; + }; + computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols, deadIsPrevailing); +#else computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols); +#endif ComputeCrossModuleImport( Ret->Index, Ret->ModuleToDefinedGVSummaries, diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index f8945a6ee8d..0e98d3f9050 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -122,13 +122,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) { pub fn str(_: &[u8]) { } -// CHECK: @trait_borrow(%"core::ops::drop::Drop"* nonnull %arg0.0, {}* noalias nonnull readonly %arg0.1) +// CHECK: @trait_borrow({}* nonnull %arg0.0, {}* noalias nonnull readonly %arg0.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn trait_borrow(_: &Drop) { } -// CHECK: @trait_box(%"core::ops::drop::Drop"* noalias nonnull, {}* noalias nonnull readonly) +// CHECK: @trait_box({}* noalias nonnull, {}* noalias nonnull readonly) #[no_mangle] pub fn trait_box(_: Box<Drop>) { } diff --git a/src/test/codegen/stack-probes.rs b/src/test/codegen/stack-probes.rs index 5b26dade9af..4a489f1edb3 100644 --- a/src/test/codegen/stack-probes.rs +++ b/src/test/codegen/stack-probes.rs @@ -15,7 +15,7 @@ // ignore-wasm // ignore-emscripten // ignore-windows -// no-system-llvm +// min-system-llvm-version 5.0 // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] diff --git a/src/test/compile-fail/E0195.rs b/src/test/compile-fail/E0195.rs index 06dd903b23d..4f4d7ce0dba 100644 --- a/src/test/compile-fail/E0195.rs +++ b/src/test/compile-fail/E0195.rs @@ -10,13 +10,14 @@ trait Trait { fn bar<'a,'b:'a>(x: &'a str, y: &'b str); + //~^ NOTE lifetimes in impl do not match this method in trait } struct Foo; impl Trait for Foo { fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195 - //~^ lifetimes do not match trait + //~^ NOTE lifetimes do not match method in trait } } diff --git a/src/test/compile-fail/associated-const-type-parameter-arms.rs b/src/test/compile-fail/associated-const-type-parameter-arms.rs index 52bb4a1b463..630a234fa66 100644 --- a/src/test/compile-fail/associated-const-type-parameter-arms.rs +++ b/src/test/compile-fail/associated-const-type-parameter-arms.rs @@ -16,6 +16,7 @@ pub trait Foo { } struct Abc; + impl Foo for Abc { const X: EFoo = EFoo::B; } @@ -27,8 +28,10 @@ impl Foo for Def { pub fn test<A: Foo, B: Foo>(arg: EFoo) { match arg { - A::X => println!("A::X"), //~ error: statics cannot be referenced in patterns [E0158] - B::X => println!("B::X"), //~ error: statics cannot be referenced in patterns [E0158] + A::X => println!("A::X"), + //~^ error: associated consts cannot be referenced in patterns [E0158] + B::X => println!("B::X"), + //~^ error: associated consts cannot be referenced in patterns [E0158] _ => (), } } diff --git a/src/test/compile-fail/issue-16048.rs b/src/test/compile-fail/issue-16048.rs index 5012556dedd..cda83fe54b0 100644 --- a/src/test/compile-fail/issue-16048.rs +++ b/src/test/compile-fail/issue-16048.rs @@ -10,6 +10,7 @@ trait NoLifetime { fn get<'p, T : Test<'p>>(&self) -> T; + //~^ NOTE lifetimes in impl do not match this method in trait } trait Test<'p> { @@ -28,8 +29,8 @@ impl<'a> Test<'a> for Foo<'a> { impl<'a> NoLifetime for Foo<'a> { fn get<'p, T : Test<'a>>(&self) -> T { -//~^ ERROR E0195 -//~| lifetimes do not match trait + //~^ ERROR E0195 + //~| NOTE lifetimes do not match method in trait return *self as T; } } diff --git a/src/test/compile-fail/nll/do-not-ignore-lifetime-bounds-in-copy.rs b/src/test/compile-fail/nll/do-not-ignore-lifetime-bounds-in-copy.rs new file mode 100644 index 00000000000..2a4295fd90a --- /dev/null +++ b/src/test/compile-fail/nll/do-not-ignore-lifetime-bounds-in-copy.rs @@ -0,0 +1,23 @@ +// Copyright 2012 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the 'static bound from the Copy impl is respected. Regression test for #29149. + +#![feature(nll)] + +#[derive(Clone)] struct Foo<'a>(&'a u32); +impl Copy for Foo<'static> {} + +fn main() { + let s = 2; + let a = Foo(&s); //~ ERROR `s` does not live long enough [E0597] + drop(a); + drop(a); +} diff --git a/src/test/parse-fail/bad-char-literals.rs b/src/test/parse-fail/bad-char-literals.rs index 96311d6de17..821015ece77 100644 --- a/src/test/parse-fail/bad-char-literals.rs +++ b/src/test/parse-fail/bad-char-literals.rs @@ -15,7 +15,7 @@ fn main() { // these literals are just silly. '''; - //~^ ERROR: character constant must be escaped: \' + //~^ ERROR: character constant must be escaped: ' // note that this is a literal "\n" byte ' diff --git a/src/test/parse-fail/lex-stray-backslash.rs b/src/test/parse-fail/lex-stray-backslash.rs new file mode 100644 index 00000000000..b6042bbdc1a --- /dev/null +++ b/src/test/parse-fail/lex-stray-backslash.rs @@ -0,0 +1,13 @@ +// Copyright 2014 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +\ //~ ERROR: unknown start of token: \ diff --git a/src/test/run-make/stdin-non-utf8/Makefile b/src/test/run-make/stdin-non-utf8/Makefile new file mode 100644 index 00000000000..7948c442616 --- /dev/null +++ b/src/test/run-make/stdin-non-utf8/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + cp non-utf8 $(TMPDIR)/non-utf.rs + cat $(TMPDIR)/non-utf.rs | $(RUSTC) - 2>&1 \ + | $(CGREP) "error: couldn't read from stdin, as it did not contain valid UTF-8" diff --git a/src/test/run-make/stdin-non-utf8/non-utf8 b/src/test/run-make/stdin-non-utf8/non-utf8 new file mode 100644 index 00000000000..bc87051a852 --- /dev/null +++ b/src/test/run-make/stdin-non-utf8/non-utf8 @@ -0,0 +1 @@ + diff --git a/src/test/run-pass/generator/too-live-local-in-immovable-gen.rs b/src/test/run-pass/generator/too-live-local-in-immovable-gen.rs new file mode 100644 index 00000000000..2314533a681 --- /dev/null +++ b/src/test/run-pass/generator/too-live-local-in-immovable-gen.rs @@ -0,0 +1,28 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators)] + +fn main() { + unsafe { + static move || { + // Tests that the generator transformation finds out that `a` is not live + // during the yield expression. Type checking will also compute liveness + // and it should also find out that `a` is not live. + // The compiler will panic if the generator transformation finds that + // `a` is live and type checking finds it dead. + let a = { + yield (); + 4i32 + }; + &a; + }; + } +} diff --git a/src/test/run-pass/issue-47139-1.rs b/src/test/run-pass/issue-47139-1.rs new file mode 100644 index 00000000000..cb87991a491 --- /dev/null +++ b/src/test/run-pass/issue-47139-1.rs @@ -0,0 +1,87 @@ +// Copyright 2016 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for issue #47139: +// +// Coherence was encountering an (unnecessary) overflow trying to +// decide if the two impls of dummy overlap. +// +// The overflow went something like: +// +// - `&'a ?T: Insertable` ? +// - let ?T = Option<?U> ? +// - `Option<?U>: Insertable` ? +// - `Option<&'a ?U>: Insertable` ? +// - `&'a ?U: Insertable` ? +// +// While somewhere in the middle, a projection would occur, which +// broke cycle detection. +// +// It turned out that this cycle was being kicked off due to some +// extended diagnostic attempts in coherence, so removing those +// sidestepped the issue for now. + +#![allow(dead_code)] + +pub trait Insertable { + type Values; + + fn values(self) -> Self::Values; +} + +impl<T> Insertable for Option<T> + where + T: Insertable, + T::Values: Default, +{ + type Values = T::Values; + + fn values(self) -> Self::Values { + self.map(Insertable::values).unwrap_or_default() + } +} + +impl<'a, T> Insertable for &'a Option<T> + where + Option<&'a T>: Insertable, +{ + type Values = <Option<&'a T> as Insertable>::Values; + + fn values(self) -> Self::Values { + self.as_ref().values() + } +} + +impl<'a, T> Insertable for &'a [T] +{ + type Values = Self; + + fn values(self) -> Self::Values { + self + } +} + +trait Unimplemented { } + +trait Dummy { } + +struct Foo<T> { t: T } + +impl<'a, U> Dummy for Foo<&'a U> + where &'a U: Insertable +{ +} + +impl<T> Dummy for T + where T: Unimplemented +{ } + +fn main() { +} diff --git a/src/test/run-pass/issue-47139-2.rs b/src/test/run-pass/issue-47139-2.rs new file mode 100644 index 00000000000..08eaee5acd7 --- /dev/null +++ b/src/test/run-pass/issue-47139-2.rs @@ -0,0 +1,75 @@ +// Copyright 2016 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for issue #47139: +// +// Same as issue-47139-1.rs, but the impls of dummy are in the +// opposite order. This influenced the way that coherence ran and in +// some cases caused the overflow to occur when it wouldn't otherwise. +// In an effort to make the regr test more robust, I am including both +// orderings. + +#![allow(dead_code)] + +pub trait Insertable { + type Values; + + fn values(self) -> Self::Values; +} + +impl<T> Insertable for Option<T> + where + T: Insertable, + T::Values: Default, +{ + type Values = T::Values; + + fn values(self) -> Self::Values { + self.map(Insertable::values).unwrap_or_default() + } +} + +impl<'a, T> Insertable for &'a Option<T> + where + Option<&'a T>: Insertable, +{ + type Values = <Option<&'a T> as Insertable>::Values; + + fn values(self) -> Self::Values { + self.as_ref().values() + } +} + +impl<'a, T> Insertable for &'a [T] +{ + type Values = Self; + + fn values(self) -> Self::Values { + self + } +} + +trait Unimplemented { } + +trait Dummy { } + +struct Foo<T> { t: T } + +impl<T> Dummy for T + where T: Unimplemented +{ } + +impl<'a, U> Dummy for Foo<&'a U> + where &'a U: Insertable +{ +} + +fn main() { +} diff --git a/src/test/run-pass/issue-47638.rs b/src/test/run-pass/issue-47638.rs new file mode 100644 index 00000000000..6f627b2a3c1 --- /dev/null +++ b/src/test/run-pass/issue-47638.rs @@ -0,0 +1,18 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn id<'c, 'b>(f: &'c &'b Fn(&i32)) -> &'c &'b Fn(&'static i32) { + f +} + +fn main() { + let f: &Fn(&i32) = &|x| {}; + id(&f); +} diff --git a/src/test/run-pass/issue-47789.rs b/src/test/run-pass/issue-47789.rs new file mode 100644 index 00000000000..3148939992c --- /dev/null +++ b/src/test/run-pass/issue-47789.rs @@ -0,0 +1,20 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +#![feature(nll)] + +static mut x: &'static u32 = &0; + +fn foo() { + unsafe { x = &1; } +} + +fn main() { } diff --git a/src/test/run-pass/match-beginning-vert.rs b/src/test/run-pass/match-beginning-vert.rs new file mode 100644 index 00000000000..cdacfb2f057 --- /dev/null +++ b/src/test/run-pass/match-beginning-vert.rs @@ -0,0 +1,28 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Foo { + A, + B, + C, + D, + E, +} +use Foo::*; + +fn main() { + for foo in &[A, B, C, D, E] { + match *foo { + | A => println!("A"), + | B | C if 1 < 2 => println!("BC!"), + | _ => {}, + } + } +} diff --git a/src/test/run-pass/sse2.rs b/src/test/run-pass/sse2.rs index c2414e5ff5d..22469b2fde0 100644 --- a/src/test/run-pass/sse2.rs +++ b/src/test/run-pass/sse2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// min-llvm-version 4.0 +// no-system-llvm -- needs MCSubtargetInfo::getFeatureTable() // ignore-cloudabi no std::env #![feature(cfg_target_feature)] diff --git a/src/test/run-pass/stack-probes-lto.rs b/src/test/run-pass/stack-probes-lto.rs index 22555c8d6a7..4deced1297b 100644 --- a/src/test/run-pass/stack-probes-lto.rs +++ b/src/test/run-pass/stack-probes-lto.rs @@ -15,7 +15,7 @@ // ignore-emscripten no processes // ignore-musl FIXME #31506 // ignore-pretty -// no-system-llvm +// min-system-llvm-version 5.0 // compile-flags: -C lto // no-prefer-dynamic diff --git a/src/test/run-pass/stack-probes.rs b/src/test/run-pass/stack-probes.rs index 248ad701926..4224a65ffd7 100644 --- a/src/test/run-pass/stack-probes.rs +++ b/src/test/run-pass/stack-probes.rs @@ -14,7 +14,7 @@ // ignore-cloudabi no processes // ignore-emscripten no processes // ignore-musl FIXME #31506 -// no-system-llvm +// min-system-llvm-version 5.0 use std::mem; use std::process::Command; diff --git a/src/test/rustdoc/const-evalutation-ice.rs b/src/test/rustdoc/const-evalutation-ice.rs new file mode 100644 index 00000000000..9fed67ee583 --- /dev/null +++ b/src/test/rustdoc/const-evalutation-ice.rs @@ -0,0 +1,22 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Just check if we don't get an ICE for the _S type. + +#![feature(const_size_of)] + +use std::cell::Cell; +use std::mem; + +pub struct S { + s: Cell<usize> +} + +pub type _S = [usize; 0 - (mem::size_of::<S>() != 4) as usize]; diff --git a/src/test/ui/associated-const-impl-wrong-lifetime.stderr b/src/test/ui/associated-const-impl-wrong-lifetime.stderr index a7aee9b19f1..ab0e1003a9e 100644 --- a/src/test/ui/associated-const-impl-wrong-lifetime.stderr +++ b/src/test/ui/associated-const-impl-wrong-lifetime.stderr @@ -9,11 +9,8 @@ error[E0308]: mismatched types note: the lifetime 'a as defined on the impl at 17:1... --> $DIR/associated-const-impl-wrong-lifetime.rs:17:1 | -17 | / impl<'a> Foo for &'a () { -18 | | const NAME: &'a str = "unit"; -19 | | //~^ ERROR mismatched types [E0308] -20 | | } - | |_^ +17 | impl<'a> Foo for &'a () { + | ^^^^^^^^^^^^^^^^^^^^^^^ = note: ...does not necessarily outlive the static lifetime error: aborting due to previous error diff --git a/src/test/ui/blind-item-item-shadow.stderr b/src/test/ui/blind-item-item-shadow.stderr index 855b3799eb5..d3588be2669 100644 --- a/src/test/ui/blind-item-item-shadow.stderr +++ b/src/test/ui/blind-item-item-shadow.stderr @@ -10,8 +10,8 @@ error[E0255]: the name `foo` is defined multiple times = note: `foo` must be defined only once in the type namespace of this module help: You can use `as` to change the binding name of the import | -13 | use foo::foo as Otherfoo; - | ^^^^^^^^^^^^^^^^^^^^ +13 | use foo::foo as other_foo; + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs index 617de2c5dfe..617de2c5dfe 100644 --- a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs +++ b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.rs diff --git a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr new file mode 100644 index 00000000000..e8323247af9 --- /dev/null +++ b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr @@ -0,0 +1,48 @@ +error[E0195]: lifetime parameters or bounds on method `no_bound` do not match the trait declaration + --> $DIR/regions-bound-missing-bound-in-impl.rs:28:5 + | +20 | fn no_bound<'b>(self, b: Inv<'b>); + | ---------------------------------- lifetimes in impl do not match this method in trait +... +28 | fn no_bound<'b:'a>(self, b: Inv<'b>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait + +error[E0195]: lifetime parameters or bounds on method `has_bound` do not match the trait declaration + --> $DIR/regions-bound-missing-bound-in-impl.rs:32:5 + | +21 | fn has_bound<'b:'a>(self, b: Inv<'b>); + | -------------------------------------- lifetimes in impl do not match this method in trait +... +32 | fn has_bound<'b>(self, b: Inv<'b>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait + +error[E0308]: method not compatible with trait + --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5 + | +36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected type `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'d>)` + found type `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'d>)` +note: the lifetime 'c as defined on the method body at 36:5... + --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5 + | +36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...does not necessarily outlive the lifetime 'c as defined on the method body at 36:5 + --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5 + | +36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0276]: impl has stricter requirements than trait + --> $DIR/regions-bound-missing-bound-in-impl.rs:53:5 + | +24 | fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>); + | ------------------------------------------------------- definition of `another_bound` from trait +... +53 | fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'x: 't` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/closure-expected-type/expect-region-supply-region.stderr b/src/test/ui/closure-expected-type/expect-region-supply-region.stderr index ebb1e561e57..5c612522d9a 100644 --- a/src/test/ui/closure-expected-type/expect-region-supply-region.stderr +++ b/src/test/ui/closure-expected-type/expect-region-supply-region.stderr @@ -41,14 +41,8 @@ note: the anonymous lifetime #2 defined on the body at 47:29... note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:1 --> $DIR/expect-region-supply-region.rs:42:1 | -42 | / fn expect_bound_supply_named<'x>() { -43 | | let mut f: Option<&u32> = None; -44 | | -45 | | // Here we give a type annotation that `x` should be free. We get -... | -54 | | }); -55 | | } - | |_^ +42 | fn expect_bound_supply_named<'x>() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/expect-region-supply-region.rs:47:33 @@ -61,14 +55,8 @@ error[E0308]: mismatched types note: the lifetime 'x as defined on the function body at 42:1... --> $DIR/expect-region-supply-region.rs:42:1 | -42 | / fn expect_bound_supply_named<'x>() { -43 | | let mut f: Option<&u32> = None; -44 | | -45 | | // Here we give a type annotation that `x` should be free. We get -... | -54 | | }); -55 | | } - | |_^ +42 | fn expect_bound_supply_named<'x>() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 47:29 --> $DIR/expect-region-supply-region.rs:47:29 | diff --git a/src/test/ui/double-import.stderr b/src/test/ui/double-import.stderr index fcd3f2696f2..2a0f9ee34f2 100644 --- a/src/test/ui/double-import.stderr +++ b/src/test/ui/double-import.stderr @@ -9,8 +9,8 @@ error[E0252]: the name `foo` is defined multiple times = note: `foo` must be defined only once in the value namespace of this module help: You can use `as` to change the binding name of the import | -23 | use sub2::foo as Otherfoo; //~ ERROR the name `foo` is defined multiple times - | ^^^^^^^^^^^^^^^^^^^^^ +23 | use sub2::foo as other_foo; //~ ERROR the name `foo` is defined multiple times + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/feature-gate-match_beginning_vert.rs b/src/test/ui/feature-gate-match_beginning_vert.rs deleted file mode 100644 index 9085563c99d..00000000000 --- a/src/test/ui/feature-gate-match_beginning_vert.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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(dead_code)] -enum Foo { - A, - B, - C, - D, - E, -} -use Foo::*; - -fn main() { - let x = Foo::A; - match x { - | A => println!("A"), - //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101) - | B | C => println!("BC!"), - //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101) - | _ => {}, - //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101) - }; - match x { - A | B | C => println!("ABC!"), - _ => {}, - }; -} - diff --git a/src/test/ui/feature-gate-match_beginning_vert.stderr b/src/test/ui/feature-gate-match_beginning_vert.stderr deleted file mode 100644 index 1d45dedb497..00000000000 --- a/src/test/ui/feature-gate-match_beginning_vert.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0658]: Use of a '|' at the beginning of a match arm is experimental (see issue #44101) - --> $DIR/feature-gate-match_beginning_vert.rs:24:9 - | -24 | | A => println!("A"), - | ^ - | - = help: add #![feature(match_beginning_vert)] to the crate attributes to enable - -error[E0658]: Use of a '|' at the beginning of a match arm is experimental (see issue #44101) - --> $DIR/feature-gate-match_beginning_vert.rs:26:9 - | -26 | | B | C => println!("BC!"), - | ^ - | - = help: add #![feature(match_beginning_vert)] to the crate attributes to enable - -error[E0658]: Use of a '|' at the beginning of a match arm is experimental (see issue #44101) - --> $DIR/feature-gate-match_beginning_vert.rs:28:9 - | -28 | | _ => {}, - | ^ - | - = help: add #![feature(match_beginning_vert)] to the crate attributes to enable - -error: aborting due to 3 previous errors - diff --git a/src/test/ui/generator/generator-with-nll.stderr b/src/test/ui/generator/generator-with-nll.stderr index 0a52a928f69..0f7d2e540d8 100644 --- a/src/test/ui/generator/generator-with-nll.stderr +++ b/src/test/ui/generator/generator-with-nll.stderr @@ -1,12 +1,3 @@ -error[E0626]: borrow may still be in use when generator yields (Mir) - --> $DIR/generator-with-nll.rs:20:17 - | -20 | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast) - | ^^^^^^^^^ -21 | //~^ borrow may still be in use when generator yields (Mir) -22 | yield (); - | -------- possible yield occurs here - error[E0626]: borrow may still be in use when generator yields (Ast) --> $DIR/generator-with-nll.rs:19:23 | @@ -25,5 +16,14 @@ error[E0626]: borrow may still be in use when generator yields (Ast) 22 | yield (); | -------- possible yield occurs here +error[E0626]: borrow may still be in use when generator yields (Mir) + --> $DIR/generator-with-nll.rs:20:17 + | +20 | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast) + | ^^^^^^^^^ +21 | //~^ borrow may still be in use when generator yields (Mir) +22 | yield (); + | -------- possible yield occurs here + error: aborting due to 3 previous errors diff --git a/src/test/ui/generator/pattern-borrow.rs b/src/test/ui/generator/pattern-borrow.rs new file mode 100644 index 00000000000..557a5e62f7e --- /dev/null +++ b/src/test/ui/generator/pattern-borrow.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators)] + +enum Test { A(i32), B, } + +fn main() { } + +fn fun(test: Test) { + move || { + if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields + yield (); + } + }; +} diff --git a/src/test/ui/generator/pattern-borrow.stderr b/src/test/ui/generator/pattern-borrow.stderr new file mode 100644 index 00000000000..6b39b272d0e --- /dev/null +++ b/src/test/ui/generator/pattern-borrow.stderr @@ -0,0 +1,10 @@ +error[E0626]: borrow may still be in use when generator yields + --> $DIR/pattern-borrow.rs:19:24 + | +19 | if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields + | ^^^^^^ +20 | yield (); + | -------- possible yield occurs here + +error: aborting due to previous error + diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs new file mode 100644 index 00000000000..f38ebf8b946 --- /dev/null +++ b/src/test/ui/generator/sized-yield.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::Generator; + +fn main() { + let s = String::from("foo"); + let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + yield s[..]; + }; + gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied +} diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr new file mode 100644 index 00000000000..7adb2cc5598 --- /dev/null +++ b/src/test/ui/generator/sized-yield.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied + --> $DIR/sized-yield.rs:17:26 + | +17 | let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + | __________________________^ +18 | | yield s[..]; +19 | | }; + | |____^ `str` does not have a constant size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `str` + = note: the yield type of a generator must have a statically known size + +error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied + --> $DIR/sized-yield.rs:20:8 + | +20 | gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + | ^^^^^^ `str` does not have a constant size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `str` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/generator/yield-while-local-borrowed.stderr b/src/test/ui/generator/yield-while-local-borrowed.stderr index 7961dd97441..114fe8ffcab 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.stderr +++ b/src/test/ui/generator/yield-while-local-borrowed.stderr @@ -1,12 +1,3 @@ -error[E0626]: borrow may still be in use when generator yields (Mir) - --> $DIR/yield-while-local-borrowed.rs:24:17 - | -24 | let a = &mut 3; - | ^^^^^^ -... -27 | yield(); - | ------- possible yield occurs here - error[E0626]: borrow may still be in use when generator yields (Ast) --> $DIR/yield-while-local-borrowed.rs:24:22 | @@ -26,6 +17,15 @@ error[E0626]: borrow may still be in use when generator yields (Ast) | ------- possible yield occurs here error[E0626]: borrow may still be in use when generator yields (Mir) + --> $DIR/yield-while-local-borrowed.rs:24:17 + | +24 | let a = &mut 3; + | ^^^^^^ +... +27 | yield(); + | ------- possible yield occurs here + +error[E0626]: borrow may still be in use when generator yields (Mir) --> $DIR/yield-while-local-borrowed.rs:52:21 | 52 | let b = &a; diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr index 7a0d01a8ec2..1417c71ca12 100644 --- a/src/test/ui/impl-trait/trait_type.stderr +++ b/src/test/ui/impl-trait/trait_type.stderr @@ -2,7 +2,7 @@ error[E0053]: method `fmt` has an incompatible type for trait --> $DIR/trait_type.rs:17:4 | 17 | fn fmt(&self, x: &str) -> () { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected type `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` found type `fn(&MyType, &str)` @@ -19,7 +19,7 @@ error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in th --> $DIR/trait_type.rs:27:4 | 27 | fn fmt() -> () { } - | ^^^^^^^^^^^^^^^^^^ expected `&self` in impl + | ^^^^^^^^^^^^^^ expected `&self` in impl | = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` diff --git a/src/test/ui/imports/duplicate.stderr b/src/test/ui/imports/duplicate.stderr index a74401314a1..6e5b91a11c9 100644 --- a/src/test/ui/imports/duplicate.stderr +++ b/src/test/ui/imports/duplicate.stderr @@ -9,8 +9,8 @@ error[E0252]: the name `foo` is defined multiple times = note: `foo` must be defined only once in the value namespace of this module help: You can use `as` to change the binding name of the import | -25 | use a::foo as Otherfoo; //~ ERROR the name `foo` is defined multiple times - | ^^^^^^^^^^^^^^^^^^ +25 | use a::foo as other_foo; //~ ERROR the name `foo` is defined multiple times + | ^^^^^^^^^^^^^^^^^^^ error[E0659]: `foo` is ambiguous --> $DIR/duplicate.rs:56:9 diff --git a/src/test/ui/in-band-lifetimes/ellided-lifetimes.rs b/src/test/ui/in-band-lifetimes/ellided-lifetimes.rs new file mode 100644 index 00000000000..5151abd6823 --- /dev/null +++ b/src/test/ui/in-band-lifetimes/ellided-lifetimes.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![allow(warnings)] +#![allow(unused_variables, dead_code, unused, bad_style)] +#![deny(elided_lifetime_in_path)] + +struct Foo<'a> { x: &'a u32 } +fn foo(x: &Foo) { + //~^ ERROR: hidden lifetime parameters are deprecated, try `Foo<'_>` +} + +fn main() {} diff --git a/src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr b/src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr new file mode 100644 index 00000000000..613a7be6ed2 --- /dev/null +++ b/src/test/ui/in-band-lifetimes/ellided-lifetimes.stderr @@ -0,0 +1,14 @@ +error: hidden lifetime parameters are deprecated, try `Foo<'_>` + --> $DIR/ellided-lifetimes.rs:15:12 + | +15 | fn foo(x: &Foo) { + | ^^^ + | +note: lint level defined here + --> $DIR/ellided-lifetimes.rs:12:9 + | +12 | #![deny(elided_lifetime_in_path)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs new file mode 100644 index 00000000000..f845762cefd --- /dev/null +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs @@ -0,0 +1,22 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; +trait Trait {} + +struct Struct; + +impl Deref for Struct { + type Target = Trait; + fn deref(&self) -> &Trait { + unimplemented!(); + } +} +//~^^^^ ERROR cannot infer an appropriate lifetime for lifetime parameter diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr new file mode 100644 index 00000000000..7aab31eb909 --- /dev/null +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -0,0 +1,22 @@ +error[E0601]: main function not found + +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements + --> $DIR/mismatched_trait_impl-2.rs:18:5 + | +18 | fn deref(&self) -> &Trait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5... + --> $DIR/mismatched_trait_impl-2.rs:18:5 + | +18 | / fn deref(&self) -> &Trait { +19 | | unimplemented!(); +20 | | } + | |_____^ + = note: ...but the lifetime must also be valid for the static lifetime... + = note: ...so that the method type is compatible with trait: + expected fn(&Struct) -> &Trait + 'static + found fn(&Struct) -> &Trait + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index e96f7181a6d..fd6be01da9f 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -1,10 +1,8 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements --> $DIR/mismatched_trait_impl.rs:19:5 | -19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer -20 | | x -21 | | } - | |_____^ +19 | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 19:5... --> $DIR/mismatched_trait_impl.rs:19:5 @@ -13,27 +11,14 @@ note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on th 20 | | x 21 | | } | |_____^ -note: ...so that method type is compatible with trait (expected fn(&i32, &'a u32, &u32) -> &'a u32, found fn(&i32, &u32, &u32) -> &u32) - --> $DIR/mismatched_trait_impl.rs:19:5 - | -19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer -20 | | x -21 | | } - | |_____^ -note: but, the lifetime must be valid for the lifetime 'a as defined on the method body at 19:5... +note: ...but the lifetime must also be valid for the lifetime 'a as defined on the method body at 19:5... --> $DIR/mismatched_trait_impl.rs:19:5 | -19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer -20 | | x -21 | | } - | |_____^ -note: ...so that method type is compatible with trait (expected fn(&i32, &'a u32, &u32) -> &'a u32, found fn(&i32, &u32, &u32) -> &u32) - --> $DIR/mismatched_trait_impl.rs:19:5 - | -19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer -20 | | x -21 | | } - | |_____^ +19 | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...so that the method type is compatible with trait: + expected fn(&i32, &'a u32, &u32) -> &'a u32 + found fn(&i32, &u32, &u32) -> &u32 error: aborting due to previous error diff --git a/src/test/ui/issue-26886.stderr b/src/test/ui/issue-26886.stderr index cb2eca87068..e6424e535ee 100644 --- a/src/test/ui/issue-26886.stderr +++ b/src/test/ui/issue-26886.stderr @@ -24,8 +24,8 @@ error[E0252]: the name `sync` is defined multiple times = note: `sync` must be defined only once in the type namespace of this module help: You can use `as` to change the binding name of the import | -14 | use std::sync as Othersync; //~ ERROR the name `sync` is defined multiple times - | ^^^^^^^^^^^^^^^^^^^^^^ +14 | use std::sync as other_sync; //~ ERROR the name `sync` is defined multiple times + | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-27942.stderr b/src/test/ui/issue-27942.stderr index b580b8e7313..b24544743d8 100644 --- a/src/test/ui/issue-27942.stderr +++ b/src/test/ui/issue-27942.stderr @@ -14,14 +14,8 @@ note: the anonymous lifetime #1 defined on the method body at 15:5... note: ...does not necessarily outlive the lifetime 'a as defined on the trait at 13:1 --> $DIR/issue-27942.rs:13:1 | -13 | / pub trait Buffer<'a, R: Resources<'a>> { -14 | | -15 | | fn select(&self) -> BufferViewHandle<R>; -16 | | //~^ ERROR mismatched types -... | -19 | | //~| lifetime mismatch -20 | | } - | |_^ +13 | pub trait Buffer<'a, R: Resources<'a>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/issue-27942.rs:15:5 @@ -34,14 +28,8 @@ error[E0308]: mismatched types note: the lifetime 'a as defined on the trait at 13:1... --> $DIR/issue-27942.rs:13:1 | -13 | / pub trait Buffer<'a, R: Resources<'a>> { -14 | | -15 | | fn select(&self) -> BufferViewHandle<R>; -16 | | //~^ ERROR mismatched types -... | -19 | | //~| lifetime mismatch -20 | | } - | |_^ +13 | pub trait Buffer<'a, R: Resources<'a>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the anonymous lifetime #1 defined on the method body at 15:5 --> $DIR/issue-27942.rs:15:5 | diff --git a/src/test/ui/issue-37884.stderr b/src/test/ui/issue-37884.stderr index 439b123975f..c4ad232ae7e 100644 --- a/src/test/ui/issue-37884.stderr +++ b/src/test/ui/issue-37884.stderr @@ -24,14 +24,8 @@ note: the anonymous lifetime #1 defined on the method body at 16:5... note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 13:1 --> $DIR/issue-37884.rs:13:1 | -13 | / impl<'a, T: 'a> Iterator for RepeatMut<'a, T> { -14 | | -15 | | type Item = &'a mut T; -16 | | fn next(&'a mut self) -> Option<Self::Item> -... | -21 | | } -22 | | } - | |_^ +13 | impl<'a, T: 'a> Iterator for RepeatMut<'a, T> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issue-46472.stderr b/src/test/ui/issue-46472.stderr index 2f332a7a558..7b5cce218e9 100644 --- a/src/test/ui/issue-46472.stderr +++ b/src/test/ui/issue-46472.stderr @@ -10,12 +10,8 @@ error[E0597]: borrowed value does not live long enough (Ast) note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1... --> $DIR/issue-46472.rs:13:1 | -13 | / fn bar<'a>() -> &'a mut u32 { -14 | | &mut 4 -15 | | //~^ ERROR borrowed value does not live long enough (Ast) [E0597] -16 | | //~| ERROR borrowed value does not live long enough (Mir) [E0597] -17 | | } - | |_^ +13 | fn bar<'a>() -> &'a mut u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0597]: borrowed value does not live long enough (Mir) --> $DIR/issue-46472.rs:14:10 @@ -29,12 +25,8 @@ error[E0597]: borrowed value does not live long enough (Mir) note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1... --> $DIR/issue-46472.rs:13:1 | -13 | / fn bar<'a>() -> &'a mut u32 { -14 | | &mut 4 -15 | | //~^ ERROR borrowed value does not live long enough (Ast) [E0597] -16 | | //~| ERROR borrowed value does not live long enough (Mir) [E0597] -17 | | } - | |_^ +13 | fn bar<'a>() -> &'a mut u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-47706-trait.rs b/src/test/ui/issue-47706-trait.rs new file mode 100644 index 00000000000..86a9da49a05 --- /dev/null +++ b/src/test/ui/issue-47706-trait.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait T { + fn f(&self, _: ()) { + None::<()>.map(Self::f); + } + //~^^ ERROR function is expected to take a single 0-tuple as argument +} diff --git a/src/test/ui/issue-47706-trait.stderr b/src/test/ui/issue-47706-trait.stderr new file mode 100644 index 00000000000..320e98dee4a --- /dev/null +++ b/src/test/ui/issue-47706-trait.stderr @@ -0,0 +1,12 @@ +error[E0601]: main function not found + +error[E0593]: function is expected to take a single 0-tuple as argument, but it takes 2 distinct arguments + --> $DIR/issue-47706-trait.rs:13:20 + | +12 | fn f(&self, _: ()) { + | ------------------ takes 2 distinct arguments +13 | None::<()>.map(Self::f); + | ^^^ expected function that takes a single 0-tuple as argument + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs new file mode 100644 index 00000000000..b4e6c5074e3 --- /dev/null +++ b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs @@ -0,0 +1,40 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully + +#![warn(unused_parens)] + +macro_rules! the_worship_the_heart_lifts_above { + ( @as_expr, $e:expr) => { $e }; + ( @generate_fn, $name:tt) => { + #[allow(dead_code)] fn the_moth_for_the_star<'a>() -> Option<&'a str> { + Some(the_worship_the_heart_lifts_above!( @as_expr, $name )) + } + }; + ( $name:ident ) => { the_worship_the_heart_lifts_above!( @generate_fn, (stringify!($name))); } + // ↑ Notably, this does 𝘯𝘰𝘵 warn: we're declining to lint unused parens in + // function/method arguments inside of nested macros because of situations + // like those reported in Issue #47775 +} + +macro_rules! and_the_heavens_reject_not { + () => { + // ↓ But let's test that we still lint for unused parens around + // function args inside of simple, one-deep macros. + #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) } + //~^ WARN unnecessary parentheses around function argument + } +} + +the_worship_the_heart_lifts_above!(rah); +and_the_heavens_reject_not!(); + +fn main() {} diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr new file mode 100644 index 00000000000..097ec1b1c80 --- /dev/null +++ b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr @@ -0,0 +1,15 @@ +warning: unnecessary parentheses around function argument + --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:32:83 + | +32 | #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) } + | ^^^ help: remove these parentheses +... +38 | and_the_heavens_reject_not!(); + | ------------------------------ in this macro invocation + | +note: lint level defined here + --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:13:9 + | +13 | #![warn(unused_parens)] + | ^^^^^^^^^^^^^ + diff --git a/src/test/ui/lint/suggestions.rs b/src/test/ui/lint/suggestions.rs index dfcaede1402..e35675eacd8 100644 --- a/src/test/ui/lint/suggestions.rs +++ b/src/test/ui/lint/suggestions.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-tab + #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896 #![feature(no_debug)] @@ -46,11 +48,15 @@ fn main() { let mut a = (1); // should suggest no `mut`, no parens //~^ WARN does not need to be mutable //~| WARN unnecessary parentheses + // the line after `mut` has a `\t` at the beginning, this is on purpose + let mut + b = 1; + //~^^ WARN does not need to be mutable let d = Equinox { warp_factor: 9.975 }; match d { Equinox { warp_factor: warp_factor } => {} // should suggest shorthand //~^ WARN this pattern is redundant } - println!("{}", a); + println!("{} {}", a, b); } } diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr index 8b30f552d37..90d6bd312e4 100644 --- a/src/test/ui/lint/suggestions.stderr +++ b/src/test/ui/lint/suggestions.stderr @@ -1,41 +1,53 @@ warning: unnecessary parentheses around assigned value - --> $DIR/suggestions.rs:46:21 + --> $DIR/suggestions.rs:48:21 | -46 | let mut a = (1); // should suggest no `mut`, no parens +48 | let mut a = (1); // should suggest no `mut`, no parens | ^^^ help: remove these parentheses | note: lint level defined here - --> $DIR/suggestions.rs:11:21 + --> $DIR/suggestions.rs:13:21 | -11 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896 +13 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896 | ^^^^^^^^^^^^^ warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721 - --> $DIR/suggestions.rs:41:1 + --> $DIR/suggestions.rs:43:1 | -41 | #[no_debug] // should suggest removal of deprecated attribute +43 | #[no_debug] // should suggest removal of deprecated attribute | ^^^^^^^^^^^ help: remove this attribute | = note: #[warn(deprecated)] on by default warning: variable does not need to be mutable - --> $DIR/suggestions.rs:46:13 + --> $DIR/suggestions.rs:48:13 | -46 | let mut a = (1); // should suggest no `mut`, no parens - | ---^^ +48 | let mut a = (1); // should suggest no `mut`, no parens + | ----^ | | | help: remove this `mut` | note: lint level defined here - --> $DIR/suggestions.rs:11:9 + --> $DIR/suggestions.rs:13:9 | -11 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896 +13 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896 | ^^^^^^^^^^ +warning: variable does not need to be mutable + --> $DIR/suggestions.rs:52:13 + | +52 | let mut + | _____________^ + | |_____________| + | || +53 | || b = 1; + | ||____________-^ + | |____________| + | help: remove this `mut` + warning: static is marked #[no_mangle], but not exported - --> $DIR/suggestions.rs:14:14 + --> $DIR/suggestions.rs:16:14 | -14 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub` +16 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub` | -^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | help: try making it public: `pub` @@ -43,9 +55,9 @@ warning: static is marked #[no_mangle], but not exported = note: #[warn(private_no_mangle_statics)] on by default error: const items should never be #[no_mangle] - --> $DIR/suggestions.rs:16:14 + --> $DIR/suggestions.rs:18:14 | -16 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const` +18 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const` | -----^^^^^^^^^^^^^^^^^^^^^^ | | | help: try a static value: `pub static` @@ -53,19 +65,19 @@ error: const items should never be #[no_mangle] = note: #[deny(no_mangle_const_items)] on by default warning: functions generic over types must be mangled - --> $DIR/suggestions.rs:20:1 + --> $DIR/suggestions.rs:22:1 | -19 | #[no_mangle] // should suggest removal (generics can't be no-mangle) +21 | #[no_mangle] // should suggest removal (generics can't be no-mangle) | ------------ help: remove this attribute -20 | pub fn defiant<T>(_t: T) {} +22 | pub fn defiant<T>(_t: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: #[warn(no_mangle_generic_items)] on by default warning: function is marked #[no_mangle], but not exported - --> $DIR/suggestions.rs:24:1 + --> $DIR/suggestions.rs:26:1 | -24 | fn rio_grande() {} // should suggest `pub` +26 | fn rio_grande() {} // should suggest `pub` | -^^^^^^^^^^^^^^^^^ | | | help: try making it public: `pub` @@ -73,29 +85,29 @@ warning: function is marked #[no_mangle], but not exported = note: #[warn(private_no_mangle_fns)] on by default warning: static is marked #[no_mangle], but not exported - --> $DIR/suggestions.rs:31:18 + --> $DIR/suggestions.rs:33:18 | -31 | #[no_mangle] pub static DAUNTLESS: bool = true; +33 | #[no_mangle] pub static DAUNTLESS: bool = true; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: function is marked #[no_mangle], but not exported - --> $DIR/suggestions.rs:33:18 + --> $DIR/suggestions.rs:35:18 | -33 | #[no_mangle] pub fn val_jean() {} +35 | #[no_mangle] pub fn val_jean() {} | ^^^^^^^^^^^^^^^^^^^^ warning: denote infinite loops with `loop { ... }` - --> $DIR/suggestions.rs:44:5 + --> $DIR/suggestions.rs:46:5 | -44 | while true { // should suggest `loop` +46 | while true { // should suggest `loop` | ^^^^^^^^^^ help: use `loop` | = note: #[warn(while_true)] on by default warning: the `warp_factor:` in this pattern is redundant - --> $DIR/suggestions.rs:51:23 + --> $DIR/suggestions.rs:57:23 | -51 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand +57 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand | ------------^^^^^^^^^^^^ | | | help: remove this diff --git a/src/test/ui/loop-break-value-no-repeat.stderr b/src/test/ui/loop-break-value-no-repeat.stderr index 296b3b191e3..982de00b4fa 100644 --- a/src/test/ui/loop-break-value-no-repeat.stderr +++ b/src/test/ui/loop-break-value-no-repeat.stderr @@ -3,6 +3,10 @@ error[E0571]: `break` with value from a `for` loop | 22 | break 22 //~ ERROR `break` with value from a `for` loop | ^^^^^^^^ can only break with a value inside `loop` +help: instead, use `break` on its own without a value inside this `for` loop + | +22 | break //~ ERROR `break` with value from a `for` loop + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/span-covering-argument-1.rs b/src/test/ui/macros/span-covering-argument-1.rs new file mode 100644 index 00000000000..bfc137fc7b2 --- /dev/null +++ b/src/test/ui/macros/span-covering-argument-1.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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! bad { + ($s:ident whatever) => { + { + let $s = 0; + *&mut $s = 0; + //~^ ERROR cannot borrow immutable local variable `foo` as mutable [E0596] + } + } +} + +fn main() { + bad!(foo whatever); +} diff --git a/src/test/ui/macros/span-covering-argument-1.stderr b/src/test/ui/macros/span-covering-argument-1.stderr new file mode 100644 index 00000000000..677d2f10fd6 --- /dev/null +++ b/src/test/ui/macros/span-covering-argument-1.stderr @@ -0,0 +1,13 @@ +error[E0596]: cannot borrow immutable local variable `foo` as mutable + --> $DIR/span-covering-argument-1.rs:15:19 + | +14 | let $s = 0; + | -- consider changing this to `mut $s` +15 | *&mut $s = 0; + | ^^ cannot borrow mutably +... +22 | bad!(foo whatever); + | ------------------- in this macro invocation + +error: aborting due to previous error + diff --git a/src/test/ui/resolve-conflict-item-vs-import.stderr b/src/test/ui/resolve-conflict-item-vs-import.stderr index 03ef66681e4..e2245b8a8b1 100644 --- a/src/test/ui/resolve-conflict-item-vs-import.stderr +++ b/src/test/ui/resolve-conflict-item-vs-import.stderr @@ -10,8 +10,8 @@ error[E0255]: the name `transmute` is defined multiple times = note: `transmute` must be defined only once in the value namespace of this module help: You can use `as` to change the binding name of the import | -11 | use std::mem::transmute as Othertransmute; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +11 | use std::mem::transmute as other_transmute; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/span/macro-span-replacement.stderr b/src/test/ui/span/macro-span-replacement.stderr index 2a0e71e192c..728cd12e2c6 100644 --- a/src/test/ui/span/macro-span-replacement.stderr +++ b/src/test/ui/span/macro-span-replacement.stderr @@ -1,8 +1,8 @@ warning: struct is never used: `S` - --> $DIR/macro-span-replacement.rs:17:9 + --> $DIR/macro-span-replacement.rs:17:14 | 17 | $b $a; //~ WARN struct is never used - | ^^^^^^ + | ^ ... 22 | m!(S struct); | ------------- in this macro invocation diff --git a/src/test/ui/static-lifetime.stderr b/src/test/ui/static-lifetime.stderr index a99dbf21e54..24ba27b27ad 100644 --- a/src/test/ui/static-lifetime.stderr +++ b/src/test/ui/static-lifetime.stderr @@ -8,7 +8,7 @@ note: lifetime parameter instantiated with the lifetime 'a as defined on the imp --> $DIR/static-lifetime.rs:13:1 | 13 | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} //~ ERROR lifetime bound - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: but lifetime parameter must outlive the static lifetime error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr b/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr index d2ac15f7ffc..01dba62a851 100644 --- a/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr +++ b/src/test/ui/suggestions/issue-45799-bad-extern-crate-rename-suggestion-formatting.stderr @@ -7,7 +7,7 @@ error[E0259]: the name `std` is defined multiple times = note: `std` must be defined only once in the type namespace of this module help: You can use `as` to change the binding name of the import | -11 | extern crate std as Otherstd; +11 | extern crate std as other_std; | error: aborting due to previous error diff --git a/src/test/ui/use-mod.stderr b/src/test/ui/use-mod.stderr index bb64909e64a..1c9f306f493 100644 --- a/src/test/ui/use-mod.stderr +++ b/src/test/ui/use-mod.stderr @@ -25,7 +25,7 @@ error[E0252]: the name `bar` is defined multiple times = note: `bar` must be defined only once in the type namespace of this module help: You can use `as` to change the binding name of the import | -15 | self as Otherbar +15 | self as other_bar | error: aborting due to 3 previous errors diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index ff662736bdd..80750f9a3fe 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -167,7 +167,7 @@ impl EarlyProps { .expect("Malformed llvm version directive"); // Ignore if using system LLVM and actual version // is smaller the minimum required version - !(config.system_llvm && &actual_version[..] < min_version) + config.system_llvm && &actual_version[..] < min_version } else { false } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index abf62a060b8..46df211cbaf 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -79,7 +79,7 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Misma let mut results = Vec::new(); let mut mismatch = Mismatch::new(0); - for result in diff::lines(actual, expected) { + for result in diff::lines(expected, actual) { match result { diff::Result::Left(str) => { if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { @@ -91,7 +91,8 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Misma mismatch.lines.push(DiffLine::Context(line.to_owned())); } - mismatch.lines.push(DiffLine::Resulting(str.to_owned())); + mismatch.lines.push(DiffLine::Expected(str.to_owned())); + line_number += 1; lines_since_mismatch = 0; } diff::Result::Right(str) => { @@ -104,8 +105,7 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Misma mismatch.lines.push(DiffLine::Context(line.to_owned())); } - mismatch.lines.push(DiffLine::Expected(str.to_owned())); - line_number += 1; + mismatch.lines.push(DiffLine::Resulting(str.to_owned())); lines_since_mismatch = 0; } diff::Result::Both(str, _) => { diff --git a/src/tools/rls b/src/tools/rls -Subproject 511321ae1c2fa3f0e334885fecf406dd6c88283 +Subproject dee42bda8156a28ead609080e27b02173bb9c29 diff --git a/src/tools/rustfmt b/src/tools/rustfmt -Subproject e0e3e22248cd14ebbe0253e9720261a0328bfc5 +Subproject 346238f49740d6c98102a6a59811b1625c73a9d |
